mirror of
https://github.com/micropython/micropython.git
synced 2025-12-30 16:50:12 +01:00
Compare commits
150 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccedf000ed | ||
|
|
429e3f077e | ||
|
|
8768f8ad4b | ||
|
|
e4e52f5370 | ||
|
|
e503512f83 | ||
|
|
bc1488a05f | ||
|
|
b2f19b8d34 | ||
|
|
480a7ce58f | ||
|
|
de3c806965 | ||
|
|
c76af32575 | ||
|
|
b0b0012fd8 | ||
|
|
91bd4e8a23 | ||
|
|
124df6f8d0 | ||
|
|
d7353fe6fe | ||
|
|
627852019b | ||
|
|
c9fc620723 | ||
|
|
e5a3759ff5 | ||
|
|
8becca7c82 | ||
|
|
8456cc017b | ||
|
|
1084b0f9c2 | ||
|
|
fcff4663dd | ||
|
|
8204db6831 | ||
|
|
21dfd207ca | ||
|
|
a64d5d67b5 | ||
|
|
0b13f3e026 | ||
|
|
564963a170 | ||
|
|
d00d8ac95c | ||
|
|
e294bee45b | ||
|
|
e5b1b7348a | ||
|
|
e2f8d98525 | ||
|
|
185cb0d943 | ||
|
|
e7bb0443cd | ||
|
|
dd4f4530ab | ||
|
|
3aa09f5784 | ||
|
|
37378f8a9d | ||
|
|
f5d69794a8 | ||
|
|
e72be1b999 | ||
|
|
5fc42a6c97 | ||
|
|
842210f53a | ||
|
|
e7a478204a | ||
|
|
efa04eafd3 | ||
|
|
d46a822262 | ||
|
|
3be6984b8f | ||
|
|
8d62bbd46a | ||
|
|
3e42570538 | ||
|
|
481d714bd5 | ||
|
|
20f59e182e | ||
|
|
b1e217222e | ||
|
|
a3efe04dce | ||
|
|
2fe4cf7761 | ||
|
|
abf0f07a5a | ||
|
|
072bd07f17 | ||
|
|
0c3955b506 | ||
|
|
21ca2d76a2 | ||
|
|
9c9db3a7a1 | ||
|
|
1a55b6a787 | ||
|
|
c92672d7f8 | ||
|
|
b7a4b0f86f | ||
|
|
297d8469b8 | ||
|
|
391db8669b | ||
|
|
235f9b33c8 | ||
|
|
9870fdd4b0 | ||
|
|
c30595eb1b | ||
|
|
090c9236e8 | ||
|
|
37ada236b3 | ||
|
|
923a8a8320 | ||
|
|
0c7b26c0f8 | ||
|
|
067ae1269d | ||
|
|
9b0b373e5e | ||
|
|
4859edb95b | ||
|
|
95908b0f50 | ||
|
|
d27c0bb3aa | ||
|
|
911c00bbc5 | ||
|
|
e6c5a63fab | ||
|
|
4b71c056ef | ||
|
|
29f5682621 | ||
|
|
bfb6af857a | ||
|
|
34162872b1 | ||
|
|
426bb58b23 | ||
|
|
50062587c7 | ||
|
|
136b5cbd76 | ||
|
|
0107e90328 | ||
|
|
c14a81662c | ||
|
|
3c34d4140d | ||
|
|
91cfd414c0 | ||
|
|
1ef2348df0 | ||
|
|
1606607bd4 | ||
|
|
457c0a606c | ||
|
|
fbf976c9aa | ||
|
|
37671c9a97 | ||
|
|
dd5ee9ff9c | ||
|
|
26fa3e30ec | ||
|
|
945df4e564 | ||
|
|
1ce916aefd | ||
|
|
c36c75c4dc | ||
|
|
6c2ab5c315 | ||
|
|
f7bcce0552 | ||
|
|
5edbadefc1 | ||
|
|
c71e045165 | ||
|
|
1c795445b3 | ||
|
|
9b6617ea8b | ||
|
|
cc5b4a2653 | ||
|
|
23b3b04072 | ||
|
|
a2d8f98a7e | ||
|
|
1e49b151a7 | ||
|
|
f0f964807e | ||
|
|
9bf5f2857d | ||
|
|
a8202762f0 | ||
|
|
40e4c777a1 | ||
|
|
7989b07637 | ||
|
|
4091445612 | ||
|
|
e20cbbec73 | ||
|
|
2090a98e80 | ||
|
|
3556e45711 | ||
|
|
67f25dfe6f | ||
|
|
5d328cbeb9 | ||
|
|
5dc8f9b28a | ||
|
|
9aeec0e3a3 | ||
|
|
f53c343363 | ||
|
|
9c6f7378f7 | ||
|
|
f32498fe04 | ||
|
|
fec70ad369 | ||
|
|
9336ee320a | ||
|
|
fcdb239815 | ||
|
|
a9bcd51dc7 | ||
|
|
5a04e2cca8 | ||
|
|
854c8c0153 | ||
|
|
d03c681608 | ||
|
|
c4d0868df1 | ||
|
|
a91ac2011f | ||
|
|
6dba992182 | ||
|
|
ba0383a8c7 | ||
|
|
55f68b3ce8 | ||
|
|
97ef94df83 | ||
|
|
c3ab90da46 | ||
|
|
d112cbfd7c | ||
|
|
dc1ea1156a | ||
|
|
a2f9c9445a | ||
|
|
24119176e7 | ||
|
|
c568a2b443 | ||
|
|
1f2558d647 | ||
|
|
e5268963c6 | ||
|
|
00be7a849a | ||
|
|
39dc145478 | ||
|
|
3eaa0c3833 | ||
|
|
42f3de924b | ||
|
|
877dba3e1a | ||
|
|
e535a61983 | ||
|
|
3550de4ebe | ||
|
|
5fc6aa8100 |
@@ -8,6 +8,8 @@ before_script:
|
||||
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y python3.3 python3 gcc-4.7 gcc-arm-none-eabi qemu-system mingw32
|
||||
# For teensy build
|
||||
- sudo apt-get install realpath
|
||||
|
||||
script:
|
||||
- make -C unix CC=gcc-4.7
|
||||
|
||||
15
README.md
15
README.md
@@ -49,23 +49,28 @@ The Unix version
|
||||
|
||||
The "unix" port requires a standard Unix environment with gcc and GNU make.
|
||||
x86 and x64 architectures are supported (i.e. x86 32- and 64-bit), as well
|
||||
as ARMv7. Porting to other architectures require writing some assembly code
|
||||
for the exception handling.
|
||||
as ARM and MIPS. Making full-featured port to another architecture requires
|
||||
writing some assembly code for the exception handling and garbage collection.
|
||||
Alternatively, fallback implementation based on setjmp/longjmp can be used.
|
||||
|
||||
To build:
|
||||
|
||||
$ cd unix
|
||||
$ make
|
||||
|
||||
Then to test it:
|
||||
Then to give it a try:
|
||||
|
||||
$ ./micropython
|
||||
>>> list(5 * x + y for x in range(10) for y in [4, 2, 1])
|
||||
|
||||
Run complete testsuite:
|
||||
|
||||
$ make test
|
||||
|
||||
Debian/Ubuntu/Mint derivative Linux distros will require build-essentials and
|
||||
libreadline-dev packages installed. To build FFI (Foreign Function Interface)
|
||||
module, libffi-dev package is required. If you have problems with some
|
||||
dependencies, they can be disabled in unix/mpconfigport.mk .
|
||||
module, libffi-dev and pkg-config packages are required. If you have problems
|
||||
with some dependencies, they can be disabled in unix/mpconfigport.mk .
|
||||
|
||||
The STM version
|
||||
---------------
|
||||
|
||||
@@ -36,8 +36,9 @@ void do_str(const char *src) {
|
||||
mp_lexer_free(lex);
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
||||
|
||||
if (module_fun == mp_const_none) {
|
||||
if (mp_obj_is_exception_instance(module_fun)) {
|
||||
// compile error
|
||||
mp_obj_print_exception(module_fun);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,10 +70,10 @@ mp_import_stat_t mp_import_stat(const char *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
void nlr_jump_fail(void *val) {
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (0)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_SET (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (0)
|
||||
|
||||
@@ -5,6 +5,11 @@ Micro Python documentation and references
|
||||
|
||||
Here you can find documentation for Micro Python and the pyboard.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
quickref.rst
|
||||
|
||||
Software
|
||||
--------
|
||||
|
||||
|
||||
127
docs/quickref.rst
Normal file
127
docs/quickref.rst
Normal file
@@ -0,0 +1,127 @@
|
||||
Quick reference for the pyboard
|
||||
=====================================
|
||||
|
||||
.. image:: http://micropython.org/static/resources/pybv10-pinout.jpg
|
||||
:alt: AMP skin
|
||||
:width: 700px
|
||||
|
||||
General board control
|
||||
---------------------
|
||||
::
|
||||
|
||||
import pyb
|
||||
|
||||
pyb.delay(50) # wait 50 milliseconds
|
||||
pyb.millis() # number of milliseconds since bootup
|
||||
pyb.repl_uart(pyb.UART(1, 9600)) # duplicate REPL on UART(1)
|
||||
pyb.wfi() # pause CPU, waiting for interrupt
|
||||
pyb.freq() # get CPU and bus frequencies
|
||||
pyb.freq(60000000) # set CPU freq to 60MHz
|
||||
pyb.stop() # stop CPU, waiting for external interrupt
|
||||
|
||||
LEDs
|
||||
----
|
||||
::
|
||||
|
||||
from pyb import LED
|
||||
|
||||
led = LED(1) # red led
|
||||
led.toggle()
|
||||
led.on()
|
||||
led.off()
|
||||
|
||||
Pins and GPIO
|
||||
-------------
|
||||
::
|
||||
|
||||
from pyb import Pin
|
||||
|
||||
p_out = Pin('X1', Pin.OUT_PP)
|
||||
p_out.high()
|
||||
p_out.low()
|
||||
|
||||
p_in = Pin('X2', Pin.IN, Pin.PULL_UP)
|
||||
p_in.value() # get value, 0 or 1
|
||||
|
||||
External interrupts
|
||||
-------------------
|
||||
::
|
||||
|
||||
from pyb import Pin, ExtInt
|
||||
|
||||
callback = lambda e: print("intr")
|
||||
ext = ExtInt(Pin('Y1'), ExtInt.IRQ_RISING, Pin.PULL_NONE, callback)
|
||||
|
||||
Timers
|
||||
------
|
||||
::
|
||||
|
||||
from pyb import Timer
|
||||
|
||||
tim = Timer(1, freq=1000)
|
||||
tim.counter() # get counter value
|
||||
tim.freq(0.5) # 0.5 Hz
|
||||
tim.callback(lambda t: pyb.LED(1).toggle())
|
||||
|
||||
PWM (pulse width modulation)
|
||||
----------------------------
|
||||
::
|
||||
|
||||
from pyb import Pin, Timer
|
||||
|
||||
p = Pin('X1') # X1 has TIM2, CH1
|
||||
tim = Timer(2, freq=1000)
|
||||
ch = tim.channel(1, Timer.PWM, pin=p)
|
||||
ch.pulse_width_percent(50)
|
||||
|
||||
ADC (analog to digital conversion)
|
||||
----------------------------------
|
||||
::
|
||||
|
||||
from pyb import Pin, ADC
|
||||
|
||||
adc = ADC(Pin('X19'))
|
||||
adc.read() # read value, 0-4095
|
||||
|
||||
DAC (digital to analog conversion)
|
||||
----------------------------------
|
||||
::
|
||||
|
||||
from pyb import Pin, DAC
|
||||
|
||||
dac = DAC(Pin('X5'))
|
||||
dac.write(120) # output between 0 and 255
|
||||
|
||||
UART (serial bus)
|
||||
-----------------
|
||||
::
|
||||
|
||||
from pyb import UART
|
||||
|
||||
uart = UART(1, 9600)
|
||||
uart.write('hello')
|
||||
uart.read(5) # read up to 5 bytes
|
||||
|
||||
SPI bus
|
||||
-------
|
||||
::
|
||||
|
||||
from pyb import SPI
|
||||
|
||||
spi = SPI(1, SPI.MASTER, baudrate=200000, polarity=1, phase=0)
|
||||
spi.send('hello')
|
||||
spi.recv(5) # receive 5 bytes on the bus
|
||||
spi.send_recv('hello') # send a receive 5 bytes
|
||||
|
||||
I2C bus
|
||||
-------
|
||||
::
|
||||
|
||||
from pyb import I2C
|
||||
|
||||
i2c = I2C(1, I2C.MASTER, baudrate=100000)
|
||||
i2c.scan() # returns list of slave addresses
|
||||
i2c.send('hello', 0x42) # send 5 bytes to slave with address 0x42
|
||||
i2c.recv(5, 0x42) # receive 5 bytes from slave
|
||||
i2c.mem_read(2, 0x42, 0x10) # read 2 bytes from slave 0x42, slave memory 0x10
|
||||
i2c.mem_write('xy', 0x42, 0x10) # write 2 bytes to slave 0x42, slave memory 0x10
|
||||
234
drivers/nrf24l01/nrf24l01.py
Normal file
234
drivers/nrf24l01/nrf24l01.py
Normal file
@@ -0,0 +1,234 @@
|
||||
"""NRF24L01 driver for Micro Python"""
|
||||
|
||||
import pyb
|
||||
|
||||
# nRF24L01+ registers
|
||||
CONFIG = const(0x00)
|
||||
EN_RXADDR = const(0x02)
|
||||
SETUP_AW = const(0x03)
|
||||
SETUP_RETR = const(0x04)
|
||||
RF_CH = const(0x05)
|
||||
RF_SETUP = const(0x06)
|
||||
STATUS = const(0x07)
|
||||
OBSERVE_TX = const(0x08)
|
||||
RX_ADDR_P0 = const(0x0a)
|
||||
TX_ADDR = const(0x10)
|
||||
RX_PW_P0 = const(0x11)
|
||||
FIFO_STATUS = const(0x17)
|
||||
DYNPD = const(0x1c)
|
||||
|
||||
# CONFIG register
|
||||
EN_CRC = const(0x08) # enable CRC
|
||||
CRCO = const(0x04) # CRC encoding scheme; 0=1 byte, 1=2 bytes
|
||||
PWR_UP = const(0x02) # 1=power up, 0=power down
|
||||
PRIM_RX = const(0x01) # RX/TX control; 0=PTX, 1=PRX
|
||||
|
||||
# RF_SETUP register
|
||||
POWER_0 = const(0x00) # -18 dBm
|
||||
POWER_1 = const(0x02) # -12 dBm
|
||||
POWER_2 = const(0x04) # -6 dBm
|
||||
POWER_3 = const(0x06) # 0 dBm
|
||||
SPEED_1M = const(0x00)
|
||||
SPEED_2M = const(0x08)
|
||||
SPEED_250K = const(0x20)
|
||||
|
||||
# STATUS register
|
||||
RX_DR = const(0x40) # RX data ready; write 1 to clear
|
||||
TX_DS = const(0x20) # TX data sent; write 1 to clear
|
||||
MAX_RT = const(0x10) # max retransmits reached; write 1 to clear
|
||||
|
||||
# FIFO_STATUS register
|
||||
RX_EMPTY = const(0x01) # 1 if RX FIFO is empty
|
||||
|
||||
# constants for instructions
|
||||
R_RX_PL_WID = const(0x60) # read RX payload width
|
||||
R_RX_PAYLOAD = const(0x61) # read RX payload
|
||||
W_TX_PAYLOAD = const(0xa0) # write TX payload
|
||||
FLUSH_TX = const(0xe1) # flush TX FIFO
|
||||
FLUSH_RX = const(0xe2) # flush RX FIFO
|
||||
NOP = const(0xff) # use to read STATUS register
|
||||
|
||||
class NRF24L01:
|
||||
def __init__(self, spi, cs, ce, channel=46, payload_size=16):
|
||||
assert payload_size <= 32
|
||||
|
||||
# init the SPI bus and pins
|
||||
spi.init(spi.MASTER, baudrate=4000000, polarity=0, phase=1, firstbit=spi.MSB)
|
||||
cs.init(cs.OUT_PP, cs.PULL_NONE)
|
||||
ce.init(ce.OUT_PP, ce.PULL_NONE)
|
||||
|
||||
# store the pins
|
||||
self.spi = spi
|
||||
self.cs = cs
|
||||
self.ce = ce
|
||||
|
||||
# reset everything
|
||||
self.ce.low()
|
||||
self.cs.high()
|
||||
self.payload_size = payload_size
|
||||
self.pipe0_read_addr = None
|
||||
pyb.delay(5)
|
||||
|
||||
# set address width to 5 bytes
|
||||
self.reg_write(SETUP_AW, 0b11)
|
||||
|
||||
# disable dynamic payloads
|
||||
self.reg_write(DYNPD, 0)
|
||||
|
||||
# auto retransmit delay: 1750us
|
||||
# auto retransmit count: 8
|
||||
self.reg_write(SETUP_RETR, (6 << 4) | 8)
|
||||
|
||||
# set rf power and speed
|
||||
self.set_power_speed(POWER_3, SPEED_1M)
|
||||
|
||||
# init CRC
|
||||
self.set_crc(2)
|
||||
|
||||
# clear status flags
|
||||
self.reg_write(STATUS, RX_DR | TX_DS | MAX_RT)
|
||||
|
||||
# set channel
|
||||
self.set_channel(channel)
|
||||
|
||||
# flush buffers
|
||||
self.flush_rx()
|
||||
self.flush_tx()
|
||||
|
||||
def reg_read(self, reg):
|
||||
self.cs.low()
|
||||
self.spi.send_recv(reg)
|
||||
buf = self.spi.recv(1)
|
||||
self.cs.high()
|
||||
return buf[0]
|
||||
|
||||
def reg_read_ret_status(self, reg):
|
||||
self.cs.low()
|
||||
status = self.spi.send_recv(reg)[0]
|
||||
buf = self.spi.recv(1)
|
||||
self.cs.high()
|
||||
return status
|
||||
|
||||
def reg_write(self, reg, buf):
|
||||
self.cs.low()
|
||||
status = self.spi.send_recv(0x20 | reg)[0]
|
||||
self.spi.send(buf)
|
||||
self.cs.high()
|
||||
return status
|
||||
|
||||
def flush_rx(self):
|
||||
self.cs.low()
|
||||
self.spi.send(FLUSH_RX)
|
||||
self.cs.high()
|
||||
|
||||
def flush_tx(self):
|
||||
self.cs.low()
|
||||
self.spi.send(FLUSH_TX)
|
||||
self.cs.high()
|
||||
|
||||
# power is one of POWER_x defines; speed is one of SPEED_x defines
|
||||
def set_power_speed(self, power, speed):
|
||||
setup = self.reg_read(RF_SETUP) & 0b11010001
|
||||
self.reg_write(RF_SETUP, setup | power | speed)
|
||||
|
||||
# length in bytes: 0, 1 or 2
|
||||
def set_crc(self, length):
|
||||
config = self.reg_read(CONFIG) & ~(CRCO | EN_CRC)
|
||||
if length == 0:
|
||||
pass
|
||||
elif length == 1:
|
||||
config |= EN_CRC
|
||||
else:
|
||||
config |= EN_CRC | CRCO
|
||||
self.reg_write(CONFIG, config)
|
||||
|
||||
def set_channel(self, channel):
|
||||
self.reg_write(RF_CH, min(channel, 127))
|
||||
|
||||
# address should be a bytes object 5 bytes long
|
||||
def open_tx_pipe(self, address):
|
||||
assert len(address) == 5
|
||||
self.reg_write(RX_ADDR_P0, address)
|
||||
self.reg_write(TX_ADDR, address)
|
||||
self.reg_write(RX_PW_P0, self.payload_size)
|
||||
|
||||
# address should be a bytes object 5 bytes long
|
||||
# pipe 0 and 1 have 5 byte address
|
||||
# pipes 2-5 use same 4 most-significant bytes as pipe 1, plus 1 extra byte
|
||||
def open_rx_pipe(self, pipe_id, address):
|
||||
assert len(address) == 5
|
||||
assert 0 <= pipe_id <= 5
|
||||
if pipe_id == 0:
|
||||
self.pipe0_read_addr = address
|
||||
if pipe_id < 2:
|
||||
self.reg_write(RX_ADDR_P0 + pipe_id, address)
|
||||
else:
|
||||
self.reg_write(RX_ADDR_P0 + pipe_id, address[0])
|
||||
self.reg_write(RX_PW_P0 + pipe_id, self.payload_size)
|
||||
self.reg_write(EN_RXADDR, self.reg_read(EN_RXADDR) | (1 << pipe_id))
|
||||
|
||||
def start_listening(self):
|
||||
self.reg_write(CONFIG, self.reg_read(CONFIG) | PWR_UP | PRIM_RX)
|
||||
self.reg_write(STATUS, RX_DR | TX_DS | MAX_RT)
|
||||
|
||||
if self.pipe0_read_addr is not None:
|
||||
self.reg_write(RX_ADDR_P0, self.pipe0_read_addr)
|
||||
|
||||
self.flush_rx()
|
||||
self.flush_tx()
|
||||
self.ce.high()
|
||||
pyb.udelay(130)
|
||||
|
||||
def stop_listening(self):
|
||||
self.ce.low()
|
||||
self.flush_tx()
|
||||
self.flush_rx()
|
||||
|
||||
# returns True if any data available to recv
|
||||
def any(self):
|
||||
return not bool(self.reg_read(FIFO_STATUS) & RX_EMPTY)
|
||||
|
||||
def recv(self):
|
||||
# get the data
|
||||
self.cs.low()
|
||||
self.spi.send(R_RX_PAYLOAD)
|
||||
buf = self.spi.recv(self.payload_size)
|
||||
self.cs.high()
|
||||
|
||||
# clear RX ready flag
|
||||
self.reg_write(STATUS, RX_DR)
|
||||
|
||||
return buf
|
||||
|
||||
def send(self, buf, timeout=500):
|
||||
# power up
|
||||
self.reg_write(CONFIG, (self.reg_read(CONFIG) | PWR_UP) & ~PRIM_RX)
|
||||
pyb.udelay(150)
|
||||
|
||||
# send the data
|
||||
self.cs.low()
|
||||
self.spi.send(W_TX_PAYLOAD)
|
||||
self.spi.send(buf)
|
||||
if len(buf) < self.payload_size:
|
||||
self.spi.send(b'\x00' * (self.payload_size - len(buf))) # pad out data
|
||||
self.cs.high()
|
||||
|
||||
# enable the chip so it can send the data
|
||||
self.ce.high()
|
||||
pyb.udelay(15) # needs to be >10us
|
||||
self.ce.low()
|
||||
|
||||
# blocking wait for tx complete
|
||||
start = pyb.millis()
|
||||
while pyb.millis() - start < timeout:
|
||||
status = self.reg_read_ret_status(OBSERVE_TX)
|
||||
if status & (TX_DS | MAX_RT):
|
||||
break
|
||||
|
||||
# get and clear all status flags
|
||||
status = self.reg_write(STATUS, RX_DR | TX_DS | MAX_RT)
|
||||
if not (status & TX_DS):
|
||||
raise OSError("send failed")
|
||||
|
||||
# power down
|
||||
self.reg_write(CONFIG, self.reg_read(CONFIG) & ~PWR_UP)
|
||||
100
drivers/nrf24l01/nrf24l01test.py
Normal file
100
drivers/nrf24l01/nrf24l01test.py
Normal file
@@ -0,0 +1,100 @@
|
||||
"""Test for nrf24l01 module."""
|
||||
|
||||
import struct
|
||||
import pyb
|
||||
from pyb import Pin, SPI
|
||||
from nrf24l01 import NRF24L01
|
||||
|
||||
pipes = (b'\xf0\xf0\xf0\xf0\xe1', b'\xf0\xf0\xf0\xf0\xd2')
|
||||
|
||||
def master():
|
||||
nrf = NRF24L01(SPI(2), Pin('Y5'), Pin('Y4'), payload_size=8)
|
||||
|
||||
nrf.open_tx_pipe(pipes[0])
|
||||
nrf.open_rx_pipe(1, pipes[1])
|
||||
nrf.start_listening()
|
||||
|
||||
num_needed = 16
|
||||
num_successes = 0
|
||||
num_failures = 0
|
||||
led_state = 0
|
||||
|
||||
print('NRF24L01 master mode, sending %d packets...' % num_needed)
|
||||
|
||||
while num_successes < num_needed and num_failures < num_needed:
|
||||
# stop listening and send packet
|
||||
nrf.stop_listening()
|
||||
millis = pyb.millis()
|
||||
led_state = max(1, (led_state << 1) & 0x0f)
|
||||
print('sending:', millis, led_state)
|
||||
try:
|
||||
nrf.send(struct.pack('ii', millis, led_state))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# start listening again
|
||||
nrf.start_listening()
|
||||
|
||||
# wait for response, with 250ms timeout
|
||||
start_time = pyb.millis()
|
||||
timeout = False
|
||||
while not nrf.any() and not timeout:
|
||||
if pyb.elapsed_millis(start_time) > 250:
|
||||
timeout = True
|
||||
|
||||
if timeout:
|
||||
print('failed, respones timed out')
|
||||
num_failures += 1
|
||||
|
||||
else:
|
||||
# recv packet
|
||||
got_millis, = struct.unpack('i', nrf.recv())
|
||||
|
||||
# print response and round-trip delay
|
||||
print('got response:', got_millis, '(delay', pyb.millis() - got_millis, 'ms)')
|
||||
num_successes += 1
|
||||
|
||||
# delay then loop
|
||||
pyb.delay(250)
|
||||
|
||||
print('master finished sending; succeses=%d, failures=%d' % (num_successes, num_failures))
|
||||
|
||||
def slave():
|
||||
nrf = NRF24L01(SPI(2), Pin('Y5'), Pin('Y4'), payload_size=8)
|
||||
|
||||
nrf.open_tx_pipe(pipes[1])
|
||||
nrf.open_rx_pipe(1, pipes[0])
|
||||
nrf.start_listening()
|
||||
|
||||
print('NRF24L01 slave mode, waiting for packets... (ctrl-C to stop)')
|
||||
|
||||
while True:
|
||||
pyb.wfi()
|
||||
if nrf.any():
|
||||
while nrf.any():
|
||||
buf = nrf.recv()
|
||||
millis, led_state = struct.unpack('ii', buf)
|
||||
print('received:', millis, led_state)
|
||||
for i in range(4):
|
||||
if led_state & (1 << i):
|
||||
pyb.LED(i + 1).on()
|
||||
else:
|
||||
pyb.LED(i + 1).off()
|
||||
pyb.delay(15)
|
||||
|
||||
nrf.stop_listening()
|
||||
try:
|
||||
nrf.send(struct.pack('i', millis))
|
||||
except OSError:
|
||||
pass
|
||||
print('sent response')
|
||||
nrf.start_listening()
|
||||
|
||||
print('NRF24L01 test module loaded')
|
||||
print('NRF24L01 pinout for test:')
|
||||
print(' CE on Y4')
|
||||
print(' CSN on Y5')
|
||||
print(' SCK on Y6')
|
||||
print(' MISO on Y7')
|
||||
print(' MOSI on Y8')
|
||||
print('run nrf24l01test.slave() on slave, then nrf24l01test.master() on master')
|
||||
@@ -19,7 +19,7 @@ while True:
|
||||
if switch():
|
||||
pyb.delay(200) # delay avoids detection of multiple presses
|
||||
blue.on() # blue LED indicates file open
|
||||
log = open('1:/log.csv', 'w') # open file on SD (SD: '1:/', flash: '0/)
|
||||
log = open('/sd/log.csv', 'w') # open file on SD (SD: '/sd/', flash: '/flash/)
|
||||
|
||||
# until switch is pressed again
|
||||
while not switch():
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#import essential libraries
|
||||
import lcd
|
||||
import pyb
|
||||
|
||||
lcd = pyb.LCD('x')
|
||||
lcd.light(1)
|
||||
|
||||
# do 1 iteration of Conway's Game of Life
|
||||
def conway_step():
|
||||
for x in range(128): # loop over x coordinates
|
||||
@@ -21,26 +23,24 @@ def conway_step():
|
||||
|
||||
# apply the rules of life
|
||||
if self and not (2 <= num_neighbours <= 3):
|
||||
lcd.reset(x, y) # not enough, or too many neighbours: cell dies
|
||||
lcd.pixel(x, y, 0) # not enough, or too many neighbours: cell dies
|
||||
elif not self and num_neighbours == 3:
|
||||
lcd.set(x, y) # exactly 3 neigbours around an empty cell: cell is born
|
||||
lcd.pixel(x, y, 1) # exactly 3 neigbours around an empty cell: cell is born
|
||||
|
||||
# randomise the start
|
||||
def conway_rand():
|
||||
lcd.clear() # clear the LCD
|
||||
lcd.fill(0) # clear the LCD
|
||||
for x in range(128): # loop over x coordinates
|
||||
for y in range(32): # loop over y coordinates
|
||||
if pyb.rand() & 1: # get a 1-bit random number
|
||||
lcd.set(x, y) # set the pixel randomly
|
||||
lcd.pixel(x, y, pyb.rng() & 1) # set the pixel randomly
|
||||
|
||||
# loop for a certain number of frames, doing iterations of Conway's Game of Life
|
||||
def conway_go(num_frames):
|
||||
for i in range(num_frames):
|
||||
conway_step() # do 1 iteration
|
||||
lcd.show() # update the LCD
|
||||
pyb.delay(300)
|
||||
pyb.delay(50)
|
||||
|
||||
# PC testing
|
||||
lcd = lcd.LCD(128, 32)
|
||||
# testing
|
||||
conway_rand()
|
||||
conway_go(1000)
|
||||
conway_go(100)
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# LCD testing object for PC
|
||||
# uses double buffering
|
||||
class LCD:
|
||||
def __init__(self, width, height):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.buf1 = [[0 for x in range(self.width)] for y in range(self.height)]
|
||||
self.buf2 = [[0 for x in range(self.width)] for y in range(self.height)]
|
||||
|
||||
def clear(self):
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
self.buf1[y][x] = self.buf2[y][x] = 0
|
||||
|
||||
def show(self):
|
||||
print('') # blank line to separate frames
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
self.buf1[y][x] = self.buf2[y][x]
|
||||
for y in range(self.height):
|
||||
row = ''.join(['*' if self.buf1[y][x] else ' ' for x in range(self.width)])
|
||||
print(row)
|
||||
|
||||
def get(self, x, y):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
return self.buf1[y][x]
|
||||
else:
|
||||
return 0
|
||||
|
||||
def reset(self, x, y):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
self.buf2[y][x] = 0
|
||||
|
||||
def set(self, x, y):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
self.buf2[y][x] = 1
|
||||
@@ -6,8 +6,44 @@ def delay(n):
|
||||
pass
|
||||
|
||||
rand_seed = 1
|
||||
def rand():
|
||||
def rng():
|
||||
global rand_seed
|
||||
# for these choice of numbers, see P L'Ecuyer, "Tables of linear congruential generators of different sizes and good lattice structure"
|
||||
rand_seed = (rand_seed * 653276) % 8388593
|
||||
return rand_seed
|
||||
|
||||
# LCD testing object for PC
|
||||
# uses double buffering
|
||||
class LCD:
|
||||
def __init__(self, port):
|
||||
self.width = 128
|
||||
self.height = 32
|
||||
self.buf1 = [[0 for x in range(self.width)] for y in range(self.height)]
|
||||
self.buf2 = [[0 for x in range(self.width)] for y in range(self.height)]
|
||||
|
||||
def light(self, value):
|
||||
pass
|
||||
|
||||
def fill(self, value):
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
self.buf1[y][x] = self.buf2[y][x] = value
|
||||
|
||||
def show(self):
|
||||
print('') # blank line to separate frames
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
self.buf1[y][x] = self.buf2[y][x]
|
||||
for y in range(self.height):
|
||||
row = ''.join(['*' if self.buf1[y][x] else ' ' for x in range(self.width)])
|
||||
print(row)
|
||||
|
||||
def get(self, x, y):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
return self.buf1[y][x]
|
||||
else:
|
||||
return 0
|
||||
|
||||
def pixel(self, x, y, value):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
self.buf2[y][x] = value
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
try:
|
||||
import microsocket as _socket
|
||||
import usocket as _socket
|
||||
except:
|
||||
import _socket
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
try:
|
||||
import microsocket as socket
|
||||
import usocket as socket
|
||||
except:
|
||||
import socket
|
||||
|
||||
@@ -1,595 +0,0 @@
|
||||
/* 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/>
|
||||
*/
|
||||
@@ -401,7 +401,7 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
||||
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);
|
||||
self->addr + offset, val);
|
||||
}
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
|
||||
138
extmod/moduheapq.c
Normal file
138
extmod/moduheapq.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 <unistd.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "nlr.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objlist.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_UHEAPQ
|
||||
|
||||
// the algorithm here is modelled on CPython's heapq.py
|
||||
|
||||
STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) {
|
||||
if (!MP_OBJ_IS_TYPE(heap_in, &mp_type_list)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "heap must be a list"));
|
||||
}
|
||||
return heap_in;
|
||||
}
|
||||
|
||||
STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
|
||||
mp_obj_t item = heap->items[pos];
|
||||
while (pos > start_pos) {
|
||||
mp_uint_t parent_pos = (pos - 1) >> 1;
|
||||
mp_obj_t parent = heap->items[parent_pos];
|
||||
if (mp_binary_op(MP_BINARY_OP_LESS, item, parent) == mp_const_true) {
|
||||
heap->items[pos] = parent;
|
||||
pos = parent_pos;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
heap->items[pos] = item;
|
||||
}
|
||||
|
||||
STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
|
||||
mp_uint_t start_pos = pos;
|
||||
mp_uint_t end_pos = heap->len;
|
||||
mp_obj_t item = heap->items[pos];
|
||||
for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {
|
||||
// choose right child if it's <= left child
|
||||
if (child_pos + 1 < end_pos && mp_binary_op(MP_BINARY_OP_LESS, heap->items[child_pos], heap->items[child_pos + 1]) == mp_const_false) {
|
||||
child_pos += 1;
|
||||
}
|
||||
// bubble up the smaller child
|
||||
heap->items[pos] = heap->items[child_pos];
|
||||
pos = child_pos;
|
||||
}
|
||||
heap->items[pos] = item;
|
||||
heap_siftdown(heap, start_pos, pos);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) {
|
||||
mp_obj_list_t *heap = get_heap(heap_in);
|
||||
mp_obj_list_append(heap, item);
|
||||
heap_siftdown(heap, 0, heap->len - 1);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
|
||||
|
||||
STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
|
||||
mp_obj_list_t *heap = get_heap(heap_in);
|
||||
if (heap->len == 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
|
||||
}
|
||||
mp_obj_t item = heap->items[0];
|
||||
heap->len -= 1;
|
||||
heap->items[0] = heap->items[heap->len];
|
||||
heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer
|
||||
if (heap->len) {
|
||||
heap_siftup(heap, 0);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop);
|
||||
|
||||
STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) {
|
||||
mp_obj_list_t *heap = get_heap(heap_in);
|
||||
for (mp_uint_t i = heap->len / 2; i > 0;) {
|
||||
heap_siftup(heap, --i);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_uheapq_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uheapq) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heappush), (mp_obj_t)&mod_uheapq_heappush_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heappop), (mp_obj_t)&mod_uheapq_heappop_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heapify), (mp_obj_t)&mod_uheapq_heapify_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_uheapq_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_uheapq_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_uheapq_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_uheapq_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_uheapq = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uheapq,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_uheapq_globals,
|
||||
};
|
||||
|
||||
#endif //MICROPY_PY_UHEAPQ
|
||||
250
extmod/modure.c
Normal file
250
extmod/modure.c
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "binary.h"
|
||||
|
||||
#if MICROPY_PY_URE
|
||||
|
||||
#include "re1.5/re1.5.h"
|
||||
|
||||
#define FLAG_DEBUG 0x1000
|
||||
|
||||
typedef struct _mp_obj_re_t {
|
||||
mp_obj_base_t base;
|
||||
ByteProg re;
|
||||
} mp_obj_re_t;
|
||||
|
||||
typedef struct _mp_obj_match_t {
|
||||
mp_obj_base_t base;
|
||||
int num_matches;
|
||||
mp_obj_t str;
|
||||
const char *caps[0];
|
||||
} mp_obj_match_t;
|
||||
|
||||
|
||||
STATIC void match_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_match_t *self = self_in;
|
||||
print(env, "<match num=%d @%p>", self->num_matches);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) {
|
||||
mp_obj_match_t *self = self_in;
|
||||
mp_int_t no = mp_obj_int_get(no_in);
|
||||
if (no < 0 || no >= self->num_matches / 2) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, no_in));
|
||||
}
|
||||
|
||||
const char *start = self->caps[no * 2];
|
||||
return mp_obj_new_str(start, self->caps[no * 2 + 1] - start, false);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(match_group_obj, match_group);
|
||||
|
||||
STATIC const mp_map_elem_t match_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_group), (mp_obj_t) &match_group_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t match_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_match,
|
||||
.print = match_print,
|
||||
.locals_dict = (mp_obj_t)&match_locals_dict,
|
||||
};
|
||||
|
||||
STATIC void re_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_re_t *self = self_in;
|
||||
print(env, "<re %p>", self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_re_t *self = args[0];
|
||||
Subject subj;
|
||||
mp_uint_t len;
|
||||
subj.begin = mp_obj_str_get_data(args[1], &len);
|
||||
subj.end = subj.begin + len;
|
||||
int caps_num = (self->re.sub + 1) * 2;
|
||||
mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, char*, caps_num);
|
||||
int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, is_anchored);
|
||||
if (res == 0) {
|
||||
m_del_var(mp_obj_match_t, char*, caps_num, match);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
match->base.type = &match_type;
|
||||
match->num_matches = caps_num;
|
||||
match->str = args[1];
|
||||
return match;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t re_match(uint n_args, const mp_obj_t *args) {
|
||||
return re_exec(true, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_match_obj, 2, 4, re_match);
|
||||
|
||||
STATIC mp_obj_t re_search(uint n_args, const mp_obj_t *args) {
|
||||
return re_exec(false, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_search_obj, 2, 4, re_search);
|
||||
|
||||
STATIC mp_obj_t re_split(uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_re_t *self = args[0];
|
||||
Subject subj;
|
||||
mp_uint_t len;
|
||||
subj.begin = mp_obj_str_get_data(args[1], &len);
|
||||
subj.end = subj.begin + len;
|
||||
int caps_num = (self->re.sub + 1) * 2;
|
||||
|
||||
int maxsplit = 0;
|
||||
if (n_args > 2) {
|
||||
maxsplit = mp_obj_int_get(args[2]);
|
||||
}
|
||||
|
||||
mp_obj_t retval = mp_obj_new_list(0, NULL);
|
||||
const char *caps[caps_num];
|
||||
while (true) {
|
||||
int res = re1_5_recursiveloopprog(&self->re, &subj, caps, caps_num, false);
|
||||
|
||||
// if we didn't have a match, or had an empty match, it's time to stop
|
||||
if (!res || caps[0] == caps[1]) {
|
||||
break;
|
||||
}
|
||||
|
||||
mp_obj_t s = mp_obj_new_str(subj.begin, caps[0] - subj.begin, false);
|
||||
mp_obj_list_append(retval, s);
|
||||
if (self->re.sub > 0) {
|
||||
mp_not_implemented("Splitting with sub-captures");
|
||||
}
|
||||
subj.begin = caps[1];
|
||||
if (maxsplit > 0 && --maxsplit == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t s = mp_obj_new_str(subj.begin, subj.end - subj.begin, false);
|
||||
mp_obj_list_append(retval, s);
|
||||
return retval;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_split_obj, 2, 3, re_split);
|
||||
|
||||
STATIC const mp_map_elem_t re_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_match), (mp_obj_t) &re_match_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_search), (mp_obj_t) &re_search_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_split), (mp_obj_t) &re_split_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t re_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ure,
|
||||
.print = re_print,
|
||||
.locals_dict = (mp_obj_t)&re_locals_dict,
|
||||
};
|
||||
|
||||
mp_obj_t mod_re_compile(uint n_args, const mp_obj_t *args) {
|
||||
const char *re_str = mp_obj_str_get_str(args[0]);
|
||||
int size = re1_5_sizecode(re_str);
|
||||
mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size);
|
||||
o->base.type = &re_type;
|
||||
int flags = 0;
|
||||
if (n_args > 1) {
|
||||
flags = mp_obj_get_int(args[1]);
|
||||
}
|
||||
int error = re1_5_compilecode(&o->re, re_str);
|
||||
if (error != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Error in regex"));
|
||||
}
|
||||
if (flags & FLAG_DEBUG) {
|
||||
re1_5_dumpcode(&o->re);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
|
||||
|
||||
STATIC mp_obj_t mod_re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_re_t *self = mod_re_compile(1, args);
|
||||
|
||||
const mp_obj_t args2[] = {self, args[1]};
|
||||
mp_obj_match_t *match = re_exec(is_anchored, 2, args2);
|
||||
return match;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_re_match(uint n_args, const mp_obj_t *args) {
|
||||
return mod_re_exec(true, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_match_obj, 2, 4, mod_re_match);
|
||||
|
||||
STATIC mp_obj_t mod_re_search(uint n_args, const mp_obj_t *args) {
|
||||
return mod_re_exec(false, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_search_obj, 2, 4, mod_re_search);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_re_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ure) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_compile), (mp_obj_t)&mod_re_compile_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_match), (mp_obj_t)&mod_re_match_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_search), (mp_obj_t)&mod_re_search_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEBUG), MP_OBJ_NEW_SMALL_INT(FLAG_DEBUG) },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_re_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_re_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_re_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_re_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_ure = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_ure,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_re_globals,
|
||||
};
|
||||
|
||||
// Source files #include'd here to make sure they're compiled in
|
||||
// only if module is enabled by config setting.
|
||||
|
||||
#define re1_5_fatal(x) assert(!x)
|
||||
#include "re1.5/compilecode.c"
|
||||
#include "re1.5/dumpcode.c"
|
||||
#include "re1.5/recursiveloop.c"
|
||||
#include "re1.5/charclass.c"
|
||||
|
||||
#endif //MICROPY_PY_URE
|
||||
114
extmod/moduzlib.c
Normal file
114
extmod/moduzlib.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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 "nlr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_UZLIB
|
||||
|
||||
#include "uzlib/tinf.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC int mod_uzlib_grow_buf(TINF_DATA *d, unsigned alloc_req) {
|
||||
if (alloc_req < 256) {
|
||||
alloc_req = 256;
|
||||
}
|
||||
DEBUG_printf("uzlib: Resizing buffer to " UINT_FMT " bytes\n", d->destSize + alloc_req);
|
||||
d->destStart = m_renew(byte, d->destStart, d->destSize, d->destSize + alloc_req);
|
||||
d->destSize += alloc_req;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_uzlib_decompress(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_t data = args[0];
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
TINF_DATA *decomp = m_new_obj(TINF_DATA);
|
||||
DEBUG_printf("sizeof(TINF_DATA)=" UINT_FMT "\n", sizeof(*decomp));
|
||||
|
||||
decomp->destStart = m_new(byte, bufinfo.len);
|
||||
decomp->destSize = bufinfo.len;
|
||||
decomp->destGrow = mod_uzlib_grow_buf;
|
||||
decomp->source = bufinfo.buf;
|
||||
|
||||
int st = tinf_zlib_uncompress_dyn(decomp, bufinfo.len);
|
||||
if (st != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st)));
|
||||
}
|
||||
|
||||
mp_obj_t res = mp_obj_new_bytearray_by_ref(decomp->dest - decomp->destStart, decomp->destStart);
|
||||
m_del_obj(TINF_DATA, decomp);
|
||||
return res;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_uzlib_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uzlib) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_decompress), (mp_obj_t)&mod_uzlib_decompress_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_uzlib_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_uzlib_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_uzlib_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_uzlib_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_uzlib = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uzlib,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_uzlib_globals,
|
||||
};
|
||||
|
||||
// Source files #include'd here to make sure they're compiled in
|
||||
// only if module is enabled by config setting.
|
||||
|
||||
#include "uzlib/tinflate.c"
|
||||
#include "uzlib/tinfzlib.c"
|
||||
#include "uzlib/adler32.c"
|
||||
|
||||
#endif // MICROPY_PY_UZLIB
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* 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,
|
||||
(mz_uint8*) 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
|
||||
13
extmod/re1.5/charclass.c
Normal file
13
extmod/re1.5/charclass.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "re1.5.h"
|
||||
|
||||
int _re1_5_classmatch(const char *pc, const char *sp)
|
||||
{
|
||||
// pc points to "cnt" byte after opcode
|
||||
int is_positive = (pc[-1] == Class);
|
||||
int cnt = *pc++;
|
||||
while (cnt--) {
|
||||
if (*sp >= *pc && *sp <= pc[1]) return is_positive;
|
||||
pc += 2;
|
||||
}
|
||||
return !is_positive;
|
||||
}
|
||||
249
extmod/re1.5/compilecode.c
Normal file
249
extmod/re1.5/compilecode.c
Normal file
@@ -0,0 +1,249 @@
|
||||
// Copyright 2014 Paul Sokolovsky.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "re1.5.h"
|
||||
|
||||
static void insert_code(char *code, int at, int num, int *pc)
|
||||
{
|
||||
memmove(code + at + num, code + at, *pc - at);
|
||||
*pc += num;
|
||||
}
|
||||
|
||||
#define REL(at, to) (to - at - 2)
|
||||
|
||||
int re1_5_sizecode(const char *re)
|
||||
{
|
||||
int pc = 5 + NON_ANCHORED_PREFIX; // Save 0, Save 1, Match; more bytes for "search" (vs "match") prefix code
|
||||
|
||||
for (; *re; re++) {
|
||||
switch (*re) {
|
||||
case '\\':
|
||||
re++;
|
||||
default:
|
||||
pc += 2;
|
||||
break;
|
||||
case '+':
|
||||
// Skip entire "+?"
|
||||
if (re[1] == '?')
|
||||
re++;
|
||||
case '?':
|
||||
pc += 2;
|
||||
break;
|
||||
case '.':
|
||||
case '^':
|
||||
case '$':
|
||||
pc++;
|
||||
break;
|
||||
case '*':
|
||||
// Skip entire "*?"
|
||||
if (re[1] == '?')
|
||||
re++;
|
||||
case '|':
|
||||
case '(':
|
||||
pc += 4;
|
||||
break;
|
||||
case ')':
|
||||
break;
|
||||
case '[': {
|
||||
pc += 2;
|
||||
re++;
|
||||
if (*re == '^') re++;
|
||||
while (*re != ']') {
|
||||
if (!*re) return -1;
|
||||
if (re[1] == '-') {
|
||||
re += 2;
|
||||
}
|
||||
pc += 2;
|
||||
re++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
#define EMIT(at, byte) code[at] = byte
|
||||
|
||||
const char *_compilecode(const char *re, ByteProg *prog)
|
||||
{
|
||||
char *code = prog->insts;
|
||||
int pc = prog->bytelen;
|
||||
int start = pc;
|
||||
int term = pc;
|
||||
int alt_label = 0;
|
||||
|
||||
for (; *re && *re != ')'; re++) {
|
||||
switch (*re) {
|
||||
case '\\':
|
||||
re++;
|
||||
default:
|
||||
term = pc;
|
||||
EMIT(pc++, Char);
|
||||
EMIT(pc++, *re);
|
||||
prog->len++;
|
||||
break;
|
||||
case '.':
|
||||
term = pc;
|
||||
EMIT(pc++, Any);
|
||||
prog->len++;
|
||||
break;
|
||||
case '[': {
|
||||
int cnt;
|
||||
term = pc;
|
||||
re++;
|
||||
if (*re == '^') {
|
||||
EMIT(pc++, ClassNot);
|
||||
re++;
|
||||
} else {
|
||||
EMIT(pc++, Class);
|
||||
}
|
||||
pc++; // Skip # of pair byte
|
||||
prog->len++;
|
||||
for (cnt = 0; *re != ']'; re++, cnt++) {
|
||||
if (!*re) return NULL;
|
||||
EMIT(pc++, *re);
|
||||
if (re[1] == '-') {
|
||||
re += 2;
|
||||
}
|
||||
EMIT(pc++, *re);
|
||||
}
|
||||
EMIT(term + 1, cnt);
|
||||
break;
|
||||
}
|
||||
case '(':
|
||||
term = pc;
|
||||
|
||||
EMIT(pc++, Save);
|
||||
EMIT(pc++, 2 * ++prog->sub);
|
||||
prog->len++;
|
||||
|
||||
prog->bytelen = pc;
|
||||
re = _compilecode(re + 1, prog);
|
||||
pc = prog->bytelen;
|
||||
|
||||
EMIT(pc++, Save);
|
||||
EMIT(pc++, 2 * prog->sub + 1);
|
||||
prog->len++;
|
||||
|
||||
break;
|
||||
case '?':
|
||||
insert_code(code, term, 2, &pc);
|
||||
EMIT(term, Split);
|
||||
EMIT(term + 1, REL(term, pc));
|
||||
prog->len++;
|
||||
break;
|
||||
case '*':
|
||||
insert_code(code, term, 2, &pc);
|
||||
EMIT(pc, Jmp);
|
||||
EMIT(pc + 1, REL(pc, term));
|
||||
pc += 2;
|
||||
if (re[1] == '?') {
|
||||
EMIT(term, RSplit);
|
||||
re++;
|
||||
} else {
|
||||
EMIT(term, Split);
|
||||
}
|
||||
EMIT(term + 1, REL(term, pc));
|
||||
prog->len += 2;
|
||||
break;
|
||||
case '+':
|
||||
if (re[1] == '?') {
|
||||
EMIT(pc, Split);
|
||||
re++;
|
||||
} else {
|
||||
EMIT(pc, RSplit);
|
||||
}
|
||||
EMIT(pc + 1, REL(pc, term));
|
||||
pc += 2;
|
||||
prog->len++;
|
||||
break;
|
||||
case '|':
|
||||
if (alt_label) {
|
||||
EMIT(alt_label, REL(alt_label, pc) + 1);
|
||||
}
|
||||
insert_code(code, start, 2, &pc);
|
||||
EMIT(pc++, Jmp);
|
||||
alt_label = pc++;
|
||||
EMIT(start, Split);
|
||||
EMIT(start + 1, REL(start, pc));
|
||||
prog->len += 2;
|
||||
break;
|
||||
case '^':
|
||||
EMIT(pc++, Bol);
|
||||
prog->len++;
|
||||
break;
|
||||
case '$':
|
||||
EMIT(pc++, Eol);
|
||||
prog->len++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alt_label) {
|
||||
EMIT(alt_label, REL(alt_label, pc) + 1);
|
||||
}
|
||||
prog->bytelen = pc;
|
||||
return re;
|
||||
}
|
||||
|
||||
int re1_5_compilecode(ByteProg *prog, const char *re)
|
||||
{
|
||||
prog->len = 0;
|
||||
prog->bytelen = 0;
|
||||
prog->sub = 0;
|
||||
|
||||
// Add code to implement non-anchored operation ("search"),
|
||||
// for anchored operation ("match"), this code will be just skipped.
|
||||
// TODO: Implement search in much more efficient manner
|
||||
prog->insts[prog->bytelen++] = RSplit;
|
||||
prog->insts[prog->bytelen++] = 3;
|
||||
prog->insts[prog->bytelen++] = Any;
|
||||
prog->insts[prog->bytelen++] = Jmp;
|
||||
prog->insts[prog->bytelen++] = -5;
|
||||
prog->len += 3;
|
||||
|
||||
prog->insts[prog->bytelen++] = Save;
|
||||
prog->insts[prog->bytelen++] = 0;
|
||||
prog->len++;
|
||||
|
||||
_compilecode(re, prog);
|
||||
|
||||
prog->insts[prog->bytelen++] = Save;
|
||||
prog->insts[prog->bytelen++] = 1;
|
||||
prog->len++;
|
||||
|
||||
prog->insts[prog->bytelen++] = Match;
|
||||
prog->len++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
cleanmarks(ByteProg *prog)
|
||||
{
|
||||
char *pc = prog->insts;
|
||||
char *end = pc + prog->bytelen;
|
||||
while (pc < end) {
|
||||
*pc &= 0x7f;
|
||||
switch (*pc) {
|
||||
case Jmp:
|
||||
case Split:
|
||||
case RSplit:
|
||||
case Save:
|
||||
case Char:
|
||||
pc++;
|
||||
}
|
||||
pc++;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int pc = 0;
|
||||
ByteProg *code = re1_5_compilecode(argv[1]);
|
||||
re1_5_dumpcode(code);
|
||||
}
|
||||
#endif
|
||||
62
extmod/re1.5/dumpcode.c
Normal file
62
extmod/re1.5/dumpcode.c
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2014 Paul Sokolovsky.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "re1.5.h"
|
||||
|
||||
void re1_5_dumpcode(ByteProg *prog)
|
||||
{
|
||||
int pc = 0;
|
||||
char *code = prog->insts;
|
||||
while (pc < prog->bytelen) {
|
||||
printf("%2d: ", pc);
|
||||
switch(code[pc++]) {
|
||||
default:
|
||||
assert(0);
|
||||
// re1_5_fatal("printprog");
|
||||
case Split:
|
||||
printf("split %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]);
|
||||
pc++;
|
||||
break;
|
||||
case RSplit:
|
||||
printf("rsplit %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]);
|
||||
pc++;
|
||||
break;
|
||||
case Jmp:
|
||||
printf("jmp %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]);
|
||||
pc++;
|
||||
break;
|
||||
case Char:
|
||||
printf("char %c\n", code[pc++]);
|
||||
break;
|
||||
case Any:
|
||||
printf("any\n");
|
||||
break;
|
||||
case Class:
|
||||
case ClassNot: {
|
||||
int num = code[pc];
|
||||
printf("class%s %d", (code[pc - 1] == ClassNot ? "not" : ""), num);
|
||||
pc++;
|
||||
while (num--) {
|
||||
printf(" 0x%02x-0x%02x", code[pc], code[pc + 1]);
|
||||
pc += 2;
|
||||
}
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
case Match:
|
||||
printf("match\n");
|
||||
break;
|
||||
case Save:
|
||||
printf("save %d\n", (unsigned char)code[pc++]);
|
||||
break;
|
||||
case Bol:
|
||||
printf("assert bol\n");
|
||||
break;
|
||||
case Eol:
|
||||
printf("assert eol\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("Bytes: %d, insts: %d\n", prog->bytelen, prog->len);
|
||||
}
|
||||
149
extmod/re1.5/re1.5.h
Normal file
149
extmod/re1.5/re1.5.h
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright 2007-2009 Russ Cox. All Rights Reserved.
|
||||
// Copyright 2014 Paul Sokolovsky.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef _RE1_5_REGEXP__H
|
||||
#define _RE1_5_REGEXP__H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define nil ((void*)0)
|
||||
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
typedef struct Regexp Regexp;
|
||||
typedef struct Prog Prog;
|
||||
typedef struct ByteProg ByteProg;
|
||||
typedef struct Inst Inst;
|
||||
typedef struct Subject Subject;
|
||||
|
||||
struct Regexp
|
||||
{
|
||||
int type;
|
||||
int n;
|
||||
int ch;
|
||||
Regexp *left;
|
||||
Regexp *right;
|
||||
};
|
||||
|
||||
enum /* Regexp.type */
|
||||
{
|
||||
Alt = 1,
|
||||
Cat,
|
||||
Lit,
|
||||
Dot,
|
||||
Paren,
|
||||
Quest,
|
||||
Star,
|
||||
Plus,
|
||||
};
|
||||
|
||||
Regexp *parse(char*);
|
||||
Regexp *reg(int type, Regexp *left, Regexp *right);
|
||||
void printre(Regexp*);
|
||||
#ifndef re1_5_fatal
|
||||
void re1_5_fatal(char*);
|
||||
#endif
|
||||
void *mal(int);
|
||||
|
||||
struct Prog
|
||||
{
|
||||
Inst *start;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct ByteProg
|
||||
{
|
||||
int bytelen;
|
||||
int len;
|
||||
int sub;
|
||||
char insts[0];
|
||||
};
|
||||
|
||||
struct Inst
|
||||
{
|
||||
int opcode;
|
||||
int c;
|
||||
int n;
|
||||
Inst *x;
|
||||
Inst *y;
|
||||
int gen; // global state, oooh!
|
||||
};
|
||||
|
||||
enum /* Inst.opcode */
|
||||
{
|
||||
// Instructions which consume input bytes (and thus fail if none left)
|
||||
CONSUMERS = 1,
|
||||
Char = CONSUMERS,
|
||||
Any,
|
||||
Class,
|
||||
ClassNot,
|
||||
|
||||
ASSERTS = 0x50,
|
||||
Bol = ASSERTS,
|
||||
Eol,
|
||||
|
||||
// Instructions which take relative offset as arg
|
||||
JUMPS = 0x60,
|
||||
Jmp = JUMPS,
|
||||
Split,
|
||||
RSplit,
|
||||
|
||||
// Other (special) instructions
|
||||
Save = 0x7e,
|
||||
Match = 0x7f,
|
||||
};
|
||||
|
||||
#define inst_is_consumer(inst) ((inst) < ASSERTS)
|
||||
#define inst_is_jump(inst) ((inst) & 0x70 == JUMPS)
|
||||
|
||||
Prog *compile(Regexp*);
|
||||
void printprog(Prog*);
|
||||
|
||||
extern int gen;
|
||||
|
||||
enum {
|
||||
MAXSUB = 20
|
||||
};
|
||||
|
||||
typedef struct Sub Sub;
|
||||
|
||||
struct Sub
|
||||
{
|
||||
int ref;
|
||||
int nsub;
|
||||
const char *sub[MAXSUB];
|
||||
};
|
||||
|
||||
Sub *newsub(int n);
|
||||
Sub *incref(Sub*);
|
||||
Sub *copy(Sub*);
|
||||
Sub *update(Sub*, int, const char*);
|
||||
void decref(Sub*);
|
||||
|
||||
struct Subject {
|
||||
const char *begin;
|
||||
const char *end;
|
||||
};
|
||||
|
||||
|
||||
#define NON_ANCHORED_PREFIX 5
|
||||
#define HANDLE_ANCHORED(bytecode, is_anchored) ((is_anchored) ? (bytecode) + NON_ANCHORED_PREFIX : (bytecode))
|
||||
|
||||
int re1_5_backtrack(ByteProg*, Subject*, const char**, int, int);
|
||||
int re1_5_pikevm(ByteProg*, Subject*, const char**, int, int);
|
||||
int re1_5_recursiveloopprog(ByteProg*, Subject*, const char**, int, int);
|
||||
int re1_5_recursiveprog(ByteProg*, Subject*, const char**, int, int);
|
||||
int re1_5_thompsonvm(ByteProg*, Subject*, const char**, int, int);
|
||||
|
||||
int re1_5_sizecode(const char *re);
|
||||
int re1_5_compilecode(ByteProg *prog, const char *re);
|
||||
void re1_5_dumpcode(ByteProg *prog);
|
||||
void cleanmarks(ByteProg *prog);
|
||||
int _re1_5_classmatch(const char *pc, const char *sp);
|
||||
|
||||
#endif /*_RE1_5_REGEXP__H*/
|
||||
78
extmod/re1.5/recursiveloop.c
Normal file
78
extmod/re1.5/recursiveloop.c
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2007-2009 Russ Cox. All Rights Reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "re1.5.h"
|
||||
|
||||
static int
|
||||
recursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int nsubp)
|
||||
{
|
||||
const char *old;
|
||||
int off;
|
||||
|
||||
for(;;) {
|
||||
if(inst_is_consumer(*pc)) {
|
||||
// If we need to match a character, but there's none left, it's fail
|
||||
if(sp >= input->end)
|
||||
return 0;
|
||||
}
|
||||
switch(*pc++) {
|
||||
case Char:
|
||||
if(*sp != *pc++)
|
||||
return 0;
|
||||
case Any:
|
||||
sp++;
|
||||
continue;
|
||||
case Class:
|
||||
case ClassNot:
|
||||
if (!_re1_5_classmatch(pc, sp))
|
||||
return 0;
|
||||
pc += *(unsigned char*)pc * 2 + 1;
|
||||
sp++;
|
||||
continue;
|
||||
case Match:
|
||||
return 1;
|
||||
case Jmp:
|
||||
off = (signed char)*pc++;
|
||||
pc = pc + off;
|
||||
continue;
|
||||
case Split:
|
||||
off = (signed char)*pc++;
|
||||
if(recursiveloop(pc, sp, input, subp, nsubp))
|
||||
return 1;
|
||||
pc = pc + off;
|
||||
continue;
|
||||
case RSplit:
|
||||
off = (signed char)*pc++;
|
||||
if(recursiveloop(pc + off, sp, input, subp, nsubp))
|
||||
return 1;
|
||||
continue;
|
||||
case Save:
|
||||
off = (unsigned char)*pc++;
|
||||
if(off >= nsubp) {
|
||||
continue;
|
||||
}
|
||||
old = subp[off];
|
||||
subp[off] = sp;
|
||||
if(recursiveloop(pc, sp, input, subp, nsubp))
|
||||
return 1;
|
||||
subp[off] = old;
|
||||
return 0;
|
||||
case Bol:
|
||||
if(sp != input->begin)
|
||||
return 0;
|
||||
continue;
|
||||
case Eol:
|
||||
if(sp != input->end)
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
re1_5_fatal("recursiveloop");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
re1_5_recursiveloopprog(ByteProg *prog, Subject *input, const char **subp, int nsubp, int is_anchored)
|
||||
{
|
||||
return recursiveloop(HANDLE_ANCHORED(prog->insts, is_anchored), input->begin, input, subp, nsubp);
|
||||
}
|
||||
78
extmod/uzlib/adler32.c
Normal file
78
extmod/uzlib/adler32.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Adler-32 checksum
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adler-32 algorithm taken from the zlib source, which is
|
||||
* Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
#define A32_BASE 65521
|
||||
#define A32_NMAX 5552
|
||||
|
||||
unsigned int tinf_adler32(const void *data, unsigned int length)
|
||||
{
|
||||
const unsigned char *buf = (const unsigned char *)data;
|
||||
|
||||
unsigned int s1 = 1;
|
||||
unsigned int s2 = 0;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
int k = length < A32_NMAX ? length : A32_NMAX;
|
||||
int i;
|
||||
|
||||
for (i = k / 16; i; --i, buf += 16)
|
||||
{
|
||||
s1 += buf[0]; s2 += s1; s1 += buf[1]; s2 += s1;
|
||||
s1 += buf[2]; s2 += s1; s1 += buf[3]; s2 += s1;
|
||||
s1 += buf[4]; s2 += s1; s1 += buf[5]; s2 += s1;
|
||||
s1 += buf[6]; s2 += s1; s1 += buf[7]; s2 += s1;
|
||||
|
||||
s1 += buf[8]; s2 += s1; s1 += buf[9]; s2 += s1;
|
||||
s1 += buf[10]; s2 += s1; s1 += buf[11]; s2 += s1;
|
||||
s1 += buf[12]; s2 += s1; s1 += buf[13]; s2 += s1;
|
||||
s1 += buf[14]; s2 += s1; s1 += buf[15]; s2 += s1;
|
||||
}
|
||||
|
||||
for (i = k % 16; i; --i) { s1 += *buf++; s2 += s1; }
|
||||
|
||||
s1 %= A32_BASE;
|
||||
s2 %= A32_BASE;
|
||||
|
||||
length -= k;
|
||||
}
|
||||
|
||||
return (s2 << 16) | s1;
|
||||
}
|
||||
102
extmod/uzlib/tinf.h
Normal file
102
extmod/uzlib/tinf.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* uzlib - tiny deflate/inflate library (deflate, gzip, zlib)
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* Copyright (c) 2014 by Paul Sokolovsky
|
||||
*/
|
||||
|
||||
#ifndef TINF_H_INCLUDED
|
||||
#define TINF_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* calling convention */
|
||||
#ifndef TINFCC
|
||||
#ifdef __WATCOMC__
|
||||
#define TINFCC __cdecl
|
||||
#else
|
||||
#define TINFCC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TINF_OK 0
|
||||
#define TINF_DATA_ERROR (-3)
|
||||
#define TINF_DEST_OVERFLOW (-4)
|
||||
|
||||
/* data structures */
|
||||
|
||||
typedef struct {
|
||||
unsigned short table[16]; /* table of code length counts */
|
||||
unsigned short trans[288]; /* code -> symbol translation table */
|
||||
} TINF_TREE;
|
||||
|
||||
struct TINF_DATA;
|
||||
typedef struct TINF_DATA {
|
||||
const unsigned char *source;
|
||||
unsigned int tag;
|
||||
unsigned int bitcount;
|
||||
|
||||
/* Buffer start */
|
||||
unsigned char *destStart;
|
||||
/* Buffer total size */
|
||||
unsigned int destSize;
|
||||
/* Current pointer in buffer */
|
||||
unsigned char *dest;
|
||||
/* Remaining bytes in buffer */
|
||||
unsigned int destRemaining;
|
||||
/* Argument is the allocation size which didn't fit into buffer. Note that
|
||||
exact mimumum size to grow buffer by is lastAlloc - destRemaining. But
|
||||
growing by this exact size is ineficient, as the next allocation will
|
||||
fail again. */
|
||||
int (*destGrow)(struct TINF_DATA *data, unsigned int lastAlloc);
|
||||
|
||||
TINF_TREE ltree; /* dynamic length/symbol tree */
|
||||
TINF_TREE dtree; /* dynamic distance tree */
|
||||
} TINF_DATA;
|
||||
|
||||
|
||||
/* low-level API */
|
||||
|
||||
/* Step 1: Allocate TINF_DATA structure */
|
||||
/* Step 2: Set destStart, destSize, and destGrow fields */
|
||||
/* Step 3: Set source field */
|
||||
/* Step 4: Call tinf_uncompress_dyn() */
|
||||
/* Step 5: In response to destGrow callback, update destStart and destSize fields */
|
||||
/* Step 6: When tinf_uncompress_dyn() returns, buf.dest points to a byte past last uncompressed byte */
|
||||
|
||||
int TINFCC tinf_uncompress_dyn(TINF_DATA *d);
|
||||
int TINFCC tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen);
|
||||
|
||||
/* high-level API */
|
||||
|
||||
void TINFCC tinf_init();
|
||||
|
||||
int TINFCC tinf_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
|
||||
int TINFCC tinf_gzip_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
|
||||
int TINFCC tinf_zlib_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
|
||||
unsigned int TINFCC tinf_adler32(const void *data, unsigned int length);
|
||||
|
||||
unsigned int TINFCC tinf_crc32(const void *data, unsigned int length);
|
||||
|
||||
/* compression API */
|
||||
|
||||
void TINFCC tinf_compress(void *data, const uint8_t *src, unsigned slen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* TINF_H_INCLUDED */
|
||||
511
extmod/uzlib/tinflate.c
Normal file
511
extmod/uzlib/tinflate.c
Normal file
@@ -0,0 +1,511 @@
|
||||
/*
|
||||
* tinflate - tiny inflate
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* Copyright (c) 2014 by Paul Sokolovsky
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
/* --------------------------------------------------- *
|
||||
* -- uninitialized global data (static structures) -- *
|
||||
* --------------------------------------------------- */
|
||||
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
|
||||
/* extra bits and base tables for length codes */
|
||||
unsigned char length_bits[30];
|
||||
unsigned short length_base[30];
|
||||
|
||||
/* extra bits and base tables for distance codes */
|
||||
unsigned char dist_bits[30];
|
||||
unsigned short dist_base[30];
|
||||
|
||||
#else
|
||||
|
||||
const unsigned char length_bits[30] = {
|
||||
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
|
||||
};
|
||||
const unsigned short length_base[30] = {
|
||||
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
|
||||
};
|
||||
|
||||
const unsigned char dist_bits[30] = {
|
||||
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
|
||||
};
|
||||
const unsigned short dist_base[30] = {
|
||||
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
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* special ordering of code length codes */
|
||||
const unsigned char clcidx[] = {
|
||||
16, 17, 18, 0, 8, 7, 9, 6,
|
||||
10, 5, 11, 4, 12, 3, 13, 2,
|
||||
14, 1, 15
|
||||
};
|
||||
|
||||
/* ----------------------- *
|
||||
* -- utility functions -- *
|
||||
* ----------------------- */
|
||||
|
||||
/* Execute callback to grow destination buffer */
|
||||
static int tinf_grow_dest_buf(TINF_DATA *d, unsigned int lastAlloc)
|
||||
{
|
||||
unsigned int oldsize = d->dest - d->destStart;
|
||||
/* This will update only destStart and destSize */
|
||||
if (!d->destGrow)
|
||||
{
|
||||
return TINF_DEST_OVERFLOW;
|
||||
}
|
||||
d->destGrow(d, lastAlloc);
|
||||
d->dest = d->destStart + oldsize;
|
||||
d->destRemaining = d->destSize - oldsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
/* build extra bits and base tables */
|
||||
static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first)
|
||||
{
|
||||
int i, sum;
|
||||
|
||||
/* build bits table */
|
||||
for (i = 0; i < delta; ++i) bits[i] = 0;
|
||||
for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta;
|
||||
|
||||
/* build base table */
|
||||
for (sum = first, i = 0; i < 30; ++i)
|
||||
{
|
||||
base[i] = sum;
|
||||
sum += 1 << bits[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* build the fixed huffman trees */
|
||||
static void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* build fixed length tree */
|
||||
for (i = 0; i < 7; ++i) lt->table[i] = 0;
|
||||
|
||||
lt->table[7] = 24;
|
||||
lt->table[8] = 152;
|
||||
lt->table[9] = 112;
|
||||
|
||||
for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i;
|
||||
for (i = 0; i < 144; ++i) lt->trans[24 + i] = i;
|
||||
for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i;
|
||||
for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i;
|
||||
|
||||
/* build fixed distance tree */
|
||||
for (i = 0; i < 5; ++i) dt->table[i] = 0;
|
||||
|
||||
dt->table[5] = 32;
|
||||
|
||||
for (i = 0; i < 32; ++i) dt->trans[i] = i;
|
||||
}
|
||||
|
||||
/* given an array of code lengths, build a tree */
|
||||
static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num)
|
||||
{
|
||||
unsigned short offs[16];
|
||||
unsigned int i, sum;
|
||||
|
||||
/* clear code length count table */
|
||||
for (i = 0; i < 16; ++i) t->table[i] = 0;
|
||||
|
||||
/* scan symbol lengths, and sum code length counts */
|
||||
for (i = 0; i < num; ++i) t->table[lengths[i]]++;
|
||||
|
||||
t->table[0] = 0;
|
||||
|
||||
/* compute offset table for distribution sort */
|
||||
for (sum = 0, i = 0; i < 16; ++i)
|
||||
{
|
||||
offs[i] = sum;
|
||||
sum += t->table[i];
|
||||
}
|
||||
|
||||
/* create code->symbol translation table (symbols sorted by code) */
|
||||
for (i = 0; i < num; ++i)
|
||||
{
|
||||
if (lengths[i]) t->trans[offs[lengths[i]]++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------- *
|
||||
* -- decode functions -- *
|
||||
* ---------------------- */
|
||||
|
||||
/* get one bit from source stream */
|
||||
static int tinf_getbit(TINF_DATA *d)
|
||||
{
|
||||
unsigned int bit;
|
||||
|
||||
/* check if tag is empty */
|
||||
if (!d->bitcount--)
|
||||
{
|
||||
/* load next tag */
|
||||
d->tag = *d->source++;
|
||||
d->bitcount = 7;
|
||||
}
|
||||
|
||||
/* shift bit out of tag */
|
||||
bit = d->tag & 0x01;
|
||||
d->tag >>= 1;
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
/* read a num bit value from a stream and add base */
|
||||
static unsigned int tinf_read_bits(TINF_DATA *d, int num, int base)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
/* read num bits */
|
||||
if (num)
|
||||
{
|
||||
unsigned int limit = 1 << (num);
|
||||
unsigned int mask;
|
||||
|
||||
for (mask = 1; mask < limit; mask *= 2)
|
||||
if (tinf_getbit(d)) val += mask;
|
||||
}
|
||||
|
||||
return val + base;
|
||||
}
|
||||
|
||||
/* given a data stream and a tree, decode a symbol */
|
||||
static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)
|
||||
{
|
||||
int sum = 0, cur = 0, len = 0;
|
||||
|
||||
/* get more bits while code value is above sum */
|
||||
do {
|
||||
|
||||
cur = 2*cur + tinf_getbit(d);
|
||||
|
||||
++len;
|
||||
|
||||
sum += t->table[len];
|
||||
cur -= t->table[len];
|
||||
|
||||
} while (cur >= 0);
|
||||
|
||||
return t->trans[sum + cur];
|
||||
}
|
||||
|
||||
/* given a data stream, decode dynamic trees from it */
|
||||
static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
|
||||
{
|
||||
unsigned char lengths[288+32];
|
||||
unsigned int hlit, hdist, hclen;
|
||||
unsigned int i, num, length;
|
||||
|
||||
/* get 5 bits HLIT (257-286) */
|
||||
hlit = tinf_read_bits(d, 5, 257);
|
||||
|
||||
/* get 5 bits HDIST (1-32) */
|
||||
hdist = tinf_read_bits(d, 5, 1);
|
||||
|
||||
/* get 4 bits HCLEN (4-19) */
|
||||
hclen = tinf_read_bits(d, 4, 4);
|
||||
|
||||
for (i = 0; i < 19; ++i) lengths[i] = 0;
|
||||
|
||||
/* read code lengths for code length alphabet */
|
||||
for (i = 0; i < hclen; ++i)
|
||||
{
|
||||
/* get 3 bits code length (0-7) */
|
||||
unsigned int clen = tinf_read_bits(d, 3, 0);
|
||||
|
||||
lengths[clcidx[i]] = clen;
|
||||
}
|
||||
|
||||
/* build code length tree, temporarily use length tree */
|
||||
tinf_build_tree(lt, lengths, 19);
|
||||
|
||||
/* decode code lengths for the dynamic trees */
|
||||
for (num = 0; num < hlit + hdist; )
|
||||
{
|
||||
int sym = tinf_decode_symbol(d, lt);
|
||||
|
||||
switch (sym)
|
||||
{
|
||||
case 16:
|
||||
/* copy previous code length 3-6 times (read 2 bits) */
|
||||
{
|
||||
unsigned char prev = lengths[num - 1];
|
||||
for (length = tinf_read_bits(d, 2, 3); length; --length)
|
||||
{
|
||||
lengths[num++] = prev;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 17:
|
||||
/* repeat code length 0 for 3-10 times (read 3 bits) */
|
||||
for (length = tinf_read_bits(d, 3, 3); length; --length)
|
||||
{
|
||||
lengths[num++] = 0;
|
||||
}
|
||||
break;
|
||||
case 18:
|
||||
/* repeat code length 0 for 11-138 times (read 7 bits) */
|
||||
for (length = tinf_read_bits(d, 7, 11); length; --length)
|
||||
{
|
||||
lengths[num++] = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* values 0-15 represent the actual code lengths */
|
||||
lengths[num++] = sym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build dynamic trees */
|
||||
tinf_build_tree(lt, lengths, hlit);
|
||||
tinf_build_tree(dt, lengths + hlit, hdist);
|
||||
}
|
||||
|
||||
/* ----------------------------- *
|
||||
* -- block inflate functions -- *
|
||||
* ----------------------------- */
|
||||
|
||||
/* given a stream and two trees, inflate a block of data */
|
||||
static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int sym = tinf_decode_symbol(d, lt);
|
||||
|
||||
/* check for end of block */
|
||||
if (sym == 256)
|
||||
{
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
if (sym < 256)
|
||||
{
|
||||
if (d->destRemaining == 0)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, 1);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
*d->dest++ = sym;
|
||||
|
||||
} else {
|
||||
|
||||
int length, dist, offs;
|
||||
int i;
|
||||
|
||||
sym -= 257;
|
||||
|
||||
/* possibly get more bits from length code */
|
||||
length = tinf_read_bits(d, length_bits[sym], length_base[sym]);
|
||||
|
||||
dist = tinf_decode_symbol(d, dt);
|
||||
|
||||
/* possibly get more bits from distance code */
|
||||
offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
|
||||
|
||||
if (d->destRemaining < length)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, length);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
/* copy match */
|
||||
for (i = 0; i < length; ++i)
|
||||
{
|
||||
d->dest[i] = d->dest[i - offs];
|
||||
}
|
||||
|
||||
d->dest += length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* inflate an uncompressed block of data */
|
||||
static int tinf_inflate_uncompressed_block(TINF_DATA *d)
|
||||
{
|
||||
unsigned int length, invlength;
|
||||
unsigned int i;
|
||||
|
||||
/* get length */
|
||||
length = d->source[1];
|
||||
length = 256*length + d->source[0];
|
||||
|
||||
/* get one's complement of length */
|
||||
invlength = d->source[3];
|
||||
invlength = 256*invlength + d->source[2];
|
||||
|
||||
/* check length */
|
||||
if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;
|
||||
|
||||
if (d->destRemaining < length)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, length);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
d->source += 4;
|
||||
|
||||
/* copy block */
|
||||
for (i = length; i; --i) *d->dest++ = *d->source++;
|
||||
|
||||
/* make sure we start next block on a byte boundary */
|
||||
d->bitcount = 0;
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
/* inflate a block of data compressed with fixed huffman trees */
|
||||
static int tinf_inflate_fixed_block(TINF_DATA *d)
|
||||
{
|
||||
/* build fixed huffman trees */
|
||||
tinf_build_fixed_trees(&d->ltree, &d->dtree);
|
||||
|
||||
/* decode block using fixed trees */
|
||||
return tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||
}
|
||||
|
||||
/* inflate a block of data compressed with dynamic huffman trees */
|
||||
static int tinf_inflate_dynamic_block(TINF_DATA *d)
|
||||
{
|
||||
/* decode trees from stream */
|
||||
tinf_decode_trees(d, &d->ltree, &d->dtree);
|
||||
|
||||
/* decode block using decoded trees */
|
||||
return tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||
}
|
||||
|
||||
/* ---------------------- *
|
||||
* -- public functions -- *
|
||||
* ---------------------- */
|
||||
|
||||
/* initialize global (static) data */
|
||||
void tinf_init()
|
||||
{
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
/* build extra bits and base tables */
|
||||
tinf_build_bits_base(length_bits, length_base, 4, 3);
|
||||
tinf_build_bits_base(dist_bits, dist_base, 2, 1);
|
||||
|
||||
/* fix a special case */
|
||||
length_bits[28] = 0;
|
||||
length_base[28] = 258;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* inflate stream from source to dest */
|
||||
int tinf_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen)
|
||||
{
|
||||
TINF_DATA d;
|
||||
int res;
|
||||
|
||||
/* initialise data */
|
||||
d.source = (const unsigned char *)source;
|
||||
|
||||
d.destStart = (unsigned char *)dest;
|
||||
d.destRemaining = *destLen;
|
||||
|
||||
res = tinf_uncompress_dyn(&d);
|
||||
|
||||
*destLen = d.dest - d.destStart;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* inflate stream from source to dest */
|
||||
int tinf_uncompress_dyn(TINF_DATA *d)
|
||||
{
|
||||
int bfinal;
|
||||
|
||||
/* initialise data */
|
||||
d->bitcount = 0;
|
||||
|
||||
d->dest = d->destStart;
|
||||
d->destRemaining = d->destSize;
|
||||
|
||||
do {
|
||||
|
||||
unsigned int btype;
|
||||
int res;
|
||||
|
||||
/* read final block flag */
|
||||
bfinal = tinf_getbit(d);
|
||||
|
||||
/* read block type (2 bits) */
|
||||
btype = tinf_read_bits(d, 2, 0);
|
||||
|
||||
/* decompress block */
|
||||
switch (btype)
|
||||
{
|
||||
case 0:
|
||||
/* decompress uncompressed block */
|
||||
res = tinf_inflate_uncompressed_block(d);
|
||||
break;
|
||||
case 1:
|
||||
/* decompress block with fixed huffman trees */
|
||||
res = tinf_inflate_fixed_block(d);
|
||||
break;
|
||||
case 2:
|
||||
/* decompress block with dynamic huffman trees */
|
||||
res = tinf_inflate_dynamic_block(d);
|
||||
break;
|
||||
default:
|
||||
return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
if (res != TINF_OK) return TINF_DATA_ERROR;
|
||||
|
||||
} while (!bfinal);
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
101
extmod/uzlib/tinfzlib.c
Normal file
101
extmod/uzlib/tinfzlib.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* tinfzlib - tiny zlib decompressor
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
int tinf_zlib_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen)
|
||||
{
|
||||
TINF_DATA d;
|
||||
int res;
|
||||
|
||||
/* initialise data */
|
||||
d.source = (const unsigned char *)source;
|
||||
|
||||
d.destStart = (unsigned char *)dest;
|
||||
d.destRemaining = *destLen;
|
||||
|
||||
res = tinf_zlib_uncompress_dyn(&d, sourceLen);
|
||||
|
||||
*destLen = d.dest - d.destStart;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen)
|
||||
{
|
||||
unsigned int a32;
|
||||
int res;
|
||||
unsigned char cmf, flg;
|
||||
|
||||
/* -- get header bytes -- */
|
||||
|
||||
cmf = d->source[0];
|
||||
flg = d->source[1];
|
||||
|
||||
/* -- check format -- */
|
||||
|
||||
/* check checksum */
|
||||
if ((256*cmf + flg) % 31) return TINF_DATA_ERROR;
|
||||
|
||||
/* check method is deflate */
|
||||
if ((cmf & 0x0f) != 8) return TINF_DATA_ERROR;
|
||||
|
||||
/* check window size is valid */
|
||||
if ((cmf >> 4) > 7) return TINF_DATA_ERROR;
|
||||
|
||||
/* check there is no preset dictionary */
|
||||
if (flg & 0x20) return TINF_DATA_ERROR;
|
||||
|
||||
/* -- get adler32 checksum -- */
|
||||
|
||||
a32 = d->source[sourceLen - 4];
|
||||
a32 = 256*a32 + d->source[sourceLen - 3];
|
||||
a32 = 256*a32 + d->source[sourceLen - 2];
|
||||
a32 = 256*a32 + d->source[sourceLen - 1];
|
||||
|
||||
d->source += 2;
|
||||
|
||||
/* -- inflate -- */
|
||||
|
||||
res = tinf_uncompress_dyn(d);
|
||||
|
||||
if (res != TINF_OK) return res;
|
||||
|
||||
/* -- check adler32 checksum -- */
|
||||
|
||||
if (a32 != tinf_adler32(d->destStart, d->dest - d->destStart)) return TINF_DATA_ERROR;
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
93
py/asmarm.c
93
py/asmarm.c
@@ -175,6 +175,21 @@ STATIC uint asm_arm_op_sub_reg(uint rd, uint rn, uint rm) {
|
||||
return 0x0400000 | (rn << 16) | (rd << 12) | rm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_and_reg(uint rd, uint rn, uint rm) {
|
||||
// and rd, rn, rm
|
||||
return 0x0000000 | (rn << 16) | (rd << 12) | rm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_eor_reg(uint rd, uint rn, uint rm) {
|
||||
// eor rd, rn, rm
|
||||
return 0x0200000 | (rn << 16) | (rd << 12) | rm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_orr_reg(uint rd, uint rn, uint rm) {
|
||||
// orr rd, rn, rm
|
||||
return 0x1800000 | (rn << 16) | (rd << 12) | rm;
|
||||
}
|
||||
|
||||
void asm_arm_bkpt(asm_arm_t *as) {
|
||||
// bkpt #0
|
||||
emit_al(as, 0x1200070);
|
||||
@@ -297,10 +312,9 @@ void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn) {
|
||||
emit_al(as, 0x1500000 | (rd << 16) | rn);
|
||||
}
|
||||
|
||||
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
asm_arm_cmp_reg_reg(as, rn, rm); // cmp rn, rm
|
||||
emit(as, asm_arm_op_mov_imm(rd, 1) | ASM_ARM_CC_LT); // movlt rd, #1
|
||||
emit(as, asm_arm_op_mov_imm(rd, 0) | ASM_ARM_CC_GE); // movge rd, #0
|
||||
void asm_arm_setcc_reg(asm_arm_t *as, uint rd, uint cond) {
|
||||
emit(as, asm_arm_op_mov_imm(rd, 1) | cond); // movCOND rd, #1
|
||||
emit(as, asm_arm_op_mov_imm(rd, 0) | (cond ^ (1 << 28))); // mov!COND rd, #0
|
||||
}
|
||||
|
||||
void asm_arm_add_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
@@ -313,11 +327,82 @@ void asm_arm_sub_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
emit_al(as, asm_arm_op_sub_reg(rd, rn, rm));
|
||||
}
|
||||
|
||||
void asm_arm_and_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
// and rd, rn, rm
|
||||
emit_al(as, asm_arm_op_and_reg(rd, rn, rm));
|
||||
}
|
||||
|
||||
void asm_arm_eor_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
// eor rd, rn, rm
|
||||
emit_al(as, asm_arm_op_eor_reg(rd, rn, rm));
|
||||
}
|
||||
|
||||
void asm_arm_orr_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
// orr rd, rn, rm
|
||||
emit_al(as, asm_arm_op_orr_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, ASM_ARM_REG_SP, local_num << 2));
|
||||
}
|
||||
|
||||
void asm_arm_lsl_reg_reg(asm_arm_t *as, uint rd, uint rs) {
|
||||
// mov rd, rd, lsl rs
|
||||
emit_al(as, 0x1a00010 | (rd << 12) | (rs << 8) | rd);
|
||||
}
|
||||
|
||||
void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs) {
|
||||
// mov rd, rd, asr rs
|
||||
emit_al(as, 0x1a00050 | (rd << 12) | (rs << 8) | rd);
|
||||
}
|
||||
|
||||
void asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn) {
|
||||
// ldr rd, [rn]
|
||||
emit_al(as, 0x5900000 | (rn << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn) {
|
||||
// ldrh rd, [rn]
|
||||
emit_al(as, 0x1d000b0 | (rn << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn) {
|
||||
// ldrb rd, [rn]
|
||||
emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm) {
|
||||
// str rd, [rm]
|
||||
emit_al(as, 0x5800000 | (rm << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm) {
|
||||
// strh rd, [rm]
|
||||
emit_al(as, 0x1c000b0 | (rm << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm) {
|
||||
// strb rd, [rm]
|
||||
emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {
|
||||
// str rd, [rm, rn, lsl #2]
|
||||
emit_al(as, 0x7800100 | (rm << 16) | (rd << 12) | rn);
|
||||
}
|
||||
|
||||
void asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {
|
||||
// strh doesn't support scaled register index
|
||||
emit_al(as, 0x1a00080 | (ASM_ARM_REG_R8 << 12) | rn); // mov r8, rn, lsl #1
|
||||
emit_al(as, 0x18000b0 | (rm << 16) | (rd << 12) | ASM_ARM_REG_R8); // strh rd, [rm, r8]
|
||||
}
|
||||
|
||||
void asm_arm_strb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {
|
||||
// strb rd, [rm, rn]
|
||||
emit_al(as, 0x7c00000 | (rm << 16) | (rd << 12) | rn);
|
||||
}
|
||||
|
||||
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) {
|
||||
assert(label < as->max_num_labels);
|
||||
mp_uint_t dest = as->label_offsets[label];
|
||||
|
||||
25
py/asmarm.h
25
py/asmarm.h
@@ -81,18 +81,41 @@ 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);
|
||||
|
||||
// mov
|
||||
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_setcc_reg(asm_arm_t *as, uint rd, uint cond);
|
||||
|
||||
// compare
|
||||
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, uint rm);
|
||||
|
||||
// arithmetic
|
||||
void asm_arm_add_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_sub_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_and_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_eor_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_orr_reg_reg_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_lsl_reg_reg(asm_arm_t *as, uint rd, uint rs);
|
||||
void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs);
|
||||
|
||||
// memory
|
||||
void asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm);
|
||||
void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm);
|
||||
void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm);
|
||||
// store to array
|
||||
void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn);
|
||||
void asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn);
|
||||
void asm_arm_strb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn);
|
||||
|
||||
// control flow
|
||||
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);
|
||||
|
||||
46
py/asmx64.c
46
py/asmx64.c
@@ -51,8 +51,12 @@
|
||||
#define OPCODE_MOV_I32_TO_RM32 (0xc7)
|
||||
#define OPCODE_MOV_R8_TO_RM8 (0x88) /* /r */
|
||||
#define OPCODE_MOV_R64_TO_RM64 (0x89) /* /r */
|
||||
#define OPCODE_MOV_RM64_TO_R64 (0x8b)
|
||||
#define OPCODE_MOV_RM64_TO_R64 (0x8b) /* /r */
|
||||
#define OPCODE_MOVZX_RM8_TO_R64 (0xb6) /* 0x0f 0xb6/r */
|
||||
#define OPCODE_MOVZX_RM16_TO_R64 (0xb7) /* 0x0f 0xb7/r */
|
||||
#define OPCODE_LEA_MEM_TO_R64 (0x8d) /* /r */
|
||||
#define OPCODE_AND_R64_TO_RM64 (0x21) /* /r */
|
||||
#define OPCODE_OR_R64_TO_RM64 (0x09) /* /r */
|
||||
#define OPCODE_XOR_R64_TO_RM64 (0x31) /* /r */
|
||||
#define OPCODE_ADD_R64_TO_RM64 (0x01) /* /r */
|
||||
#define OPCODE_ADD_I32_TO_RM32 (0x81) /* /0 */
|
||||
@@ -300,7 +304,7 @@ void asm_x64_mov_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
|
||||
asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_MOV_R64_TO_RM64);
|
||||
}
|
||||
|
||||
void asm_x64_mov_r8_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
void asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
assert(dest_r64 < 8);
|
||||
if (src_r64 < 8) {
|
||||
asm_x64_write_byte_1(as, OPCODE_MOV_R8_TO_RM8);
|
||||
@@ -310,7 +314,7 @@ void asm_x64_mov_r8_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_d
|
||||
asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_r16_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
void asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
assert(dest_r64 < 8);
|
||||
if (src_r64 < 8) {
|
||||
asm_x64_write_byte_2(as, OP_SIZE_PREFIX, OPCODE_MOV_R64_TO_RM64);
|
||||
@@ -320,14 +324,34 @@ void asm_x64_mov_r16_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_
|
||||
asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_r64_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
void asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
// use REX prefix for 64 bit operation
|
||||
assert(dest_r64 < 8);
|
||||
asm_x64_write_byte_2(as, REX_PREFIX | REX_W | (src_r64 < 8 ? 0 : REX_R), OPCODE_MOV_R64_TO_RM64);
|
||||
asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
assert(src_r64 < 8);
|
||||
if (dest_r64 < 8) {
|
||||
asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R64);
|
||||
} else {
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM8_TO_R64);
|
||||
}
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
assert(src_r64 < 8);
|
||||
if (dest_r64 < 8) {
|
||||
asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R64);
|
||||
} else {
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM16_TO_R64);
|
||||
}
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
// use REX prefix for 64 bit operation
|
||||
assert(src_r64 < 8);
|
||||
asm_x64_write_byte_2(as, REX_PREFIX | REX_W | (dest_r64 < 8 ? 0 : REX_R), OPCODE_MOV_RM64_TO_R64);
|
||||
@@ -385,6 +409,14 @@ void asm_x64_mov_i64_to_r64_aligned(asm_x64_t *as, int64_t src_i64, int dest_r64
|
||||
asm_x64_mov_i64_to_r64(as, src_i64, dest_r64);
|
||||
}
|
||||
|
||||
void asm_x64_and_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
|
||||
asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_AND_R64_TO_RM64);
|
||||
}
|
||||
|
||||
void asm_x64_or_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
|
||||
asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_OR_R64_TO_RM64);
|
||||
}
|
||||
|
||||
void asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
|
||||
asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_XOR_R64_TO_RM64);
|
||||
}
|
||||
@@ -577,11 +609,11 @@ STATIC int asm_x64_local_offset_from_ebp(asm_x64_t *as, int local_num) {
|
||||
}
|
||||
|
||||
void asm_x64_mov_local_to_r64(asm_x64_t *as, int src_local_num, int dest_r64) {
|
||||
asm_x64_mov_disp_to_r64(as, ASM_X64_REG_RBP, asm_x64_local_offset_from_ebp(as, src_local_num), dest_r64);
|
||||
asm_x64_mov_mem64_to_r64(as, ASM_X64_REG_RBP, asm_x64_local_offset_from_ebp(as, src_local_num), dest_r64);
|
||||
}
|
||||
|
||||
void asm_x64_mov_r64_to_local(asm_x64_t *as, int src_r64, int dest_local_num) {
|
||||
asm_x64_mov_r64_to_disp(as, src_r64, ASM_X64_REG_RBP, asm_x64_local_offset_from_ebp(as, dest_local_num));
|
||||
asm_x64_mov_r64_to_mem64(as, src_r64, ASM_X64_REG_RBP, asm_x64_local_offset_from_ebp(as, dest_local_num));
|
||||
}
|
||||
|
||||
void asm_x64_mov_local_addr_to_r64(asm_x64_t *as, int local_num, int dest_r64) {
|
||||
|
||||
11
py/asmx64.h
11
py/asmx64.h
@@ -83,9 +83,14 @@ void asm_x64_mov_r64_r64(asm_x64_t* as, int dest_r64, int src_r64);
|
||||
void asm_x64_mov_i64_to_r64(asm_x64_t* as, int64_t src_i64, int dest_r64);
|
||||
void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64);
|
||||
void asm_x64_mov_i64_to_r64_aligned(asm_x64_t *as, int64_t src_i64, int dest_r64);
|
||||
void asm_x64_mov_r8_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_r16_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_r64_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64);
|
||||
void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64);
|
||||
void asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64);
|
||||
void asm_x64_and_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
|
||||
void asm_x64_or_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
|
||||
void asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
|
||||
void asm_x64_shl_r64_cl(asm_x64_t* as, int dest_r64);
|
||||
void asm_x64_sar_r64_cl(asm_x64_t* as, int dest_r64);
|
||||
|
||||
42
py/asmx86.c
42
py/asmx86.c
@@ -50,9 +50,13 @@
|
||||
#define OPCODE_MOV_I32_TO_R32 (0xb8)
|
||||
//#define OPCODE_MOV_I32_TO_RM32 (0xc7)
|
||||
#define OPCODE_MOV_R8_TO_RM8 (0x88) /* /r */
|
||||
#define OPCODE_MOV_R32_TO_RM32 (0x89)
|
||||
#define OPCODE_MOV_RM32_TO_R32 (0x8b)
|
||||
#define OPCODE_MOV_R32_TO_RM32 (0x89) /* /r */
|
||||
#define OPCODE_MOV_RM32_TO_R32 (0x8b) /* /r */
|
||||
#define OPCODE_MOVZX_RM8_TO_R32 (0xb6) /* 0x0f 0xb6/r */
|
||||
#define OPCODE_MOVZX_RM16_TO_R32 (0xb7) /* 0x0f 0xb7/r */
|
||||
#define OPCODE_LEA_MEM_TO_R32 (0x8d) /* /r */
|
||||
#define OPCODE_AND_R32_TO_RM32 (0x21) /* /r */
|
||||
#define OPCODE_OR_R32_TO_RM32 (0x09) /* /r */
|
||||
#define OPCODE_XOR_R32_TO_RM32 (0x31) /* /r */
|
||||
#define OPCODE_ADD_R32_TO_RM32 (0x01)
|
||||
#define OPCODE_ADD_I32_TO_RM32 (0x81) /* /0 */
|
||||
@@ -242,22 +246,32 @@ void asm_x86_mov_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {
|
||||
asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_MOV_R32_TO_RM32);
|
||||
}
|
||||
|
||||
void asm_x86_mov_r8_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
void asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
asm_x86_write_byte_1(as, OPCODE_MOV_R8_TO_RM8);
|
||||
asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp);
|
||||
}
|
||||
|
||||
void asm_x86_mov_r16_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
void asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
asm_x86_write_byte_2(as, OP_SIZE_PREFIX, OPCODE_MOV_R32_TO_RM32);
|
||||
asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp);
|
||||
}
|
||||
|
||||
void asm_x86_mov_r32_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
void asm_x86_mov_r32_to_mem32(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
asm_x86_write_byte_1(as, OPCODE_MOV_R32_TO_RM32);
|
||||
asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp);
|
||||
}
|
||||
|
||||
STATIC void asm_x86_mov_disp_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {
|
||||
void asm_x86_mov_mem8_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {
|
||||
asm_x86_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R32);
|
||||
asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);
|
||||
}
|
||||
|
||||
void asm_x86_mov_mem16_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {
|
||||
asm_x86_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R32);
|
||||
asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);
|
||||
}
|
||||
|
||||
void asm_x86_mov_mem32_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {
|
||||
asm_x86_write_byte_1(as, OPCODE_MOV_RM32_TO_R32);
|
||||
asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);
|
||||
}
|
||||
@@ -287,6 +301,14 @@ void asm_x86_mov_i32_to_r32_aligned(asm_x86_t *as, int32_t src_i32, int dest_r32
|
||||
asm_x86_mov_i32_to_r32(as, src_i32, dest_r32);
|
||||
}
|
||||
|
||||
void asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {
|
||||
asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_AND_R32_TO_RM32);
|
||||
}
|
||||
|
||||
void asm_x86_or_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {
|
||||
asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_OR_R32_TO_RM32);
|
||||
}
|
||||
|
||||
void asm_x86_xor_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {
|
||||
asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_XOR_R32_TO_RM32);
|
||||
}
|
||||
@@ -464,12 +486,12 @@ void asm_x86_push_arg(asm_x86_t *as, int src_arg_num) {
|
||||
#endif
|
||||
|
||||
void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32) {
|
||||
asm_x86_mov_disp_to_r32(as, ASM_X86_REG_EBP, 2 * WORD_SIZE + src_arg_num * WORD_SIZE, dest_r32);
|
||||
asm_x86_mov_mem32_to_r32(as, ASM_X86_REG_EBP, 2 * WORD_SIZE + src_arg_num * WORD_SIZE, dest_r32);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void asm_x86_mov_r32_to_arg(asm_x86_t *as, int src_r32, int dest_arg_num) {
|
||||
asm_x86_mov_r32_to_disp(as, src_r32, ASM_X86_REG_EBP, 2 * WORD_SIZE + dest_arg_num * WORD_SIZE);
|
||||
asm_x86_mov_r32_to_mem32(as, src_r32, ASM_X86_REG_EBP, 2 * WORD_SIZE + dest_arg_num * WORD_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -489,11 +511,11 @@ STATIC int asm_x86_local_offset_from_ebp(asm_x86_t *as, int local_num) {
|
||||
}
|
||||
|
||||
void asm_x86_mov_local_to_r32(asm_x86_t *as, int src_local_num, int dest_r32) {
|
||||
asm_x86_mov_disp_to_r32(as, ASM_X86_REG_EBP, asm_x86_local_offset_from_ebp(as, src_local_num), dest_r32);
|
||||
asm_x86_mov_mem32_to_r32(as, ASM_X86_REG_EBP, asm_x86_local_offset_from_ebp(as, src_local_num), dest_r32);
|
||||
}
|
||||
|
||||
void asm_x86_mov_r32_to_local(asm_x86_t *as, int src_r32, int dest_local_num) {
|
||||
asm_x86_mov_r32_to_disp(as, src_r32, ASM_X86_REG_EBP, asm_x86_local_offset_from_ebp(as, dest_local_num));
|
||||
asm_x86_mov_r32_to_mem32(as, src_r32, ASM_X86_REG_EBP, asm_x86_local_offset_from_ebp(as, dest_local_num));
|
||||
}
|
||||
|
||||
void asm_x86_mov_local_addr_to_r32(asm_x86_t *as, int local_num, int dest_r32) {
|
||||
|
||||
11
py/asmx86.h
11
py/asmx86.h
@@ -80,9 +80,14 @@ void* asm_x86_get_code(asm_x86_t* as);
|
||||
void asm_x86_mov_r32_r32(asm_x86_t* as, int dest_r32, int src_r32);
|
||||
void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32);
|
||||
void asm_x86_mov_i32_to_r32_aligned(asm_x86_t *as, int32_t src_i32, int dest_r32);
|
||||
void asm_x86_mov_r8_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_r16_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_r32_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_r32_to_mem32(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_mem8_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32);
|
||||
void asm_x86_mov_mem16_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32);
|
||||
void asm_x86_mov_mem32_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32);
|
||||
void asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
|
||||
void asm_x86_or_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
|
||||
void asm_x86_xor_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
|
||||
void asm_x86_shl_r32_cl(asm_x86_t* as, int dest_r32);
|
||||
void asm_x86_sar_r32_cl(asm_x86_t* as, int dest_r32);
|
||||
|
||||
26
py/bc.c
26
py/bc.c
@@ -75,9 +75,9 @@ STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expecte
|
||||
}
|
||||
|
||||
#if DEBUG_PRINT
|
||||
STATIC void dump_args(const mp_obj_t *a, int sz) {
|
||||
STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) {
|
||||
DEBUG_printf("%p: ", a);
|
||||
for (int i = 0; i < sz; i++) {
|
||||
for (mp_uint_t i = 0; i < sz; i++) {
|
||||
DEBUG_printf("%p ", a[i]);
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
@@ -93,7 +93,6 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
|
||||
// usage for the common case of positional only args.
|
||||
mp_obj_fun_bc_t *self = self_in;
|
||||
mp_uint_t n_state = code_state->n_state;
|
||||
const byte *ip = code_state->ip;
|
||||
|
||||
code_state->code_info = self->bytecode;
|
||||
code_state->sp = &code_state->state[0] - 1;
|
||||
@@ -153,13 +152,21 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
|
||||
*var_pos_kw_args = dict;
|
||||
}
|
||||
|
||||
// get pointer to arg_names array at start of bytecode prelude
|
||||
const mp_obj_t *arg_names;
|
||||
{
|
||||
const byte *code_info = code_state->code_info;
|
||||
mp_uint_t code_info_size = mp_decode_uint(&code_info);
|
||||
arg_names = (const mp_obj_t*)(code_state->code_info + code_info_size);
|
||||
}
|
||||
|
||||
for (mp_uint_t i = 0; i < n_kw; i++) {
|
||||
qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
|
||||
mp_obj_t wanted_arg_name = kwargs[2 * i];
|
||||
for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
|
||||
if (arg_name == self->args[j]) {
|
||||
if (wanted_arg_name == arg_names[j]) {
|
||||
if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function got multiple values for argument '%s'", qstr_str(arg_name)));
|
||||
"function got multiple values for argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(wanted_arg_name))));
|
||||
}
|
||||
code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
|
||||
goto continue2;
|
||||
@@ -179,7 +186,7 @@ continue2:;
|
||||
// fill in defaults for positional args
|
||||
mp_obj_t *d = &code_state->state[n_state - self->n_pos_args];
|
||||
mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
|
||||
for (int i = self->n_def_args; i > 0; i--, d++, s--) {
|
||||
for (mp_uint_t i = self->n_def_args; i > 0; i--, d++, s--) {
|
||||
if (*d == MP_OBJ_NULL) {
|
||||
*d = *s;
|
||||
}
|
||||
@@ -202,13 +209,13 @@ continue2:;
|
||||
if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) {
|
||||
mp_map_elem_t *elem = NULL;
|
||||
if (self->has_def_kw_args) {
|
||||
elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, MP_OBJ_NEW_QSTR(self->args[self->n_pos_args + i]), MP_MAP_LOOKUP);
|
||||
elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, arg_names[self->n_pos_args + i], MP_MAP_LOOKUP);
|
||||
}
|
||||
if (elem != NULL) {
|
||||
code_state->state[n_state - 1 - self->n_pos_args - i] = elem->value;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
|
||||
"function missing required keyword argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(arg_names[self->n_pos_args + i]))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,6 +232,7 @@ continue2:;
|
||||
}
|
||||
|
||||
// bytecode prelude: initialise closed over variables
|
||||
const byte *ip = code_state->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]);
|
||||
|
||||
6
py/bc.h
6
py/bc.h
@@ -42,7 +42,7 @@ typedef struct _mp_code_state {
|
||||
mp_obj_t *sp;
|
||||
// bit 0 is saved currently_in_except_block value
|
||||
mp_exc_stack_t *exc_sp;
|
||||
uint n_state;
|
||||
mp_uint_t n_state;
|
||||
// Variable-length
|
||||
mp_obj_t state[0];
|
||||
// Variable-length, never accessed by name, only as (void*)(state + n_state)
|
||||
@@ -53,8 +53,8 @@ mp_uint_t mp_decode_uint(const byte **ptr);
|
||||
|
||||
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, 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);
|
||||
void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *code, mp_uint_t len);
|
||||
void mp_bytecode_print2(const byte *code, mp_uint_t len);
|
||||
|
||||
// Helper macros to access pointer with least significant bit holding a flag
|
||||
#define MP_TAGPTR_PTR(x) ((void*)((mp_uint_t)(x) & ~((mp_uint_t)1)))
|
||||
|
||||
152
py/bc0.h
152
py/bc0.h
@@ -31,92 +31,90 @@
|
||||
#define MP_BC_LOAD_CONST_NONE (0x11)
|
||||
#define MP_BC_LOAD_CONST_TRUE (0x12)
|
||||
#define MP_BC_LOAD_CONST_ELLIPSIS (0x13)
|
||||
#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // 24-bit, in excess
|
||||
#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // signed var-int
|
||||
#define MP_BC_LOAD_CONST_INT (0x15) // qstr
|
||||
#define MP_BC_LOAD_CONST_DEC (0x16) // qstr
|
||||
#define MP_BC_LOAD_CONST_BYTES (0x18) // qstr
|
||||
#define MP_BC_LOAD_CONST_STRING (0x19) // qstr
|
||||
#define MP_BC_LOAD_NULL (0x1a)
|
||||
#define MP_BC_LOAD_CONST_BYTES (0x17) // qstr
|
||||
#define MP_BC_LOAD_CONST_STRING (0x18) // qstr
|
||||
#define MP_BC_LOAD_NULL (0x19)
|
||||
|
||||
#define MP_BC_LOAD_FAST_0 (0x20)
|
||||
#define MP_BC_LOAD_FAST_1 (0x21)
|
||||
#define MP_BC_LOAD_FAST_2 (0x22)
|
||||
#define MP_BC_LOAD_FAST_N (0x23) // uint
|
||||
#define MP_BC_LOAD_DEREF (0x25) // uint
|
||||
#define MP_BC_LOAD_NAME (0x26) // qstr
|
||||
#define MP_BC_LOAD_GLOBAL (0x27) // qstr
|
||||
#define MP_BC_LOAD_ATTR (0x28) // qstr
|
||||
#define MP_BC_LOAD_METHOD (0x29) // qstr
|
||||
#define MP_BC_LOAD_BUILD_CLASS (0x2a)
|
||||
#define MP_BC_LOAD_SUBSCR (0x2b)
|
||||
#define MP_BC_LOAD_FAST_N (0x1a) // uint
|
||||
#define MP_BC_LOAD_DEREF (0x1b) // uint
|
||||
#define MP_BC_LOAD_NAME (0x1c) // qstr
|
||||
#define MP_BC_LOAD_GLOBAL (0x1d) // qstr
|
||||
#define MP_BC_LOAD_ATTR (0x1e) // qstr
|
||||
#define MP_BC_LOAD_METHOD (0x1f) // qstr
|
||||
#define MP_BC_LOAD_BUILD_CLASS (0x20)
|
||||
#define MP_BC_LOAD_SUBSCR (0x21)
|
||||
|
||||
#define MP_BC_STORE_FAST_0 (0x30)
|
||||
#define MP_BC_STORE_FAST_1 (0x31)
|
||||
#define MP_BC_STORE_FAST_2 (0x32)
|
||||
#define MP_BC_STORE_FAST_N (0x33) // uint
|
||||
#define MP_BC_STORE_DEREF (0x34) // uint
|
||||
#define MP_BC_STORE_NAME (0x35) // qstr
|
||||
#define MP_BC_STORE_GLOBAL (0x36) // qstr
|
||||
#define MP_BC_STORE_ATTR (0x37) // qstr
|
||||
#define MP_BC_STORE_SUBSCR (0x38)
|
||||
#define MP_BC_STORE_FAST_N (0x22) // uint
|
||||
#define MP_BC_STORE_DEREF (0x23) // uint
|
||||
#define MP_BC_STORE_NAME (0x24) // qstr
|
||||
#define MP_BC_STORE_GLOBAL (0x25) // qstr
|
||||
#define MP_BC_STORE_ATTR (0x26) // qstr
|
||||
#define MP_BC_STORE_SUBSCR (0x27)
|
||||
|
||||
#define MP_BC_DELETE_FAST (0x39) // uint
|
||||
#define MP_BC_DELETE_DEREF (0x3a) // uint
|
||||
#define MP_BC_DELETE_NAME (0x3b) // qstr
|
||||
#define MP_BC_DELETE_GLOBAL (0x3c) // qstr
|
||||
#define MP_BC_DELETE_FAST (0x28) // uint
|
||||
#define MP_BC_DELETE_DEREF (0x29) // uint
|
||||
#define MP_BC_DELETE_NAME (0x2a) // qstr
|
||||
#define MP_BC_DELETE_GLOBAL (0x2b) // qstr
|
||||
|
||||
#define MP_BC_DUP_TOP (0x40)
|
||||
#define MP_BC_DUP_TOP_TWO (0x41)
|
||||
#define MP_BC_POP_TOP (0x42)
|
||||
#define MP_BC_ROT_TWO (0x43)
|
||||
#define MP_BC_ROT_THREE (0x44)
|
||||
#define MP_BC_DUP_TOP (0x30)
|
||||
#define MP_BC_DUP_TOP_TWO (0x31)
|
||||
#define MP_BC_POP_TOP (0x32)
|
||||
#define MP_BC_ROT_TWO (0x33)
|
||||
#define MP_BC_ROT_THREE (0x34)
|
||||
|
||||
#define MP_BC_JUMP (0x45) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_POP_JUMP_IF_TRUE (0x46) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_POP_JUMP_IF_FALSE (0x47) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_JUMP_IF_TRUE_OR_POP (0x48) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_JUMP_IF_FALSE_OR_POP (0x49) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_SETUP_WITH (0x4d) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_WITH_CLEANUP (0x4e)
|
||||
#define MP_BC_SETUP_EXCEPT (0x4f) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_SETUP_FINALLY (0x50) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_END_FINALLY (0x51)
|
||||
#define MP_BC_GET_ITER (0x52)
|
||||
#define MP_BC_FOR_ITER (0x53) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_POP_BLOCK (0x54)
|
||||
#define MP_BC_POP_EXCEPT (0x55)
|
||||
#define MP_BC_UNWIND_JUMP (0x56) // rel byte code offset, 16-bit signed, in excess; then a byte
|
||||
#define MP_BC_JUMP (0x35) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_POP_JUMP_IF_TRUE (0x36) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_POP_JUMP_IF_FALSE (0x37) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_JUMP_IF_TRUE_OR_POP (0x38) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_JUMP_IF_FALSE_OR_POP (0x39) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_SETUP_WITH (0x3d) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_WITH_CLEANUP (0x3e)
|
||||
#define MP_BC_SETUP_EXCEPT (0x3f) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_SETUP_FINALLY (0x40) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_END_FINALLY (0x41)
|
||||
#define MP_BC_GET_ITER (0x42)
|
||||
#define MP_BC_FOR_ITER (0x43) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_POP_BLOCK (0x44)
|
||||
#define MP_BC_POP_EXCEPT (0x45)
|
||||
#define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte
|
||||
|
||||
#define MP_BC_NOT (0x60)
|
||||
#define MP_BC_UNARY_OP (0x61) // byte
|
||||
#define MP_BC_BINARY_OP (0x62) // byte
|
||||
#define MP_BC_NOT (0x47)
|
||||
|
||||
#define MP_BC_BUILD_TUPLE (0x70) // uint
|
||||
#define MP_BC_BUILD_LIST (0x71) // uint
|
||||
#define MP_BC_LIST_APPEND (0x72) // uint
|
||||
#define MP_BC_BUILD_MAP (0x73) // uint
|
||||
#define MP_BC_STORE_MAP (0x74)
|
||||
#define MP_BC_MAP_ADD (0x75) // uint
|
||||
#define MP_BC_BUILD_SET (0x76) // uint
|
||||
#define MP_BC_SET_ADD (0x77) // uint
|
||||
#define MP_BC_BUILD_SLICE (0x78) // uint
|
||||
#define MP_BC_UNPACK_SEQUENCE (0x79) // uint
|
||||
#define MP_BC_UNPACK_EX (0x7a) // uint
|
||||
#define MP_BC_BUILD_TUPLE (0x50) // uint
|
||||
#define MP_BC_BUILD_LIST (0x51) // uint
|
||||
#define MP_BC_LIST_APPEND (0x52) // uint
|
||||
#define MP_BC_BUILD_MAP (0x53) // uint
|
||||
#define MP_BC_STORE_MAP (0x54)
|
||||
#define MP_BC_MAP_ADD (0x55) // uint
|
||||
#define MP_BC_BUILD_SET (0x56) // uint
|
||||
#define MP_BC_SET_ADD (0x57) // uint
|
||||
#define MP_BC_BUILD_SLICE (0x58) // uint
|
||||
#define MP_BC_UNPACK_SEQUENCE (0x59) // uint
|
||||
#define MP_BC_UNPACK_EX (0x5a) // uint
|
||||
|
||||
#define MP_BC_RETURN_VALUE (0x80)
|
||||
#define MP_BC_RAISE_VARARGS (0x81) // byte
|
||||
#define MP_BC_YIELD_VALUE (0x82)
|
||||
#define MP_BC_YIELD_FROM (0x83)
|
||||
#define MP_BC_RETURN_VALUE (0x5b)
|
||||
#define MP_BC_RAISE_VARARGS (0x5c) // byte
|
||||
#define MP_BC_YIELD_VALUE (0x5d)
|
||||
#define MP_BC_YIELD_FROM (0x5e)
|
||||
|
||||
#define MP_BC_MAKE_FUNCTION (0x90) // uint
|
||||
#define MP_BC_MAKE_FUNCTION_DEFARGS (0x91) // uint
|
||||
#define MP_BC_MAKE_CLOSURE (0x92) // uint
|
||||
#define MP_BC_MAKE_CLOSURE_DEFARGS (0x93) // uint
|
||||
#define MP_BC_CALL_FUNCTION (0x94) // uint
|
||||
#define MP_BC_CALL_FUNCTION_VAR_KW (0x95) // uint
|
||||
#define MP_BC_CALL_METHOD (0x96) // uint
|
||||
#define MP_BC_CALL_METHOD_VAR_KW (0x97) // uint
|
||||
#define MP_BC_MAKE_FUNCTION (0x60) // uint
|
||||
#define MP_BC_MAKE_FUNCTION_DEFARGS (0x61) // uint
|
||||
#define MP_BC_MAKE_CLOSURE (0x62) // uint
|
||||
#define MP_BC_MAKE_CLOSURE_DEFARGS (0x63) // uint
|
||||
#define MP_BC_CALL_FUNCTION (0x64) // uint
|
||||
#define MP_BC_CALL_FUNCTION_VAR_KW (0x65) // uint
|
||||
#define MP_BC_CALL_METHOD (0x66) // uint
|
||||
#define MP_BC_CALL_METHOD_VAR_KW (0x67) // uint
|
||||
|
||||
#define MP_BC_IMPORT_NAME (0xe0) // qstr
|
||||
#define MP_BC_IMPORT_FROM (0xe1) // qstr
|
||||
#define MP_BC_IMPORT_STAR (0xe2)
|
||||
#define MP_BC_IMPORT_NAME (0x68) // qstr
|
||||
#define MP_BC_IMPORT_FROM (0x69) // qstr
|
||||
#define MP_BC_IMPORT_STAR (0x6a)
|
||||
|
||||
#define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // + N(64)
|
||||
#define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16)
|
||||
#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16)
|
||||
#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(5)
|
||||
#define MP_BC_BINARY_OP_MULTI (0xd5) // + op(35)
|
||||
|
||||
64
py/binary.c
64
py/binary.c
@@ -99,7 +99,7 @@ int mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) {
|
||||
return size;
|
||||
}
|
||||
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) {
|
||||
mp_int_t val = 0;
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
@@ -140,23 +140,23 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
// The long long type is guaranteed to hold at least 64 bits, and size is at
|
||||
// most 8 (for q and Q), so we will always be able to parse the given data
|
||||
// and fit it into a long long.
|
||||
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, byte *p) {
|
||||
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src) {
|
||||
int delta;
|
||||
if (!big_endian) {
|
||||
delta = -1;
|
||||
p += size - 1;
|
||||
src += size - 1;
|
||||
} else {
|
||||
delta = 1;
|
||||
}
|
||||
|
||||
long long val = 0;
|
||||
if (is_signed && *p & 0x80) {
|
||||
if (is_signed && *src & 0x80) {
|
||||
val = -1;
|
||||
}
|
||||
for (uint i = 0; i < size; i++) {
|
||||
val <<= 8;
|
||||
val |= *p;
|
||||
p += delta;
|
||||
val |= *src;
|
||||
src += delta;
|
||||
}
|
||||
|
||||
return val;
|
||||
@@ -201,20 +201,22 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
}
|
||||
}
|
||||
|
||||
void mp_binary_set_int(mp_uint_t 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;
|
||||
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val) {
|
||||
if (MP_ENDIANNESS_LITTLE && !big_endian) {
|
||||
memcpy(dest, &val, val_sz);
|
||||
} else if (MP_ENDIANNESS_BIG && big_endian) {
|
||||
// only copy the least-significant val_sz bytes
|
||||
memcpy(dest, (byte*)&val + sizeof(mp_uint_t) - val_sz, val_sz);
|
||||
} else {
|
||||
in_delta = out_delta = 1;
|
||||
}
|
||||
|
||||
for (uint i = val_sz; i > 0; i--) {
|
||||
*p = *val_ptr;
|
||||
p += out_delta;
|
||||
val_ptr += in_delta;
|
||||
const byte *src;
|
||||
if (MP_ENDIANNESS_LITTLE) {
|
||||
src = (const byte*)&val + val_sz;
|
||||
} else {
|
||||
src = (const byte*)&val + sizeof(mp_uint_t);
|
||||
}
|
||||
while (val_sz--) {
|
||||
*dest++ = *--src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,31 +228,27 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
|
||||
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
|
||||
if (MP_ENDIANNESS_LITTLE) {
|
||||
struct_type = '<';
|
||||
} else {
|
||||
struct_type = '>';
|
||||
}
|
||||
}
|
||||
*ptr = p + size;
|
||||
|
||||
#if MP_ENDIANNESS_BIG
|
||||
#error Not implemented
|
||||
#endif
|
||||
mp_int_t val;
|
||||
byte *in = (byte*)&val;
|
||||
mp_uint_t val;
|
||||
switch (val_type) {
|
||||
case 'O':
|
||||
in = (byte*)&val_in;
|
||||
val = (mp_uint_t)val_in;
|
||||
break;
|
||||
default:
|
||||
val = mp_obj_get_int(val_in);
|
||||
}
|
||||
|
||||
mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, in);
|
||||
mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, val);
|
||||
}
|
||||
|
||||
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
|
||||
void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in) {
|
||||
switch (typecode) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f':
|
||||
@@ -265,7 +263,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, mp_int_t val) {
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val) {
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
((int8_t*)p)[index] = val;
|
||||
|
||||
10
py/binary.h
10
py/binary.h
@@ -29,10 +29,10 @@
|
||||
#define BYTEARRAY_TYPECODE 0
|
||||
|
||||
int mp_binary_get_size(char struct_type, char val_type, mp_uint_t *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, mp_int_t val);
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index);
|
||||
void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in);
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t 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);
|
||||
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, byte *p);
|
||||
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *p, byte *val_ptr);
|
||||
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src);
|
||||
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objstr.h"
|
||||
#include "smallint.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
@@ -253,8 +254,8 @@ STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero"));
|
||||
}
|
||||
mp_obj_t args[2];
|
||||
args[0] = MP_OBJ_NEW_SMALL_INT(i1 / i2);
|
||||
args[1] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
|
||||
args[0] = MP_OBJ_NEW_SMALL_INT(mp_small_int_floor_divide(i1, i2));
|
||||
args[1] = MP_OBJ_NEW_SMALL_INT(mp_small_int_modulo(i1, i2));
|
||||
return mp_obj_new_tuple(2, args);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (MP_OBJ_IS_TYPE(o1_in, &mp_type_float) || MP_OBJ_IS_TYPE(o2_in, &mp_type_float)) {
|
||||
@@ -415,9 +416,9 @@ STATIC mp_obj_t mp_builtin_print(mp_uint_t n_args, const mp_obj_t *args, mp_map_
|
||||
|
||||
pfenv_t pfenv;
|
||||
pfenv.data = stream_obj;
|
||||
pfenv.print_strn = (void (*)(void *, const char *, unsigned int))mp_stream_write;
|
||||
pfenv.print_strn = (void (*)(void *, const char *, mp_uint_t))mp_stream_write;
|
||||
#endif
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
for (mp_uint_t i = 0; i < n_args; i++) {
|
||||
if (i > 0) {
|
||||
#if MICROPY_PY_IO
|
||||
mp_stream_write(stream_obj, sep_data, sep_len);
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args);
|
||||
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj);
|
||||
@@ -35,6 +35,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bin_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_compile_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_dir_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_divmod_obj);
|
||||
@@ -88,5 +89,7 @@ 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;
|
||||
extern const mp_obj_module_t mp_module_uzlib;
|
||||
extern const mp_obj_module_t mp_module_ujson;
|
||||
extern const mp_obj_module_t mp_module_ure;
|
||||
extern const mp_obj_module_t mp_module_uheapq;
|
||||
|
||||
144
py/builtinevex.c
144
py/builtinevex.c
@@ -34,72 +34,120 @@
|
||||
#include "lexerunix.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "objfun.h"
|
||||
#include "parsehelper.h"
|
||||
#include "compile.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
|
||||
STATIC mp_obj_t parse_compile_execute(mp_obj_t o_in, mp_parse_input_kind_t parse_input_kind) {
|
||||
mp_uint_t str_len;
|
||||
const char *str = mp_obj_str_get_data(o_in, &str_len);
|
||||
#if MICROPY_PY_BUILTINS_COMPILE
|
||||
|
||||
// create the lexer
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0);
|
||||
qstr source_name = mp_lexer_source_name(lex);
|
||||
typedef struct _mp_obj_code_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t module_fun;
|
||||
} mp_obj_code_t;
|
||||
|
||||
// parse the string
|
||||
mp_parse_error_kind_t parse_error_kind;
|
||||
mp_parse_node_t pn = mp_parse(lex, parse_input_kind, &parse_error_kind);
|
||||
STATIC const mp_obj_type_t mp_type_code = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_code,
|
||||
};
|
||||
|
||||
if (pn == MP_PARSE_NODE_NULL) {
|
||||
// parse error; raise exception
|
||||
mp_obj_t exc = mp_parse_make_exception(lex, parse_error_kind);
|
||||
mp_lexer_free(lex);
|
||||
nlr_raise(exc);
|
||||
}
|
||||
|
||||
mp_lexer_free(lex);
|
||||
|
||||
// compile the string
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
|
||||
|
||||
if (module_fun == mp_const_none) {
|
||||
// TODO handle compile error correctly
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
// complied successfully, execute it
|
||||
return mp_call_function_0(module_fun);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_builtin_eval(mp_obj_t o_in) {
|
||||
return parse_compile_execute(o_in, MP_PARSE_EVAL_INPUT);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_eval_obj, mp_builtin_eval);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_exec(uint n_args, const mp_obj_t *args) {
|
||||
// Unconditional getting/setting assumes that these operations
|
||||
// are cheap, which is the case when this comment was written.
|
||||
STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_t globals, mp_obj_t locals) {
|
||||
// save context and set new context
|
||||
mp_obj_dict_t *old_globals = mp_globals_get();
|
||||
mp_obj_dict_t *old_locals = mp_locals_get();
|
||||
mp_globals_set(globals);
|
||||
mp_locals_set(locals);
|
||||
|
||||
// a bit of a hack: fun_bc will re-set globals, so need to make sure it's
|
||||
// the correct one
|
||||
if (MP_OBJ_IS_TYPE(self->module_fun, &mp_type_fun_bc)) {
|
||||
mp_obj_fun_bc_t *fun_bc = self->module_fun;
|
||||
fun_bc->globals = globals;
|
||||
}
|
||||
|
||||
// execute code
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_obj_t ret = mp_call_function_0(self->module_fun);
|
||||
nlr_pop();
|
||||
mp_globals_set(old_globals);
|
||||
mp_locals_set(old_locals);
|
||||
return ret;
|
||||
} else {
|
||||
// exception; restore context and re-raise same exception
|
||||
mp_globals_set(old_globals);
|
||||
mp_locals_set(old_locals);
|
||||
nlr_raise(nlr.ret_val);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_builtin_compile(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// get the source
|
||||
mp_uint_t str_len;
|
||||
const char *str = mp_obj_str_get_data(args[0], &str_len);
|
||||
|
||||
// get the filename
|
||||
qstr filename = mp_obj_str_get_qstr(args[1]);
|
||||
|
||||
// create the lexer
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(filename, str, str_len, 0);
|
||||
|
||||
// get the compile mode
|
||||
qstr mode = mp_obj_str_get_qstr(args[2]);
|
||||
mp_parse_input_kind_t parse_input_kind;
|
||||
switch (mode) {
|
||||
case MP_QSTR_single: parse_input_kind = MP_PARSE_SINGLE_INPUT; break;
|
||||
case MP_QSTR_exec: parse_input_kind = MP_PARSE_FILE_INPUT; break;
|
||||
case MP_QSTR_eval: parse_input_kind = MP_PARSE_EVAL_INPUT; break;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad compile mode"));
|
||||
}
|
||||
|
||||
mp_obj_code_t *code = m_new_obj(mp_obj_code_t);
|
||||
code->base.type = &mp_type_code;
|
||||
code->module_fun = mp_parse_compile_execute(lex, parse_input_kind, NULL, NULL);
|
||||
return code;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj, 3, 6, mp_builtin_compile);
|
||||
|
||||
#endif // MICROPY_PY_BUILTINS_COMPILE
|
||||
|
||||
STATIC mp_obj_t eval_exec_helper(mp_uint_t n_args, const mp_obj_t *args, mp_parse_input_kind_t parse_input_kind) {
|
||||
// work out the context
|
||||
mp_obj_dict_t *globals = mp_globals_get();
|
||||
mp_obj_dict_t *locals = mp_locals_get();
|
||||
if (n_args > 1) {
|
||||
mp_obj_t globals = args[1];
|
||||
mp_obj_t locals;
|
||||
globals = args[1];
|
||||
if (n_args > 2) {
|
||||
locals = args[2];
|
||||
} else {
|
||||
locals = globals;
|
||||
}
|
||||
mp_globals_set(globals);
|
||||
mp_locals_set(locals);
|
||||
}
|
||||
mp_obj_t res = parse_compile_execute(args[0], MP_PARSE_FILE_INPUT);
|
||||
// TODO if the above call throws an exception, then we never get to reset the globals/locals
|
||||
mp_globals_set(old_globals);
|
||||
mp_locals_set(old_locals);
|
||||
return res;
|
||||
|
||||
#if MICROPY_PY_BUILTINS_COMPILE
|
||||
if (MP_OBJ_IS_TYPE(args[0], &mp_type_code)) {
|
||||
return code_execute(args[0], globals, locals);
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_uint_t str_len;
|
||||
const char *str = mp_obj_str_get_data(args[0], &str_len);
|
||||
|
||||
// create the lexer
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0);
|
||||
|
||||
return mp_parse_compile_execute(lex, parse_input_kind, globals, locals);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_builtin_eval(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
return eval_exec_helper(n_args, args, MP_PARSE_EVAL_INPUT);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj, 1, 3, mp_builtin_eval);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_exec(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
return eval_exec_helper(n_args, args, MP_PARSE_FILE_INPUT);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj, 1, 3, mp_builtin_exec);
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
#include "builtintables.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -54,6 +55,12 @@
|
||||
|
||||
#define PATH_SEP_CHAR '/'
|
||||
|
||||
bool mp_obj_is_package(mp_obj_t module) {
|
||||
mp_obj_t dest[2];
|
||||
mp_load_method_maybe(module, MP_QSTR___path__, dest);
|
||||
return dest[0] != MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
|
||||
//printf("stat %s\n", vstr_str(path));
|
||||
mp_import_stat_t stat = mp_import_stat(vstr_str(path));
|
||||
@@ -82,7 +89,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d
|
||||
return stat_dir_or_file(dest);
|
||||
} else {
|
||||
// go through each path looking for a directory or file
|
||||
for (int i = 0; i < path_num; i++) {
|
||||
for (mp_uint_t i = 0; i < path_num; i++) {
|
||||
vstr_reset(dest);
|
||||
mp_uint_t p_len;
|
||||
const char *p = mp_obj_str_get_data(path_items[i], &p_len);
|
||||
@@ -111,63 +118,20 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "No module named '%s'", vstr_str(file)));
|
||||
}
|
||||
|
||||
qstr source_name = mp_lexer_source_name(lex);
|
||||
|
||||
// save the old context
|
||||
mp_obj_dict_t *old_locals = mp_locals_get();
|
||||
mp_obj_dict_t *old_globals = mp_globals_get();
|
||||
|
||||
// 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));
|
||||
qstr source_name = mp_lexer_source_name(lex);
|
||||
mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
|
||||
#endif
|
||||
|
||||
// parse the imported script
|
||||
mp_parse_error_kind_t parse_error_kind;
|
||||
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_error_kind);
|
||||
|
||||
if (pn == MP_PARSE_NODE_NULL) {
|
||||
// parse error; clean up and raise exception
|
||||
mp_obj_t exc = mp_parse_make_exception(lex, parse_error_kind);
|
||||
mp_lexer_free(lex);
|
||||
mp_locals_set(old_locals);
|
||||
mp_globals_set(old_globals);
|
||||
nlr_raise(exc);
|
||||
}
|
||||
|
||||
mp_lexer_free(lex);
|
||||
|
||||
// compile the imported script
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
|
||||
|
||||
if (module_fun == mp_const_none) {
|
||||
// TODO handle compile error correctly
|
||||
mp_locals_set(old_locals);
|
||||
mp_globals_set(old_globals);
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "Syntax error in imported module"));
|
||||
}
|
||||
|
||||
// complied successfully, execute it
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
// exception; restore context and re-raise same exception
|
||||
mp_locals_set(old_locals);
|
||||
mp_globals_set(old_globals);
|
||||
nlr_raise(nlr.ret_val);
|
||||
}
|
||||
mp_locals_set(old_locals);
|
||||
mp_globals_set(old_globals);
|
||||
// parse, compile and execute the module in its context
|
||||
mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj);
|
||||
mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals);
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args) {
|
||||
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
#if DEBUG_PRINT
|
||||
DEBUG_printf("__import__:\n");
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
for (mp_uint_t i = 0; i < n_args; i++) {
|
||||
DEBUG_printf(" ");
|
||||
mp_obj_print(args[i], PRINT_REPR);
|
||||
DEBUG_printf("\n");
|
||||
@@ -176,7 +140,7 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args) {
|
||||
|
||||
mp_obj_t module_name = args[0];
|
||||
mp_obj_t fromtuple = mp_const_none;
|
||||
int level = 0;
|
||||
mp_int_t level = 0;
|
||||
if (n_args >= 4) {
|
||||
fromtuple = args[3];
|
||||
if (n_args >= 5) {
|
||||
@@ -294,17 +258,42 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args) {
|
||||
}
|
||||
DEBUG_printf("Current path: %s\n", vstr_str(&path));
|
||||
|
||||
// fail if we couldn't find the file
|
||||
if (stat == MP_IMPORT_STAT_NO_EXIST) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "No module named '%s'", qstr_str(mod_name)));
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
// check if there is a weak link to this module
|
||||
if (i == mod_len) {
|
||||
mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_dict_obj.map, MP_OBJ_NEW_QSTR(mod_name), MP_MAP_LOOKUP);
|
||||
if (el == NULL) {
|
||||
goto no_exist;
|
||||
}
|
||||
// found weak linked module
|
||||
module_obj = el->value;
|
||||
} else {
|
||||
no_exist:
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
// couldn't find the file, so fail
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "No module named '%s'", qstr_str(mod_name)));
|
||||
}
|
||||
} else {
|
||||
// found the file, so get the module
|
||||
module_obj = mp_module_get(mod_name);
|
||||
}
|
||||
|
||||
module_obj = mp_module_get(mod_name);
|
||||
if (module_obj == MP_OBJ_NULL) {
|
||||
// module not already loaded, so load it!
|
||||
|
||||
module_obj = mp_obj_new_module(mod_name);
|
||||
|
||||
// if args[3] (fromtuple) has magic value False, set up
|
||||
// this module for command-line "-m" option (set module's
|
||||
// name to __main__ instead of real name).
|
||||
if (i == mod_len && fromtuple == mp_const_false) {
|
||||
mp_obj_module_t *o = module_obj;
|
||||
mp_obj_dict_store(o->globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
|
||||
}
|
||||
|
||||
if (stat == MP_IMPORT_STAT_DIR) {
|
||||
DEBUG_printf("%s is dir\n", vstr_str(&path));
|
||||
// https://docs.python.org/3/reference/import.html
|
||||
|
||||
@@ -61,6 +61,9 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_int), (mp_obj_t)&mp_type_int },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_list), (mp_obj_t)&mp_type_list },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_map), (mp_obj_t)&mp_type_map },
|
||||
#if MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_memoryview), (mp_obj_t)&mp_type_memoryview },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_object), (mp_obj_t)&mp_type_object },
|
||||
#if MICROPY_PY_BUILTINS_PROPERTY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_property), (mp_obj_t)&mp_type_property },
|
||||
@@ -88,6 +91,9 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&mp_builtin_any_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bin), (mp_obj_t)&mp_builtin_bin_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callable), (mp_obj_t)&mp_builtin_callable_obj },
|
||||
#if MICROPY_PY_BUILTINS_COMPILE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_compile), (mp_obj_t)&mp_builtin_compile_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_chr), (mp_obj_t)&mp_builtin_chr_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dir), (mp_obj_t)&mp_builtin_dir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_divmod), (mp_obj_t)&mp_builtin_divmod_obj },
|
||||
@@ -136,7 +142,6 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RuntimeError), (mp_obj_t)&mp_type_RuntimeError },
|
||||
{ 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 },
|
||||
@@ -203,12 +208,18 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
|
||||
#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 },
|
||||
#if MICROPY_PY_UZLIB
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uzlib), (mp_obj_t)&mp_module_uzlib },
|
||||
#endif
|
||||
#if MICROPY_PY_UJSON
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ujson), (mp_obj_t)&mp_module_ujson },
|
||||
#endif
|
||||
#if MICROPY_PY_URE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ure), (mp_obj_t)&mp_module_ure },
|
||||
#endif
|
||||
#if MICROPY_PY_UHEAPQ
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uheapq), (mp_obj_t)&mp_module_uheapq },
|
||||
#endif
|
||||
|
||||
// extra builtin modules as defined by a port
|
||||
MICROPY_PORT_BUILTIN_MODULES
|
||||
@@ -224,3 +235,20 @@ const mp_obj_dict_t mp_builtin_module_dict_obj = {
|
||||
.table = (mp_map_elem_t*)mp_builtin_module_table,
|
||||
},
|
||||
};
|
||||
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
STATIC const mp_map_elem_t mp_builtin_module_weak_links_table[] = {
|
||||
MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS
|
||||
};
|
||||
|
||||
const mp_obj_dict_t mp_builtin_module_weak_links_dict_obj = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_builtin_module_weak_links_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_builtin_module_weak_links_table),
|
||||
.table = (mp_map_elem_t*)mp_builtin_module_weak_links_table,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -26,3 +26,7 @@
|
||||
|
||||
extern const mp_obj_dict_t mp_builtin_object_dict_obj;
|
||||
extern const mp_obj_dict_t mp_builtin_module_dict_obj;
|
||||
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
extern const mp_obj_dict_t mp_builtin_module_weak_links_dict_obj;
|
||||
#endif
|
||||
|
||||
178
py/compile.c
178
py/compile.c
@@ -62,24 +62,29 @@ typedef enum {
|
||||
#define EMIT_INLINE_ASM(fun) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm))
|
||||
#define EMIT_INLINE_ASM_ARG(fun, ...) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm, __VA_ARGS__))
|
||||
|
||||
// elements in this struct are ordered to make it compact
|
||||
typedef struct _compiler_t {
|
||||
qstr source_file;
|
||||
|
||||
uint8_t is_repl;
|
||||
uint8_t pass; // holds enum type pass_kind_t
|
||||
uint8_t had_error; // try to keep compiler clean from nlr
|
||||
uint8_t func_arg_is_super; // used to compile special case of super() function call
|
||||
uint8_t have_star;
|
||||
|
||||
// try to keep compiler clean from nlr
|
||||
// this is set to an exception object if we have a compile error
|
||||
mp_obj_t compile_error;
|
||||
|
||||
uint next_label;
|
||||
|
||||
uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
|
||||
uint16_t continue_label;
|
||||
int break_continue_except_level;
|
||||
uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
|
||||
|
||||
uint8_t have_star;
|
||||
uint16_t num_dict_params;
|
||||
uint16_t num_default_params;
|
||||
|
||||
uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
|
||||
uint16_t continue_label;
|
||||
uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
|
||||
uint16_t break_continue_except_level;
|
||||
|
||||
scope_t *scope_head;
|
||||
scope_t *scope_cur;
|
||||
|
||||
@@ -91,14 +96,15 @@ typedef struct _compiler_t {
|
||||
} 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
|
||||
mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);
|
||||
// we don't have a 'block' name, so just pass the NULL qstr to indicate this
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line);
|
||||
mp_obj_exception_add_traceback(exc, comp->source_file, (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line, MP_QSTR_NULL);
|
||||
} else {
|
||||
printf(" File \"%s\"\n", qstr_str(comp->source_file));
|
||||
// we don't have a line number, so just pass 0
|
||||
mp_obj_exception_add_traceback(exc, comp->source_file, 0, MP_QSTR_NULL);
|
||||
}
|
||||
printf("SyntaxError: %s\n", msg);
|
||||
comp->had_error = true;
|
||||
comp->compile_error = exc;
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t mp_constants_table[] = {
|
||||
@@ -493,14 +499,14 @@ STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vst
|
||||
return;
|
||||
}
|
||||
|
||||
int 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: assert(0);
|
||||
case MP_PARSE_NODE_INTEGER: vstr_printf(vstr, "%s", qstr_str(arg)); break;
|
||||
case MP_PARSE_NODE_DECIMAL: vstr_printf(vstr, "%s", qstr_str(arg)); break;
|
||||
case MP_PARSE_NODE_STRING:
|
||||
case MP_PARSE_NODE_BYTES: {
|
||||
uint len;
|
||||
mp_uint_t len;
|
||||
const byte *str = qstr_data(arg, &len);
|
||||
cpython_c_print_quoted_str(vstr, (const char*)str, len, MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_BYTES);
|
||||
break;
|
||||
@@ -597,12 +603,13 @@ void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
}
|
||||
|
||||
STATIC bool node_is_const_false(mp_parse_node_t pn) {
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE);
|
||||
// untested: || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0);
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE)
|
||||
|| (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0);
|
||||
}
|
||||
|
||||
STATIC bool node_is_const_true(mp_parse_node_t pn) {
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE) || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 1);
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE)
|
||||
|| (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) != 0);
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
@@ -853,7 +860,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
|
||||
assert(0);
|
||||
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
int arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
qstr arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
switch (assign_kind) {
|
||||
case ASSIGN_STORE:
|
||||
case ASSIGN_AUG_STORE:
|
||||
@@ -1107,7 +1114,7 @@ qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint
|
||||
comp->num_default_params = 0;
|
||||
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param);
|
||||
|
||||
if (comp->had_error) {
|
||||
if (comp->compile_error != MP_OBJ_NULL) {
|
||||
return MP_QSTR_NULL;
|
||||
}
|
||||
|
||||
@@ -1361,6 +1368,7 @@ void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
if (comp->break_label == 0) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, "'break' outside loop");
|
||||
}
|
||||
assert(comp->cur_except_level >= comp->break_continue_except_level);
|
||||
EMIT_ARG(break_loop, comp->break_label, comp->cur_except_level - comp->break_continue_except_level);
|
||||
}
|
||||
|
||||
@@ -1368,6 +1376,7 @@ void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
if (comp->continue_label == 0) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, "'continue' outside loop");
|
||||
}
|
||||
assert(comp->cur_except_level >= comp->break_continue_except_level);
|
||||
EMIT_ARG(continue_loop, comp->continue_label, comp->cur_except_level - comp->break_continue_except_level);
|
||||
}
|
||||
|
||||
@@ -1459,7 +1468,7 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
|
||||
if (i > 0) {
|
||||
*str_dest++ = '.';
|
||||
}
|
||||
uint str_src_len;
|
||||
mp_uint_t str_src_len;
|
||||
const byte *str_src = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &str_src_len);
|
||||
memcpy(str_dest, str_src, str_src_len);
|
||||
str_dest += str_src_len;
|
||||
@@ -1564,7 +1573,7 @@ void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
vstr_printf(vstr, ", ");
|
||||
}
|
||||
vstr_printf(vstr, "'");
|
||||
uint len;
|
||||
mp_uint_t len;
|
||||
const byte *str = qstr_data(id2, &len);
|
||||
vstr_add_strn(vstr, (const char*)str, len);
|
||||
vstr_printf(vstr, "'");
|
||||
@@ -1650,54 +1659,52 @@ void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
|
||||
uint l_end = comp_next_label(comp);
|
||||
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition
|
||||
// optimisation: don't emit anything when "if False" (not in CPython)
|
||||
if (MICROPY_EMIT_CPYTHON || !node_is_const_false(pns->nodes[0])) {
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition
|
||||
|
||||
compile_node(comp, pns->nodes[1]); // if block
|
||||
compile_node(comp, pns->nodes[1]); // if block
|
||||
|
||||
if (
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// optimisation to not jump over non-existent elif/else blocks (this optimisation is not in CPython)
|
||||
!(MP_PARSE_NODE_IS_NULL(pns->nodes[2]) && MP_PARSE_NODE_IS_NULL(pns->nodes[3])) &&
|
||||
#endif
|
||||
// optimisation to not jump if last instruction was return
|
||||
!EMIT(last_emit_was_return_value)
|
||||
) {
|
||||
// jump over elif/else blocks
|
||||
EMIT_ARG(jump, l_end);
|
||||
// optimisation: skip everything else when "if True" (not in CPython)
|
||||
if (!MICROPY_EMIT_CPYTHON && node_is_const_true(pns->nodes[0])) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (
|
||||
// optimisation: don't jump over non-existent elif/else blocks (not in CPython)
|
||||
(MICROPY_EMIT_CPYTHON || !(MP_PARSE_NODE_IS_NULL(pns->nodes[2]) && MP_PARSE_NODE_IS_NULL(pns->nodes[3])))
|
||||
// optimisation: don't jump if last instruction was return
|
||||
&& !EMIT(last_emit_was_return_value)
|
||||
) {
|
||||
// jump over elif/else blocks
|
||||
EMIT_ARG(jump, l_end);
|
||||
}
|
||||
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
}
|
||||
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
// compile elif blocks (if any)
|
||||
mp_parse_node_t *pn_elif;
|
||||
int n_elif = list_get(&pns->nodes[2], PN_if_stmt_elif_list, &pn_elif);
|
||||
for (int i = 0; i < n_elif; i++) {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_elif[i], PN_if_stmt_elif)); // should be
|
||||
mp_parse_node_struct_t *pns_elif = (mp_parse_node_struct_t*)pn_elif[i];
|
||||
|
||||
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
|
||||
// compile elif blocks
|
||||
|
||||
mp_parse_node_struct_t *pns_elif = (mp_parse_node_struct_t*)pns->nodes[2];
|
||||
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns_elif) == PN_if_stmt_elif_list) {
|
||||
// multiple elif blocks
|
||||
|
||||
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_elif);
|
||||
for (int i = 0; i < n; i++) {
|
||||
mp_parse_node_struct_t *pns_elif2 = (mp_parse_node_struct_t*)pns_elif->nodes[i];
|
||||
l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns_elif2->nodes[0], false, l_fail); // elif condition
|
||||
|
||||
compile_node(comp, pns_elif2->nodes[1]); // elif block
|
||||
if (!EMIT(last_emit_was_return_value)) { // simple optimisation to align with CPython
|
||||
EMIT_ARG(jump, l_end);
|
||||
}
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
}
|
||||
|
||||
} else {
|
||||
// a single elif block
|
||||
|
||||
l_fail = comp_next_label(comp);
|
||||
// optimisation: don't emit anything when "if False" (not in CPython)
|
||||
if (MICROPY_EMIT_CPYTHON || !node_is_const_false(pns_elif->nodes[0])) {
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns_elif->nodes[0], false, l_fail); // elif condition
|
||||
|
||||
compile_node(comp, pns_elif->nodes[1]); // elif block
|
||||
if (!EMIT(last_emit_was_return_value)) { // simple optimisation to align with CPython
|
||||
|
||||
// optimisation: skip everything else when "elif True" (not in CPython)
|
||||
if (!MICROPY_EMIT_CPYTHON && node_is_const_true(pns_elif->nodes[0])) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// optimisation: don't jump if last instruction was return
|
||||
if (!EMIT(last_emit_was_return_value)) {
|
||||
EMIT_ARG(jump, l_end);
|
||||
}
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
@@ -1707,12 +1714,14 @@ void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// compile else block
|
||||
compile_node(comp, pns->nodes[3]); // can be null
|
||||
|
||||
done:
|
||||
EMIT_ARG(label_assign, l_end);
|
||||
}
|
||||
|
||||
#define START_BREAK_CONTINUE_BLOCK \
|
||||
uint old_break_label = comp->break_label; \
|
||||
uint old_continue_label = comp->continue_label; \
|
||||
uint16_t old_break_label = comp->break_label; \
|
||||
uint16_t old_continue_label = comp->continue_label; \
|
||||
uint16_t old_break_continue_except_level = comp->break_continue_except_level; \
|
||||
uint break_label = comp_next_label(comp); \
|
||||
uint continue_label = comp_next_label(comp); \
|
||||
comp->break_label = break_label; \
|
||||
@@ -1722,7 +1731,7 @@ void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
#define END_BREAK_CONTINUE_BLOCK \
|
||||
comp->break_label = old_break_label; \
|
||||
comp->continue_label = old_continue_label; \
|
||||
comp->break_continue_except_level = comp->cur_except_level;
|
||||
comp->break_continue_except_level = old_break_continue_except_level;
|
||||
|
||||
void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
START_BREAK_CONTINUE_BLOCK
|
||||
@@ -1744,12 +1753,16 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
EMIT(pop_block);
|
||||
}
|
||||
#else
|
||||
uint top_label = comp_next_label(comp);
|
||||
EMIT_ARG(jump, continue_label);
|
||||
EMIT_ARG(label_assign, top_label);
|
||||
compile_node(comp, pns->nodes[1]); // body
|
||||
EMIT_ARG(label_assign, continue_label);
|
||||
c_if_cond(comp, pns->nodes[0], true, top_label); // condition
|
||||
if (!node_is_const_false(pns->nodes[0])) { // optimisation: don't emit anything for "while False"
|
||||
uint top_label = comp_next_label(comp);
|
||||
if (!node_is_const_true(pns->nodes[0])) { // optimisation: don't jump to cond for "while True"
|
||||
EMIT_ARG(jump, continue_label);
|
||||
}
|
||||
EMIT_ARG(label_assign, top_label);
|
||||
compile_node(comp, pns->nodes[1]); // body
|
||||
EMIT_ARG(label_assign, continue_label);
|
||||
c_if_cond(comp, pns->nodes[0], true, top_label); // condition
|
||||
}
|
||||
#endif
|
||||
|
||||
// break/continue apply to outer loop (if any) in the else block
|
||||
@@ -2563,7 +2576,7 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
byte *s_dest = qstr_build_start(n_bytes, &q_ptr);
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[i])) {
|
||||
uint s_len;
|
||||
mp_uint_t s_len;
|
||||
const byte *s = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &s_len);
|
||||
memcpy(s_dest, s, s_len);
|
||||
s_dest += s_len;
|
||||
@@ -3415,7 +3428,8 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
||||
if (comp->pass > MP_PASS_SCOPE) {
|
||||
bool success = EMIT_INLINE_ASM(end_pass);
|
||||
if (!success) {
|
||||
comp->had_error = true;
|
||||
// TODO get proper exception from inline assembler
|
||||
compile_syntax_error(comp, MP_PARSE_NODE_NULL, "inline assembler error");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3550,6 +3564,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
compiler_t *comp = m_new0(compiler_t, 1);
|
||||
comp->source_file = source_file;
|
||||
comp->is_repl = is_repl;
|
||||
comp->compile_error = MP_OBJ_NULL;
|
||||
|
||||
// optimise constants
|
||||
mp_map_t consts;
|
||||
@@ -3566,7 +3581,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
comp->emit_inline_asm = NULL;
|
||||
comp->emit_inline_asm_method_table = NULL;
|
||||
uint max_num_labels = 0;
|
||||
for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) {
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
if (false) {
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
} else if (s->emit_options == MP_EMIT_OPT_ASM_THUMB) {
|
||||
@@ -3583,7 +3598,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
}
|
||||
|
||||
// compute some things related to scope and identifiers
|
||||
for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) {
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
compile_scope_compute_things(comp, s);
|
||||
}
|
||||
|
||||
@@ -3600,7 +3615,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
emit_inline_asm_t *emit_inline_thumb = NULL;
|
||||
#endif
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) {
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
if (false) {
|
||||
// dummy
|
||||
|
||||
@@ -3615,7 +3630,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
comp->emit_inline_asm = emit_inline_thumb;
|
||||
comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table;
|
||||
compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE);
|
||||
if (!comp->had_error) {
|
||||
if (comp->compile_error == MP_OBJ_NULL) {
|
||||
compile_scope_inline_asm(comp, s, MP_PASS_EMIT);
|
||||
}
|
||||
#endif
|
||||
@@ -3674,12 +3689,12 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
|
||||
// second last pass: compute code size
|
||||
if (!comp->had_error) {
|
||||
if (comp->compile_error == MP_OBJ_NULL) {
|
||||
compile_scope(comp, s, MP_PASS_CODE_SIZE);
|
||||
}
|
||||
|
||||
// final pass: emit code
|
||||
if (!comp->had_error) {
|
||||
if (comp->compile_error == MP_OBJ_NULL) {
|
||||
compile_scope(comp, s, MP_PASS_EMIT);
|
||||
}
|
||||
}
|
||||
@@ -3722,12 +3737,11 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
}
|
||||
|
||||
// free the compiler
|
||||
bool had_error = comp->had_error;
|
||||
mp_obj_t compile_error = comp->compile_error;
|
||||
m_del_obj(compiler_t, comp);
|
||||
|
||||
if (had_error) {
|
||||
// TODO return a proper error message
|
||||
return mp_const_none;
|
||||
if (compile_error != MP_OBJ_NULL) {
|
||||
return compile_error;
|
||||
} else {
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
// can't create code, so just return true
|
||||
|
||||
@@ -35,3 +35,6 @@ enum {
|
||||
|
||||
// the compiler will free the parse tree (pn) before it returns
|
||||
mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is_repl);
|
||||
|
||||
// this is implemented in runtime.c
|
||||
mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_input_kind, mp_obj_dict_t *globals, mp_obj_dict_t *locals);
|
||||
|
||||
54
py/emitbc.c
54
py/emitbc.c
@@ -218,6 +218,13 @@ STATIC void emit_write_bytecode_byte_uint(emit_t* emit, byte b, mp_uint_t val) {
|
||||
emit_write_uint(emit, emit_get_cur_to_write_bytecode, val);
|
||||
}
|
||||
|
||||
STATIC void emit_write_bytecode_prealigned_ptr(emit_t* emit, void *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;
|
||||
}
|
||||
|
||||
// aligns the pointer so it is friendly to GC
|
||||
STATIC void emit_write_bytecode_byte_ptr(emit_t* emit, byte b, void *ptr) {
|
||||
emit_write_bytecode_byte(emit, b);
|
||||
@@ -294,7 +301,16 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
emit_write_code_info_qstr(emit, scope->simple_name);
|
||||
emit_write_code_info_qstr(emit, scope->source_file);
|
||||
|
||||
// bytecode prelude: local state size and exception stack size; 16 bit uints for now
|
||||
// bytecode prelude: argument names (needed to resolve positional args passed as keywords)
|
||||
// we store them as full word-sized objects for efficient access in mp_setup_code_state
|
||||
// this is the start of the prelude and is guaranteed to be aligned on a word boundary
|
||||
{
|
||||
for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) {
|
||||
emit_write_bytecode_prealigned_ptr(emit, MP_OBJ_NEW_QSTR(scope->id_info[i].qst));
|
||||
}
|
||||
}
|
||||
|
||||
// bytecode prelude: local state size and exception stack size
|
||||
{
|
||||
mp_uint_t n_state = scope->num_locals + scope->stack_size;
|
||||
if (n_state == 0) {
|
||||
@@ -358,13 +374,9 @@ STATIC void emit_bc_end_pass(emit_t *emit) {
|
||||
emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size);
|
||||
|
||||
} else if (emit->pass == MP_PASS_EMIT) {
|
||||
qstr *arg_names = m_new(qstr, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
|
||||
for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
|
||||
arg_names[i] = emit->scope->id_info[i].qst;
|
||||
}
|
||||
mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base,
|
||||
emit->code_info_size + emit->bytecode_size,
|
||||
emit->scope->num_pos_args, emit->scope->num_kwonly_args, arg_names,
|
||||
emit->scope->num_pos_args, emit->scope->num_kwonly_args,
|
||||
emit->scope->scope_flags);
|
||||
}
|
||||
}
|
||||
@@ -457,7 +469,11 @@ 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, mp_int_t arg) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
|
||||
if (-16 <= arg && arg <= 47) {
|
||||
emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_SMALL_INT_MULTI + 16 + arg);
|
||||
} else {
|
||||
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_const_int(emit_t *emit, qstr qst) {
|
||||
@@ -487,11 +503,10 @@ STATIC void emit_bc_load_null(emit_t *emit) {
|
||||
STATIC void emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
|
||||
assert(local_num >= 0);
|
||||
emit_bc_pre(emit, 1);
|
||||
switch (local_num) {
|
||||
case 0: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_0); break;
|
||||
case 1: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_1); break;
|
||||
case 2: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_2); break;
|
||||
default: emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break;
|
||||
if (local_num <= 15) {
|
||||
emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num);
|
||||
} else {
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,11 +548,10 @@ STATIC void emit_bc_load_subscr(emit_t *emit) {
|
||||
STATIC void emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
assert(local_num >= 0);
|
||||
emit_bc_pre(emit, -1);
|
||||
switch (local_num) {
|
||||
case 0: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_0); break;
|
||||
case 1: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_1); break;
|
||||
case 2: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_2); break;
|
||||
default: emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num); break;
|
||||
if (local_num <= 15) {
|
||||
emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num);
|
||||
} else {
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,12 +726,12 @@ STATIC void emit_bc_pop_except(emit_t *emit) {
|
||||
STATIC void emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) {
|
||||
if (op == MP_UNARY_OP_NOT) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_bytecode_byte_byte(emit, MP_BC_UNARY_OP, MP_UNARY_OP_BOOL);
|
||||
emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_BOOL);
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_bytecode_byte(emit, MP_BC_NOT);
|
||||
} else {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_bytecode_byte_byte(emit, MP_BC_UNARY_OP, op);
|
||||
emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + op);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,7 +745,7 @@ STATIC void emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) {
|
||||
op = MP_BINARY_OP_IS;
|
||||
}
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_bytecode_byte_byte(emit, MP_BC_BINARY_OP, op);
|
||||
emit_write_bytecode_byte(emit, MP_BC_BINARY_OP_MULTI + op);
|
||||
if (invert) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_bytecode_byte(emit, MP_BC_NOT);
|
||||
|
||||
@@ -55,33 +55,20 @@ 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, 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_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags) {
|
||||
rc->kind = MP_CODE_BYTECODE;
|
||||
rc->scope_flags = scope_flags;
|
||||
rc->n_pos_args = n_pos_args;
|
||||
rc->n_kwonly_args = n_kwonly_args;
|
||||
rc->arg_names = arg_names;
|
||||
rc->u_byte.code = code;
|
||||
rc->u_byte.len = len;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
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]));
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
#endif
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
if (mp_verbose_flag > 0) {
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf(" %02x", code[i]);
|
||||
}
|
||||
printf("\n");
|
||||
mp_bytecode_print(rc, code, len);
|
||||
if (mp_verbose_flag >= 2) {
|
||||
mp_bytecode_print(rc, n_pos_args + n_kwonly_args, code, len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -128,7 +115,7 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
|
||||
mp_obj_t fun;
|
||||
switch (rc->kind) {
|
||||
case MP_CODE_BYTECODE:
|
||||
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code);
|
||||
fun = mp_obj_new_fun_bc(rc->scope_flags, 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:
|
||||
|
||||
@@ -35,12 +35,11 @@ typedef enum {
|
||||
MP_CODE_NATIVE_ASM,
|
||||
} mp_raw_code_kind_t;
|
||||
|
||||
typedef struct _mp_code_t {
|
||||
typedef struct _mp_raw_code_t {
|
||||
mp_raw_code_kind_t kind : 3;
|
||||
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;
|
||||
@@ -55,7 +54,7 @@ typedef struct _mp_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, 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_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, 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);
|
||||
|
||||
218
py/emitnative.c
218
py/emitnative.c
@@ -145,12 +145,19 @@
|
||||
|
||||
#define ASM_LSL_REG(as, reg) asm_x64_shl_r64_cl((as), (reg))
|
||||
#define ASM_ASR_REG(as, reg) asm_x64_sar_r64_cl((as), (reg))
|
||||
#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_x64_or_r64_r64((as), (reg_dest), (reg_src))
|
||||
#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_x64_xor_r64_r64((as), (reg_dest), (reg_src))
|
||||
#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_x64_and_r64_r64((as), (reg_dest), (reg_src))
|
||||
#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_x64_add_r64_r64((as), (reg_dest), (reg_src))
|
||||
#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x64_sub_r64_r64((as), (reg_dest), (reg_src))
|
||||
|
||||
#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x64_mov_r64_to_disp((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x64_mov_r8_to_disp((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x64_mov_r16_to_disp((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem64_to_r64((as), (reg_base), 0, (reg_dest))
|
||||
#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem8_to_r64zx((as), (reg_base), 0, (reg_dest))
|
||||
#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 0, (reg_dest))
|
||||
|
||||
#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x64_mov_r8_to_mem8((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x64_mov_r16_to_mem16((as), (reg_src), (reg_base), 0)
|
||||
|
||||
#elif N_X86
|
||||
|
||||
@@ -270,12 +277,19 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
|
||||
|
||||
#define ASM_LSL_REG(as, reg) asm_x86_shl_r32_cl((as), (reg))
|
||||
#define ASM_ASR_REG(as, reg) asm_x86_sar_r32_cl((as), (reg))
|
||||
#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_x86_or_r32_r32((as), (reg_dest), (reg_src))
|
||||
#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_x86_xor_r32_r32((as), (reg_dest), (reg_src))
|
||||
#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_x86_and_r32_r32((as), (reg_dest), (reg_src))
|
||||
#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_x86_add_r32_r32((as), (reg_dest), (reg_src))
|
||||
#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x86_sub_r32_r32((as), (reg_dest), (reg_src))
|
||||
|
||||
#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_disp((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x86_mov_r8_to_disp((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x86_mov_r16_to_disp((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest))
|
||||
#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem8_to_r32zx((as), (reg_base), 0, (reg_dest))
|
||||
#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 0, (reg_dest))
|
||||
|
||||
#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x86_mov_r8_to_mem8((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x86_mov_r16_to_mem16((as), (reg_src), (reg_base), 0)
|
||||
|
||||
#elif N_THUMB
|
||||
|
||||
@@ -346,9 +360,16 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
|
||||
|
||||
#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSL, (reg_dest), (reg_shift))
|
||||
#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ASR, (reg_dest), (reg_shift))
|
||||
#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ORR, (reg_dest), (reg_src))
|
||||
#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_EOR, (reg_dest), (reg_src))
|
||||
#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_AND, (reg_dest), (reg_src))
|
||||
#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_thumb_add_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src))
|
||||
#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_thumb_sub_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src))
|
||||
|
||||
#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), 0)
|
||||
#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrb_rlo_rlo_i5((as), (reg_dest), (reg_base), 0)
|
||||
#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrh_rlo_rlo_i5((as), (reg_dest), (reg_base), 0)
|
||||
|
||||
#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_thumb_strb_rlo_rlo_i5((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_thumb_strh_rlo_rlo_i5((as), (reg_src), (reg_base), 0)
|
||||
@@ -420,16 +441,21 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
|
||||
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_arm_mov_reg_reg((as), (reg_dest), (reg_src))
|
||||
#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_arm_mov_reg_local_addr(as, (reg), (local_num))
|
||||
|
||||
// TODO someone please implement lsl and asr
|
||||
#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_arm_lsl_((as), (reg_dest), (reg_shift))
|
||||
#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_arm_asr_((as), (reg_dest), (reg_shift))
|
||||
#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_arm_lsl_reg_reg((as), (reg_dest), (reg_shift))
|
||||
#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_arm_asr_reg_reg((as), (reg_dest), (reg_shift))
|
||||
#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_arm_orr_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
|
||||
#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_arm_eor_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
|
||||
#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_arm_and_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
|
||||
#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_arm_add_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
|
||||
#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_arm_sub_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
|
||||
|
||||
// TODO someone please implement str
|
||||
#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_arm_str_reg_reg_i5((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_arm_strb_reg_reg_i5((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_arm_strh_reg_reg_i5((as), (reg_src), (reg_base), 0)
|
||||
#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base))
|
||||
#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_arm_ldrb_reg_reg((as), (reg_dest), (reg_base))
|
||||
#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_arm_ldrh_reg_reg((as), (reg_dest), (reg_base))
|
||||
|
||||
#define ASM_STORE_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base))
|
||||
#define ASM_STORE8_REG_REG(as, reg_value, reg_base) asm_arm_strb_reg_reg((as), (reg_value), (reg_base))
|
||||
#define ASM_STORE16_REG_REG(as, reg_value, reg_base) asm_arm_strh_reg_reg((as), (reg_value), (reg_base))
|
||||
|
||||
#else
|
||||
|
||||
@@ -481,6 +507,7 @@ struct _emit_t {
|
||||
|
||||
mp_uint_t stack_info_alloc;
|
||||
stack_info_t *stack_info;
|
||||
vtype_kind_t saved_stack_vtype;
|
||||
|
||||
int stack_start;
|
||||
int stack_size;
|
||||
@@ -688,15 +715,23 @@ STATIC bool emit_native_last_emit_was_return_value(emit_t *emit) {
|
||||
}
|
||||
|
||||
STATIC void adjust_stack(emit_t *emit, mp_int_t stack_size_delta) {
|
||||
DEBUG_printf(" adjust_stack; stack_size=%d, delta=%d\n", emit->stack_size, stack_size_delta);
|
||||
assert((mp_int_t)emit->stack_size + stack_size_delta >= 0);
|
||||
emit->stack_size += stack_size_delta;
|
||||
if (emit->pass > MP_PASS_SCOPE && emit->stack_size > emit->scope->stack_size) {
|
||||
emit->scope->stack_size = emit->stack_size;
|
||||
}
|
||||
#ifdef DEBUG_PRINT
|
||||
DEBUG_printf(" adjust_stack; stack_size=%d+%d; stack now:", emit->stack_size - stack_size_delta, stack_size_delta);
|
||||
for (int i = 0; i < emit->stack_size; i++) {
|
||||
stack_info_t *si = &emit->stack_info[i];
|
||||
DEBUG_printf(" (v=%d k=%d %d)", si->vtype, si->kind, si->u_reg);
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void emit_native_adjust_stack_size(emit_t *emit, mp_int_t delta) {
|
||||
DEBUG_printf("adjust_stack_size(" INT_FMT ")\n", delta);
|
||||
// If we are adjusting the stack in a positive direction (pushing) then we
|
||||
// need to fill in values for the stack kind and vtype of the newly-pushed
|
||||
// entries. These should be set to "value" (ie not reg or imm) because we
|
||||
@@ -705,7 +740,13 @@ STATIC void emit_native_adjust_stack_size(emit_t *emit, mp_int_t delta) {
|
||||
for (mp_int_t i = 0; i < delta; i++) {
|
||||
stack_info_t *si = &emit->stack_info[emit->stack_size + i];
|
||||
si->kind = STACK_VALUE;
|
||||
si->vtype = VTYPE_PYOBJ; // XXX we don't know the vtype...
|
||||
// TODO we don't know the vtype to use here. At the moment this is a
|
||||
// hack to get the case of multi comparison working.
|
||||
if (delta == 1) {
|
||||
si->vtype = emit->saved_stack_vtype;
|
||||
} else {
|
||||
si->vtype = VTYPE_PYOBJ;
|
||||
}
|
||||
}
|
||||
adjust_stack(emit, delta);
|
||||
}
|
||||
@@ -1075,7 +1116,7 @@ STATIC void emit_native_import_star(emit_t *emit) {
|
||||
STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
DEBUG_printf("load_const_tok(tok=%u)\n", tok);
|
||||
emit_native_pre(emit);
|
||||
int vtype;
|
||||
vtype_kind_t vtype;
|
||||
mp_uint_t val;
|
||||
if (emit->do_viper_types) {
|
||||
switch (tok) {
|
||||
@@ -1149,6 +1190,7 @@ STATIC void emit_native_load_null(emit_t *emit) {
|
||||
}
|
||||
|
||||
STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
|
||||
DEBUG_printf("load_fast(%s, " UINT_FMT ", " UINT_FMT ")\n", qstr_str(qst), id_flags, local_num);
|
||||
vtype_kind_t vtype = emit->local_vtype[local_num];
|
||||
if (vtype == VTYPE_UNBOUND) {
|
||||
printf("ViperTypeError: local %s used before type known\n", qstr_str(qst));
|
||||
@@ -1267,13 +1309,100 @@ STATIC void emit_native_load_build_class(emit_t *emit) {
|
||||
}
|
||||
|
||||
STATIC void emit_native_load_subscr(emit_t *emit) {
|
||||
vtype_kind_t vtype_lhs, vtype_rhs;
|
||||
emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_2, &vtype_lhs, REG_ARG_1);
|
||||
if (vtype_lhs == VTYPE_PYOBJ && vtype_rhs == VTYPE_PYOBJ) {
|
||||
DEBUG_printf("load_subscr\n");
|
||||
// need to compile: base[index]
|
||||
|
||||
// pop: index, base
|
||||
// optimise case where index is an immediate
|
||||
vtype_kind_t vtype_base = peek_vtype(emit, 1);
|
||||
|
||||
if (vtype_base == VTYPE_PYOBJ) {
|
||||
// standard Python call
|
||||
vtype_kind_t vtype_index;
|
||||
emit_pre_pop_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1);
|
||||
assert(vtype_index == VTYPE_PYOBJ);
|
||||
emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_SENTINEL, REG_ARG_3);
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
} else {
|
||||
printf("ViperTypeError: can't do subscr of types %d and %d\n", vtype_lhs, vtype_rhs);
|
||||
// viper load
|
||||
// TODO The different machine architectures have very different
|
||||
// capabilities and requirements for loads, so probably best to
|
||||
// write a completely separate load-optimiser for each one.
|
||||
stack_info_t *top = peek_stack(emit, 0);
|
||||
if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {
|
||||
// index is an immediate
|
||||
mp_int_t index_value = top->u_imm;
|
||||
emit_pre_pop_discard(emit); // discard index
|
||||
int reg_base = REG_ARG_1;
|
||||
int reg_index = REG_ARG_2;
|
||||
emit_pre_pop_reg_flexible(emit, &vtype_base, ®_base, reg_index, reg_index);
|
||||
switch (vtype_base) {
|
||||
case VTYPE_PTR8: {
|
||||
// pointer to 8-bit memory
|
||||
// TODO optimise to use thumb ldrb r1, [r2, r3]
|
||||
if (index_value != 0) {
|
||||
// index is non-zero
|
||||
#if N_THUMB
|
||||
if (index_value > 0 && index_value < 32) {
|
||||
asm_thumb_ldrb_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
ASM_MOV_IMM_TO_REG(emit->as, index_value, reg_index);
|
||||
ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base
|
||||
reg_base = reg_index;
|
||||
}
|
||||
ASM_LOAD8_REG_REG(emit->as, REG_RET, reg_base); // load from (base+index)
|
||||
break;
|
||||
}
|
||||
case VTYPE_PTR16: {
|
||||
// pointer to 16-bit memory
|
||||
if (index_value != 0) {
|
||||
// index is a non-zero immediate
|
||||
#if N_THUMB
|
||||
if (index_value > 0 && index_value < 32) {
|
||||
asm_thumb_ldrh_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
ASM_MOV_IMM_TO_REG(emit->as, index_value << 1, reg_index);
|
||||
ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base
|
||||
reg_base = reg_index;
|
||||
}
|
||||
ASM_LOAD16_REG_REG(emit->as, REG_RET, reg_base); // load from (base+2*index)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("ViperTypeError: can't load from type %d\n", vtype_base);
|
||||
}
|
||||
} else {
|
||||
// index is not an immediate
|
||||
vtype_kind_t vtype_index;
|
||||
int reg_index = REG_ARG_2;
|
||||
emit_pre_pop_reg_flexible(emit, &vtype_index, ®_index, REG_ARG_1, REG_ARG_1);
|
||||
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
|
||||
switch (vtype_base) {
|
||||
case VTYPE_PTR8: {
|
||||
// pointer to 8-bit memory
|
||||
// TODO optimise to use thumb ldrb r1, [r2, r3]
|
||||
assert(vtype_index == VTYPE_INT);
|
||||
ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
|
||||
ASM_LOAD8_REG_REG(emit->as, REG_RET, REG_ARG_1); // store value to (base+index)
|
||||
break;
|
||||
}
|
||||
case VTYPE_PTR16: {
|
||||
// pointer to 16-bit memory
|
||||
assert(vtype_index == VTYPE_INT);
|
||||
ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
|
||||
ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
|
||||
ASM_LOAD16_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+2*index)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("ViperTypeError: can't load from type %d\n", vtype_base);
|
||||
}
|
||||
}
|
||||
emit_post_push_reg(emit, VTYPE_INT, REG_RET);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1424,6 +1553,10 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
|
||||
}
|
||||
#endif
|
||||
ASM_MOV_IMM_TO_REG(emit->as, index_value, reg_index);
|
||||
#if N_ARM
|
||||
asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);
|
||||
return;
|
||||
#endif
|
||||
ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base
|
||||
reg_base = reg_index;
|
||||
}
|
||||
@@ -1441,6 +1574,10 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
|
||||
}
|
||||
#endif
|
||||
ASM_MOV_IMM_TO_REG(emit->as, index_value << 1, reg_index);
|
||||
#if N_ARM
|
||||
asm_arm_strh_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);
|
||||
return;
|
||||
#endif
|
||||
ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base
|
||||
reg_base = reg_index;
|
||||
}
|
||||
@@ -1468,6 +1605,10 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
|
||||
// pointer to 8-bit memory
|
||||
// TODO optimise to use thumb strb r1, [r2, r3]
|
||||
assert(vtype_index == VTYPE_INT);
|
||||
#if N_ARM
|
||||
asm_arm_strb_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#endif
|
||||
ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
|
||||
ASM_STORE8_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+index)
|
||||
break;
|
||||
@@ -1475,6 +1616,10 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
|
||||
case VTYPE_PTR16: {
|
||||
// pointer to 16-bit memory
|
||||
assert(vtype_index == VTYPE_INT);
|
||||
#if N_ARM
|
||||
asm_arm_strh_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#endif
|
||||
ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
|
||||
ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
|
||||
ASM_STORE16_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+2*index)
|
||||
@@ -1528,8 +1673,9 @@ STATIC void emit_native_delete_subscr(emit_t *emit) {
|
||||
STATIC void emit_native_dup_top(emit_t *emit) {
|
||||
DEBUG_printf("dup_top\n");
|
||||
vtype_kind_t vtype;
|
||||
emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
|
||||
emit_post_push_reg_reg(emit, vtype, REG_TEMP0, vtype, REG_TEMP0);
|
||||
int reg = REG_TEMP0;
|
||||
emit_pre_pop_reg_flexible(emit, &vtype, ®, -1, -1);
|
||||
emit_post_push_reg_reg(emit, vtype, reg, vtype, reg);
|
||||
}
|
||||
|
||||
STATIC void emit_native_dup_top_two(emit_t *emit) {
|
||||
@@ -1589,6 +1735,11 @@ STATIC void emit_native_jump_helper(emit_t *emit, mp_uint_t label, bool pop) {
|
||||
printf("ViperTypeError: expecting a bool or pyobj, got %d\n", vtype);
|
||||
assert(0);
|
||||
}
|
||||
// For non-pop need to save the vtype so that emit_native_adjust_stack_size
|
||||
// can use it. This is a bit of a hack.
|
||||
if (!pop) {
|
||||
emit->saved_stack_vtype = vtype;
|
||||
}
|
||||
// need to commit stack because we may jump elsewhere
|
||||
need_stack_settled(emit);
|
||||
}
|
||||
@@ -1755,6 +1906,15 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
|
||||
ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
|
||||
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
|
||||
#endif
|
||||
} else if (op == MP_BINARY_OP_OR || op == MP_BINARY_OP_INPLACE_OR) {
|
||||
ASM_OR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
|
||||
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
|
||||
} else if (op == MP_BINARY_OP_XOR || op == MP_BINARY_OP_INPLACE_XOR) {
|
||||
ASM_XOR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
|
||||
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
|
||||
} else if (op == MP_BINARY_OP_AND || op == MP_BINARY_OP_INPLACE_AND) {
|
||||
ASM_AND_REG_REG(emit->as, REG_ARG_2, reg_rhs);
|
||||
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
|
||||
} else if (op == MP_BINARY_OP_ADD || op == MP_BINARY_OP_INPLACE_ADD) {
|
||||
ASM_ADD_REG_REG(emit->as, REG_ARG_2, reg_rhs);
|
||||
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
|
||||
@@ -1769,6 +1929,7 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
|
||||
// MP_BINARY_OP_LESS_EQUAL
|
||||
// MP_BINARY_OP_MORE_EQUAL
|
||||
// MP_BINARY_OP_NOT_EQUAL
|
||||
need_reg_single(emit, REG_RET, 0);
|
||||
#if N_X64
|
||||
asm_x64_xor_r64_r64(emit->as, REG_RET, REG_RET);
|
||||
asm_x64_cmp_r64_with_r64(emit->as, reg_rhs, REG_ARG_2);
|
||||
@@ -1808,9 +1969,16 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
|
||||
asm_thumb_mov_rlo_i8(emit->as, REG_RET, ret[op - MP_BINARY_OP_LESS]);
|
||||
asm_thumb_mov_rlo_i8(emit->as, REG_RET, ret[op - MP_BINARY_OP_LESS] ^ 1);
|
||||
#elif N_ARM
|
||||
#error generic comparisons for ARM needs implementing
|
||||
//asm_arm_less_op(emit->as, REG_RET, REG_ARG_2, reg_rhs);
|
||||
//asm_arm_more_op(emit->as, REG_RET, REG_ARG_2, reg_rhs);
|
||||
asm_arm_cmp_reg_reg(emit->as, REG_ARG_2, reg_rhs);
|
||||
static uint ccs[6] = {
|
||||
ASM_ARM_CC_LT,
|
||||
ASM_ARM_CC_GT,
|
||||
ASM_ARM_CC_EQ,
|
||||
ASM_ARM_CC_LE,
|
||||
ASM_ARM_CC_GE,
|
||||
ASM_ARM_CC_NE,
|
||||
};
|
||||
asm_arm_setcc_reg(emit->as, REG_RET, ccs[op - MP_BINARY_OP_LESS]);
|
||||
#else
|
||||
#error not implemented
|
||||
#endif
|
||||
|
||||
118
py/gc.c
118
py/gc.c
@@ -58,7 +58,11 @@ STATIC mp_uint_t gc_alloc_table_byte_len;
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
STATIC byte *gc_finaliser_table_start;
|
||||
#endif
|
||||
STATIC mp_uint_t *gc_pool_start;
|
||||
// We initialise gc_pool_start to a dummy value so it stays out of the bss
|
||||
// section. This makes sure we don't trace this pointer in a collect cycle.
|
||||
// If we did trace it, it would make the first block of the heap always
|
||||
// reachable, and hence we can never free that block.
|
||||
STATIC mp_uint_t *gc_pool_start = (void*)4;
|
||||
STATIC mp_uint_t *gc_pool_end;
|
||||
|
||||
STATIC int gc_stack_overflow;
|
||||
@@ -153,13 +157,6 @@ void gc_init(void *start, void *end) {
|
||||
memset(gc_finaliser_table_start, 0, gc_finaliser_table_byte_len);
|
||||
#endif
|
||||
|
||||
// allocate first block because gc_pool_start points there and it will never
|
||||
// be freed, so allocating 1 block with null pointers will minimise memory loss
|
||||
ATB_FREE_TO_HEAD(0);
|
||||
for (int i = 0; i < WORDS_PER_BLOCK; i++) {
|
||||
gc_pool_start[i] = 0;
|
||||
}
|
||||
|
||||
// set last free ATB index to start of heap
|
||||
gc_last_free_atb_index = 0;
|
||||
|
||||
@@ -487,11 +484,15 @@ void gc_free(void *ptr_in) {
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
gc_dump_alloc_table();
|
||||
#endif
|
||||
} else {
|
||||
assert(!"bad free");
|
||||
}
|
||||
} else if (ptr_in != NULL) {
|
||||
assert(!"bad free");
|
||||
}
|
||||
}
|
||||
|
||||
mp_uint_t gc_nbytes(void *ptr_in) {
|
||||
mp_uint_t gc_nbytes(const void *ptr_in) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
|
||||
if (VERIFY_PTR(ptr)) {
|
||||
@@ -549,6 +550,12 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
|
||||
return gc_alloc(n_bytes, false);
|
||||
}
|
||||
|
||||
// check for pure free
|
||||
if (n_bytes == 0) {
|
||||
gc_free(ptr_in);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
|
||||
// sanity check the ptr
|
||||
@@ -567,22 +574,28 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
|
||||
// compute number of new blocks that are requested
|
||||
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
|
||||
// Get the total number of consecutive blocks that are already allocated to
|
||||
// this chunk of memory, and then count the number of free blocks following
|
||||
// it. Stop if we reach the end of the heap, or if we find enough extra
|
||||
// free blocks to satisfy the realloc. Note that we need to compute the
|
||||
// total size of the existing memory chunk so we can correctly and
|
||||
// efficiently shrink it (see below for shrinking code).
|
||||
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
|
||||
break;
|
||||
for (mp_uint_t bl = block + n_blocks; bl < max_block; bl++) {
|
||||
byte block_type = ATB_GET_KIND(bl);
|
||||
if (block_type == AT_TAIL) {
|
||||
n_blocks++;
|
||||
continue;
|
||||
}
|
||||
byte block_type = ATB_GET_KIND(block + n_blocks + n_free);
|
||||
switch (block_type) {
|
||||
case AT_FREE: n_free++; continue;
|
||||
case AT_TAIL: n_blocks++; continue;
|
||||
case AT_MARK: assert(0);
|
||||
if (block_type == AT_FREE) {
|
||||
n_free++;
|
||||
if (n_blocks + n_free >= new_blocks) {
|
||||
// stop as soon as we find enough blocks for n_bytes
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -595,7 +608,7 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
|
||||
// check if we can shrink the allocated area
|
||||
if (new_blocks < n_blocks) {
|
||||
// free unneeded tail blocks
|
||||
for (mp_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
|
||||
for (mp_uint_t bl = block + new_blocks, count = n_blocks - new_blocks; count > 0; bl++, count--) {
|
||||
ATB_ANY_TO_FREE(bl);
|
||||
}
|
||||
|
||||
@@ -668,32 +681,61 @@ void gc_dump_alloc_table(void) {
|
||||
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;
|
||||
mp_uint_t bl2 = bl;
|
||||
while (bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && ATB_GET_KIND(bl2) == AT_FREE) {
|
||||
bl2++;
|
||||
}
|
||||
if (bl2 - bl >= 2 * DUMP_BYTES_PER_LINE) {
|
||||
// there are at least 2 lines containing only free blocks, so abbreviate their printing
|
||||
printf("\n (" UINT_FMT " lines all free)", (bl2 - bl) / DUMP_BYTES_PER_LINE);
|
||||
bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1));
|
||||
if (bl >= gc_alloc_table_byte_len * BLOCKS_PER_ATB) {
|
||||
// got to end of heap
|
||||
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);
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
printf("\n%05x: ", (uint)(bl * BYTES_PER_BLOCK) & 0xfffff);
|
||||
#else
|
||||
printf("\n%05x: ", (uint)PTR_FROM_BLOCK(bl) & 0xfffff);
|
||||
#endif
|
||||
}
|
||||
int c = ' ';
|
||||
switch (ATB_GET_KIND(bl)) {
|
||||
case AT_FREE: c = '.'; break;
|
||||
case AT_HEAD: c = 'h'; break;
|
||||
/* this prints the uPy object type of the head block
|
||||
/* this prints out if the object is reachable from BSS or STACK (for unix only)
|
||||
case AT_HEAD: {
|
||||
extern char __bss_start, _end;
|
||||
extern char *stack_top;
|
||||
c = 'h';
|
||||
void **ptrs = (void**)&__bss_start;
|
||||
mp_uint_t len = ((mp_uint_t)&_end - (mp_uint_t)&__bss_start) / sizeof(mp_uint_t);
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptrs[i];
|
||||
if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) {
|
||||
c = 'B';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == 'h') {
|
||||
ptrs = (void**)&c;
|
||||
len = ((mp_uint_t)stack_top - (mp_uint_t)&c) / sizeof(mp_uint_t);
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptrs[i];
|
||||
if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) {
|
||||
c = 'S';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
/* this prints the uPy object type of the head block */
|
||||
case AT_HEAD: {
|
||||
mp_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
|
||||
if (*ptr == (mp_uint_t)&mp_type_tuple) { c = 'T'; }
|
||||
@@ -701,10 +743,10 @@ void gc_dump_alloc_table(void) {
|
||||
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 if (*ptr == (mp_uint_t)&mp_type_module) { c = 'M'; }
|
||||
else { c = 'h'; }
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case AT_TAIL: c = 't'; break;
|
||||
case AT_MARK: c = 'm'; break;
|
||||
}
|
||||
|
||||
2
py/gc.h
2
py/gc.h
@@ -40,7 +40,7 @@ void gc_collect_end(void);
|
||||
|
||||
void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser);
|
||||
void gc_free(void *ptr);
|
||||
mp_uint_t gc_nbytes(void *ptr);
|
||||
mp_uint_t gc_nbytes(const void *ptr);
|
||||
void *gc_realloc(void *ptr, mp_uint_t n_bytes);
|
||||
|
||||
typedef struct _gc_info_t {
|
||||
|
||||
@@ -731,7 +731,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_byte_t stream_next_byte, mp_lexer_stream_close_t stream_close) {
|
||||
mp_lexer_t *lex = m_new_maybe(mp_lexer_t, 1);
|
||||
mp_lexer_t *lex = m_new_obj_maybe(mp_lexer_t);
|
||||
|
||||
// check for memory allocation error
|
||||
if (lex == NULL) {
|
||||
|
||||
@@ -52,7 +52,10 @@ STATIC void str_buf_free(mp_lexer_str_buf_t *sb) {
|
||||
}
|
||||
|
||||
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);
|
||||
mp_lexer_str_buf_t *sb = m_new_obj_maybe(mp_lexer_str_buf_t);
|
||||
if (sb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
sb->free_len = free_len;
|
||||
sb->src_beg = str;
|
||||
sb->src_cur = str;
|
||||
|
||||
@@ -69,7 +69,10 @@ STATIC void file_buf_close(mp_lexer_file_buf_t *fb) {
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
mp_lexer_file_buf_t *fb = m_new_obj(mp_lexer_file_buf_t);
|
||||
mp_lexer_file_buf_t *fb = m_new_obj_maybe(mp_lexer_file_buf_t);
|
||||
if (fb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
fb->fd = open(filename, O_RDONLY);
|
||||
if (fb->fd < 0) {
|
||||
m_del_obj(mp_lexer_file_buf_t, fb);
|
||||
|
||||
42
py/malloc.c
42
py/malloc.c
@@ -63,11 +63,8 @@ STATIC size_t peak_bytes_allocated = 0;
|
||||
#endif // MICROPY_ENABLE_GC
|
||||
|
||||
void *m_malloc(size_t num_bytes) {
|
||||
if (num_bytes == 0) {
|
||||
return NULL;
|
||||
}
|
||||
void *ptr = malloc(num_bytes);
|
||||
if (ptr == NULL) {
|
||||
if (ptr == NULL && num_bytes != 0) {
|
||||
return m_malloc_fail(num_bytes);
|
||||
}
|
||||
#if MICROPY_MEM_STATS
|
||||
@@ -81,9 +78,6 @@ void *m_malloc(size_t num_bytes) {
|
||||
|
||||
void *m_malloc_maybe(size_t num_bytes) {
|
||||
void *ptr = malloc(num_bytes);
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#if MICROPY_MEM_STATS
|
||||
total_bytes_allocated += num_bytes;
|
||||
current_bytes_allocated += num_bytes;
|
||||
@@ -95,11 +89,8 @@ void *m_malloc_maybe(size_t num_bytes) {
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
void *m_malloc_with_finaliser(size_t num_bytes) {
|
||||
if (num_bytes == 0) {
|
||||
return NULL;
|
||||
}
|
||||
void *ptr = malloc_with_finaliser(num_bytes);
|
||||
if (ptr == NULL) {
|
||||
if (ptr == NULL && num_bytes != 0) {
|
||||
return m_malloc_fail(num_bytes);
|
||||
}
|
||||
#if MICROPY_MEM_STATS
|
||||
@@ -114,19 +105,16 @@ void *m_malloc_with_finaliser(size_t num_bytes) {
|
||||
|
||||
void *m_malloc0(size_t num_bytes) {
|
||||
void *ptr = m_malloc(num_bytes);
|
||||
if (ptr != NULL) {
|
||||
memset(ptr, 0, num_bytes);
|
||||
if (ptr == NULL && num_bytes != 0) {
|
||||
return m_malloc_fail(num_bytes);
|
||||
}
|
||||
memset(ptr, 0, num_bytes);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
|
||||
if (new_num_bytes == 0) {
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
void *new_ptr = realloc(ptr, new_num_bytes);
|
||||
if (new_ptr == NULL) {
|
||||
if (new_ptr == NULL && new_num_bytes != 0) {
|
||||
return m_malloc_fail(new_num_bytes);
|
||||
}
|
||||
#if MICROPY_MEM_STATS
|
||||
@@ -146,28 +134,26 @@ void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
|
||||
|
||||
void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
|
||||
void *new_ptr = realloc(ptr, new_num_bytes);
|
||||
if (new_ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#if MICROPY_MEM_STATS
|
||||
// At first thought, "Total bytes allocated" should only grow,
|
||||
// after all, it's *total*. But consider for example 2K block
|
||||
// shrunk to 1K and then grown to 2K again. It's still 2K
|
||||
// allocated total. If we process only positive increments,
|
||||
// we'll count 3K.
|
||||
size_t diff = new_num_bytes - old_num_bytes;
|
||||
total_bytes_allocated += diff;
|
||||
current_bytes_allocated += diff;
|
||||
UPDATE_PEAK();
|
||||
// Also, don't count failed reallocs.
|
||||
if (!(new_ptr == NULL && new_num_bytes != 0)) {
|
||||
size_t diff = new_num_bytes - old_num_bytes;
|
||||
total_bytes_allocated += diff;
|
||||
current_bytes_allocated += diff;
|
||||
UPDATE_PEAK();
|
||||
}
|
||||
#endif
|
||||
DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void m_free(void *ptr, size_t num_bytes) {
|
||||
if (ptr != NULL) {
|
||||
free(ptr);
|
||||
}
|
||||
free(ptr);
|
||||
#if MICROPY_MEM_STATS
|
||||
current_bytes_allocated -= num_bytes;
|
||||
#endif
|
||||
|
||||
@@ -54,6 +54,7 @@ typedef unsigned int uint;
|
||||
#define m_new_maybe(type, num) ((type*)(m_malloc_maybe(sizeof(type) * (num))))
|
||||
#define m_new0(type, num) ((type*)(m_malloc0(sizeof(type) * (num))))
|
||||
#define m_new_obj(type) (m_new(type, 1))
|
||||
#define m_new_obj_maybe(type) (m_new_maybe(type, 1))
|
||||
#define m_new_obj_var(obj_type, var_type, var_num) ((obj_type*)m_malloc(sizeof(obj_type) + sizeof(var_type) * (var_num)))
|
||||
#define m_new_obj_var_maybe(obj_type, var_type, var_num) ((obj_type*)m_malloc_maybe(sizeof(obj_type) + sizeof(var_type) * (var_num)))
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
|
||||
@@ -160,16 +160,16 @@ STATIC mp_obj_t struct_unpack(mp_obj_t fmt_in, mp_obj_t data_in) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(struct_unpack_obj, struct_unpack);
|
||||
|
||||
STATIC mp_obj_t struct_pack(uint n_args, mp_obj_t *args) {
|
||||
STATIC mp_obj_t struct_pack(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// TODO: "The arguments must match the values required by the format exactly."
|
||||
const char *fmt = mp_obj_str_get_str(args[0]);
|
||||
char fmt_type = get_fmt_type(&fmt);
|
||||
int size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
|
||||
mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
|
||||
byte *p;
|
||||
mp_obj_t res = mp_obj_str_builder_start(&mp_type_bytes, size, &p);
|
||||
memset(p, 0, size);
|
||||
|
||||
for (uint i = 1; i < n_args; i++) {
|
||||
for (mp_uint_t i = 1; i < n_args; i++) {
|
||||
mp_uint_t sz = 1;
|
||||
if (unichar_isdigit(*fmt)) {
|
||||
sz = get_fmt_num(&fmt);
|
||||
|
||||
@@ -269,6 +269,11 @@ typedef double mp_float_t;
|
||||
#define MICROPY_STREAMS_NON_BLOCK (0)
|
||||
#endif
|
||||
|
||||
// Whether module weak links are supported
|
||||
#ifndef MICROPY_MODULE_WEAK_LINKS
|
||||
#define MICROPY_MODULE_WEAK_LINKS (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Fine control over Python builtins, classes, modules, etc */
|
||||
|
||||
@@ -282,6 +287,11 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
|
||||
#endif
|
||||
|
||||
// Whether to support memoryview object
|
||||
#ifndef MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
|
||||
#endif
|
||||
|
||||
// Whether to support set object
|
||||
#ifndef MICROPY_PY_BUILTINS_SET
|
||||
#define MICROPY_PY_BUILTINS_SET (1)
|
||||
@@ -302,6 +312,11 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (1)
|
||||
#endif
|
||||
|
||||
// Whether to support compile function
|
||||
#ifndef MICROPY_PY_BUILTINS_COMPILE
|
||||
#define MICROPY_PY_BUILTINS_COMPILE (0)
|
||||
#endif
|
||||
|
||||
// Whether to set __file__ for imported modules
|
||||
#ifndef MICROPY_PY___FILE__
|
||||
#define MICROPY_PY___FILE__ (1)
|
||||
@@ -386,14 +401,22 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PY_UCTYPES (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_ZLIBD
|
||||
#define MICROPY_PY_ZLIBD (0)
|
||||
#ifndef MICROPY_PY_UZLIB
|
||||
#define MICROPY_PY_UZLIB (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UJSON
|
||||
#define MICROPY_PY_UJSON (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_URE
|
||||
#define MICROPY_PY_URE (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UHEAPQ
|
||||
#define MICROPY_PY_UHEAPQ (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Hooks for a port to add builtins */
|
||||
|
||||
@@ -407,6 +430,11 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PORT_BUILTIN_MODULES
|
||||
#endif
|
||||
|
||||
// Any module weak links - see builtintables.c:mp_builtin_module_weak_links_table.
|
||||
#ifndef MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS
|
||||
#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS
|
||||
#endif
|
||||
|
||||
// Additional constant definitions for the compiler - see compile.c:mp_constants_table.
|
||||
#ifndef MICROPY_PORT_CONSTANTS
|
||||
#define MICROPY_PORT_CONSTANTS
|
||||
@@ -417,10 +445,10 @@ typedef double mp_float_t;
|
||||
|
||||
// On embedded platforms, these will typically enable/disable irqs.
|
||||
#ifndef MICROPY_BEGIN_ATOMIC_SECTION
|
||||
#define MICROPY_BEGIN_ATOMIC_SECTION()
|
||||
#define MICROPY_BEGIN_ATOMIC_SECTION() (0)
|
||||
#endif
|
||||
#ifndef MICROPY_END_ATOMIC_SECTION
|
||||
#define MICROPY_END_ATOMIC_SECTION()
|
||||
#define MICROPY_END_ATOMIC_SECTION(state) (void)(state)
|
||||
#endif
|
||||
|
||||
// Allow to override static modifier for global objects, e.g. to use with
|
||||
@@ -434,13 +462,28 @@ typedef double mp_float_t;
|
||||
// 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?
|
||||
#define MP_ENDIANNESS_LITTLE (1)
|
||||
#endif
|
||||
// Ensure we don't accidentally set both endiannesses
|
||||
#if MP_ENDIANNESS_BIG
|
||||
#define MP_ENDIANNESS_LITTLE (0)
|
||||
// Make sure both MP_ENDIANNESS_LITTLE and MP_ENDIANNESS_BIG are
|
||||
// defined and that they are the opposite of each other.
|
||||
#if defined(MP_ENDIANNESS_LITTLE)
|
||||
#define MP_ENDIANNESS_BIG (!MP_ENDIANNESS_LITTLE)
|
||||
#elif defined(MP_ENDIANNESS_BIG)
|
||||
#define MP_ENDIANNESS_LITTLE (!MP_ENDIANNESS_BIG)
|
||||
#else
|
||||
// Endiannes not defined by port so try to autodetect it.
|
||||
#if defined(__BYTE_ORDER__)
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define MP_ENDIANNESS_LITTLE (1)
|
||||
#else
|
||||
#define MP_ENDIANNESS_LITTLE (0)
|
||||
#endif
|
||||
#elif defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN)
|
||||
#define MP_ENDIANNESS_LITTLE (1)
|
||||
#elif defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined (_BIG_ENDIAN)
|
||||
#define MP_ENDIANNESS_LITTLE (0)
|
||||
#else
|
||||
#error endianness not defined and cannot detect it
|
||||
#endif
|
||||
#define MP_ENDIANNESS_BIG (!MP_ENDIANNESS_LITTLE)
|
||||
#endif
|
||||
|
||||
// Make a pointer to RAM callable (eg set lower bit for Thumb code)
|
||||
|
||||
8
py/mpz.c
8
py/mpz.c
@@ -58,7 +58,7 @@
|
||||
returns sign(i - j)
|
||||
assumes i, j are normalised
|
||||
*/
|
||||
STATIC mp_int_t mpn_cmp(const mpz_dig_t *idig, mp_uint_t ilen, const mpz_dig_t *jdig, mp_uint_t jlen) {
|
||||
STATIC int mpn_cmp(const mpz_dig_t *idig, mp_uint_t ilen, const mpz_dig_t *jdig, mp_uint_t jlen) {
|
||||
if (ilen < jlen) { return -1; }
|
||||
if (ilen > jlen) { return 1; }
|
||||
|
||||
@@ -361,7 +361,7 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig,
|
||||
|
||||
// handle simple cases
|
||||
{
|
||||
mp_int_t cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);
|
||||
int cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);
|
||||
if (cmp == 0) {
|
||||
*num_len = 0;
|
||||
quo_dig[0] = 1;
|
||||
@@ -744,8 +744,8 @@ bool mpz_is_even(const mpz_t *z) {
|
||||
return z->len == 0 || (z->dig[0] & 1) == 0;
|
||||
}
|
||||
|
||||
mp_int_t mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
|
||||
mp_int_t cmp = z2->neg - z1->neg;
|
||||
int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
|
||||
int cmp = (int)z2->neg - (int)z1->neg;
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
||||
2
py/mpz.h
2
py/mpz.h
@@ -88,7 +88,7 @@ bool mpz_is_neg(const mpz_t *z);
|
||||
bool mpz_is_odd(const mpz_t *z);
|
||||
bool mpz_is_even(const mpz_t *z);
|
||||
|
||||
mp_int_t mpz_cmp(const mpz_t *lhs, const mpz_t *rhs);
|
||||
int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs);
|
||||
|
||||
mpz_t *mpz_abs(const mpz_t *z);
|
||||
mpz_t *mpz_neg(const mpz_t *z);
|
||||
|
||||
16
py/obj.h
16
py/obj.h
@@ -212,9 +212,9 @@ typedef struct _mp_buffer_info_t {
|
||||
// them with ver = sizeof(struct). Cons: overkill for *micro*?
|
||||
//int ver; // ?
|
||||
|
||||
void *buf; // can be NULL if len == 0
|
||||
mp_int_t len; // in bytes; TODO should it be mp_uint_t?
|
||||
int typecode; // as per binary.h; TODO what is the correct type to use?
|
||||
void *buf; // can be NULL if len == 0
|
||||
mp_uint_t len; // in bytes
|
||||
int typecode; // as per binary.h
|
||||
|
||||
// Rationale: to load arbitrary-sized sprites directly to LCD
|
||||
// Cons: a bit adhoc usecase
|
||||
@@ -292,6 +292,7 @@ extern const mp_obj_type_t mp_type_int;
|
||||
extern const mp_obj_type_t mp_type_str;
|
||||
extern const mp_obj_type_t mp_type_bytes;
|
||||
extern const mp_obj_type_t mp_type_bytearray;
|
||||
extern const mp_obj_type_t mp_type_memoryview;
|
||||
extern const mp_obj_type_t mp_type_float;
|
||||
extern const mp_obj_type_t mp_type_complex;
|
||||
extern const mp_obj_type_t mp_type_tuple;
|
||||
@@ -329,6 +330,7 @@ extern const mp_obj_type_t mp_type_GeneratorExit;
|
||||
extern const mp_obj_type_t mp_type_ImportError;
|
||||
extern const mp_obj_type_t mp_type_IndentationError;
|
||||
extern const mp_obj_type_t mp_type_IndexError;
|
||||
extern const mp_obj_type_t mp_type_KeyboardInterrupt;
|
||||
extern const mp_obj_type_t mp_type_KeyError;
|
||||
extern const mp_obj_type_t mp_type_LookupError;
|
||||
extern const mp_obj_type_t mp_type_MemoryError;
|
||||
@@ -339,7 +341,6 @@ extern const mp_obj_type_t mp_type_OverflowError;
|
||||
extern const mp_obj_type_t mp_type_RuntimeError;
|
||||
extern const mp_obj_type_t mp_type_StopIteration;
|
||||
extern const mp_obj_type_t mp_type_SyntaxError;
|
||||
extern const mp_obj_type_t mp_type_SystemError;
|
||||
extern const mp_obj_type_t mp_type_SystemExit;
|
||||
extern const mp_obj_type_t mp_type_TypeError;
|
||||
extern const mp_obj_type_t mp_type_ValueError;
|
||||
@@ -350,10 +351,12 @@ extern const mp_obj_type_t mp_type_ZeroDivisionError;
|
||||
#define mp_const_none ((mp_obj_t)&mp_const_none_obj)
|
||||
#define mp_const_false ((mp_obj_t)&mp_const_false_obj)
|
||||
#define mp_const_true ((mp_obj_t)&mp_const_true_obj)
|
||||
#define mp_const_empty_bytes ((mp_obj_t)&mp_const_empty_bytes_obj)
|
||||
#define mp_const_empty_tuple ((mp_obj_t)&mp_const_empty_tuple_obj)
|
||||
extern const struct _mp_obj_none_t mp_const_none_obj;
|
||||
extern const struct _mp_obj_bool_t mp_const_false_obj;
|
||||
extern const struct _mp_obj_bool_t mp_const_true_obj;
|
||||
extern const struct _mp_obj_str_t mp_const_empty_bytes_obj;
|
||||
extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj;
|
||||
extern const struct _mp_obj_ellipsis_t mp_const_ellipsis_obj;
|
||||
extern const struct _mp_obj_exception_t mp_const_MemoryError_obj;
|
||||
@@ -381,7 +384,7 @@ mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
|
||||
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, mp_uint_t 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(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_bc(mp_uint_t scope_flags, 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);
|
||||
@@ -527,7 +530,6 @@ void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
|
||||
void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step);
|
||||
|
||||
// array
|
||||
mp_uint_t mp_obj_array_len(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_new_bytearray_by_ref(mp_uint_t n, void *items);
|
||||
|
||||
// functions
|
||||
@@ -554,6 +556,8 @@ typedef struct _mp_obj_module_t {
|
||||
mp_obj_dict_t *globals;
|
||||
} mp_obj_module_t;
|
||||
mp_obj_dict_t *mp_obj_module_get_globals(mp_obj_t self_in);
|
||||
// check if given module object is a package
|
||||
bool mp_obj_is_package(mp_obj_t module);
|
||||
|
||||
// staticmethod and classmethod types; defined here so we can make const versions
|
||||
// this structure is used for instances of both staticmethod and classmethod
|
||||
|
||||
188
py/objarray.c
188
py/objarray.c
@@ -37,7 +37,28 @@
|
||||
#include "runtime.h"
|
||||
#include "binary.h"
|
||||
|
||||
#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
|
||||
// About memoryview object: We want to reuse as much code as possible from
|
||||
// array, and keep the memoryview object 4 words in size so it fits in 1 GC
|
||||
// block. Also, memoryview must keep a pointer to the base of the buffer so
|
||||
// that the buffer is not GC'd if the original parent object is no longer
|
||||
// around (we are assuming that all memoryview'able objects return a pointer
|
||||
// which points to the start of a GC chunk). Given the above constraints we
|
||||
// do the following:
|
||||
// - typecode high bit is set if the buffer is read-write (else read-only)
|
||||
// - free is the offset in elements to the first item in the memoryview
|
||||
// - len is the length in elements
|
||||
// - items points to the start of the original buffer
|
||||
// Note that we don't handle the case where the original buffer might change
|
||||
// size due to a resize of the original parent object.
|
||||
|
||||
// make (& TYPECODE_MASK) a null operation if memorview not enabled
|
||||
#if MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
#define TYPECODE_MASK (0x7f)
|
||||
#else
|
||||
#define TYPECODE_MASK (~(mp_uint_t)1)
|
||||
#endif
|
||||
|
||||
typedef struct _mp_obj_array_t {
|
||||
mp_obj_base_t base;
|
||||
@@ -50,13 +71,13 @@ typedef struct _mp_obj_array_t {
|
||||
} 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, mp_uint_t 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, mp_uint_t flags);
|
||||
|
||||
/******************************************************************************/
|
||||
/* array */
|
||||
// array
|
||||
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
|
||||
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) {
|
||||
@@ -66,7 +87,7 @@ STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *en
|
||||
print(env, "array('%c'", o->typecode);
|
||||
if (o->len > 0) {
|
||||
print(env, ", [");
|
||||
for (int i = 0; i < o->len; i++) {
|
||||
for (mp_uint_t i = 0; i < o->len; i++) {
|
||||
if (i > 0) {
|
||||
print(env, ", ");
|
||||
}
|
||||
@@ -77,7 +98,31 @@ STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *en
|
||||
}
|
||||
print(env, ")");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
|
||||
STATIC mp_obj_array_t *array_new(char typecode, mp_uint_t n) {
|
||||
int typecode_size = mp_binary_get_size('@', typecode, NULL);
|
||||
if (typecode_size <= 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode"));
|
||||
}
|
||||
mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY
|
||||
o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;
|
||||
#elif MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
o->base.type = &mp_type_bytearray;
|
||||
#else
|
||||
o->base.type = &mp_type_array;
|
||||
#endif
|
||||
o->typecode = typecode;
|
||||
o->free = 0;
|
||||
o->len = n;
|
||||
o->items = m_malloc(typecode_size * o->len);
|
||||
return o;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
|
||||
STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
|
||||
uint len;
|
||||
// Try to create array of exact len if initializer len is known
|
||||
@@ -92,7 +137,7 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
|
||||
|
||||
mp_obj_t iterable = mp_getiter(initializer);
|
||||
mp_obj_t item;
|
||||
int i = 0;
|
||||
mp_uint_t i = 0;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
if (len == 0) {
|
||||
array_append(array, item);
|
||||
@@ -103,7 +148,9 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
|
||||
|
||||
return array;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_ARRAY
|
||||
STATIC mp_obj_t array_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, 2, false);
|
||||
|
||||
@@ -119,7 +166,9 @@ STATIC mp_obj_t array_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k
|
||||
return array_construct(*typecode, args[1]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
|
||||
@@ -137,6 +186,33 @@ STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
|
||||
return array_construct(BYTEARRAY_TYPECODE, args[0]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
STATIC mp_obj_t memoryview_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// TODO possibly allow memoryview constructor to take start/stop so that one
|
||||
// can do memoryview(b, 4, 8) instead of memoryview(b)[4:8] (uses less RAM)
|
||||
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
mp_obj_array_t *self = m_new_obj(mp_obj_array_t);
|
||||
self->base.type = type_in;
|
||||
self->typecode = bufinfo.typecode;
|
||||
self->free = 0;
|
||||
self->len = bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL); // element len
|
||||
self->items = bufinfo.buf;
|
||||
|
||||
// test if the object can be written to
|
||||
if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) {
|
||||
self->typecode |= 0x80; // used to indicate writable buffer
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t array_unary_op(mp_uint_t op, mp_obj_t o_in) {
|
||||
mp_obj_array_t *o = o_in;
|
||||
@@ -154,7 +230,7 @@ STATIC mp_obj_t array_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in)
|
||||
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_const_false;
|
||||
}
|
||||
return MP_BOOL(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
|
||||
}
|
||||
@@ -202,21 +278,41 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
|
||||
"only slices with step=1 (aka None) are supported"));
|
||||
}
|
||||
mp_obj_array_t *res = array_new(o->typecode, slice.stop - slice.start);
|
||||
int sz = mp_binary_get_size('@', o->typecode, NULL);
|
||||
mp_obj_array_t *res;
|
||||
int sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
|
||||
assert(sz > 0);
|
||||
byte *p = o->items;
|
||||
memcpy(res->items, p + slice.start * sz, (slice.stop - slice.start) * sz);
|
||||
if (0) {
|
||||
// dummy
|
||||
#if MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
} else if (o->base.type == &mp_type_memoryview) {
|
||||
res = m_new_obj(mp_obj_array_t);
|
||||
*res = *o;
|
||||
res->free += slice.start;
|
||||
res->len = slice.stop - slice.start;
|
||||
#endif
|
||||
} else {
|
||||
res = array_new(o->typecode, slice.stop - slice.start);
|
||||
memcpy(res->items, o->items + slice.start * sz, (slice.stop - slice.start) * sz);
|
||||
}
|
||||
return res;
|
||||
#endif
|
||||
} else {
|
||||
uint index = mp_get_index(o->base.type, o->len, index_in, false);
|
||||
mp_uint_t index = mp_get_index(o->base.type, o->len, index_in, false);
|
||||
#if MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
if (o->base.type == &mp_type_memoryview) {
|
||||
index += o->free;
|
||||
if (value != MP_OBJ_SENTINEL && (o->typecode & 0x80) == 0) {
|
||||
// store to read-only memoryview
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
return mp_binary_get_val_array(o->typecode, o->items, index);
|
||||
return mp_binary_get_val_array(o->typecode & TYPECODE_MASK, o->items, index);
|
||||
} else {
|
||||
// store
|
||||
mp_binary_set_val_array(o->typecode, o->items, index, value);
|
||||
mp_binary_set_val_array(o->typecode & TYPECODE_MASK, o->items, index, value);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
@@ -225,18 +321,31 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
|
||||
|
||||
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
|
||||
mp_obj_array_t *o = o_in;
|
||||
int sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
|
||||
bufinfo->buf = o->items;
|
||||
bufinfo->len = o->len * mp_binary_get_size('@', o->typecode, NULL);
|
||||
bufinfo->typecode = o->typecode;
|
||||
bufinfo->len = o->len * sz;
|
||||
bufinfo->typecode = o->typecode & TYPECODE_MASK;
|
||||
#if MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
if (o->base.type == &mp_type_memoryview) {
|
||||
if ((o->typecode & 0x80) == 0 && (flags & MP_BUFFER_WRITE)) {
|
||||
// read-only memoryview
|
||||
return 1;
|
||||
}
|
||||
bufinfo->buf += (mp_uint_t)o->free * sz;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
|
||||
STATIC const mp_map_elem_t array_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_append), (mp_obj_t)&array_append_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_ARRAY
|
||||
const mp_obj_type_t mp_type_array = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_array,
|
||||
@@ -249,7 +358,9 @@ const mp_obj_type_t mp_type_array = {
|
||||
.buffer_p = { .get_buffer = array_get_buffer },
|
||||
.locals_dict = (mp_obj_t)&array_locals_dict,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
const mp_obj_type_t mp_type_bytearray = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_bytearray,
|
||||
@@ -262,25 +373,28 @@ const mp_obj_type_t mp_type_bytearray = {
|
||||
.buffer_p = { .get_buffer = array_get_buffer },
|
||||
.locals_dict = (mp_obj_t)&array_locals_dict,
|
||||
};
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_array_t *array_new(char typecode, mp_uint_t n) {
|
||||
int typecode_size = mp_binary_get_size('@', typecode, NULL);
|
||||
if (typecode_size <= 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode"));
|
||||
}
|
||||
mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
|
||||
o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;
|
||||
o->typecode = typecode;
|
||||
o->free = 0;
|
||||
o->len = n;
|
||||
o->items = m_malloc(typecode_size * o->len);
|
||||
return o;
|
||||
}
|
||||
#if MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
const mp_obj_type_t mp_type_memoryview = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_memoryview,
|
||||
.make_new = memoryview_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 },
|
||||
};
|
||||
#endif
|
||||
|
||||
/* unused
|
||||
mp_uint_t mp_obj_array_len(mp_obj_t self_in) {
|
||||
return ((mp_obj_array_t *)self_in)->len;
|
||||
}
|
||||
*/
|
||||
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items) {
|
||||
mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);
|
||||
memcpy(o->items, items, n);
|
||||
@@ -290,27 +404,29 @@ mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items) {
|
||||
// Create bytearray which references specified memory area
|
||||
mp_obj_t mp_obj_new_bytearray_by_ref(mp_uint_t n, void *items) {
|
||||
mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
|
||||
o->base.type = &mp_type_array;
|
||||
o->base.type = &mp_type_bytearray;
|
||||
o->typecode = BYTEARRAY_TYPECODE;
|
||||
o->free = 0;
|
||||
o->len = n;
|
||||
o->items = items;
|
||||
return o;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* array iterator */
|
||||
// array iterator
|
||||
|
||||
typedef struct _mp_obj_array_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_array_t *array;
|
||||
mp_uint_t offset;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_array_it_t;
|
||||
|
||||
STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
|
||||
mp_obj_array_it_t *self = self_in;
|
||||
if (self->cur < self->array->len) {
|
||||
return mp_binary_get_val_array(self->array->typecode, self->array->items, self->cur++);
|
||||
return mp_binary_get_val_array(self->array->typecode & TYPECODE_MASK, self->array->items, self->offset + self->cur++);
|
||||
} else {
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
}
|
||||
@@ -325,11 +441,15 @@ STATIC const mp_obj_type_t array_it_type = {
|
||||
|
||||
STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) {
|
||||
mp_obj_array_t *array = array_in;
|
||||
mp_obj_array_it_t *o = m_new_obj(mp_obj_array_it_t);
|
||||
mp_obj_array_it_t *o = m_new0(mp_obj_array_it_t, 1);
|
||||
o->base.type = &array_it_type;
|
||||
o->array = array;
|
||||
o->cur = 0;
|
||||
#if MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
if (array->base.type == &mp_type_memoryview) {
|
||||
o->offset = array->free;
|
||||
}
|
||||
#endif
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
|
||||
@@ -55,7 +55,7 @@ mp_obj_t bound_meth_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, con
|
||||
|
||||
// need to insert self->self before all other args and then call self->meth
|
||||
|
||||
int n_total = n_args + 2 * n_kw;
|
||||
mp_uint_t n_total = n_args + 2 * n_kw;
|
||||
if (n_total <= 4) {
|
||||
// use stack to allocate temporary args array
|
||||
mp_obj_t args2[5];
|
||||
|
||||
@@ -46,7 +46,7 @@ mp_obj_t closure_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const
|
||||
|
||||
// need to concatenate closed-over-vars and args
|
||||
|
||||
int n_total = self->n_closed + n_args + 2 * n_kw;
|
||||
mp_uint_t n_total = self->n_closed + n_args + 2 * n_kw;
|
||||
if (n_total <= 5) {
|
||||
// use stack to allocate temporary args array
|
||||
mp_obj_t args2[5];
|
||||
@@ -67,8 +67,10 @@ mp_obj_t closure_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
|
||||
STATIC void closure_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
mp_obj_closure_t *o = o_in;
|
||||
print(env, "<closure %s at %p, n_closed=%u ", mp_obj_fun_get_name(o->fun), o, o->n_closed);
|
||||
for (int i = 0; i < o->n_closed; i++) {
|
||||
print(env, "<closure ");
|
||||
mp_obj_print_helper(print, env, o->fun, PRINT_REPR);
|
||||
print(env, " at %p, n_closed=%u ", o, o->n_closed);
|
||||
for (mp_uint_t i = 0; i < o->n_closed; i++) {
|
||||
if (o->closed[i] == MP_OBJ_NULL) {
|
||||
print(env, "(nil)");
|
||||
} else {
|
||||
|
||||
@@ -88,10 +88,10 @@ mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {
|
||||
|
||||
// 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_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
||||
mp_emergency_exception_buf_size = size;
|
||||
mp_emergency_exception_buf = buf;
|
||||
MICROPY_END_ATOMIC_SECTION(irq_state);
|
||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
||||
|
||||
if (old_buf != NULL) {
|
||||
m_free(old_buf, old_size);
|
||||
@@ -211,7 +211,7 @@ const mp_obj_type_t mp_type_ ## exc_name = { \
|
||||
// http://docs.python.org/3/library/exceptions.html
|
||||
MP_DEFINE_EXCEPTION_BASE(BaseException)
|
||||
MP_DEFINE_EXCEPTION(SystemExit, BaseException)
|
||||
//MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
|
||||
MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
|
||||
MP_DEFINE_EXCEPTION(GeneratorExit, BaseException)
|
||||
MP_DEFINE_EXCEPTION(Exception, BaseException)
|
||||
MP_DEFINE_EXCEPTION_BASE(Exception)
|
||||
@@ -268,7 +268,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
|
||||
MP_DEFINE_EXCEPTION_BASE(IndentationError)
|
||||
MP_DEFINE_EXCEPTION(TabError, IndentationError)
|
||||
*/
|
||||
MP_DEFINE_EXCEPTION(SystemError, Exception)
|
||||
//MP_DEFINE_EXCEPTION(SystemError, Exception)
|
||||
MP_DEFINE_EXCEPTION(TypeError, Exception)
|
||||
MP_DEFINE_EXCEPTION(ValueError, Exception)
|
||||
//TODO: Implement UnicodeErrors which take arguments
|
||||
|
||||
35
py/objfun.c
35
py/objfun.c
@@ -116,29 +116,6 @@ const mp_obj_type_t mp_type_fun_builtin = {
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
#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_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;
|
||||
o->n_args_max = MP_OBJ_FUN_ARGS_MAX;
|
||||
o->fun = fun;
|
||||
return o;
|
||||
}
|
||||
|
||||
// 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_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;
|
||||
o->n_args_max = n_args_max;
|
||||
o->fun = fun;
|
||||
return o;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* byte code functions */
|
||||
|
||||
@@ -161,9 +138,9 @@ STATIC void fun_bc_print(void (*print)(void *env, const char *fmt, ...), void *e
|
||||
#endif
|
||||
|
||||
#if DEBUG_PRINT
|
||||
STATIC void dump_args(const mp_obj_t *a, int sz) {
|
||||
STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) {
|
||||
DEBUG_printf("%p: ", a);
|
||||
for (int i = 0; i < sz; i++) {
|
||||
for (mp_uint_t i = 0; i < sz; i++) {
|
||||
DEBUG_printf("%p ", a[i]);
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
@@ -196,7 +173,10 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
|
||||
mp_uint_t code_info_size = mp_decode_uint(&code_info);
|
||||
const byte *ip = self->bytecode + code_info_size;
|
||||
|
||||
// bytecode prelude: state size and exception stack size; 16 bit uints
|
||||
// bytecode prelude: skip arg names
|
||||
ip += (self->n_pos_args + self->n_kwonly_args) * sizeof(mp_obj_t);
|
||||
|
||||
// bytecode prelude: state size and exception stack size
|
||||
mp_uint_t n_state = mp_decode_uint(&ip);
|
||||
mp_uint_t n_exc_stack = mp_decode_uint(&ip);
|
||||
|
||||
@@ -291,7 +271,7 @@ const mp_obj_type_t mp_type_fun_bc = {
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
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_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, 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;
|
||||
@@ -306,7 +286,6 @@ mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_ar
|
||||
mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args);
|
||||
o->base.type = &mp_type_fun_bc;
|
||||
o->globals = mp_globals_get();
|
||||
o->args = args;
|
||||
o->n_pos_args = n_pos_args;
|
||||
o->n_kwonly_args = n_kwonly_args;
|
||||
o->n_def_args = n_def_args;
|
||||
|
||||
@@ -27,14 +27,13 @@
|
||||
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
|
||||
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 n_pos_args : 8; // number of arguments this function takes
|
||||
mp_uint_t n_kwonly_args : 8; // number of keyword-only arguments this function takes
|
||||
mp_uint_t n_def_args : 8; // 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)
|
||||
|
||||
@@ -62,6 +62,9 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw
|
||||
mp_uint_t code_info_size = mp_decode_uint(&code_info);
|
||||
const byte *ip = self_fun->bytecode + code_info_size;
|
||||
|
||||
// bytecode prelude: skip arg names
|
||||
ip += (self_fun->n_pos_args + self_fun->n_kwonly_args) * sizeof(mp_obj_t);
|
||||
|
||||
// bytecode prelude: get state size and exception stack size
|
||||
mp_uint_t n_state = mp_decode_uint(&ip);
|
||||
mp_uint_t n_exc_stack = mp_decode_uint(&ip);
|
||||
|
||||
32
py/objint.c
32
py/objint.c
@@ -88,8 +88,8 @@ void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env,
|
||||
// enough, a dynamic one will be allocated.
|
||||
char stack_buf[sizeof(mp_int_t) * 4];
|
||||
char *buf = stack_buf;
|
||||
int buf_size = sizeof(stack_buf);
|
||||
int fmt_size;
|
||||
mp_uint_t buf_size = sizeof(stack_buf);
|
||||
mp_uint_t fmt_size;
|
||||
|
||||
char *str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, self_in, 10, NULL, '\0', '\0');
|
||||
print(env, "%s", str);
|
||||
@@ -135,7 +135,7 @@ STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma)
|
||||
//
|
||||
// The resulting formatted string will be returned from this function and the
|
||||
// formatted size will be in *fmt_size.
|
||||
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
|
||||
char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in,
|
||||
int base, const char *prefix, char base_char, char comma) {
|
||||
fmt_int_t num;
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
@@ -327,20 +327,28 @@ 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(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
mp_int_t val = mp_obj_int_get_checked(args[0]);
|
||||
|
||||
uint len = MP_OBJ_SMALL_INT_VALUE(args[1]);
|
||||
byte *data;
|
||||
|
||||
// TODO: Support long ints
|
||||
// TODO: Support byteorder param
|
||||
// TODO: Support signed param
|
||||
// TODO: Support byteorder param (assumes 'little')
|
||||
// TODO: Support signed param (assumes signed=False)
|
||||
|
||||
mp_int_t val = mp_obj_int_get_checked(args[0]);
|
||||
mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[1]);
|
||||
|
||||
byte *data;
|
||||
mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, len, &data);
|
||||
memset(data, 0, len);
|
||||
memcpy(data, &val, len < sizeof(mp_int_t) ? len : sizeof(mp_int_t));
|
||||
|
||||
if (MP_ENDIANNESS_LITTLE) {
|
||||
memcpy(data, &val, len < sizeof(mp_int_t) ? len : sizeof(mp_int_t));
|
||||
} else {
|
||||
while (len--) {
|
||||
*data++ = val;
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
return mp_obj_str_builder_end(o);
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 2, 4, int_to_bytes);
|
||||
|
||||
STATIC const mp_map_elem_t int_locals_dict_table[] = {
|
||||
|
||||
@@ -36,9 +36,9 @@ typedef struct _mp_obj_int_t {
|
||||
extern const mp_obj_int_t mp_maxsize_obj;
|
||||
|
||||
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
|
||||
char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in,
|
||||
int base, const char *prefix, char base_char, char comma);
|
||||
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
|
||||
char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *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);
|
||||
|
||||
@@ -81,12 +81,12 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
|
||||
// formatted size will be in *fmt_size.
|
||||
//
|
||||
// This particular routine should only be called for the mpz representation of the int.
|
||||
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
|
||||
char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in,
|
||||
int base, const char *prefix, char base_char, char comma) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
|
||||
const mp_obj_int_t *self = self_in;
|
||||
|
||||
uint needed_size = mpz_as_str_size(&self->mpz, base, prefix, comma);
|
||||
mp_uint_t needed_size = mpz_as_str_size(&self->mpz, base, prefix, comma);
|
||||
if (needed_size > *buf_size) {
|
||||
*buf = m_new(char, needed_size);
|
||||
*buf_size = needed_size;
|
||||
|
||||
@@ -164,7 +164,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int len_adj = slice.start - slice.stop;
|
||||
mp_int_t len_adj = slice.start - slice.stop;
|
||||
//printf("Len adj: %d\n", len_adj);
|
||||
assert(len_adj <= 0);
|
||||
mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items/*NULL*/, 0, mp_obj_t);
|
||||
@@ -203,7 +203,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) {
|
||||
assert(0);
|
||||
}
|
||||
int len_adj = slice->len - (slice_out.stop - slice_out.start);
|
||||
mp_int_t len_adj = slice->len - (slice_out.stop - slice_out.start);
|
||||
//printf("Len adj: %d\n", len_adj);
|
||||
if (len_adj > 0) {
|
||||
if (self->len + len_adj > self->alloc) {
|
||||
|
||||
@@ -81,7 +81,7 @@ STATIC uint namedtuple_count_fields(const char *namedef) {
|
||||
|
||||
STATIC int namedtuple_find_field(const char *name, const char *namedef) {
|
||||
int id = 0;
|
||||
int len = strlen(name);
|
||||
size_t len = strlen(name);
|
||||
while (namedef) {
|
||||
if (memcmp(name, namedef, len) == 0) {
|
||||
namedef += len;
|
||||
@@ -101,9 +101,9 @@ STATIC void namedtuple_print(void (*print)(void *env, const char *fmt, ...), voi
|
||||
print(env, "%s(", qstr_str(o->tuple.base.type->name));
|
||||
const char *fields = ((mp_obj_namedtuple_type_t*)o->tuple.base.type)->fields;
|
||||
|
||||
for (int i = 0; i < o->tuple.len; i++) {
|
||||
for (mp_uint_t i = 0; i < o->tuple.len; i++) {
|
||||
if (i > 0) {
|
||||
print(env, ", ");
|
||||
print(env, ", ");
|
||||
}
|
||||
const char *next = fields;
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ STATIC const mp_obj_type_t range_it_type = {
|
||||
.iternext = range_it_iternext,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step) {
|
||||
STATIC mp_obj_t mp_obj_new_range_iterator(mp_int_t cur, mp_int_t stop, mp_int_t step) {
|
||||
mp_obj_range_it_t *o = m_new_obj(mp_obj_range_it_t);
|
||||
o->base.type = &range_it_type;
|
||||
o->cur = cur;
|
||||
|
||||
26
py/objstr.c
26
py/objstr.c
@@ -42,7 +42,6 @@
|
||||
#include "objlist.h"
|
||||
|
||||
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, mp_uint_t n_args, const mp_obj_t *args, mp_obj_t dict);
|
||||
const mp_obj_t mp_const_empty_bytes;
|
||||
|
||||
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);
|
||||
@@ -213,10 +212,10 @@ STATIC mp_obj_t bytes_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k
|
||||
return mp_obj_str_builder_end(o);
|
||||
}
|
||||
|
||||
int len;
|
||||
mp_int_t len;
|
||||
byte *data;
|
||||
vstr_t *vstr = NULL;
|
||||
mp_obj_t o = NULL;
|
||||
mp_obj_t o = MP_OBJ_NULL;
|
||||
// Try to create array of exact len if initializer len is known
|
||||
mp_obj_t len_in = mp_obj_len_maybe(args[0]);
|
||||
if (len_in == MP_OBJ_NULL) {
|
||||
@@ -293,7 +292,7 @@ mp_obj_t mp_obj_str_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
// add 2 strings or bytes
|
||||
|
||||
GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len);
|
||||
int alloc_len = lhs_len + rhs_len;
|
||||
mp_uint_t alloc_len = lhs_len + rhs_len;
|
||||
|
||||
/* code for making qstr
|
||||
byte *q_ptr;
|
||||
@@ -440,8 +439,8 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
|
||||
}
|
||||
|
||||
// count required length
|
||||
int required_len = 0;
|
||||
for (int i = 0; i < seq_len; i++) {
|
||||
mp_uint_t required_len = 0;
|
||||
for (mp_uint_t i = 0; i < seq_len; i++) {
|
||||
if (mp_obj_get_type(seq_items[i]) != self_type) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||
"join expects a list of str/bytes objects consistent with self object"));
|
||||
@@ -456,7 +455,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
|
||||
// make joined string
|
||||
byte *data;
|
||||
mp_obj_t joined_str = mp_obj_str_builder_start(self_type, required_len, &data);
|
||||
for (int i = 0; i < seq_len; i++) {
|
||||
for (mp_uint_t i = 0; i < seq_len; i++) {
|
||||
if (i > 0) {
|
||||
memcpy(data, sep_str, sep_len);
|
||||
data += sep_len;
|
||||
@@ -562,7 +561,7 @@ STATIC mp_obj_t str_rsplit(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// Preallocate list to the max expected # of elements, as we
|
||||
// will fill it from the end.
|
||||
mp_obj_list_t *res = mp_obj_new_list(splits + 1, NULL);
|
||||
int idx = splits;
|
||||
mp_int_t idx = splits;
|
||||
|
||||
if (sep == mp_const_none) {
|
||||
assert(!"TODO: rsplit(None,n) not implemented");
|
||||
@@ -598,7 +597,7 @@ STATIC mp_obj_t str_rsplit(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
if (idx != 0) {
|
||||
// We split less parts than split limit, now go cleanup surplus
|
||||
int used = org_splits + 1 - idx;
|
||||
mp_int_t used = org_splits + 1 - idx;
|
||||
memmove(res->items, &res->items[idx], used * sizeof(mp_obj_t));
|
||||
mp_seq_clear(res->items, used, res->alloc, sizeof(*res->items));
|
||||
res->len = used;
|
||||
@@ -1554,7 +1553,7 @@ STATIC mp_obj_t str_caseconv(unichar (*op)(unichar), mp_obj_t self_in) {
|
||||
GET_STR_DATA_LEN(self_in, self_data, self_len);
|
||||
byte *data;
|
||||
mp_obj_t s = mp_obj_str_builder_start(mp_obj_get_type(self_in), self_len, &data);
|
||||
for (int i = 0; i < self_len; i++) {
|
||||
for (mp_uint_t i = 0; i < self_len; i++) {
|
||||
*data++ = op(*self_data++);
|
||||
}
|
||||
*data = 0;
|
||||
@@ -1577,7 +1576,7 @@ STATIC mp_obj_t str_uni_istype(bool (*f)(unichar), mp_obj_t self_in) {
|
||||
}
|
||||
|
||||
if (f != unichar_isupper && f != unichar_islower) {
|
||||
for (int i = 0; i < self_len; i++) {
|
||||
for (mp_uint_t i = 0; i < self_len; i++) {
|
||||
if (!f(*self_data++)) {
|
||||
return mp_const_false;
|
||||
}
|
||||
@@ -1585,7 +1584,7 @@ STATIC mp_obj_t str_uni_istype(bool (*f)(unichar), mp_obj_t self_in) {
|
||||
} else {
|
||||
bool contains_alpha = false;
|
||||
|
||||
for (int i = 0; i < self_len; i++) { // only check alphanumeric characters
|
||||
for (mp_uint_t i = 0; i < self_len; i++) { // only check alphanumeric characters
|
||||
if (unichar_isalpha(*self_data++)) {
|
||||
contains_alpha = true;
|
||||
if (!f(*(self_data - 1))) { // -1 because we already incremented above
|
||||
@@ -1763,8 +1762,7 @@ const mp_obj_type_t mp_type_bytes = {
|
||||
};
|
||||
|
||||
// the zero-length bytes
|
||||
STATIC const mp_obj_str_t empty_bytes_obj = {{&mp_type_bytes}, 0, 0, NULL};
|
||||
const mp_obj_t mp_const_empty_bytes = (mp_obj_t)&empty_bytes_obj;
|
||||
const mp_obj_str_t mp_const_empty_bytes_obj = {{&mp_type_bytes}, 0, 0, NULL};
|
||||
|
||||
mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, mp_uint_t len, byte **data) {
|
||||
mp_obj_str_t *o = m_new_obj(mp_obj_str_t);
|
||||
|
||||
@@ -36,17 +36,17 @@ typedef struct _mp_obj_str_t {
|
||||
|
||||
// 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)) \
|
||||
mp_uint_t 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)) \
|
||||
mp_uint_t 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)) \
|
||||
const byte *str_data; mp_uint_t 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; }
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ mp_obj_t instance_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, c
|
||||
o = new_ret;
|
||||
|
||||
// now call Python class __init__ function with all args
|
||||
init_fn[0] = init_fn[1] = NULL;
|
||||
init_fn[0] = init_fn[1] = MP_OBJ_NULL;
|
||||
lookup.obj = o;
|
||||
lookup.attr = MP_QSTR___init__;
|
||||
lookup.meth_offset = 0;
|
||||
|
||||
22
py/parse.c
22
py/parse.c
@@ -180,17 +180,17 @@ void mp_parse_node_free(mp_parse_node_t pn) {
|
||||
mp_uint_t rule_id = MP_PARSE_NODE_STRUCT_KIND(pns);
|
||||
if (rule_id == RULE_string) {
|
||||
m_del(char, (char*)pns->nodes[0], (mp_uint_t)pns->nodes[1]);
|
||||
return;
|
||||
}
|
||||
bool adjust = ADD_BLANK_NODE(rule_id);
|
||||
if (adjust) {
|
||||
n--;
|
||||
}
|
||||
for (mp_uint_t i = 0; i < n; i++) {
|
||||
mp_parse_node_free(pns->nodes[i]);
|
||||
}
|
||||
if (adjust) {
|
||||
n++;
|
||||
} else {
|
||||
bool adjust = ADD_BLANK_NODE(rule_id);
|
||||
if (adjust) {
|
||||
n--;
|
||||
}
|
||||
for (mp_uint_t i = 0; i < n; i++) {
|
||||
mp_parse_node_free(pns->nodes[i]);
|
||||
}
|
||||
if (adjust) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
m_del_var(mp_parse_node_struct_t, mp_parse_node_t, n, pns);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@ typedef struct _mp_parse_node_struct_t {
|
||||
#define MP_PARSE_NODE_IS_TOKEN_KIND(pn, k) ((pn) == (MP_PARSE_NODE_TOKEN | ((k) << 5)))
|
||||
|
||||
#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) (((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)
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
static const char pad_spaces[] = " ";
|
||||
static const char pad_zeroes[] = "0000000000000000";
|
||||
|
||||
void pfenv_vstr_add_strn(void *data, const char *str, unsigned int len){
|
||||
void pfenv_vstr_add_strn(void *data, const char *str, mp_uint_t len){
|
||||
vstr_add_strn(data, str, len);
|
||||
}
|
||||
|
||||
int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, char fill, int width) {
|
||||
int pfenv_print_strn(const pfenv_t *pfenv, const char *str, mp_uint_t len, int flags, char fill, int width) {
|
||||
int left_pad = 0;
|
||||
int right_pad = 0;
|
||||
int pad = width - len;
|
||||
@@ -234,8 +234,8 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
|
||||
// enough, a dynamic one will be allocated.
|
||||
char stack_buf[sizeof(mp_int_t) * 4];
|
||||
char *buf = stack_buf;
|
||||
int buf_size = sizeof(stack_buf);
|
||||
int fmt_size = 0;
|
||||
mp_uint_t buf_size = sizeof(stack_buf);
|
||||
mp_uint_t fmt_size = 0;
|
||||
char *str;
|
||||
|
||||
if (prec > 1) {
|
||||
|
||||
@@ -38,12 +38,12 @@
|
||||
|
||||
typedef struct _pfenv_t {
|
||||
void *data;
|
||||
void (*print_strn)(void *, const char *str, unsigned int len);
|
||||
void (*print_strn)(void *, const char *str, mp_uint_t len);
|
||||
} pfenv_t;
|
||||
|
||||
void pfenv_vstr_add_strn(void *data, const char *str, unsigned int len);
|
||||
void pfenv_vstr_add_strn(void *data, const char *str, mp_uint_t len);
|
||||
|
||||
int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, char fill, int width);
|
||||
int pfenv_print_strn(const pfenv_t *pfenv, const char *str, mp_uint_t len, 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
|
||||
|
||||
5
py/py.mk
5
py/py.mk
@@ -111,8 +111,10 @@ PY_O_BASENAME = \
|
||||
pfenv.o \
|
||||
pfenv_printf.o \
|
||||
../extmod/moductypes.o \
|
||||
../extmod/modzlibd.o \
|
||||
../extmod/modujson.o \
|
||||
../extmod/modure.o \
|
||||
../extmod/moduzlib.o \
|
||||
../extmod/moduheapq.o \
|
||||
|
||||
# prepend the build destination prefix to the py object files
|
||||
PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))
|
||||
@@ -165,4 +167,3 @@ $(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT)
|
||||
|
||||
# optimising vm for speed, adds only a small amount to code size but makes a huge difference to speed (20% faster)
|
||||
$(PY_BUILD)/vm.o: CFLAGS += $(CSUPEROPT)
|
||||
|
||||
|
||||
29
py/qstr.c
29
py/qstr.c
@@ -30,6 +30,7 @@
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "gc.h"
|
||||
|
||||
// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)
|
||||
// ultimately we will replace this with a static hash table of some kind
|
||||
@@ -55,7 +56,7 @@
|
||||
#define Q_GET_DATA(q) ((q) + 4)
|
||||
|
||||
// this must match the equivalent function in makeqstrdata.py
|
||||
mp_uint_t qstr_compute_hash(const byte *data, uint len) {
|
||||
mp_uint_t qstr_compute_hash(const byte *data, mp_uint_t len) {
|
||||
// djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html
|
||||
mp_uint_t hash = 5381;
|
||||
for (const byte *top = data + len; data < top; data++) {
|
||||
@@ -71,9 +72,9 @@ mp_uint_t qstr_compute_hash(const byte *data, uint len) {
|
||||
|
||||
typedef struct _qstr_pool_t {
|
||||
struct _qstr_pool_t *prev;
|
||||
uint total_prev_len;
|
||||
uint alloc;
|
||||
uint len;
|
||||
mp_uint_t total_prev_len;
|
||||
mp_uint_t alloc;
|
||||
mp_uint_t len;
|
||||
const byte *qstrs[];
|
||||
} qstr_pool_t;
|
||||
|
||||
@@ -130,7 +131,7 @@ STATIC qstr qstr_add(const byte *q_ptr) {
|
||||
return last_pool->total_prev_len + last_pool->len - 1;
|
||||
}
|
||||
|
||||
qstr qstr_find_strn(const char *str, uint str_len) {
|
||||
qstr qstr_find_strn(const char *str, mp_uint_t str_len) {
|
||||
// work out hash of str
|
||||
mp_uint_t str_hash = qstr_compute_hash((const byte*)str, str_len);
|
||||
|
||||
@@ -151,7 +152,7 @@ qstr qstr_from_str(const char *str) {
|
||||
return qstr_from_strn(str, strlen(str));
|
||||
}
|
||||
|
||||
qstr qstr_from_strn(const char *str, uint len) {
|
||||
qstr qstr_from_strn(const char *str, mp_uint_t len) {
|
||||
qstr q = qstr_find_strn(str, len);
|
||||
if (q == 0) {
|
||||
mp_uint_t hash = qstr_compute_hash((const byte*)str, len);
|
||||
@@ -167,7 +168,7 @@ qstr qstr_from_strn(const char *str, uint len) {
|
||||
return q;
|
||||
}
|
||||
|
||||
byte *qstr_build_start(uint len, byte **q_ptr) {
|
||||
byte *qstr_build_start(mp_uint_t len, byte **q_ptr) {
|
||||
assert(len <= 65535);
|
||||
*q_ptr = m_new(byte, 4 + len + 1);
|
||||
(*q_ptr)[2] = len;
|
||||
@@ -194,7 +195,7 @@ mp_uint_t qstr_hash(qstr q) {
|
||||
return Q_GET_HASH(find_qstr(q));
|
||||
}
|
||||
|
||||
uint qstr_len(qstr q) {
|
||||
mp_uint_t qstr_len(qstr q) {
|
||||
const byte *qd = find_qstr(q);
|
||||
return Q_GET_LENGTH(qd);
|
||||
}
|
||||
@@ -205,13 +206,13 @@ const char *qstr_str(qstr q) {
|
||||
return (const char*)Q_GET_DATA(qd);
|
||||
}
|
||||
|
||||
const byte *qstr_data(qstr q, uint *len) {
|
||||
const byte *qstr_data(qstr q, mp_uint_t *len) {
|
||||
const byte *qd = find_qstr(q);
|
||||
*len = Q_GET_LENGTH(qd);
|
||||
return Q_GET_DATA(qd);
|
||||
}
|
||||
|
||||
void qstr_pool_info(uint *n_pool, uint *n_qstr, uint *n_str_data_bytes, uint *n_total_bytes) {
|
||||
void qstr_pool_info(mp_uint_t *n_pool, mp_uint_t *n_qstr, mp_uint_t *n_str_data_bytes, mp_uint_t *n_total_bytes) {
|
||||
*n_pool = 0;
|
||||
*n_qstr = 0;
|
||||
*n_str_data_bytes = 0;
|
||||
@@ -220,9 +221,17 @@ void qstr_pool_info(uint *n_pool, uint *n_qstr, uint *n_str_data_bytes, uint *n_
|
||||
*n_pool += 1;
|
||||
*n_qstr += pool->len;
|
||||
for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {
|
||||
#if MICROPY_ENABLE_GC
|
||||
*n_str_data_bytes += gc_nbytes(*q); // this counts actual bytes used in heap
|
||||
#else
|
||||
*n_str_data_bytes += Q_GET_ALLOC(*q);
|
||||
#endif
|
||||
}
|
||||
#if MICROPY_ENABLE_GC
|
||||
*n_total_bytes += gc_nbytes(pool); // this counts actual bytes used in heap
|
||||
#else
|
||||
*n_total_bytes += sizeof(qstr_pool_t) + sizeof(qstr) * pool->alloc;
|
||||
#endif
|
||||
}
|
||||
*n_total_bytes += *n_str_data_bytes;
|
||||
}
|
||||
|
||||
16
py/qstr.h
16
py/qstr.h
@@ -45,20 +45,18 @@ typedef mp_uint_t qstr;
|
||||
|
||||
void qstr_init(void);
|
||||
|
||||
mp_uint_t qstr_compute_hash(const byte *data, uint len);
|
||||
qstr qstr_find_strn(const char *str, uint str_len); // returns MP_QSTR_NULL if not found
|
||||
mp_uint_t qstr_compute_hash(const byte *data, mp_uint_t len);
|
||||
qstr qstr_find_strn(const char *str, mp_uint_t str_len); // returns MP_QSTR_NULL if not found
|
||||
|
||||
qstr qstr_from_str(const char *str);
|
||||
qstr qstr_from_strn(const char *str, uint len);
|
||||
//qstr qstr_from_str_static(const char *str);
|
||||
//qstr qstr_from_strn_copy(const char *str, int len);
|
||||
qstr qstr_from_strn(const char *str, mp_uint_t len);
|
||||
|
||||
byte* qstr_build_start(uint len, byte **q_ptr);
|
||||
byte* qstr_build_start(mp_uint_t len, byte **q_ptr);
|
||||
qstr qstr_build_end(byte *q_ptr);
|
||||
|
||||
mp_uint_t qstr_hash(qstr q);
|
||||
const char* qstr_str(qstr q);
|
||||
uint qstr_len(qstr q);
|
||||
const byte* qstr_data(qstr q, uint *len);
|
||||
mp_uint_t qstr_len(qstr q);
|
||||
const byte* qstr_data(qstr q, mp_uint_t *len);
|
||||
|
||||
void qstr_pool_info(uint *n_pool, uint *n_qstr, uint *n_str_data_bytes, uint *n_total_bytes);
|
||||
void qstr_pool_info(mp_uint_t *n_pool, mp_uint_t *n_qstr, mp_uint_t *n_str_data_bytes, mp_uint_t *n_total_bytes);
|
||||
|
||||
@@ -108,6 +108,7 @@ Q(GeneratorExit)
|
||||
Q(ImportError)
|
||||
Q(IndentationError)
|
||||
Q(IndexError)
|
||||
Q(KeyboardInterrupt)
|
||||
Q(KeyError)
|
||||
Q(LookupError)
|
||||
Q(MemoryError)
|
||||
@@ -117,7 +118,6 @@ Q(OSError)
|
||||
Q(OverflowError)
|
||||
Q(RuntimeError)
|
||||
Q(SyntaxError)
|
||||
Q(SystemError)
|
||||
Q(SystemExit)
|
||||
Q(TypeError)
|
||||
Q(UnboundLocalError)
|
||||
@@ -135,11 +135,18 @@ Q(abs)
|
||||
Q(all)
|
||||
Q(any)
|
||||
Q(args)
|
||||
#if MICROPY_PY_ARRAY
|
||||
Q(array)
|
||||
#endif
|
||||
Q(bin)
|
||||
Q({:#b})
|
||||
Q(bool)
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
Q(bytearray)
|
||||
#endif
|
||||
#if MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
Q(memoryview)
|
||||
#endif
|
||||
Q(bytes)
|
||||
Q(callable)
|
||||
#if MICROPY_PY_STRUCT
|
||||
@@ -207,6 +214,12 @@ Q(value)
|
||||
Q(write)
|
||||
Q(zip)
|
||||
|
||||
#if MICROPY_PY_BUILTINS_COMPILE
|
||||
Q(compile)
|
||||
Q(code)
|
||||
Q(single)
|
||||
#endif
|
||||
|
||||
Q(sep)
|
||||
Q(end)
|
||||
|
||||
@@ -437,6 +450,7 @@ Q(BF_LEN)
|
||||
#if MICROPY_PY_IO
|
||||
Q(_io)
|
||||
Q(readall)
|
||||
Q(readinto)
|
||||
Q(readline)
|
||||
Q(readlines)
|
||||
Q(FileIO)
|
||||
@@ -445,6 +459,9 @@ Q(StringIO)
|
||||
Q(BytesIO)
|
||||
Q(getvalue)
|
||||
Q(file)
|
||||
Q(mode)
|
||||
Q(r)
|
||||
Q(encoding)
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_GC
|
||||
@@ -463,8 +480,8 @@ Q(setter)
|
||||
Q(deleter)
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_ZLIBD
|
||||
Q(zlibd)
|
||||
#if MICROPY_PY_UZLIB
|
||||
Q(uzlib)
|
||||
Q(decompress)
|
||||
#endif
|
||||
|
||||
@@ -473,3 +490,19 @@ Q(ujson)
|
||||
Q(dumps)
|
||||
Q(loads)
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_URE
|
||||
Q(ure)
|
||||
Q(compile)
|
||||
Q(match)
|
||||
Q(search)
|
||||
Q(group)
|
||||
Q(DEBUG)
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_UHEAPQ
|
||||
Q(uheapq)
|
||||
Q(heappush)
|
||||
Q(heappop)
|
||||
Q(heapify)
|
||||
#endif
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#if MICROPY_HELPER_REPL
|
||||
|
||||
bool str_startswith_word(const char *str, const char *head) {
|
||||
int i;
|
||||
mp_uint_t i;
|
||||
for (i = 0; str[i] && head[i]; i++) {
|
||||
if (str[i] != head[i]) {
|
||||
return false;
|
||||
|
||||
89
py/runtime.c
89
py/runtime.c
@@ -24,6 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
@@ -46,7 +47,11 @@
|
||||
#include "smallint.h"
|
||||
#include "objgenerator.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
#include "parsehelper.h"
|
||||
#include "compile.h"
|
||||
#include "stackctrl.h"
|
||||
#include "gc.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -57,6 +62,9 @@
|
||||
#define DEBUG_OP_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
// pending exception object (MP_OBJ_NULL if not pending)
|
||||
mp_obj_t mp_pending_exception;
|
||||
|
||||
// locals and globals need to be pointers because they can be the same in outer module scope
|
||||
STATIC mp_obj_dict_t *dict_locals;
|
||||
STATIC mp_obj_dict_t *dict_globals;
|
||||
@@ -74,6 +82,9 @@ void mp_init(void) {
|
||||
qstr_init();
|
||||
mp_stack_ctrl_init();
|
||||
|
||||
// no pending exceptions to start with
|
||||
mp_pending_exception = MP_OBJ_NULL;
|
||||
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
mp_init_emergency_exception_buf();
|
||||
#endif
|
||||
@@ -109,14 +120,14 @@ void mp_deinit(void) {
|
||||
|
||||
mp_obj_t mp_load_const_int(qstr qstr) {
|
||||
DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
|
||||
uint len;
|
||||
mp_uint_t len;
|
||||
const byte* data = qstr_data(qstr, &len);
|
||||
return mp_parse_num_integer((const char*)data, len, 0);
|
||||
}
|
||||
|
||||
mp_obj_t mp_load_const_dec(qstr qstr) {
|
||||
DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
|
||||
uint len;
|
||||
mp_uint_t len;
|
||||
const byte* data = qstr_data(qstr, &len);
|
||||
return mp_parse_num_decimal((const char*)data, len, true, false);
|
||||
}
|
||||
@@ -128,7 +139,7 @@ mp_obj_t mp_load_const_str(qstr qstr) {
|
||||
|
||||
mp_obj_t mp_load_const_bytes(qstr qstr) {
|
||||
DEBUG_OP_printf("load b'%s'\n", qstr_str(qstr));
|
||||
uint len;
|
||||
mp_uint_t len;
|
||||
const byte *data = qstr_data(qstr, &len);
|
||||
return mp_obj_new_bytes(data, len);
|
||||
}
|
||||
@@ -470,8 +481,8 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
}
|
||||
if (type->getiter != NULL) {
|
||||
/* second attempt, walk the iterator */
|
||||
mp_obj_t next = NULL;
|
||||
mp_obj_t iter = mp_getiter(rhs);
|
||||
mp_obj_t next;
|
||||
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
|
||||
if (mp_obj_equal(next, lhs)) {
|
||||
return mp_const_true;
|
||||
@@ -1093,8 +1104,7 @@ import_error:
|
||||
}
|
||||
|
||||
// See if it's a package, then can try FS import
|
||||
mp_load_method_maybe(module, MP_QSTR___path__, dest);
|
||||
if (dest[0] == MP_OBJ_NULL) {
|
||||
if (!mp_obj_is_package(module)) {
|
||||
goto import_error;
|
||||
}
|
||||
|
||||
@@ -1153,9 +1163,74 @@ void mp_globals_set(mp_obj_dict_t *d) {
|
||||
dict_globals = d;
|
||||
}
|
||||
|
||||
// this is implemented in this file so it can optimise access to locals/globals
|
||||
mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_input_kind, mp_obj_dict_t *globals, mp_obj_dict_t *locals) {
|
||||
// parse the string
|
||||
mp_parse_error_kind_t parse_error_kind;
|
||||
mp_parse_node_t pn = mp_parse(lex, parse_input_kind, &parse_error_kind);
|
||||
|
||||
if (pn == MP_PARSE_NODE_NULL) {
|
||||
// parse error; raise exception
|
||||
mp_obj_t exc = mp_parse_make_exception(lex, parse_error_kind);
|
||||
mp_lexer_free(lex);
|
||||
nlr_raise(exc);
|
||||
}
|
||||
|
||||
qstr source_name = mp_lexer_source_name(lex);
|
||||
mp_lexer_free(lex);
|
||||
|
||||
// save context and set new context
|
||||
mp_obj_dict_t *old_globals = mp_globals_get();
|
||||
mp_obj_dict_t *old_locals = mp_locals_get();
|
||||
mp_globals_set(globals);
|
||||
mp_locals_set(locals);
|
||||
|
||||
// compile the string
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
|
||||
|
||||
// check if there was a compile error
|
||||
if (mp_obj_is_exception_instance(module_fun)) {
|
||||
mp_globals_set(old_globals);
|
||||
mp_locals_set(old_locals);
|
||||
nlr_raise(module_fun);
|
||||
}
|
||||
|
||||
// for compile only
|
||||
if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) {
|
||||
mp_globals_set(old_globals);
|
||||
mp_locals_set(old_locals);
|
||||
return module_fun;
|
||||
}
|
||||
|
||||
// complied successfully, execute it
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_obj_t ret = mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
mp_globals_set(old_globals);
|
||||
mp_locals_set(old_locals);
|
||||
return ret;
|
||||
} else {
|
||||
// exception; restore context and re-raise same exception
|
||||
mp_globals_set(old_globals);
|
||||
mp_locals_set(old_locals);
|
||||
nlr_raise(nlr.ret_val);
|
||||
}
|
||||
}
|
||||
|
||||
void *m_malloc_fail(size_t num_bytes) {
|
||||
DEBUG_printf("memory allocation failed, allocating " UINT_FMT " bytes\n", num_bytes);
|
||||
nlr_raise((mp_obj_t)&mp_const_MemoryError_obj);
|
||||
if (0) {
|
||||
// dummy
|
||||
#if MICROPY_ENABLE_GC
|
||||
} else if (gc_is_locked()) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError,
|
||||
"memory allocation failed, heap is locked"));
|
||||
#endif
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError,
|
||||
"memory allocation failed, allocating " UINT_FMT " bytes", num_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
NORETURN void mp_not_implemented(const char *msg) {
|
||||
|
||||
@@ -116,6 +116,7 @@ mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type);
|
||||
mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, mp_uint_t n_args_kw, const mp_obj_t *args);
|
||||
NORETURN void mp_native_raise(mp_obj_t o);
|
||||
|
||||
extern mp_obj_t mp_pending_exception;
|
||||
extern struct _mp_obj_list_t mp_sys_path_obj;
|
||||
extern struct _mp_obj_list_t mp_sys_argv_obj;
|
||||
#define mp_sys_path ((mp_obj_t)&mp_sys_path_obj)
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
// Implements backend of sequence * integer operation. Assumes elements are
|
||||
// memory-adjacent in sequence.
|
||||
void mp_seq_multiply(const void *items, mp_uint_t item_sz, mp_uint_t len, mp_uint_t times, void *dest) {
|
||||
for (int i = 0; i < times; i++) {
|
||||
for (mp_uint_t i = 0; i < times; i++) {
|
||||
uint copy_sz = item_sz * len;
|
||||
memcpy(dest, items, copy_sz);
|
||||
dest = (char*)dest + copy_sz;
|
||||
@@ -185,8 +185,8 @@ bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, mp_uint_t len1, const
|
||||
}
|
||||
}
|
||||
|
||||
int len = len1 < len2 ? len1 : len2;
|
||||
for (int i = 0; i < len; i++) {
|
||||
mp_uint_t len = len1 < len2 ? len1 : len2;
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
// If current elements equal, can't decide anything - go on
|
||||
if (mp_obj_equal(items1[i], items2[i])) {
|
||||
continue;
|
||||
|
||||
87
py/showbc.c
87
py/showbc.c
@@ -57,9 +57,7 @@
|
||||
ip += sizeof(mp_uint_t); \
|
||||
} while (0)
|
||||
|
||||
void mp_bytecode_print2(const byte *ip, int len);
|
||||
|
||||
void mp_bytecode_print(const void *descr, const byte *ip, int len) {
|
||||
void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *ip, mp_uint_t len) {
|
||||
const byte *ip_start = ip;
|
||||
|
||||
// get code info size
|
||||
@@ -69,9 +67,27 @@ void mp_bytecode_print(const void *descr, const byte *ip, int len) {
|
||||
|
||||
qstr block_name = mp_decode_uint(&code_info);
|
||||
qstr source_file = mp_decode_uint(&code_info);
|
||||
printf("File %s, code block '%s' (descriptor: %p, bytecode @%p %d bytes)\n",
|
||||
printf("File %s, code block '%s' (descriptor: %p, bytecode @%p " UINT_FMT " bytes)\n",
|
||||
qstr_str(source_file), qstr_str(block_name), descr, code_info, len);
|
||||
|
||||
// raw bytecode dump
|
||||
printf("Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n", code_info_size, len - code_info_size);
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf(" %02x", ip_start[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// bytecode prelude: arg names (as qstr objects)
|
||||
printf("arg names:");
|
||||
for (int i = 0; i < n_total_args; i++) {
|
||||
printf(" %s", qstr_str(MP_OBJ_QSTR_VALUE(*(mp_obj_t*)ip)));
|
||||
ip += sizeof(mp_obj_t);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// bytecode prelude: state size and exception stack size; 16 bit uints
|
||||
{
|
||||
uint n_state = mp_decode_uint(&ip);
|
||||
@@ -89,15 +105,14 @@ void mp_bytecode_print(const void *descr, const byte *ip, int len) {
|
||||
printf("(INIT_CELL %u)\n", local_num);
|
||||
}
|
||||
len -= ip - ip_start;
|
||||
ip_start = ip;
|
||||
}
|
||||
|
||||
// print out line number info
|
||||
{
|
||||
mp_int_t bc = (code_info + code_info_size) - ip;
|
||||
mp_int_t bc = (ip_start + code_info_size) - ip; // start counting from the prelude
|
||||
mp_uint_t source_line = 1;
|
||||
printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line);
|
||||
for (const byte* ci = code_info + 12; *ci;) {
|
||||
for (const byte* ci = code_info; *ci;) {
|
||||
if ((ci[0] & 0x80) == 0) {
|
||||
// 0b0LLBBBBB encoding
|
||||
bc += ci[0] & 0x1f;
|
||||
@@ -115,14 +130,13 @@ void mp_bytecode_print(const void *descr, const byte *ip, int len) {
|
||||
mp_bytecode_print2(ip, len - 0);
|
||||
}
|
||||
|
||||
void mp_bytecode_print2(const byte *ip, int len) {
|
||||
void mp_bytecode_print2(const byte *ip, mp_uint_t len) {
|
||||
const byte *ip_start = ip;
|
||||
mp_uint_t unum;
|
||||
qstr qstr;
|
||||
while (ip - ip_start < len) {
|
||||
printf("%02u ", (uint)(ip - ip_start));
|
||||
int op = *ip++;
|
||||
switch (op) {
|
||||
switch (*ip++) {
|
||||
case MP_BC_LOAD_CONST_FALSE:
|
||||
printf("LOAD_CONST_FALSE");
|
||||
break;
|
||||
@@ -176,18 +190,6 @@ void mp_bytecode_print2(const byte *ip, int len) {
|
||||
printf("LOAD_NULL");
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_FAST_0:
|
||||
printf("LOAD_FAST_0");
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_FAST_1:
|
||||
printf("LOAD_FAST_1");
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_FAST_2:
|
||||
printf("LOAD_FAST_2");
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_FAST_N:
|
||||
DECODE_UINT;
|
||||
printf("LOAD_FAST_N " UINT_FMT, unum);
|
||||
@@ -226,18 +228,6 @@ void mp_bytecode_print2(const byte *ip, int len) {
|
||||
printf("LOAD_SUBSCR");
|
||||
break;
|
||||
|
||||
case MP_BC_STORE_FAST_0:
|
||||
printf("STORE_FAST_0");
|
||||
break;
|
||||
|
||||
case MP_BC_STORE_FAST_1:
|
||||
printf("STORE_FAST_1");
|
||||
break;
|
||||
|
||||
case MP_BC_STORE_FAST_2:
|
||||
printf("STORE_FAST_2");
|
||||
break;
|
||||
|
||||
case MP_BC_STORE_FAST_N:
|
||||
DECODE_UINT;
|
||||
printf("STORE_FAST_N " UINT_FMT, unum);
|
||||
@@ -383,16 +373,6 @@ void mp_bytecode_print2(const byte *ip, int len) {
|
||||
printf("NOT");
|
||||
break;
|
||||
|
||||
case MP_BC_UNARY_OP:
|
||||
unum = *ip++;
|
||||
printf("UNARY_OP " UINT_FMT, unum);
|
||||
break;
|
||||
|
||||
case MP_BC_BINARY_OP:
|
||||
unum = *ip++;
|
||||
printf("BINARY_OP " UINT_FMT, unum);
|
||||
break;
|
||||
|
||||
case MP_BC_BUILD_TUPLE:
|
||||
DECODE_UINT;
|
||||
printf("BUILD_TUPLE " UINT_FMT, unum);
|
||||
@@ -520,9 +500,22 @@ void mp_bytecode_print2(const byte *ip, int len) {
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("code %p, byte code 0x%02x not implemented\n", ip, op);
|
||||
assert(0);
|
||||
return;
|
||||
if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) {
|
||||
printf("LOAD_CONST_SMALL_INT " INT_FMT, (mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16);
|
||||
} else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) {
|
||||
printf("LOAD_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI);
|
||||
} else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
|
||||
printf("STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI);
|
||||
} else if (ip[-1] < MP_BC_UNARY_OP_MULTI + 5) {
|
||||
printf("UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI);
|
||||
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 35) {
|
||||
printf("BINARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_BINARY_OP_MULTI);
|
||||
} else {
|
||||
printf("code %p, byte code 0x%02x not implemented\n", ip, ip[-1]);
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -57,23 +57,23 @@ bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y) {
|
||||
}
|
||||
|
||||
mp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor) {
|
||||
mp_int_t lsign = (dividend >= 0) ? 1 :-1;
|
||||
mp_int_t rsign = (divisor >= 0) ? 1 :-1;
|
||||
// Python specs require that mod has same sign as second operand
|
||||
dividend %= divisor;
|
||||
if (lsign != rsign) {
|
||||
if ((dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0)) {
|
||||
dividend += divisor;
|
||||
}
|
||||
return dividend;
|
||||
}
|
||||
|
||||
mp_int_t mp_small_int_floor_divide(mp_int_t num, mp_int_t denom) {
|
||||
mp_int_t lsign = num > 0 ? 1 : -1;
|
||||
mp_int_t rsign = denom > 0 ? 1 : -1;
|
||||
if (lsign == -1) {num *= -1;}
|
||||
if (rsign == -1) {denom *= -1;}
|
||||
if (lsign != rsign){
|
||||
return - ( num + denom - 1) / denom;
|
||||
if (num >= 0) {
|
||||
if (denom < 0) {
|
||||
num += -denom - 1;
|
||||
}
|
||||
} else {
|
||||
return num / denom;
|
||||
if (denom >= 0) {
|
||||
num += -denom + 1;
|
||||
}
|
||||
}
|
||||
return num / denom;
|
||||
}
|
||||
|
||||
77
py/stream.c
77
py/stream.c
@@ -60,7 +60,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in);
|
||||
|
||||
#define STREAM_CONTENT_TYPE(stream) (((stream)->is_text) ? &mp_type_str : &mp_type_bytes)
|
||||
|
||||
STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t stream_read(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
|
||||
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
|
||||
// CPython: io.UnsupportedOperation, OSError subclass
|
||||
@@ -110,7 +110,7 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
|
||||
}
|
||||
|
||||
if (out_sz < more_bytes) {
|
||||
@@ -166,7 +166,8 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
#endif
|
||||
|
||||
byte *buf = m_new(byte, sz);
|
||||
byte *buf;
|
||||
mp_obj_t ret_obj = mp_obj_str_builder_start(STREAM_CONTENT_TYPE(o->type->stream_p), sz, &buf);
|
||||
int error;
|
||||
mp_uint_t out_sz = o->type->stream_p->read(o, buf, sz, &error);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
@@ -178,11 +179,9 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
// this as EOF.
|
||||
return mp_const_none;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
|
||||
} else {
|
||||
mp_obj_t s = mp_obj_new_str_of_type(STREAM_CONTENT_TYPE(o->type->stream_p), buf, out_sz); // will reallocate to use exact size
|
||||
m_free(buf, sz);
|
||||
return s;
|
||||
return mp_obj_str_builder_end_with_len(ret_obj, out_sz);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +203,7 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t len) {
|
||||
// see abobe.
|
||||
return mp_const_none;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
|
||||
} else {
|
||||
return MP_OBJ_NEW_SMALL_INT(out_sz);
|
||||
}
|
||||
@@ -216,6 +215,38 @@ STATIC mp_obj_t stream_write_method(mp_obj_t self_in, mp_obj_t arg) {
|
||||
return mp_stream_write(self_in, bufinfo.buf, bufinfo.len);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t stream_readinto(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
|
||||
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
|
||||
// CPython: io.UnsupportedOperation, OSError subclass
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported"));
|
||||
}
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
|
||||
|
||||
// CPython extension: if 2nd arg is provided, that's max len to read,
|
||||
// instead of full buffer. Similar to
|
||||
// https://docs.python.org/3/library/socket.html#socket.socket.recv_into
|
||||
mp_uint_t len = bufinfo.len;
|
||||
if (n_args > 2) {
|
||||
len = mp_obj_int_get(args[2]);
|
||||
if (len > bufinfo.len) {
|
||||
len = bufinfo.len;
|
||||
}
|
||||
}
|
||||
|
||||
int error;
|
||||
mp_uint_t out_sz = o->type->stream_p->read(o, bufinfo.buf, len, &error);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
if (is_nonblocking_error(error)) {
|
||||
return mp_const_none;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
|
||||
} else {
|
||||
return MP_OBJ_NEW_SMALL_INT(out_sz);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
|
||||
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)self_in;
|
||||
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
|
||||
@@ -223,12 +254,12 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported"));
|
||||
}
|
||||
|
||||
int total_size = 0;
|
||||
mp_uint_t total_size = 0;
|
||||
vstr_t *vstr = vstr_new_size(DEFAULT_BUFFER_SIZE);
|
||||
char *p = vstr_str(vstr);
|
||||
int error;
|
||||
int current_read = DEFAULT_BUFFER_SIZE;
|
||||
mp_uint_t current_read = DEFAULT_BUFFER_SIZE;
|
||||
while (true) {
|
||||
int error;
|
||||
mp_uint_t out_sz = o->type->stream_p->read(self_in, p, current_read, &error);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
if (is_nonblocking_error(error)) {
|
||||
@@ -240,7 +271,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
|
||||
}
|
||||
if (out_sz == 0) {
|
||||
break;
|
||||
@@ -265,7 +296,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
|
||||
}
|
||||
|
||||
// Unbuffered, inefficient implementation of readline() for raw I/O files.
|
||||
STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t stream_unbuffered_readline(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
|
||||
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
|
||||
// CPython: io.UnsupportedOperation, OSError subclass
|
||||
@@ -284,18 +315,33 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) {
|
||||
vstr = vstr_new();
|
||||
}
|
||||
|
||||
int error;
|
||||
while (max_size == -1 || max_size-- != 0) {
|
||||
char *p = vstr_add_len(vstr, 1);
|
||||
if (p == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory"));
|
||||
}
|
||||
|
||||
int error;
|
||||
mp_uint_t out_sz = o->type->stream_p->read(o, p, 1, &error);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
||||
if (is_nonblocking_error(error)) {
|
||||
if (vstr->len == 1) {
|
||||
// We just incremented it, but otherwise we read nothing
|
||||
// and immediately got EAGAIN. This is case is not well
|
||||
// specified in
|
||||
// https://docs.python.org/3/library/io.html#io.IOBase.readline
|
||||
// unlike similar case for read(). But we follow the latter's
|
||||
// behavior - return None.
|
||||
vstr_free(vstr);
|
||||
return mp_const_none;
|
||||
} else {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
|
||||
}
|
||||
if (out_sz == 0) {
|
||||
done:
|
||||
// Back out previously added byte
|
||||
// Consider, what's better - read a char and get OutOfMemory (so read
|
||||
// char is lost), or allocate first as we do.
|
||||
@@ -335,6 +381,7 @@ mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) {
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj, 1, 2, stream_read);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj, 2, 3, stream_readinto);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_readall_obj, stream_readall);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj, 1, 2, stream_unbuffered_readline);
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write_obj, stream_write_method);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_stream_read_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_stream_readinto_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_stream_readall_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readline_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readlines_obj);
|
||||
|
||||
107
py/vm.c
107
py/vm.c
@@ -110,10 +110,12 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
|
||||
code_state->ip = ip; \
|
||||
goto *entry_table[*ip++]; \
|
||||
} while(0)
|
||||
#define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check
|
||||
#define ENTRY(op) entry_##op
|
||||
#define ENTRY_DEFAULT entry_default
|
||||
#else
|
||||
#define DISPATCH() break
|
||||
#define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check
|
||||
#define ENTRY(op) case op
|
||||
#define ENTRY_DEFAULT default
|
||||
#endif
|
||||
@@ -223,18 +225,6 @@ dispatch_loop:
|
||||
PUSH(MP_OBJ_NULL);
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_LOAD_FAST_0):
|
||||
obj_shared = fastn[0];
|
||||
goto load_check;
|
||||
|
||||
ENTRY(MP_BC_LOAD_FAST_1):
|
||||
obj_shared = fastn[-1];
|
||||
goto load_check;
|
||||
|
||||
ENTRY(MP_BC_LOAD_FAST_2):
|
||||
obj_shared = fastn[-2];
|
||||
goto load_check;
|
||||
|
||||
ENTRY(MP_BC_LOAD_FAST_N):
|
||||
DECODE_UINT;
|
||||
obj_shared = fastn[-unum];
|
||||
@@ -288,18 +278,6 @@ dispatch_loop:
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_STORE_FAST_0):
|
||||
fastn[0] = POP();
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_STORE_FAST_1):
|
||||
fastn[-1] = POP();
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_STORE_FAST_2):
|
||||
fastn[-2] = POP();
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_STORE_FAST_N):
|
||||
DECODE_UINT;
|
||||
fastn[-unum] = POP();
|
||||
@@ -396,21 +374,21 @@ dispatch_loop:
|
||||
ENTRY(MP_BC_JUMP):
|
||||
DECODE_SLABEL;
|
||||
ip += unum;
|
||||
DISPATCH();
|
||||
DISPATCH_WITH_PEND_EXC_CHECK();
|
||||
|
||||
ENTRY(MP_BC_POP_JUMP_IF_TRUE):
|
||||
DECODE_SLABEL;
|
||||
if (mp_obj_is_true(POP())) {
|
||||
ip += unum;
|
||||
}
|
||||
DISPATCH();
|
||||
DISPATCH_WITH_PEND_EXC_CHECK();
|
||||
|
||||
ENTRY(MP_BC_POP_JUMP_IF_FALSE):
|
||||
DECODE_SLABEL;
|
||||
if (!mp_obj_is_true(POP())) {
|
||||
ip += unum;
|
||||
}
|
||||
DISPATCH();
|
||||
DISPATCH_WITH_PEND_EXC_CHECK();
|
||||
|
||||
ENTRY(MP_BC_JUMP_IF_TRUE_OR_POP):
|
||||
DECODE_SLABEL;
|
||||
@@ -419,7 +397,7 @@ dispatch_loop:
|
||||
} else {
|
||||
sp--;
|
||||
}
|
||||
DISPATCH();
|
||||
DISPATCH_WITH_PEND_EXC_CHECK();
|
||||
|
||||
ENTRY(MP_BC_JUMP_IF_FALSE_OR_POP):
|
||||
DECODE_SLABEL;
|
||||
@@ -428,7 +406,7 @@ dispatch_loop:
|
||||
} else {
|
||||
ip += unum;
|
||||
}
|
||||
DISPATCH();
|
||||
DISPATCH_WITH_PEND_EXC_CHECK();
|
||||
|
||||
ENTRY(MP_BC_SETUP_WITH): {
|
||||
mp_obj_t obj = TOP();
|
||||
@@ -526,7 +504,7 @@ unwind_jump:
|
||||
if (unum != 0) {
|
||||
sp--;
|
||||
}
|
||||
DISPATCH();
|
||||
DISPATCH_WITH_PEND_EXC_CHECK();
|
||||
|
||||
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
|
||||
ENTRY(MP_BC_SETUP_EXCEPT):
|
||||
@@ -606,19 +584,6 @@ unwind_jump:
|
||||
}
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_UNARY_OP):
|
||||
unum = *ip++;
|
||||
SET_TOP(mp_unary_op(unum, TOP()));
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_BINARY_OP): {
|
||||
unum = *ip++;
|
||||
mp_obj_t rhs = POP();
|
||||
mp_obj_t lhs = TOP();
|
||||
SET_TOP(mp_binary_op(unum, lhs, rhs));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_BUILD_TUPLE):
|
||||
DECODE_UINT;
|
||||
sp -= unum - 1;
|
||||
@@ -890,7 +855,53 @@ yield:
|
||||
mp_import_all(POP());
|
||||
DISPATCH();
|
||||
|
||||
ENTRY_DEFAULT: {
|
||||
#if MICROPY_OPT_COMPUTED_GOTO
|
||||
ENTRY(MP_BC_LOAD_CONST_SMALL_INT_MULTI):
|
||||
PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16));
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_LOAD_FAST_MULTI):
|
||||
obj_shared = fastn[MP_BC_LOAD_FAST_MULTI - (mp_int_t)ip[-1]];
|
||||
goto load_check;
|
||||
|
||||
ENTRY(MP_BC_STORE_FAST_MULTI):
|
||||
fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP();
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_UNARY_OP_MULTI):
|
||||
SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP()));
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_BINARY_OP_MULTI): {
|
||||
mp_obj_t rhs = POP();
|
||||
mp_obj_t lhs = TOP();
|
||||
SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY_DEFAULT:
|
||||
#else
|
||||
ENTRY_DEFAULT:
|
||||
if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) {
|
||||
PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16));
|
||||
DISPATCH();
|
||||
} else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) {
|
||||
obj_shared = fastn[MP_BC_LOAD_FAST_MULTI - (mp_int_t)ip[-1]];
|
||||
goto load_check;
|
||||
} else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
|
||||
fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP();
|
||||
DISPATCH();
|
||||
} else if (ip[-1] < MP_BC_UNARY_OP_MULTI + 5) {
|
||||
SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP()));
|
||||
DISPATCH();
|
||||
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 35) {
|
||||
mp_obj_t rhs = POP();
|
||||
mp_obj_t lhs = TOP();
|
||||
SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs));
|
||||
DISPATCH();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented");
|
||||
nlr_pop();
|
||||
fastn[0] = obj;
|
||||
@@ -900,6 +911,14 @@ yield:
|
||||
#if !MICROPY_OPT_COMPUTED_GOTO
|
||||
} // switch
|
||||
#endif
|
||||
|
||||
pending_exception_check:
|
||||
if (mp_pending_exception != MP_OBJ_NULL) {
|
||||
mp_obj_t obj = mp_pending_exception;
|
||||
mp_pending_exception = MP_OBJ_NULL;
|
||||
RAISE(obj);
|
||||
}
|
||||
|
||||
} // for loop
|
||||
|
||||
} else {
|
||||
|
||||
@@ -41,9 +41,6 @@ static void* entry_table[256] = {
|
||||
[MP_BC_LOAD_CONST_BYTES] = &&entry_MP_BC_LOAD_CONST_BYTES,
|
||||
[MP_BC_LOAD_CONST_STRING] = &&entry_MP_BC_LOAD_CONST_STRING,
|
||||
[MP_BC_LOAD_NULL] = &&entry_MP_BC_LOAD_NULL,
|
||||
[MP_BC_LOAD_FAST_0] = &&entry_MP_BC_LOAD_FAST_0,
|
||||
[MP_BC_LOAD_FAST_1] = &&entry_MP_BC_LOAD_FAST_1,
|
||||
[MP_BC_LOAD_FAST_2] = &&entry_MP_BC_LOAD_FAST_2,
|
||||
[MP_BC_LOAD_FAST_N] = &&entry_MP_BC_LOAD_FAST_N,
|
||||
[MP_BC_LOAD_DEREF] = &&entry_MP_BC_LOAD_DEREF,
|
||||
[MP_BC_LOAD_NAME] = &&entry_MP_BC_LOAD_NAME,
|
||||
@@ -52,9 +49,6 @@ static void* entry_table[256] = {
|
||||
[MP_BC_LOAD_METHOD] = &&entry_MP_BC_LOAD_METHOD,
|
||||
[MP_BC_LOAD_BUILD_CLASS] = &&entry_MP_BC_LOAD_BUILD_CLASS,
|
||||
[MP_BC_LOAD_SUBSCR] = &&entry_MP_BC_LOAD_SUBSCR,
|
||||
[MP_BC_STORE_FAST_0] = &&entry_MP_BC_STORE_FAST_0,
|
||||
[MP_BC_STORE_FAST_1] = &&entry_MP_BC_STORE_FAST_1,
|
||||
[MP_BC_STORE_FAST_2] = &&entry_MP_BC_STORE_FAST_2,
|
||||
[MP_BC_STORE_FAST_N] = &&entry_MP_BC_STORE_FAST_N,
|
||||
[MP_BC_STORE_DEREF] = &&entry_MP_BC_STORE_DEREF,
|
||||
[MP_BC_STORE_NAME] = &&entry_MP_BC_STORE_NAME,
|
||||
@@ -86,8 +80,6 @@ static void* entry_table[256] = {
|
||||
[MP_BC_POP_BLOCK] = &&entry_MP_BC_POP_BLOCK,
|
||||
[MP_BC_POP_EXCEPT] = &&entry_MP_BC_POP_EXCEPT,
|
||||
[MP_BC_NOT] = &&entry_MP_BC_NOT,
|
||||
[MP_BC_UNARY_OP] = &&entry_MP_BC_UNARY_OP,
|
||||
[MP_BC_BINARY_OP] = &&entry_MP_BC_BINARY_OP,
|
||||
[MP_BC_BUILD_TUPLE] = &&entry_MP_BC_BUILD_TUPLE,
|
||||
[MP_BC_BUILD_LIST] = &&entry_MP_BC_BUILD_LIST,
|
||||
[MP_BC_LIST_APPEND] = &&entry_MP_BC_LIST_APPEND,
|
||||
@@ -114,6 +106,11 @@ static void* entry_table[256] = {
|
||||
[MP_BC_IMPORT_NAME] = &&entry_MP_BC_IMPORT_NAME,
|
||||
[MP_BC_IMPORT_FROM] = &&entry_MP_BC_IMPORT_FROM,
|
||||
[MP_BC_IMPORT_STAR] = &&entry_MP_BC_IMPORT_STAR,
|
||||
[MP_BC_LOAD_CONST_SMALL_INT_MULTI ... MP_BC_LOAD_CONST_SMALL_INT_MULTI + 63] = &&entry_MP_BC_LOAD_CONST_SMALL_INT_MULTI,
|
||||
[MP_BC_LOAD_FAST_MULTI ... MP_BC_LOAD_FAST_MULTI + 15] = &&entry_MP_BC_LOAD_FAST_MULTI,
|
||||
[MP_BC_STORE_FAST_MULTI ... MP_BC_STORE_FAST_MULTI + 15] = &&entry_MP_BC_STORE_FAST_MULTI,
|
||||
[MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + 4] = &&entry_MP_BC_UNARY_OP_MULTI,
|
||||
[MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + 34] = &&entry_MP_BC_BINARY_OP_MULTI,
|
||||
};
|
||||
|
||||
#if __clang__
|
||||
|
||||
18
py/vstr.c
18
py/vstr.c
@@ -263,24 +263,6 @@ copy:
|
||||
vstr->buf[vstr->len] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
void vstr_add_le16(vstr_t *vstr, unsigned short v) {
|
||||
byte *buf = (byte*)vstr_add_len(vstr, 2);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
encode_le16(buf, v);
|
||||
}
|
||||
|
||||
void vstr_add_le32(vstr_t *vstr, unsigned int v) {
|
||||
byte *buf = (byte*)vstr_add_len(vstr, 4);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
encode_le32(buf, v);
|
||||
}
|
||||
*/
|
||||
|
||||
char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len) {
|
||||
if (vstr->had_error) {
|
||||
return NULL;
|
||||
|
||||
@@ -36,8 +36,9 @@ void do_str(const char *src) {
|
||||
mp_lexer_free(lex);
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
||||
|
||||
if (module_fun == mp_const_none) {
|
||||
if (mp_obj_is_exception_instance(module_fun)) {
|
||||
// compile error
|
||||
mp_obj_print_exception(module_fun);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,10 +70,10 @@ mp_import_stat_t mp_import_stat(const char *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
void nlr_jump_fail(void *val) {
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user