[
  {
    "path": ".gitignore",
    "content": "/.vscode/settings.json\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2013, 2014 Damien P. George\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# MicroPython\n\n[中文页](README_ZH.md) | English\n\n## 1. Introduction\n\nThis is a port of `MicroPython` on RT-Thread, which can run on **RT-Thread 3.0** or higher. This software package can run `MicroPython` on embedded systems equipped with RT-Thread.\n\nIf it is the first time to come into contact with RT-Thread MicroPython, it is recommended that you use RT-Thread officially supported development boards to get started quickly. These development boards have complete firmware functions and provide source code, suitable for introductory learning, and officially support development boards [firmware download Please click on me](https://www.rt-thread.org/qa/forum.php?mod=viewthread&tid=12305&extra=page%3D1%26filter%3Dtypeid%26typeid%3D20).\n\n### 1.1 Directory structure\n\n| Name | Description |\n| ---- | ---- |\n| docs | Document directory, including getting started guide and development manual |\n| drivers | MicroPython source code directory |\n| extmod | MicroPython Source Code Directory |\n| lib | MicroPython source code directory |\n| py | MicroPython source code directory |\n| port | Porting code directory |\n| LICENSE | Micropython MIT License |\n\n### 1.2 License\n\nRT-Thread MicroPython follows the MIT license, see the `LICENSE` file for details.\n\n### 1.3 Dependency\n\n- RT-Thread 3.0+\n\n## 2. How to open RT-Thread MicroPython\n\nTo use `MicroPython package`, you need to select it in the RT-Thread package manager. The specific path is as follows:\n\n![elect_micropytho](./docs/assets/select_micropython.png)\n\nThen let the RT-Thread package manager automatically update, or use the `pkgs --update` command to update the package to the BSP.\n\n## 3. Use RT-Thread MicroPython\n\n### 3.1 Add software package to project\n\nAfter selecting `MicroPython package`, when compiling with `bsp` again, it will be added to the `bsp` project for compilation.\n\n* For firmware development, please refer to [《MicroPython Firmware Development Guide》](./docs/firmware-develop.md)\n\n* For more MicroPython documentation, please visit [RT-Thread Documentation Center](https://www.rt-thread.org/document/site/submodules/micropython/docs/introduction/)\n\n\n### 3.2 Using MicroPython IDE\n\n[RT-Thread MicroPython IDE](https://marketplace.visualstudio.com/items?itemName=RT-Thread.rt-thread-micropython) provides a powerful development environment for MicroPython, which can be directly searched and downloaded through the VScode application store. Examples are as follows:\n\n![08_direct_run_files](docs/assets/08_direct_run_files.gif)\n\n\n### 3.3 Add C extension to MicroPython\n\nIn order to facilitate users to add their own C functions to MicroPython to be called by Python scripts, RT-Thread provides [MicroPython C binding code automatic generator](https://summerlife.github.io/RT-MicroPython-Generator/) For everyone to use. With this tool, users only need a few simple steps to achieve C function extension. The following figure shows the form of the automatically generated C code.\n\n![08_direct_run_files](docs/assets/c-gen.png)\n\n## 4. Matters needing attention\n\n- Need to use **RT-Thread 3.0** or above\n- Select the `latest` version of `Micropython` in the `menuconfig` option\n- Currently, the `ffi` module under `System Module` only supports GCC toolchain, and relevant information needs to be added to the link script\n\n## 5. Development resources\n\n* [RT-Thread MicroPython Forum](https://www.rt-thread.org/qa/forum.php)\n* [RT-Thread MicroPython Documentation Center](https://www.rt-thread.org/document/site/submodules/micropython/docs/introduction/)\n* [Click to join the RT-Thread MicroPython exchange group](https://jq.qq.com/?_wv=1027&k=5EhyEjx)\n"
  },
  {
    "path": "README_ZH.md",
    "content": "# MicroPython\n\n中文页 | [English](README.md)\n\n## 1、介绍\n\n这是一个在 RT-Thread 上的 `MicroPython` 移植，可以运行在 **RT-Thread 3.0** 版本以上。通过该软件包可以在搭载了 RT-Thread 的嵌入式系统上运行 `MicroPython`。\n\n如果是第一次接触 RT-Thread MicroPython，推荐你先通过 RT-Thread 官方支持的开发板来快速上手，这些开发板的固件功能完善并提供源代码，适合入门学习，官方支持开发板 [固件下载请点我](https://www.rt-thread.org/qa/forum.php?mod=viewthread&tid=12305&extra=page%3D1%26filter%3Dtypeid%26typeid%3D20)。\n\n### 1.1 目录结构\n\n| 名称 | 说明 |\n| ---- | ---- |\n| docs  | 文档目录，包括入门指南和开发手册 |\n| drivers | MicroPython 源代码目录 |\n| extmod | MicroPython 源代码目录 |\n| lib | MicroPython 源代码目录 |\n| py | MicroPython 源代码目录 |\n| port | 移植代码目录 |\n| LICENSE | Micropython MIT 许可证 |\n\n### 1.2 许可证\n\nRT-Thread MicroPython  遵循 MIT 许可，详见 `LICENSE` 文件。\n\n### 1.3 依赖\n\n- RT-Thread 3.0+\n\n## 2、如何打开 RT-Thread MicroPython\n\n使用 `MicroPython package` 需要在 RT-Thread 的包管理器中选择它，具体路径如下：\n\n![elect_micropytho](./docs/assets/select_micropython.png)\n\n然后让 RT-Thread 的包管理器自动更新，或者使用 `pkgs --update` 命令更新包到 BSP 中。\n\n## 3、使用 RT-Thread MicroPython\n\n### 3.1 添加软件包到工程\n\n选中 `MicroPython package` 后，再次进行 `bsp` 编译时，它会被加入到 `bsp` 工程中进行编译。\n\n* 固件开发可参考 [《MicroPython 固件开发指南》](./docs/firmware-develop.md)\n\n* 查阅更多 MicroPython 说明文档请访问 [RT-Thread 文档中心](https://www.rt-thread.org/document/site/submodules/micropython/docs/introduction/)\n\n\n### 3.2 使用 MicroPython IDE\n\n[RT-Thread MicroPython IDE](https://marketplace.visualstudio.com/items?itemName=RT-Thread.rt-thread-micropython) 为 MicroPython 提供了强大的开发环境，可以通过 VScode 应用商店直接查询下载，示例如下所示：\n\n![08_direct_run_files](docs/assets/08_direct_run_files.gif)\n\n\n### 3.3 向 MicroPython 添加 C 扩展\n\n为了方便用户添加自己编写的 C 函数到 MicroPython 中被 Python 脚本调用，RT-Thread 提供了 [MicroPython C 绑定代码自动生成器](https://summerlife.github.io/RT-MicroPython-Generator/) 供大家使用。通过该工具，用户只需要简单几步，即可实现 C 函数扩展，下图展示了自动生成的 C 代码的形式。\n\n![08_direct_run_files](docs/assets/c-gen.png)\n\n## 4、注意事项\n\n- 需要使用 **RT-Thread 3.0** 以上版本\n- 在 `menuconfig` 选项中选择 `Micropython` 的 `latest` 版本\n- 目前 `System Module` 下的 `ffi` 模块只支持 GCC 工具链，且需要在链接脚本中添加相关段信息\n\n## 5、开发资源\n\n* [RT-Thread MicroPython 论坛](https://www.rt-thread.org/qa/forum.php)\n* [RT-Thread MicroPython 文档中心](https://www.rt-thread.org/document/site/submodules/micropython/docs/introduction/)\n* [点击加入 RT-Thread MicroPython 交流群](https://jq.qq.com/?_wv=1027&k=5EhyEjx)\n"
  },
  {
    "path": "SConscript",
    "content": "from building import *\nimport rtconfig\n\n# get current directory\ncwd     = GetCurrentDir()\n# The set of source files associated with this SConscript file.\nsrc     = Glob('py/*.c')\nsrc    += Glob('lib/mp-readline/*.c')\nsrc    += Glob('lib/utils/*.c')\nsrc    += Glob('extmod/*.c')\nsrc    += Glob('port/*.c')\nsrc    += Glob('port/modules/*.c')\nsrc    += Glob('port/modules/machine/*.c')\nsrc    += Glob('port/modules/user/*.c')\nsrc    += Glob('lib/netutils/*.c')\nsrc    += Glob('lib/timeutils/*.c')\nsrc    += Glob('drivers/bus/*.c')\nsrc    += Glob('port/native/*.c')\n\npath    = [cwd + '/']\npath   += [cwd + '/port']\npath   += [cwd + '/port/modules']\npath   += [cwd + '/port/modules/machine']\n\nLOCAL_CCFLAGS = ''\n\nif rtconfig.PLATFORM in ['gcc', 'armclang']:\n    LOCAL_CCFLAGS += ' -std=gnu99'\nelif rtconfig.PLATFORM in ['keil']:\n    LOCAL_CCFLAGS += ' --c99 --gnu'\n\ngroup = DefineGroup('MicroPython', src, depend = ['PKG_USING_MICROPYTHON'], CPPPATH = path, LOCAL_CCFLAGS = LOCAL_CCFLAGS)\n\nReturn('group')\n"
  },
  {
    "path": "docs/external_c_modules.md",
    "content": "# 为 MicroPython 扩展 C 模块\n\n当使用原生 MicroPython 进行开发时，你可能会遇到这样一些限制，比如官方没有实现自己想要的功能，或者你觉得这些实现不符合自己的工作需求。此时，添加自己的 C 模块到 MicroPython 中是一个不错的选择，你可以按照自己的想法，设计适合自己的 Python 函数调用。\n\n为了帮助各位开发者快速添加 C 模块，RT-Thread 提供了相应的辅助工具 [C 绑定代码自动生成器](https://summerlife.github.io/RT-MicroPython-Generator/)。该工具可以帮助开发者自动生成 C 代码和 MicroPython 之间的接口层，开发者只需将 C 语言编写的功能代码添加到指定位置，MicroPython 即可直接调用该功能。\n\n## Python 调用 C 函数的实现原理\n\nC 语言和 Python 是两种完全不同的语言，如何使用 MicroPython 来调用 C 语言所实现的函数是许多小伙伴非常疑惑的地方。简单来说，这个问题的关键点在于，如何用 C 语言的形式在 MicroPython 源代码中**表述函数的入参和出参**。我举一个例子来讲解这个问题， 请观察如下 Python 函数：\n\n```python\ndef add(a, b):\n    return a + b\n```\n\n该函数有两个入参，返回一个参数。此时如果能用 C 语言表示该 **Python 函数的输入输出参数**，就可以将一个实现该功能的 C 函数对接到 MicroPython 中。\n\n### 添加用户函数到 MicroPython\n\n假设上述函数的参数类型都为整形，通过自动生成器可以得到如下样板函数：\n\n```c\nSTATIC mp_obj_t add(\n    mp_obj_t arg_1_obj,\n    mp_obj_t arg_2_obj) {\n    mp_int_t arg_1 = mp_obj_get_int(arg_1_obj);  /* 通过 Python 获取的第一个整形参数 arg_1 */\n    mp_int_t arg_2 = mp_obj_get_int(arg_2_obj);  /* 通过 Python 获取的第二个整形参数 arg_2 */\n    mp_int_t ret_val;\n\n    /* Your code start! */\n\n    ret_val = arg_1 + arg_2;  /* 处理入参 arg_1 和 arg_2，并将结果赋给返回值 ret_val */\n\n    /* Your code end! */\n\n    return mp_obj_new_int(ret_val);               /* 向 python 返回整形参数 ret_val */\n}\nMP_DEFINE_CONST_FUN_OBJ_2(add_obj, add);\n```\n\n生成器会处理好需要导出到 MicroPython 的函数的入参和出参，而开发者只需要编写相应的代码来处理这些输入参数，并且把返回值赋给输出参数即可。 通过包含头文件的方式，可以调用先前编写的 C 函数来对输入参数进行处理，或者根据输入参数来执行相应的动作，添加控制硬件的驱动的原理也是一样的。\n\n最终使用 Python 调用 C 函数的效果如下：  \n\n```python\n>>> import userfunc\n>>> userfunc.add(666,777)\n1443\n```\n\n### 添加用户模块到 MicroPython\n\n添加用户模块到 MicroPython 中也不难，首先应当熟练掌握上述添加 C 函数的过程，然后参考 PR [add module userfunc to MicroPython](https://github.com/RT-Thread-packages/micropython/pull/144) 来添加属于自己的模块，该 PR 实现了添加 `userfunc` 模块到 MicroPython 的功能，你可以按照同样的方式将自己编写的模块注册到 MicroPython 中，要注意仔细查看这个 PR 中修改的 4 个文件，不要漏掉修改的细节。\n"
  },
  {
    "path": "docs/firmware-develop.md",
    "content": "## MicroPython 固件开发指南\n\n如果手上没有官方支持固件的开发板，就需要自己来动手制作 MicroPython 固件了。由于 RT-Thread 官方提供了 [MicroPython 软件包](https://github.com/RT-Thread-packages/micropython)，并且 MicroPython 底层和硬件绑定时对接了 RT-Thread 驱动框架，因此可以很方便地在运行了 RT-Thread 的板卡上将 MicroPython 跑起来。\n\n**注意**：RT-Thread MicroPython 需要运行在 **RT-Thread 3.0** 版本以上。\n\n### 选择合适的 BSP 平台\n\nRT-Thread MicroPython mini 版本占用资源最大不超过：\n\n- ROM : 190KB\n- RAM :  20KB\n\n只要系统资源满足上述要求，常见的许多开发板都可以运行 MicroPython，例如 STM32 系列 BSP。\n\n接下来我们以 `rt-thread\\bsp\\stm32\\stm32f407-atk-explorer` 上的 MDK 工程为例，讲解如何在 BSP 的基础上制作 MicroPython 固件。\n\n### 获取 MicroPython 软件包\n\n先使用 `pkgs --upgrade` 命令更新软件包列表，然后通过 env 工具选中 MicroPython 软件包，最后使用 `pkgs --update` 命令将软件包拉取到本地。\n\n![select_mpy_package](assets/select_mpy_package.png)\n\n### 增大 main 线程栈\n\n为了能后续在 main 线程中启动 MicroPython 运行时环境，需要增大 main 线程的栈大小，这里我们将栈大小增加到 8k。\n\n![add_main_stack](assets/add_main_stack.png)\n\n### 配置 MicroPython 运行环境堆大小\n\n接下来根据板卡内存实际剩余情况来给 MicroPython 运行环境分配内存，这里填写的数值越大，就能运行更大代码量的 Python 程序。但是如果这里填写的数值超过了实际可分配内存，就可能会出现无法分配内存而报错。因此在配置此项目之前，需要对系统 RAM 资源的分配情况有一定了解。\n\n#### 查看系统剩余内存\n\n重新生成工程，编译下载后通过 `msh` 的 `free` 命令来查看内存使用情况。\n\n![check_memory](assets/check_memory.png)\n\n#### 配置系统\n\n通过上一步查询的内存分配情况，对系统 RAM 资源有了一定的了解。在本次示例中，我们分配 20k 内存用于 MicroPython 运行时环境。后续如果想要运行更多 MicroPython 代码，可以将更多空余内存分配给 MicroPython 运行时环境，配置如下图所示：\n\n![config_runtime](assets/config_runtime.png)\n\n### 在系统根目录挂载文件系统\n\n最后要确保系统中 `/` 目录挂载了文件系统。有了文件系统，后续才能使用 [**MicroPython 开发环境**](https://marketplace.visualstudio.com/items?itemName=RT-Thread.rt-thread-micropython) 将 Python 代码文件同步到板卡中来运行。\n\n1. 打开 MicroPython 的文件同步功能选项\n\n![open filesync option](assets/open_filesync_option.png)\n\n2. 本次示例使用的开发板，文件系统存放在 SPI Flash 上，BSP 对该存储设备的支持已经做好了，在这里只需开启 elm-fat 文件系统即可，对系统进行如下配置：\n\n![mount_fs](assets/mount_fs.png)\n\n配置完成后，记得要使用 `scons --target=mkd5` 重新生成工程，使配置在工程中生效。\n\n当你在自己的板卡上运行 MicroPython 时，你可以自由选择文件系统的存储介质，但是有一点很重要，文件系统要被挂载到根目录 / 上，这样才能保证在后续使用 MicroPython IDE 进行文件传输时不会出错。\n\n### 在 main 线程中启动 MicroPython \n\n最后要在 main 线程中启动 MicroPython，代码修改如下所示：\n\n```c\n#include <rtthread.h>\n#include <rtdevice.h>\n#include <board.h>\n#include <dfs_fs.h>\n#include <rtdevice.h>\n\n/* 文件系统所在分区名称，根据实际情况填写 */\n#define FS_PARTITION_NAME     \"W25Q128\"\n\nint main(void)\n{\n    /* 挂载 elm 文件系统到 / 目录，如果你所使用的开发板没有文件系统也可以跳过这一步 */\n    if (dfs_mount(FS_PARTITION_NAME, \"/\", \"elm\", 0, 0) == 0)\n    {\n        rt_kprintf(\"Filesystem initialized!\");\n    }\n    else\n    {\n        /* 如果挂载失败，则尝试在文件系统分区重新创建文件系统 */\n        dfs_mkfs(\"elm\", FS_PARTITION_NAME);\n        /* 尝试重新挂载文件系统 */\n        if (dfs_mount(FS_PARTITION_NAME, \"/\", \"elm\", 0, 0) == 0)\n        {\n            /* 仍然挂载文件系统失败，请自行检查失败原因 */\n            rt_kprintf(\"Failed to initialize filesystem!\");\n        }\n    }\n\n    rt_thread_mdelay(100);\n\n    while(1)\n    {\n        /* 在这里让程序进入循环，通过这种方式实现 MicroPython 的软复位*/\n        extern void mpy_main(const char *filename);\n         /* 启动 MicroPython */\n        mpy_main(NULL);\n    }\n\n    return RT_EOK;\n}\n```\n\n重新编译工程并下载程序到板卡中，就会在 main 线程中自动启动 MicroPython，接下来就可以使用 [**RT-Thread MicroPython 开发环境**](https://marketplace.visualstudio.com/items?itemName=RT-Thread.rt-thread-micropython) 来进行应用开发了。 通过开发环境连接到开发板，即可看到 MicroPython 的交互环境 REPL，如下图所示：\n\n![en_connect_board](assets/en_connect_board.gif)\n\n"
  },
  {
    "path": "docs/introduction.md",
    "content": "# MicroPython 入门必读\n\n本文档将初步介绍 MicroPython 的基本概念，RT-Thread MicroPython 的特性与优势，以及可以被用在哪些领域。\n\n## 主要特性\n\n- MicroPython 是 Python 3 编程语言的一种精简而高效的实现，它包含 Python 标准库的一个子集，并被优化为在微控制器和受限环境中运行。\n\n- RT-Thread MicroPython 可以运行在任何搭载了 RT-Thread 操作系统并且有一定资源的嵌入式平台上。\n\n- MicroPython 可以运行在有一定资源的开发板上，给你一个低层次的 Python 操作系统，可以用来控制各种电子系统。\n\n- MicroPython 富有各种高级特性，比如交互式提示、任意精度整数、闭包函数、列表解析、生成器、异常处理等等。\n\n- MicroPython 的目标是尽可能与普通 Python 兼容，使开发者能够轻松地将代码从桌面端转移到微控制器或嵌入式系统。程序可移植性很强，因为不需要考虑底层驱动，所以程序移植变得轻松和容易。\n\n## MicroPython 的优势\n\n- Python 是一款容易上手的脚本语言，同时具有强大的功能，语法优雅简单。使用 MicroPython 编程可以降低嵌入式的开发门槛，让更多的人体验嵌入式的乐趣。\n- 通过 MicroPython 实现硬件底层的访问和控制，不需要了解底层寄存器、数据手册、厂家的库函数等，即可轻松控制硬件。\n- 外设与常用功能都有相应的模块，降低开发难度，使开发和移植变得容易和快速。\n\n## MicroPython 的应用领域\n\n- MicroPython 在嵌入式系统上完整实现了 Python3 的核心功能，可以在产品开发的各个阶段给开发者带来便利。\n- 通过 MicroPython 提供的库和函数，开发者可以快速控制 LED、液晶、舵机、多种传感器、SD、UART、I2C 等，实现各种功能，而不用再去研究底层硬件模块的使用方法，翻看寄存器手册。这样不但降低了开发难度，而且减少了重复开发工作，可以加快开发速度，提高开发效率。以前需要较高水平的嵌入式工程师花费数天甚至数周才能完成的功能，现在普通的嵌入式开发者用几个小时就能实现类似的功能。\n- 随着半导体技术的不断发展，芯片的功能、内部的存储器容量和资源不断增加，成本不断降低，可以使用 MicroPython 来进行开发设计的应用领域也会越来越多。\n\n### 产品原型验证\n\n- 众所周知，在开发新产品时，原型设计是一个非常重要的环节，这个环节需要以最快速的方式设计出产品的大致模型，并验证业务流程或者技术点。与传统开发方法相比，使用 MicroPython 对于原型验证非常有用，让原型验证过程变得轻松，加速原型验证过程。\n- 在进行一些物联网功能开发时，网络功能也是 MicroPython 的长处，可以利用现成的众多 MicroPython 网络模块，节省开发时间。而这些功能如果使用 C/C++ 来完成，会耗费几倍的时间。\n\n### 硬件测试\n\n- 嵌入式产品在开发时，一般会分为硬件开发及软件开发。硬件工程师并不一定都擅长软件开发，所以在测试新硬件时，经常需要软件工程师参与。这就导致软件工程师可能会耗费很多时间帮助硬件工程师查找设计或者焊接问题。有了 MicroPython 后，将 MicroPython 固件烧入待测试的新硬件，在检查焊接、连线等问题时，只需使用简单的 Python 命令即可测试。这样，硬件工程师一人即可搞定，再也不用麻烦别人了。\n\n### 创客 DIY\n\n- MicroPython 无需复杂的设置，不需要安装特别的软件环境和额外的硬件，使用任何文本编辑器就可以进行编程。大部分硬件功能，使用一个命令就能驱动，不用了解硬件底层就能快速开发。这些特性使得 MicroPython 非常适合创客使用来开发一些有创意的项目。\n- 下面是使用 MicroPython 开发的一些 DIY 项目：\n    - [显示温湿度的 WIFI 时钟](https://www.bilibili.com/video/av15929152?from=search&seid=16285206333541196172)\n    - [OpenMV 智能摄像头](https://www.bilibili.com/video/av16418889?from=search&seid=16285206333541196172)\n    - [快速实现人脸识别](https://www.bilibili.com/video/av73853903?from=search&seid=9793819178982436353)\n    - [搭建 MQTT 服务器](http://www.360doc.com/content/17/1218/22/8473307_714341237.shtml)\n\n### 教育\n\n- MicroPython 使用简单、方便，非常适合于编程入门。在校学生或者业余爱好者都可以通过 MicroPython 快速的开发一些好玩的项目，在开发的过程中学习编程思想，提高自己的动手能力。\n"
  },
  {
    "path": "docs/micropython-ide.md",
    "content": "# MicroPython IDE\n\nRT-Thread 为广大开发者提供了 VSCode 最好用的 MicroPython 插件 来帮助大家使用 MicroPython 来开发应用程序。该插件为 MicroPython 开发提供了功能强大的开发环境，主要特性如下：\n\n- 便捷的开发板连接方式（串口、网络、USB）\n- 支持基于 MicroPython 的代码智能补全与语法检查\n- 支持 MicroPython REPL 交互环境\n- 提供丰富的代码示例与 demo 程序\n- 提供工程同步功能\n- 支持下载单个文件或文件夹至开发板\n- 支持在内存中快速运行代码文件功能\n- 支持运行代码片段功能\n- 支持多款主流 MicroPython 开发板\n- 支持 Windows、Ubuntu、Mac 操作系统\n\n### 安装 IDE 开发环境\n\n开发者可以通过 RT-Thread MicroPython IDE 来快速开发 MicroPython 应用，下图展示了 IDE 的快速调试功能：\n\n![08_direct_run_files](assets/08_direct_run_files.gif)\n\n可通过查看如下文档进一步了解并使用 RT-Thread MicroPython IDE：\n\n- [RT-Thread MicroPython Develop Environment](https://marketplace.visualstudio.com/items?itemName=RT-Thread.rt-thread-micropython)"
  },
  {
    "path": "docs/micropython-librarys.md",
    "content": "# MicroPython 库\n\n### MicroPython 标准库\n\n- [`Builtin functions and exceptions`](std-librarys/builtins.md) – 内置函数与异常\n- [`cmath`](std-librarys/cmath.md)  – 复数运算函数功能\n- [`gc`](std-librarys/gc.md) – 控制垃圾收集器\n- [`math`](std-librarys/math.md) – 数学函数功能\n- [`sys`](std-librarys/sys.md) – 系统特定功能\n- [`uarray`](std-librarys/uarray.md) – 数组存储功能\n- [`ubinascii`](std-librarys/ubinascii.md) – 二进制与 ASCII 码转换功能\n- [`ucollections`](std-librarys/ucollections.md) – 集合与容器类型\n- [`uerrno`](std-librarys/uerrno.md) – 系统错误码\n- [`uhashlib`](std-librarys/uhashlib.md) – 哈希算法\n- [`uheapq`](std-librarys/uheapq.md) – 堆队列算法\n- [`uio`](std-librarys/uio.md) – 输入输出流\n- [`ujson`](std-librarys/ujson.md) – JSON 编解码\n- [`uos`](std-librarys/uos.md) – 基本的操作系统服务\n- [`ure`](std-librarys/ure.md) – 正则表达式\n- [`uselect`](std-librarys/uselect.md) – 在一组 streams 上等待事件\n- [`usocket`](std-librarys/usocket.md) – socket 模块\n- [`ussl`](std-librarys/ussl.md) – SSL/TLS 模块\n- [`ustruct`](std-librarys/ustruct.md) – 原生数据类型的打包和解包\n- [`utime`](std-librarys/utime.md) – 时间相关功能\n- [`uzlib`](std-librarys/uzlib.md) – zlib 解压\n- [`_thread`](std-librarys/_thread.md) – 多线程支持\n\n### MicroPython 特定库\n\n在 RT-Thread 移植的 MicroPython 版本中，实现了如下特定功能库：\n\n- [`micropython`](spec-librarys/micropython.md) – 实现 MicroPython 内部功能访问与控制\n- [`rtthread`](spec-librarys/rtthread.md) – RT-Thread 系统功能模块\n- [`machine`](spec-librarys/machine.md) – 硬件控制模块\n    - [Pin](spec-librarys/machine/Pin.md) \n    - [I2C ](spec-librarys/machine/I2C.md)\n    - [SPI](spec-librarys/machine/SPI.md)\n    - [UART](spec-librarys/machine/UART.md)\n    - [LCD](spec-librarys/machine/LCD.md)\n    - [RTC](spec-librarys/machine/RTC.md)\n    - [PWM](spec-librarys/machine/PWM.md)\n    - [ADC](spec-librarys/machine/ADC.md)\n    - [WDT](spec-librarys/machine/WDT.md)\n    - [TIMER](spec-librarys/machine/Timer.md)\n\n- [`network`](spec-librarys/network.md) – 网络功能配置模块\n    - [wlan](spec-librarys/network/wlan.md) \n"
  },
  {
    "path": "docs/micropython-mpy.md",
    "content": "# MicroPython .mpy 文件详解\n\nMicroPython 定义了 `.mpy` 文件的概念，该文件是一种二进制容器文件格式，在其中包含了预编译的 Python 代码，这种类型的文件可以像普通的 `.py` 模块一样被导入到  MicroPython 程序中。举个例子来说明这种类型文件的使用方法。例如，只要 `foo.mpy` 存在于指定的路径中，我们就可以通过 `import foo` 语句来导入 `foo.mpy` 文件。\n\n这种类型文件的导入规则是这样的，首先按顺序搜索 `sys.path` 中列出的每个目录。当搜索特定目录时，首先查找 `foo.py`，如果找不到该目录，则查找 `foo.mpy`，如果没有找到，则在下一个目录中继续搜索。通过这种方式，`foo.py` 文件的优先级将高于 `foo.mpy` 文件。这些 `.mpy` 文件中的主要内容是字节码，这种类型的文件可以通过 `mpy-cross` 程序从 Python 源文件（`.py`文件）生成。\n\n"
  },
  {
    "path": "docs/micropython_for_pandora_iot_board.md",
    "content": "# MicroPython for Pandora IoT Board\n\n![IoT_Board](assets/IoT_Board.png)\n\n[**IoT Board 潘多拉**](https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-18400369818.12.2ba47ea5PzJxZx&id=583843059625) 是 RT-Thread 推出的一款物联网开发板，它给开发者带来了物联网时代的无限可能。而现在，它已经不仅仅是一块简单的物联网开发板，因为它已经全面支持 **MicroPython** 。在 IoT Board 上，你将会体验到有别于传统的，前所未有的开发方式。\n\n借助于 MicroPython，你将有能力使用 Python 语言控制所有硬件外设，体验高级语言带来的便利特性，与此同时你还可以利用高级软件库快速实现你的 IoT 构想。\n\n## 硬件支持\n\nPandora MicroPython 固件硬件功能如下所示：\n\n| 外设名称 | 引脚号                                         | 简介                                      |\n| -------- | ---------------------------------------------- | ----------------------------------------- |\n| pin      | PA4 PA8, PB8-9 PB10-15, PC2 PC4 PC6-7, PD12-15 | 开发板引出的可自由分配的 IO，支持引脚中断 |\n| led      | PE7                                            | 红色 led 灯                               |\n| rgb      | R: PE7, G: PE8, B: PE9                         | rgb 灯                                    |\n| key      | KEY0: PD10, KEY1: PD9, KEY2: PD8               | 输入按键                                  |\n| uart1    | PA9, PA10                                      | 串口1                                     |\n| i2c      |                                                | 软件 i2c 可选择任意 pin                   |\n| spi      |                                                | 软件 spi 可选择任意引出 pin               |\n| adc      | PC4                                            | adc1，通道 13                             |\n| pwm      | PB0                                            | pwm3,  通道 3,  用于红外发射              |\n| timer    |                                                | 硬件定时器 15                             |\n| wdt      |                                                | 看门狗                                    |\n| rtc      |                                                | 实时时钟                                  |\n| beeper   | PB2                                            | 蜂鸣器                                    |\n| lcd      |                                                | lcd 显示屏                                |\n| wifi     |                                                | wifi 网络连接                             |\n| aht10    | CLK: PD6, SDA: PC1                             | 温湿度传感器                              |\n| ap3216c  | CLK: PC0, SDA: PC1                             | 接近与光强传感器                          |\n| icm20608 | CLK: PC0, SDA: PC1                             | 六轴传感器                                |\n\n\n## 入门必读\n\n如果您从来没有了解过 MicroPython, 可以阅读这篇简短的文章来 [带你入门 MicroPython](introduction.md)。\n\n## 开启 MicroPython 之旅\n\n推荐遵循如下步骤开始进行 MicroPython 开发：\n\n- 在您的开发板上烧录合适的固件\n- 在 PC 机上安装 RT-Thread MicroPython 开发环境并连接上开发板  \n\n接下来就可以尽情挥洒您的创意了，更详细的内容可以点击下文中的链接来进一步了解。\n\n### 下载合适的固件\n\n- [Pandora IoT Board firmware](https://www.rt-thread.org/qa/forum.php?mod=viewthread&tid=12305&extra=page%3D1%26filter%3Dtypeid%26typeid%3D20)\n\n### 安装 IDE 开发环境\n\n- [RT-Thread MicroPython develop environment](https://marketplace.visualstudio.com/items?itemName=RT-Thread.rt-thread-micropython)\n\n## 开发资料\n\n### 示例程序\n\n以下示例程序可以在 RT-Thread MicroPython IDE 开发环境中直接添加到工程：\n\n![check_pandora_examples](assets/check_pandora_examples.png)\n\n### MicroPython 模块详解\n\n- [MicroPython Librarys](micropython-librarys.md)\n\n\n## 联系我们\n\n如果在使用的过程中遇到问题，您可以用如下方式联系我们：\n\n- 在 github 上提交 issue\n- [RT-Thread MicroPython 官方论坛](https://www.rt-thread.org/qa/forum.php?mod=forumdisplay&fid=2&filter=typeid&typeid=20)\n\n- RT-Thread MicroPython 交流 QQ 群：703840633"
  },
  {
    "path": "docs/micropython_for_sparrow_one_board.md",
    "content": "# MicroPython for sparrow one board\n\n![sparrow_one](assets/sparrow_one_board.png)\n\n[**麻雀一号开发板**](https://item.taobao.com/item.htm?spm=a1z10.1-c.w4004-5210898174.2.29401ae39JyGKY&id=606684373403) 是 RT-Thread 推出的一款物联网音视频开发板，现在它已经全面支持 **MicroPython** 。在麻雀一号开发板上，你将会体验到有别于传统的，前所未有的开发方式。\n\n借助于 MicroPython，你将有能力使用 Python 语言控制所有硬件外设，体验高级语言带来的便利特性，与此同时你还可以利用高级软件库快速实现你的 IoT 构想。\n\n## 硬件支持\n\n麻雀一号开发板固件硬件功能如下所示：\n\n| 外设名称  | 简介                                                       |\n| --------- | ---------------------------------------------------------- |\n| key       | 输入按键                                                   |\n| uart1     | 串口1                                                      |\n| lcd       | lcd 显示屏                                                 |\n| wifi      | wifi 网络连接                                              |\n| bluetooth | 蓝牙                                                       |\n| player    | 扬声器，音频播放                                           |\n| recorder  | 麦克风，录音功能                                           |\n| camera    | 摄像头，可拍照并存入文件系统，开启 TCP Server 查看实时图像 |\n\n## 入门必读\n\n如果您从来没有了解过 MicroPython, 可以阅读这篇简短的文章来 [带你入门 MicroPython](https://github.com/RT-Thread-packages/micropython/blob/master/docs/introduction.md)。\n\n## 开启 MicroPython 之旅\n\n推荐遵循如下步骤开始进行 MicroPython 开发：\n\n- 在您的开发板上烧录合适的固件\n- 在 PC 机上安装 RT-Thread MicroPython 开发环境并连接上开发板\n\n接下来就可以尽情挥洒您的创意了，更详细的内容可以点击下文中的链接来进一步了解。\n\n### 下载合适的固件\n\n- [Sparrow One Board firmware](https://www.rt-thread.org/qa/forum.php?mod=viewthread&tid=12305&extra=page%3D1%26filter%3Dtypeid%26typeid%3D20)\n\n### 安装 IDE 开发环境\n\n- [RT-Thread MicroPython develop environment](https://marketplace.visualstudio.com/items?itemName=RT-Thread.rt-thread-micropython)\n\n## 开发资料\n\n### 示例程序\n\n以下示例程序可以在 RT-Thread MicroPython IDE 开发环境中直接添加到工程：\n\n![sparrow_example](assets/sparrow_example.png)\n\n### MicroPython 模块详解\n\n- [MicroPython Librarys](https://github.com/RT-Thread-packages/micropython/blob/master/docs/micropython-librarys.md)\n\n\n## 联系我们\n\n如果在使用的过程中遇到问题，您可以用如下方式联系我们：\n\n- 在 github 上提交 issue\n- [RT-Thread MicroPython 官方论坛](https://www.rt-thread.org/qa/forum.php?mod=forumdisplay&fid=2&filter=typeid&typeid=20)\n\n- RT-Thread MicroPython 交流 QQ 群：703840633\n"
  },
  {
    "path": "docs/micropython_for_w601_iot_board.md",
    "content": "# MicroPython for W601 IoT Board\n\n![IoT_Board](assets/W60x_HW_origin.png)\n\n[**W601 IoT Board**](https://item.taobao.com/item.htm?spm=a230r.1.14.13.7c5b4a9bS2LYUD&id=602233847745&ns=1&abbucket=17#detail) 是 RT-Thread 推出的一款物联网开发板，它给开发者带来了物联网时代的无限可能。而现在，它已经不仅仅是一块简单的物联网开发板，因为它已经全面支持 **MicroPython** 。在 IoT Board 上，你将会体验到有别于传统的，前所未有的开发方式。\n\n借助于 MicroPython，你将有能力使用 Python 语言控制所有硬件外设，体验高级语言带来的便利特性，与此同时你还可以利用高级软件库快速实现你的 IoT 构想。\n\n## 硬件支持\n\nW601 IoT Board MicroPython 固件硬件功能如下所示：\n\n| 外设名称 | 引脚号                                 | 简介                                      |\n| -------- | -------------------------------------- | ----------------------------------------- |\n| pin      | PA11, PB4、10-14 、17-18、23-26、30-31 | 开发板引出的可自由分配的 IO，支持引脚中断 |\n| led      | PA13                                   | 红色 led 灯                               |\n| rgb      | R: PA13, G: PA14, B: PA15              | rgb 灯                                    |\n| key      | KEY0: PA7, KEY1: PA6,                  | 输入按键                                  |\n| uart1    | PA4, PA5                               | 串口1                                     |\n| i2c      |                                        | 软件 i2c 可选择任意 pin                   |\n| spi      |                                        | 软件 spi 可选择任意引出 pin               |\n| adc      | PB23 - 26                              | adc，通道 5 - 8                           |\n| pwm      | PB17、PB18                             | pwm1,  通道 1、2                          |\n| timer    |                                        | 硬件定时器 1                              |\n| wdt      |                                        | 看门狗                                    |\n| rtc      |                                        | 实时时钟                                  |\n| beeper   | PB15                                   | 蜂鸣器                                    |\n| lcd      |                                        | lcd 显示屏                                |\n| wifi     |                                        | wifi 网络连接                             |\n| aht10    | CLK: PA0, SDA: PA1                     | 温湿度传感器                              |\n| ap3216c  | CLK: PA2, SDA: PA1                     | 接近与光强传感器                          |\n\n## 入门必读\n\n如果您从来没有了解过 MicroPython, 可以阅读这篇简短的文章来 [带你入门 MicroPython](https://github.com/RT-Thread-packages/micropython/blob/master/docs/introduction.md)。\n\n## 开启 MicroPython 之旅\n\n推荐遵循如下步骤开始进行 MicroPython 开发：\n\n- 在您的开发板上烧录合适的固件\n- 在 PC 机上安装 RT-Thread MicroPython 开发环境并连接上开发板  \n\n接下来就可以尽情挥洒您的创意了，更详细的内容可以点击下文中的链接来进一步了解。\n\n### 下载合适的固件\n\n- [W601 IoT Board firmware](https://www.rt-thread.org/qa/forum.php?mod=viewthread&tid=12305&extra=page%3D1%26filter%3Dtypeid%26typeid%3D20)\n\n### 安装 IDE 开发环境\n\n- [RT-Thread MicroPython develop environment](https://marketplace.visualstudio.com/items?itemName=RT-Thread.rt-thread-micropython)\n\n## 开发资料\n\n### 示例程序\n\n以下示例程序可以在 RT-Thread MicroPython IDE 开发环境中直接添加到工程：\n\n![w601_examples](assets/w601_examples.png)\n\n### MicroPython 模块详解\n\n- [MicroPython Librarys](https://github.com/RT-Thread-packages/micropython/blob/master/docs/micropython-librarys.md)\n\n\n## 联系我们\n\n如果在使用的过程中遇到问题，您可以用如下方式联系我们：\n\n- 在 github 上提交 issue\n- [RT-Thread MicroPython 官方论坛](https://www.rt-thread.org/qa/forum.php?mod=forumdisplay&fid=2&filter=typeid&typeid=20)\n\n- RT-Thread MicroPython 交流 QQ 群：703840633"
  },
  {
    "path": "docs/spec-librarys/machine/ADC.md",
    "content": "## machine.ADC\n\n**machine.ADC** 类是 machine 模块下的一个硬件类，用于指定 ADC 设备的配置和控制，提供对 ADC 设备的操作方法。\n\n- ADC（Analog-to-Digital Converter，模数转换器），用于将连续变化的模拟信号转化为离散的数字信号。\n- ADC 设备两个重要参数：采样值、分辨率；\n  - 采样值：当前时间由模拟信号转化的数值信号的数值；\n  - 分辨率：以二进制（或十进制）数的位数来表示，一般有 8 位、10 位、12 位、16 位等，它说明模数转换器对输入信号的分辨能力，位数越多，表示分辨率越高，采样值会更精确。 \n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `ADC` 对象的构造函数如下：\n\n#### **class machine.ADC**(id, channel)\n\n- **id**：使用的 ADC 设备编号，`id = 1` 表示编号为 1 的 ADC 设备，或者表示使用的 ADC 设备名，如 `id = \"adc\"` 表示设备名为 `adc` 的 ADC 设备；\n- **channel**：使用的 ADC 设备通道号，每个 ADC 设备对应多个通道；\n\n例如：`ADC(1,4)` 表示当前使用编号为 1 的 ADC 设备的 4 通道。\n\n### 方法\n\n#### **ADC.init**(channel)\n\n根据输入的层参数初始化 ADC 对象，入参为使用的 ADC 对象通道号；\n\n#### **ADC.deinit**()\n\n用于关闭 ADC 对象，ADC 对象 deinit 之后需要重新 init 才能使用。\n\n#### **ADC.read**()\n\n用于获取并返回当前 ADC 对象的采样值。例如当前采样值为 2048，对应设备的分辨率为 12位，当前设备参考电压为 3.3V ，则该 ADC 对象通道上实际电压值的计算公式为：**采样值 * 参考电压  /  （1 <<  分辨率位数）**，即 `vol = 2048 / 4096 * 3.3 V = 1.15V`。\n\n### 示例\n\n``` python\n>>> from machine import ADC      # 从 machine 导入 ADC 类\n>>> adc = ADC(1, 13)             # 创建 ADC 对象，当前使用编号为 1 的 ADC 设备的 13 通道\n>>> adc.read()                   # 获取 ADC 对象采样值\n4095\n>>> adc.deinit()                 # 关闭 ADC 对象\n>>> adc.init(13)                 # 开启并重新配置 ADC 对象\n```\n"
  },
  {
    "path": "docs/spec-librarys/machine/I2C.md",
    "content": "## machine.I2C\n\n**machine.I2C** 类是 `machine` 模块下面的一个硬件类，用于对 `I2C` 的配置和控制，提供对 `I2C` 设备的操作方法。\n\n- `I2C` 是一种用于设备间通信的两线协议。在物理层上，它由两根线组成：`SCL`  和 `SDA` ，即时钟和数据线。\n- `I2C` 对象被创建到一个特定的总线上，它们可以在创建时被初始化，也可以之后再来初始化。\n- 打印 `I2C` 对象会打印出配置时的信息。\n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `I2C` 对象的构造函数如下：\n\n#### **class machine.I2C**(id= -1,  scl, sda, freq=400000)\n使用下面的参数构造并返回一个新的 `I2C` 对象：\n\n- **id** ：标识特定的 `I2C`  外设。如果填入 id = -1，即选择软件模拟的方式实现 `I2C`，这时可以使用任意引脚来模拟 `I2C` 总线 ，这样在初始化时就必须指定 `scl` 和 `sda` 。  \n软件 I2C 的初始化方式可参考 [软件 I2C 示例](#i2c_2)。  \n硬件 I2C 的初始化方式可参考 [硬件 I2C 示例](#i2c_3)。\n\n- **scl** : 应该是一个 `Pin` 对象，指定为一个用于 `scl` 的 `Pin` 对象。\n- **sda** : 应该是一个 `Pin` 对象，指定为一个用于 `sda` 的 `Pin` 对象。\n- **freq** ：应该是为 `scl` 设置的最大频率。\n\n### 方法\n\n#### **I2C.init**(scl, sda, freq=400000)\n初始化 `I2C` 总线，参数介绍可以参考构造函数中的参数。\n\n#### **I2C.deinit**()\n关闭 `I2C` 总线。\n\n#### **I2C.scan**()\n扫描所有 0x08 和 0x77 之间的 `I2C` 地址，然后返回一个有响应地址的列表。如果一个设备在总线上收到了他的地址，就会通过拉低 `SDA` 的方式来响应。\n\n### I2C 基础方法\n下面的方法实现了基本的 `I2C` 总线操作，可以组合成任何的 `I2C` 通信操作，如果需要对总线进行更多的控制，可以可以使用他们，否则可以使用后面介绍的标准使用方法。\n\n#### **I2C.start**()\n在总线上产生一个启动信号。（`SCL` 为高时，`SDA` 转换为低）\n\n#### **I2C.stop**()\n在总线上产生一个停止信号。（`SCL` 为高时，`SDA` 转换为高）\n\n#### **I2C.readinto**(buf, nack=True)\n从总线上读取字节并将他们存储到 `buf` 中，读取的字节数时 `buf` 的长度。在收到最后一个字节以外的所有内容后，将在总线上发送 `ACK`。在收到最后一个字节之后，如果 `NACK` 是正确的，那么就会发送一个 `NACK`，否则将会发送 `ACK`。\n\n####  **I2C.write**(buf)\n将 `buf` 中的数据接入到总线，检查每个字节之后是否收到 `ACK`，并在收到 `NACK` 时停止传输剩余的字节。这个函数返回接收到的 `ACK` 的数量。\n\n### I2C 标准总线操作\n下面的方法实现了标准 `I2C` 主设备对一个给定从设备的读写操作。\n\n#### **I2C.readfrom**(addr, nbytes, stop=True)\n从 `addr` 指定的从设备中读取 n 个字节，如果 `stop = True`，那么在传输结束时会产生一个停止信号。函数会返回一个存储着读到数据的字节对象。\n\n#### **I2C.readfrom_into**(addr, buf, stop=True)\n从 `addr` 指定的从设备中读取数据存储到 `buf` 中，读取的字节数将是 `buf` 的长度，如果 `stop = True`，那么在传输结束时会产生一个停止信号。  \n这个方法没有返回值。\n\n#### **I2C.writeto**(addr, buf, stop=True)\n将 `buf` 中的数据写入到 `addr` 指定的的从设备中，如果在写的过程中收到了 `NACK` 信号，那么就不会发送剩余的字节。如果 `stop = True`，那么在传输结束时会产生一个停止信号，即使收到一个 `NACK`。这个函数返回接收到的 `ACK` 的数量。\n\n### 内存操作\n\n一些 `I2C` 设备充当一个内存设备，可以读取和写入。在这种情况下，有两个与 `I2C` 相关的地址，从机地址和内存地址。下面的方法是与这些设备进行通信的便利函数。\n\n#### **I2C.readfrom_mem**(addr, memaddr, nbytes, \\*, addrsize=8)\n从 `addr` 指定的从设备中 `memaddr` 地址开始读取 n 个字节。`addrsize` 参数指定地址的长度。返回一个存储读取数据的字节对象。\n\n#### **I2C.readfrom_mem_into**(addr, memaddr, buf, \\*, addrsize=8)\n从 `addr` 指定的从设备中 `memaddr` 地址读取数据到 `buf` 中，，读取的字节数是 `buf` 的长度。  \n这个方法没有返回值。\n\n#### **I2C.writeto_mem**(addr, memaddr, buf, \\*, addrsize=8)\n将 `buf` 里的数据写入 `addr` 指定的从机的 `memaddr` 地址中。 \n这个方法没有返回值。\n\n### 示例\n\n#### 软件模拟 I2C\n```python\n>>> from machine import Pin, I2C\n>>> clk = Pin((\"clk\", 29), Pin.OUT_OD)   # Select the 29 pin device as the clock\n>>> sda = Pin((\"sda\", 30), Pin.OUT_OD)   # Select the 30 pin device as the data line\n>>> i2c = I2C(-1, clk, sda, freq=100000) # create I2C peripheral at frequency of 100kHz\n>>> i2c.scan()                        # scan for slaves, returning a list of 7-bit addresses\n[81]                                  # Decimal representation\n>>> i2c.writeto(0x51, b'123')         # write 3 bytes to slave with 7-bit address 42\n3\n>>> i2c.readfrom(0x51, 4)             # read 4 bytes from slave with 7-bit address 42\nb'\\xf8\\xc0\\xc0\\xc0'\n>>> i2c.readfrom_mem(0x51, 0x02, 1)   # read 1 bytes from memory of slave 0x51(7-bit),\nb'\\x12'                               # starting at memory-address 8 in the slave\n>>> i2c.writeto_mem(0x51, 2, b'\\x10') # write 1 byte to memory of slave 42,\n                                      # starting at address 2 in the slave\n```\n\n#### 硬件 I2C\n\n需要先开启 `I2C` 设备驱动，查找设备可以在 `msh` 中输入`list_device` 命令。  \n在构造函数的第一个参数传入 `0`，系统就会搜索名为 `i2c0` 的设备，找到之后使用这个设备来构建 `I2C` 对象：\n\n```python\n>>> from machine import Pin, I2C\n>>> i2c = I2C(0)                      # create I2C peripheral at frequency of 100kHz\n>>> i2c.scan()                        # scan for slaves, returning a list of 7-bit addresses\n[81]                                  # Decimal representation\n```\n\n  更多内容可参考 [machine.I2C](http://docs.micropython.org/en/latest/pyboard/library/machine.I2C.html) 。\n\n"
  },
  {
    "path": "docs/spec-librarys/machine/LCD.md",
    "content": "## machine.LCD\n\n**machine.LCD** 类是 machine 模块下面的一个硬件类，用于对 LCD 的配置和控制，提供对 LCD 设备的操作方法。\n\nIoT board 板载一块 1.3 寸，分辨率为 `240*240` 的 LCD 显示屏，因此对该屏幕操作时，(x, y)  坐标的范围是 `0 - 239`。\n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `LCD` 对象的构造函数如下：\n\n#### **class machine.LCD**()\n在给定总线上构造一个 `LCD` 对象，无入参，初始化的对象取决于特定硬件，初始化方式可参考 [示例](#_3)。\n\n### 方法\n\n#### **LCD.light**(value)\n\n控制是否开启 LCD 背光，入参为 True 则打开 LCD 背光，入参为 False 则关闭 LCD 背光。\n\n#### **LCD.fill**(color)\n\n根据给定的颜色填充整个屏幕，支持多种颜色，可以传入的参数有：\n\n```\nWHITE BLACK BLUE BRED GRED GBLUE RED MAGENTA GREEN CYAN YELLOW BROWN BRRED GRAY GRAY175 GRAY151 GRAY187 GRAY240\n```\n\n详细的使用方法可参考[示例](#_3)。\n\n#### **LCD.pixel**(x, y, color)\n\n向指定的位置（x, y）画点，点的颜色为 color 指定的颜色，可指定的颜色和上一个功能相同。\n\n> 注意：(x, y)  坐标不要超过实际范围，使用下面的方法对坐标进行操作时同样需要遵循此限制。\n\n#### **LCD.text**(str, x, y, size)\n\n在指定的位置（x,y）写入字符串，字符串由 str 指定，字体的大小由 size 指定，size 的大小可为 16，24，32。\n\n#### **LCD.line**(x1, y1, x2, y2)\n\n在 LCD 上画一条直线，起始地址为 （x1, y1），终点为（x2, y2）。\n\n#### **LCD.rectangle**(x1, y1, x2, y2)\n\n在 LCD 上画一个矩形，左上角的位置为（x1, y1），右下角的位置为（x2, y2）。\n\n#### **LCD.circle**(x1, y1, r)\n\n在 LCD 上画一个圆形，圆心的位置为（x1, y1），半径长度为 r。\n\n#### **LCD.show_bmp**( x,  y, pathname)\n\n在 LCD 指定位置上显示 32-bit bmp 格式的图片信息，注意显示 bmp 图片时，(x, y) 坐标是图片的左下角。\n\n### 示例\n\n```python\nfrom machine import LCD     # 从 machine 导入 LCD 类\nlcd = LCD()                 # 创建一个 lcd 对象\nlcd.light(False)            # 关闭背光\nlcd.light(True)             # 打开背光\nlcd.fill(lcd.BLACK)         # 将整个 LCD 填充为黑色\nlcd.fill(lcd.RED)           # 将整个 LCD 填充为红色\nlcd.fill(lcd.GRAY)          # 将整个 LCD 填充为灰色\nlcd.fill(lcd.WHITE)         # 将整个 LCD 填充为白色\nlcd.pixel(50, 50, lcd.BLUE) # 将（50,50）位置的像素填充为蓝色\nlcd.text(\"hello RT-Thread\", 0, 0, 16)   # 在（0, 0） 位置以 16 字号打印字符串\nlcd.text(\"hello RT-Thread\", 0, 16, 24)  # 在（0, 16）位置以 24 字号打印字符串\nlcd.text(\"hello RT-Thread\", 0, 48, 32)  # 在（0, 48）位置以 32 字号打印字符串\nlcd.line(0, 50, 239, 50)    # 以起点（0，50），终点（239，50）画一条线\nlcd.line(0, 50, 239, 50)    # 以起点（0，50），终点（239，50）画一条线\nlcd.rectangle(100, 100, 200, 200) # 以左上角为（100,100），右下角（200,200）画矩形\nlcd.circle(150, 150, 80)    # 以圆心位置（150,150），半径为 80 画圆\nlcd.show_bmp(180, 50, \"sun.bmp\")  # 以位置（180,50）为图片左下角坐标显示文件系统中的 bmp 图片 \"sun.bmp\"\n```\n"
  },
  {
    "path": "docs/spec-librarys/machine/PWM.md",
    "content": "## machine.PWM\n\n**machine.PWM** 类是 machine 模块下的一个硬件类，用于指定 PWM 设备的配置和控制，提供对 PWM 设备的操作方法。\n\n- PWM (Pulse Width Modulation，脉冲宽度调制)  是一种对模拟信号电平进行数字编码的方式；\n- PWM 设备可以通过调节有效电平在一个周期信号中的比例时间来操作设备；\n- PWM 设备两个重要的参数：频率（freq）和占空比（duty）；\n  - 频率：从一个上升沿（下降沿）到下一个上升沿（下降沿）的时间周期，单位为 Hz；\n  - 占空比：有效电平（通常为电平）在一个周期内的时间比例；\n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `PWM` 对象的构造函数如下：\n\n#### **class machine.PWM**(id, channel, freq, duty)\n\n在给定的总线上构建一个 `PWM` 对象，参数介绍如下：\n\n- **id**：使用的 PWM 设备编号，如  `id = 1` 表示编号为 1 的 PWM 设备，或者表示使用的 PWM 设备名，如 `id = \"pwm\"` 表示设备名为 `pwm` 的 PWM 设备；\n- **channel**：使用的 PWM 设备通道号，每个 PWM 设备包含多个通道，范围为 [0, 4]；\n- **freq**：初始化频率，范围 [1, 156250]；\n- **duty**：初始化占空比数值，范围 [0 255]；\n\n例如：`PWM(1,4,100,100)` 表示当前使用 编号为 1 的 PWM 设备的 4 通道，初始化频率为 1000 Hz，初始化占空比的数值为 100。\n\n### 方法\n\n#### **PWM.init**(channel, freq, duty)\n\n根据输入的参数初始化 PWM 对象，参数说明同上。\n\n#### **PWM.deinit**()\n\n用于关闭 PWM 对象，对象 deinit 之后需要重新 init 才能使用。\n\n#### **PWM.freq**(freq)\n\n用于获取或者设置 PWM 对象的频率，频率的范围为 [1, 156250]。如果参数为空，返回当前 PWM 对象的频率；如果参数非空，则使用该参数设置当前 PWM 对象的频率。\n\n#### **PWM.duty**(duty)\n\n用于获取或者设置 PWM 对象的占空比数值，占空比数值的范围为 [0, 255]，例如 `duty = 100`，表示当前设备占空比为 `100/255 = 39.22%` 。如果参数为空，返回当前 PWM 对象的占空比数值；如果参数非空，则使用该参数设置当前 PWM 对象的占空比数值。\n\n### 示例\n\n``` python\n>>> from machine import PWM     # 从 machine 导入 PWM 类\n>>> pwm = PWM(3, 3, 1000, 100)  # 创建 PWM 对象，当前使用编号为 3 的 PWM 设备的 3 通道，初始化的频率为 1000Hz，占空比数值为 100（占空比为 100/255 = 39.22%）\n>>> pwm.freq(2000)              # 设置 PWM 对象频率\n>>> pwm.freq()                  # 获取 PWM 对象频率\n2000\n>>> pwm.duty(200)               # 设置 PWM 对象占空比数值\n>>> pwm.duty()                  # 获取 PWM 对象占空比数值\n200\n>>> pwm.deinit()                # 关闭 PWM 对象\n>>> pwm.init(3, 1000, 100)      # 开启并重新配置 PWM 对象\n```"
  },
  {
    "path": "docs/spec-librarys/machine/Pin.md",
    "content": "## machine.Pin\n\n**machine.Pin** 类是 machine 模块下面的一个硬件类，用于对引脚的配置和控制，提供对 `Pin` 设备的操作方法。\n\n`Pin` 对象用于控制输入/输出引脚（也称为 `GPIO`）。`Pin` 对象通常与一个物理引脚相关联，他可以驱动输出电压和读取输入电压。Pin 类中有设置引脚模式（输入/输出）的方法，也有获取和设置数字逻辑（`0` 或 `1`）的方法。\n\n一个 `Pin` 对象是通过一个标识符来构造的，它明确地指定了一个特定的输入输出。标识符的形式和物理引脚的映射是特定于一次移植的。标识符可以是整数，字符串或者是一个带有端口和引脚号码的元组。在 RT-Thread MicroPython 中，引脚标识符是一个由代号和引脚号组成的元组，如 `Pin((\"PB15\", 31), Pin.OUT_PP)` 中的` (\"PB15\", 31)`。\n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `Pin` 对象的构造函数如下：\n\n#### **class machine.Pin**( id, mode = -1, pull = -1，value)\n- **id** ：由用户自定义的引脚名和 `Pin`  设备引脚号组成，如 (\"PB15\", 31)，\"PB15\" 为用户自定义的引脚名，`31` 为 `RT-Thread Pin` 设备驱动在本次移植中的引脚号。\n\n- **mode** ： 指定引脚模式，可以是以下几种：\n    - **Pin.IN** ：输入模式\n    - **Pin.OUT_PP** ：输出模式\n    - **Pin.OUT_OD** ：开漏模式\n\n- **pull** ： 如果指定的引脚连接了上拉下拉电阻，那么可以配置成下面的状态：\n    - **None** ：没有上拉或者下拉电阻。\n    - **Pin.PULL_UP** ：使能上拉电阻。\n    - **Pin.PULL_DOWN** ：使能下拉电阻。\n\n- **value** ： `value` 的值只对输出模式和开漏输出模式有效，用来设置初始输出值。\n\n### 方法\n\n#### **Pin.init**(mode= -1, pull= -1, \\*, value, drive, alt)\n\n根据输入的参数重新初始化引脚。只有那些被指定的参数才会被设置，其余引脚的状态将保持不变，详细的参数可以参考上面的构造函数。\n\n#### **Pin.value**([x])\n如果没有给定参数 `x` ,这个方法可以获得引脚的值。  \n如果给定参数 `x` ，如 `0` 或 `1`，那么设置引脚的值为 逻辑 `0` 或 逻辑 `1`。\n\n#### **Pin.name**()\n返回引脚对象在构造时用户自定义的引脚名。\n\n#### **Pin.irq**(handler=None, trigger=(Pin.IRQ_RISING))\n\n配置在引脚的触发源处于活动状态时调用的中断处理程序。如果引脚模式是， `Pin.IN` 则触发源是引脚上的外部值。 如果引脚模式是， `Pin.OUT` 则触发源是引脚的输出缓冲器。 否则，如果引脚模式是， `Pin.OPEN_DRAIN` 那么触发源是状态'0'的输出缓冲器和状态'1'的外部引脚值。\n\n参数:\n\n- `handler` 是一个可选的函数，在中断触发时调用\n- `trigger` 配置可以触发中断的事件。可能的值是：\n    - `Pin.IRQ_FALLING` 下降沿中断\n    - `Pin.IRQ_RISING` 上升沿中断\n    - `Pin.IRQ_RISING_FALLING` 上升沿或下降沿中断\n    - `Pin.IRQ_LOW_LEVEL` 低电平中断\n    - `Pin.IRQ_HIGH_LEVEL` 高电平中断\n\n### 常量\n\n下面的常量用来配置 `Pin` 对象。 \n\n#### 选择引脚模式：\n##### **Pin.IN**\n##### **Pin.OUT_PP**\n##### **Pin.OUT_OD**\n\n#### 选择上/下拉模式：\n##### **Pin.PULL_UP**\n##### **Pin.PULL_DOWN**\n##### **None**  \n使用值 `None` 代表不进行上下拉。\n\n#### 选择中断触发模式：\n##### **Pin.IRQ_FALLING**\n##### **Pin.IRQ_RISING**\n##### **Pin.IRQ_RISING_FALLING**\n##### **Pin.IRQ_LOW_LEVEL** \n##### **Pin.IRQ_HIGH_LEVEL** \n\n### 示例一\n\n控制引脚输出高低电平信号，并读取按键引脚电平信号。\n\n```\nfrom machine import Pin\n\nPIN_OUT = 31\nPIN_IN  = 58\n\np_out = Pin((\"PB15\", PIN_OUT), Pin.OUT_PP)\np_out.value(1)                 # set io high\np_out.value(0)                 # set io low\n\np_in = Pin((\"key_0\", PIN_IN), Pin.IN, Pin.PULL_UP)\nprint(p_in.value() )           # get value, 0 or 1\n```\n\n### 示例二\n\n上升沿信号触发引脚中断后执行中断处理函数。\n\n```\nfrom machine import Pin\n\nPIN_KEY0 = 58    # PD10\nkey_0 = Pin((\"key_0\", PIN_KEY0), Pin.IN, Pin.PULL_UP)\n\ndef func(v):\n    print(\"Hello rt-thread!\")\n\nkey_0.irq(trigger=Pin.IRQ_RISING, handler=func)\n```\n更多内容可参考 [machine.Pin](http://docs.micropython.org/en/latest/pyboard/library/machine.Pin.html)  。"
  },
  {
    "path": "docs/spec-librarys/machine/RTC.md",
    "content": "## machine.RTC\n\n**machine.RTC** 类是 machine 模块下面的一个硬件类，用于对指定 RTC 设备的配置和控制，提供对 RTC 设备的操作方法。\n\n- RTC（Real-Time Clock ）实时时钟可以提供精确的实时时间，它可以用于产生年、月、日、时、分、秒等信息。\n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `RTC` 对象的构造函数如下：\n\n#### **class machine.RTC**()\n\n所以在给定的总线上构造一个 `RTC` 对象，无入参对象，使用方式可参考 [示例](#_3)。 \n\n### 方法\n\n#### **RTC.init**(datetime)\n\n根据传入的参数初始化 RTC 设备起始时间。入参 `datetime` 为一个时间元组，格式如下：\n\n```\n(year, month, day, wday, hour, minute, second, yday)\n```\n参数介绍如下所示：\n\n- **year**：年份；\n- **month**：月份，范围 [1, 12]；\n- **day**：日期，范围 [1, 31]；\n- **wday**：星期，范围 [0, 6]，0 表示星期一，以此类推；\n- **hour**：小时，范围 [0, 23]；\n- **minute**：分钟，范围[0, 59]；\n- **second**：秒，范围[0, 59]；\n- **yday**：从当前年份 1 月 1 日开始的天数，范围 [0, 365]，一般置位 0 未实现。\n\n使用的方式可参考 [示例](#_3)。\n\n#### **RTC.deinit**()\n\n重置 RTC 设备时间到 2015 年 1 月 1日，重新运行 RTC 设备。\n\n#### **RTC.now**()\n\n获取当前时间，返回值为上述 `datetime` 时间元组格式。\n\n### 示例\n\n```python\n>>> from machine import RTC\n>>> rtc = RTC()                        # 创建 RTC 设备对象\n>>> rtc.init((2019,6,5,2,10,22,30,0))  # 设置初始化时间\n>>> rtc.now()                          # 获取当前时间\n(2019, 6, 5, 2, 10, 22, 40, 0)\n>>> rtc.deinit()                       # 重置时间到2015年1月1日\n>>> rtc.now()                          # 获取当前时间\n(2015, 1, 1, 3, 0, 0, 1, 0)\n```\n"
  },
  {
    "path": "docs/spec-librarys/machine/SPI.md",
    "content": "## machine.SPI\n\n**machine.SPI** 类是 machine 模块下面的一个硬件类，用于对 SPI 的配置和控制，提供对 SPI 设备的操作方法。\n\n- `SPI` 是一个由主机驱动的同步串行协议。在物理层，总线有三根：`SCK`、`MOSI`、`MISO`。多个设备可以共享同一总线，每个设备都由一个单独的信号 `SS` 来选中，也称片选信号。\n- 主机通过片选信号选定一个设备进行通信。`SS` 信号的管理应该由用户代码负责。（通过 [machine.Pin](Pin.md)）\n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `SPI` 对象的构造函数如下：\n\n#### **class machine.SPI**(id, ...)\n在给定总线上构造一个 `SPI` 对象，`id` 取决于特定的移植。\n\n如果想要使用软件 `SPI` , 即使用引脚模拟 `SPI` 总线，那么初始化的第一个参数需要设置为 `-1` ，可参考 [软件 SPI 示例](#spi) 。\n\n使用硬件 `SPI` 在初始化时只需传入 `SPI` 设备的编号即可，如 '50' 表示 `SPI5` 总线上的第 0 个设备。初始化方式可参考 [硬件 SPI 示例](#spi_1)。\n\n如果没有额外的参数，`SPI` 对象会被创建，但是不会被初始化，如果给出额外的参数，那么总线将被初始化，初始化参数可以参考下面的 `SPI.init` 方法。\n\n### 方法\n\n#### **SPI.init**(baudrate=1000000, \\*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=None, mosi=None, miso=None)\n\n用给定的参数初始化`SPI`总线：\n\n- **baudrate** ：`SCK` 时钟频率。\n- **polarity** ：极性可以是 `0` 或 `1`，是时钟空闲时所处的电平。\n- **phase** ：相位可以是 `0` 或 `1`，分别在第一个或者第二个时钟边缘采集数据。\n- **bits** ：每次传输的数据长度，一般是 8 位。\n- **firstbit** ：传输数据从高位开始还是从低位开始，可以是 `SPI.MSB` 或者 `SPI.LSB`。\n- **sck** ：用于 `sck` 的 `machine.Pin` 对象。\n- **mosi** ：用于 `mosi` 的 `machine.Pin` 对象。\n- **miso** ：用于`miso` 的 `machine.Pin` 对象。\n\n#### **SPI.deinit**()\n关闭 `SPI` 总线。\n\n#### **SPI.read**(nbytes, write=0x00)\n读出 n 字节的同时不断的写入 `write` 给定的单字节。返回一个存放着读出数据的字节对象。\n\n#### **SPI.readinto**(buf, write=0x00)\n读出 n 字节到 `buf` 的同时不断地写入 `write` 给定的单字节。  \n这个方法返回读入的字节数。\n\n#### **SPI.write**(buf)\n写入 `buf` 中包含的字节。返回`None`。\n\n#### **SPI.write_readinto**(write_buf, read_buf)\n在读出数据到 `readbuf` 时，从 `writebuf` 中写入数据。缓冲区可以是相同的或不同，但是两个缓冲区必须具有相同的长度。返回 `None`。\n\n### 常量\n\n#### **SPI.MSB**\n设置从高位开始传输数据。\n\n#### **SPI.LSB**\n设置从低位开始传输数据。\n\n### 示例\n\n#### 软件模拟 SPI\n```\n>>> from machine import Pin, SPI\n>>> clk = Pin((\"clk\", 26), Pin.OUT_PP)\n>>> mosi = Pin((\"mosi\", 27), Pin.OUT_PP)\n>>> miso = Pin((\"miso\", 28), Pin.IN)\n>>> spi = SPI(-1, 500000, polarity = 0, phase = 0, bits = 8, firstbit = 0, sck = clk, mosi = mosi, miso = miso)\n>>> print(spi)\nSoftSPI(baudrate=500000, polarity=0, phase=0, sck=clk, mosi=mosi, miso=miso)\n>>> spi.write(\"hello rt-thread!\")\n>>> spi.read(10)\nb'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n```\n\n#### 硬件 SPI\n\n需要先开启 `SPI` 设备驱动，查找设备可以在 `msh` 中输入`list_device` 命令。  \n在构造函数的第一个参数传入 `50`，系统就会搜索名为 `spi50` 的设备，找到之后使用这个设备来构建 `SPI` 对象：\n\n```\n>>> from machine import SPI\n>>> spi = SPI(50)\n>>> print(spi)\nSPI(device port : spi50)\n>>> spi.write(b'\\x9f')\n>>> spi.read(5)\nb'\\xff\\xff\\xff\\xff\\xff'\n>>> buf = bytearray(1)\n>>> spi.write_readinto(b\"\\x9f\",buf)\n>>> buf\nbytearray(b'\\xef')\n>>> spi.init(100000,0,0,8,1)     # Resetting SPI parameter\n```\n\n  更多内容可参考 [machine.SPI](http://docs.micropython.org/en/latest/pyboard/library/machine.SPI.html) 。\n"
  },
  {
    "path": "docs/spec-librarys/machine/Timer.md",
    "content": "## machine.Timer\n\n**machine.Timer** 类是 machine 模块下的一个硬件类，用于 Timer 设备的配置和控制，提供对 Timer 设备的操作方法。\n\n- Timer（硬件定时器），是一种用于处理周期性和定时性事件的设备。\n- Timer 硬件定时器主要通过内部计数器模块对脉冲信号进行计数，实现周期性设备控制的功能。\n- Timer 硬件定时器可以自定义**超时时间**和**超时回调函数**，并且提供两种**定时器模式**：\n  - `ONE_SHOT`：定时器只执行一次设置的回调函数；\n  - `PERIOD`：定时器会周期性执行设置的回调函数；\n- 打印 Timer 对象会打印出配置的信息。\n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `Timer` 对象的构造函数如下：\n\n#### **class machine.Timer**(id)\n\n- **id**：使用的 Timer 设备编号，`id = 1` 表示编号为 1 的 Timer 设备，或者表示使用的 timer 设备名，如 `id = \"timer\"` 表示设备名为 `timer` 的 Timer 设备；\n\n该函数主要用于通过设备编号创建 Timer 设备对象。\n\n### 方法\n\n#### **Timer.init**(mode = Timer.PERIODIC, period = 0, callback = None)\n\n- **mode**：设置 Timer 定时器模式，可以设置两种模式：`ONE_SHOT`（执行一次）、`PERIOD`（周期性执行），默认设置的模式为 `PERIOD` 模式；\n\n- **period**：设置 Timer 定时器定时周期，单位：毫秒（ms）\n\n- **callback**：设置 Timer 定义器超时回调函数，默认设置的函数为 None 空函数，设置的函数格式如下所示：\n\n```python\ndef callback_test(device):         # 回调函数有且只有一个入参，为创建的 Timer 对象\n    print(\"Timer callback test\")\n    print(device)                  # 打印 Timer 对象配置信息\n```\n\n该函数使用方式如下示例所示：\n\n```python\ntimer.init(wdt.PERIOD, 5000, callback_test)   # 设置定时器模式为周期性执行，超时时间为 5 秒, 超时函数为 callback_test\n```\n#### **Timer.deinit**()\n\n该函数用于停止并关闭 Timer 设备。\n\n### 常量\n\n下面的常量用来配置 `Timer` 对象。\n\n#### 选择定时器模式：\n##### **Timer.PERIODIC**\n##### **Timer.ONE_SHOT**\n\n### 示例\n\n```python\n>>> from machine import Timer                       # 从 machine 导入 Timer 类\n>>> timer = Timer(15)                               # 创建 Timer 对象，当前设备编号为 11\n>>>                                                 # 进入粘贴模式\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\n=== def callback_test(device):                      # 定义超时回调函数 \n===     print(\"Timer callback test\")\n>>> timer.init(timer.PERIODIC, 5000, callback_test) # 初始化 Timer 对象，设置定时器模式为循环执行，超时时间为 5 秒，超时回调函数 callback_test\n>>> Timer callback test                             # 5 秒超时循环执行回调函数，打印日志\n>>> Timer callback test\n>>> Timer callback test\n>>> timer.init(timer.ONE_SHOT, 5000, callback_test) # 设置定时器模式为只执行一次，超时时间为 5 秒，超时回调函数为 callback_test\n>>> Timer callback test                             # 5 秒超时后执行一次回调函数，打印日志\n>>> timer.deinit()                                  # 停止并关闭 Timer 定时器\n```\n\n更多内容可参考 [machine.Timer](http://docs.micropython.org/en/latest/library/machine.Timer.html)。\n"
  },
  {
    "path": "docs/spec-librarys/machine/UART.md",
    "content": "## machine.UART\n\n**machine.UART** 类是 machine 模块下面的一个硬件类，用于对 UART 的配置和控制，提供对 UART 设备的操作方法。\n\n`UART` 实现了标准的 `uart/usart` 双工串行通信协议，在物理层上，他由两根数据线组成：`RX` 和 `TX`。通信单元是一个字符，它可以是 8 或 9 位宽。\n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `UART` 对象的构造函数如下：\n\n#### **class machine.UART**(id, ...)\n在给定总线上构造一个 `UART` 对象，`id` 取决于特定的移植。  \n初始化参数可以参考下面的 `UART.init` 方法。 \n\n使用硬件 UART 在初始化时只需传入 `UART` 设备的编号即可，如传入 `1` 表示 `uart1` 设备。   \n初始化方式可参考 [示例](#_3)。\n\n### 方法\n\n#### **UART.init**(baudrate = 9600, bits=8, parity=None, stop=1)\n- **baudrate** ：`SCK` 时钟频率。\n- **bits** ：每次发送数据的长度。\n- **parity** ：校验方式。\n- **stop** ：停止位的长度。\n\n#### **UART.deinit**()\n关闭串口总线。\n\n#### **UART.read**([nbytes])\n读取字符，如果指定读 n 个字节，那么最多读取 n 个字节，否则就会读取尽可能多的数据。\n返回值：一个包含读入数据的字节对象。如果如果超时则返回 `None`。\n\n#### **UART.readinto**(buf[, nbytes])\n读取字符到 `buf` 中，如果指定读 n 个字节，那么最多读取 n 个字节，否则就读取尽可能多的数据。另外读取数据的长度不超过 `buf` 的长度。\n返回值：读取和存储到 `buf` 中的字节数。如果超时则返回 `None`。\n\n#### **UART.readline**()\n读一行数据，以换行符结尾。\n返回值：读入的行数，如果超时则返回 `None`。\n\n#### **UART.write**(buf)\n将 `buf` 中的数据写入总线。\n返回值：写入的字节数，如果超时则返回 `None`。\n\n### 示例\n\n在构造函数的第一个参数传入`1`，系统就会搜索名为 `uart1` 的设备，找到之后使用这个设备来构建 `UART` 对象：\n\n```python\nfrom machine import UART\nuart = UART(1, 115200)                         # init with given baudrate\nuart.init(115200, bits=8, parity=None, stop=1) # init with given parameters\nuart.read(10)       # read 10 characters, returns a bytes object\nuart.read()         # read all available characters\nuart.readline()     # read a line\nuart.readinto(buf)  # read and store into the given buffer\nuart.write('abc')   # write the 3 characters\n```\n\n  更多内容可参考 [machine.UART](http://docs.micropython.org/en/latest/pyboard/library/machine.UART.html) 。"
  },
  {
    "path": "docs/spec-librarys/machine/WDT.md",
    "content": "## machine.WDT\n\n**machine.WDT** 类是 machine 模块下的一个硬件类，用于 WDT 设备的配置和控制，提供对 WDT 设备的操作方法。\n\n如下为 WDT 设备基本介绍：\n\n- WDT（WatchDog Timer，硬件看门狗），是一个定时器设备，用于系统程序结束或出错导致系统进入不可恢复状态时重启系统。\n\n- WDT 启动之后，计数器开始计数，在计数器溢出前没有被复位，会对 CPU 产生一个复位信号使设备重启（简称 “被狗咬”）；\n\n- 系统正常运行时，需要在 WDT 设备允许的时间间隔内对看门狗计数清零（简称“喂狗”），WDT 设备一旦启动，需要定时“喂狗”以确保设备正常运行。\n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `WDT` 对象的构造函数如下：\n\n#### **class machine.WDT**(id = \"wdt\", timeout=5)\n\n- **id**: 使用的 WDT 设备编号，`id = 1` 表示编号为 1 的 WDT 设备，或者表示使用的 WDT 设备名，如 `id = \"wdt\"` 表示设备名为 `wdt` 的 WDT 设备；\n\n- **timeout**：设置看门狗超时时间，单位：秒（s）；\n\n用于创建一个 WDT 对象并且启动 WDT 功能。一旦启动，设置的超时时间无法改动，WDT 功能无法停止。\n\n如果该函数入参为空，则设置超时时间为 5 秒；如果入参非空，则使用该入参设置 WDT 超时时间，超时时间最小设置为 1 秒。\n\n### 方法\n\n#### **WDT.feed**()\n\n用于执行“喂狗”操作，清空看门狗设备计数。应用程序应该合理的周期性调用该函数，以防止系统重启。\n\n### 示例\n\n``` python\n>>> from machine import WDT     # 从 machine 导入 WDT 类\n>>> wdt = WDT()                 # 创建 WDT 对象，默认超时时间为 5 秒\n>>> wdt = WDT(10)               # 创建 WDT 对象，设置超时时间为 10 秒\n>>> wdt.feed()                  # 在 10 秒超时时间内需要执行“喂狗”操作，清空看门狗设备计数，否则系统将重启\n```\n\n更多内容可参考 [machine.WDT](http://docs.micropython.org/en/latest/library/machine.WDT.html) 。\n"
  },
  {
    "path": "docs/spec-librarys/machine.md",
    "content": "## **machine** – 与硬件相关的功能\n\n**machine** 模块包含与特定开发板上的硬件相关的特定函数。 在这个模块中的大多数功能允许实现直接和不受限制地访问和控制系统上的硬件块（如CPU，定时器，总线等）。如果使用不当，会导致故障，死机，崩溃，在极端的情况下，硬件会损坏。\n\n需要注意的是，由于不同开发板的硬件资源不同，MicroPython 移植所能控制的硬件也是不一样的。因此对于控制硬件的例程来说，在使用前需要修改相关的配置参数来适配不同的开发板，或者直接运行已经对某一开发板适配好的 MicroPython 示例程序。本文档中的例程都是基于 RT-Thread IoT Board 潘多拉开发板而讲解的。\n\n### 函数\n\n#### 复位相关函数\n\n##### **machine.info**()  \n  显示关于系统介绍和内存占用等信息。\n\n##### **machine.reset**()  注：暂未实现\n  重启设备，类似于按下复位按钮。\n\n##### **machine.reset_cause**()  注：暂未实现\n  获得复位的原因，查看可能的返回值的常量。\n\n#### 中断相关函数\n\n##### **machine.disable_irq**()  \n  禁用中断请求。返回先前的 `IRQ` 状态，该状态应该被认为是一个未知的值。这个返回值应该在 `disable_irq` 函数被调用之前被传给 `enable_irq` 函数来重置中断到初始状态。\n\n##### **machine.enable_irq**(state)  \n  重新使能中断请求。状态参数应该是从最近一次禁用功能的调用中返回的值。\n\n#### 功耗相关函数\n\n##### **machine.freq**()  \n  返回 `CPU` 的运行频率。\n\n##### **machine.idle**()  注：暂未实现\n  阻断给 `CPU` 的时钟信号，在较短或者较长的周期里减少功耗。当中断发生时，外设将继续工作。\n\n##### **machine.sleep**()  注：暂未实现\n  停止 `CPU` 并禁止除了 `WLAN` 之外的所有外设。系统会从睡眠请求的地方重新恢复工作。为了确保唤醒一定会发生，应当首先配置中断源。\n\n##### **machine.deepsleep**()  注：暂未实现\n  停止 `CPU` 和所有外设（包括网络接口）。执行从主函数中恢复，就像被复位一样。复位的原因可以检查 `machine.DEEPSLEEP` 参数获得。为了确保唤醒一定会发生，应该首先配置中断源，比如一个引脚的变换或者 `RTC` 的超时。\n"
  },
  {
    "path": "docs/spec-librarys/micropython.md",
    "content": "\n# micropython – 内部功能访问与控制模块\n\n## Functions\n\n### micropython.const(expr)\nUsed to declare that the expression is a constant so that the compile can optimise it. The use of this function should be as follows:\n\n\n```python\nfrom micropython import const\nCONST_X = const(123)\nCONST_Y = const(2 * CONST_X + 1)\n```\n\nConstants 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.\n\nThis const function is recognised directly by the MicroPython parser and is provided as part of the micropython module mainly so that scripts can be written which run under both CPython and MicroPython, by following the above pattern.\n\n### micropython.opt_level([level])\n\nIf 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.\n\n- The optimisation level controls the following compilation features:\n- Assertions: at level 0 assertion statements are enabled and compiled into the bytecode; at levels 1 and higher assertions are not compiled.\n- Built-in __debug__ variable: at level 0 this variable expands to True; at levels 1 and higher it expands to False.\n  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.\n- The default optimisation level is usually level 0.\n\n### micropython.alloc_emergency_exception_buf(size)\nAllocate size bytes of RAM for the emergency exception buffer (a good size is around 100 bytes). The buffer is used to create exceptions in cases when normal RAM allocation would fail (eg within an interrupt handler) and therefore give useful traceback information in these situations.\n\nA good way to use this function is to put it at the start of your main script (eg boot.py or main.py) and then the emergency exception buffer will be active for all the code following it.\n\n### micropython.mem_info([verbose])\n\nPrint information about currently used memory. If the verbose argument is given then extra information is printed.\n\nThe information that is printed is implementation dependent, but currently includes the amount of stack and heap used. In verbose mode it prints out the entire heap indicating which blocks are used and which are free.\n\n### micropython.qstr_info([verbose])\nPrint information about currently interned strings. If the verbose argument is given then extra information is printed.\n\nThe information that is printed is implementation dependent, but currently 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.\n\n### micropython.stack_use()\n  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.\n\n### micropython.heap_lock()\n### micropython.heap_unlock()\n  Lock or unlock the heap. When locked no memory allocation can occur and a MemoryError will be raised if any heap allocation is attempted.\n\nThese functions can be nested, ie heap_lock() can be called multiple times in a row and the lock-depth will increase, and then heap_unlock() must be called the same number of times to make the heap available again.\n\nIf the REPL becomes active with the heap locked then it will be forcefully unlocked.\n\n### micropython.kbd_intr(chr)\nSet 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.\n\nThis 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.\n\n### micropython.schedule(func, arg)\n  Schedule the function func to be executed “very soon”. The function is passed the value arg as its single argument. “Very soon” means that the MicroPython runtime will do its best to execute the function at the earliest possible time, given that it is also trying to be efficient, and that the following conditions hold:\n\n- A scheduled function will never preempt another scheduled function.\n- Scheduled functions are always executed “between opcodes” which means that all fundamental Python operations (such as appending to a list) are guaranteed to be atomic.\n- A given port may define “critical regions” within which scheduled functions will never be executed. Functions may be scheduled within a critical region but they will not be executed until that region is exited. An example of a critical region is a preempting interrupt handler (an IRQ).\n  A use for this function is to schedule a callback from a preempting IRQ. Such an IRQ puts restrictions on the code that runs in the IRQ (for example the heap may be locked) and scheduling a function to call later will lift those restrictions.\n\nNote: If schedule() is called from a preempting IRQ, when memory allocation is not allowed and the callback to be passed to schedule() is a bound method, passing this directly will fail. This is because creating a reference to a bound method causes memory allocation. A solution is to create a reference to the method in the class constructor and to pass that reference to schedule(). This is discussed in detail here reference documentation under “Creation of Python objects”.\n\nThere is a finite queue to hold the scheduled functions and schedule() will raise a RuntimeError if the queue is full."
  },
  {
    "path": "docs/spec-librarys/network/wlan.md",
    "content": "## class WLAN – 控制内置的 WiFi 网络接口\n\n该类为 WiFi 网络处理器提供一个驱动程序。使用示例:\n\n```python\nimport network\n# enable station interface and connect to WiFi access point\nnic = network.WLAN(network.STA_IF)\nnic.active(True)\nnic.connect('your-ssid', 'your-password')\n# now use sockets as usual\n```\n\n### 构造函数\n\n在 RT-Thread MicroPython 中 `WLAN` 对象的构造函数如下：\n\n#### class network.WLAN(interface_id)\n\n创建一个 WLAN 网络接口对象。支持的接口是 ` network.STA_IF`（STA 模式，可以连接到上游的 WiFi 热点上） 和 `network.AP_IF`（AP 模式，允许其他 WiFi 客户端连接到自身的热点)。下面方法的可用性取决于接口的类型。例如，只有STA 接口可以使用 `WLAN.connect()`  方法连接到 AP 热点上。\n\n### 方法\n\n#### **WLAN.active**([is_active])\n\n如果向该方法传入布尔数值，传入 True 则使能卡，传入 False 则禁止网卡。否则，如果不传入参数，则查询当前网卡的状态。\n\n#### **WLAN.connect**(ssid, password)\n使用指定的账号和密码链接指定的无线热点。\n\n#### **WLAN.disconnect**()\n从当前链接的无线网络中断开。\n\n#### **WLAN.scan**()\n\n扫描当前可以连接的无线网络。\n\n只能在 STA 模式下进行扫描，使用元组列表的形式返回 WiFi 接入点的相关信息。\n\n（ssid, bssid, channel, rssi, authmode, hidden）\n\n#### **WLAN.status**([param])\n\n返回当前无线连接的状态。\n\n当调用该方法时没有附带参数，就会返回值描述当前网络连接的状态。如果还没有从热点连接中获得 IP 地址，此时的状态为 `STATION_IDLE`。如果已经从连接的无线网络中获得 IP 地址，此时的状态为 `STAT_GOT_IP`。\n\n当调用该函数使用的参数为 `rssi` 时，则返回 `rssi` 的值，该函数目前只支持这一个参数。\n\n#### **WLAN.isconnected**()\n\n在 STA 模式时，如果已经连接到 WiFi 网络，并且获得了 IP 地址，则返回 True。如果处在 AP 模式，此时已经与客户端建立连接，则返回 True。其他情况下都返回 False。\n\n#### WLAN.ifconfig([(ip, subnet, gateway, dns)])\n\n获取或者设置网络接口的参数，IP 地址，子网掩码，网关，DNS 服务器。当调用该方法不附带参数时，该方法会返回一个包含四个元素的元组来描述上面的信息。想要设置上面的值，传入一个包含上述四个元素的元组，例如：\n\n```python\nnic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))\n```\n\n#### **WLAN.config**('param')\n\n#### WLAN.config(param=value, ...)\n\n获取或者设置一般网络接口参数，这些方法允许处理标准的 ip 配置之外的其他参数，如 `WLAN. ifconfig()` 函数处理的参数。这些参数包括特定网络和特定硬件的参数。对于参数的设置，应该使用关键字的语法，可以一次性设置多个参数。\n\n当查询参数时，参数名称的引用应该为字符串，且每次只能查询一个参数。\n\n```python\n# Set WiFi access point name (formally known as ESSID) and WiFi password\nap.config(essid='My_AP', password=\"88888888\")\n# Query params one by one\nprint(ap.config('essid'))\nprint(ap.config('channel'))\n```\n下面是目前支持的参数：\n\n| Parameter | Description                       |\n| --------- | --------------------------------- |\n| mac       | MAC address (bytes)               |\n| essid     | WiFi access point name (string)   |\n| channel   | WiFi channel (integer)            |\n| hidden    | Whether ESSID is hidden (boolean) |\n| password  | Access password (string)          |\n\n\n### 示例\n\nSTA 模式下：\n\n```python\nimport network\nwlan = network.WLAN(network.STA_IF)\nwlan.scan()\nwlan.connect(\"rtthread\",\"02188888888\")\nwlan.isconnected()\n```\n\nAP 模式下：\n\n```python\nimport network\nap = network.WLAN(network.AP_IF)\nap.config(essid=\"hello_rt-thread\", password=\"88888888\")\nap.active(True)\nap.config(\"essid\")\n```\n\n"
  },
  {
    "path": "docs/spec-librarys/network.md",
    "content": "## network – 网络配置\n\n此模块提供网络驱动程序和路由配置。特定硬件的网络驱动程序在此模块中可用，用于配置硬件网络接口。然后，配置接口提供的网络服务可以通过 `usocket` 模块使用。\n\n### 专用的网络类配置\n\n下面具体的类实现了抽象网卡的接口，并提供了一种控制各种网络接口的方法。\n\n- [class WLAN – control built-in WiFi interfaces](network/wlan.md)\n\n"
  },
  {
    "path": "docs/spec-librarys/rtthread.md",
    "content": "## **rtthread** – 系统相关函数\n\n**rtthread** 模块提供了与 RT-Thread 操作系统相关的功能，如查看栈使用情况等。\n\n### 函数\n\n#### rtthread.current_tid()  \n返回当前线程的 id 。\n\n#### rtthread.is_preempt_thread()  \n返回是否是可抢占线程。\n\n### 示例\n\n```\n>>> import rtthread\n>>> \n>>> rtthread.is_preempt_thread()       # determine if it's a preemptible thread\nTrue\n>>> rtthread.current_tid()             # current thread id\n268464956\n>>> \n```\n"
  },
  {
    "path": "docs/std-librarys/_thread.md",
    "content": "## _thread – 多线程支持\n\n`_thread` 模块提供了用于处理多线程的基本方法——多个控制线程共享它们的全局数据空间。为了实现同步，提供了简单的锁（也称为互斥锁或二进制信号量）。\n\n### 示例\n\n```python\nimport _thread\nimport time\ndef testThread():\n    while True:\n        print(\"Hello from thread\")\n        time.sleep(2)\n\n_thread.start_new_thread(testThread, ())\nwhile True:\n    pass\n```\n\n输出结果（启动新的线程，每隔两秒打印字符）：\n\nHello from thread\nHello from thread\nHello from thread\nHello from thread\nHello from thread\n\n更多内容可参考 [_thread](http://docs.micropython.org/en/latest/pyboard/library/_thread.html)  。\n"
  },
  {
    "path": "docs/std-librarys/builtins.md",
    "content": "# Builtin functions and exceptions\n\n所有的内饰函数和异常类型都在下面描述。\n\n## 函数和类型\n\n- abs()\n- all()\n- any()\n- bin()\n- **class** bool\n- **class** bytearray\n- **class** bytes\n- callable()\n- chr()\n- classmethod()\n- compile()\n- **class** complex\n- delattr(obj, name)\n\n- **class** dict\n- dir()\n\n- divmod()\n- enumerate()\n- eval()\n- exec()\n- filter()\n- **class** float\n- **class** frozenset\n- getattr()\n- globals()\n- hasattr()\n- hash()\n- hex()\n- id()\n- input()\n- **class** int\n  - classmethod from_bytes(bytes, byteorder)\n    In MicroPython, byteorder parameter must be positional (this is compatible with CPython).\n  - to_bytes(size, byteorder)\n    In MicroPython, byteorder parameter must be positional (this is compatible with CPython).\n\n- isinstance()\n- issubclass()\n- iter()\n- len()\n- class list\n- locals()\n- map()\n- max()\n- **class** memoryview\n- min()\n- next()\n- **class** object\n- oct()\n- open()\n- ord()\n- pow()\n- print()\n- property()\n- range()\n- repr()\n- reversed()\n- round()\n- class set\n- setattr()\n- **class** slice\n  - The slice builtin is the type that slice objects have.\n- sorted()\n- staticmethod()\n- **class** str\n- sum()\n- super()\n- **class** tuple\n- type()\n- zip()\n\n## 异常类型\n- **exception** AssertionError\n- **exception** AttributeError\n- **exception** Exception\n- **exception** ImportError\n- **exception** IndexError\n- **exception** KeyboardInterrupt\n- **exception** KeyError\n- **exception** MemoryError\n- **exception** NameError\n- **exception** NotImplementedError\n- **exception** OSError\n  - See CPython documentation: OSError. MicroPython doesn’t implement errno attribute, instead use the standard way to access exception arguments: exc.args[0].\n\n- **exception** RuntimeError\n- **exception** StopIteration\n- **exception** SyntaxError\n- **exception** SystemExit\n  - See CPython documentation: SystemExit.\n\n- **exception** TypeError\n  - See CPython documentation: TypeError.\n\n- **exception** ValueError\n- **exception** ZeroDivisionError\n\n"
  },
  {
    "path": "docs/std-librarys/cmath.md",
    "content": "## **cmath** – 复数运算函数功能\n\n`cmath` 模块提供了一些用于复数运算的函数。这个模块中的函数接受整数、浮点数或复数作为参数。他们还将接受任何有复数或浮点方法的 Python 对象：这些方法分别用于将对象转换成复数或浮点数，然后将该函数应用到转换的结果中。\n\n### 函数\n\n#### **cmath.cos**(z)  \n返回``z``的余弦。\n\n#### **cmath.exp**(z)  \n返回``z``的指数。\n\n#### **cmath.log**(z)  \n返回``z``的对数。\n\n#### **cmath.log10**(z)  \n返回``z``的常用对数。\n\n#### **cmath.phase**(z)  \n返回``z``的相位, 范围是(-pi, +pi]，以弧度表示。\n\n#### **cmath.polar**(z)  \n返回``z``的极坐标。\n\n#### **cmath.rect**(r, phi)  \n返回`模量r`和相位``phi``的复数。\n\n#### **cmath.sin**(z)  \n返回``z``的正弦。\n\n#### **cmath.sqrt**(z)  \n返回``z``的平方根。\n\n### 常数\n\n#### **cmath.e**  \n自然对数的指数。\n\n#### **cmath.pi**  \n圆周率。\n\n更多内容可参考 [cmath](http://docs.micropython.org/en/latest/pyboard/library/cmath.html)  。\n"
  },
  {
    "path": "docs/std-librarys/gc.md",
    "content": "## **gc** – 控制垃圾回收\n\n**gc** 模块提供了垃圾收集器的控制接口。\n\n### 函数\n\n#### **gc.enable**()  \n允许自动回收内存碎片。 \n\n#### **gc.disable**()  \n禁止自动回收，但可以通过collect()函数进行手动回收内存碎片。 \n\n#### **gc.collect**()  \n运行一次垃圾回收。\n\n#### **gc.mem_alloc**()  \n返回已分配的内存数量。 \n\n#### **gc.mem_free**()  \n返回剩余的内存数量。 \n\n更多内容可参考  [gc](http://docs.micropython.org/en/latest/pyboard/library/gc.html) 。\n"
  },
  {
    "path": "docs/std-librarys/math.md",
    "content": "## **math** – 数学函数\n\n**math** 模块提供了对 C 标准定义的数学函数的访问。\n\n> 注意：本模块需要带有硬件 FPU，精度是32位，这个模块需要浮点功能支持。\n\n### 常数\n\n#### **math.e**  \n自然对数的底数。\n\n示例：\n```\n>>>import math\n>>>print(math.e)\n2.718282\n```\n#### **math.pi**  \n圆周长与直径的比值。\n\n示例：\n\n```\n>>> print(math.pi)\n3.141593\n```\n\n### 函数\n\n#### **math.acos(x)**\n传入弧度值，计算cos(x)的反三角函数。 \n\n#### **math.acosh(x)** \n  返回 ``x`` 的逆双曲余弦。\n\n#### **math.asin(x)**\n传入弧度值，计算sin(x)的反三角函数。 \n示例：\n\n```\n>>> x = math.asin(0.5)\n>>> print(x)\n0.5235988\n```\n\n#### **math.asinh(x)**\n  返回``x`` 的逆双曲正弦。\n\n#### **math.atan(x)**\n  返回 ``x`` 的逆切线。\n\n#### **math.atan2(y, x)**\n  Return the principal value of the inverse tangent of y/x.\n\n#### **math.atanh(x)**\n  Return the inverse hyperbolic tangent of x.\n\n#### **math.ceil(x)**\n向上取整。 \n示例：\n\n```\n>>> x = math.ceil(5.6454)\n>>> print(x)\n6\n```\n\n#### **math.copysign(x, y)** \n  Return x with the sign of y.\n\n#### **math.cos(x)**  \n传入弧度值，计算余弦。 \n示例：计算cos60°\n\n```\n>>> math.cos(math.radians(60))\n0.5\n```\n\n#### **math.cosh(x)**  \n  Return the hyperbolic cosine of x.\n\n#### **math.degrees(x)**  \n弧度转化为角度。 \n示例：\n\n```\n>>> x = math.degrees(1.047198)\n>>> print(x)\n60.00002\n```\n\n#### **math.erf(x)**  \n  Return the error function of x.\n\n#### **math.erfc(x)**  \n  Return the complementary error function of x.\n\n#### **math.exp(x)**  \n计算e的x次方（幂）。 \n示例：\n\n```\n>>> x = math.exp(2)\n>>> print(x)\n7.389056\n```\n\n#### **math.expm1(x)**  \n计算 math.exp(x) - 1。 \n\n#### **math.fabs(x)**  \n计算绝对值。 \n示例：\n\n```\n>>> x = math.fabs(-5)\n>>> print(x)\n5.0\n>>> y = math.fabs(5.0)\n>>> print(y)\n5.0\n```\n\n#### **math.floor(x)**  \n向下取整。 \n示例：\n\n```\n>>> x = math.floor(2.99)\n>>> print(x)\n2\n>>> y = math.floor(-2.34)\n>>> print(y)\n-3\n```\n\n#### **math.fmod(x, y)**  \n取x除以y的模。 \n示例：\n\n```\n>>> x = math.fmod(4, 5)\n>>> print(x)\n4.0\n```\n\n#### **math.frexp(x)**  \n  Decomposes a floating-point number into its mantissa and exponent. The returned value is the tuple (m, e) such that x == m * 2**e exactly. If x == 0 then the function returns (0.0, 0), otherwise the relation 0.5 <= abs(m) < 1 holds.\n\n#### **math.gamma(x)**  \n返回伽马函数。 \n示例：\n\n```\n>>> x = math.gamma(5.21)\n>>> print(x)\n33.08715\n```\n\n#### **math.isfinite(x)**  \n  Return True if x is finite.\n\n#### **math.isinf(x)**  \n  Return True if x is infinite.\n\n#### **math.isnan(x)**  \n  Return True if x is not-a-number\n\n#### **math.ldexp(x, exp)**  \n  Return x * (2**exp).\n\n#### **math.lgamma(x)**  \n返回伽马函数的自然对数。 \n示例：\n\n```\n>>> x = math.lgamma(5.21)\n>>> print(x)\n3.499145\n```\n\n#### **math.log(x)**  \n计算以e为底的x的对数。 \n示例：\n\n```\n>>> x = math.log(10)\n>>> print(x)\n2.302585\n```\n\n#### **math.log10(x)**  \n计算以10为底的x的对数。 \n示例：\n\n```\n>>> x = math.log10(10)\n>>> print(x)\n1.0\n```\n\n#### **math.log2(x)**  \n 计算以2为底的x的对数。 \n示例：\n\n```\n>>> x = math.log2(8)\n>>> print(x)\n3.0\n```\n\n#### **math.modf(x)**  \n  Return a tuple of two floats, being the fractional and integral parts of x. Both return values have the same sign as x.\n\n#### **math.pow(x, y)**  \n计算 x 的 y 次方（幂）。 \n示例：\n\n```\n>>> x = math.pow(2, 3)\n>>> print(x)\n8.0\n```\n\n#### **math.radians(x)**  \n角度转化为弧度。 \n示例：\n\n```\n>>> x = math.radians(60)\n>>> print(x)\n1.047198\n```\n\n#### **math.sin(x)**  \n传入弧度值，计算正弦。 \n示例：计算sin90°\n\n```\n>>> math.sin(math.radians(90))\n1.0\n```\n\n#### **math.sinh(x)**  \n  Return the hyperbolic sine of x.\n\n#### **math.sqrt(x)**  \n计算平方根。 \n示例：\n\n```\n>>> x = math.sqrt(9)\n>>> print(x)\n3.0\n```\n\n#### **math.tan(x)**  \n传入弧度值，计算正切。 \n示例：计算tan60°\n\n```\n>>> math.tan(math.radians(60))\n1.732051\n```\n\n#### **math.tanh(x)**  \n  Return the hyperbolic tangent of x.\n\n#### **math.trunc(x)**  \n取整。 \n示例：\n\n```\n>>> x = math.trunc(5.12)\n>>> print(x)\n5\n>>> y = math.trunc(-6.8)\n>>> print(y)\n-6\n```\n\n更多内容可参考  [math](http://docs.micropython.org/en/latest/pyboard/library/math.html) 。\n"
  },
  {
    "path": "docs/std-librarys/rtthread.md",
    "content": "## **rtthread** – 系统相关函数\n\n**rtthread** 模块提供了与 RT-Thread 操作系统相关的功能，如查看栈使用情况等。\n\n### 函数\n\n#### rtthread.current_tid()  \n返回当前线程的 id 。\n\n#### rtthread.is_preempt_thread()  \n返回是否是可抢占线程。\n\n#### rtthread.stacks_analyze()  \n返回当前系统线程和栈使用信息。\n\n### 示例\n\n```\n>>> import rtthread\n>>> \n>>> rtthread.is_preempt_thread()       # determine if code is running in a preemptible thread\nTrue\n>>> rtthread.current_tid()             # current thread id\n268464956\n>>> rtthread.stacks_analyze()          # show thread information\nthread     pri  status      sp     stack size max used left tick  error\n---------- ---  ------- ---------- ----------  ------  ---------- ---\nelog_async  31  suspend 0x000000a8 0x00000400    26%   0x00000003 000\ntshell      20  ready   0x00000260 0x00001000    39%   0x00000003 000\ntidle       31  ready   0x00000070 0x00000100    51%   0x0000000f 000\nSysMonitor  30  suspend 0x000000a4 0x00000200    32%   0x00000005 000\ntimer        4  suspend 0x00000080 0x00000200    25%   0x00000009 000\n>>> \n```\n"
  },
  {
    "path": "docs/std-librarys/sys.md",
    "content": "## **sys** – 系统特有功能函数\n\n**sys** 模块提供系统特有的功能。\n\n### 函数\n\n#### **sys.exit**(retval=0)  \n  终止当前程序给定的退出代码。 函数会抛出 `SystemExit` 异常。\n#### **sys.print_exception**(exc, file=sys.stdout)  \n  打印异常与追踪到一个类似文件的对象 file (或者缺省 `sys.stdout` ).\n\n> 提示：这是 CPython 中回溯模块的简化版本。不同于 `traceback.print_exception()`，这个函数用异常值代替了异常类型、异常参数和回溯对象。文件参数在对应位置，不支持更多参数。CPython 兼容回溯模块在 `micropython-lib`。  \n\n### 常数\n\n#### **sys.argv**  \n  当前程序启动时参数的可变列表。\n\n#### **sys.byteorder**  \n  系统字节顺序 (“little” or “big”).\n\n#### **sys.implementation**  \n  关于当前 Python 实现的信息，对于 MicroPython 来说，有以下属性：  \n  - 名称 -  ‘’micropython“  \n  - 版本 - 元组（主要，次要，小），比如（1，9，3） \n\n#### **sys.modules**  \n  已加载模块的字典。在一部分移植中，它可能不包含内置模块。\n\n#### **sys.path**  \n  用来搜索导入模块地址的列表。\n\n#### **sys.platform**  \n  返回当前平台的信息。\n\n#### **sys.stderr**  \n  标准错误流。\n\n#### **sys.stdin**  \n  标准输入流。\n\n#### **sys.stdout**  \n  标准输出流。\n\n#### **sys.version**  \n  符合的 Python 语言版本，如字符串。\n\n#### **sys.version_info**  \n  本次实现使用的 Python 语言版本，用一个元组的方式表示。\n\n### 示例 \n\n```\n>>> import sys\n>>> sys.version\n'3.4.0'\n>>> sys.version_info\n(3, 4, 0)\n>>> sys.path\n['', '/libs/mpy/']\n>>> sys.__name__\n'sys'\n>>> sys.platform\n'rt-thread'\n>>> sys.byteorder\n'little'\n```\n\n更多内容可参考 [sys](http://docs.micropython.org/en/latest/pyboard/library/sys.html) 。\n"
  },
  {
    "path": "docs/std-librarys/uarray.md",
    "content": "## **array** – 数字数据数组\n\n**array**  模块定义了一个对象类型，它可以简洁地表示基本值的数组：字符、整数、浮点数。支持代码格式: b, B, h, H, i, I, l, L, q, Q, f, d (最后2个需要支持浮点数)。\n\n### 构造函数\n\n#### **class array.array**(typecode[, iterable])  \n用给定类型的元素创建数组。数组的初始内容由 iterable 提供，如果没有提供，则创建一个空数组。\n\n```\ntypecode：数组的类型\niterable：数组初始内容\n```\n\n示例：\n\n```python\n>>> import array\n>>> a = array.array('i', [2, 4, 1, 5])\n>>> b = array.array('f')\n>>> print(a)\narray('i', [2, 4, 1, 5])\n>>> print(b)\narray('f')\n```\n\n### 方法\n\n#### **array.append**(val)  \n将一个新元素追加到数组的末尾。 \n\n示例：\n\n```python\n>>> a = array.array('f', [3, 6])\n>>> print(a)\narray('f', [3.0, 6.0])\n>>> a.append(7.0)\n>>> print(a)\narray('f', [3.0, 6.0, 7.0])\n```\n\n#### **array.extend**(iterable)  \n将一个新的数组追加到数组的末尾，注意追加的数组和原来数组的数据类型要保持一致。 \n\n示例：\n\n```python\n>>> a = array.array('i', [1, 2, 3])\n>>> b = array.array('i', [4, 5])\n>>> a.extend(b)\n>>> print(a)\narray('i', [1, 2, 3, 4, 5])\n```\n\n更多内容可参考  [array](http://docs.micropython.org/en/latest/pyboard/library/array.html) 。\n"
  },
  {
    "path": "docs/std-librarys/ubinascii.md",
    "content": "## **ubinascii** – 二进制/ ASCII转换\n\n`ubinascii` 模块包含许多在二进制和各种 ascii 编码的二进制表示之间转换的方法。\n\n### 函数\n\n#### **ubinascii.hexlify**(data[, sep])  \n将字符串转换为十六进制表示的字符串。 \n\n示例：\n\n```\n>>> ubinascii.hexlify('hello RT-Thread')\nb'68656c6c6f2052542d546872656164'\n>>> ubinascii.hexlify('summer')\nb'73756d6d6572'\n```\n如果指定了第二个参数sep，它将用于分隔两个十六进制数。 \n\n示例：\n\n```\n如果指定了第二个参数sep，它将用于分隔两个十六进制数。 \n示例：\n>>> ubinascii.hexlify('hello RT-Thread',\" \")\nb'68 65 6c 6c 6f 20 52 54 2d 54 68 72 65 61 64'\n>>> ubinascii.hexlify('hello RT-Thread',\",\")\nb'68,65,6c,6c,6f,20,52,54,2d,54,68,72,65,61,64'\n```\n\n#### **ubinascii.unhexlify**(data)  \n转换十六进制字符串为二进制字符串，功能和 hexlify 相反。 \n\n示例：\n\n```\n>>> ubinascii.unhexlify('73756d6d6572')\nb'summer'\n```\n\n#### **ubinascii.a2b_base64**(data)  \nBase64编码的数据转换为二进制表示。返回字节串。\n\n#### **ubinascii.b2a_base64**(data)  \n编码base64格式的二进制数据。返回的字符串。\n\n更多内容可参考 [ubinascii](http://docs.micropython.org/en/latest/pyboard/library/ubinascii.html)  。\n"
  },
  {
    "path": "docs/std-librarys/ucollections.md",
    "content": "## **ucollections** – 集合与容器类型\n\n**ucollections** 模块实现了专门的容器数据类型，它提供了 Python 的通用内置容器的替代方案，包括了字典、列表、集合和元组。\n\n### 类\n\n#### **ucollections.namedtuple**(name, fields)  \n这是工厂函数创建一个新的 `namedtuple` 型与一个特定的字段名称和集合。`namedtuple` 是元组允许子类要访问它的字段不仅是数字索引，而且还具有属性使用符号字段名访问语法。 字段是字符串序列指定字段名称。为了兼容的实现也可以用空间分隔的字符串命名的字段（但效率较低） 。\n\n代码示例：\n```python\nfrom ucollections import namedtuple\n\nMyTuple = namedtuple(\"MyTuple\", (\"id\", \"name\"))\nt1 = MyTuple(1, \"foo\")\nt2 = MyTuple(2, \"bar\")\nprint(t1.name)\nassert t2.name == t2[1]\nucollections.OrderedDict(...)\n```\n\n#### **ucollections.OrderedDict**(...)  \n字典类型的子类，会记住并保留键/值的追加顺序。当有序的字典被迭代输出时，键/值 会按照他们被添加的顺序返回 :\n\n```python\nfrom ucollections import OrderedDict\n\n# To make benefit of ordered keys, OrderedDict should be initialized\n# from sequence of (key, value) pairs.\nd = OrderedDict([(\"z\", 1), (\"a\", 2)])\n# More items can be added as usual\nd[\"w\"] = 5\nd[\"b\"] = 3\nfor k, v in d.items():\n    print(k, v)\n```\n输出:\n\nz 1\na 2\nw 5\nb 3\n\n更多的内容可参考 [ucollections](http://docs.micropython.org/en/latest/pyboard/library/ucollections.html) 。\n"
  },
  {
    "path": "docs/std-librarys/uctypes.md",
    "content": "## **uctypes** – 以结构化的方式访问二进制数据\n\nuctypes 模块用来访问二进制数据结构，它提供 C 兼容的数据类型。\n\n### 常量\n- uctypes.LITTLE_ENDIAN — 小端压缩结构。\n- uctypes.BIG_ENDIAN — 大端压缩结构类型。\n- NATIVE —  mricopython 本地的存储类型\n\n\n### 构造函数\n\n#### class uctypes.struct(addr, descriptor, type)\n将内存中以 c 形式打包的结构体或联合体转换为字典，并返回该字典。\n```\naddr：开始转换的地址\ndescriptor：转换描述符\n格式：\"field_name\":offset|uctypes.UINT32\noffset：偏移量，\n单位：字节、VOID、UINT8、INT8、UINT16、INT16、UINT32、INT32、UINT64、INT64、BFUINT8、BFINT8、BFUINT16、BFINT16、BFUINT32、BFINT32、BF_POS、BF_LEN、FLOAT32、FLOAT64、PTR、ARRAY\ntype：c 结构体或联合体存储类型，默认为本地存储类型\n```\n\n示例：\n\n```python\n>>> a = b\"0123\"\n>>> s = uctypes.struct(uctypes.addressof(a), {\"a\": uctypes.UINT8 | 0, \"b\": uctypes.UINT16 | 1}, uctypes.LITTLE_ENDIAN)\n>>> print(s)\n<struct STRUCT 3ffc7360>\n>>> print(s.a)\n48\n>>> s.a = 49\n>>> print(a)\nb'1123'\n```\n\n### 方法\n\n#### **uctypes.sizeof**(struct)  \n按字节返回数据的大小。参数可以是类或者数据对象 (或集合)。 \n示例：\n```python\n>>> a = b\"0123\"\n>>>b = uctypes.struct(uctypes.addressof(a), {\"a\": uctypes.UINT8 | 0, \"b\": uctypes.UINT16 | 1}, uctypes.LITTLE_ENDIAN)\n>>> b.a\n48\n>>> print(uctypes.sizeof(b))\n3\n```\n\n#### **uctypes.addressof**(obj)  \n返回对象地址。参数需要是 bytes, bytearray 。 \n示例：\n\n```python\n>>> a = b\"0123\"\n>>> print(uctypes.addressof(a))\n1073504048\n```\n\n#### **uctypes.bytes_at**(addr, size)  \n捕捉从 addr 开始到 size 个地址偏移量结束的内存数据为 bytearray 对象并返回。 \n示例：\n\n```python\n>>> a = b\"0123\"\n>>>print( uctypes.bytes_at(uctypes.addressof(a), 4))\nb'0123'\n```\n\n#### **uctypes.bytearray_at**(addr, size)  \n捕捉给定大小和地址内存为 bytearray 对象。与 bytes_at() 函数不同的是，它可以被再次写入，可以访问给定地址的参数。 \n示例：\n\n```python\n>>> a = b\"0123\"\n>>> print(uctypes.bytearray_at(uctypes.addressof(a), 2))\nbytearray(b'01')\n```\n\n更多内容可参考 [uctypes](http://docs.micropython.org/en/latest/pyboard/library/uctypes.html) 。\n"
  },
  {
    "path": "docs/std-librarys/uerrno.md",
    "content": "## **uerrno** – 系统错误码模块\n\n`uerrno` 模块提供了标准的 errno 系统符号，每个符号都有对应的整数值。\n\n### 示例\n\n```python\ntry:\n    uos.mkdir(\"my_dir\")\nexcept OSError as exc:\n    if exc.args[0] == uerrno.EEXIST:\n        print(\"Directory already exists\")\nuerrno.errorcode\nDictionary mapping numeric error codes to strings with symbolic error code (see above):\n\n>>> print(uerrno.errorcode[uerrno.EEXIST])\nEEXIST\n```\n\n更多内容可参考 [uerrno](http://docs.micropython.org/en/latest/pyboard/library/uerrno.html) 。\n"
  },
  {
    "path": "docs/std-librarys/uhashlib.md",
    "content": "## **uhashlib** – 哈希算法\n\n`uhashlib` 模块实现了二进制数据哈希算法。\n\n### 算法功能\n\n#### **SHA256** \n当代的散列算法（SHA2系列），它适用于密码安全的目的。被包含在 MicroPython 内核中，除非有特定的代码大小限制，否则推荐任何开发板都支持这个功能。\n\n#### **SHA1**\n上一代的算法，不推荐新的应用使用这种算法，但是 SHA1 算法是互联网标准和现有应用程序的一部分，所以针对网络连接便利的开发板会提供这种功能。\n\n#### **MD5** \n一种遗留下来的算法，作为密码使用被认为是不安全的。只有特定的开发板，为了兼容老的应用才会提供这种算法。\n\n### 函数\n\n#### **class uhashlib.sha256**([data])  \n创建一个SHA256哈希对象并提供 data 赋值。\n\n#### **class uhashlib.sha1**([data])  \n创建一个SHA1哈希对象并提供 data 赋值。\n\n#### **class uhashlib.md5**([data])  \n创建一个MD5哈希对象并提供 data 赋值。\n\n#### **hash.update**(data)  \n将更多二进制数据放入哈希表中。\n\n#### **hash.digest**()  \n返回字节对象哈希的所有数据。调用此方法后，将无法将更多数据送入哈希。\n\n#### **hash.hexdigest**()  \n此方法没有实现， 使用 ubinascii.hexlify(hash.digest()) 达到类似效果。\n\n更多内容可参考 [uhashlib](http://docs.micropython.org/en/latest/pyboard/library/uhashlib.html)  。\n"
  },
  {
    "path": "docs/std-librarys/uheapq.md",
    "content": "## **uheapq** – 堆排序算法\n\n`uheapq` 模块提供了堆排序相关算法，堆队列是一个列表，它的元素以特定的方式存储。\n\n### 函数\n\n#### **uheapq.heappush**(heap, item)  \n将对象压入堆中。\n\n#### **uheapq.heappop**(heap)  \n从 heap 弹出第一个元素并返回。 如果是堆时空的会抛出 IndexError。\n\n#### **uheapq.heapify**(x)  \n将列表 x 转换成堆。\n\n更多内容可参考 [uheapq](http://docs.micropython.org/en/latest/pyboard/library/uheapq.html)  。\n"
  },
  {
    "path": "docs/std-librarys/uio.md",
    "content": "## **uio** – 输入/输出流\n\n**uio** 模块包含流类型 (类似文件) 对象和帮助函数。\n\n### 函数\n\n#### **uio.open**(name, mode='r', \\*\\*kwargs)\n\n打开一个文件，关联到内建函数``open()``。所有端口 (用于访问文件系统) 需要支持模式参数，但支持其他参数不同的端口。\n\n### 类\n\n#### **class uio.FileIO**(...)\n  这个文件类型用二进制方式打开文件，等于使用``open(name, “rb”)``。 不应直接使用这个实例。\n\n#### **class uio.TextIOWrapper**(...)  \n  这个类型以文本方式打开文件，等同于使用``open(name, “rt”)``不应直接使用这个实例。\n\n#### **class uio.StringIO**([string])  \n\n#### **class uio.BytesIO**([string])  \n  内存文件对象。`StringIO` 用于文本模式 I/O (用 “t” 打开文件)，`BytesIO` 用于二进制方式 (用 “b” 方式)。文件对象的初始内容可以用字符串参数指定（`stringio`用普通字符串，`bytesio`用`bytes`对象）。所有的文件方法，如 `read(), write(), seek(), flush(), close()` 都可以用在这些对象上，包括下面方法:\n\n#### **getvalue**()  \n  获取缓存区内容。\n\n更多内容可参考  [uio](http://docs.micropython.org/en/latest/pyboard/library/uio.html) 。\n"
  },
  {
    "path": "docs/std-librarys/ujson.md",
    "content": "## **ujson** – JSON编码与解码\n\n`ujson` 模块提供 Python 对象到 JSON（JavaScript Object Notation） 数据格式的转换。\n\n### 函数\n\n#### **ujson.dumps**(obj)  \n\n将 dict 类型转换成 str。\n\n```\nobj：要转换的对象\n```\n\n示例：\n\n```\n>>> obj = {1:2, 3:4, \"a\":6}\n>>> print(type(obj), obj) #原来为dict类型\n<class 'dict'> {3: 4, 1: 2, 'a': 6}\n>>> jsObj = json.dumps(obj) #将dict类型转换成str\n>>> print(type(jsObj), jsObj)\n<class 'str'> {3: 4, 1: 2, \"a\": 6}\n```\n\n#### **ujson.loads**(str)  \n解析 JSON 字符串并返回对象。如果字符串格式错误将引发 ValueError 异常。 \n示例：\n\n```\n>>> obj = {1:2, 3:4, \"a\":6}\n>>> jsDumps = json.dumps(obj)\n>>> jsLoads = json.loads(jsDumps)\n>>> print(type(obj), obj)\n<class 'dict'> {3: 4, 1: 2, 'a': 6}\n>>> print(type(jsDumps), jsDumps)\n<class 'str'> {3: 4, 1: 2, \"a\": 6}\n>>> print(type(jsLoads), jsLoads)\n<class 'dict'> {'a': 6, 1: 2, 3: 4}\n```\n\n更多内容可参考 [ujson](http://docs.micropython.org/en/latest/pyboard/library/ujson.html)  。\n"
  },
  {
    "path": "docs/std-librarys/uos.md",
    "content": "## **uos** – 基本的操作系统服务\n\n`uos` 模块包含了对文件系统的访问操作，是对应 CPython 模块的一个子集。\n\n### 函数\n\n#### **uos.chdir**(path)  \n更改当前目录。\n\n#### **uos.getcwd**()  \n获取当前目录。\n\n#### **uos.listdir**([dir])\n没有参数就列出当前目录，否则列出给定目录。\n\n#### **uos.mkdir**(path)  \n创建一个目录。\n\n#### **uos.remove**(path)  \n删除文件。\n\n#### **uos.rmdir**(path)  \n删除目录。\n\n#### **uos.rename**(old_path, new_path)  \n重命名文件或者文件夹。\n\n#### **uos.stat**(path)  \n获取文件或目录的状态。\n\n#### **uos.sync**()  \n同步所有的文件系统。\n\n### 示例\n\n```\n>>> import uos\n>>> uos.                        # Tab \n__name__        uname           chdir           getcwd\nlistdir         mkdir           remove          rmdir\nstat            unlink          mount           umount\n>>> uos.mkdir(\"rtthread\")\n>>> uos.getcwd()\n'/'\n>>> uos.chdir(\"rtthread\")\n>>> uos.getcwd()\n'/rtthread'\n>>> uos.listdir()\n['web_root', 'rtthread', '11']\n>>> uos.rmdir(\"11\")\n>>> uos.listdir()\n['web_root', 'rtthread']\n>>> \n```\n\n更多内容可参考 [uos](http://docs.micropython.org/en/latest/pyboard/library/uos.html) 。\n"
  },
  {
    "path": "docs/std-librarys/urandom.md",
    "content": "## **urandom** - 随机数生成模块\n\n`urandom` 模块实现了伪随机数生成器。\n\n### 函数 \n\n#### **urandom.choice**(obj)  \n\n随机生成对象 obj 中的元数。\n\n```\nobj：元数列表\n```\n\n示例：\n\n```python\n>>> print(random.choice(\"DFRobot\"))\nR\n>>> print(random.choice(\"DFRobot\"))\nD\n>>> print(random.choice([0, 2, 4, 3]))\n3\n>>> print(random.choice([0, 2, 4, 3]))\n3\n>>> print(random.choice([0, 2, 4, 3]))\n2\n```\n\n#### **urandom.getrandbits**(size)  \n\n随机生成 0 到 size 个位二进制数范围内的正整数。 比如 ：\n\n- size = 4，那么便是从 0 到0b1111中随机一个正整数。 \n- size = 8，那么便是从 0 到 0b11111111中随机一个正整数。\n\n```python\nsize：位大小\n```\n\n示例：\n\n```python\n>>> print( random.getrandbits(1))  #1位二进制位，范围为0~1（十进制：0~1）\n1\n>>> print(random.getrandbits(1))\n0\n>>> print(random.getrandbits(8))  #8位二进制位，范围为0000 0000~1111 11111（十进制：0~255）\n224\n>>> print(random.getrandbits(8))\n155\n```\n\n#### **urandom.randint**(start, end)  \n\n随机生成一个 start 到 end 之间的整数。 \n\n```\nstart：指定范围内的开始值，包含在范围内\nend：指定范围内的结束值，包含在范围内\n```\n\n示例：\n\n```python\n>>> import random\n>>> print(random.randint(1, 4))\n4\n>>> print(random.randint(1, 4))\n2\n```\n\n#### **urandom.random**()  \n随机生成一个 0 到 1 之间的浮点数。 \n示例：\n\n```python\n>>> print(random.random())\n0.7111824\n>>> print(random.random())\n0.3168149\n```\n\n#### **urandom.randrange**(start, end, step)  \n\n随机生成 start 到 end 并且递增为 step 的范围内的正整数。例如，randrange(0, 8, 2)中，随机生成的数为 0、2、4、6 中任一个。\n\n```\nstart：指定范围内的开始值，包含在范围内\nend：指定范围内的结束值，包含在范围内\nstep：递增基数\n```\n\n示例：\n\n```python\n>>> print(random.randrange(2, 8, 2))\n4\n>>> print(random.randrange(2, 8, 2))\n6\n>>> print(random.randrange(2, 8, 2))\n2\n```\n\n#### **urandom.seed**(sed)  \n\n指定随机数种子，通常和其他随机数生成函数搭配使用。 \n**注意：** \n   MicroPython 中的随机数其实是一个稳定算法得出的稳定结果序列，而不是一个随机序列。sed 就是这个算法开始计算的第一个值。所以就会出现只要 sed 是一样的，那么后续所有“随机”结果和顺序也都完全一致。\n\n```\nsed：随机数种子\n```\n\n示例：\n\n```python\nimport random\n\nfor j in range(0, 2):\n  random.seed(13)  #指定随机数种子\n  for i in range(0, 10):  #生成0到10范围内的随机序列\n    print(random.randint(1, 10))\n  print(\"end\")\n```\n\n运行结果：\n\n```\n5\n2\n3\n2\n3\n4\n2\n5\n8\n2\nend\n5\n2\n3\n2\n3\n4\n2\n5\n8\n2\nend\n```\n\n   从上面可以看到生成两个随机数列表是一样的，你也可以多生成几个随机数列表查看结果。\n\n#### **urandom.uniform**(start, end)  \n\n随机生成start到end之间的浮点数。\n\n```\nstart：指定范围内的开始值，包含在范围内\nstop：指定范围内的结束值，包含在范围内\n```\n\n示例：\n\n```python\n>>> print(random.uniform(2, 4))\n2.021441\n>>> print(random.uniform(2, 4))\n3.998012\n```\n\n更多内容可参考 [urandom](https://docs.python.org/3/library/random.html?highlight=random#module-random) 。\n"
  },
  {
    "path": "docs/std-librarys/ure.md",
    "content": "## **ure** – 正则表达式\n\n`ure` 模块用于测试字符串的某个模式，执行正则表达式操作。\n\n### 匹配字符集\n\n\n#### 匹配任意字符\n  ``'.'``\n\n#### 匹配字符集合，支持单个字符和一个范围\n  ``'[]'``\n\n#### 支持多种匹配元字符\n  ``'^'``\n  ``'$'``\n  ``'?'``\n  ``'*'``\n  ``'+'``\n  ``'??'``\n  ``'*?'``\n  ``'+?'``\n  ``'{m,n}'``\n\n### 函数\n\n#### **ure.compile**(regex)  \n编译正则表达式，返回 regex 对象。\n\n#### **ure.match**(regex, string)  \n用 string 匹配 regex，匹配总是从字符串的开始匹配。\n\n#### **ure.search**(regex, string)  \n在 string 中搜索 regex。不同于匹配，它搜索第一个匹配位置的正则表达式字符串 (结果可能会是0)。\n\n#### **ure.DEBUG**  \n标志值，显示表达式的调试信息。\n\n### **正则表达式对象**:\n编译正则表达式，使用 `ure.compile()` 创建实例。\n\n#### **regex.match**(string)  \n#### **regex.search**(string)  \n#### **regex.split**(string, max_split=-1)  \n\n### **匹配对象** :\n匹配对象是 match() 和 search() 方法的返回值。\n\n#### **match.group**([index])  \n只支持数字组。\n\n更多内容可参考 [ure](http://docs.micropython.org/en/latest/pyboard/library/ure.html)  。\n"
  },
  {
    "path": "docs/std-librarys/uselect.md",
    "content": "## **uselect** – 等待流事件\n\n`uselect` 模块提供了等待数据流的事件功能。\n\n### 常数\n\n#### **select.POLLIN** - 读取可用数据  \n\n#### **select.POLLOUT** - 写入更多数据  \n\n#### **select.POLLERR** - 发生错误  \n\n#### **select.POLLHUP** - 流结束/连接终止检测  \n\n### 函数\n\n#### **select.select**(rlist, wlist, xlist[, timeout])  \n监控对象何时可读或可写，一旦监控的对象状态改变，返回结果（阻塞线程）。这个函数是为了兼容，效率不高，推荐用 `poll` 函数 。\n\n```\nrlist：等待读就绪的文件描述符数组\nwlist：等待写就绪的文件描述符数组\nxlist：等待异常的数组\ntimeout：等待时间（单位：秒）\n```\n示例：\n\n```python\ndef selectTest():\n  global s\n  rs, ws, es = select.select([s,], [], [])\n  #程序会在此等待直到对象s可读\n  print(rs)\n  for i in rs:\n    if i == s:\n      print(\"s can read now\")\n      data,addr=s.recvfrom(1024)\n      print('received:',data,'from',addr)\n```\n\n### Poll 类\n\n#### **select.poll**()  \n创建 poll 实例。\n\n示例：\n\n```\n>>>poller = select.poll()\n>>>print(poller)\n<poll>\n```\n\n#### **poll.register**(obj[, eventmask])  \n注册一个用以监控的对象，并设置被监控对象的监控标志位 flag。 \n\n```\nobj：被监控的对象\nflag：被监控的标志\n    select.POLLIN — 可读\n    select.POLLHUP — 已挂断\n    select.POLLERR — 出错\n    select.POLLOUT — 可写\n```\n\n#### **poll.unregister**(obj)  \n解除监控的对象的注册。 \n\n```\nobj：注册过的对象\n```\n\n示例：\n\n```\n>>>READ_ONLY = select.POLLIN | select.POLLHUP | select.POLLERR\n>>>READ_WRITE = select.POLLOUT | READ_ONLY\n>>>poller.register(s, READ_WRITE)\n>>>poller.unregister(s)\n```\n\n#### **poll.modify**(obj, eventmask)  \n修改已注册的对象监控标志。 \n\n```\nobj：已注册的被监控对象\nflag：修改为的监控标志\n```\n\n示例：\n\n```\n>>>READ_ONLY = select.POLLIN | select.POLLHUP | select.POLLERR\n>>>READ_WRITE = select.POLLOUT | READ_ONLY\n>>>poller.register(s, READ_WRITE)\n>>>poller.modify(s, READ_ONLY)\n```\n\n#### **poll.poll**([timeout])  \n等待至少一个已注册的对象准备就绪。返回 (obj, event, ...) 元组, event 元素指定了一个流发生的事件，是上面所描述的 `select.POLL*`常量组合。 根据平台和版本的不同，在元组中可能有其他元素，所以不要假定元组的大小是 2 。如果超时，则返回空列表。\n\n更多内容可参考 [uselect](http://docs.micropython.org/en/latest/pyboard/library/uselect.html) 。\n"
  },
  {
    "path": "docs/std-librarys/usocket.md",
    "content": "## **usocket** – 套接字模块\n\n`usocket` 模块提供对BSD套接字接口的访问。 \n\n### 常数\n\n#### 地址簇\n- socket.AF_INET =2 — TCP/IP – IPv4\n- socket.AF_INET6 =10 — TCP/IP – IPv6\n\n#### 套接字类型\n- socket.SOCK_STREAM =1 — TCP流\n- socket.SOCK_DGRAM =2 — UDP数据报\n- socket.SOCK_RAW =3 — 原始套接字\n- socket.SO_REUSEADDR =4 — socket可重用\n\n#### IP协议号\n- socket.IPPROTO_TCP =16\n- socket.IPPROTO_UDP =17\n\n#### 套接字选项级别\n- socket.SOL_SOCKET =4095\n\n### 函数\n\n#### **socket.socket**\n\n`socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)` \n\n创建新的套接字，使用指定的地址、类型和协议号。\n\n#### **socket.getaddrinfo**(host, port) \n将主机域名（host）和端口（port）转换为用于创建套接字的5元组序列。元组列表的结构如下:\n\n```\n(family, type, proto, canonname, sockaddr)\n```\n\n示例：\n\n```\n>>> info = socket.getaddrinfo(\"rt-thread.org\", 10000)\n>>> print(info)\n[(2, 1, 0, '', ('118.31.15.152', 10000))]\n```\n\n#### **socket.close**()  \n关闭套接字。一旦关闭后，套接字所有的功能都将失效。远端将接收不到任何数据 (清理队列数据后)。 虽然在垃圾回收时套接字会自动关闭，但还是推荐在必要时用 close() 去关闭。\n\n#### **socket.bind**(address)  \n将套接字绑定到地址，套接字不能是已经绑定的。\n\n#### **socket.listen**([backlog])  \n监听套接字，使服务器能够接收连接。\n```\nbacklog：接受套接字的最大个数，至少为0，如果没有指定，则默认一个合理值。\n```\n\n#### **socket.accept**()  \n接收连接请求。 \n**注意：** \n   只能在绑定地址端口号和监听后调用，返回 conn 和 address。\n\n```\nconn：新的套接字对象，可以用来收发消息\naddress：连接到服务器的客户端地址\n```\n\n#### **socket.connect**(address)  \n连接服务器。\n\n```\naddress：服务器地址和端口号的元组或列表\n```\n\n#### **socket.send**(bytes)  \n发送数据，并返回成功发送的字节数，返回字节数可能比发送的数据长度少。\n\n```\nbytes：bytes类型数据\n```\n\n#### **socket.recv**(bufsize)  \n接收数据，返回接收到的数据对象。\n\n```\nbufsize：指定一次接收的最大数据量\n```\n\n示例：\n\n```\ndata = conn.recv(1024)\n```\n\n#### **socket.sendto**(bytes, address)  \n发送数据，目标由address决定，常用于UDP通信，返回发送的数据大小。\n\n```\nbytes：bytes类型数据\naddress：目标地址和端口号的元组\n```\n\n示例：\n\n```\ndata = sendto(\"hello RT-Thread\", (\"192.168.10.110\", 100))\n```\n\n#### **socket.recvfrom**(bufsize)  \n接收数据，常用于UDP通信，并返回接收到的数据对象和对象的地址。\n\n```\nbufsize：指定一次接收的最大数据量\n```\n\n示例：\n\n```\ndata,addr=fd.recvfrom(1024)\n```\n\n#### **socket.setsockopt**(level, optname, value)  \n根据选项值设置套接字。\n\n```\nlevel：套接字选项级别\noptname：套接字的选项\nvalue：可以是一个整数，也可以是一个表示缓冲区的bytes类对象。\n```\n\n示例：\n\n```\ns.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n```\n\n#### **socket.settimeout**(value)  \n设置超时时间，单位：秒。 \n示例：\n\n```\ns.settimeout(2)\n```\n\n#### **socket.setblocking**(flag)  \n设置阻塞或非阻塞模式: 如果 flag 是 false，设置非阻塞模式。\n\n#### **socket.read**([size])  \nRead up to size bytes from the socket. Return a bytes object. If size is not given, it reads all data available from the socket until EOF; as such the method will not return until the socket is closed. This function tries to read as much data as requested (no “short reads”). This may be not possible with non-blocking socket though, and then less data will be returned.\n\n#### **socket.readinto**(buf[, nbytes])  \nRead bytes into the buf. If nbytes is specified then read at most that many bytes. Otherwise, read at most len(buf) bytes. Just as read(), this method follows “no short reads” policy.\nReturn value: number of bytes read and stored into buf.\n\n#### **socket.readline**()  \n接收一行数据，遇换行符结束，并返回接收数据的对象 。 \n\n#### **socket.write**(buf)  \n将字节类型数据写入套接字，并返回写入成功的数据大小。 \n\n### 示例\n\n#### TCP Server example\n\n```\n>>> import usocket \n>>> s = usocket.socket(usocket.AF_INET,usocket.SOCK_STREAM)  # Create STREAM TCP socket\n>>> s.bind(('192.168.12.32', 6001))   \n>>> s.listen(5)\n>>> s.setblocking(True)\n>>> sock,addr=s.accept()              \n>>> sock.recv(10)                    \nb'rt-thread\\r'\n>>> s.close()\n```\n\n#### TCP Client example\n\n```\n>>> import usocket \n>>> s = usocket.socket(usocket.AF_INET,usocket.SOCK_STREAM)\n>>> s.connect((\"192.168.10.110\",6000))  \n>>> s.send(\"micropython\")               \n11\n>>> s.close()\n```\n\n`connect to a web site example`:\n```\ns = socket.socket()\ns.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1])\n```\n\n更多的内容可参考 [usocket](http://docs.micropython.org/en/latest/pyboard/library/usocket.html) 。\n"
  },
  {
    "path": "docs/std-librarys/ussl.md",
    "content": "# ussl – SSL/TLS 模块\n\nThis module implements a subset of the corresponding* [`CPython`](http://docs.micropython.org/en/latest/reference/glossary.html#term-cpython) *module, as described below. For more information, refer to the original CPython documentation: [`ssl`](https://docs.python.org/3.5/library/ssl.html#module-ssl).\n\nThis module provides access to Transport Layer Security (previously and widely known as “Secure Sockets Layer”) encryption and peer authentication facilities for network sockets, both client-side and server-side.\n\n## 功能函数\n\n- `ussl.wrap_socket`(sock, server_side=False, key=None, cert=None)\n\nTakes a [`stream`](http://docs.micropython.org/en/latest/reference/glossary.html#term-stream) *sock* (usually usocket.socket instance of `SOCK_STREAM` type), and returns an instance of ssl.SSLSocket, which wraps the underlying stream in an SSL context. Returned object has the usual [`stream`](http://docs.micropython.org/en/latest/reference/glossary.html#term-stream) interface methods like `read()`, `write()`, etc. In MicroPython, the returned object does not expose socket interface and methods like `recv()`, `send()`. In particular, a server-side SSL socket should be created from a normal socket returned from[`accept()`](http://docs.micropython.org/en/latest/library/usocket.html#usocket.socket.accept) on a non-SSL listening server socket. Depending on the underlying module implementation in a particular [`MicroPython port`](http://docs.micropython.org/en/latest/reference/glossary.html#term-micropython-port), some or all keyword arguments above may be not supported.\n\nWarning: Some implementations of `ussl` module do NOT validate server certificates, which makes an SSL connection established prone to man-in-the-middle attacks.\n\n## 异常类型\n\n- `ssl.SSLError`\n\n  This exception does NOT exist. Instead its base class, OSError, is used.\n\n## 常量\n\n- `ussl.CERT_NONE`\n\n- `ussl.CERT_OPTIONAL`\n\n- `ussl.CERT_REQUIRED`\n- Supported values for **cert_reqs** parameter."
  },
  {
    "path": "docs/std-librarys/ustruct.md",
    "content": "## **ustruct** – 打包和解包原始数据类型\n\n**ustruct** 模块在 Python 值和以 Python 字节对象表示的 C 结构之间执行转换。\n\n- 支持 size/byte 的前缀: @, <, >, !.\n- 支持的格式代码: b, B, h, H, i, I, l, L, q, Q, s, P, f, d (最后2个需要支持浮点数).\n\n### 函数\n\n#### **ustruct.calcsize**(fmt)  \n返回存放某一类型数据 fmt 需要的字节数。\n\n```\nfmt：数据类型\n    b — 字节型\n    B — 无符号字节型\n    h — 短整型\n    H — 无符号短整型\n    i — 整型\n    I — 无符号整型\n    l — 整型\n    L — 无符号整型\n    q — 长整型\n    Q — 无符号长整型\n    f — 浮点型\n    d — 双精度浮点型\n    P — 无符号型\n```\n\n示例：\n\n```python\n>>> print(struct.calcsize(\"i\"))\n4\n>>> print(struct.calcsize(\"B\"))\n1\n```\n\n#### **ustruct.pack**(fmt, v1, v2, ...)  \n按照格式字符串 fmt 打包参数 v1, v2, ... 。返回值是参数打包后的字节对象。\n\n```\nfmt：同上\n```\n\n示例：\n\n```python\n>>> struct.pack(\"ii\", 3, 2)\nb'\\x03\\x00\\x00\\x00\\x02\\x00\\x00\\x00'\n```\n\n#### **ustruct.unpack**(fmt, data)  \n从 fmt 中解包数据。返回值是解包后参数的元组。\n\n```\ndata：要解压的字节对象\n```\n\n示例：\n\n```python\n>>> buf = struct.pack(\"bb\", 1, 2)\n>>> print(buf)\nb'\\x01\\x02'\n>>> print(struct.unpack(\"bb\", buf))\n(1, 2)\n```\n\n#### **ustruct.pack_into**(fmt, buffer, offset, v1, v2, ...)  \n按照格式字符串 fmt 压缩参数 v1, v2, ... 到缓冲区 buffer，开始位置是 offset。当offset 为负数时，从缓冲区末尾开始计数。 \n\n#### **ustruct.unpack_from**(fmt, data, offset=0)  \n以 fmt 作为规则从 data 的 offset 位置开始解包数据，如果 offset 是负数就是从缓冲区末尾开始计算。返回值是解包后的参数元组。\n```python\n>>> buf = struct.pack(\"bb\", 1, 2)\n>>> print(struct.unpack(\"bb\", buf))\n(1, 2)\n>>> print(struct.unpack_from(\"b\", buf, 1))\n(2,)\n```\n更多的内容可参考  [ustruct](http://docs.micropython.org/en/latest/pyboard/library/ustruct.html) 。\n"
  },
  {
    "path": "docs/std-librarys/utime.md",
    "content": "## **utime** – 时间相关函数\n\n**utime** 模块提供获取当前时间和日期、测量时间间隔和延迟的功能。\n\n**初始时刻**: `Unix` 使用 `POSIX` 系统标准，从 1970-01-01 00:00:00 `UTC` 开始。\n嵌入式程序从 2000-01-01 00:00:00 `UTC` 开始。\n\n**保持实际日历日期/时间**:需要一个实时时钟 `(RTC)`。在底层系统 (包括一些 `RTOS` 中)，`RTC` 已经包含在其中。设置时间是通过 `OS/RTOS` 而不是 MicroPython 完成，查询日期/时间也需要通过系统 `API`。对于裸板系统时钟依赖于 ``machine.RTC()`` 对象。设置时间通过 ``machine.RTC().datetime(tuple)`` 函数，并通过下面方式维持:\n\n* 后备电池 (可能是选件、扩展板等)。\n* 使用网络时间协议 (需要用户设置)。\n* 每次上电时手工设置 (大部分只是在硬复位时需要设置，少部分每次复位都需要设置)。\n\n如果实际时间不是通过系统 / MicroPython RTC 维持，那么下面函数结果可能不是和预期的相同。\n\n### 函数\n\n#### **utime.localtime**([secs])  \n   从初始时间的秒转换为元组: (年, 月, 日, 时, 分, 秒, 星期, ``yearday``) 。如果 ``secs`` 是空或者 ``None``，那么使用当前时间。  \n\n- `year ` 年份包括世纪（例如2014）。 \n- `month`  范围 1-12     \n- `day`    范围 1-31  \n- `hour`    范围 0-23  \n- `minute` 范围 0-59  \n- `second`  范围 0-59  \n- `weekday` 范围 0-6 对应周一到周日  \n- `yearday` 范围 1-366  \n\n#### **utime.mktime**()  \n   时间的反函数，它的参数是完整8参数的元组，返回值一个整数自2000年1月1日以来的秒数。\n\n#### **utime.sleep**(seconds)  \n  休眠指定的时间（秒），``Seconds`` 可以是浮点数。注意有些版本的 MicroPython不支持浮点数，为了兼容可以使用 ``sleep_ms()`` 和 ``sleep_us()``函数。\n\n#### **utime.sleep_ms**(ms)  \n  延时指定毫秒，参数不能小于0。\n\n#### **utime.sleep_us**(us)  \n  延时指定微秒，参数不能小于0。\n\n#### **utime.ticks_ms**()  \n  返回不断递增的毫秒计数器，在某些值后会重新计数(未指定)。计数值本身无特定意义，只适合用在``ticks_diff()``。  \n  注： 直接在这些值上执行标准数学运算（+，-）或关系运算符（<，>，>，> =）会导致无效结果。执行数学运算然后传递结果作为参数给`ticks_diff()` 或 ` ticks_add() ` 也将导致函数产生无效结果。\n\n#### **utime.ticks_us**()  \n  和上面 `ticks_ms()` 类似，只是返回微秒。\n\n#### **utime.ticks_cpu**()  \n  与 ``ticks_ms()`` 和 ``ticks_us()`` 类似，具有更高精度 (使用 CPU 时钟)，并非每个端口都实现此功能。\n\n#### **utime.ticks_add**(ticks, delta)\n  给定一个数字作为节拍的偏移值 `delta`，这个数字的值是正数或者负数都可以。\n  给定一个 `ticks` 节拍值，本函数允许根据节拍值的模算数定义来计算给定节拍值之前或者之后 `delta` 个节拍的节拍值 。\n  `ticks` 参数必须是 `ticks_ms()`, `ticks_us()`, or `ticks_cpu()` 函数的直接返回值。然而，`delta` 可以是一个任意整数或者是数字表达式。`ticks_add` 函数对计算事件/任务的截至时间很有用。（注意：必须使用 `ticksdiff()` 函数来处理\n最后期限)。\n\n代码示例：\n```python\n## 查找 100ms 之前的节拍值\nprint(utime.ticks_add(utime.ticks_ms(), -100))\n\n## 计算操作的截止时间然后进行测试\ndeadline = utime.ticks_add(utime.ticks_ms(), 200)\nwhile utime.ticks_diff(deadline, utime.ticks_ms()) > 0:\n    do_a_little_of_something()\n\n## 找出本次移植节拍值的最大值\nprint(utime.ticks_add(0, -1))\n```\n\n#### **utime.ticks_diff**(ticks1, ticks2)\n   计算两次调用 `ticksms()`, `ticks_us()`, 或 `ticks_cpu()`之间的时间。因为这些函数的计数值可能会回绕，所以不能直接相减，需要使用 `ticks_diff()` 函数。“旧” 时间需要在 “新” 时间之前，否则结果无法确定。这个函数不要用在计算很长的时间 (因为 `ticks*()` 函数会回绕，通常周期不是很长)。通常用法是在带超时的轮询事件中调用:\n\n代码示例：\n```python\n## 等待 GPIO 引脚有效，但是最多等待500微秒\nstart = time.ticks_us()\nwhile pin.value() == 0:\n    if time.ticks_diff(time.ticks_us(), start) > 500:\n        raise TimeoutError\n```\n\n#### **utime.time**()\n  返回从开始时间的秒数（整数），假设 `RTC` 已经按照前面方法设置好。如果 `RTC` 没有设置，函数将返回参考点开始计算的秒数 (对于 `RTC` 没有后备电池的板子，上电或复位后的情况)。如果你开发便携版的 MicroPython 应用程序，你不要依赖函数来提供超过秒级的精度。如果需要高精度，使用 `ticks_ms()` 和 `ticks_us()` 函数。如果需要日历时间，使用不带参数的 `localtime()` 是更好选择。\n\n!!! tip \"与 CPython 的区别\"\n    在 `CPython` 中，这个函数用浮点数返回从 `Unix` 开始时间（1970-01-01 00:00 `UTC`）的秒数，通常是毫秒级的精度。在 MicroPython 中，只有 `Unix` 版才使用相同开始时间，如果允许浮点精度，将返回亚秒精度。嵌入式硬件通常没有用浮点数表示长时间访问和亚秒精度，所以返回值是整数。一些嵌入式系统硬件不支持 `RTC` 电池供电方式，所以返回的秒数是从最后上电、或相对某个时间、以及特定硬件时间 (如复位)。\n\n###   示例 \n\n```\n>>> import utime\n>>> utime.sleep(1)           # sleep for 1 second\n>>> utime.sleep_ms(500)      # sleep for 500 milliseconds\n>>> utime.sleep_us(10)       # sleep for 10 microseconds\n>>> start = utime.ticks_ms() # get value of millisecond counter\n>>> delta = utime.ticks_diff(utime.ticks_ms(), start) # compute time difference\n>>> delta\n6928\n>>> print(utime.ticks_add(utime.ticks_ms(), -100))\n1140718\n>>> print(utime.ticks_add(0, -1))\n1073741823\n```\n\n更多内容可参考 [`utime`](http://docs.micropython.org/en/latest/pyboard/library/utime.html#module-utime)  。\n"
  },
  {
    "path": "docs/std-librarys/uzlib.md",
    "content": "## **uzlib** – zlib 解压缩\n\n`uzlib` 模块实现了使用 DEFLATE 算法解压缩二进制数据 (常用的 zlib 库和 gzip 文档)。目前不支持压缩。\n\n### 函数\n\n#### **uzlib.decompress**(data)  \n返回解压后的 bytes 数据。\n\n更多内容可参考 [uzlib](http://docs.micropython.org/en/latest/pyboard/library/uzlib.html) 。\n"
  },
  {
    "path": "docs/tools-mpy-cross.md",
    "content": "# 生成并运行 .mpy 文件\n\nPython 工程中，.py 文件可以被编译成 .pyc 字节码文件。使用这类预先编译好的二进制文件的优势是一定程度上能够保护源代码，同时可以提高程序的加载速度。在 micropython 中同样地提供了类似的功能，能够将 .py 文件编译成 .mpy 文件，并且能够在 MCU 内直接运行，减少资源消耗的同时提高了程序的加载速度。本篇演示使用潘多拉开发板，以 hello world 工程为例，编译并运行该 demo。\n\n## 使用 mpy-cross 工具编译\n\nRT-Thread 为开发者提供了便利的开发环境 ，针对 windows 平台提供了可以直接运行的 mpy-cross.exe，无需拖带 Linux 环境，轻量且速度快。\n\n本文将在 windows 环境中，使用软件包中提供的 mpy-cross.exe 软件。\n\n在 RT-Thread/micropython 项目里找到 tools 文件夹，下载 mpy-cross.exe。\n\n这里以 `hellortt.py` 示例：\n\n```python\nclass HelloRtt:\n  def __repr__(self):\n     self.__call__()\n     return \"\"\n\n  def __call__(self):\n     print(\"hello world!!\")\n     print(\"hello RTT\")\n\nhello = HelloRtt()\n```\n\n首先将需要被编译的 `hellortt.py` 文件拖入到 mpy-cross.exe 所在文件夹中，在按住 shift 键的同时，点击鼠标右键，选择 `在此处打开 Powershell 窗口`（ cmd 窗口在这里也是可以使用的）。然后在 Powershell 中，键入 `.\\mpy-cross.exe` 后面接上需要编译的工程 `hellortt.py`：\n\n![powershell_mpycross_deploy](assets/powershell_mpycross_deploy.png)\n\n此时如果编译成功将会生成 mpy 文件，上图编译成功后，在文件夹中生成了 `hellortt.mpy` 文件。我们将 `hellortt.mpy` 拷贝到 MCU 的文件系统上，便可以像 .py 文件一样被 import 并调用。\n\n## 拷贝至 MCU 文件系统中\n\n将生成好的 .mpy 文件，拷贝至 MicroPython IDE 的工程中，并选中它，右键下载到开发板的文件系统中，如图：\n\n![tools-mpy-download](assets/tools-mpy-download.png)\n\n当下载完成之后，便可以在串口命令行中尝试 import 该 mpy 文件，执行该文件的函数，确认能够正常使用：\n\n![mpy-usage-demo](assets/mpy-usage-demo.png)\n\n如果运行时出现 `ValueError: invalid .mpy file` 错误，有可能是 MCU 上 的 micropython 固件与 mpy-cross 版本固件不相符所致，当前提供的 mpy-cross 工具支持 v1.12 版本的固件 。\n\n"
  },
  {
    "path": "drivers/bus/qspi.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017-2018 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H\n#define MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H\n\n#include \"py/mphal.h\"\n\nenum {\n    MP_QSPI_IOCTL_INIT,\n    MP_QSPI_IOCTL_DEINIT,\n    MP_QSPI_IOCTL_BUS_ACQUIRE,\n    MP_QSPI_IOCTL_BUS_RELEASE,\n};\n\ntypedef struct _mp_qspi_proto_t {\n    int (*ioctl)(void *self, uint32_t cmd);\n    void (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data);\n    void (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src);\n    uint32_t (*read_cmd)(void *self, uint8_t cmd, size_t len);\n    void (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest);\n} mp_qspi_proto_t;\n\ntypedef struct _mp_soft_qspi_obj_t {\n    mp_hal_pin_obj_t cs;\n    mp_hal_pin_obj_t clk;\n    mp_hal_pin_obj_t io0;\n    mp_hal_pin_obj_t io1;\n    mp_hal_pin_obj_t io2;\n    mp_hal_pin_obj_t io3;\n} mp_soft_qspi_obj_t;\n\nextern const mp_qspi_proto_t mp_soft_qspi_proto;\n\n#endif // MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H\n"
  },
  {
    "path": "drivers/bus/softqspi.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017-2018 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"drivers/bus/qspi.h\"\n\n#define CS_LOW(self) mp_hal_pin_write(self->cs, 0)\n#define CS_HIGH(self) mp_hal_pin_write(self->cs, 1)\n\n#ifdef MICROPY_HW_SOFTQSPI_SCK_LOW\n\n// Use externally provided functions for SCK control and IO reading\n#define SCK_LOW(self) MICROPY_HW_SOFTQSPI_SCK_LOW(self)\n#define SCK_HIGH(self) MICROPY_HW_SOFTQSPI_SCK_HIGH(self)\n#define NIBBLE_READ(self) MICROPY_HW_SOFTQSPI_NIBBLE_READ(self)\n\n#else\n\n// Use generic pin functions for SCK control and IO reading\n#define SCK_LOW(self) mp_hal_pin_write(self->clk, 0)\n#define SCK_HIGH(self) mp_hal_pin_write(self->clk, 1)\n#define NIBBLE_READ(self) ( \\\n    mp_hal_pin_read(self->io0) \\\n    | (mp_hal_pin_read(self->io1) << 1) \\\n    | (mp_hal_pin_read(self->io2) << 2) \\\n    | (mp_hal_pin_read(self->io3) << 3))\n\n#endif\n\nSTATIC void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) {\n    mp_hal_pin_write(self->io0, v & 1);\n    mp_hal_pin_write(self->io1, (v >> 1) & 1);\n    mp_hal_pin_write(self->io2, (v >> 2) & 1);\n    mp_hal_pin_write(self->io3, (v >> 3) & 1);\n}\n\nSTATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) {\n    mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;\n\n    switch (cmd) {\n        case MP_QSPI_IOCTL_INIT:\n            mp_hal_pin_high(self->cs);\n            mp_hal_pin_output(self->cs);\n\n            // Configure pins\n            mp_hal_pin_write(self->clk, 0);\n            mp_hal_pin_output(self->clk);\n            //mp_hal_pin_write(self->clk, 1);\n            mp_hal_pin_output(self->io0);\n            mp_hal_pin_input(self->io1);\n            mp_hal_pin_write(self->io2, 1);\n            mp_hal_pin_output(self->io2);\n            mp_hal_pin_write(self->io3, 1);\n            mp_hal_pin_output(self->io3);\n            break;\n    }\n\n    return 0; // success\n}\n\nSTATIC void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest) {\n    // Will run as fast as possible, limited only by CPU speed and GPIO time\n    mp_hal_pin_input(self->io1);\n    mp_hal_pin_output(self->io0);\n    if (self->io3) {\n        mp_hal_pin_write(self->io2, 1);\n        mp_hal_pin_output(self->io2);\n        mp_hal_pin_write(self->io3, 1);\n        mp_hal_pin_output(self->io3);\n    }\n    if (src) {\n        for (size_t i = 0; i < len; ++i) {\n            uint8_t data_out = src[i];\n            uint8_t data_in = 0;\n            for (int j = 0; j < 8; ++j, data_out <<= 1) {\n                mp_hal_pin_write(self->io0, (data_out >> 7) & 1);\n                mp_hal_pin_write(self->clk, 1);\n                data_in = (data_in << 1) | mp_hal_pin_read(self->io1);\n                mp_hal_pin_write(self->clk, 0);\n            }\n            if (dest != NULL) {\n                dest[i] = data_in;\n            }\n        }\n    } else {\n        for (size_t i = 0; i < len; ++i) {\n            uint8_t data_in = 0;\n            for (int j = 0; j < 8; ++j) {\n                mp_hal_pin_write(self->clk, 1);\n                data_in = (data_in << 1) | mp_hal_pin_read(self->io1);\n                mp_hal_pin_write(self->clk, 0);\n            }\n            if (dest != NULL) {\n                dest[i] = data_in;\n            }\n        }\n    }\n}\n\nSTATIC void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *buf) {\n    // Make all IO lines input\n    mp_hal_pin_input(self->io2);\n    mp_hal_pin_input(self->io3);\n    mp_hal_pin_input(self->io0);\n    mp_hal_pin_input(self->io1);\n\n    // Will run as fast as possible, limited only by CPU speed and GPIO time\n    while (len--) {\n        SCK_HIGH(self);\n        uint8_t data_in = NIBBLE_READ(self);\n        SCK_LOW(self);\n        SCK_HIGH(self);\n        *buf++ = (data_in << 4) | NIBBLE_READ(self);\n        SCK_LOW(self);\n    }\n}\n\nSTATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *buf) {\n    // Make all IO lines output\n    mp_hal_pin_output(self->io2);\n    mp_hal_pin_output(self->io3);\n    mp_hal_pin_output(self->io0);\n    mp_hal_pin_output(self->io1);\n\n    // Will run as fast as possible, limited only by CPU speed and GPIO time\n    for (size_t i = 0; i < len; ++i) {\n        nibble_write(self, buf[i] >> 4);\n        SCK_HIGH(self);\n        SCK_LOW(self);\n\n        nibble_write(self, buf[i]);\n        SCK_HIGH(self);\n        SCK_LOW(self);\n    }\n\n    //mp_hal_pin_input(self->io1);\n}\n\nSTATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {\n    mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;\n    uint32_t cmd_buf = cmd | data << 8;\n    CS_LOW(self);\n    mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, NULL);\n    CS_HIGH(self);\n}\n\nSTATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {\n    mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;\n    uint8_t cmd_buf[4] = {cmd, addr >> 16, addr >> 8, addr};\n    CS_LOW(self);\n    mp_soft_qspi_transfer(self, 4, cmd_buf, NULL);\n    mp_soft_qspi_transfer(self, len, src, NULL);\n    CS_HIGH(self);\n}\n\nSTATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) {\n    mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;\n    uint32_t cmd_buf = cmd;\n    CS_LOW(self);\n    mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, (uint8_t*)&cmd_buf);\n    CS_HIGH(self);\n    return cmd_buf >> 8;\n}\n\nSTATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {\n    mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;\n    uint8_t cmd_buf[7] = {cmd, addr >> 16, addr >> 8, addr};\n    CS_LOW(self);\n    mp_soft_qspi_transfer(self, 1, cmd_buf, NULL);\n    mp_soft_qspi_qwrite(self, 6, &cmd_buf[1]); // 3 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles)\n    mp_soft_qspi_qread(self, len, dest);\n    CS_HIGH(self);\n}\n\nconst mp_qspi_proto_t mp_soft_qspi_proto = {\n    .ioctl = mp_soft_qspi_ioctl,\n    .write_cmd_data = mp_soft_qspi_write_cmd_data,\n    .write_cmd_addr_data = mp_soft_qspi_write_cmd_addr_data,\n    .read_cmd = mp_soft_qspi_read_cmd,\n    .read_cmd_qaddr_qdata = mp_soft_qspi_read_cmd_qaddr_qdata,\n};\n"
  },
  {
    "path": "drivers/bus/softspi.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016-2018 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"drivers/bus/spi.h\"\n\nint mp_soft_spi_ioctl(void *self_in, uint32_t cmd) {\n    mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;\n\n    switch (cmd) {\n        case MP_SPI_IOCTL_INIT:\n            mp_hal_pin_write(self->sck, self->polarity);\n            mp_hal_pin_output(self->sck);\n            mp_hal_pin_output(self->mosi);\n            mp_hal_pin_input(self->miso);\n            break;\n\n        case MP_SPI_IOCTL_DEINIT:\n            break;\n    }\n\n    return 0;\n}\n\nvoid mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) {\n    mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;\n    uint32_t delay_half = self->delay_half;\n\n    // only MSB transfer is implemented\n\n    // If a port defines MICROPY_HW_SOFTSPI_MIN_DELAY, and the configured\n    // delay_half is equal to this value, then the software SPI implementation\n    // will run as fast as possible, limited only by CPU speed and GPIO time.\n    #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY\n    if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {\n        for (size_t i = 0; i < len; ++i) {\n            uint8_t data_out = src[i];\n            uint8_t data_in = 0;\n            for (int j = 0; j < 8; ++j, data_out <<= 1) {\n                mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);\n                mp_hal_pin_write(self->sck, 1 - self->polarity);\n                data_in = (data_in << 1) | mp_hal_pin_read(self->miso);\n                mp_hal_pin_write(self->sck, self->polarity);\n            }\n            if (dest != NULL) {\n                dest[i] = data_in;\n            }\n        }\n        return;\n    }\n    #endif\n\n    for (size_t i = 0; i < len; ++i) {\n        uint8_t data_out = src[i];\n        uint8_t data_in = 0;\n        for (int j = 0; j < 8; ++j, data_out <<= 1) {\n            mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);\n            if (self->phase == 0) {\n                mp_hal_delay_us_fast(delay_half);\n                mp_hal_pin_write(self->sck, 1 - self->polarity);\n            } else {\n                mp_hal_pin_write(self->sck, 1 - self->polarity);\n                mp_hal_delay_us_fast(delay_half);\n            }\n            data_in = (data_in << 1) | mp_hal_pin_read(self->miso);\n            if (self->phase == 0) {\n                mp_hal_delay_us_fast(delay_half);\n                mp_hal_pin_write(self->sck, self->polarity);\n            } else {\n                mp_hal_pin_write(self->sck, self->polarity);\n                mp_hal_delay_us_fast(delay_half);\n            }\n        }\n        if (dest != NULL) {\n            dest[i] = data_in;\n        }\n    }\n}\n\nconst mp_spi_proto_t mp_soft_spi_proto = {\n    .ioctl = mp_soft_spi_ioctl,\n    .transfer = mp_soft_spi_transfer,\n};\n"
  },
  {
    "path": "drivers/bus/spi.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016-2018 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_DRIVERS_BUS_SPI_H\n#define MICROPY_INCLUDED_DRIVERS_BUS_SPI_H\n\n#include \"py/mphal.h\"\n\nenum {\n    MP_SPI_IOCTL_INIT,\n    MP_SPI_IOCTL_DEINIT,\n};\n\ntypedef struct _mp_spi_proto_t {\n    int (*ioctl)(void *self, uint32_t cmd);\n    void (*transfer)(void *self, size_t len, const uint8_t *src, uint8_t *dest);\n} mp_spi_proto_t;\n\ntypedef struct _mp_soft_spi_obj_t {\n    uint32_t delay_half; // microsecond delay for half SCK period\n    uint8_t polarity;\n    uint8_t phase;\n    mp_hal_pin_obj_t sck;\n    mp_hal_pin_obj_t mosi;\n    mp_hal_pin_obj_t miso;\n} mp_soft_spi_obj_t;\n\nextern const mp_spi_proto_t mp_soft_spi_proto;\n\nint mp_soft_spi_ioctl(void *self, uint32_t cmd);\nvoid mp_soft_spi_transfer(void *self, size_t len, const uint8_t *src, uint8_t *dest);\n\n#endif // MICROPY_INCLUDED_DRIVERS_BUS_SPI_H\n"
  },
  {
    "path": "extmod/axtls-include/config.h",
    "content": "/*\n * Automatically generated header file: don't edit\n */\n\n#define HAVE_DOT_CONFIG 1\n#define CONFIG_PLATFORM_LINUX 1\n#undef CONFIG_PLATFORM_CYGWIN\n#undef CONFIG_PLATFORM_WIN32\n\n/*\n * General Configuration\n */\n#define PREFIX \"/usr/local\"\n#undef CONFIG_DEBUG\n#undef CONFIG_STRIP_UNWANTED_SECTIONS\n#undef CONFIG_VISUAL_STUDIO_7_0\n#undef CONFIG_VISUAL_STUDIO_8_0\n#undef CONFIG_VISUAL_STUDIO_10_0\n#define CONFIG_VISUAL_STUDIO_7_0_BASE \"\"\n#define CONFIG_VISUAL_STUDIO_8_0_BASE \"\"\n#define CONFIG_VISUAL_STUDIO_10_0_BASE \"\"\n#define CONFIG_EXTRA_CFLAGS_OPTIONS \"\"\n#define CONFIG_EXTRA_LDFLAGS_OPTIONS \"\"\n\n/*\n * SSL Library\n */\n#undef CONFIG_SSL_SERVER_ONLY\n#undef CONFIG_SSL_CERT_VERIFICATION\n#undef CONFIG_SSL_FULL_MODE\n#define CONFIG_SSL_SKELETON_MODE 1\n#define CONFIG_SSL_ENABLE_SERVER 1\n#define CONFIG_SSL_ENABLE_CLIENT 1\n#undef CONFIG_SSL_DIAGNOSTICS\n#define CONFIG_SSL_PROT_LOW 1\n#undef CONFIG_SSL_PROT_MEDIUM\n#undef CONFIG_SSL_PROT_HIGH\n#define CONFIG_SSL_AES 1\n#define CONFIG_SSL_USE_DEFAULT_KEY 1\n#define CONFIG_SSL_PRIVATE_KEY_LOCATION \"\"\n#define CONFIG_SSL_PRIVATE_KEY_PASSWORD \"\"\n#define CONFIG_SSL_X509_CERT_LOCATION \"\"\n#undef CONFIG_SSL_GENERATE_X509_CERT\n#define CONFIG_SSL_X509_COMMON_NAME \"\"\n#define CONFIG_SSL_X509_ORGANIZATION_NAME \"\"\n#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME \"\"\n#undef CONFIG_SSL_HAS_PEM\n#undef CONFIG_SSL_USE_PKCS12\n#define CONFIG_SSL_EXPIRY_TIME \n#define CONFIG_X509_MAX_CA_CERTS 0\n#define CONFIG_SSL_MAX_CERTS 3\n#undef CONFIG_SSL_CTX_MUTEXING\n#undef CONFIG_USE_DEV_URANDOM\n#undef CONFIG_WIN32_USE_CRYPTO_LIB\n#undef CONFIG_OPENSSL_COMPATIBLE\n#undef CONFIG_PERFORMANCE_TESTING\n#undef CONFIG_SSL_TEST\n#undef CONFIG_AXTLSWRAP\n#undef CONFIG_AXHTTPD\n#undef CONFIG_HTTP_STATIC_BUILD\n#define CONFIG_HTTP_PORT \n#define CONFIG_HTTP_HTTPS_PORT \n#define CONFIG_HTTP_SESSION_CACHE_SIZE \n#define CONFIG_HTTP_WEBROOT \"\"\n#define CONFIG_HTTP_TIMEOUT \n#undef CONFIG_HTTP_HAS_CGI\n#define CONFIG_HTTP_CGI_EXTENSIONS \"\"\n#undef CONFIG_HTTP_ENABLE_LUA\n#define CONFIG_HTTP_LUA_PREFIX \"\"\n#undef CONFIG_HTTP_BUILD_LUA\n#define CONFIG_HTTP_CGI_LAUNCHER \"\"\n#undef CONFIG_HTTP_DIRECTORIES\n#undef CONFIG_HTTP_HAS_AUTHORIZATION\n#undef CONFIG_HTTP_HAS_IPV6\n#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER\n#define CONFIG_HTTP_USER \"\"\n#undef CONFIG_HTTP_VERBOSE\n#undef CONFIG_HTTP_IS_DAEMON\n\n/*\n * Language Bindings\n */\n#undef CONFIG_BINDINGS\n#undef CONFIG_CSHARP_BINDINGS\n#undef CONFIG_VBNET_BINDINGS\n#define CONFIG_DOT_NET_FRAMEWORK_BASE \"\"\n#undef CONFIG_JAVA_BINDINGS\n#define CONFIG_JAVA_HOME \"\"\n#undef CONFIG_PERL_BINDINGS\n#define CONFIG_PERL_CORE \"\"\n#define CONFIG_PERL_LIB \"\"\n#undef CONFIG_LUA_BINDINGS\n#define CONFIG_LUA_CORE \"\"\n\n/*\n * Samples\n */\n#undef CONFIG_SAMPLES\n#undef CONFIG_C_SAMPLES\n#undef CONFIG_CSHARP_SAMPLES\n#undef CONFIG_VBNET_SAMPLES\n#undef CONFIG_JAVA_SAMPLES\n#undef CONFIG_PERL_SAMPLES\n#undef CONFIG_LUA_SAMPLES\n#undef CONFIG_BIGINT_CLASSICAL\n#undef CONFIG_BIGINT_MONTGOMERY\n#undef CONFIG_BIGINT_BARRETT\n#undef CONFIG_BIGINT_CRT\n#undef CONFIG_BIGINT_KARATSUBA\n#define MUL_KARATSUBA_THRESH \n#define SQU_KARATSUBA_THRESH \n#undef CONFIG_BIGINT_SLIDING_WINDOW\n#undef CONFIG_BIGINT_SQUARE\n#undef CONFIG_BIGINT_CHECK_ON\n#undef CONFIG_INTEGER_32BIT\n#undef CONFIG_INTEGER_16BIT\n#undef CONFIG_INTEGER_8BIT\n"
  },
  {
    "path": "extmod/axtls-include/version.h",
    "content": "#define AXTLS_VERSION    \"(no version)\"\n"
  },
  {
    "path": "extmod/crypto-algorithms/sha256.c",
    "content": "/*********************************************************************\n* Source:     https://github.com/B-Con/crypto-algorithms\n* Filename:   sha256.c\n* Author:     Brad Conte (brad AT bradconte.com)\n* Copyright:  This code is released into the public domain.\n* Disclaimer: This code is presented \"as is\" without any guarantees.\n* Details:    Implementation of the SHA-256 hashing algorithm.\n              SHA-256 is one of the three algorithms in the SHA2\n              specification. The others, SHA-384 and SHA-512, are not\n              offered in this implementation.\n              Algorithm specification can be found here:\n               * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf\n              This implementation uses little endian byte order.\n*********************************************************************/\n\n/*************************** HEADER FILES ***************************/\n#include <stdlib.h>\n#include \"sha256.h\"\n\n/****************************** MACROS ******************************/\n#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))\n#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))\n\n#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))\n#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))\n#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))\n#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))\n#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))\n#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))\n\n/**************************** VARIABLES *****************************/\nstatic const WORD k[64] = {\n\t0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n\t0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n\t0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n\t0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n\t0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n\t0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n\t0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n\t0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2\n};\n\n/*********************** FUNCTION DEFINITIONS ***********************/\nstatic void sha256_transform(CRYAL_SHA256_CTX *ctx, const BYTE data[])\n{\n\tWORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];\n\n\tfor (i = 0, j = 0; i < 16; ++i, j += 4)\n\t\tm[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);\n\tfor ( ; i < 64; ++i)\n\t\tm[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];\n\n\ta = ctx->state[0];\n\tb = ctx->state[1];\n\tc = ctx->state[2];\n\td = ctx->state[3];\n\te = ctx->state[4];\n\tf = ctx->state[5];\n\tg = ctx->state[6];\n\th = ctx->state[7];\n\n\tfor (i = 0; i < 64; ++i) {\n\t\tt1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];\n\t\tt2 = EP0(a) + MAJ(a,b,c);\n\t\th = g;\n\t\tg = f;\n\t\tf = e;\n\t\te = d + t1;\n\t\td = c;\n\t\tc = b;\n\t\tb = a;\n\t\ta = t1 + t2;\n\t}\n\n\tctx->state[0] += a;\n\tctx->state[1] += b;\n\tctx->state[2] += c;\n\tctx->state[3] += d;\n\tctx->state[4] += e;\n\tctx->state[5] += f;\n\tctx->state[6] += g;\n\tctx->state[7] += h;\n}\n\nvoid sha256_init(CRYAL_SHA256_CTX *ctx)\n{\n\tctx->datalen = 0;\n\tctx->bitlen = 0;\n\tctx->state[0] = 0x6a09e667;\n\tctx->state[1] = 0xbb67ae85;\n\tctx->state[2] = 0x3c6ef372;\n\tctx->state[3] = 0xa54ff53a;\n\tctx->state[4] = 0x510e527f;\n\tctx->state[5] = 0x9b05688c;\n\tctx->state[6] = 0x1f83d9ab;\n\tctx->state[7] = 0x5be0cd19;\n}\n\nvoid sha256_update(CRYAL_SHA256_CTX *ctx, const BYTE data[], size_t len)\n{\n\tWORD i;\n\n\tfor (i = 0; i < len; ++i) {\n\t\tctx->data[ctx->datalen] = data[i];\n\t\tctx->datalen++;\n\t\tif (ctx->datalen == 64) {\n\t\t\tsha256_transform(ctx, ctx->data);\n\t\t\tctx->bitlen += 512;\n\t\t\tctx->datalen = 0;\n\t\t}\n\t}\n}\n\nvoid sha256_final(CRYAL_SHA256_CTX *ctx, BYTE hash[])\n{\n\tWORD i;\n\n\ti = ctx->datalen;\n\n\t// Pad whatever data is left in the buffer.\n\tif (ctx->datalen < 56) {\n\t\tctx->data[i++] = 0x80;\n\t\twhile (i < 56)\n\t\t\tctx->data[i++] = 0x00;\n\t}\n\telse {\n\t\tctx->data[i++] = 0x80;\n\t\twhile (i < 64)\n\t\t\tctx->data[i++] = 0x00;\n\t\tsha256_transform(ctx, ctx->data);\n\t\tmemset(ctx->data, 0, 56);\n\t}\n\n\t// Append to the padding the total message's length in bits and transform.\n\tctx->bitlen += ctx->datalen * 8;\n\tctx->data[63] = ctx->bitlen;\n\tctx->data[62] = ctx->bitlen >> 8;\n\tctx->data[61] = ctx->bitlen >> 16;\n\tctx->data[60] = ctx->bitlen >> 24;\n\tctx->data[59] = ctx->bitlen >> 32;\n\tctx->data[58] = ctx->bitlen >> 40;\n\tctx->data[57] = ctx->bitlen >> 48;\n\tctx->data[56] = ctx->bitlen >> 56;\n\tsha256_transform(ctx, ctx->data);\n\n\t// Since this implementation uses little endian byte ordering and SHA uses big endian,\n\t// reverse all the bytes when copying the final state to the output hash.\n\tfor (i = 0; i < 4; ++i) {\n\t\thash[i]      = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 4]  = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 8]  = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;\n\t}\n}\n"
  },
  {
    "path": "extmod/crypto-algorithms/sha256.h",
    "content": "/*********************************************************************\n* Source:     https://github.com/B-Con/crypto-algorithms\n* Filename:   sha256.h\n* Author:     Brad Conte (brad AT bradconte.com)\n* Copyright:  This code is released into the public domain.\n* Disclaimer: This code is presented \"as is\" without any guarantees.\n* Details:    Defines the API for the corresponding SHA1 implementation.\n*********************************************************************/\n\n#ifndef SHA256_H\n#define SHA256_H\n\n/*************************** HEADER FILES ***************************/\n#include <stddef.h>\n\n/****************************** MACROS ******************************/\n#define SHA256_BLOCK_SIZE 32            // SHA256 outputs a 32 byte digest\n\n/**************************** DATA TYPES ****************************/\ntypedef unsigned char BYTE;             // 8-bit byte\ntypedef unsigned int  WORD;             // 32-bit word, change to \"long\" for 16-bit machines\n\ntypedef struct {\n\tBYTE data[64];\n\tWORD datalen;\n\tunsigned long long bitlen;\n\tWORD state[8];\n} CRYAL_SHA256_CTX;\n\n/*********************** FUNCTION DECLARATIONS **********************/\nvoid sha256_init(CRYAL_SHA256_CTX *ctx);\nvoid sha256_update(CRYAL_SHA256_CTX *ctx, const BYTE data[], size_t len);\nvoid sha256_final(CRYAL_SHA256_CTX *ctx, BYTE hash[]);\n\n#endif   // SHA256_H\n"
  },
  {
    "path": "extmod/lwip-include/arch/cc.h",
    "content": "#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H\n#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H\n\n#include <stdint.h>\n\n// Generate lwip's internal types from stdint\n\ntypedef uint8_t u8_t;\ntypedef int8_t s8_t;\ntypedef uint16_t u16_t;\ntypedef int16_t s16_t;\ntypedef uint32_t u32_t;\ntypedef int32_t s32_t;\n\ntypedef u32_t mem_ptr_t;\n\n#define U16_F \"hu\"\n#define S16_F \"hd\"\n#define X16_F \"hx\"\n#define U32_F \"u\"\n#define S32_F \"d\"\n#define X32_F \"x\"\n\n#define X8_F  \"02x\"\n#define SZT_F \"u\"\n\n#define BYTE_ORDER LITTLE_ENDIAN\n\n#define LWIP_CHKSUM_ALGORITHM 2\n\n#include <assert.h>\n#define LWIP_PLATFORM_DIAG(x)\n#define LWIP_PLATFORM_ASSERT(x)  { assert(1); }\n\n//#define PACK_STRUCT_FIELD(x) x __attribute__((packed))\n#define PACK_STRUCT_FIELD(x) x\n#define PACK_STRUCT_STRUCT __attribute__((packed))\n#define PACK_STRUCT_BEGIN\n#define PACK_STRUCT_END\n\n#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H\n"
  },
  {
    "path": "extmod/lwip-include/arch/perf.h",
    "content": "#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H\n#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H\n\n#define PERF_START    /* null definition */\n#define PERF_STOP(x)  /* null definition */\n\n#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H\n"
  },
  {
    "path": "extmod/lwip-include/lwipopts.h",
    "content": "#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H\n#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H\n\n#include <py/mpconfig.h>\n#include <py/misc.h>\n#include <py/mphal.h>\n\n// We're running without an OS for this port. We don't provide any services except light protection.\n#define NO_SYS 1\n\n#define SYS_LIGHTWEIGHT_PROT 1\n#include <stdint.h>\ntypedef uint32_t sys_prot_t;\n\n#define TCP_LISTEN_BACKLOG 1\n\n// We'll put these into a proper ifdef once somebody implements an ethernet driver\n#define LWIP_ARP 0\n#define LWIP_ETHERNET 0\n\n#define LWIP_DNS 1\n\n#define LWIP_NETCONN 0\n#define LWIP_SOCKET 0\n\n#ifdef MICROPY_PY_LWIP_SLIP\n#define LWIP_HAVE_SLIPIF 1\n#endif\n\n// For now, we can simply define this as a macro for the timer code. But this function isn't\n// universal and other ports will need to do something else. It may be necessary to move\n// things like this into a port-provided header file.\n#define sys_now mp_hal_ticks_ms\n\n#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H\n"
  },
  {
    "path": "extmod/machine_i2c.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/mperrno.h\"\n#include \"py/mphal.h\"\n#include \"py/runtime.h\"\n#include \"extmod/machine_i2c.h\"\n\n#if MICROPY_PY_MACHINE_I2C\n\ntypedef mp_machine_soft_i2c_obj_t machine_i2c_obj_t;\n\nSTATIC void mp_hal_i2c_delay(machine_i2c_obj_t *self) {\n    // We need to use an accurate delay to get acceptable I2C\n    // speeds (eg 1us should be not much more than 1us).\n    mp_hal_delay_us_fast(self->us_delay);\n}\n\nSTATIC void mp_hal_i2c_scl_low(machine_i2c_obj_t *self) {\n    mp_hal_pin_od_low(self->scl);\n}\n\nSTATIC int mp_hal_i2c_scl_release(machine_i2c_obj_t *self) {\n    uint32_t count = self->us_timeout;\n\n    mp_hal_pin_od_high(self->scl);\n    mp_hal_i2c_delay(self);\n    // For clock stretching, wait for the SCL pin to be released, with timeout.\n    for (; mp_hal_pin_read(self->scl) == 0 && count; --count) {\n        mp_hal_delay_us_fast(1);\n    }\n    if (count == 0) {\n        return -MP_ETIMEDOUT;\n    }\n    return 0; // success\n}\n\nSTATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) {\n    mp_hal_pin_od_low(self->sda);\n}\n\nSTATIC void mp_hal_i2c_sda_release(machine_i2c_obj_t *self) {\n    mp_hal_pin_od_high(self->sda);\n}\n\nSTATIC int mp_hal_i2c_sda_read(machine_i2c_obj_t *self) {\n    return mp_hal_pin_read(self->sda);\n}\n\nSTATIC int mp_hal_i2c_start(machine_i2c_obj_t *self) {\n    mp_hal_i2c_sda_release(self);\n    mp_hal_i2c_delay(self);\n    int ret = mp_hal_i2c_scl_release(self);\n    if (ret != 0) {\n        return ret;\n    }\n    mp_hal_i2c_sda_low(self);\n    mp_hal_i2c_delay(self);\n    return 0; // success\n}\n\nSTATIC int mp_hal_i2c_stop(machine_i2c_obj_t *self) {\n    mp_hal_i2c_delay(self);\n    mp_hal_i2c_sda_low(self);\n    mp_hal_i2c_delay(self);\n    int ret = mp_hal_i2c_scl_release(self);\n    mp_hal_i2c_sda_release(self);\n    mp_hal_i2c_delay(self);\n    return ret;\n}\n\nSTATIC void mp_hal_i2c_init(machine_i2c_obj_t *self, uint32_t freq) {\n    self->us_delay = 500000 / freq;\n    if (self->us_delay == 0) {\n        self->us_delay = 1;\n    }\n    mp_hal_pin_open_drain(self->scl);\n    mp_hal_pin_open_drain(self->sda);\n    mp_hal_i2c_stop(self); // ignore error\n}\n\n// return value:\n//    0 - byte written and ack received\n//    1 - byte written and nack received\n//   <0 - error, with errno being the negative of the return value\nSTATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) {\n    mp_hal_i2c_delay(self);\n    mp_hal_i2c_scl_low(self);\n\n    for (int i = 7; i >= 0; i--) {\n        if ((val >> i) & 1) {\n            mp_hal_i2c_sda_release(self);\n        } else {\n            mp_hal_i2c_sda_low(self);\n        }\n        mp_hal_i2c_delay(self);\n        int ret = mp_hal_i2c_scl_release(self);\n        if (ret != 0) {\n            mp_hal_i2c_sda_release(self);\n            return ret;\n        }\n        mp_hal_i2c_scl_low(self);\n    }\n\n    mp_hal_i2c_sda_release(self);\n    mp_hal_i2c_delay(self);\n    int ret = mp_hal_i2c_scl_release(self);\n    if (ret != 0) {\n        return ret;\n    }\n\n    int ack = mp_hal_i2c_sda_read(self);\n    mp_hal_i2c_delay(self);\n    mp_hal_i2c_scl_low(self);\n\n    return ack;\n}\n\n// return value:\n//    0 - success\n//   <0 - error, with errno being the negative of the return value\nSTATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack) {\n    mp_hal_i2c_delay(self);\n    mp_hal_i2c_scl_low(self);\n    mp_hal_i2c_delay(self);\n\n    uint8_t data = 0;\n    for (int i = 7; i >= 0; i--) {\n        int ret = mp_hal_i2c_scl_release(self);\n        if (ret != 0) {\n            return ret;\n        }\n        data = (data << 1) | mp_hal_i2c_sda_read(self);\n        mp_hal_i2c_scl_low(self);\n        mp_hal_i2c_delay(self);\n    }\n    *val = data;\n\n    // send ack/nack bit\n    if (!nack) {\n        mp_hal_i2c_sda_low(self);\n    }\n    mp_hal_i2c_delay(self);\n    int ret = mp_hal_i2c_scl_release(self);\n    if (ret != 0) {\n        mp_hal_i2c_sda_release(self);\n        return ret;\n    }\n    mp_hal_i2c_scl_low(self);\n    mp_hal_i2c_sda_release(self);\n\n    return 0; // success\n}\n\n// return value:\n//  >=0 - success; for read it's 0, for write it's number of acks received\n//   <0 - error, with errno being the negative of the return value\nint mp_machine_soft_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) {\n    machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;\n\n    // start the I2C transaction\n    int ret = mp_hal_i2c_start(self);\n    if (ret != 0) {\n        return ret;\n    }\n\n    // write the slave address\n    ret = mp_hal_i2c_write_byte(self, (addr << 1) | (flags & MP_MACHINE_I2C_FLAG_READ));\n    if (ret < 0) {\n        return ret;\n    } else if (ret != 0) {\n        // nack received, release the bus cleanly\n        mp_hal_i2c_stop(self);\n        return -MP_ENODEV;\n    }\n\n    int transfer_ret = 0;\n    for (; n--; ++bufs) {\n        size_t len = bufs->len;\n        uint8_t *buf = bufs->buf;\n        if (flags & MP_MACHINE_I2C_FLAG_READ) {\n            // read bytes from the slave into the given buffer(s)\n            while (len--) {\n                ret = mp_hal_i2c_read_byte(self, buf++, (n | len) == 0);\n                if (ret != 0) {\n                    return ret;\n                }\n            }\n        } else {\n            // write bytes from the given buffer(s) to the slave\n            while (len--) {\n                ret = mp_hal_i2c_write_byte(self, *buf++);\n                if (ret < 0) {\n                    return ret;\n                } else if (ret != 0) {\n                    // nack received, stop sending\n                    n = 0;\n                    break;\n                }\n                ++transfer_ret; // count the number of acks\n            }\n        }\n    }\n\n    // finish the I2C transaction\n    if (flags & MP_MACHINE_I2C_FLAG_STOP) {\n        ret = mp_hal_i2c_stop(self);\n        if (ret != 0) {\n            return ret;\n        }\n    }\n\n    return transfer_ret;\n}\n\n/******************************************************************************/\n// Generic helper functions\n\n// For use by ports that require a single buffer of data for a read/write transfer\nint mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) {\n    size_t len;\n    uint8_t *buf;\n    if (n == 1) {\n        // Use given single buffer\n        len = bufs[0].len;\n        buf = bufs[0].buf;\n    } else {\n        // Combine buffers into a single one\n        len = 0;\n        for (size_t i = 0; i < n; ++i) {\n            len += bufs[i].len;\n        }\n        buf = m_new(uint8_t, len);\n        if (!(flags & MP_MACHINE_I2C_FLAG_READ)) {\n            len = 0;\n            for (size_t i = 0; i < n; ++i) {\n                memcpy(buf + len, bufs[i].buf, bufs[i].len);\n                len += bufs[i].len;\n            }\n        }\n    }\n\n    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;\n    int ret = i2c_p->transfer_single(self, addr, len, buf, flags);\n\n    if (n > 1) {\n        if (flags & MP_MACHINE_I2C_FLAG_READ) {\n            // Copy data from single buffer to individual ones\n            len = 0;\n            for (size_t i = 0; i < n; ++i) {\n                memcpy(bufs[i].buf, buf + len, bufs[i].len);\n                len += bufs[i].len;\n            }\n        }\n        m_del(uint8_t, buf, len);\n    }\n\n    return ret;\n}\n\nSTATIC int mp_machine_i2c_readfrom(mp_obj_base_t *self, uint16_t addr, uint8_t *dest, size_t len, bool stop) {\n    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;\n    mp_machine_i2c_buf_t buf = {.len = len, .buf = dest};\n    unsigned int flags = MP_MACHINE_I2C_FLAG_READ | (stop ? MP_MACHINE_I2C_FLAG_STOP : 0);\n    return i2c_p->transfer(self, addr, 1, &buf, flags);\n}\n\nSTATIC int mp_machine_i2c_writeto(mp_obj_base_t *self, uint16_t addr, const uint8_t *src, size_t len, bool stop) {\n    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;\n    mp_machine_i2c_buf_t buf = {.len = len, .buf = (uint8_t*)src};\n    unsigned int flags = stop ? MP_MACHINE_I2C_FLAG_STOP : 0;\n    return i2c_p->transfer(self, addr, 1, &buf, flags);\n}\n\n/******************************************************************************/\n// MicroPython bindings for I2C\n\nSTATIC void machine_i2c_obj_init_helper(machine_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_scl, ARG_sda, ARG_freq, ARG_timeout };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },\n        { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ },\n        { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },\n        { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} },\n    };\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n    self->scl = mp_hal_get_pin_obj(args[ARG_scl].u_obj);\n    self->sda = mp_hal_get_pin_obj(args[ARG_sda].u_obj);\n    self->us_timeout = args[ARG_timeout].u_int;\n    mp_hal_i2c_init(self, args[ARG_freq].u_int);\n}\n\nSTATIC mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    // check the id argument, if given\n    if (n_args > 0) {\n        if (args[0] != MP_OBJ_NEW_SMALL_INT(-1)) {\n            #if defined(MICROPY_PY_MACHINE_I2C_MAKE_NEW)\n            // dispatch to port-specific constructor\n            extern mp_obj_t MICROPY_PY_MACHINE_I2C_MAKE_NEW(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);\n            return MICROPY_PY_MACHINE_I2C_MAKE_NEW(type, n_args, n_kw, args);\n            #else\n            mp_raise_ValueError(\"invalid I2C peripheral\");\n            #endif\n        }\n        --n_args;\n        ++args;\n    }\n\n    // create new soft I2C object\n    machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t);\n    self->base.type = &machine_i2c_type;\n    mp_map_t kw_args;\n    mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);\n    machine_i2c_obj_init_helper(self, n_args, args, &kw_args);\n    return MP_OBJ_FROM_PTR(self);\n}\n\nSTATIC mp_obj_t machine_i2c_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {\n    machine_i2c_obj_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_init_obj, 1, machine_i2c_obj_init);\n\nSTATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) {\n    mp_obj_base_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t list = mp_obj_new_list(0, NULL);\n    // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved\n    for (int addr = 0x08; addr < 0x78; ++addr) {\n        int ret = mp_machine_i2c_writeto(self, addr, NULL, 0, true);\n        if (ret == 0) {\n            mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));\n        }\n    }\n    return list;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_scan_obj, machine_i2c_scan);\n\nSTATIC mp_obj_t machine_i2c_start(mp_obj_t self_in) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in);\n    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;\n    if (i2c_p->start == NULL) {\n        mp_raise_msg(&mp_type_OSError, \"I2C operation not supported\");\n    }\n    int ret = i2c_p->start(self);\n    if (ret != 0) {\n        mp_raise_OSError(-ret);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_start_obj, machine_i2c_start);\n\nSTATIC mp_obj_t machine_i2c_stop(mp_obj_t self_in) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in);\n    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;\n    if (i2c_p->stop == NULL) {\n        mp_raise_msg(&mp_type_OSError, \"I2C operation not supported\");\n    }\n    int ret = i2c_p->stop(self);\n    if (ret != 0) {\n        mp_raise_OSError(-ret);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_stop_obj, machine_i2c_stop);\n\nSTATIC mp_obj_t machine_i2c_readinto(size_t n_args, const mp_obj_t *args) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;\n    if (i2c_p->read == NULL) {\n        mp_raise_msg(&mp_type_OSError, \"I2C operation not supported\");\n    }\n\n    // get the buffer to read into\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);\n\n    // work out if we want to send a nack at the end\n    bool nack = (n_args == 2) ? true : mp_obj_is_true(args[2]);\n\n    // do the read\n    int ret = i2c_p->read(self, bufinfo.buf, bufinfo.len, nack);\n    if (ret != 0) {\n        mp_raise_OSError(-ret);\n    }\n\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readinto_obj, 2, 3, machine_i2c_readinto);\n\nSTATIC mp_obj_t machine_i2c_write(mp_obj_t self_in, mp_obj_t buf_in) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in);\n    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;\n    if (i2c_p->write == NULL) {\n        mp_raise_msg(&mp_type_OSError, \"I2C operation not supported\");\n    }\n\n    // get the buffer to write from\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);\n\n    // do the write\n    int ret = i2c_p->write(self, bufinfo.buf, bufinfo.len);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n\n    // return number of acks received\n    return MP_OBJ_NEW_SMALL_INT(ret);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_write_obj, machine_i2c_write);\n\nSTATIC mp_obj_t machine_i2c_readfrom(size_t n_args, const mp_obj_t *args) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n    mp_int_t addr = mp_obj_get_int(args[1]);\n    vstr_t vstr;\n    vstr_init_len(&vstr, mp_obj_get_int(args[2]));\n    bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);\n    int ret = mp_machine_i2c_readfrom(self, addr, (uint8_t*)vstr.buf, vstr.len, stop);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_obj, 3, 4, machine_i2c_readfrom);\n\nSTATIC mp_obj_t machine_i2c_readfrom_into(size_t n_args, const mp_obj_t *args) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n    mp_int_t addr = mp_obj_get_int(args[1]);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);\n    bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);\n    int ret = mp_machine_i2c_readfrom(self, addr, bufinfo.buf, bufinfo.len, stop);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_into_obj, 3, 4, machine_i2c_readfrom_into);\n\nSTATIC mp_obj_t machine_i2c_writeto(size_t n_args, const mp_obj_t *args) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n    mp_int_t addr = mp_obj_get_int(args[1]);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);\n    bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);\n    int ret = mp_machine_i2c_writeto(self, addr, bufinfo.buf, bufinfo.len, stop);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n    // return number of acks received\n    return MP_OBJ_NEW_SMALL_INT(ret);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writeto_obj, 3, 4, machine_i2c_writeto);\n\nSTATIC mp_obj_t machine_i2c_writevto(size_t n_args, const mp_obj_t *args) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n    mp_int_t addr = mp_obj_get_int(args[1]);\n\n    // Get the list of data buffer(s) to write\n    size_t nitems;\n    const mp_obj_t *items;\n    mp_obj_get_array(args[2], &nitems, (mp_obj_t**)&items);\n\n    // Get the stop argument\n    bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);\n\n    // Extract all buffer data, skipping zero-length buffers\n    size_t alloc = nitems == 0 ? 1 : nitems;\n    size_t nbufs = 0;\n    mp_machine_i2c_buf_t *bufs = mp_local_alloc(alloc * sizeof(mp_machine_i2c_buf_t));\n    for (; nitems--; ++items) {\n        mp_buffer_info_t bufinfo;\n        mp_get_buffer_raise(*items, &bufinfo, MP_BUFFER_READ);\n        if (bufinfo.len > 0) {\n            bufs[nbufs].len = bufinfo.len;\n            bufs[nbufs++].buf = bufinfo.buf;\n        }\n    }\n\n    // Make sure there is at least one buffer, empty if needed\n    if (nbufs == 0) {\n        bufs[0].len = 0;\n        bufs[0].buf = NULL;\n        nbufs = 1;\n    }\n\n    // Do the I2C transfer\n    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;\n    int ret = i2c_p->transfer(self, addr, nbufs, bufs, stop ? MP_MACHINE_I2C_FLAG_STOP : 0);\n    mp_local_free(bufs);\n\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n\n    // Return number of acks received\n    return MP_OBJ_NEW_SMALL_INT(ret);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writevto_obj, 3, 4, machine_i2c_writevto);\n\nSTATIC int read_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, uint8_t *buf, size_t len) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in);\n    uint8_t memaddr_buf[4];\n    size_t memaddr_len = 0;\n    for (int16_t i = addrsize - 8; i >= 0; i -= 8) {\n        memaddr_buf[memaddr_len++] = memaddr >> i;\n    }\n    int ret = mp_machine_i2c_writeto(self, addr, memaddr_buf, memaddr_len, false);\n    if (ret != memaddr_len) {\n        // must generate STOP\n        mp_machine_i2c_writeto(self, addr, NULL, 0, true);\n        return ret;\n    }\n    return mp_machine_i2c_readfrom(self, addr, buf, len, true);\n}\n\nSTATIC int write_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, const uint8_t *buf, size_t len) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in);\n\n    // Create buffer with memory address\n    size_t memaddr_len = 0;\n    uint8_t memaddr_buf[4];\n    for (int16_t i = addrsize - 8; i >= 0; i -= 8) {\n        memaddr_buf[memaddr_len++] = memaddr >> i;\n    }\n\n    // Create partial write buffers\n    mp_machine_i2c_buf_t bufs[2] = {\n        {.len = memaddr_len, .buf = memaddr_buf},\n        {.len = len, .buf = (uint8_t*)buf},\n    };\n\n    // Do I2C transfer\n    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;\n    return i2c_p->transfer(self, addr, 2, bufs, MP_MACHINE_I2C_FLAG_STOP);\n}\n\nSTATIC const mp_arg_t machine_i2c_mem_allowed_args[] = {\n    { MP_QSTR_addr,    MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },\n    { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },\n    { MP_QSTR_arg,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },\n    { MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },\n};\n\nSTATIC mp_obj_t machine_i2c_readfrom_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_addr, ARG_memaddr, ARG_n, ARG_addrsize };\n    mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,\n        MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);\n\n    // create the buffer to store data into\n    vstr_t vstr;\n    vstr_init_len(&vstr, mp_obj_get_int(args[ARG_n].u_obj));\n\n    // do the transfer\n    int ret = read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,\n        args[ARG_addrsize].u_int, (uint8_t*)vstr.buf, vstr.len);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_obj, 1, machine_i2c_readfrom_mem);\n\n\nSTATIC mp_obj_t machine_i2c_readfrom_mem_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize };\n    mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,\n        MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);\n\n    // get the buffer to store data into\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_WRITE);\n\n    // do the transfer\n    int ret = read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,\n        args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_into_obj, 1, machine_i2c_readfrom_mem_into);\n\nSTATIC mp_obj_t machine_i2c_writeto_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize };\n    mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,\n        MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);\n\n    // get the buffer to write the data from\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ);\n\n    // do the transfer\n    int ret = write_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,\n        args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_mem_obj, 1, machine_i2c_writeto_mem);\n\nSTATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_i2c_init_obj) },\n    { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&machine_i2c_scan_obj) },\n\n    // primitive I2C operations\n    { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_i2c_start_obj) },\n    { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_i2c_stop_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&machine_i2c_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&machine_i2c_write_obj) },\n\n    // standard bus operations\n    { MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&machine_i2c_readfrom_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&machine_i2c_readfrom_into_obj) },\n    { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&machine_i2c_writeto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_writevto), MP_ROM_PTR(&machine_i2c_writevto_obj) },\n\n    // memory operations\n    { MP_ROM_QSTR(MP_QSTR_readfrom_mem), MP_ROM_PTR(&machine_i2c_readfrom_mem_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readfrom_mem_into), MP_ROM_PTR(&machine_i2c_readfrom_mem_into_obj) },\n    { MP_ROM_QSTR(MP_QSTR_writeto_mem), MP_ROM_PTR(&machine_i2c_writeto_mem_obj) },\n};\n\nMP_DEFINE_CONST_DICT(mp_machine_soft_i2c_locals_dict, machine_i2c_locals_dict_table);\n\nint mp_machine_soft_i2c_read(mp_obj_base_t *self_in, uint8_t *dest, size_t len, bool nack) {\n    machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;\n    while (len--) {\n        int ret = mp_hal_i2c_read_byte(self, dest++, nack && (len == 0));\n        if (ret != 0) {\n            return ret;\n        }\n    }\n    return 0; // success\n}\n\nint mp_machine_soft_i2c_write(mp_obj_base_t *self_in, const uint8_t *src, size_t len) {\n    machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;\n    int num_acks = 0;\n    while (len--) {\n        int ret = mp_hal_i2c_write_byte(self, *src++);\n        if (ret < 0) {\n            return ret;\n        } else if (ret != 0) {\n            // nack received, stop sending\n            break;\n        }\n        ++num_acks;\n    }\n    return num_acks;\n}\n\nSTATIC const mp_machine_i2c_p_t mp_machine_soft_i2c_p = {\n    .start = (int(*)(mp_obj_base_t*))mp_hal_i2c_start,\n    .stop = (int(*)(mp_obj_base_t*))mp_hal_i2c_stop,\n    .read = mp_machine_soft_i2c_read,\n    .write = mp_machine_soft_i2c_write,\n    .transfer = mp_machine_soft_i2c_transfer,\n};\n\nconst mp_obj_type_t machine_i2c_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_I2C,\n    .make_new = machine_i2c_make_new,\n    .protocol = &mp_machine_soft_i2c_p,\n    .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict,\n};\n\n#endif // MICROPY_PY_MACHINE_I2C\n"
  },
  {
    "path": "extmod/machine_i2c.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H\n#define MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H\n\n#include \"py/obj.h\"\n\n#define MP_MACHINE_I2C_FLAG_READ (0x01) // if not set then it's a write\n#define MP_MACHINE_I2C_FLAG_STOP (0x02)\n\ntypedef struct _mp_machine_i2c_buf_t {\n    size_t len;\n    uint8_t *buf;\n} mp_machine_i2c_buf_t;\n\n// I2C protocol\n// the first 4 methods can be NULL, meaning operation is not supported\n// transfer_single only needs to be set if transfer=mp_machine_i2c_transfer_adaptor\ntypedef struct _mp_machine_i2c_p_t {\n    int (*start)(mp_obj_base_t *obj);\n    int (*stop)(mp_obj_base_t *obj);\n    int (*read)(mp_obj_base_t *obj, uint8_t *dest, size_t len, bool nack);\n    int (*write)(mp_obj_base_t *obj, const uint8_t *src, size_t len);\n    int (*transfer)(mp_obj_base_t *obj, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);\n    int (*transfer_single)(mp_obj_base_t *obj, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags);\n} mp_machine_i2c_p_t;\n\ntypedef struct _mp_machine_soft_i2c_obj_t {\n    mp_obj_base_t base;\n    uint32_t us_delay;\n    uint32_t us_timeout;\n    mp_hal_pin_obj_t scl;\n    mp_hal_pin_obj_t sda;\n} mp_machine_soft_i2c_obj_t;\n\nextern const mp_obj_type_t machine_i2c_type;\nextern const mp_obj_dict_t mp_machine_soft_i2c_locals_dict;\n\nint mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);\nint mp_machine_soft_i2c_transfer(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);\n\n#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H\n"
  },
  {
    "path": "extmod/machine_mem.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/runtime.h\"\n#include \"extmod/machine_mem.h\"\n\n#if MICROPY_PY_MACHINE\n\n// If you wish to override the functions for mapping the machine_mem read/write\n// address, then add a #define for MICROPY_MACHINE_MEM_GET_READ_ADDR and/or\n// MICROPY_MACHINE_MEM_GET_WRITE_ADDR in your mpconfigport.h. Since the\n// prototypes are identical, it is allowable for both of the macros to evaluate\n// the to same function.\n//\n// It is expected that the modmachine.c file for a given port will provide the\n// implementations, if the default implementation isn't used.\n\n#if !defined(MICROPY_MACHINE_MEM_GET_READ_ADDR) || !defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR)\nSTATIC uintptr_t machine_mem_get_addr(mp_obj_t addr_o, uint align) {\n    uintptr_t addr = mp_obj_int_get_truncated(addr_o);\n    if ((addr & (align - 1)) != 0) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, \"address %08x is not aligned to %d bytes\", addr, align));\n    }\n    return addr;\n}\n#if !defined(MICROPY_MACHINE_MEM_GET_READ_ADDR)\n#define MICROPY_MACHINE_MEM_GET_READ_ADDR machine_mem_get_addr\n#endif\n#if !defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR)\n#define MICROPY_MACHINE_MEM_GET_WRITE_ADDR machine_mem_get_addr\n#endif\n#endif\n\nSTATIC void machine_mem_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    machine_mem_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<%u-bit memory>\", 8 * self->elem_size);\n}\n\nSTATIC mp_obj_t machine_mem_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {\n    // TODO support slice index to read/write multiple values at once\n    machine_mem_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    if (value == MP_OBJ_NULL) {\n        // delete\n        return MP_OBJ_NULL; // op not supported\n    } else if (value == MP_OBJ_SENTINEL) {\n        // load\n        uintptr_t addr = MICROPY_MACHINE_MEM_GET_READ_ADDR(index, self->elem_size);\n        uint32_t val;\n        switch (self->elem_size) {\n            case 1: val = (*(uint8_t*)addr); break;\n            case 2: val = (*(uint16_t*)addr); break;\n            default: val = (*(uint32_t*)addr); break;\n        }\n        return mp_obj_new_int(val);\n    } else {\n        // store\n        uintptr_t addr = MICROPY_MACHINE_MEM_GET_WRITE_ADDR(index, self->elem_size);\n        uint32_t val = mp_obj_get_int_truncated(value);\n        switch (self->elem_size) {\n            case 1: (*(uint8_t*)addr) = val; break;\n            case 2: (*(uint16_t*)addr) = val; break;\n            default: (*(uint32_t*)addr) = val; break;\n        }\n        return mp_const_none;\n    }\n}\n\nconst mp_obj_type_t machine_mem_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_mem,\n    .print = machine_mem_print,\n    .subscr = machine_mem_subscr,\n};\n\nconst machine_mem_obj_t machine_mem8_obj = {{&machine_mem_type}, 1};\nconst machine_mem_obj_t machine_mem16_obj = {{&machine_mem_type}, 2};\nconst machine_mem_obj_t machine_mem32_obj = {{&machine_mem_type}, 4};\n\n#endif // MICROPY_PY_MACHINE\n"
  },
  {
    "path": "extmod/machine_mem.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H\n#define MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H\n\n#include \"py/obj.h\"\n\ntypedef struct _machine_mem_obj_t {\n    mp_obj_base_t base;\n    unsigned elem_size; // in bytes\n} machine_mem_obj_t;\n\nextern const mp_obj_type_t machine_mem_type;\n\nextern const machine_mem_obj_t machine_mem8_obj;\nextern const machine_mem_obj_t machine_mem16_obj;\nextern const machine_mem_obj_t machine_mem32_obj;\n\n#if defined(MICROPY_MACHINE_MEM_GET_READ_ADDR)\nuintptr_t MICROPY_MACHINE_MEM_GET_READ_ADDR(mp_obj_t addr_o, uint align);\n#endif\n#if defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR)\nuintptr_t MICROPY_MACHINE_MEM_GET_WRITE_ADDR(mp_obj_t addr_o, uint align);\n#endif\n\n#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H\n"
  },
  {
    "path": "extmod/machine_pinbase.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_PY_MACHINE\n\n#include \"py/obj.h\"\n#include \"py/runtime.h\"\n#include \"extmod/virtpin.h\"\n#include \"extmod/machine_pinbase.h\"\n\n// PinBase class\n\n// As this is abstract class, its instance is null.\n// But there should be an instance, as the rest of instance code\n// expects that there will be concrete object for inheritance.\ntypedef struct _mp_pinbase_t {\n    mp_obj_base_t base;\n} mp_pinbase_t;\n\nSTATIC const mp_pinbase_t pinbase_singleton = {\n    .base = { &machine_pinbase_type },\n};\n\nSTATIC mp_obj_t pinbase_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    (void)type;\n    (void)n_args;\n    (void)n_kw;\n    (void)args;\n    return MP_OBJ_FROM_PTR(&pinbase_singleton);\n}\n\nmp_uint_t pinbase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);\nmp_uint_t pinbase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode) {\n    (void)errcode;\n    switch (request) {\n        case MP_PIN_READ: {\n            mp_obj_t dest[2];\n            mp_load_method(obj, MP_QSTR_value, dest);\n            return mp_obj_get_int(mp_call_method_n_kw(0, 0, dest));\n        }\n        case MP_PIN_WRITE: {\n            mp_obj_t dest[3];\n            mp_load_method(obj, MP_QSTR_value, dest);\n            dest[2] = (arg == 0 ? mp_const_false : mp_const_true);\n            mp_call_method_n_kw(1, 0, dest);\n            return 0;\n        }\n    }\n    return -1;\n}\n\nSTATIC const mp_pin_p_t pinbase_pin_p = {\n    .ioctl = pinbase_ioctl,\n};\n\nconst mp_obj_type_t machine_pinbase_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_PinBase,\n    .make_new = pinbase_make_new,\n    .protocol = &pinbase_pin_p,\n};\n\n#endif // MICROPY_PY_MACHINE\n"
  },
  {
    "path": "extmod/machine_pinbase.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H\n#define MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H\n\n#include \"py/obj.h\"\n\nextern const mp_obj_type_t machine_pinbase_type;\n\n#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H\n"
  },
  {
    "path": "extmod/machine_pulse.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/runtime.h\"\n#include \"py/mperrno.h\"\n#include \"extmod/machine_pulse.h\"\n\n#if MICROPY_PY_MACHINE_PULSE\n\nMP_WEAK mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) {\n    mp_uint_t start = mp_hal_ticks_us();\n    while (mp_hal_pin_read(pin) != pulse_level) {\n        if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) {\n            return (mp_uint_t)-2;\n        }\n    }\n    start = mp_hal_ticks_us();\n    while (mp_hal_pin_read(pin) == pulse_level) {\n        if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) {\n            return (mp_uint_t)-1;\n        }\n    }\n    return mp_hal_ticks_us() - start;\n}\n\nSTATIC mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) {\n    mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(args[0]);\n    int level = 0;\n    if (mp_obj_is_true(args[1])) {\n        level = 1;\n    }\n    mp_uint_t timeout_us = 1000000;\n    if (n_args > 2) {\n        timeout_us = mp_obj_get_int(args[2]);\n    }\n    mp_uint_t us = machine_time_pulse_us(pin, level, timeout_us);\n    // May return -1 or -2 in case of timeout\n    return mp_obj_new_int(us);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj, 2, 3, machine_time_pulse_us_);\n\n#endif\n"
  },
  {
    "path": "extmod/machine_pulse.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H\n#define MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H\n\n#include \"py/obj.h\"\n#include \"py/mphal.h\"\n\nmp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us);\n\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj);\n\n#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H\n"
  },
  {
    "path": "extmod/machine_signal.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_PY_MACHINE\n\n#include <string.h>\n\n#include \"py/obj.h\"\n#include \"py/runtime.h\"\n#include \"extmod/virtpin.h\"\n#include \"extmod/machine_signal.h\"\n\n// Signal class\n\ntypedef struct _machine_signal_t {\n    mp_obj_base_t base;\n    mp_obj_t pin;\n    bool invert;\n} machine_signal_t;\n\nSTATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_obj_t pin;\n    bool invert = false;\n\n    #if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW)\n    mp_pin_p_t *pin_p = NULL;\n\n    if (n_args > 0 && mp_obj_is_obj(args[0])) {\n        mp_obj_base_t *pin_base = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n        pin_p = (mp_pin_p_t*)pin_base->type->protocol;\n    }\n\n    if (pin_p == NULL) {\n        // If first argument isn't a Pin-like object, we filter out \"invert\"\n        // from keyword arguments and pass them all to the exported Pin\n        // constructor to create one.\n        mp_obj_t *pin_args = mp_local_alloc((n_args + n_kw * 2) * sizeof(mp_obj_t));\n        memcpy(pin_args, args, n_args * sizeof(mp_obj_t));\n        const mp_obj_t *src = args + n_args;\n        mp_obj_t *dst = pin_args + n_args;\n        mp_obj_t *sig_value = NULL;\n        for (size_t cnt = n_kw; cnt; cnt--) {\n            if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) {\n                invert = mp_obj_is_true(src[1]);\n                n_kw--;\n            } else {\n                *dst++ = *src;\n                *dst++ = src[1];\n            }\n            if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_value)) {\n                // Value is pertained to Signal, so we should invert\n                // it for Pin if needed, and we should do it only when\n                // inversion status is guaranteedly known.\n                sig_value = dst - 1;\n            }\n            src += 2;\n        }\n\n        if (invert && sig_value != NULL) {\n            *sig_value = mp_obj_is_true(*sig_value) ? MP_OBJ_NEW_SMALL_INT(0) : MP_OBJ_NEW_SMALL_INT(1);\n        }\n\n        // Here we pass NULL as a type, hoping that mp_pin_make_new()\n        // will just ignore it as set a concrete type. If not, we'd need\n        // to expose port's \"default\" pin type too.\n        pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args);\n\n        mp_local_free(pin_args);\n    }\n    else\n    #endif\n    // Otherwise there should be 1 or 2 args\n    {\n        if (n_args == 1) {\n            pin = args[0];\n            if (n_kw == 0) {\n            } else if (n_kw == 1 && args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) {\n                invert = mp_obj_is_true(args[2]);\n            } else {\n                goto error;\n            }\n        } else {\n        error:\n            mp_raise_TypeError(NULL);\n        }\n    }\n\n    machine_signal_t *o = m_new_obj(machine_signal_t);\n    o->base.type = type;\n    o->pin = pin;\n    o->invert = invert;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_uint_t signal_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    (void)errcode;\n    machine_signal_t *self = MP_OBJ_TO_PTR(self_in);\n\n    switch (request) {\n        case MP_PIN_READ: {\n            return mp_virtual_pin_read(self->pin) ^ self->invert;\n        }\n        case MP_PIN_WRITE: {\n            mp_virtual_pin_write(self->pin, arg ^ self->invert);\n            return 0;\n        }\n    }\n    return -1;\n}\n\n// fast method for getting/setting signal value\nSTATIC mp_obj_t signal_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n    if (n_args == 0) {\n        // get pin\n        return MP_OBJ_NEW_SMALL_INT(mp_virtual_pin_read(self_in));\n    } else {\n        // set pin\n        mp_virtual_pin_write(self_in, mp_obj_is_true(args[0]));\n        return mp_const_none;\n    }\n}\n\nSTATIC mp_obj_t signal_value(size_t n_args, const mp_obj_t *args) {\n    return signal_call(args[0], n_args - 1, 0, args + 1);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(signal_value_obj, 1, 2, signal_value);\n\nSTATIC mp_obj_t signal_on(mp_obj_t self_in) {\n    mp_virtual_pin_write(self_in, 1);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(signal_on_obj, signal_on);\n\nSTATIC mp_obj_t signal_off(mp_obj_t self_in) {\n    mp_virtual_pin_write(self_in, 0);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(signal_off_obj, signal_off);\n\nSTATIC const mp_rom_map_elem_t signal_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&signal_value_obj) },\n    { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&signal_on_obj) },\n    { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&signal_off_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(signal_locals_dict, signal_locals_dict_table);\n\nSTATIC const mp_pin_p_t signal_pin_p = {\n    .ioctl = signal_ioctl,\n};\n\nconst mp_obj_type_t machine_signal_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_Signal,\n    .make_new = signal_make_new,\n    .call = signal_call,\n    .protocol = &signal_pin_p,\n    .locals_dict = (void*)&signal_locals_dict,\n};\n\n#endif // MICROPY_PY_MACHINE\n"
  },
  {
    "path": "extmod/machine_signal.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_SIGNAL_H\n#define MICROPY_INCLUDED_EXTMOD_MACHINE_SIGNAL_H\n\n#include \"py/obj.h\"\n\nextern const mp_obj_type_t machine_signal_type;\n\n#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_SIGNAL_H\n"
  },
  {
    "path": "extmod/machine_spi.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"extmod/machine_spi.h\"\n\n#if MICROPY_PY_MACHINE_SPI\n\n// if a port didn't define MSB/LSB constants then provide them\n#ifndef MICROPY_PY_MACHINE_SPI_MSB\n#define MICROPY_PY_MACHINE_SPI_MSB (0)\n#define MICROPY_PY_MACHINE_SPI_LSB (1)\n#endif\n\n/******************************************************************************/\n// MicroPython bindings for generic machine.SPI\n\nSTATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);\n\nmp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    // check the id argument, if given\n    if (n_args > 0) {\n        if (args[0] != MP_OBJ_NEW_SMALL_INT(-1)) {\n            #if defined(MICROPY_PY_MACHINE_SPI_MAKE_NEW)\n            // dispatch to port-specific constructor\n            extern mp_obj_t MICROPY_PY_MACHINE_SPI_MAKE_NEW(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);\n            return MICROPY_PY_MACHINE_SPI_MAKE_NEW(type, n_args, n_kw, args);\n            #else\n            mp_raise_ValueError(\"invalid SPI peripheral\");\n            #endif\n        }\n        --n_args;\n        ++args;\n    }\n\n    // software SPI\n    return mp_machine_soft_spi_make_new(type, n_args, n_kw, args);\n}\n\nSTATIC mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {\n    mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n    mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol;\n    spi_p->init(s, n_args - 1, args + 1, kw_args);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_spi_init_obj, 1, machine_spi_init);\n\nSTATIC mp_obj_t machine_spi_deinit(mp_obj_t self) {\n    mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(self);\n    mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol;\n    if (spi_p->deinit != NULL) {\n        spi_p->deinit(s);\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_deinit_obj, machine_spi_deinit);\n\nSTATIC void mp_machine_spi_transfer(mp_obj_t self, size_t len, const void *src, void *dest) {\n    mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(self);\n    mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol;\n    spi_p->transfer(s, len, src, dest);\n}\n\nSTATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) {\n    vstr_t vstr;\n    vstr_init_len(&vstr, mp_obj_get_int(args[1]));\n    memset(vstr.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, vstr.len);\n    mp_machine_spi_transfer(args[0], vstr.len, vstr.buf, vstr.buf);\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read);\n\nSTATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);\n    memset(bufinfo.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len);\n    mp_machine_spi_transfer(args[0], bufinfo.len, bufinfo.buf, bufinfo.buf);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto);\n\nSTATIC mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) {\n    mp_buffer_info_t src;\n    mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);\n    mp_machine_spi_transfer(self, src.len, (const uint8_t*)src.buf, NULL);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write);\n\nSTATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp_obj_t rd_buf) {\n    mp_buffer_info_t src;\n    mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);\n    mp_buffer_info_t dest;\n    mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE);\n    if (src.len != dest.len) {\n        mp_raise_ValueError(\"buffers must be the same length\");\n    }\n    mp_machine_spi_transfer(self, src.len, src.buf, dest.buf);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto);\n\nSTATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_spi_init_obj) },\n    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_spi_deinit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) },\n\n    { MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_MSB) },\n    { MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_LSB) },\n};\n\nMP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table);\n\n/******************************************************************************/\n// Implementation of soft SPI\n\nSTATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {\n    #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY\n    if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {\n        return MICROPY_HW_SOFTSPI_MAX_BAUDRATE;\n    } else\n    #endif\n    {\n        return 500000 / delay_half;\n    }\n}\n\nSTATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) {\n    #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY\n    if (baudrate >= MICROPY_HW_SOFTSPI_MAX_BAUDRATE) {\n        return MICROPY_HW_SOFTSPI_MIN_DELAY;\n    } else\n    #endif\n    {\n        uint32_t delay_half = 500000 / baudrate;\n        // round delay_half up so that: actual_baudrate <= requested_baudrate\n        if (500000 % baudrate != 0) {\n            delay_half += 1;\n        }\n        return delay_half;\n    }\n}\n\nSTATIC void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"SoftSPI(baudrate=%u, polarity=%u, phase=%u,\"\n        \" sck=\" MP_HAL_PIN_FMT \", mosi=\" MP_HAL_PIN_FMT \", miso=\" MP_HAL_PIN_FMT \")\",\n        baudrate_from_delay_half(self->spi.delay_half), self->spi.polarity, self->spi.phase,\n        mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso));\n}\n\nSTATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {\n    enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} },\n        { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },\n        { MP_QSTR_phase,    MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },\n        { MP_QSTR_bits,     MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },\n        { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} },\n        { MP_QSTR_sck,      MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },\n        { MP_QSTR_mosi,     MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },\n        { MP_QSTR_miso,     MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },\n    };\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n\n    // create new object\n    mp_machine_soft_spi_obj_t *self = m_new_obj(mp_machine_soft_spi_obj_t);\n    self->base.type = &mp_machine_soft_spi_type;\n\n    // set parameters\n    self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);\n    self->spi.polarity = args[ARG_polarity].u_int;\n    self->spi.phase = args[ARG_phase].u_int;\n    if (args[ARG_bits].u_int != 8) {\n        mp_raise_ValueError(\"bits must be 8\");\n    }\n    if (args[ARG_firstbit].u_int != MICROPY_PY_MACHINE_SPI_MSB) {\n        mp_raise_ValueError(\"firstbit must be MSB\");\n    }\n    if (args[ARG_sck].u_obj == MP_OBJ_NULL\n        || args[ARG_mosi].u_obj == MP_OBJ_NULL\n        || args[ARG_miso].u_obj == MP_OBJ_NULL) {\n        mp_raise_ValueError(\"must specify all of sck/mosi/miso\");\n    }\n    self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);\n    self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);\n    self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);\n\n    // configure bus\n    mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT);\n\n    return MP_OBJ_FROM_PTR(self);\n}\n\nSTATIC void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;\n\n    enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_sck, ARG_mosi, ARG_miso };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },\n        { MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1} },\n        { MP_QSTR_phase, MP_ARG_INT, {.u_int = -1} },\n        { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },\n        { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },\n        { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },\n    };\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n\n    if (args[ARG_baudrate].u_int != -1) {\n        self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);\n    }\n    if (args[ARG_polarity].u_int != -1) {\n        self->spi.polarity = args[ARG_polarity].u_int;\n    }\n    if (args[ARG_phase].u_int != -1) {\n        self->spi.phase = args[ARG_phase].u_int;\n    }\n    if (args[ARG_sck].u_obj != MP_OBJ_NULL) {\n        self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);\n    }\n    if (args[ARG_mosi].u_obj != MP_OBJ_NULL) {\n        self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);\n    }\n    if (args[ARG_miso].u_obj != MP_OBJ_NULL) {\n        self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);\n    }\n\n    // configure bus\n    mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT);\n}\n\nSTATIC void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {\n    mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;\n    mp_soft_spi_transfer(&self->spi, len, src, dest);\n}\n\nconst mp_machine_spi_p_t mp_machine_soft_spi_p = {\n    .init = mp_machine_soft_spi_init,\n    .deinit = NULL,\n    .transfer = mp_machine_soft_spi_transfer,\n};\n\nconst mp_obj_type_t mp_machine_soft_spi_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_SoftSPI,\n    .print = mp_machine_soft_spi_print,\n    .make_new = mp_machine_spi_make_new, // delegate to master constructor\n    .protocol = &mp_machine_soft_spi_p,\n    .locals_dict = (mp_obj_dict_t*)&mp_machine_spi_locals_dict,\n};\n\n#endif // MICROPY_PY_MACHINE_SPI\n"
  },
  {
    "path": "extmod/machine_spi.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H\n#define MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H\n\n#include \"py/obj.h\"\n#include \"py/mphal.h\"\n#include \"drivers/bus/spi.h\"\n\n// SPI protocol\ntypedef struct _mp_machine_spi_p_t {\n    void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);\n    void (*deinit)(mp_obj_base_t *obj); // can be NULL\n    void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest);\n} mp_machine_spi_p_t;\n\ntypedef struct _mp_machine_soft_spi_obj_t {\n    mp_obj_base_t base;\n    mp_soft_spi_obj_t spi;\n} mp_machine_soft_spi_obj_t;\n\nextern const mp_machine_spi_p_t mp_machine_soft_spi_p;\nextern const mp_obj_type_t mp_machine_soft_spi_type;\nextern const mp_obj_dict_t mp_machine_spi_locals_dict;\n\nmp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);\n\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj);\nMP_DECLARE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj);\n\n#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H\n"
  },
  {
    "path": "extmod/misc.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2016 Damien P. George\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_MISC_H\n#define MICROPY_INCLUDED_EXTMOD_MISC_H\n\n// This file contains cumulative declarations for extmod/ .\n\n#include <stddef.h>\n#include \"py/runtime.h\"\n\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj);\n\n#if MICROPY_PY_OS_DUPTERM\nbool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream);\nuintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags);\nint mp_uos_dupterm_rx_chr(void);\nvoid mp_uos_dupterm_tx_strn(const char *str, size_t len);\nvoid mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc);\n#else\n#define mp_uos_dupterm_tx_strn(s, l)\n#endif\n\n#endif // MICROPY_INCLUDED_EXTMOD_MISC_H\n"
  },
  {
    "path": "extmod/modbtree.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <errno.h> // for declaration of global errno variable\n#include <fcntl.h>\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n\n#if MICROPY_PY_BTREE\n\n#include <db.h>\n#include <../../btree/btree.h>\n\ntypedef struct _mp_obj_btree_t {\n    mp_obj_base_t base;\n    DB *db;\n    mp_obj_t start_key;\n    mp_obj_t end_key;\n    #define FLAG_END_KEY_INCL 1\n    #define FLAG_DESC 2\n    #define FLAG_ITER_TYPE_MASK 0xc0\n    #define FLAG_ITER_KEYS   0x40\n    #define FLAG_ITER_VALUES 0x80\n    #define FLAG_ITER_ITEMS  0xc0\n    byte flags;\n    byte next_flags;\n} mp_obj_btree_t;\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_obj_type_t btree_type;\n#endif\n\n#define CHECK_ERROR(res) \\\n        if (res == RET_ERROR) { \\\n            mp_raise_OSError(errno); \\\n        }\n\nvoid __dbpanic(DB *db) {\n    mp_printf(&mp_plat_print, \"__dbpanic(%p)\\n\", db);\n}\n\nSTATIC mp_obj_btree_t *btree_new(DB *db) {\n    mp_obj_btree_t *o = m_new_obj(mp_obj_btree_t);\n    o->base.type = &btree_type;\n    o->db = db;\n    o->start_key = mp_const_none;\n    o->end_key = mp_const_none;\n    o->next_flags = 0;\n    return o;\n}\n\nSTATIC void btree_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<btree %p>\", self->db);\n}\n\nSTATIC mp_obj_t btree_flush(mp_obj_t self_in) {\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);\n    return MP_OBJ_NEW_SMALL_INT(__bt_sync(self->db, 0));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(btree_flush_obj, btree_flush);\n\nSTATIC mp_obj_t btree_close(mp_obj_t self_in) {\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);\n    return MP_OBJ_NEW_SMALL_INT(__bt_close(self->db));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(btree_close_obj, btree_close);\n\nSTATIC mp_obj_t btree_put(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]);\n    DBT key, val;\n    key.data = (void*)mp_obj_str_get_data(args[1], &key.size);\n    val.data = (void*)mp_obj_str_get_data(args[2], &val.size);\n    return MP_OBJ_NEW_SMALL_INT(__bt_put(self->db, &key, &val, 0));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_put_obj, 3, 4, btree_put);\n\nSTATIC mp_obj_t btree_get(size_t n_args, const mp_obj_t *args) {\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]);\n    DBT key, val;\n    key.data = (void*)mp_obj_str_get_data(args[1], &key.size);\n    int res = __bt_get(self->db, &key, &val, 0);\n    if (res == RET_SPECIAL) {\n        if (n_args > 2) {\n            return args[2];\n        } else {\n            return mp_const_none;\n        }\n    }\n    CHECK_ERROR(res);\n    return mp_obj_new_bytes(val.data, val.size);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_get_obj, 2, 3, btree_get);\n\nSTATIC mp_obj_t btree_seq(size_t n_args, const mp_obj_t *args) {\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]);\n    int flags = MP_OBJ_SMALL_INT_VALUE(args[1]);\n    DBT key, val;\n    if (n_args > 2) {\n        key.data = (void*)mp_obj_str_get_data(args[2], &key.size);\n    }\n\n    int res = __bt_seq(self->db, &key, &val, flags);\n    CHECK_ERROR(res);\n    if (res == RET_SPECIAL) {\n        return mp_const_none;\n    }\n\n    mp_obj_t pair_o = mp_obj_new_tuple(2, NULL);\n    mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(pair_o);\n    pair->items[0] = mp_obj_new_bytes(key.data, key.size);\n    pair->items[1] = mp_obj_new_bytes(val.data, val.size);\n    return pair_o;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_seq_obj, 2, 4, btree_seq);\n\nSTATIC mp_obj_t btree_init_iter(size_t n_args, const mp_obj_t *args, byte type) {\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]);\n    self->next_flags = type;\n    self->start_key = mp_const_none;\n    self->end_key = mp_const_none;\n    if (n_args > 1) {\n        self->start_key = args[1];\n        if (n_args > 2) {\n            self->end_key = args[2];\n            if (n_args > 3) {\n                self->next_flags = type | MP_OBJ_SMALL_INT_VALUE(args[3]);\n            }\n        }\n    }\n    return args[0];\n}\n\nSTATIC mp_obj_t btree_keys(size_t n_args, const mp_obj_t *args) {\n    return btree_init_iter(n_args, args, FLAG_ITER_KEYS);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_keys_obj, 1, 4, btree_keys);\n\nSTATIC mp_obj_t btree_values(size_t n_args, const mp_obj_t *args) {\n    return btree_init_iter(n_args, args, FLAG_ITER_VALUES);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_values_obj, 1, 4, btree_values);\n\nSTATIC mp_obj_t btree_items(size_t n_args, const mp_obj_t *args) {\n    return btree_init_iter(n_args, args, FLAG_ITER_ITEMS);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_items_obj, 1, 4, btree_items);\n\nSTATIC mp_obj_t btree_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {\n    (void)iter_buf;\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->next_flags != 0) {\n        // If we're called immediately after keys(), values(), or items(),\n        // use their setup for iteration.\n        self->flags = self->next_flags;\n        self->next_flags = 0;\n    } else {\n        // Otherwise, iterate over all keys.\n        self->flags = FLAG_ITER_KEYS;\n        self->start_key = mp_const_none;\n        self->end_key = mp_const_none;\n    }\n\n    return self_in;\n}\n\nSTATIC mp_obj_t btree_iternext(mp_obj_t self_in) {\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);\n    DBT key, val;\n    int res;\n    bool desc = self->flags & FLAG_DESC;\n    if (self->start_key != MP_OBJ_NULL) {\n        int flags = R_FIRST;\n        if (self->start_key != mp_const_none) {\n            key.data = (void*)mp_obj_str_get_data(self->start_key, &key.size);\n            flags = R_CURSOR;\n        } else if (desc) {\n            flags = R_LAST;\n        }\n        res = __bt_seq(self->db, &key, &val, flags);\n        self->start_key = MP_OBJ_NULL;\n    } else {\n        res = __bt_seq(self->db, &key, &val, desc ? R_PREV : R_NEXT);\n    }\n\n    if (res == RET_SPECIAL) {\n        return MP_OBJ_STOP_ITERATION;\n    }\n    CHECK_ERROR(res);\n\n    if (self->end_key != mp_const_none) {\n        DBT end_key;\n        end_key.data = (void*)mp_obj_str_get_data(self->end_key, &end_key.size);\n        BTREE *t = self->db->internal;\n        int cmp = t->bt_cmp(&key, &end_key);\n        if (desc) {\n            cmp = -cmp;\n        }\n        if (self->flags & FLAG_END_KEY_INCL) {\n            cmp--;\n        }\n        if (cmp >= 0) {\n            self->end_key = MP_OBJ_NULL;\n            return MP_OBJ_STOP_ITERATION;\n        }\n    }\n\n    switch (self->flags & FLAG_ITER_TYPE_MASK) {\n        case FLAG_ITER_KEYS:\n            return mp_obj_new_bytes(key.data, key.size);\n        case FLAG_ITER_VALUES:\n            return mp_obj_new_bytes(val.data, val.size);\n        default: {\n            mp_obj_t pair_o = mp_obj_new_tuple(2, NULL);\n            mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(pair_o);\n            pair->items[0] = mp_obj_new_bytes(key.data, key.size);\n            pair->items[1] = mp_obj_new_bytes(val.data, val.size);\n            return pair_o;\n        }\n    }\n}\n\nSTATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);\n    if (value == MP_OBJ_NULL) {\n        // delete\n        DBT key;\n        key.data = (void*)mp_obj_str_get_data(index, &key.size);\n        int res = __bt_delete(self->db, &key, 0);\n        if (res == RET_SPECIAL) {\n            nlr_raise(mp_obj_new_exception(&mp_type_KeyError));\n        }\n        CHECK_ERROR(res);\n        return mp_const_none;\n    } else if (value == MP_OBJ_SENTINEL) {\n        // load\n        DBT key, val;\n        key.data = (void*)mp_obj_str_get_data(index, &key.size);\n        int res = __bt_get(self->db, &key, &val, 0);\n        if (res == RET_SPECIAL) {\n            nlr_raise(mp_obj_new_exception(&mp_type_KeyError));\n        }\n        CHECK_ERROR(res);\n        return mp_obj_new_bytes(val.data, val.size);\n    } else {\n        // store\n        DBT key, val;\n        key.data = (void*)mp_obj_str_get_data(index, &key.size);\n        val.data = (void*)mp_obj_str_get_data(value, &val.size);\n        int res = __bt_put(self->db, &key, &val, 0);\n        CHECK_ERROR(res);\n        return mp_const_none;\n    }\n}\n\nSTATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    mp_obj_btree_t *self = MP_OBJ_TO_PTR(lhs_in);\n    switch (op) {\n        case MP_BINARY_OP_CONTAINS: {\n            DBT key, val;\n            key.data = (void*)mp_obj_str_get_data(rhs_in, &key.size);\n            int res = __bt_get(self->db, &key, &val, 0);\n            CHECK_ERROR(res);\n            return mp_obj_new_bool(res != RET_SPECIAL);\n        }\n        default:\n            // op not supported\n            return MP_OBJ_NULL;\n    }\n}\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_rom_map_elem_t btree_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&btree_close_obj) },\n    { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&btree_flush_obj) },\n    { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&btree_get_obj) },\n    { MP_ROM_QSTR(MP_QSTR_put), MP_ROM_PTR(&btree_put_obj) },\n    { MP_ROM_QSTR(MP_QSTR_seq), MP_ROM_PTR(&btree_seq_obj) },\n    { MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&btree_keys_obj) },\n    { MP_ROM_QSTR(MP_QSTR_values), MP_ROM_PTR(&btree_values_obj) },\n    { MP_ROM_QSTR(MP_QSTR_items), MP_ROM_PTR(&btree_items_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table);\n\nSTATIC const mp_obj_type_t btree_type = {\n    { &mp_type_type },\n    // Save on qstr's, reuse same as for module\n    .name = MP_QSTR_btree,\n    .print = btree_print,\n    .getiter = btree_getiter,\n    .iternext = btree_iternext,\n    .binary_op = btree_binary_op,\n    .subscr = btree_subscr,\n    .locals_dict = (void*)&btree_locals_dict,\n};\n#endif\n\nSTATIC const FILEVTABLE btree_stream_fvtable = {\n    mp_stream_posix_read,\n    mp_stream_posix_write,\n    mp_stream_posix_lseek,\n    mp_stream_posix_fsync\n};\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_flags, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },\n        { MP_QSTR_cachesize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },\n        { MP_QSTR_pagesize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },\n        { MP_QSTR_minkeypage, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },\n    };\n\n    // Make sure we got a stream object\n    mp_get_stream_raise(pos_args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);\n\n    struct {\n        mp_arg_val_t flags;\n        mp_arg_val_t cachesize;\n        mp_arg_val_t pagesize;\n        mp_arg_val_t minkeypage;\n    } args;\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,\n        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);\n    BTREEINFO openinfo = {0};\n    openinfo.flags = args.flags.u_int;\n    openinfo.cachesize = args.cachesize.u_int;\n    openinfo.psize = args.pagesize.u_int;\n    openinfo.minkeypage = args.minkeypage.u_int;\n\n    DB *db = __bt_open(MP_OBJ_TO_PTR(pos_args[0]), &btree_stream_fvtable, &openinfo, /*dflags*/0);\n    if (db == NULL) {\n        mp_raise_OSError(errno);\n    }\n    return MP_OBJ_FROM_PTR(btree_new(db));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_btree_open_obj, 1, mod_btree_open);\n\nSTATIC const mp_rom_map_elem_t mp_module_btree_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_btree) },\n    { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_btree_open_obj) },\n    { MP_ROM_QSTR(MP_QSTR_INCL), MP_ROM_INT(FLAG_END_KEY_INCL) },\n    { MP_ROM_QSTR(MP_QSTR_DESC), MP_ROM_INT(FLAG_DESC) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_btree_globals, mp_module_btree_globals_table);\n\nconst mp_obj_module_t mp_module_btree = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_btree_globals,\n};\n#endif\n\n#endif // MICROPY_PY_BTREE\n"
  },
  {
    "path": "extmod/modframebuf.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_FRAMEBUF\n\n#include \"ports/stm32/font_petme128_8x8.h\"\n\ntypedef struct _mp_obj_framebuf_t {\n    mp_obj_base_t base;\n    mp_obj_t buf_obj; // need to store this to prevent GC from reclaiming buf\n    void *buf;\n    uint16_t width, height, stride;\n    uint8_t format;\n} mp_obj_framebuf_t;\n\ntypedef void (*setpixel_t)(const mp_obj_framebuf_t*, int, int, uint32_t);\ntypedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t*, int, int);\ntypedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, int, int, uint32_t);\n\ntypedef struct _mp_framebuf_p_t {\n    setpixel_t setpixel;\n    getpixel_t getpixel;\n    fill_rect_t fill_rect;\n} mp_framebuf_p_t;\n\n// constants for formats\n#define FRAMEBUF_MVLSB    (0)\n#define FRAMEBUF_RGB565   (1)\n#define FRAMEBUF_GS2_HMSB (5)\n#define FRAMEBUF_GS4_HMSB (2)\n#define FRAMEBUF_GS8      (6)\n#define FRAMEBUF_MHLSB    (3)\n#define FRAMEBUF_MHMSB    (4)\n\n// Functions for MHLSB and MHMSB\n\nSTATIC void mono_horiz_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {\n    size_t index = (x + y * fb->stride) >> 3;\n    int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07);\n    ((uint8_t*)fb->buf)[index] = (((uint8_t*)fb->buf)[index] & ~(0x01 << offset)) | ((col != 0) << offset);\n}\n\nSTATIC uint32_t mono_horiz_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {\n    size_t index = (x + y * fb->stride) >> 3;\n    int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07);\n    return (((uint8_t*)fb->buf)[index] >> (offset)) & 0x01;\n}\n\nSTATIC void mono_horiz_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {\n    int reverse = fb->format == FRAMEBUF_MHMSB;\n    int advance = fb->stride >> 3;\n    while (w--) {\n        uint8_t *b = &((uint8_t*)fb->buf)[(x >> 3) + y * advance];\n        int offset = reverse ?  x & 7 : 7 - (x & 7);\n        for (int hh = h; hh; --hh) {\n            *b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);\n            b += advance;\n        }\n        ++x;\n    }\n}\n\n// Functions for MVLSB format\n\nSTATIC void mvlsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {\n    size_t index = (y >> 3) * fb->stride + x;\n    uint8_t offset = y & 0x07;\n    ((uint8_t*)fb->buf)[index] = (((uint8_t*)fb->buf)[index] & ~(0x01 << offset)) | ((col != 0) << offset);\n}\n\nSTATIC uint32_t mvlsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {\n    return (((uint8_t*)fb->buf)[(y >> 3) * fb->stride + x] >> (y & 0x07)) & 0x01;\n}\n\nSTATIC void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {\n    while (h--) {\n        uint8_t *b = &((uint8_t*)fb->buf)[(y >> 3) * fb->stride + x];\n        uint8_t offset = y & 0x07;\n        for (int ww = w; ww; --ww) {\n            *b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);\n            ++b;\n        }\n        ++y;\n    }\n}\n\n// Functions for RGB565 format\n\nSTATIC void rgb565_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {\n    ((uint16_t*)fb->buf)[x + y * fb->stride] = col;\n}\n\nSTATIC uint32_t rgb565_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {\n    return ((uint16_t*)fb->buf)[x + y * fb->stride];\n}\n\nSTATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {\n    uint16_t *b = &((uint16_t*)fb->buf)[x + y * fb->stride];\n    while (h--) {\n        for (int ww = w; ww; --ww) {\n            *b++ = col;\n        }\n        b += fb->stride - w;\n    }\n}\n\n// Functions for GS2_HMSB format\n\nSTATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {\n    uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2];\n    uint8_t shift = (x & 0x3) << 1;\n    uint8_t mask = 0x3 << shift;\n    uint8_t color = (col & 0x3) << shift;\n    *pixel = color | (*pixel & (~mask));\n}\n\nSTATIC uint32_t gs2_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {\n    uint8_t pixel = ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2];\n    uint8_t shift = (x & 0x3) << 1;\n    return (pixel >> shift) & 0x3;\n}\n\nSTATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {\n    for (int xx=x; xx < x+w; xx++) {\n        for (int yy=y; yy < y+h; yy++) {\n            gs2_hmsb_setpixel(fb, xx, yy, col);\n        }\n    }\n}\n\n// Functions for GS4_HMSB format\n\nSTATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {\n    uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1];\n\n    if (x % 2) {\n        *pixel = ((uint8_t)col & 0x0f) | (*pixel & 0xf0);\n    } else {\n        *pixel = ((uint8_t)col << 4) | (*pixel & 0x0f);\n    }\n}\n\nSTATIC uint32_t gs4_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {\n    if (x % 2) {\n        return ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1] & 0x0f;\n    }\n\n    return ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1] >> 4;\n}\n\nSTATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {\n    col &= 0x0f;\n    uint8_t *pixel_pair = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1];\n    uint8_t col_shifted_left = col << 4;\n    uint8_t col_pixel_pair = col_shifted_left | col;\n    int pixel_count_till_next_line = (fb->stride - w) >> 1;\n    bool odd_x = (x % 2 == 1);\n\n    while (h--) {\n        int ww = w;\n\n        if (odd_x && ww > 0) {\n            *pixel_pair = (*pixel_pair & 0xf0) | col;\n            pixel_pair++;\n            ww--;\n        }\n\n        memset(pixel_pair, col_pixel_pair, ww >> 1);\n        pixel_pair += ww >> 1;\n\n        if (ww % 2) {\n            *pixel_pair = col_shifted_left | (*pixel_pair & 0x0f);\n            if (!odd_x) {\n                pixel_pair++;\n            }\n        }\n\n        pixel_pair += pixel_count_till_next_line;\n    }\n}\n\n// Functions for GS8 format\n\nSTATIC void gs8_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {\n    uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)];\n    *pixel = col & 0xff;\n}\n\nSTATIC uint32_t gs8_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {\n    return ((uint8_t*)fb->buf)[(x + y * fb->stride)];\n}\n\nSTATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {\n    uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)];\n    while (h--) {\n        memset(pixel, col, w);\n        pixel += fb->stride;\n    }\n}\n\nSTATIC mp_framebuf_p_t formats[] = {\n    [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect},\n    [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect},\n    [FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect},\n    [FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect},\n    [FRAMEBUF_GS8] = {gs8_setpixel, gs8_getpixel, gs8_fill_rect},\n    [FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},\n    [FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},\n};\n\nstatic inline void setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {\n    formats[fb->format].setpixel(fb, x, y, col);\n}\n\nstatic inline uint32_t getpixel(const mp_obj_framebuf_t *fb, int x, int y) {\n    return formats[fb->format].getpixel(fb, x, y);\n}\n\nSTATIC void fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {\n    if (h < 1 || w < 1 || x + w <= 0 || y + h <= 0 || y >= fb->height || x >= fb->width) {\n        // No operation needed.\n        return;\n    }\n\n    // clip to the framebuffer\n    int xend = MIN(fb->width, x + w);\n    int yend = MIN(fb->height, y + h);\n    x = MAX(x, 0);\n    y = MAX(y, 0);\n\n    formats[fb->format].fill_rect(fb, x, y, xend - x, yend - y, col);\n}\n\nSTATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 4, 5, false);\n\n    mp_obj_framebuf_t *o = m_new_obj(mp_obj_framebuf_t);\n    o->base.type = type;\n    o->buf_obj = args[0];\n\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE);\n    o->buf = bufinfo.buf;\n\n    o->width = mp_obj_get_int(args[1]);\n    o->height = mp_obj_get_int(args[2]);\n    o->format = mp_obj_get_int(args[3]);\n    if (n_args >= 5) {\n        o->stride = mp_obj_get_int(args[4]);\n    } else {\n        o->stride = o->width;\n    }\n\n    switch (o->format) {\n        case FRAMEBUF_MVLSB:\n        case FRAMEBUF_RGB565:\n            break;\n        case FRAMEBUF_MHLSB:\n        case FRAMEBUF_MHMSB:\n            o->stride = (o->stride + 7) & ~7;\n            break;\n        case FRAMEBUF_GS2_HMSB:\n            o->stride = (o->stride + 3) & ~3;\n            break;\n        case FRAMEBUF_GS4_HMSB:\n            o->stride = (o->stride + 1) & ~1;\n            break;\n        case FRAMEBUF_GS8:\n            break;\n        default:\n            mp_raise_ValueError(\"invalid format\");\n    }\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_int_t framebuf_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {\n    (void)flags;\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);\n    bufinfo->buf = self->buf;\n    bufinfo->len = self->stride * self->height * (self->format == FRAMEBUF_RGB565 ? 2 : 1);\n    bufinfo->typecode = 'B'; // view framebuf as bytes\n    return 0;\n}\n\nSTATIC mp_obj_t framebuf_fill(mp_obj_t self_in, mp_obj_t col_in) {\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_int_t col = mp_obj_get_int(col_in);\n    formats[self->format].fill_rect(self, 0, 0, self->width, self->height, col);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(framebuf_fill_obj, framebuf_fill);\n\nSTATIC mp_obj_t framebuf_fill_rect(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_int_t x = mp_obj_get_int(args[1]);\n    mp_int_t y = mp_obj_get_int(args[2]);\n    mp_int_t width = mp_obj_get_int(args[3]);\n    mp_int_t height = mp_obj_get_int(args[4]);\n    mp_int_t col = mp_obj_get_int(args[5]);\n\n    fill_rect(self, x, y, width, height, col);\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_fill_rect_obj, 6, 6, framebuf_fill_rect);\n\nSTATIC mp_obj_t framebuf_pixel(size_t n_args, const mp_obj_t *args) {\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_int_t x = mp_obj_get_int(args[1]);\n    mp_int_t y = mp_obj_get_int(args[2]);\n    if (0 <= x && x < self->width && 0 <= y && y < self->height) {\n        if (n_args == 3) {\n            // get\n            return MP_OBJ_NEW_SMALL_INT(getpixel(self, x, y));\n        } else {\n            // set\n            setpixel(self, x, y, mp_obj_get_int(args[3]));\n        }\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_pixel_obj, 3, 4, framebuf_pixel);\n\nSTATIC mp_obj_t framebuf_hline(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_int_t x = mp_obj_get_int(args[1]);\n    mp_int_t y = mp_obj_get_int(args[2]);\n    mp_int_t w = mp_obj_get_int(args[3]);\n    mp_int_t col = mp_obj_get_int(args[4]);\n\n    fill_rect(self, x, y, w, 1, col);\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_hline_obj, 5, 5, framebuf_hline);\n\nSTATIC mp_obj_t framebuf_vline(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_int_t x = mp_obj_get_int(args[1]);\n    mp_int_t y = mp_obj_get_int(args[2]);\n    mp_int_t h = mp_obj_get_int(args[3]);\n    mp_int_t col = mp_obj_get_int(args[4]);\n\n    fill_rect(self, x, y, 1, h, col);\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_vline_obj, 5, 5, framebuf_vline);\n\nSTATIC mp_obj_t framebuf_rect(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_int_t x = mp_obj_get_int(args[1]);\n    mp_int_t y = mp_obj_get_int(args[2]);\n    mp_int_t w = mp_obj_get_int(args[3]);\n    mp_int_t h = mp_obj_get_int(args[4]);\n    mp_int_t col = mp_obj_get_int(args[5]);\n\n    fill_rect(self, x, y, w, 1, col);\n    fill_rect(self, x, y + h- 1, w, 1, col);\n    fill_rect(self, x, y, 1, h, col);\n    fill_rect(self, x + w- 1, y, 1, h, col);\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_rect_obj, 6, 6, framebuf_rect);\n\nSTATIC mp_obj_t framebuf_line(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_int_t x1 = mp_obj_get_int(args[1]);\n    mp_int_t y1 = mp_obj_get_int(args[2]);\n    mp_int_t x2 = mp_obj_get_int(args[3]);\n    mp_int_t y2 = mp_obj_get_int(args[4]);\n    mp_int_t col = mp_obj_get_int(args[5]);\n\n    mp_int_t dx = x2 - x1;\n    mp_int_t sx;\n    if (dx > 0) {\n        sx = 1;\n    } else {\n        dx = -dx;\n        sx = -1;\n    }\n\n    mp_int_t dy = y2 - y1;\n    mp_int_t sy;\n    if (dy > 0) {\n        sy = 1;\n    } else {\n        dy = -dy;\n        sy = -1;\n    }\n\n    bool steep;\n    if (dy > dx) {\n        mp_int_t temp;\n        temp = x1; x1 = y1; y1 = temp;\n        temp = dx; dx = dy; dy = temp;\n        temp = sx; sx = sy; sy = temp;\n        steep = true;\n    } else {\n        steep = false;\n    }\n\n    mp_int_t e = 2 * dy - dx;\n    for (mp_int_t i = 0; i < dx; ++i) {\n        if (steep) {\n            if (0 <= y1 && y1 < self->width && 0 <= x1 && x1 < self->height) {\n                setpixel(self, y1, x1, col);\n            }\n        } else {\n            if (0 <= x1 && x1 < self->width && 0 <= y1 && y1 < self->height) {\n                setpixel(self, x1, y1, col);\n            }\n        }\n        while (e >= 0) {\n            y1 += sy;\n            e -= 2 * dx;\n        }\n        x1 += sx;\n        e += 2 * dy;\n    }\n\n    if (0 <= x2 && x2 < self->width && 0 <= y2 && y2 < self->height) {\n        setpixel(self, x2, y2, col);\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_line_obj, 6, 6, framebuf_line);\n\nSTATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_obj_framebuf_t *source = MP_OBJ_TO_PTR(args[1]);\n    mp_int_t x = mp_obj_get_int(args[2]);\n    mp_int_t y = mp_obj_get_int(args[3]);\n    mp_int_t key = -1;\n    if (n_args > 4) {\n        key = mp_obj_get_int(args[4]);\n    }\n\n    if (\n        (x >= self->width) ||\n        (y >= self->height) ||\n        (-x >= source->width) ||\n        (-y >= source->height)\n    ) {\n        // Out of bounds, no-op.\n        return mp_const_none;\n    }\n\n    // Clip.\n    int x0 = MAX(0, x);\n    int y0 = MAX(0, y);\n    int x1 = MAX(0, -x);\n    int y1 = MAX(0, -y);\n    int x0end = MIN(self->width, x + source->width);\n    int y0end = MIN(self->height, y + source->height);\n\n    for (; y0 < y0end; ++y0) {\n        int cx1 = x1;\n        for (int cx0 = x0; cx0 < x0end; ++cx0) {\n            uint32_t col = getpixel(source, cx1, y1);\n            if (col != (uint32_t)key) {\n                setpixel(self, cx0, y0, col);\n            }\n            ++cx1;\n        }\n        ++y1;\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 5, framebuf_blit);\n\nSTATIC mp_obj_t framebuf_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) {\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_int_t xstep = mp_obj_get_int(xstep_in);\n    mp_int_t ystep = mp_obj_get_int(ystep_in);\n    int sx, y, xend, yend, dx, dy;\n    if (xstep < 0) {\n        sx = 0;\n        xend = self->width + xstep;\n        dx = 1;\n    } else {\n        sx = self->width - 1;\n        xend = xstep - 1;\n        dx = -1;\n    }\n    if (ystep < 0) {\n        y = 0;\n        yend = self->height + ystep;\n        dy = 1;\n    } else {\n        y = self->height - 1;\n        yend = ystep - 1;\n        dy = -1;\n    }\n    for (; y != yend; y += dy) {\n        for (int x = sx; x != xend; x += dx) {\n            setpixel(self, x, y, getpixel(self, x - xstep, y - ystep));\n        }\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_3(framebuf_scroll_obj, framebuf_scroll);\n\nSTATIC mp_obj_t framebuf_text(size_t n_args, const mp_obj_t *args) {\n    // extract arguments\n    mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);\n    const char *str = mp_obj_str_get_str(args[1]);\n    mp_int_t x0 = mp_obj_get_int(args[2]);\n    mp_int_t y0 = mp_obj_get_int(args[3]);\n    mp_int_t col = 1;\n    if (n_args >= 5) {\n        col = mp_obj_get_int(args[4]);\n    }\n\n    // loop over chars\n    for (; *str; ++str) {\n        // get char and make sure its in range of font\n        int chr = *(uint8_t*)str;\n        if (chr < 32 || chr > 127) {\n            chr = 127;\n        }\n        // get char data\n        const uint8_t *chr_data = &font_petme128_8x8[(chr - 32) * 8];\n        // loop over char data\n        for (int j = 0; j < 8; j++, x0++) {\n            if (0 <= x0 && x0 < self->width) { // clip x\n                uint vline_data = chr_data[j]; // each byte is a column of 8 pixels, LSB at top\n                for (int y = y0; vline_data; vline_data >>= 1, y++) { // scan over vertical column\n                    if (vline_data & 1) { // only draw if pixel set\n                        if (0 <= y && y < self->height) { // clip y\n                            setpixel(self, x0, y, col);\n                        }\n                    }\n                }\n            }\n        }\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_text_obj, 4, 5, framebuf_text);\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_rom_map_elem_t framebuf_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&framebuf_fill_obj) },\n    { MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&framebuf_fill_rect_obj) },\n    { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&framebuf_pixel_obj) },\n    { MP_ROM_QSTR(MP_QSTR_hline), MP_ROM_PTR(&framebuf_hline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_vline), MP_ROM_PTR(&framebuf_vline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&framebuf_rect_obj) },\n    { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&framebuf_line_obj) },\n    { MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&framebuf_blit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_scroll), MP_ROM_PTR(&framebuf_scroll_obj) },\n    { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&framebuf_text_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table);\n\nSTATIC const mp_obj_type_t mp_type_framebuf = {\n    { &mp_type_type },\n    .name = MP_QSTR_FrameBuffer,\n    .make_new = framebuf_make_new,\n    .buffer_p = { .get_buffer = framebuf_get_buffer },\n    .locals_dict = (mp_obj_dict_t*)&framebuf_locals_dict,\n};\n#endif\n\n// this factory function is provided for backwards compatibility with old FrameBuffer1 class\nSTATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args) {\n    mp_obj_framebuf_t *o = m_new_obj(mp_obj_framebuf_t);\n    o->base.type = &mp_type_framebuf;\n\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE);\n    o->buf = bufinfo.buf;\n\n    o->width = mp_obj_get_int(args[1]);\n    o->height = mp_obj_get_int(args[2]);\n    o->format = FRAMEBUF_MVLSB;\n    if (n_args >= 4) {\n        o->stride = mp_obj_get_int(args[3]);\n    } else {\n        o->stride = o->width;\n    }\n\n    return MP_OBJ_FROM_PTR(o);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(legacy_framebuffer1_obj, 3, 4, legacy_framebuffer1);\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_framebuf) },\n    { MP_ROM_QSTR(MP_QSTR_FrameBuffer), MP_ROM_PTR(&mp_type_framebuf) },\n    { MP_ROM_QSTR(MP_QSTR_FrameBuffer1), MP_ROM_PTR(&legacy_framebuffer1_obj) },\n    { MP_ROM_QSTR(MP_QSTR_MVLSB), MP_ROM_INT(FRAMEBUF_MVLSB) },\n    { MP_ROM_QSTR(MP_QSTR_MONO_VLSB), MP_ROM_INT(FRAMEBUF_MVLSB) },\n    { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) },\n    { MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) },\n    { MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) },\n    { MP_ROM_QSTR(MP_QSTR_GS8), MP_ROM_INT(FRAMEBUF_GS8) },\n    { MP_ROM_QSTR(MP_QSTR_MONO_HLSB), MP_ROM_INT(FRAMEBUF_MHLSB) },\n    { MP_ROM_QSTR(MP_QSTR_MONO_HMSB), MP_ROM_INT(FRAMEBUF_MHMSB) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(framebuf_module_globals, framebuf_module_globals_table);\n\nconst mp_obj_module_t mp_module_framebuf = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&framebuf_module_globals,\n};\n#endif\n\n#endif // MICROPY_PY_FRAMEBUF\n"
  },
  {
    "path": "extmod/modonewire.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n\n#include \"py/obj.h\"\n#include \"py/mphal.h\"\n\n/******************************************************************************/\n// Low-level 1-Wire routines\n\n#define TIMING_RESET1 (480)\n#define TIMING_RESET2 (70)\n#define TIMING_RESET3 (410)\n#define TIMING_READ1 (5)\n#define TIMING_READ2 (5)\n#define TIMING_READ3 (40)\n#define TIMING_WRITE1 (10)\n#define TIMING_WRITE2 (50)\n#define TIMING_WRITE3 (10)\n\nSTATIC int onewire_bus_reset(mp_hal_pin_obj_t pin) {\n    mp_hal_pin_write(pin, 0);\n    mp_hal_delay_us(TIMING_RESET1);\n    uint32_t i = mp_hal_quiet_timing_enter();\n    mp_hal_pin_write(pin, 1);\n    mp_hal_delay_us_fast(TIMING_RESET2);\n    int status = !mp_hal_pin_read(pin);\n    mp_hal_quiet_timing_exit(i);\n    mp_hal_delay_us(TIMING_RESET3);\n    return status;\n}\n\nSTATIC int onewire_bus_readbit(mp_hal_pin_obj_t pin) {\n    mp_hal_pin_write(pin, 1);\n    uint32_t i = mp_hal_quiet_timing_enter();\n    mp_hal_pin_write(pin, 0);\n    mp_hal_delay_us_fast(TIMING_READ1);\n    mp_hal_pin_write(pin, 1);\n    mp_hal_delay_us_fast(TIMING_READ2);\n    int value = mp_hal_pin_read(pin);\n    mp_hal_quiet_timing_exit(i);\n    mp_hal_delay_us_fast(TIMING_READ3);\n    return value;\n}\n\nSTATIC void onewire_bus_writebit(mp_hal_pin_obj_t pin, int value) {\n    uint32_t i = mp_hal_quiet_timing_enter();\n    mp_hal_pin_write(pin, 0);\n    mp_hal_delay_us_fast(TIMING_WRITE1);\n    if (value) {\n        mp_hal_pin_write(pin, 1);\n    }\n    mp_hal_delay_us_fast(TIMING_WRITE2);\n    mp_hal_pin_write(pin, 1);\n    mp_hal_delay_us_fast(TIMING_WRITE3);\n    mp_hal_quiet_timing_exit(i);\n}\n\n/******************************************************************************/\n// MicroPython bindings\n\nSTATIC mp_obj_t onewire_reset(mp_obj_t pin_in) {\n    return mp_obj_new_bool(onewire_bus_reset(mp_hal_get_pin_obj(pin_in)));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_reset_obj, onewire_reset);\n\nSTATIC mp_obj_t onewire_readbit(mp_obj_t pin_in) {\n    return MP_OBJ_NEW_SMALL_INT(onewire_bus_readbit(mp_hal_get_pin_obj(pin_in)));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_readbit_obj, onewire_readbit);\n\nSTATIC mp_obj_t onewire_readbyte(mp_obj_t pin_in) {\n    mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(pin_in);\n    uint8_t value = 0;\n    for (int i = 0; i < 8; ++i) {\n        value |= onewire_bus_readbit(pin) << i;\n    }\n    return MP_OBJ_NEW_SMALL_INT(value);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_readbyte_obj, onewire_readbyte);\n\nSTATIC mp_obj_t onewire_writebit(mp_obj_t pin_in, mp_obj_t value_in) {\n    onewire_bus_writebit(mp_hal_get_pin_obj(pin_in), mp_obj_get_int(value_in));\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(onewire_writebit_obj, onewire_writebit);\n\nSTATIC mp_obj_t onewire_writebyte(mp_obj_t pin_in, mp_obj_t value_in) {\n    mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(pin_in);\n    int value = mp_obj_get_int(value_in);\n    for (int i = 0; i < 8; ++i) {\n        onewire_bus_writebit(pin, value & 1);\n        value >>= 1;\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(onewire_writebyte_obj, onewire_writebyte);\n\nSTATIC mp_obj_t onewire_crc8(mp_obj_t data) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);\n    uint8_t crc = 0;\n    for (size_t i = 0; i < bufinfo.len; ++i) {\n        uint8_t byte = ((uint8_t*)bufinfo.buf)[i];\n        for (int b = 0; b < 8; ++b) {\n            uint8_t fb_bit = (crc ^ byte) & 0x01;\n            if (fb_bit == 0x01) {\n                crc = crc ^ 0x18;\n            }\n            crc = (crc >> 1) & 0x7f;\n            if (fb_bit == 0x01) {\n                crc = crc | 0x80;\n            }\n            byte = byte >> 1;\n        }\n    }\n    return MP_OBJ_NEW_SMALL_INT(crc);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_crc8_obj, onewire_crc8);\n\nSTATIC const mp_rom_map_elem_t onewire_module_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_onewire) },\n\n    { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&onewire_reset_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readbit), MP_ROM_PTR(&onewire_readbit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readbyte), MP_ROM_PTR(&onewire_readbyte_obj) },\n    { MP_ROM_QSTR(MP_QSTR_writebit), MP_ROM_PTR(&onewire_writebit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_writebyte), MP_ROM_PTR(&onewire_writebyte_obj) },\n    { MP_ROM_QSTR(MP_QSTR_crc8), MP_ROM_PTR(&onewire_crc8_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(onewire_module_globals, onewire_module_globals_table);\n\nconst mp_obj_module_t mp_module_onewire = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&onewire_module_globals,\n};\n"
  },
  {
    "path": "extmod/modubinascii.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <assert.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/binary.h\"\n#include \"extmod/modubinascii.h\"\n\nmp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) {\n    // Second argument is for an extension to allow a separator to be used\n    // between values.\n    const char *sep = NULL;\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);\n\n    // Code below assumes non-zero buffer length when computing size with\n    // separator, so handle the zero-length case here.\n    if (bufinfo.len == 0) {\n        return mp_const_empty_bytes;\n    }\n\n    vstr_t vstr;\n    size_t out_len = bufinfo.len * 2;\n    if (n_args > 1) {\n        // 1-char separator between hex numbers\n        out_len += bufinfo.len - 1;\n        sep = mp_obj_str_get_str(args[1]);\n    }\n    vstr_init_len(&vstr, out_len);\n    byte *in = bufinfo.buf, *out = (byte*)vstr.buf;\n    for (mp_uint_t i = bufinfo.len; i--;) {\n        byte d = (*in >> 4);\n        if (d > 9) {\n            d += 'a' - '9' - 1;\n        }\n        *out++ = d + '0';\n        d = (*in++ & 0xf);\n        if (d > 9) {\n            d += 'a' - '9' - 1;\n        }\n        *out++ = d + '0';\n        if (sep != NULL && i != 0) {\n            *out++ = *sep;\n        }\n    }\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj, 1, 2, mod_binascii_hexlify);\n\nmp_obj_t mod_binascii_unhexlify(mp_obj_t data) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);\n\n    if ((bufinfo.len & 1) != 0) {\n        mp_raise_ValueError(\"odd-length string\");\n    }\n    vstr_t vstr;\n    vstr_init_len(&vstr, bufinfo.len / 2);\n    byte *in = bufinfo.buf, *out = (byte*)vstr.buf;\n    byte hex_byte = 0;\n    for (mp_uint_t i = bufinfo.len; i--;) {\n        byte hex_ch = *in++;\n        if (unichar_isxdigit(hex_ch)) {\n            hex_byte += unichar_xdigit_value(hex_ch);\n        } else {\n            mp_raise_ValueError(\"non-hex digit found\");\n        }\n        if (i & 1) {\n            hex_byte <<= 4;\n        } else {\n            *out++ = hex_byte;\n            hex_byte = 0;\n        }\n    }\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj, mod_binascii_unhexlify);\n\n// If ch is a character in the base64 alphabet, and is not a pad character, then\n// the corresponding integer between 0 and 63, inclusively, is returned.\n// Otherwise, -1 is returned.\nstatic int mod_binascii_sextet(byte ch) {\n    if (ch >= 'A' && ch <= 'Z') {\n        return ch - 'A';\n    } else if (ch >= 'a' && ch <= 'z') {\n        return ch - 'a' + 26;\n    } else if (ch >= '0' && ch <= '9') {\n        return ch - '0' + 52;\n    } else if (ch == '+') {\n        return 62;\n    } else if (ch == '/') {\n        return 63;\n    } else {\n        return -1;\n    }\n}\n\nmp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);\n    byte *in = bufinfo.buf;\n\n    vstr_t vstr;\n    vstr_init(&vstr, (bufinfo.len / 4) * 3 + 1); // Potentially over-allocate\n    byte *out = (byte *)vstr.buf;\n\n    uint shift = 0;\n    int nbits = 0; // Number of meaningful bits in shift\n    bool hadpad = false; // Had a pad character since last valid character\n    for (size_t i = 0; i < bufinfo.len; i++) {\n        if (in[i] == '=') {\n            if ((nbits == 2) || ((nbits == 4) && hadpad)) {\n                nbits = 0;\n                break;\n            }\n            hadpad = true;\n        }\n\n        int sextet = mod_binascii_sextet(in[i]);\n        if (sextet == -1) {\n            continue;\n        }\n        hadpad = false;\n        shift = (shift << 6) | sextet;\n        nbits += 6;\n\n        if (nbits >= 8) {\n            nbits -= 8;\n            out[vstr.len++] = (shift >> nbits) & 0xFF;\n        }\n    }\n\n    if (nbits) {\n        mp_raise_ValueError(\"incorrect padding\");\n    }\n\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64);\n\nmp_obj_t mod_binascii_b2a_base64(mp_obj_t data) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);\n\n    vstr_t vstr;\n    vstr_init_len(&vstr, ((bufinfo.len != 0) ? (((bufinfo.len - 1) / 3) + 1) * 4 : 0) + 1);\n\n    // First pass, we convert input buffer to numeric base 64 values\n    byte *in = bufinfo.buf, *out = (byte*)vstr.buf;\n    mp_uint_t i;\n    for (i = bufinfo.len; i >= 3; i -= 3) {\n        *out++ = (in[0] & 0xFC) >> 2;\n        *out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4;\n        *out++ = (in[1] & 0x0F) << 2 | (in[2] & 0xC0) >> 6;\n        *out++ = in[2] & 0x3F;\n        in += 3;\n    }\n    if (i != 0) {\n        *out++ = (in[0] & 0xFC) >> 2;\n        if (i == 2) {\n            *out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4;\n            *out++ = (in[1] & 0x0F) << 2;\n        }\n        else {\n            *out++ = (in[0] & 0x03) << 4;\n            *out++ = 64;\n        }\n        *out = 64;\n    }\n\n    // Second pass, we convert number base 64 values to actual base64 ascii encoding\n    out = (byte*)vstr.buf;\n    for (mp_uint_t j = vstr.len - 1; j--;) {\n        if (*out < 26) {\n            *out += 'A';\n        } else if (*out < 52) {\n            *out += 'a' - 26;\n        } else if (*out < 62) {\n            *out += '0' - 52;\n        } else if (*out == 62) {\n            *out ='+';\n        } else if (*out == 63) {\n            *out = '/';\n        } else {\n            *out = '=';\n        }\n        out++;\n    }\n    *out = '\\n';\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64);\n\n#if MICROPY_PY_UBINASCII_CRC32\n#include \"uzlib/tinf.h\"\n\nmp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);\n    uint32_t crc = (n_args > 1) ? mp_obj_get_int_truncated(args[1]) : 0;\n    crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);\n    return mp_obj_new_int_from_uint(crc ^ 0xffffffff);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32);\n#endif\n\n#if MICROPY_PY_UBINASCII\n\nSTATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubinascii) },\n    { MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&mod_binascii_hexlify_obj) },\n    { MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&mod_binascii_unhexlify_obj) },\n    { MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) },\n    { MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) },\n    #if MICROPY_PY_UBINASCII_CRC32\n    { MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_binascii_crc32_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table);\n\nconst mp_obj_module_t mp_module_ubinascii = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_binascii_globals,\n};\n\n#endif //MICROPY_PY_UBINASCII\n"
  },
  {
    "path": "extmod/modubinascii.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_MODUBINASCII_H\n#define MICROPY_INCLUDED_EXTMOD_MODUBINASCII_H\n\nextern mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args);\nextern mp_obj_t mod_binascii_unhexlify(mp_obj_t data);\nextern mp_obj_t mod_binascii_a2b_base64(mp_obj_t data);\nextern mp_obj_t mod_binascii_b2a_base64(mp_obj_t data);\nextern mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args);\n\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj);\n\n#endif // MICROPY_INCLUDED_EXTMOD_MODUBINASCII_H\n"
  },
  {
    "path": "extmod/moducryptolib.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017-2018 Paul Sokolovsky\n * Copyright (c) 2018 Yonatan Goldschmidt\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_PY_UCRYPTOLIB\n\n#include <assert.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n\n// This module implements crypto ciphers API, roughly following\n// https://www.python.org/dev/peps/pep-0272/ . Exact implementation\n// of PEP 272 can be made with a simple wrapper which adds all the\n// needed boilerplate.\n\n// values follow PEP 272\nenum {\n    UCRYPTOLIB_MODE_ECB = 1,\n    UCRYPTOLIB_MODE_CBC = 2,\n    UCRYPTOLIB_MODE_CTR = 6,\n};\n\nstruct ctr_params {\n    // counter is the IV of the AES context.\n\n    size_t offset; // in encrypted_counter\n    // encrypted counter\n    uint8_t encrypted_counter[16];\n};\n\n#if MICROPY_SSL_AXTLS\n#include \"lib/axtls/crypto/crypto.h\"\n\n#define AES_CTX_IMPL AES_CTX\n#endif\n\n#if MICROPY_SSL_MBEDTLS\n#include <mbedtls/aes.h>\n\n// we can't run mbedtls AES key schedule until we know whether we're used for encrypt or decrypt.\n// therefore, we store the key & keysize and on the first call to encrypt/decrypt we override them\n// with the mbedtls_aes_context, as they are not longer required. (this is done to save space)\nstruct mbedtls_aes_ctx_with_key {\n    union {\n        mbedtls_aes_context mbedtls_ctx;\n        struct {\n            uint8_t key[32];\n            uint8_t keysize;\n        } init_data;\n    } u;\n    unsigned char iv[16];\n};\n#define AES_CTX_IMPL struct mbedtls_aes_ctx_with_key\n#endif\n\ntypedef struct _mp_obj_aes_t {\n    mp_obj_base_t base;\n    AES_CTX_IMPL ctx;\n    uint8_t block_mode: 6;\n#define AES_KEYTYPE_NONE 0\n#define AES_KEYTYPE_ENC  1\n#define AES_KEYTYPE_DEC  2\n    uint8_t key_type: 2;\n} mp_obj_aes_t;\n\nstatic inline bool is_ctr_mode(int block_mode) {\n    #if MICROPY_PY_UCRYPTOLIB_CTR\n    return block_mode == UCRYPTOLIB_MODE_CTR;\n    #else\n    return false;\n    #endif\n}\n\nstatic inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) {\n    // ctr_params follows aes object struct\n    return (struct ctr_params*)&o[1];\n}\n\n#if MICROPY_SSL_AXTLS\nSTATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) {\n    assert(16 == keysize || 32 == keysize);\n    AES_set_key(ctx, key, iv, (16 == keysize) ? AES_MODE_128 : AES_MODE_256);\n}\n\nSTATIC void aes_final_set_key_impl(AES_CTX_IMPL *ctx, bool encrypt) {\n    if (!encrypt) {\n        AES_convert_key(ctx);\n    }\n}\n\nSTATIC void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_t out[16], bool encrypt) {\n    memcpy(out, in, 16);\n    // We assume that out (vstr.buf or given output buffer) is uint32_t aligned\n    uint32_t *p = (uint32_t*)out;\n    // axTLS likes it weird and complicated with byteswaps\n    for (int i = 0; i < 4; i++) {\n        p[i] = MP_HTOBE32(p[i]);\n    }\n    if (encrypt) {\n        AES_encrypt(ctx, p);\n    } else {\n        AES_decrypt(ctx, p);\n    }\n    for (int i = 0; i < 4; i++) {\n        p[i] = MP_BE32TOH(p[i]);\n    }\n}\n\nSTATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) {\n    if (encrypt) {\n        AES_cbc_encrypt(ctx, in, out, in_len);\n    } else {\n        AES_cbc_decrypt(ctx, in, out, in_len);\n    }\n}\n\n#if MICROPY_PY_UCRYPTOLIB_CTR\n// axTLS doesn't have CTR support out of the box. This implements the counter part using the ECB primitive.\nSTATIC void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) {\n    size_t n = ctr_params->offset;\n    uint8_t *const counter = ctx->iv;\n\n    while (in_len--) {\n        if (n == 0) {\n            aes_process_ecb_impl(ctx, counter, ctr_params->encrypted_counter, true);\n\n            // increment the 128-bit counter\n            for (int i = 15; i >= 0; --i) {\n                if (++counter[i] != 0) {\n                    break;\n                }\n            }\n        }\n\n        *out++ = *in++ ^ ctr_params->encrypted_counter[n];\n        n = (n + 1) & 0xf;\n    }\n\n    ctr_params->offset = n;\n}\n#endif\n\n#endif\n\n#if MICROPY_SSL_MBEDTLS\nSTATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) {\n    ctx->u.init_data.keysize = keysize;\n    memcpy(ctx->u.init_data.key, key, keysize);\n\n    if (NULL != iv) {\n        memcpy(ctx->iv, iv, sizeof(ctx->iv));\n    }\n}\n\nSTATIC void aes_final_set_key_impl(AES_CTX_IMPL *ctx, bool encrypt) {\n    // first, copy key aside\n    uint8_t key[32];\n    uint8_t keysize = ctx->u.init_data.keysize;\n    memcpy(key, ctx->u.init_data.key, keysize);\n    // now, override key with the mbedtls context object\n    mbedtls_aes_init(&ctx->u.mbedtls_ctx);\n\n    // setkey call will succeed, we've already checked the keysize earlier.\n    assert(16 == keysize || 32 == keysize);\n    if (encrypt) {\n        mbedtls_aes_setkey_enc(&ctx->u.mbedtls_ctx, key, keysize * 8);\n    } else {\n        mbedtls_aes_setkey_dec(&ctx->u.mbedtls_ctx, key, keysize * 8);\n    }\n}\n\nSTATIC void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_t out[16], bool encrypt) {\n    mbedtls_aes_crypt_ecb(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in, out);\n}\n\nSTATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) {\n    mbedtls_aes_crypt_cbc(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in_len, ctx->iv, in, out);\n}\n\n#if MICROPY_PY_UCRYPTOLIB_CTR\nSTATIC void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) {\n    mbedtls_aes_crypt_ctr(&ctx->u.mbedtls_ctx, in_len, &ctr_params->offset, ctx->iv, ctr_params->encrypted_counter, in, out);\n}\n#endif\n\n#endif\n\nSTATIC mp_obj_t ucryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 2, 3, false);\n\n    const mp_int_t block_mode = mp_obj_get_int(args[1]);\n\n    switch (block_mode) {\n        case UCRYPTOLIB_MODE_ECB:\n        case UCRYPTOLIB_MODE_CBC:\n        #if MICROPY_PY_UCRYPTOLIB_CTR\n        case UCRYPTOLIB_MODE_CTR:\n        #endif\n            break;\n\n        default:\n            mp_raise_ValueError(\"mode\");\n    }\n\n    mp_obj_aes_t *o = m_new_obj_var(mp_obj_aes_t, struct ctr_params, !!is_ctr_mode(block_mode));\n    o->base.type = type;\n\n    o->block_mode = block_mode;\n    o->key_type = AES_KEYTYPE_NONE;\n\n    mp_buffer_info_t keyinfo;\n    mp_get_buffer_raise(args[0], &keyinfo, MP_BUFFER_READ);\n    if (32 != keyinfo.len && 16 != keyinfo.len) {\n        mp_raise_ValueError(\"key\");\n    }\n\n    mp_buffer_info_t ivinfo;\n    ivinfo.buf = NULL;\n    if (n_args > 2 && args[2] != mp_const_none) {\n        mp_get_buffer_raise(args[2], &ivinfo, MP_BUFFER_READ);\n\n        if (16 != ivinfo.len) {\n            mp_raise_ValueError(\"IV\");\n        }\n    } else if (o->block_mode == UCRYPTOLIB_MODE_CBC || is_ctr_mode(o->block_mode)) {\n        mp_raise_ValueError(\"IV\");\n    }\n\n    if (is_ctr_mode(block_mode)) {\n        ctr_params_from_aes(o)->offset = 0;\n    }\n\n    aes_initial_set_key_impl(&o->ctx, keyinfo.buf, keyinfo.len, ivinfo.buf);\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) {\n    mp_obj_aes_t *self = MP_OBJ_TO_PTR(args[0]);\n\n    mp_obj_t in_buf = args[1];\n    mp_obj_t out_buf = MP_OBJ_NULL;\n    if (n_args > 2) {\n        out_buf = args[2];\n    }\n\n    mp_buffer_info_t in_bufinfo;\n    mp_get_buffer_raise(in_buf, &in_bufinfo, MP_BUFFER_READ);\n\n    if (!is_ctr_mode(self->block_mode) && in_bufinfo.len % 16 != 0) {\n        mp_raise_ValueError(\"blksize % 16\");\n    }\n\n    vstr_t vstr;\n    mp_buffer_info_t out_bufinfo;\n    uint8_t *out_buf_ptr;\n\n    if (out_buf != MP_OBJ_NULL) {\n        mp_get_buffer_raise(out_buf, &out_bufinfo, MP_BUFFER_WRITE);\n        if (out_bufinfo.len < in_bufinfo.len) {\n            mp_raise_ValueError(\"output too small\");\n        }\n        out_buf_ptr = out_bufinfo.buf;\n    } else {\n        vstr_init_len(&vstr, in_bufinfo.len);\n        out_buf_ptr = (uint8_t*)vstr.buf;\n    }\n\n    if (AES_KEYTYPE_NONE == self->key_type) {\n        // always set key for encryption if CTR mode.\n        const bool encrypt_mode = encrypt || is_ctr_mode(self->block_mode);\n        aes_final_set_key_impl(&self->ctx, encrypt_mode);\n        self->key_type = encrypt ? AES_KEYTYPE_ENC : AES_KEYTYPE_DEC;\n    } else {\n        if ((encrypt && self->key_type == AES_KEYTYPE_DEC) ||\n            (!encrypt && self->key_type == AES_KEYTYPE_ENC)) {\n\n            mp_raise_ValueError(\"can't encrypt & decrypt\");\n        }\n    }\n\n    switch (self->block_mode) {\n        case UCRYPTOLIB_MODE_ECB: {\n            uint8_t *in = in_bufinfo.buf, *out = out_buf_ptr;\n            uint8_t *top = in + in_bufinfo.len;\n            for (; in < top; in += 16, out += 16) {\n                aes_process_ecb_impl(&self->ctx, in, out, encrypt);\n            }\n            break;\n        }\n\n        case UCRYPTOLIB_MODE_CBC:\n            aes_process_cbc_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len, encrypt);\n            break;\n\n        #if MICROPY_PY_UCRYPTOLIB_CTR\n        case UCRYPTOLIB_MODE_CTR:\n            aes_process_ctr_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len,\n                ctr_params_from_aes(self));\n            break;\n        #endif\n    }\n\n    if (out_buf != MP_OBJ_NULL) {\n        return out_buf;\n    }\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\n\nSTATIC mp_obj_t ucryptolib_aes_encrypt(size_t n_args, const mp_obj_t *args) {\n    return aes_process(n_args, args, true);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ucryptolib_aes_encrypt_obj, 2, 3, ucryptolib_aes_encrypt);\n\nSTATIC mp_obj_t ucryptolib_aes_decrypt(size_t n_args, const mp_obj_t *args) {\n    return aes_process(n_args, args, false);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ucryptolib_aes_decrypt_obj, 2, 3, ucryptolib_aes_decrypt);\n\nSTATIC const mp_rom_map_elem_t ucryptolib_aes_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_encrypt), MP_ROM_PTR(&ucryptolib_aes_encrypt_obj) },\n    { MP_ROM_QSTR(MP_QSTR_decrypt), MP_ROM_PTR(&ucryptolib_aes_decrypt_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(ucryptolib_aes_locals_dict, ucryptolib_aes_locals_dict_table);\n\nSTATIC const mp_obj_type_t ucryptolib_aes_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_aes,\n    .make_new = ucryptolib_aes_make_new,\n    .locals_dict = (void*)&ucryptolib_aes_locals_dict,\n};\n\nSTATIC const mp_rom_map_elem_t mp_module_ucryptolib_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ucryptolib) },\n    { MP_ROM_QSTR(MP_QSTR_aes), MP_ROM_PTR(&ucryptolib_aes_type) },\n#if MICROPY_PY_UCRYPTOLIB_CONSTS\n    { MP_ROM_QSTR(MP_QSTR_MODE_ECB), MP_ROM_INT(UCRYPTOLIB_MODE_ECB) },\n    { MP_ROM_QSTR(MP_QSTR_MODE_CBC), MP_ROM_INT(UCRYPTOLIB_MODE_CBC) },\n    #if MICROPY_PY_UCRYPTOLIB_CTR\n    { MP_ROM_QSTR(MP_QSTR_MODE_CTR), MP_ROM_INT(UCRYPTOLIB_MODE_CTR) },\n    #endif\n#endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_ucryptolib_globals, mp_module_ucryptolib_globals_table);\n\nconst mp_obj_module_t mp_module_ucryptolib = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_ucryptolib_globals,\n};\n\n#endif //MICROPY_PY_UCRYPTOLIB\n"
  },
  {
    "path": "extmod/moductypes.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2018 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <string.h>\n#include <stdint.h>\n\n#include \"py/runtime.h\"\n#include \"py/objtuple.h\"\n#include \"py/binary.h\"\n\n#if MICROPY_PY_UCTYPES\n\n/// \\module uctypes - Access data structures in memory\n///\n/// The module allows to define layout of raw data structure (using terms\n/// of C language), and then access memory buffers using this definition.\n/// The module also provides convenience functions to access memory buffers\n/// contained in Python objects or wrap memory buffers in Python objects.\n/// \\constant UINT8_1 - uint8_t value type\n\n/// \\class struct - C-like structure\n///\n/// Encapsulalation of in-memory data structure. This class doesn't define\n/// any methods, only attribute access (for structure fields) and\n/// indexing (for pointer and array fields).\n///\n/// Usage:\n///\n///     # Define layout of a structure with 2 fields\n///     # 0 and 4 are byte offsets of fields from the beginning of struct\n///     # they are logically ORed with field type\n///     FOO_STRUCT = {\"a\": 0 | uctypes.UINT32, \"b\": 4 | uctypes.UINT8}\n///\n///     # Example memory buffer to access (contained in bytes object)\n///     buf = b\"\\x64\\0\\0\\0\\0x14\"\n///\n///     # Create structure object referring to address of\n///     # the data in the buffer above\n///     s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf))\n///\n///     # Access fields\n///     print(s.a, s.b)\n///     # Result:\n///     # 100, 20\n\n#define LAYOUT_LITTLE_ENDIAN (0)\n#define LAYOUT_BIG_ENDIAN    (1)\n#define LAYOUT_NATIVE        (2)\n\n#define VAL_TYPE_BITS 4\n#define BITF_LEN_BITS 5\n#define BITF_OFF_BITS 5\n#define OFFSET_BITS 17\n#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31\n#error Invalid encoding field length\n#endif\n\nenum {\n    UINT8, INT8, UINT16, INT16,\n    UINT32, INT32, UINT64, INT64,\n\n    BFUINT8, BFINT8, BFUINT16, BFINT16,\n    BFUINT32, BFINT32,\n\n    FLOAT32, FLOAT64,\n};\n\n#define AGG_TYPE_BITS 2\n\nenum {\n    STRUCT, PTR, ARRAY,\n};\n\n// Here we need to set sign bit right\n#define TYPE2SMALLINT(x, nbits) ((((int)x) << (32 - nbits)) >> 1)\n#define GET_TYPE(x, nbits) (((x) >> (31 - nbits)) & ((1 << nbits) - 1))\n// Bit 0 is \"is_signed\"\n#define GET_SCALAR_SIZE(val_type) (1 << ((val_type) >> 1))\n#define VALUE_MASK(type_nbits) ~((int)0x80000000 >> type_nbits)\n\n#define IS_SCALAR_ARRAY(tuple_desc) ((tuple_desc)->len == 2)\n// We cannot apply the below to INT8, as their range [-128, 127]\n#define IS_SCALAR_ARRAY_OF_BYTES(tuple_desc) (GET_TYPE(MP_OBJ_SMALL_INT_VALUE((tuple_desc)->items[1]), VAL_TYPE_BITS) == UINT8)\n\n// \"struct\" in uctypes context means \"structural\", i.e. aggregate, type.\nSTATIC const mp_obj_type_t uctypes_struct_type;\n\ntypedef struct _mp_obj_uctypes_struct_t {\n    mp_obj_base_t base;\n    mp_obj_t desc;\n    byte *addr;\n    uint32_t flags;\n} mp_obj_uctypes_struct_t;\n\nSTATIC NORETURN void syntax_error(void) {\n    mp_raise_TypeError(\"syntax error in uctypes descriptor\");\n}\n\nSTATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 2, 3, false);\n    mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);\n    o->base.type = type;\n    o->addr = (void*)(uintptr_t)mp_obj_int_get_truncated(args[0]);\n    o->desc = args[1];\n    o->flags = LAYOUT_NATIVE;\n    if (n_args == 3) {\n        o->flags = mp_obj_get_int(args[2]);\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);\n    const char *typen = \"unk\";\n    if (mp_obj_is_type(self->desc, &mp_type_dict)\n      #if MICROPY_PY_COLLECTIONS_ORDEREDDICT\n        || mp_obj_is_type(self->desc, &mp_type_ordereddict)\n      #endif\n      ) {\n        typen = \"STRUCT\";\n    } else if (mp_obj_is_type(self->desc, &mp_type_tuple)) {\n        mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);\n        mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);\n        uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);\n        switch (agg_type) {\n            case PTR: typen = \"PTR\"; break;\n            case ARRAY: typen = \"ARRAY\"; break;\n        }\n    } else {\n        typen = \"ERROR\";\n    }\n    mp_printf(print, \"<struct %s %p>\", typen, self->addr);\n}\n\n// Get size of any type descriptor\nSTATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size);\n\n// Get size of scalar type descriptor\nstatic inline mp_uint_t uctypes_struct_scalar_size(int val_type) {\n    if (val_type == FLOAT32) {\n        return 4;\n    } else {\n        return GET_SCALAR_SIZE(val_type & 7);\n    }\n}\n\n// Get size of aggregate type descriptor\nSTATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_uint_t *max_field_size) {\n    mp_uint_t total_size = 0;\n\n    mp_int_t offset_ = MP_OBJ_SMALL_INT_VALUE(t->items[0]);\n    mp_uint_t agg_type = GET_TYPE(offset_, AGG_TYPE_BITS);\n\n    switch (agg_type) {\n        case STRUCT:\n            return uctypes_struct_size(t->items[1], layout_type, max_field_size);\n        case PTR:\n            if (sizeof(void*) > *max_field_size) {\n                *max_field_size = sizeof(void*);\n            }\n            return sizeof(void*);\n        case ARRAY: {\n            mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);\n            uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);\n            arr_sz &= VALUE_MASK(VAL_TYPE_BITS);\n            mp_uint_t item_s;\n            if (t->len == 2) {\n                // Elements of array are scalar\n                item_s = GET_SCALAR_SIZE(val_type);\n                if (item_s > *max_field_size) {\n                    *max_field_size = item_s;\n                }\n            } else {\n                // Elements of array are aggregates\n                item_s = uctypes_struct_size(t->items[2], layout_type, max_field_size);\n            }\n\n            return item_s * arr_sz;\n        }\n        default:\n            assert(0);\n    }\n\n    return total_size;\n}\n\nSTATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) {\n    if (!mp_obj_is_type(desc_in, &mp_type_dict)\n      #if MICROPY_PY_COLLECTIONS_ORDEREDDICT\n        && !mp_obj_is_type(desc_in, &mp_type_ordereddict)\n      #endif\n      ) {\n        if (mp_obj_is_type(desc_in, &mp_type_tuple)) {\n            return uctypes_struct_agg_size((mp_obj_tuple_t*)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size);\n        } else if (mp_obj_is_small_int(desc_in)) {\n            // We allow sizeof on both type definitions and structures/structure fields,\n            // but scalar structure field is lowered into native Python int, so all\n            // type info is lost. So, we cannot say if it's scalar type description,\n            // or such lowered scalar.\n            mp_raise_TypeError(\"Cannot unambiguously get sizeof scalar\");\n        }\n        syntax_error();\n    }\n\n    mp_obj_dict_t *d = MP_OBJ_TO_PTR(desc_in);\n    mp_uint_t total_size = 0;\n\n    for (mp_uint_t i = 0; i < d->map.alloc; i++) {\n        if (mp_map_slot_is_filled(&d->map, i)) {\n            mp_obj_t v = d->map.table[i].value;\n            if (mp_obj_is_small_int(v)) {\n                mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v);\n                mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);\n                offset &= VALUE_MASK(VAL_TYPE_BITS);\n                if (val_type >= BFUINT8 && val_type <= BFINT32) {\n                    offset &= (1 << OFFSET_BITS) - 1;\n                }\n                mp_uint_t s = uctypes_struct_scalar_size(val_type);\n                if (s > *max_field_size) {\n                    *max_field_size = s;\n                }\n                if (offset + s > total_size) {\n                    total_size = offset + s;\n                }\n            } else {\n                if (!mp_obj_is_type(v, &mp_type_tuple)) {\n                    syntax_error();\n                }\n                mp_obj_tuple_t *t = MP_OBJ_TO_PTR(v);\n                mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);\n                offset &= VALUE_MASK(AGG_TYPE_BITS);\n                mp_uint_t s = uctypes_struct_agg_size(t, layout_type, max_field_size);\n                if (offset + s > total_size) {\n                    total_size = offset + s;\n                }\n            }\n        }\n    }\n\n    // Round size up to alignment of biggest field\n    if (layout_type == LAYOUT_NATIVE) {\n        total_size = (total_size + *max_field_size - 1) & ~(*max_field_size - 1);\n    }\n    return total_size;\n}\n\nSTATIC mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t obj_in = args[0];\n    mp_uint_t max_field_size = 0;\n    if (mp_obj_is_type(obj_in, &mp_type_bytearray)) {\n        return mp_obj_len(obj_in);\n    }\n    int layout_type = LAYOUT_NATIVE;\n    // We can apply sizeof either to structure definition (a dict)\n    // or to instantiated structure\n    if (mp_obj_is_type(obj_in, &uctypes_struct_type)) {\n        if (n_args != 1) {\n            mp_raise_TypeError(NULL);\n        }\n        // Extract structure definition\n        mp_obj_uctypes_struct_t *obj = MP_OBJ_TO_PTR(obj_in);\n        obj_in = obj->desc;\n        layout_type = obj->flags;\n    } else {\n        if (n_args == 2) {\n            layout_type = mp_obj_get_int(args[1]);\n        }\n    }\n    mp_uint_t size = uctypes_struct_size(obj_in, layout_type, &max_field_size);\n    return MP_OBJ_NEW_SMALL_INT(size);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, uctypes_struct_sizeof);\n\nstatic inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) {\n    char struct_type = big_endian ? '>' : '<';\n    static const char type2char[16] = \"BbHhIiQq------fd\";\n    return mp_binary_get_val(struct_type, type2char[val_type], p, &p);\n}\n\nstatic inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) {\n    char struct_type = big_endian ? '>' : '<';\n    static const char type2char[16] = \"BbHhIiQq------fd\";\n    mp_binary_set_val(struct_type, type2char[val_type], val, p, &p);\n}\n\nstatic inline mp_uint_t get_aligned_basic(uint val_type, void *p) {\n    switch (val_type) {\n        case UINT8:\n            return *(uint8_t*)p;\n        case UINT16:\n            return *(uint16_t*)p;\n        case UINT32:\n            return *(uint32_t*)p;\n    }\n    assert(0);\n    return 0;\n}\n\nstatic inline void set_aligned_basic(uint val_type, void *p, mp_uint_t v) {\n    switch (val_type) {\n        case UINT8:\n            *(uint8_t*)p = (uint8_t)v; return;\n        case UINT16:\n            *(uint16_t*)p = (uint16_t)v; return;\n        case UINT32:\n            *(uint32_t*)p = (uint32_t)v; return;\n    }\n    assert(0);\n}\n\nSTATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {\n    switch (val_type) {\n        case UINT8:\n            return MP_OBJ_NEW_SMALL_INT(((uint8_t*)p)[index]);\n        case INT8:\n            return MP_OBJ_NEW_SMALL_INT(((int8_t*)p)[index]);\n        case UINT16:\n            return MP_OBJ_NEW_SMALL_INT(((uint16_t*)p)[index]);\n        case INT16:\n            return MP_OBJ_NEW_SMALL_INT(((int16_t*)p)[index]);\n        case UINT32:\n            return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);\n        case INT32:\n            return mp_obj_new_int(((int32_t*)p)[index]);\n        case UINT64:\n            return mp_obj_new_int_from_ull(((uint64_t*)p)[index]);\n        case INT64:\n            return mp_obj_new_int_from_ll(((int64_t*)p)[index]);\n        #if MICROPY_PY_BUILTINS_FLOAT\n        case FLOAT32:\n            return mp_obj_new_float(((float*)p)[index]);\n        case FLOAT64:\n            return mp_obj_new_float(((double*)p)[index]);\n        #endif\n        default:\n            assert(0);\n            return MP_OBJ_NULL;\n    }\n}\n\nSTATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {\n    #if MICROPY_PY_BUILTINS_FLOAT\n    if (val_type == FLOAT32 || val_type == FLOAT64) {\n        mp_float_t v = mp_obj_get_float(val);\n        if (val_type == FLOAT32) {\n            ((float*)p)[index] = v;\n        } else {\n            ((double*)p)[index] = v;\n        }\n        return;\n    }\n    #endif\n    mp_int_t v = mp_obj_get_int_truncated(val);\n    switch (val_type) {\n        case UINT8:\n            ((uint8_t*)p)[index] = (uint8_t)v; return;\n        case INT8:\n            ((int8_t*)p)[index] = (int8_t)v; return;\n        case UINT16:\n            ((uint16_t*)p)[index] = (uint16_t)v; return;\n        case INT16:\n            ((int16_t*)p)[index] = (int16_t)v; return;\n        case UINT32:\n            ((uint32_t*)p)[index] = (uint32_t)v; return;\n        case INT32:\n            ((int32_t*)p)[index] = (int32_t)v; return;\n        case INT64:\n        case UINT64:\n            if (sizeof(mp_int_t) == 8) {\n                ((uint64_t*)p)[index] = (uint64_t)v;\n            } else {\n                // TODO: Doesn't offer atomic store semantics, but should at least try\n                set_unaligned(val_type, p, MP_ENDIANNESS_BIG, val);\n            }\n            return;\n        default:\n            assert(0);\n    }\n}\n\nSTATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) {\n    mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (!mp_obj_is_type(self->desc, &mp_type_dict)\n      #if MICROPY_PY_COLLECTIONS_ORDEREDDICT\n        && !mp_obj_is_type(self->desc, &mp_type_ordereddict)\n      #endif\n      ) {\n            mp_raise_TypeError(\"struct: no fields\");\n    }\n\n    mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));\n    if (mp_obj_is_small_int(deref)) {\n        mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);\n        mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);\n        offset &= VALUE_MASK(VAL_TYPE_BITS);\n//printf(\"scalar type=%d offset=%x\\n\", val_type, offset);\n\n        if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) {\n//            printf(\"size=%d\\n\", GET_SCALAR_SIZE(val_type));\n            if (self->flags == LAYOUT_NATIVE) {\n                if (set_val == MP_OBJ_NULL) {\n                    return get_aligned(val_type, self->addr + offset, 0);\n                } else {\n                    set_aligned(val_type, self->addr + offset, 0, set_val);\n                    return set_val; // just !MP_OBJ_NULL\n                }\n            } else {\n                if (set_val == MP_OBJ_NULL) {\n                    return get_unaligned(val_type, self->addr + offset, self->flags);\n                } else {\n                    set_unaligned(val_type, self->addr + offset, self->flags, set_val);\n                    return set_val; // just !MP_OBJ_NULL\n                }\n            }\n        } else if (val_type >= BFUINT8 && val_type <= BFINT32) {\n            uint bit_offset = (offset >> 17) & 31;\n            uint bit_len = (offset >> 22) & 31;\n            offset &= (1 << 17) - 1;\n            mp_uint_t val;\n            if (self->flags == LAYOUT_NATIVE) {\n                val = get_aligned_basic(val_type & 6, self->addr + offset);\n            } else {\n                val = mp_binary_get_int(GET_SCALAR_SIZE(val_type & 7), val_type & 1, self->flags, self->addr + offset);\n            }\n            if (set_val == MP_OBJ_NULL) {\n                val >>= bit_offset;\n                val &= (1 << bit_len) - 1;\n                // TODO: signed\n                assert((val_type & 1) == 0);\n                return mp_obj_new_int(val);\n            } else {\n                mp_uint_t set_val_int = (mp_uint_t)mp_obj_get_int(set_val);\n                mp_uint_t mask = (1 << bit_len) - 1;\n                set_val_int &= mask;\n                set_val_int <<= bit_offset;\n                mask <<= bit_offset;\n                val = (val & ~mask) | set_val_int;\n\n                if (self->flags == LAYOUT_NATIVE) {\n                    set_aligned_basic(val_type & 6, self->addr + offset, val);\n                } else {\n                    mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN,\n                        self->addr + offset, val);\n                }\n                return set_val; // just !MP_OBJ_NULL\n            }\n        }\n\n        assert(0);\n        return MP_OBJ_NULL;\n    }\n\n    if (!mp_obj_is_type(deref, &mp_type_tuple)) {\n        syntax_error();\n    }\n\n    if (set_val != MP_OBJ_NULL) {\n        // Cannot assign to aggregate\n        syntax_error();\n    }\n\n    mp_obj_tuple_t *sub = MP_OBJ_TO_PTR(deref);\n    mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);\n    mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);\n    offset &= VALUE_MASK(AGG_TYPE_BITS);\n//printf(\"agg type=%d offset=%x\\n\", agg_type, offset);\n\n    switch (agg_type) {\n        case STRUCT: {\n            mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);\n            o->base.type = &uctypes_struct_type;\n            o->desc = sub->items[1];\n            o->addr = self->addr + offset;\n            o->flags = self->flags;\n            return MP_OBJ_FROM_PTR(o);\n        }\n        case ARRAY: {\n            mp_uint_t dummy;\n            if (IS_SCALAR_ARRAY(sub) && IS_SCALAR_ARRAY_OF_BYTES(sub)) {\n                return mp_obj_new_bytearray_by_ref(uctypes_struct_agg_size(sub, self->flags, &dummy), self->addr + offset);\n            }\n            // Fall thru to return uctypes struct object\n        }\n        case PTR: {\n            mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);\n            o->base.type = &uctypes_struct_type;\n            o->desc = MP_OBJ_FROM_PTR(sub);\n            o->addr = self->addr + offset;\n            o->flags = self->flags;\n//printf(\"PTR/ARR base addr=%p\\n\", o->addr);\n            return MP_OBJ_FROM_PTR(o);\n        }\n    }\n\n    // Should be unreachable once all cases are handled\n    return MP_OBJ_NULL;\n}\n\nSTATIC void uctypes_struct_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] == MP_OBJ_NULL) {\n        // load attribute\n        mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);\n        dest[0] = val;\n    } else {\n        // delete/store attribute\n        if (uctypes_struct_attr_op(self_in, attr, dest[1]) != MP_OBJ_NULL) {\n            dest[0] = MP_OBJ_NULL; // indicate success\n        }\n    }\n}\n\nSTATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {\n    mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (value == MP_OBJ_NULL) {\n        // delete\n        return MP_OBJ_NULL; // op not supported\n    } else {\n        // load / store\n        if (!mp_obj_is_type(self->desc, &mp_type_tuple)) {\n            mp_raise_TypeError(\"struct: cannot index\");\n        }\n\n        mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);\n        mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);\n        uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);\n\n        mp_int_t index = MP_OBJ_SMALL_INT_VALUE(index_in);\n\n        if (agg_type == ARRAY) {\n            mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);\n            uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);\n            arr_sz &= VALUE_MASK(VAL_TYPE_BITS);\n            if (index >= arr_sz) {\n                mp_raise_msg(&mp_type_IndexError, \"struct: index out of range\");\n            }\n\n            if (t->len == 2) {\n                // array of scalars\n                if (self->flags == LAYOUT_NATIVE) {\n                    if (value == MP_OBJ_SENTINEL) {\n                        return get_aligned(val_type, self->addr, index);\n                    } else {\n                        set_aligned(val_type, self->addr, index, value);\n                        return value; // just !MP_OBJ_NULL\n                    }\n                } else {\n                    byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index;\n                    if (value == MP_OBJ_SENTINEL) {\n                        return get_unaligned(val_type, p, self->flags);\n                    } else {\n                        set_unaligned(val_type, p, self->flags, value);\n                        return value; // just !MP_OBJ_NULL\n                    }\n                }\n            } else if (value == MP_OBJ_SENTINEL) {\n                mp_uint_t dummy = 0;\n                mp_uint_t size = uctypes_struct_size(t->items[2], self->flags, &dummy);\n                mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);\n                o->base.type = &uctypes_struct_type;\n                o->desc = t->items[2];\n                o->addr = self->addr + size * index;\n                o->flags = self->flags;\n                return MP_OBJ_FROM_PTR(o);\n            } else {\n                return MP_OBJ_NULL; // op not supported\n            }\n\n        } else if (agg_type == PTR) {\n            byte *p = *(void**)self->addr;\n            if (mp_obj_is_small_int(t->items[1])) {\n                uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS);\n                return get_aligned(val_type, p, index);\n            } else {\n                mp_uint_t dummy = 0;\n                mp_uint_t size = uctypes_struct_size(t->items[1], self->flags, &dummy);\n                mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);\n                o->base.type = &uctypes_struct_type;\n                o->desc = t->items[1];\n                o->addr = p + size * index;\n                o->flags = self->flags;\n                return MP_OBJ_FROM_PTR(o);\n            }\n        }\n\n        assert(0);\n        return MP_OBJ_NULL;\n    }\n}\n\nSTATIC mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n    mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);\n    switch (op) {\n        case MP_UNARY_OP_INT:\n            if (mp_obj_is_type(self->desc, &mp_type_tuple)) {\n                mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);\n                mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);\n                uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);\n                if (agg_type == PTR) {\n                    byte *p = *(void**)self->addr;\n                    return mp_obj_new_int((mp_int_t)(uintptr_t)p);\n                }\n            }\n            /* fallthru */\n\n        default: return MP_OBJ_NULL; // op not supported\n    }\n}\n\nSTATIC mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {\n    (void)flags;\n    mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_uint_t max_field_size = 0;\n    mp_uint_t size = uctypes_struct_size(self->desc, self->flags, &max_field_size);\n\n    bufinfo->buf = self->addr;\n    bufinfo->len = size;\n    bufinfo->typecode = BYTEARRAY_TYPECODE;\n    return 0;\n}\n\n/// \\function addressof()\n/// Return address of object's data (applies to object providing buffer\n/// interface).\nSTATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);\n    return mp_obj_new_int((mp_int_t)(uintptr_t)bufinfo.buf);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);\n\n/// \\function bytearray_at()\n/// Capture memory at given address of given size as bytearray. Memory is\n/// captured by reference (and thus memory pointed by bytearray may change\n/// or become invalid at later time). Use bytes_at() to capture by value.\nSTATIC mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {\n    return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void*)(uintptr_t)mp_obj_int_get_truncated(ptr));\n}\nMP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);\n\n/// \\function bytes_at()\n/// Capture memory at given address of given size as bytes. Memory is\n/// captured by value, i.e. copied. Use bytearray_at() to capture by reference\n/// (\"zero copy\").\nSTATIC mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {\n    return mp_obj_new_bytes((void*)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size));\n}\nMP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);\n\n\nSTATIC const mp_obj_type_t uctypes_struct_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_struct,\n    .print = uctypes_struct_print,\n    .make_new = uctypes_struct_make_new,\n    .attr = uctypes_struct_attr,\n    .subscr = uctypes_struct_subscr,\n    .unary_op = uctypes_struct_unary_op,\n    .buffer_p = { .get_buffer = uctypes_get_buffer },\n};\n\nSTATIC const mp_rom_map_elem_t mp_module_uctypes_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uctypes) },\n    { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&uctypes_struct_type) },\n    { MP_ROM_QSTR(MP_QSTR_sizeof), MP_ROM_PTR(&uctypes_struct_sizeof_obj) },\n    { MP_ROM_QSTR(MP_QSTR_addressof), MP_ROM_PTR(&uctypes_struct_addressof_obj) },\n    { MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) },\n    { MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) },\n\n    /// \\moduleref uctypes\n\n    /// \\constant NATIVE - Native structure layout - native endianness,\n    /// platform-specific field alignment\n    { MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) },\n    /// \\constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed\n    /// (no alignment constraints)\n    { MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) },\n    /// \\constant BIG_ENDIAN - Big-endian structure layout, tightly packed\n    /// (no alignment constraints)\n    { MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) },\n\n    /// \\constant VOID - void value type, may be used only as pointer target type.\n    { MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },\n\n    /// \\constant UINT8 - uint8_t value type\n    { MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, 4)) },\n    /// \\constant INT8 - int8_t value type\n    { MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, 4)) },\n    /// \\constant UINT16 - uint16_t value type\n    { MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) },\n    /// \\constant INT16 - int16_t value type\n    { MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) },\n    /// \\constant UINT32 - uint32_t value type\n    { MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },\n    /// \\constant INT32 - int32_t value type\n    { MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },\n    /// \\constant UINT64 - uint64_t value type\n    { MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },\n    /// \\constant INT64 - int64_t value type\n    { MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },\n\n    { MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, 4)) },\n\n    { MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(17) },\n    { MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(22) },\n\n    #if MICROPY_PY_BUILTINS_FLOAT\n    { MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, 4)) },\n    #endif\n\n    #if MICROPY_PY_UCTYPES_NATIVE_C_TYPES\n    // C native type aliases. These depend on GCC-compatible predefined\n    // preprocessor macros.\n    #if __SIZEOF_SHORT__ == 2\n    { MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) },\n    #endif\n    #if __SIZEOF_INT__ == 4\n    { MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },\n    #endif\n    #if __SIZEOF_LONG__ == 4\n    { MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },\n    #elif __SIZEOF_LONG__ == 8\n    { MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },\n    #endif\n    #if __SIZEOF_LONG_LONG__ == 8\n    { MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },\n    { MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },\n    #endif\n    #endif // MICROPY_PY_UCTYPES_NATIVE_C_TYPES\n\n    { MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },\n    { MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table);\n\nconst mp_obj_module_t mp_module_uctypes = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_uctypes_globals,\n};\n\n#endif\n"
  },
  {
    "path": "extmod/moduhashlib.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_UHASHLIB\n\n#if MICROPY_SSL_MBEDTLS\n#include \"mbedtls/version.h\"\n#endif\n\n#if MICROPY_PY_UHASHLIB_SHA256\n\n#if MICROPY_SSL_MBEDTLS\n#include \"mbedtls/sha256.h\"\n#else\n#include \"crypto-algorithms/sha256.h\"\n#endif\n\n#endif\n\n#if MICROPY_PY_UHASHLIB_SHA1 || MICROPY_PY_UHASHLIB_MD5\n\n#if MICROPY_SSL_AXTLS\n#include \"lib/axtls/crypto/crypto.h\"\n#endif\n\n#if MICROPY_SSL_MBEDTLS\n#include \"mbedtls/md5.h\"\n#include \"mbedtls/sha1.h\"\n#endif\n\n#endif\n\ntypedef struct _mp_obj_hash_t {\n    mp_obj_base_t base;\n    char state[0];\n} mp_obj_hash_t;\n\n#if MICROPY_PY_UHASHLIB_SHA256\nSTATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);\n\n#if MICROPY_SSL_MBEDTLS\n\n#if MBEDTLS_VERSION_NUMBER < 0x02070000\n#define mbedtls_sha256_starts_ret mbedtls_sha256_starts\n#define mbedtls_sha256_update_ret mbedtls_sha256_update\n#define mbedtls_sha256_finish_ret mbedtls_sha256_finish\n#endif\n\nSTATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n    mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context));\n    o->base.type = type;\n    mbedtls_sha256_init((mbedtls_sha256_context*)&o->state);\n    mbedtls_sha256_starts_ret((mbedtls_sha256_context*)&o->state, 0);\n    if (n_args == 1) {\n        uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);\n    mbedtls_sha256_update_ret((mbedtls_sha256_context*)&self->state, bufinfo.buf, bufinfo.len);\n    return mp_const_none;\n}\n\nSTATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    vstr_t vstr;\n    vstr_init_len(&vstr, 32);\n    mbedtls_sha256_finish_ret((mbedtls_sha256_context*)&self->state, (unsigned char *)vstr.buf);\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\n\n#else\n\n#include \"crypto-algorithms/sha256.c\"\n\nSTATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n    mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX));\n    o->base.type = type;\n    sha256_init((CRYAL_SHA256_CTX*)o->state);\n    if (n_args == 1) {\n        uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);\n    sha256_update((CRYAL_SHA256_CTX*)self->state, bufinfo.buf, bufinfo.len);\n    return mp_const_none;\n}\n\nSTATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    vstr_t vstr;\n    vstr_init_len(&vstr, SHA256_BLOCK_SIZE);\n    sha256_final((CRYAL_SHA256_CTX*)self->state, (byte*)vstr.buf);\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\n#endif\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest);\n\nSTATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha256_update_obj) },\n    { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha256_digest_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(uhashlib_sha256_locals_dict, uhashlib_sha256_locals_dict_table);\n\nSTATIC const mp_obj_type_t uhashlib_sha256_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_sha256,\n    .make_new = uhashlib_sha256_make_new,\n    .locals_dict = (void*)&uhashlib_sha256_locals_dict,\n};\n#endif\n\n#if MICROPY_PY_UHASHLIB_SHA1\nSTATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg);\n\n#if MICROPY_SSL_AXTLS\nSTATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n    mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));\n    o->base.type = type;\n    SHA1_Init((SHA1_CTX*)o->state);\n    if (n_args == 1) {\n        uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);\n    SHA1_Update((SHA1_CTX*)self->state, bufinfo.buf, bufinfo.len);\n    return mp_const_none;\n}\n\nSTATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    vstr_t vstr;\n    vstr_init_len(&vstr, SHA1_SIZE);\n    SHA1_Final((byte*)vstr.buf, (SHA1_CTX*)self->state);\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\n#endif\n\n#if MICROPY_SSL_MBEDTLS\n\n#if MBEDTLS_VERSION_NUMBER < 0x02070000\n#define mbedtls_sha1_starts_ret mbedtls_sha1_starts\n#define mbedtls_sha1_update_ret mbedtls_sha1_update\n#define mbedtls_sha1_finish_ret mbedtls_sha1_finish\n#endif\n\nSTATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n    mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context));\n    o->base.type = type;\n    mbedtls_sha1_init((mbedtls_sha1_context*)o->state);\n    mbedtls_sha1_starts_ret((mbedtls_sha1_context*)o->state);\n    if (n_args == 1) {\n        uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);\n    mbedtls_sha1_update_ret((mbedtls_sha1_context*)self->state, bufinfo.buf, bufinfo.len);\n    return mp_const_none;\n}\n\nSTATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    vstr_t vstr;\n    vstr_init_len(&vstr, 20);\n    mbedtls_sha1_finish_ret((mbedtls_sha1_context*)self->state, (byte*)vstr.buf);\n    mbedtls_sha1_free((mbedtls_sha1_context*)self->state);\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\n#endif\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest);\n\nSTATIC const mp_rom_map_elem_t uhashlib_sha1_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha1_update_obj) },\n    { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha1_digest_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(uhashlib_sha1_locals_dict, uhashlib_sha1_locals_dict_table);\n\nSTATIC const mp_obj_type_t uhashlib_sha1_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_sha1,\n    .make_new = uhashlib_sha1_make_new,\n    .locals_dict = (void*)&uhashlib_sha1_locals_dict,\n};\n#endif\n\n#if MICROPY_PY_UHASHLIB_MD5\nSTATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg);\n\n#if MICROPY_SSL_AXTLS\nSTATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n    mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(MD5_CTX));\n    o->base.type = type;\n    MD5_Init((MD5_CTX*)o->state);\n    if (n_args == 1) {\n        uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);\n    MD5_Update((MD5_CTX*)self->state, bufinfo.buf, bufinfo.len);\n    return mp_const_none;\n}\n\nSTATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    vstr_t vstr;\n    vstr_init_len(&vstr, MD5_SIZE);\n    MD5_Final((byte*)vstr.buf, (MD5_CTX*)self->state);\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\n#endif // MICROPY_SSL_AXTLS\n\n#if MICROPY_SSL_MBEDTLS\n\n#if MBEDTLS_VERSION_NUMBER < 0x02070000\n#define mbedtls_md5_starts_ret mbedtls_md5_starts\n#define mbedtls_md5_update_ret mbedtls_md5_update\n#define mbedtls_md5_finish_ret mbedtls_md5_finish\n#endif\n\nSTATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n    mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context));\n    o->base.type = type;\n    mbedtls_md5_init((mbedtls_md5_context*)o->state);\n    mbedtls_md5_starts_ret((mbedtls_md5_context*)o->state);\n    if (n_args == 1) {\n        uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);\n    mbedtls_md5_update_ret((mbedtls_md5_context*)self->state, bufinfo.buf, bufinfo.len);\n    return mp_const_none;\n}\n\nSTATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {\n    mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);\n    vstr_t vstr;\n    vstr_init_len(&vstr, 16);\n    mbedtls_md5_finish_ret((mbedtls_md5_context*)self->state, (byte*)vstr.buf);\n    mbedtls_md5_free((mbedtls_md5_context*)self->state);\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\n#endif // MICROPY_SSL_MBEDTLS\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_md5_update_obj, uhashlib_md5_update);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_md5_digest_obj, uhashlib_md5_digest);\n\nSTATIC const mp_rom_map_elem_t uhashlib_md5_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_md5_update_obj) },\n    { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_md5_digest_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(uhashlib_md5_locals_dict, uhashlib_md5_locals_dict_table);\n\nSTATIC const mp_obj_type_t uhashlib_md5_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_md5,\n    .make_new = uhashlib_md5_make_new,\n    .locals_dict = (void*)&uhashlib_md5_locals_dict,\n};\n#endif // MICROPY_PY_UHASHLIB_MD5\n\nSTATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uhashlib) },\n    #if MICROPY_PY_UHASHLIB_SHA256\n    { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&uhashlib_sha256_type) },\n    #endif\n    #if MICROPY_PY_UHASHLIB_SHA1\n    { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&uhashlib_sha1_type) },\n    #endif\n    #if MICROPY_PY_UHASHLIB_MD5\n    { MP_ROM_QSTR(MP_QSTR_md5), MP_ROM_PTR(&uhashlib_md5_type) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_uhashlib_globals, mp_module_uhashlib_globals_table);\n\nconst mp_obj_module_t mp_module_uhashlib = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_uhashlib_globals,\n};\n\n#endif //MICROPY_PY_UHASHLIB\n"
  },
  {
    "path": "extmod/moduheapq.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/objlist.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_UHEAPQ\n\n// the algorithm here is modelled on CPython's heapq.py\n\nSTATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) {\n    if (!mp_obj_is_type(heap_in, &mp_type_list)) {\n        mp_raise_TypeError(\"heap must be a list\");\n    }\n    return MP_OBJ_TO_PTR(heap_in);\n}\n\nSTATIC void uheapq_heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {\n    mp_obj_t item = heap->items[pos];\n    while (pos > start_pos) {\n        mp_uint_t parent_pos = (pos - 1) >> 1;\n        mp_obj_t parent = heap->items[parent_pos];\n        if (mp_binary_op(MP_BINARY_OP_LESS, item, parent) == mp_const_true) {\n            heap->items[pos] = parent;\n            pos = parent_pos;\n        } else {\n            break;\n        }\n    }\n    heap->items[pos] = item;\n}\n\nSTATIC void uheapq_heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {\n    mp_uint_t start_pos = pos;\n    mp_uint_t end_pos = heap->len;\n    mp_obj_t item = heap->items[pos];\n    for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {\n        // choose right child if it's <= left child\n        if (child_pos + 1 < end_pos && mp_binary_op(MP_BINARY_OP_LESS, heap->items[child_pos], heap->items[child_pos + 1]) == mp_const_false) {\n            child_pos += 1;\n        }\n        // bubble up the smaller child\n        heap->items[pos] = heap->items[child_pos];\n        pos = child_pos;\n    }\n    heap->items[pos] = item;\n    uheapq_heap_siftdown(heap, start_pos, pos);\n}\n\nSTATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) {\n    mp_obj_list_t *heap = uheapq_get_heap(heap_in);\n    mp_obj_list_append(heap_in, item);\n    uheapq_heap_siftdown(heap, 0, heap->len - 1);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);\n\nSTATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {\n    mp_obj_list_t *heap = uheapq_get_heap(heap_in);\n    if (heap->len == 0) {\n        mp_raise_msg(&mp_type_IndexError, \"empty heap\");\n    }\n    mp_obj_t item = heap->items[0];\n    heap->len -= 1;\n    heap->items[0] = heap->items[heap->len];\n    heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer\n    if (heap->len) {\n        uheapq_heap_siftup(heap, 0);\n    }\n    return item;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop);\n\nSTATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) {\n    mp_obj_list_t *heap = uheapq_get_heap(heap_in);\n    for (mp_uint_t i = heap->len / 2; i > 0;) {\n        uheapq_heap_siftup(heap, --i);\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify);\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_rom_map_elem_t mp_module_uheapq_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uheapq) },\n    { MP_ROM_QSTR(MP_QSTR_heappush), MP_ROM_PTR(&mod_uheapq_heappush_obj) },\n    { MP_ROM_QSTR(MP_QSTR_heappop), MP_ROM_PTR(&mod_uheapq_heappop_obj) },\n    { MP_ROM_QSTR(MP_QSTR_heapify), MP_ROM_PTR(&mod_uheapq_heapify_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_uheapq_globals, mp_module_uheapq_globals_table);\n\nconst mp_obj_module_t mp_module_uheapq = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_uheapq_globals,\n};\n#endif\n\n#endif //MICROPY_PY_UHEAPQ\n"
  },
  {
    "path": "extmod/modujson.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2019 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n\n#include \"py/objlist.h\"\n#include \"py/objstringio.h\"\n#include \"py/parsenum.h\"\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n\n#if MICROPY_PY_UJSON\n\nSTATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) {\n    mp_get_stream_raise(stream, MP_STREAM_OP_WRITE);\n    mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor};\n    mp_obj_print_helper(&print, obj, PRINT_JSON);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump);\n\nSTATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {\n    vstr_t vstr;\n    mp_print_t print;\n    vstr_init_print(&vstr, 8, &print);\n    mp_obj_print_helper(&print, obj, PRINT_JSON);\n    return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);\n\n// The function below implements a simple non-recursive JSON parser.\n//\n// The JSON specification is at http://www.ietf.org/rfc/rfc4627.txt\n// The parser here will parse any valid JSON and return the correct\n// corresponding Python object.  It allows through a superset of JSON, since\n// it treats commas and colons as \"whitespace\", and doesn't care if\n// brackets/braces are correctly paired.  It will raise a ValueError if the\n// input is outside it's specs.\n//\n// Most of the work is parsing the primitives (null, false, true, numbers,\n// strings).  It does 1 pass over the input stream.  It tries to be fast and\n// small in code size, while not using more RAM than necessary.\n\ntypedef struct _ujson_stream_t {\n    mp_obj_t stream_obj;\n    mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);\n    int errcode;\n    byte cur;\n} ujson_stream_t;\n\n#define S_EOF (0) // null is not allowed in json stream so is ok as EOF marker\n#define S_END(s) ((s).cur == S_EOF)\n#define S_CUR(s) ((s).cur)\n#define S_NEXT(s) (ujson_stream_next(&(s)))\n\nSTATIC byte ujson_stream_next(ujson_stream_t *s) {\n    mp_uint_t ret = s->read(s->stream_obj, &s->cur, 1, &s->errcode);\n    if (s->errcode != 0) {\n        mp_raise_OSError(s->errcode);\n    }\n    if (ret == 0) {\n        s->cur = S_EOF;\n    }\n    return s->cur;\n}\n\nSTATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {\n    const mp_stream_p_t *stream_p = mp_get_stream_raise(stream_obj, MP_STREAM_OP_READ);\n    ujson_stream_t s = {stream_obj, stream_p->read, 0, 0};\n    vstr_t vstr;\n    vstr_init(&vstr, 8);\n    mp_obj_list_t stack; // we use a list as a simple stack for nested JSON\n    stack.len = 0;\n    stack.items = NULL;\n    mp_obj_t stack_top = MP_OBJ_NULL;\n    mp_obj_type_t *stack_top_type = NULL;\n    mp_obj_t stack_key = MP_OBJ_NULL;\n    S_NEXT(s);\n    for (;;) {\n        cont:\n        if (S_END(s)) {\n            break;\n        }\n        mp_obj_t next = MP_OBJ_NULL;\n        bool enter = false;\n        byte cur = S_CUR(s);\n        S_NEXT(s);\n        switch (cur) {\n            case ',':\n            case ':':\n            case ' ':\n            case '\\t':\n            case '\\n':\n            case '\\r':\n                goto cont;\n            case 'n':\n                if (S_CUR(s) == 'u' && S_NEXT(s) == 'l' && S_NEXT(s) == 'l') {\n                    S_NEXT(s);\n                    next = mp_const_none;\n                } else {\n                    goto fail;\n                }\n                break;\n            case 'f':\n                if (S_CUR(s) == 'a' && S_NEXT(s) == 'l' && S_NEXT(s) == 's' && S_NEXT(s) == 'e') {\n                    S_NEXT(s);\n                    next = mp_const_false;\n                } else {\n                    goto fail;\n                }\n                break;\n            case 't':\n                if (S_CUR(s) == 'r' && S_NEXT(s) == 'u' && S_NEXT(s) == 'e') {\n                    S_NEXT(s);\n                    next = mp_const_true;\n                } else {\n                    goto fail;\n                }\n                break;\n            case '\"':\n                vstr_reset(&vstr);\n                for (; !S_END(s) && S_CUR(s) != '\"';) {\n                    byte c = S_CUR(s);\n                    if (c == '\\\\') {\n                        c = S_NEXT(s);\n                        switch (c) {\n                            case 'b': c = 0x08; break;\n                            case 'f': c = 0x0c; break;\n                            case 'n': c = 0x0a; break;\n                            case 'r': c = 0x0d; break;\n                            case 't': c = 0x09; break;\n                            case 'u': {\n                                mp_uint_t num = 0;\n                                for (int i = 0; i < 4; i++) {\n                                    c = (S_NEXT(s) | 0x20) - '0';\n                                    if (c > 9) {\n                                        c -= ('a' - ('9' + 1));\n                                    }\n                                    num = (num << 4) | c;\n                                }\n                                vstr_add_char(&vstr, num);\n                                goto str_cont;\n                            }\n                        }\n                    }\n                    vstr_add_byte(&vstr, c);\n                str_cont:\n                    S_NEXT(s);\n                }\n                if (S_END(s)) {\n                    goto fail;\n                }\n                S_NEXT(s);\n                next = mp_obj_new_str(vstr.buf, vstr.len);\n                break;\n            case '-':\n            case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {\n                bool flt = false;\n                vstr_reset(&vstr);\n                for (;;) {\n                    vstr_add_byte(&vstr, cur);\n                    cur = S_CUR(s);\n                    if (cur == '.' || cur == 'E' || cur == 'e') {\n                        flt = true;\n                    } else if (cur == '+' || cur == '-' || unichar_isdigit(cur)) {\n                        // pass\n                    } else {\n                        break;\n                    }\n                    S_NEXT(s);\n                }\n                if (flt) {\n                    next = mp_parse_num_decimal(vstr.buf, vstr.len, false, false, NULL);\n                } else {\n                    next = mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL);\n                }\n                break;\n            }\n            case '[':\n                next = mp_obj_new_list(0, NULL);\n                enter = true;\n                break;\n            case '{':\n                next = mp_obj_new_dict(0);\n                enter = true;\n                break;\n            case '}':\n            case ']': {\n                if (stack_top == MP_OBJ_NULL) {\n                    // no object at all\n                    goto fail;\n                }\n                if (stack.len == 0) {\n                    // finished; compound object\n                    goto success;\n                }\n                stack.len -= 1;\n                stack_top = stack.items[stack.len];\n                stack_top_type = mp_obj_get_type(stack_top);\n                goto cont;\n            }\n            default:\n                goto fail;\n        }\n        if (stack_top == MP_OBJ_NULL) {\n            stack_top = next;\n            stack_top_type = mp_obj_get_type(stack_top);\n            if (!enter) {\n                // finished; single primitive only\n                goto success;\n            }\n        } else {\n            // append to list or dict\n            if (stack_top_type == &mp_type_list) {\n                mp_obj_list_append(stack_top, next);\n            } else {\n                if (stack_key == MP_OBJ_NULL) {\n                    stack_key = next;\n                    if (enter) {\n                        goto fail;\n                    }\n                } else {\n                    mp_obj_dict_store(stack_top, stack_key, next);\n                    stack_key = MP_OBJ_NULL;\n                }\n            }\n            if (enter) {\n                if (stack.items == NULL) {\n                    mp_obj_list_init(&stack, 1);\n                    stack.items[0] = stack_top;\n                } else {\n                    mp_obj_list_append(MP_OBJ_FROM_PTR(&stack), stack_top);\n                }\n                stack_top = next;\n                stack_top_type = mp_obj_get_type(stack_top);\n            }\n        }\n    }\n    success:\n    // eat trailing whitespace\n    while (unichar_isspace(S_CUR(s))) {\n        S_NEXT(s);\n    }\n    if (!S_END(s)) {\n        // unexpected chars\n        goto fail;\n    }\n    if (stack_top == MP_OBJ_NULL || stack.len != 0) {\n        // not exactly 1 object\n        goto fail;\n    }\n    vstr_clear(&vstr);\n    return stack_top;\n\n    fail:\n    mp_raise_ValueError(\"syntax error in JSON\");\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load);\n\nSTATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(obj, &bufinfo, MP_BUFFER_READ);\n    vstr_t vstr = {bufinfo.len, bufinfo.len, (char*)bufinfo.buf, true};\n    mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL};\n    return mod_ujson_load(MP_OBJ_FROM_PTR(&sio));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads);\n\nSTATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) },\n    { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_ujson_dump_obj) },\n    { MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) },\n    { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) },\n    { MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_ujson_globals, mp_module_ujson_globals_table);\n\nconst mp_obj_module_t mp_module_ujson = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_ujson_globals,\n};\n\n#endif //MICROPY_PY_UJSON\n"
  },
  {
    "path": "extmod/modurandom.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_URANDOM\n\n// Yasmarang random number generator\n// by Ilya Levin\n// http://www.literatecode.com/yasmarang\n// Public Domain\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233;\nSTATIC uint8_t yasmarang_dat = 0;\n#endif\n\nSTATIC uint32_t yasmarang(void)\n{\n   yasmarang_pad += yasmarang_dat + yasmarang_d * yasmarang_n;\n   yasmarang_pad = (yasmarang_pad<<3) + (yasmarang_pad>>29);\n   yasmarang_n = yasmarang_pad | 2;\n   yasmarang_d ^= (yasmarang_pad<<31) + (yasmarang_pad>>1);\n   yasmarang_dat ^= (char) yasmarang_pad ^ (yasmarang_d>>8) ^ 1;\n\n   return (yasmarang_pad^(yasmarang_d<<5)^(yasmarang_pad>>18)^(yasmarang_dat<<1));\n}  /* yasmarang */\n\n// End of Yasmarang\n\n#if MICROPY_PY_URANDOM_EXTRA_FUNCS\n\n// returns an unsigned integer below the given argument\n// n must not be zero\nSTATIC uint32_t yasmarang_randbelow(uint32_t n) {\n    uint32_t mask = 1;\n    while ((n & mask) < n) {\n        mask = (mask << 1) | 1;\n    }\n    uint32_t r;\n    do {\n        r = yasmarang() & mask;\n    } while (r >= n);\n    return r;\n}\n\n#endif\n\nSTATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) {\n    int n = mp_obj_get_int(num_in);\n    if (n > 32 || n == 0) {\n        mp_raise_ValueError(NULL);\n    }\n    uint32_t mask = ~0;\n    // Beware of C undefined behavior when shifting by >= than bit size\n    mask >>= (32 - n);\n    return mp_obj_new_int_from_uint(yasmarang() & mask);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_getrandbits_obj, mod_urandom_getrandbits);\n\nSTATIC mp_obj_t mod_urandom_seed(mp_obj_t seed_in) {\n    mp_uint_t seed = mp_obj_get_int_truncated(seed_in);\n    yasmarang_pad = seed;\n    yasmarang_n = 69;\n    yasmarang_d = 233;\n    yasmarang_dat = 0;\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_seed_obj, mod_urandom_seed);\n\n#if MICROPY_PY_URANDOM_EXTRA_FUNCS\n\nSTATIC mp_obj_t mod_urandom_randrange(size_t n_args, const mp_obj_t *args) {\n    mp_int_t start = mp_obj_get_int(args[0]);\n    if (n_args == 1) {\n        // range(stop)\n        if (start > 0) {\n            return mp_obj_new_int(yasmarang_randbelow(start));\n        } else {\n            goto error;\n        }\n    } else {\n        mp_int_t stop = mp_obj_get_int(args[1]);\n        if (n_args == 2) {\n            // range(start, stop)\n            if (start < stop) {\n                return mp_obj_new_int(start + yasmarang_randbelow(stop - start));\n            } else {\n                goto error;\n            }\n        } else {\n            // range(start, stop, step)\n            mp_int_t step = mp_obj_get_int(args[2]);\n            mp_int_t n;\n            if (step > 0) {\n                n = (stop - start + step - 1) / step;\n            } else if (step < 0) {\n                n = (stop - start + step + 1) / step;\n            } else {\n                goto error;\n            }\n            if (n > 0) {\n                return mp_obj_new_int(start + step * yasmarang_randbelow(n));\n            } else {\n                goto error;\n            }\n        }\n    }\n\nerror:\n    mp_raise_ValueError(NULL);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_urandom_randrange_obj, 1, 3, mod_urandom_randrange);\n\nSTATIC mp_obj_t mod_urandom_randint(mp_obj_t a_in, mp_obj_t b_in) {\n    mp_int_t a = mp_obj_get_int(a_in);\n    mp_int_t b = mp_obj_get_int(b_in);\n    if (a <= b) {\n        return mp_obj_new_int(a + yasmarang_randbelow(b - a + 1));\n    } else {\n        mp_raise_ValueError(NULL);\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_randint_obj, mod_urandom_randint);\n\nSTATIC mp_obj_t mod_urandom_choice(mp_obj_t seq) {\n    mp_int_t len = mp_obj_get_int(mp_obj_len(seq));\n    if (len > 0) {\n        return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL);\n    } else {\n        nlr_raise(mp_obj_new_exception(&mp_type_IndexError));\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice);\n\n#if MICROPY_PY_BUILTINS_FLOAT\n\n// returns a number in the range [0..1) using Yasmarang to fill in the fraction bits\nSTATIC mp_float_t yasmarang_float(void) {\n    #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE\n    typedef uint64_t mp_float_int_t;\n    #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n    typedef uint32_t mp_float_int_t;\n    #endif\n    union {\n        mp_float_t f;\n        #if MP_ENDIANNESS_LITTLE\n        struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p;\n        #else\n        struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p;\n        #endif\n    } u;\n    u.p.sgn = 0;\n    u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1;\n    if (MP_FLOAT_FRAC_BITS <= 32) {\n        u.p.frc = yasmarang();\n    } else {\n        u.p.frc = ((uint64_t)yasmarang() << 32) | (uint64_t)yasmarang();\n    }\n    return u.f - 1;\n}\n\nSTATIC mp_obj_t mod_urandom_random(void) {\n    return mp_obj_new_float(yasmarang_float());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom_random_obj, mod_urandom_random);\n\nSTATIC mp_obj_t mod_urandom_uniform(mp_obj_t a_in, mp_obj_t b_in) {\n    mp_float_t a = mp_obj_get_float(a_in);\n    mp_float_t b = mp_obj_get_float(b_in);\n    return mp_obj_new_float(a + (b - a) * yasmarang_float());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_uniform_obj, mod_urandom_uniform);\n\n#endif\n\n#endif // MICROPY_PY_URANDOM_EXTRA_FUNCS\n\n#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC\nSTATIC mp_obj_t mod_urandom___init__() {\n    mod_urandom_seed(MP_OBJ_NEW_SMALL_INT(MICROPY_PY_URANDOM_SEED_INIT_FUNC));\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__);\n#endif\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) },\n    #ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC\n    { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&mod_urandom___init___obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) },\n    { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_urandom_seed_obj) },\n    #if MICROPY_PY_URANDOM_EXTRA_FUNCS\n    { MP_ROM_QSTR(MP_QSTR_randrange), MP_ROM_PTR(&mod_urandom_randrange_obj) },\n    { MP_ROM_QSTR(MP_QSTR_randint), MP_ROM_PTR(&mod_urandom_randint_obj) },\n    { MP_ROM_QSTR(MP_QSTR_choice), MP_ROM_PTR(&mod_urandom_choice_obj) },\n    #if MICROPY_PY_BUILTINS_FLOAT\n    { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_urandom_random_obj) },\n    { MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&mod_urandom_uniform_obj) },\n    #endif\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_urandom_globals, mp_module_urandom_globals_table);\n\nconst mp_obj_module_t mp_module_urandom = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_urandom_globals,\n};\n#endif\n\n#endif //MICROPY_PY_URANDOM\n"
  },
  {
    "path": "extmod/modure.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <assert.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/binary.h\"\n#include \"py/objstr.h\"\n#include \"py/stackctrl.h\"\n\n#if MICROPY_PY_URE\n\n#define re1_5_stack_chk() MP_STACK_CHECK()\n\n#include \"re1.5/re1.5.h\"\n\n#define FLAG_DEBUG 0x1000\n\ntypedef struct _mp_obj_re_t {\n    mp_obj_base_t base;\n    ByteProg re;\n} mp_obj_re_t;\n\ntypedef struct _mp_obj_match_t {\n    mp_obj_base_t base;\n    int num_matches;\n    mp_obj_t str;\n    const char *caps[0];\n} mp_obj_match_t;\n\n\nSTATIC void match_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<match num=%d>\", self->num_matches);\n}\n\nSTATIC mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) {\n    mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_int_t no = mp_obj_get_int(no_in);\n    if (no < 0 || no >= self->num_matches) {\n        nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, no_in));\n    }\n\n    const char *start = self->caps[no * 2];\n    if (start == NULL) {\n        // no match for this group\n        return mp_const_none;\n    }\n    return mp_obj_new_str_of_type(mp_obj_get_type(self->str),\n        (const byte*)start, self->caps[no * 2 + 1] - start);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(match_group_obj, match_group);\n\n#if MICROPY_PY_URE_MATCH_GROUPS\n\nSTATIC mp_obj_t match_groups(mp_obj_t self_in) {\n    mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->num_matches <= 1) {\n        return mp_const_empty_tuple;\n    }\n    mp_obj_tuple_t *groups = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->num_matches - 1, NULL));\n    for (int i = 1; i < self->num_matches; ++i) {\n        groups->items[i - 1] = match_group(self_in, MP_OBJ_NEW_SMALL_INT(i));\n    }\n    return MP_OBJ_FROM_PTR(groups);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(match_groups_obj, match_groups);\n\n#endif\n\n#if MICROPY_PY_URE_MATCH_SPAN_START_END\n\nSTATIC void match_span_helper(size_t n_args, const mp_obj_t *args, mp_obj_t span[2]) {\n    mp_obj_match_t *self = MP_OBJ_TO_PTR(args[0]);\n\n    mp_int_t no = 0;\n    if (n_args == 2) {\n        no = mp_obj_get_int(args[1]);\n        if (no < 0 || no >= self->num_matches) {\n            nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, args[1]));\n        }\n    }\n\n    mp_int_t s = -1;\n    mp_int_t e = -1;\n    const char *start = self->caps[no * 2];\n    if (start != NULL) {\n        // have a match for this group\n        const char *begin = mp_obj_str_get_str(self->str);\n        s = start - begin;\n        e = self->caps[no * 2 + 1] - begin;\n    }\n\n    span[0] = mp_obj_new_int(s);\n    span[1] = mp_obj_new_int(e);\n}\n\nSTATIC mp_obj_t match_span(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t span[2];\n    match_span_helper(n_args, args, span);\n    return mp_obj_new_tuple(2, span);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_span_obj, 1, 2, match_span);\n\nSTATIC mp_obj_t match_start(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t span[2];\n    match_span_helper(n_args, args, span);\n    return span[0];\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_start_obj, 1, 2, match_start);\n\nSTATIC mp_obj_t match_end(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t span[2];\n    match_span_helper(n_args, args, span);\n    return span[1];\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_end_obj, 1, 2, match_end);\n\n#endif\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_rom_map_elem_t match_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_group), MP_ROM_PTR(&match_group_obj) },\n    #if MICROPY_PY_URE_MATCH_GROUPS\n    { MP_ROM_QSTR(MP_QSTR_groups), MP_ROM_PTR(&match_groups_obj) },\n    #endif\n    #if MICROPY_PY_URE_MATCH_SPAN_START_END\n    { MP_ROM_QSTR(MP_QSTR_span), MP_ROM_PTR(&match_span_obj) },\n    { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&match_start_obj) },\n    { MP_ROM_QSTR(MP_QSTR_end), MP_ROM_PTR(&match_end_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);\n\nSTATIC const mp_obj_type_t match_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_match,\n    .print = match_print,\n    .locals_dict = (void*)&match_locals_dict,\n};\n#endif\n\nSTATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_re_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<re %p>\", self);\n}\n\nSTATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {\n    (void)n_args;\n    mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]);\n    Subject subj;\n    size_t len;\n    subj.begin = mp_obj_str_get_data(args[1], &len);\n    subj.end = subj.begin + len;\n    int caps_num = (self->re.sub + 1) * 2;\n    mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, char*, caps_num);\n    // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char\n    memset((char*)match->caps, 0, caps_num * sizeof(char*));\n    int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, is_anchored);\n    if (res == 0) {\n        m_del_var(mp_obj_match_t, char*, caps_num, match);\n        return mp_const_none;\n    }\n\n    match->base.type = &match_type;\n    match->num_matches = caps_num / 2; // caps_num counts start and end pointers\n    match->str = args[1];\n    return MP_OBJ_FROM_PTR(match);\n}\n\nSTATIC mp_obj_t re_match(size_t n_args, const mp_obj_t *args) {\n    return ure_exec(true, n_args, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_match_obj, 2, 4, re_match);\n\nSTATIC mp_obj_t re_search(size_t n_args, const mp_obj_t *args) {\n    return ure_exec(false, n_args, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_search_obj, 2, 4, re_search);\n\nSTATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {\n    mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]);\n    Subject subj;\n    size_t len;\n    const mp_obj_type_t *str_type = mp_obj_get_type(args[1]);\n    subj.begin = mp_obj_str_get_data(args[1], &len);\n    subj.end = subj.begin + len;\n    int caps_num = (self->re.sub + 1) * 2;\n\n    int maxsplit = 0;\n    if (n_args > 2) {\n        maxsplit = mp_obj_get_int(args[2]);\n    }\n\n    mp_obj_t retval = mp_obj_new_list(0, NULL);\n    const char **caps = mp_local_alloc(caps_num * sizeof(char*));\n    while (true) {\n        // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char\n        memset((char**)caps, 0, caps_num * sizeof(char*));\n        int res = re1_5_recursiveloopprog(&self->re, &subj, caps, caps_num, false);\n\n        // if we didn't have a match, or had an empty match, it's time to stop\n        if (!res || caps[0] == caps[1]) {\n            break;\n        }\n\n        mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte*)subj.begin, caps[0] - subj.begin);\n        mp_obj_list_append(retval, s);\n        if (self->re.sub > 0) {\n            mp_raise_NotImplementedError(\"Splitting with sub-captures\");\n        }\n        subj.begin = caps[1];\n        if (maxsplit > 0 && --maxsplit == 0) {\n            break;\n        }\n    }\n    // cast is a workaround for a bug in msvc (see above)\n    mp_local_free((char**)caps);\n\n    mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte*)subj.begin, subj.end - subj.begin);\n    mp_obj_list_append(retval, s);\n    return retval;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_split_obj, 2, 3, re_split);\n\n#if MICROPY_PY_URE_SUB\n\nSTATIC mp_obj_t re_sub_helper(mp_obj_t self_in, size_t n_args, const mp_obj_t *args) {\n    mp_obj_re_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t replace = args[1];\n    mp_obj_t where = args[2];\n    mp_int_t count = 0;\n    if (n_args > 3) {\n        count = mp_obj_get_int(args[3]);\n        // Note: flags are currently ignored\n    }\n\n    size_t where_len;\n    const char *where_str = mp_obj_str_get_data(where, &where_len);\n    Subject subj;\n    subj.begin = where_str;\n    subj.end = subj.begin + where_len;\n    int caps_num = (self->re.sub + 1) * 2;\n\n    vstr_t vstr_return;\n    vstr_return.buf = NULL; // We'll init the vstr after the first match\n    mp_obj_match_t *match = mp_local_alloc(sizeof(mp_obj_match_t) + caps_num * sizeof(char*));\n    match->base.type = &match_type;\n    match->num_matches = caps_num / 2; // caps_num counts start and end pointers\n    match->str = where;\n\n    for (;;) {\n        // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char\n        memset((char*)match->caps, 0, caps_num * sizeof(char*));\n        int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, false);\n\n        // If we didn't have a match, or had an empty match, it's time to stop\n        if (!res || match->caps[0] == match->caps[1]) {\n            break;\n        }\n\n        // Initialise the vstr if it's not already\n        if (vstr_return.buf == NULL) {\n            vstr_init(&vstr_return, match->caps[0] - subj.begin);\n        }\n\n        // Add pre-match string\n        vstr_add_strn(&vstr_return, subj.begin, match->caps[0] - subj.begin);\n\n        // Get replacement string\n        const char* repl = mp_obj_str_get_str((mp_obj_is_callable(replace) ? mp_call_function_1(replace, MP_OBJ_FROM_PTR(match)) : replace));\n\n        // Append replacement string to result, substituting any regex groups\n        while (*repl != '\\0') {\n            if (*repl == '\\\\') {\n                ++repl;\n                bool is_g_format = false;\n                if (*repl == 'g' && repl[1] == '<') {\n                    // Group specified with syntax \"\\g<number>\"\n                    repl += 2;\n                    is_g_format = true;\n                }\n\n                if ('0' <= *repl && *repl <= '9') {\n                    // Group specified with syntax \"\\g<number>\" or \"\\number\"\n                    unsigned int match_no = 0;\n                    do {\n                        match_no = match_no * 10 + (*repl++ - '0');\n                    } while ('0' <= *repl && *repl <= '9');\n                    if (is_g_format && *repl == '>') {\n                        ++repl;\n                    }\n\n                    if (match_no >= (unsigned int)match->num_matches) {\n                        nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no)));\n                    }\n\n                    const char *start_match = match->caps[match_no * 2];\n                    if (start_match != NULL) {\n                        // Add the substring matched by group\n                        const char *end_match = match->caps[match_no * 2 + 1];\n                        vstr_add_strn(&vstr_return, start_match, end_match - start_match);\n                    }\n                }\n            } else {\n                // Just add the current byte from the replacement string\n                vstr_add_byte(&vstr_return, *repl++);\n            }\n        }\n\n        // Move start pointer to end of last match\n        subj.begin = match->caps[1];\n\n        // Stop substitutions if count was given and gets to 0\n        if (count > 0 && --count == 0) {\n            break;\n        }\n    }\n\n    mp_local_free(match);\n\n    if (vstr_return.buf == NULL) {\n        // Optimisation for case of no substitutions\n        return where;\n    }\n\n    // Add post-match string\n    vstr_add_strn(&vstr_return, subj.begin, subj.end - subj.begin);\n\n    return mp_obj_new_str_from_vstr(mp_obj_get_type(where), &vstr_return);\n}\n\nSTATIC mp_obj_t re_sub(size_t n_args, const mp_obj_t *args) {\n    return re_sub_helper(args[0], n_args, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub);\n\n#endif\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_rom_map_elem_t re_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },\n    { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },\n    { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&re_split_obj) },\n    #if MICROPY_PY_URE_SUB\n    { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);\n\nSTATIC const mp_obj_type_t re_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_ure,\n    .print = re_print,\n    .locals_dict = (void*)&re_locals_dict,\n};\n#endif\n\nSTATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n    const char *re_str = mp_obj_str_get_str(args[0]);\n    int size = re1_5_sizecode(re_str);\n    if (size == -1) {\n        goto error;\n    }\n    mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size);\n    o->base.type = &re_type;\n    #if MICROPY_PY_URE_DEBUG\n    int flags = 0;\n    if (n_args > 1) {\n        flags = mp_obj_get_int(args[1]);\n    }\n    #endif\n    int error = re1_5_compilecode(&o->re, re_str);\n    if (error != 0) {\nerror:\n        mp_raise_ValueError(\"Error in regex\");\n    }\n    #if MICROPY_PY_URE_DEBUG\n    if (flags & FLAG_DEBUG) {\n        re1_5_dumpcode(&o->re);\n    }\n    #endif\n    return MP_OBJ_FROM_PTR(o);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);\n\nSTATIC mp_obj_t mod_re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {\n    (void)n_args;\n    mp_obj_t self = mod_re_compile(1, args);\n\n    const mp_obj_t args2[] = {self, args[1]};\n    mp_obj_t match = ure_exec(is_anchored, 2, args2);\n    return match;\n}\n\nSTATIC mp_obj_t mod_re_match(size_t n_args, const mp_obj_t *args) {\n    return mod_re_exec(true, n_args, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_match_obj, 2, 4, mod_re_match);\n\nSTATIC mp_obj_t mod_re_search(size_t n_args, const mp_obj_t *args) {\n    return mod_re_exec(false, n_args, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_search_obj, 2, 4, mod_re_search);\n\n#if MICROPY_PY_URE_SUB\nSTATIC mp_obj_t mod_re_sub(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t self = mod_re_compile(1, args);\n    return re_sub_helper(self, n_args, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub);\n#endif\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ure) },\n    { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) },\n    { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&mod_re_match_obj) },\n    { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&mod_re_search_obj) },\n    #if MICROPY_PY_URE_SUB\n    { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) },\n    #endif\n    #if MICROPY_PY_URE_DEBUG\n    { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table);\n\nconst mp_obj_module_t mp_module_ure = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_re_globals,\n};\n#endif\n\n// Source files #include'd here to make sure they're compiled in\n// only if module is enabled by config setting.\n\n#define re1_5_fatal(x) assert(!x)\n#include \"re1.5/compilecode.c\"\n#if MICROPY_PY_URE_DEBUG\n#include \"re1.5/dumpcode.c\"\n#endif\n#include \"re1.5/recursiveloop.c\"\n#include \"re1.5/charclass.c\"\n\n#endif //MICROPY_PY_URE\n"
  },
  {
    "path": "extmod/moduselect.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n * Copyright (c) 2015-2017 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_PY_USELECT\n\n#include <stdio.h>\n\n#include \"py/runtime.h\"\n#include \"py/obj.h\"\n#include \"py/objlist.h\"\n#include \"py/stream.h\"\n#include \"py/mperrno.h\"\n#include \"py/mphal.h\"\n\n// Flags for poll()\n#define FLAG_ONESHOT (1)\n\n/// \\module select - Provides select function to wait for events on a stream\n///\n/// This module provides the select function.\n\ntypedef struct _poll_obj_t {\n    mp_obj_t obj;\n    mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);\n    mp_uint_t flags;\n    mp_uint_t flags_ret;\n} poll_obj_t;\n\nSTATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t flags, bool or_flags) {\n    for (mp_uint_t i = 0; i < obj_len; i++) {\n        mp_map_elem_t *elem = mp_map_lookup(poll_map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);\n        if (elem->value == MP_OBJ_NULL) {\n            // object not found; get its ioctl and add it to the poll list\n            const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL);\n            poll_obj_t *poll_obj = m_new_obj(poll_obj_t);\n            poll_obj->obj = obj[i];\n            poll_obj->ioctl = stream_p->ioctl;\n            poll_obj->flags = flags;\n            poll_obj->flags_ret = 0;\n            elem->value = MP_OBJ_FROM_PTR(poll_obj);\n        } else {\n            // object exists; update its flags\n            if (or_flags) {\n                ((poll_obj_t*)MP_OBJ_TO_PTR(elem->value))->flags |= flags;\n            } else {\n                ((poll_obj_t*)MP_OBJ_TO_PTR(elem->value))->flags = flags;\n            }\n        }\n    }\n}\n\n// poll each object in the map\nSTATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {\n    mp_uint_t n_ready = 0;\n    for (mp_uint_t i = 0; i < poll_map->alloc; ++i) {\n        if (!mp_map_slot_is_filled(poll_map, i)) {\n            continue;\n        }\n\n        poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map->table[i].value);\n        int errcode;\n        mp_int_t ret = poll_obj->ioctl(poll_obj->obj, MP_STREAM_POLL, poll_obj->flags, &errcode);\n        poll_obj->flags_ret = ret;\n\n        if (ret == -1) {\n            // error doing ioctl\n            mp_raise_OSError(errcode);\n        }\n\n        if (ret != 0) {\n            // object is ready\n            n_ready += 1;\n            if (rwx_num != NULL) {\n                if (ret & MP_STREAM_POLL_RD) {\n                    rwx_num[0] += 1;\n                }\n                if (ret & MP_STREAM_POLL_WR) {\n                    rwx_num[1] += 1;\n                }\n                if ((ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) {\n                    rwx_num[2] += 1;\n                }\n            }\n        }\n    }\n    return n_ready;\n}\n\n/// \\function select(rlist, wlist, xlist[, timeout])\nSTATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {\n    // get array data from tuple/list arguments\n    size_t rwx_len[3];\n    mp_obj_t *r_array, *w_array, *x_array;\n    mp_obj_get_array(args[0], &rwx_len[0], &r_array);\n    mp_obj_get_array(args[1], &rwx_len[1], &w_array);\n    mp_obj_get_array(args[2], &rwx_len[2], &x_array);\n\n    // get timeout\n    mp_uint_t timeout = -1;\n    if (n_args == 4) {\n        if (args[3] != mp_const_none) {\n            #if MICROPY_PY_BUILTINS_FLOAT\n            float timeout_f = mp_obj_get_float(args[3]);\n            if (timeout_f >= 0) {\n                timeout = (mp_uint_t)(timeout_f * 1000);\n            }\n            #else\n            timeout = mp_obj_get_int(args[3]) * 1000;\n            #endif\n        }\n    }\n\n    // merge separate lists and get the ioctl function for each object\n    mp_map_t poll_map;\n    mp_map_init(&poll_map, rwx_len[0] + rwx_len[1] + rwx_len[2]);\n    poll_map_add(&poll_map, r_array, rwx_len[0], MP_STREAM_POLL_RD, true);\n    poll_map_add(&poll_map, w_array, rwx_len[1], MP_STREAM_POLL_WR, true);\n    poll_map_add(&poll_map, x_array, rwx_len[2], MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP, true);\n\n    mp_uint_t start_tick = mp_hal_ticks_ms();\n    rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;\n    for (;;) {\n        // poll the objects\n        mp_uint_t n_ready = poll_map_poll(&poll_map, rwx_len);\n\n        if (n_ready > 0 || (timeout != -1 && mp_hal_ticks_ms() - start_tick >= timeout)) {\n            // one or more objects are ready, or we had a timeout\n            mp_obj_t list_array[3];\n            list_array[0] = mp_obj_new_list(rwx_len[0], NULL);\n            list_array[1] = mp_obj_new_list(rwx_len[1], NULL);\n            list_array[2] = mp_obj_new_list(rwx_len[2], NULL);\n            rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;\n            for (mp_uint_t i = 0; i < poll_map.alloc; ++i) {\n                if (!mp_map_slot_is_filled(&poll_map, i)) {\n                    continue;\n                }\n                poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map.table[i].value);\n                if (poll_obj->flags_ret & MP_STREAM_POLL_RD) {\n                    ((mp_obj_list_t*)MP_OBJ_TO_PTR(list_array[0]))->items[rwx_len[0]++] = poll_obj->obj;\n                }\n                if (poll_obj->flags_ret & MP_STREAM_POLL_WR) {\n                    ((mp_obj_list_t*)MP_OBJ_TO_PTR(list_array[1]))->items[rwx_len[1]++] = poll_obj->obj;\n                }\n                if ((poll_obj->flags_ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) {\n                    ((mp_obj_list_t*)MP_OBJ_TO_PTR(list_array[2]))->items[rwx_len[2]++] = poll_obj->obj;\n                }\n            }\n            mp_map_deinit(&poll_map);\n            return mp_obj_new_tuple(3, list_array);\n        }\n        MICROPY_EVENT_POLL_HOOK\n    }\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);\n\n/// \\class Poll - poll class\n\ntypedef struct _mp_obj_poll_t {\n    mp_obj_base_t base;\n    mp_map_t poll_map;\n    short iter_cnt;\n    short iter_idx;\n    int flags;\n    // callee-owned tuple\n    mp_obj_t ret_tuple;\n} mp_obj_poll_t;\n\n/// \\method register(obj[, eventmask])\nSTATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {\n    mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_uint_t flags;\n    if (n_args == 3) {\n        flags = mp_obj_get_int(args[2]);\n    } else {\n        flags = MP_STREAM_POLL_RD | MP_STREAM_POLL_WR;\n    }\n    poll_map_add(&self->poll_map, &args[1], 1, flags, false);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);\n\n/// \\method unregister(obj)\nSTATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {\n    mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);\n    // TODO raise KeyError if obj didn't exist in map\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);\n\n/// \\method modify(obj, eventmask)\nSTATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {\n    mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);\n    if (elem == NULL) {\n        mp_raise_OSError(MP_ENOENT);\n    }\n    ((poll_obj_t*)MP_OBJ_TO_PTR(elem->value))->flags = mp_obj_get_int(eventmask_in);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify);\n\nSTATIC mp_uint_t poll_poll_internal(uint n_args, const mp_obj_t *args) {\n    mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);\n\n    // work out timeout (its given already in ms)\n    mp_uint_t timeout = -1;\n    int flags = 0;\n    if (n_args >= 2) {\n        if (args[1] != mp_const_none) {\n            mp_int_t timeout_i = mp_obj_get_int(args[1]);\n            if (timeout_i >= 0) {\n                timeout = timeout_i;\n            }\n        }\n        if (n_args >= 3) {\n            flags = mp_obj_get_int(args[2]);\n        }\n    }\n\n    self->flags = flags;\n\n    mp_uint_t start_tick = mp_hal_ticks_ms();\n    mp_uint_t n_ready;\n    for (;;) {\n        // poll the objects\n        n_ready = poll_map_poll(&self->poll_map, NULL);\n        if (n_ready > 0 || (timeout != -1 && mp_hal_ticks_ms() - start_tick >= timeout)) {\n            break;\n        }\n        MICROPY_EVENT_POLL_HOOK\n    }\n\n    return n_ready;\n}\n\nSTATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) {\n    mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_uint_t n_ready = poll_poll_internal(n_args, args);\n\n    // one or more objects are ready, or we had a timeout\n    mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL));\n    n_ready = 0;\n    for (mp_uint_t i = 0; i < self->poll_map.alloc; ++i) {\n        if (!mp_map_slot_is_filled(&self->poll_map, i)) {\n            continue;\n        }\n        poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value);\n        if (poll_obj->flags_ret != 0) {\n            mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret)};\n            ret_list->items[n_ready++] = mp_obj_new_tuple(2, tuple);\n            if (self->flags & FLAG_ONESHOT) {\n                // Don't poll next time, until new event flags will be set explicitly\n                poll_obj->flags = 0;\n            }\n        }\n    }\n    return MP_OBJ_FROM_PTR(ret_list);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 3, poll_poll);\n\nSTATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) {\n    mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);\n\n    if (self->ret_tuple == MP_OBJ_NULL) {\n        self->ret_tuple = mp_obj_new_tuple(2, NULL);\n    }\n\n    int n_ready = poll_poll_internal(n_args, args);\n    self->iter_cnt = n_ready;\n    self->iter_idx = 0;\n\n    return args[0];\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_ipoll_obj, 1, 3, poll_ipoll);\n\nSTATIC mp_obj_t poll_iternext(mp_obj_t self_in) {\n    mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (self->iter_cnt == 0) {\n        return MP_OBJ_STOP_ITERATION;\n    }\n\n    self->iter_cnt--;\n\n    for (mp_uint_t i = self->iter_idx; i < self->poll_map.alloc; ++i) {\n        self->iter_idx++;\n        if (!mp_map_slot_is_filled(&self->poll_map, i)) {\n            continue;\n        }\n        poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value);\n        if (poll_obj->flags_ret != 0) {\n            mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple);\n            t->items[0] = poll_obj->obj;\n            t->items[1] = MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret);\n            if (self->flags & FLAG_ONESHOT) {\n                // Don't poll next time, until new event flags will be set explicitly\n                poll_obj->flags = 0;\n            }\n            return MP_OBJ_FROM_PTR(t);\n        }\n    }\n\n    assert(!\"inconsistent number of poll active entries\");\n    self->iter_cnt = 0;\n    return MP_OBJ_STOP_ITERATION;\n}\n\nSTATIC const mp_rom_map_elem_t poll_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) },\n    { MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&poll_unregister_obj) },\n    { MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) },\n    { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table);\n\nSTATIC const mp_obj_type_t mp_type_poll = {\n    { &mp_type_type },\n    .name = MP_QSTR_poll,\n    .getiter = mp_identity_getiter,\n    .iternext = poll_iternext,\n    .locals_dict = (void*)&poll_locals_dict,\n};\n\n/// \\function poll()\nSTATIC mp_obj_t select_poll(void) {\n    mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t);\n    poll->base.type = &mp_type_poll;\n    mp_map_init(&poll->poll_map, 0);\n    poll->iter_cnt = 0;\n    poll->ret_tuple = MP_OBJ_NULL;\n    return MP_OBJ_FROM_PTR(poll);\n}\nMP_DEFINE_CONST_FUN_OBJ_0(mp_select_poll_obj, select_poll);\n\nSTATIC const mp_rom_map_elem_t mp_module_select_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uselect) },\n    { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_select_select_obj) },\n    { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mp_select_poll_obj) },\n    { MP_ROM_QSTR(MP_QSTR_POLLIN), MP_ROM_INT(MP_STREAM_POLL_RD) },\n    { MP_ROM_QSTR(MP_QSTR_POLLOUT), MP_ROM_INT(MP_STREAM_POLL_WR) },\n    { MP_ROM_QSTR(MP_QSTR_POLLERR), MP_ROM_INT(MP_STREAM_POLL_ERR) },\n    { MP_ROM_QSTR(MP_QSTR_POLLHUP), MP_ROM_INT(MP_STREAM_POLL_HUP) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_select_globals, mp_module_select_globals_table);\n\nconst mp_obj_module_t mp_module_uselect = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_select_globals,\n};\n\n#endif // MICROPY_PY_USELECT\n"
  },
  {
    "path": "extmod/modussl_axtls.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015-2019 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n#include \"py/objstr.h\"\n\n#if MICROPY_PY_USSL && MICROPY_SSL_AXTLS\n\n#include \"ssl.h\"\n\ntypedef struct _mp_obj_ssl_socket_t {\n    mp_obj_base_t base;\n    mp_obj_t sock;\n    SSL_CTX *ssl_ctx;\n    SSL *ssl_sock;\n    byte *buf;\n    uint32_t bytes_left;\n    bool blocking;\n} mp_obj_ssl_socket_t;\n\nstruct ssl_args {\n    mp_arg_val_t key;\n    mp_arg_val_t cert;\n    mp_arg_val_t server_side;\n    mp_arg_val_t server_hostname;\n    mp_arg_val_t do_handshake;\n};\n\nSTATIC const mp_obj_type_t ussl_socket_type;\n\n// Table of error strings corresponding to SSL_xxx error codes.\nSTATIC const char *const ssl_error_tab1[] = {\n    \"NOT_OK\",\n    \"DEAD\",\n    \"CLOSE_NOTIFY\",\n    \"EAGAIN\",\n};\nSTATIC const char *const ssl_error_tab2[] = {\n    \"CONN_LOST\",\n    \"RECORD_OVERFLOW\",\n    \"SOCK_SETUP_FAILURE\",\n    NULL,\n    \"INVALID_HANDSHAKE\",\n    \"INVALID_PROT_MSG\",\n    \"INVALID_HMAC\",\n    \"INVALID_VERSION\",\n    \"UNSUPPORTED_EXTENSION\",\n    \"INVALID_SESSION\",\n    \"NO_CIPHER\",\n    \"INVALID_CERT_HASH_ALG\",\n    \"BAD_CERTIFICATE\",\n    \"INVALID_KEY\",\n    NULL,\n    \"FINISHED_INVALID\",\n    \"NO_CERT_DEFINED\",\n    \"NO_CLIENT_RENOG\",\n    \"NOT_SUPPORTED\",\n};\n\nSTATIC NORETURN void ussl_raise_error(int err) {\n    MP_STATIC_ASSERT(SSL_NOT_OK - 3 == SSL_EAGAIN);\n    MP_STATIC_ASSERT(SSL_ERROR_CONN_LOST - 18 == SSL_ERROR_NOT_SUPPORTED);\n\n    // Check if err corresponds to something in one of the error string tables.\n    const char *errstr = NULL;\n    if (SSL_NOT_OK >= err && err >= SSL_EAGAIN) {\n        errstr = ssl_error_tab1[SSL_NOT_OK - err];\n    } else if (SSL_ERROR_CONN_LOST >= err && err >= SSL_ERROR_NOT_SUPPORTED) {\n        errstr = ssl_error_tab2[SSL_ERROR_CONN_LOST - err];\n    }\n\n    // Unknown error, just raise the error code.\n    if (errstr == NULL) {\n        mp_raise_OSError(err);\n    }\n\n    // Construct string object.\n    mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);\n    if (o_str == NULL) {\n        mp_raise_OSError(err);\n    }\n    o_str->base.type = &mp_type_str;\n    o_str->data = (const byte *)errstr;\n    o_str->len = strlen((char *)o_str->data);\n    o_str->hash = qstr_compute_hash(o_str->data, o_str->len);\n\n    // Raise OSError(err, str).\n    mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), MP_OBJ_FROM_PTR(o_str)};\n    nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args));\n}\n\n\nSTATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args) {\n    #if MICROPY_PY_USSL_FINALISER\n    mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);\n    #else\n    mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);\n    #endif\n    o->base.type = &ussl_socket_type;\n    o->buf = NULL;\n    o->bytes_left = 0;\n    o->sock = sock;\n    o->blocking = true;\n\n    uint32_t options = SSL_SERVER_VERIFY_LATER;\n    if (!args->do_handshake.u_bool) {\n        options |= SSL_CONNECT_IN_PARTS;\n    }\n    if (args->key.u_obj != mp_const_none) {\n        options |= SSL_NO_DEFAULT_KEY;\n    }\n    if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) {\n        mp_raise_OSError(MP_EINVAL);\n    }\n\n    if (args->key.u_obj != mp_const_none) {\n        size_t len;\n        const byte *data = (const byte *)mp_obj_str_get_data(args->key.u_obj, &len);\n        int res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_RSA_KEY, data, len, NULL);\n        if (res != SSL_OK) {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"invalid key\"));\n        }\n\n        data = (const byte *)mp_obj_str_get_data(args->cert.u_obj, &len);\n        res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_X509_CERT, data, len, NULL);\n        if (res != SSL_OK) {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"invalid cert\"));\n        }\n    }\n\n    if (args->server_side.u_bool) {\n        o->ssl_sock = ssl_server_new(o->ssl_ctx, (long)sock);\n    } else {\n        SSL_EXTENSIONS *ext = ssl_ext_new();\n\n        if (args->server_hostname.u_obj != mp_const_none) {\n            ext->host_name = (char *)mp_obj_str_get_str(args->server_hostname.u_obj);\n        }\n\n        o->ssl_sock = ssl_client_new(o->ssl_ctx, (long)sock, NULL, 0, ext);\n\n        if (args->do_handshake.u_bool) {\n            int res = ssl_handshake_status(o->ssl_sock);\n\n            if (res != SSL_OK) {\n                ussl_raise_error(res);\n            }\n        }\n\n    }\n\n    return o;\n}\n\nSTATIC void ussl_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<_SSLSocket %p>\", self->ssl_sock);\n}\n\nSTATIC mp_uint_t ussl_socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);\n\n    if (o->ssl_sock == NULL) {\n        *errcode = EBADF;\n        return MP_STREAM_ERROR;\n    }\n\n    while (o->bytes_left == 0) {\n        mp_int_t r = ssl_read(o->ssl_sock, &o->buf);\n        if (r == SSL_OK) {\n            // SSL_OK from ssl_read() means \"everything is ok, but there's\n            // no user data yet\". It may happen e.g. if handshake is not\n            // finished yet. The best way we can treat it is by returning\n            // EAGAIN. This may be a bit unexpected in blocking mode, but\n            // default is to perform complete handshake in constructor, so\n            // this should not happen in blocking mode. On the other hand,\n            // in nonblocking mode EAGAIN (comparing to the alternative of\n            // looping) is really preferrable.\n            if (o->blocking) {\n                continue;\n            } else {\n                goto eagain;\n            }\n        }\n        if (r < 0) {\n            if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) {\n                // EOF\n                return 0;\n            }\n            if (r == SSL_EAGAIN) {\n            eagain:\n                r = MP_EAGAIN;\n            }\n            *errcode = r;\n            return MP_STREAM_ERROR;\n        }\n        o->bytes_left = r;\n    }\n\n    if (size > o->bytes_left) {\n        size = o->bytes_left;\n    }\n    memcpy(buf, o->buf, size);\n    o->buf += size;\n    o->bytes_left -= size;\n    return size;\n}\n\nSTATIC mp_uint_t ussl_socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);\n\n    if (o->ssl_sock == NULL) {\n        *errcode = EBADF;\n        return MP_STREAM_ERROR;\n    }\n\n    mp_int_t r = ssl_write(o->ssl_sock, buf, size);\n    if (r < 0) {\n        *errcode = r;\n        return MP_STREAM_ERROR;\n    }\n    return r;\n}\n\nSTATIC mp_uint_t ussl_socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);\n    if (request == MP_STREAM_CLOSE && self->ssl_sock != NULL) {\n        ssl_free(self->ssl_sock);\n        ssl_ctx_free(self->ssl_ctx);\n        self->ssl_sock = NULL;\n    }\n    // Pass all requests down to the underlying socket\n    return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode);\n}\n\nSTATIC mp_obj_t ussl_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {\n    mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t sock = o->sock;\n    mp_obj_t dest[3];\n    mp_load_method(sock, MP_QSTR_setblocking, dest);\n    dest[2] = flag_in;\n    mp_obj_t res = mp_call_method_n_kw(1, 0, dest);\n    o->blocking = mp_obj_is_true(flag_in);\n    return res;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(ussl_socket_setblocking_obj, ussl_socket_setblocking);\n\nSTATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&ussl_socket_setblocking_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },\n    #if MICROPY_PY_USSL_FINALISER\n    { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);\n\nSTATIC const mp_stream_p_t ussl_socket_stream_p = {\n    .read = ussl_socket_read,\n    .write = ussl_socket_write,\n    .ioctl = ussl_socket_ioctl,\n};\n\nSTATIC const mp_obj_type_t ussl_socket_type = {\n    { &mp_type_type },\n    // Save on qstr's, reuse same as for module\n    .name = MP_QSTR_ussl,\n    .print = ussl_socket_print,\n    .getiter = NULL,\n    .iternext = NULL,\n    .protocol = &ussl_socket_stream_p,\n    .locals_dict = (void *)&ussl_socket_locals_dict,\n};\n\nSTATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    // TODO: Implement more args\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },\n        { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },\n    };\n\n    // TODO: Check that sock implements stream protocol\n    mp_obj_t sock = pos_args[0];\n\n    struct ssl_args args;\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,\n        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);\n\n    return MP_OBJ_FROM_PTR(ussl_socket_new(sock, &args));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);\n\nSTATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) },\n    { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);\n\nconst mp_obj_module_t mp_module_ussl = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_ssl_globals,\n};\n\n#endif // MICROPY_PY_USSL\n"
  },
  {
    "path": "extmod/modussl_mbedtls.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Linaro Ltd.\n * Copyright (c) 2019 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_PY_USSL && MICROPY_SSL_MBEDTLS\n\n#include <stdio.h>\n#include <string.h>\n#include <errno.h> // needed because mp_is_nonblocking_error uses system error codes\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n#include \"py/objstr.h\"\n\n// mbedtls_time_t\n#include \"mbedtls/platform.h\"\n#include \"mbedtls/ssl.h\"\n#include \"mbedtls/x509_crt.h\"\n#include \"mbedtls/pk.h\"\n#include \"mbedtls/entropy.h\"\n#include \"mbedtls/ctr_drbg.h\"\n#include \"mbedtls/debug.h\"\n#include \"mbedtls/error.h\"\n\ntypedef struct _mp_obj_ssl_socket_t {\n    mp_obj_base_t base;\n    mp_obj_t sock;\n    mbedtls_entropy_context entropy;\n    mbedtls_ctr_drbg_context ctr_drbg;\n    mbedtls_ssl_context ssl;\n    mbedtls_ssl_config conf;\n    mbedtls_x509_crt cacert;\n    mbedtls_x509_crt cert;\n    mbedtls_pk_context pkey;\n} mp_obj_ssl_socket_t;\n\nstruct ssl_args {\n    mp_arg_val_t key;\n    mp_arg_val_t cert;\n    mp_arg_val_t server_side;\n    mp_arg_val_t server_hostname;\n    mp_arg_val_t do_handshake;\n};\n\nSTATIC const mp_obj_type_t ussl_socket_type;\n\n#ifdef MBEDTLS_DEBUG_C\nSTATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) {\n    (void)ctx;\n    (void)level;\n    printf(\"DBG:%s:%04d: %s\\n\", file, line, str);\n}\n#endif\n\nSTATIC NORETURN void mbedtls_raise_error(int err) {\n    // _mbedtls_ssl_send and _mbedtls_ssl_recv (below) turn positive error codes from the\n    // underlying socket into negative codes to pass them through mbedtls. Here we turn them\n    // positive again so they get interpreted as the OSError they really are. The\n    // cut-off of -256 is a bit hacky, sigh.\n    if (err < 0 && err > -256) {\n        mp_raise_OSError(-err);\n    }\n\n    #if defined(MBEDTLS_ERROR_C)\n    // Including mbedtls_strerror takes about 1.5KB due to the error strings.\n    // MBEDTLS_ERROR_C is the define used by mbedtls to conditionally include mbedtls_strerror.\n    // It is set/unset in the MBEDTLS_CONFIG_FILE which is defined in the Makefile.\n\n    // Try to allocate memory for the message\n    #define ERR_STR_MAX 80  // mbedtls_strerror truncates if it doesn't fit\n    mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);\n    byte *o_str_buf = m_new_maybe(byte, ERR_STR_MAX);\n    if (o_str == NULL || o_str_buf == NULL) {\n        mp_raise_OSError(err);\n    }\n\n    // print the error message into the allocated buffer\n    mbedtls_strerror(err, (char *)o_str_buf, ERR_STR_MAX);\n    size_t len = strlen((char *)o_str_buf);\n\n    // Put the exception object together\n    o_str->base.type = &mp_type_str;\n    o_str->data = o_str_buf;\n    o_str->len = len;\n    o_str->hash = qstr_compute_hash(o_str->data, o_str->len);\n    // raise\n    mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), MP_OBJ_FROM_PTR(o_str)};\n    nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args));\n    #else\n    // mbedtls is compiled without error strings so we simply return the err number\n    mp_raise_OSError(err); // err is typically a large negative number\n    #endif\n}\n\nSTATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {\n    mp_obj_t sock = *(mp_obj_t *)ctx;\n\n    const mp_stream_p_t *sock_stream = mp_get_stream(sock);\n    int err;\n\n    mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err);\n    if (out_sz == MP_STREAM_ERROR) {\n        if (mp_is_nonblocking_error(err)) {\n            return MBEDTLS_ERR_SSL_WANT_WRITE;\n        }\n        return -err; // convert an MP_ERRNO to something mbedtls passes through as error\n    } else {\n        return out_sz;\n    }\n}\n\nSTATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {\n    mp_obj_t sock = *(mp_obj_t *)ctx;\n\n    const mp_stream_p_t *sock_stream = mp_get_stream(sock);\n    int err;\n\n    mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err);\n    if (out_sz == MP_STREAM_ERROR) {\n        if (mp_is_nonblocking_error(err)) {\n            return MBEDTLS_ERR_SSL_WANT_READ;\n        }\n        return -err;\n    } else {\n        return out_sz;\n    }\n}\n\n\nSTATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {\n    // Verify the socket object has the full stream protocol\n    mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);\n\n    #if MICROPY_PY_USSL_FINALISER\n    mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);\n    #else\n    mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);\n    #endif\n    o->base.type = &ussl_socket_type;\n    o->sock = sock;\n\n    int ret;\n    mbedtls_ssl_init(&o->ssl);\n    mbedtls_ssl_config_init(&o->conf);\n    mbedtls_x509_crt_init(&o->cacert);\n    mbedtls_x509_crt_init(&o->cert);\n    mbedtls_pk_init(&o->pkey);\n    mbedtls_ctr_drbg_init(&o->ctr_drbg);\n    #ifdef MBEDTLS_DEBUG_C\n    // Debug level (0-4)\n    mbedtls_debug_set_threshold(0);\n    #endif\n\n    mbedtls_entropy_init(&o->entropy);\n    const byte seed[] = \"upy\";\n    ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed));\n    if (ret != 0) {\n        goto cleanup;\n    }\n\n    ret = mbedtls_ssl_config_defaults(&o->conf,\n        args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,\n        MBEDTLS_SSL_TRANSPORT_STREAM,\n        MBEDTLS_SSL_PRESET_DEFAULT);\n    if (ret != 0) {\n        goto cleanup;\n    }\n\n    mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE);\n    mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg);\n    #ifdef MBEDTLS_DEBUG_C\n    mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL);\n    #endif\n\n    ret = mbedtls_ssl_setup(&o->ssl, &o->conf);\n    if (ret != 0) {\n        goto cleanup;\n    }\n\n    if (args->server_hostname.u_obj != mp_const_none) {\n        const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj);\n        ret = mbedtls_ssl_set_hostname(&o->ssl, sni);\n        if (ret != 0) {\n            goto cleanup;\n        }\n    }\n\n    mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);\n\n    if (args->key.u_obj != mp_const_none) {\n        size_t key_len;\n        const byte *key = (const byte *)mp_obj_str_get_data(args->key.u_obj, &key_len);\n        // len should include terminating null\n        ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0);\n        if (ret != 0) {\n            ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors\n            goto cleanup;\n        }\n\n        size_t cert_len;\n        const byte *cert = (const byte *)mp_obj_str_get_data(args->cert.u_obj, &cert_len);\n        // len should include terminating null\n        ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1);\n        if (ret != 0) {\n            ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; // use general error for all cert errors\n            goto cleanup;\n        }\n\n        ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey);\n        if (ret != 0) {\n            goto cleanup;\n        }\n    }\n\n    if (args->do_handshake.u_bool) {\n        while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {\n            if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {\n                goto cleanup;\n            }\n        }\n    }\n\n    return o;\n\ncleanup:\n    mbedtls_pk_free(&o->pkey);\n    mbedtls_x509_crt_free(&o->cert);\n    mbedtls_x509_crt_free(&o->cacert);\n    mbedtls_ssl_free(&o->ssl);\n    mbedtls_ssl_config_free(&o->conf);\n    mbedtls_ctr_drbg_free(&o->ctr_drbg);\n    mbedtls_entropy_free(&o->entropy);\n\n    if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) {\n        mp_raise_OSError(MP_ENOMEM);\n    } else if (ret == MBEDTLS_ERR_PK_BAD_INPUT_DATA) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"invalid key\"));\n    } else if (ret == MBEDTLS_ERR_X509_BAD_INPUT_DATA) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"invalid cert\"));\n    } else {\n        mbedtls_raise_error(ret);\n    }\n}\n\nSTATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) {\n    mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);\n    if (!mp_obj_is_true(binary_form)) {\n        mp_raise_NotImplementedError(NULL);\n    }\n    const mbedtls_x509_crt *peer_cert = mbedtls_ssl_get_peer_cert(&o->ssl);\n    if (peer_cert == NULL) {\n        return mp_const_none;\n    }\n    return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert);\n\nSTATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<_SSLSocket %p>\", self);\n}\n\nSTATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);\n\n    int ret = mbedtls_ssl_read(&o->ssl, buf, size);\n    if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {\n        // end of stream\n        return 0;\n    }\n    if (ret >= 0) {\n        return ret;\n    }\n    if (ret == MBEDTLS_ERR_SSL_WANT_READ) {\n        ret = MP_EWOULDBLOCK;\n    } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {\n        // If handshake is not finished, read attempt may end up in protocol\n        // wanting to write next handshake message. The same may happen with\n        // renegotation.\n        ret = MP_EWOULDBLOCK;\n    }\n    *errcode = ret;\n    return MP_STREAM_ERROR;\n}\n\nSTATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);\n\n    int ret = mbedtls_ssl_write(&o->ssl, buf, size);\n    if (ret >= 0) {\n        return ret;\n    }\n    if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {\n        ret = MP_EWOULDBLOCK;\n    } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) {\n        // If handshake is not finished, write attempt may end up in protocol\n        // wanting to read next handshake message. The same may happen with\n        // renegotation.\n        ret = MP_EWOULDBLOCK;\n    }\n    *errcode = ret;\n    return MP_STREAM_ERROR;\n}\n\nSTATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {\n    mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t sock = o->sock;\n    mp_obj_t dest[3];\n    mp_load_method(sock, MP_QSTR_setblocking, dest);\n    dest[2] = flag_in;\n    return mp_call_method_n_kw(1, 0, dest);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);\n\nSTATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);\n    if (request == MP_STREAM_CLOSE) {\n        mbedtls_pk_free(&self->pkey);\n        mbedtls_x509_crt_free(&self->cert);\n        mbedtls_x509_crt_free(&self->cacert);\n        mbedtls_ssl_free(&self->ssl);\n        mbedtls_ssl_config_free(&self->conf);\n        mbedtls_ctr_drbg_free(&self->ctr_drbg);\n        mbedtls_entropy_free(&self->entropy);\n    }\n    // Pass all requests down to the underlying socket\n    return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode);\n}\n\nSTATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },\n    #if MICROPY_PY_USSL_FINALISER\n    { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);\n\nSTATIC const mp_stream_p_t ussl_socket_stream_p = {\n    .read = socket_read,\n    .write = socket_write,\n    .ioctl = socket_ioctl,\n};\n\nSTATIC const mp_obj_type_t ussl_socket_type = {\n    { &mp_type_type },\n    // Save on qstr's, reuse same as for module\n    .name = MP_QSTR_ussl,\n    .print = socket_print,\n    .getiter = NULL,\n    .iternext = NULL,\n    .protocol = &ussl_socket_stream_p,\n    .locals_dict = (void *)&ussl_socket_locals_dict,\n};\n\nSTATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    // TODO: Implement more args\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },\n        { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },\n    };\n\n    // TODO: Check that sock implements stream protocol\n    mp_obj_t sock = pos_args[0];\n\n    struct ssl_args args;\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,\n        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);\n\n    return MP_OBJ_FROM_PTR(socket_new(sock, &args));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);\n\nSTATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) },\n    { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);\n\nconst mp_obj_module_t mp_module_ussl = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_ssl_globals,\n};\n\n#endif // MICROPY_PY_USSL\n"
  },
  {
    "path": "extmod/modutimeq.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n * Copyright (c) 2016-2017 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n\n#include \"py/objlist.h\"\n#include \"py/runtime.h\"\n#include \"py/smallint.h\"\n\n#if MICROPY_PY_UTIMEQ\n\n#define MODULO MICROPY_PY_UTIME_TICKS_PERIOD\n\n#define DEBUG 0\n\n// the algorithm here is modelled on CPython's heapq.py\n\nstruct qentry {\n    mp_uint_t time;\n    mp_uint_t id;\n    mp_obj_t callback;\n    mp_obj_t args;\n};\n\ntypedef struct _mp_obj_utimeq_t {\n    mp_obj_base_t base;\n    mp_uint_t alloc;\n    mp_uint_t len;\n    struct qentry items[];\n} mp_obj_utimeq_t;\n\nSTATIC mp_uint_t utimeq_id;\n\nSTATIC mp_obj_utimeq_t *utimeq_get_heap(mp_obj_t heap_in) {\n    return MP_OBJ_TO_PTR(heap_in);\n}\n\nSTATIC bool time_less_than(struct qentry *item, struct qentry *parent) {\n    mp_uint_t item_tm = item->time;\n    mp_uint_t parent_tm = parent->time;\n    mp_uint_t res = parent_tm - item_tm;\n    if (res == 0) {\n        // TODO: This actually should use the same \"ring\" logic\n        // as for time, to avoid artifacts when id's overflow.\n        return item->id < parent->id;\n    }\n    if ((mp_int_t)res < 0) {\n        res += MODULO;\n    }\n    return res && res < (MODULO / 2);\n}\n\nSTATIC mp_obj_t utimeq_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 1, 1, false);\n    mp_uint_t alloc = mp_obj_get_int(args[0]);\n    mp_obj_utimeq_t *o = m_new_obj_var(mp_obj_utimeq_t, struct qentry, alloc);\n    o->base.type = type;\n    memset(o->items, 0, sizeof(*o->items) * alloc);\n    o->alloc = alloc;\n    o->len = 0;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC void utimeq_heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) {\n    struct qentry item = heap->items[pos];\n    while (pos > start_pos) {\n        mp_uint_t parent_pos = (pos - 1) >> 1;\n        struct qentry *parent = &heap->items[parent_pos];\n        bool lessthan = time_less_than(&item, parent);\n        if (lessthan) {\n            heap->items[pos] = *parent;\n            pos = parent_pos;\n        } else {\n            break;\n        }\n    }\n    heap->items[pos] = item;\n}\n\nSTATIC void utimeq_heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) {\n    mp_uint_t start_pos = pos;\n    mp_uint_t end_pos = heap->len;\n    struct qentry item = heap->items[pos];\n    for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {\n        // choose right child if it's <= left child\n        if (child_pos + 1 < end_pos) {\n            bool lessthan = time_less_than(&heap->items[child_pos], &heap->items[child_pos + 1]);\n            if (!lessthan) {\n                child_pos += 1;\n            }\n        }\n        // bubble up the smaller child\n        heap->items[pos] = heap->items[child_pos];\n        pos = child_pos;\n    }\n    heap->items[pos] = item;\n    utimeq_heap_siftdown(heap, start_pos, pos);\n}\n\nSTATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n    mp_obj_t heap_in = args[0];\n    mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);\n    if (heap->len == heap->alloc) {\n        mp_raise_msg(&mp_type_IndexError, \"queue overflow\");\n    }\n    mp_uint_t l = heap->len;\n    heap->items[l].time = MP_OBJ_SMALL_INT_VALUE(args[1]);\n    heap->items[l].id = utimeq_id++;\n    heap->items[l].callback = args[2];\n    heap->items[l].args = args[3];\n    utimeq_heap_siftdown(heap, 0, heap->len);\n    heap->len++;\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_utimeq_heappush);\n\nSTATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {\n    mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);\n    if (heap->len == 0) {\n        mp_raise_msg(&mp_type_IndexError, \"empty heap\");\n    }\n    mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);\n    if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) {\n        mp_raise_TypeError(NULL);\n    }\n\n    struct qentry *item = &heap->items[0];\n    ret->items[0] = MP_OBJ_NEW_SMALL_INT(item->time);\n    ret->items[1] = item->callback;\n    ret->items[2] = item->args;\n    heap->len -= 1;\n    heap->items[0] = heap->items[heap->len];\n    heap->items[heap->len].callback = MP_OBJ_NULL; // so we don't retain a pointer\n    heap->items[heap->len].args = MP_OBJ_NULL;\n    if (heap->len) {\n        utimeq_heap_siftup(heap, 0);\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop);\n\nSTATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) {\n    mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);\n    if (heap->len == 0) {\n        mp_raise_msg(&mp_type_IndexError, \"empty heap\");\n    }\n\n    struct qentry *item = &heap->items[0];\n    return MP_OBJ_NEW_SMALL_INT(item->time);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_peektime_obj, mod_utimeq_peektime);\n\n#if DEBUG\nSTATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) {\n    mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);\n    for (int i = 0; i < heap->len; i++) {\n        printf(UINT_FMT \"\\t%p\\t%p\\n\", heap->items[i].time,\n            MP_OBJ_TO_PTR(heap->items[i].callback), MP_OBJ_TO_PTR(heap->items[i].args));\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_dump_obj, mod_utimeq_dump);\n#endif\n\nSTATIC mp_obj_t utimeq_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n    mp_obj_utimeq_t *self = MP_OBJ_TO_PTR(self_in);\n    switch (op) {\n        case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0);\n        case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len);\n        default: return MP_OBJ_NULL; // op not supported\n    }\n}\n\nSTATIC const mp_rom_map_elem_t utimeq_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_push), MP_ROM_PTR(&mod_utimeq_heappush_obj) },\n    { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&mod_utimeq_heappop_obj) },\n    { MP_ROM_QSTR(MP_QSTR_peektime), MP_ROM_PTR(&mod_utimeq_peektime_obj) },\n    #if DEBUG\n    { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_utimeq_dump_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(utimeq_locals_dict, utimeq_locals_dict_table);\n\nSTATIC const mp_obj_type_t utimeq_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_utimeq,\n    .make_new = utimeq_make_new,\n    .unary_op = utimeq_unary_op,\n    .locals_dict = (void*)&utimeq_locals_dict,\n};\n\nSTATIC const mp_rom_map_elem_t mp_module_utimeq_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utimeq) },\n    { MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&utimeq_type) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_utimeq_globals, mp_module_utimeq_globals_table);\n\nconst mp_obj_module_t mp_module_utimeq = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_utimeq_globals,\n};\n\n#endif //MICROPY_PY_UTIMEQ\n"
  },
  {
    "path": "extmod/moduwebsocket.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n#include \"extmod/moduwebsocket.h\"\n\n#if MICROPY_PY_UWEBSOCKET\n\nenum { FRAME_HEADER, FRAME_OPT, PAYLOAD, CONTROL };\n\nenum { BLOCKING_WRITE = 0x80 };\n\ntypedef struct _mp_obj_websocket_t {\n    mp_obj_base_t base;\n    mp_obj_t sock;\n    uint32_t msg_sz;\n    byte mask[4];\n    byte state;\n    byte to_recv;\n    byte mask_pos;\n    byte buf_pos;\n    byte buf[6];\n    byte opts;\n    // Copy of last data frame flags\n    byte ws_flags;\n    // Copy of current frame flags\n    byte last_flags;\n} mp_obj_websocket_t;\n\nSTATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode);\n\nSTATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 1, 2, false);\n    mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);\n    mp_obj_websocket_t *o = m_new_obj(mp_obj_websocket_t);\n    o->base.type = type;\n    o->sock = args[0];\n    o->state = FRAME_HEADER;\n    o->to_recv = 2;\n    o->mask_pos = 0;\n    o->buf_pos = 0;\n    o->opts = FRAME_TXT;\n    if (n_args > 1 && args[1] == mp_const_true) {\n        o->opts |= BLOCKING_WRITE;\n    }\n    return  MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_websocket_t *self =  MP_OBJ_TO_PTR(self_in);\n    const mp_stream_p_t *stream_p = mp_get_stream(self->sock);\n    while (1) {\n        if (self->to_recv != 0) {\n            mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode);\n            if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {\n                return out_sz;\n            }\n            self->buf_pos += out_sz;\n            self->to_recv -= out_sz;\n            if (self->to_recv != 0) {\n                *errcode = MP_EAGAIN;\n                return MP_STREAM_ERROR;\n            }\n        }\n\n        switch (self->state) {\n            case FRAME_HEADER: {\n                // TODO: Split frame handling below is untested so far, so conservatively disable it\n                assert(self->buf[0] & 0x80);\n\n                // \"Control frames MAY be injected in the middle of a fragmented message.\"\n                // So, they must be processed before data frames (and not alter\n                // self->ws_flags)\n                byte frame_type = self->buf[0];\n                self->last_flags = frame_type;\n                frame_type &= FRAME_OPCODE_MASK;\n\n                if ((self->buf[0] & FRAME_OPCODE_MASK) == FRAME_CONT) {\n                    // Preserve previous frame type\n                    self->ws_flags = (self->ws_flags & FRAME_OPCODE_MASK) | (self->buf[0] & ~FRAME_OPCODE_MASK);\n                } else {\n                    self->ws_flags = self->buf[0];\n                }\n\n                // Reset mask in case someone will use \"simplified\" protocol\n                // without masks.\n                memset(self->mask, 0, sizeof(self->mask));\n\n                int to_recv = 0;\n                size_t sz = self->buf[1] & 0x7f;\n                if (sz == 126) {\n                    // Msg size is next 2 bytes\n                    to_recv += 2;\n                } else if (sz == 127) {\n                    // Msg size is next 8 bytes\n                    assert(0);\n                }\n                if (self->buf[1] & 0x80) {\n                    // Next 4 bytes is mask\n                    to_recv += 4;\n                }\n\n                self->buf_pos = 0;\n                self->to_recv = to_recv;\n                self->msg_sz = sz; // May be overridden by FRAME_OPT\n                if (to_recv != 0) {\n                    self->state = FRAME_OPT;\n                } else {\n                    if (frame_type >= FRAME_CLOSE) {\n                        self->state = CONTROL;\n                    } else {\n                        self->state = PAYLOAD;\n                    }\n                }\n                continue;\n            }\n\n            case FRAME_OPT: {\n                if ((self->buf_pos & 3) == 2) {\n                    // First two bytes are message length\n                    self->msg_sz = (self->buf[0] << 8) | self->buf[1];\n                }\n                if (self->buf_pos >= 4) {\n                    // Last 4 bytes is mask\n                    memcpy(self->mask, self->buf + self->buf_pos - 4, 4);\n                }\n                self->buf_pos = 0;\n                if ((self->last_flags & FRAME_OPCODE_MASK) >= FRAME_CLOSE) {\n                    self->state = CONTROL;\n                } else {\n                    self->state = PAYLOAD;\n                }\n                continue;\n            }\n\n            case PAYLOAD:\n            case CONTROL: {\n                mp_uint_t out_sz = 0;\n                if (self->msg_sz == 0) {\n                    // In case message had zero payload\n                    goto no_payload;\n                }\n\n                size_t sz = MIN(size, self->msg_sz);\n                out_sz = stream_p->read(self->sock, buf, sz, errcode);\n                if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {\n                    return out_sz;\n                }\n\n                sz = out_sz;\n                for (byte *p = buf; sz--; p++) {\n                    *p ^= self->mask[self->mask_pos++ & 3];\n                }\n\n                self->msg_sz -= out_sz;\n                if (self->msg_sz == 0) {\n                    byte last_state;\nno_payload:\n                    last_state = self->state;\n                    self->state = FRAME_HEADER;\n                    self->to_recv = 2;\n                    self->mask_pos = 0;\n                    self->buf_pos = 0;\n\n                    // Handle control frame\n                    if (last_state == CONTROL) {\n                        byte frame_type = self->last_flags & FRAME_OPCODE_MASK;\n                        if (frame_type == FRAME_CLOSE) {\n                            static const char close_resp[2] = {0x88, 0};\n                            int err;\n                            websocket_write(self_in, close_resp, sizeof(close_resp), &err);\n                            return 0;\n                        }\n\n                        //DEBUG_printf(\"Finished receiving ctrl message %x, ignoring\\n\", self->last_flags);\n                        continue;\n                    }\n                }\n\n                if (out_sz != 0) {\n                    return out_sz;\n                }\n                // Empty (data) frame received is not EOF\n                continue;\n            }\n\n        }\n    }\n}\n\nSTATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_websocket_t *self =  MP_OBJ_TO_PTR(self_in);\n    assert(size < 0x10000);\n    byte header[4] = {0x80 | (self->opts & FRAME_OPCODE_MASK)};\n    int hdr_sz;\n    if (size < 126) {\n        header[1] = size;\n        hdr_sz = 2;\n    } else {\n        header[1] = 126;\n        header[2] = size >> 8;\n        header[3] = size & 0xff;\n        hdr_sz = 4;\n    }\n\n    mp_obj_t dest[3];\n    if (self->opts & BLOCKING_WRITE) {\n        mp_load_method(self->sock, MP_QSTR_setblocking, dest);\n        dest[2] = mp_const_true;\n        mp_call_method_n_kw(1, 0, dest);\n    }\n\n    mp_uint_t out_sz = mp_stream_write_exactly(self->sock, header, hdr_sz, errcode);\n    if (*errcode == 0) {\n        out_sz = mp_stream_write_exactly(self->sock, buf, size, errcode);\n    }\n\n    if (self->opts & BLOCKING_WRITE) {\n        dest[2] = mp_const_false;\n        mp_call_method_n_kw(1, 0, dest);\n    }\n\n    if (*errcode != 0) {\n        return MP_STREAM_ERROR;\n    }\n    return out_sz;\n}\n\nSTATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);\n    switch (request) {\n        case MP_STREAM_CLOSE:\n            // TODO: Send close signaling to the other side, otherwise it's\n            // abrupt close (connection abort).\n            mp_stream_close(self->sock);\n            return 0;\n        case MP_STREAM_GET_DATA_OPTS:\n            return self->ws_flags & FRAME_OPCODE_MASK;\n        case MP_STREAM_SET_DATA_OPTS: {\n            int cur = self->opts & FRAME_OPCODE_MASK;\n            self->opts = (self->opts & ~FRAME_OPCODE_MASK) | (arg & FRAME_OPCODE_MASK);\n            return cur;\n        }\n        default:\n            *errcode = MP_EINVAL;\n            return MP_STREAM_ERROR;\n    }\n}\n\nSTATIC const mp_rom_map_elem_t websocket_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table);\n\nSTATIC const mp_stream_p_t websocket_stream_p = {\n    .read = websocket_read,\n    .write = websocket_write,\n    .ioctl = websocket_ioctl,\n};\n\nSTATIC const mp_obj_type_t websocket_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_websocket,\n    .make_new = websocket_make_new,\n    .protocol = &websocket_stream_p,\n    .locals_dict = (void*)&websocket_locals_dict,\n};\n\nSTATIC const mp_rom_map_elem_t uwebsocket_module_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uwebsocket) },\n    { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&websocket_type) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(uwebsocket_module_globals, uwebsocket_module_globals_table);\n\nconst mp_obj_module_t mp_module_uwebsocket = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&uwebsocket_module_globals,\n};\n\n#endif // MICROPY_PY_UWEBSOCKET\n"
  },
  {
    "path": "extmod/moduwebsocket.h",
    "content": "#ifndef MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H\n#define MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H\n\n#define FRAME_OPCODE_MASK 0x0f\nenum {\n    FRAME_CONT, FRAME_TXT, FRAME_BIN,\n    FRAME_CLOSE = 0x8, FRAME_PING, FRAME_PONG\n};\n\n#endif // MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H\n"
  },
  {
    "path": "extmod/moduzlib.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n#include \"py/mperrno.h\"\n\n#if MICROPY_PY_UZLIB\n\n#include \"uzlib/tinf.h\"\n\n#if 0 // print debugging info\n#define DEBUG_printf DEBUG_printf\n#else // don't print debugging info\n#define DEBUG_printf(...) (void)0\n#endif\n\ntypedef struct _mp_obj_decompio_t {\n    mp_obj_base_t base;\n    mp_obj_t src_stream;\n    TINF_DATA decomp;\n    bool eof;\n} mp_obj_decompio_t;\n\nSTATIC int read_src_stream(TINF_DATA *data) {\n    byte *p = (void*)data;\n    p -= offsetof(mp_obj_decompio_t, decomp);\n    mp_obj_decompio_t *self = (mp_obj_decompio_t*)p;\n\n    const mp_stream_p_t *stream = mp_get_stream(self->src_stream);\n    int err;\n    byte c;\n    mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err);\n    if (out_sz == MP_STREAM_ERROR) {\n        mp_raise_OSError(err);\n    }\n    if (out_sz == 0) {\n        nlr_raise(mp_obj_new_exception(&mp_type_EOFError));\n    }\n    return c;\n}\n\nSTATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 1, 2, false);\n    mp_get_stream_raise(args[0], MP_STREAM_OP_READ);\n    mp_obj_decompio_t *o = m_new_obj(mp_obj_decompio_t);\n    o->base.type = type;\n    memset(&o->decomp, 0, sizeof(o->decomp));\n    o->decomp.readSource = read_src_stream;\n    o->src_stream = args[0];\n    o->eof = false;\n\n    mp_int_t dict_opt = 0;\n    int dict_sz;\n    if (n_args > 1) {\n        dict_opt = mp_obj_get_int(args[1]);\n    }\n\n    if (dict_opt >= 16) {\n        int st = uzlib_gzip_parse_header(&o->decomp);\n        if (st != TINF_OK) {\n            goto header_error;\n        }\n        dict_sz = 1 << (dict_opt - 16);\n    } else if (dict_opt >= 0) {\n        dict_opt = uzlib_zlib_parse_header(&o->decomp);\n        if (dict_opt < 0) {\nheader_error:\n            mp_raise_ValueError(\"compression header\");\n        }\n        dict_sz = 1 << dict_opt;\n    } else {\n        dict_sz = 1 << -dict_opt;\n    }\n\n    uzlib_uncompress_init(&o->decomp, m_new(byte, dict_sz), dict_sz);\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_decompio_t *o = MP_OBJ_TO_PTR(o_in);\n    if (o->eof) {\n        return 0;\n    }\n\n    o->decomp.dest = buf;\n    o->decomp.dest_limit = (byte*)buf + size;\n    int st = uzlib_uncompress_chksum(&o->decomp);\n    if (st == TINF_DONE) {\n        o->eof = true;\n    }\n    if (st < 0) {\n        *errcode = MP_EINVAL;\n        return MP_STREAM_ERROR;\n    }\n    return o->decomp.dest - (byte*)buf;\n}\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table);\n#endif\n\nSTATIC const mp_stream_p_t decompio_stream_p = {\n    .read = decompio_read,\n};\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_obj_type_t decompio_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_DecompIO,\n    .make_new = decompio_make_new,\n    .protocol = &decompio_stream_p,\n    .locals_dict = (void*)&decompio_locals_dict,\n};\n#endif\n\nSTATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t data = args[0];\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);\n\n    TINF_DATA *decomp = m_new_obj(TINF_DATA);\n    memset(decomp, 0, sizeof(*decomp));\n    DEBUG_printf(\"sizeof(TINF_DATA)=\" UINT_FMT \"\\n\", sizeof(*decomp));\n    uzlib_uncompress_init(decomp, NULL, 0);\n    mp_uint_t dest_buf_size = (bufinfo.len + 15) & ~15;\n    byte *dest_buf = m_new(byte, dest_buf_size);\n\n    decomp->dest = dest_buf;\n    decomp->dest_limit = dest_buf + dest_buf_size;\n    DEBUG_printf(\"uzlib: Initial out buffer: \" UINT_FMT \" bytes\\n\", dest_buf_size);\n    decomp->source = bufinfo.buf;\n    decomp->source_limit = (byte*)bufinfo.buf + bufinfo.len;\n\n    int st;\n    bool is_zlib = true;\n\n    if (n_args > 1 && MP_OBJ_SMALL_INT_VALUE(args[1]) < 0) {\n        is_zlib = false;\n    }\n\n    if (is_zlib) {\n        st = uzlib_zlib_parse_header(decomp);\n        if (st < 0) {\n            goto error;\n        }\n    }\n\n    while (1) {\n        st = uzlib_uncompress_chksum(decomp);\n        if (st < 0) {\n            goto error;\n        }\n        if (st == TINF_DONE) {\n            break;\n        }\n        size_t offset = decomp->dest - dest_buf;\n        dest_buf = m_renew(byte, dest_buf, dest_buf_size, dest_buf_size + 256);\n        dest_buf_size += 256;\n        decomp->dest = dest_buf + offset;\n        decomp->dest_limit = decomp->dest + 256;\n    }\n\n    mp_uint_t final_sz = decomp->dest - dest_buf;\n    DEBUG_printf(\"uzlib: Resizing from \" UINT_FMT \" to final size: \" UINT_FMT \" bytes\\n\", dest_buf_size, final_sz);\n    dest_buf = (byte*)m_renew(byte, dest_buf, dest_buf_size, final_sz);\n    mp_obj_t res = mp_obj_new_bytearray_by_ref(final_sz, dest_buf);\n    m_del_obj(TINF_DATA, decomp);\n    return res;\n\nerror:\n        nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st)));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress);\n\n#if !MICROPY_ENABLE_DYNRUNTIME\nSTATIC const mp_rom_map_elem_t mp_module_uzlib_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) },\n    { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&mod_uzlib_decompress_obj) },\n    { MP_ROM_QSTR(MP_QSTR_DecompIO), MP_ROM_PTR(&decompio_type) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_uzlib_globals, mp_module_uzlib_globals_table);\n\nconst mp_obj_module_t mp_module_uzlib = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_uzlib_globals,\n};\n#endif\n\n// Source files #include'd here to make sure they're compiled in\n// only if module is enabled by config setting.\n\n#include \"uzlib/tinflate.c\"\n#include \"uzlib/tinfzlib.c\"\n#include \"uzlib/tinfgzip.c\"\n#include \"uzlib/adler32.c\"\n#include \"uzlib/crc32.c\"\n\n#endif // MICROPY_PY_UZLIB\n"
  },
  {
    "path": "extmod/modwebrepl.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n#include \"py/builtin.h\"\n#ifdef MICROPY_PY_WEBREPL_DELAY\n#include \"py/mphal.h\"\n#endif\n#include \"extmod/moduwebsocket.h\"\n\n#if MICROPY_PY_WEBREPL\n\n#if 0 // print debugging info\n#define DEBUG_printf DEBUG_printf\n#else // don't print debugging info\n#define DEBUG_printf(...) (void)0\n#endif\n\nstruct webrepl_file {\n    char sig[2];\n    char type;\n    char flags;\n    uint64_t offset;\n    uint32_t size;\n    uint16_t fname_len;\n    char fname[64];\n} __attribute__((packed));\n\nenum { PUT_FILE = 1, GET_FILE, GET_VER };\nenum { STATE_PASSWD, STATE_NORMAL };\n\ntypedef struct _mp_obj_webrepl_t {\n    mp_obj_base_t base;\n    mp_obj_t sock;\n    byte state;\n    byte hdr_to_recv;\n    uint32_t data_to_recv;\n    struct webrepl_file hdr;\n    mp_obj_t cur_file;\n} mp_obj_webrepl_t;\n\nSTATIC const char passwd_prompt[] = \"Password: \";\nSTATIC const char connected_prompt[] = \"\\r\\nWebREPL connected\\r\\n>>> \";\nSTATIC const char denied_prompt[] = \"\\r\\nAccess denied\\r\\n\";\n\nSTATIC char webrepl_passwd[10];\n\nSTATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) {\n    const mp_stream_p_t *sock_stream = mp_get_stream(websock);\n    int err;\n    int old_opts = sock_stream->ioctl(websock, MP_STREAM_SET_DATA_OPTS, FRAME_BIN, &err);\n    sock_stream->write(websock, buf, len, &err);\n    sock_stream->ioctl(websock, MP_STREAM_SET_DATA_OPTS, old_opts, &err);\n}\n\n#define SSTR(s) s, sizeof(s) - 1\nSTATIC void write_webrepl_str(mp_obj_t websock, const char *str, int sz) {\n    int err;\n    const mp_stream_p_t *sock_stream = mp_get_stream(websock);\n    sock_stream->write(websock, str, sz, &err);\n}\n\nSTATIC void write_webrepl_resp(mp_obj_t websock, uint16_t code) {\n    char buf[4] = {'W', 'B', code & 0xff, code >> 8};\n    write_webrepl(websock, buf, sizeof(buf));\n}\n\nSTATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 1, 2, false);\n    mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);\n    DEBUG_printf(\"sizeof(struct webrepl_file) = %lu\\n\", sizeof(struct webrepl_file));\n    mp_obj_webrepl_t *o = m_new_obj(mp_obj_webrepl_t);\n    o->base.type = type;\n    o->sock = args[0];\n    o->hdr_to_recv = sizeof(struct webrepl_file);\n    o->data_to_recv = 0;\n    o->state = STATE_PASSWD;\n    write_webrepl_str(args[0], SSTR(passwd_prompt));\n    return o;\n}\n\nSTATIC void check_file_op_finished(mp_obj_webrepl_t *self) {\n    if (self->data_to_recv == 0) {\n        mp_stream_close(self->cur_file);\n        self->hdr_to_recv = sizeof(struct webrepl_file);\n        DEBUG_printf(\"webrepl: Finished file operation %d\\n\", self->hdr.type);\n        write_webrepl_resp(self->sock, 0);\n    }\n}\n\nSTATIC int write_file_chunk(mp_obj_webrepl_t *self) {\n    const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file);\n    byte readbuf[2 + 256];\n    int err;\n    mp_uint_t out_sz = file_stream->read(self->cur_file, readbuf + 2, sizeof(readbuf) - 2, &err);\n    if (out_sz == MP_STREAM_ERROR) {\n        return out_sz;\n    }\n    readbuf[0] = out_sz;\n    readbuf[1] = out_sz >> 8;\n    DEBUG_printf(\"webrepl: Sending %d bytes of file\\n\", out_sz);\n    write_webrepl(self->sock, readbuf, 2 + out_sz);\n    return out_sz;\n}\n\nSTATIC void handle_op(mp_obj_webrepl_t *self) {\n\n    // Handle operations not requiring opened file\n\n    switch (self->hdr.type) {\n        case GET_VER: {\n            static const char ver[] = {MICROPY_VERSION_MAJOR, MICROPY_VERSION_MINOR, MICROPY_VERSION_MICRO};\n            write_webrepl(self->sock, ver, sizeof(ver));\n            self->hdr_to_recv = sizeof(struct webrepl_file);\n            return;\n        }\n    }\n\n    // Handle operations requiring opened file\n\n    mp_obj_t open_args[2] = {\n        mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname)),\n        MP_OBJ_NEW_QSTR(MP_QSTR_rb)\n    };\n\n    if (self->hdr.type == PUT_FILE) {\n        open_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_wb);\n    }\n\n    self->cur_file = mp_builtin_open(2, open_args, (mp_map_t*)&mp_const_empty_map);\n\n    #if 0\n    struct mp_stream_seek_t seek = { .offset = self->hdr.offset, .whence = 0 };\n    int err;\n    mp_uint_t res = file_stream->ioctl(self->cur_file, MP_STREAM_SEEK, (uintptr_t)&seek, &err);\n    assert(res != MP_STREAM_ERROR);\n    #endif\n\n    write_webrepl_resp(self->sock, 0);\n\n    if (self->hdr.type == PUT_FILE) {\n        self->data_to_recv = self->hdr.size;\n        check_file_op_finished(self);\n    } else if (self->hdr.type == GET_FILE) {\n        self->data_to_recv = 1;\n    }\n}\n\nSTATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode);\n\nSTATIC mp_uint_t webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {\n    mp_uint_t out_sz;\n    do {\n        out_sz = _webrepl_read(self_in, buf, size, errcode);\n    } while (out_sz == -2);\n    return out_sz;\n}\n\nSTATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {\n    // We know that os.dupterm always calls with size = 1\n    assert(size == 1);\n    mp_obj_webrepl_t *self = self_in;\n    const mp_stream_p_t *sock_stream = mp_get_stream(self->sock);\n    mp_uint_t out_sz = sock_stream->read(self->sock, buf, size, errcode);\n    //DEBUG_printf(\"webrepl: Read %d initial bytes from websocket\\n\", out_sz);\n    if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {\n        return out_sz;\n    }\n\n    if (self->state == STATE_PASSWD) {\n        char c = *(char*)buf;\n        if (c == '\\r' || c == '\\n') {\n            self->hdr.fname[self->data_to_recv] = 0;\n            DEBUG_printf(\"webrepl: entered password: %s\\n\", self->hdr.fname);\n\n            if (strcmp(self->hdr.fname, webrepl_passwd) != 0) {\n                write_webrepl_str(self->sock, SSTR(denied_prompt));\n                return 0;\n            }\n\n            self->state = STATE_NORMAL;\n            self->data_to_recv = 0;\n            write_webrepl_str(self->sock, SSTR(connected_prompt));\n        } else if (self->data_to_recv < 10) {\n            self->hdr.fname[self->data_to_recv++] = c;\n        }\n        return -2;\n    }\n\n    // If last read data belonged to text record (== REPL)\n    int err;\n    if (sock_stream->ioctl(self->sock, MP_STREAM_GET_DATA_OPTS, 0, &err) == 1) {\n        return out_sz;\n    }\n\n    DEBUG_printf(\"webrepl: received bin data, hdr_to_recv: %d, data_to_recv=%d\\n\", self->hdr_to_recv, self->data_to_recv);\n\n    if (self->hdr_to_recv != 0) {\n        char *p = (char*)&self->hdr + sizeof(self->hdr) - self->hdr_to_recv;\n        *p++ = *(char*)buf;\n        if (--self->hdr_to_recv != 0) {\n            mp_uint_t hdr_sz = sock_stream->read(self->sock, p, self->hdr_to_recv, errcode);\n            if (hdr_sz == MP_STREAM_ERROR) {\n                return hdr_sz;\n            }\n            self->hdr_to_recv -= hdr_sz;\n            if (self->hdr_to_recv != 0) {\n                return -2;\n            }\n        }\n\n        DEBUG_printf(\"webrepl: op: %d, file: %s, chunk @%x, sz=%d\\n\", self->hdr.type, self->hdr.fname, (uint32_t)self->hdr.offset, self->hdr.size);\n\n        handle_op(self);\n\n        return -2;\n    }\n\n    if (self->data_to_recv != 0) {\n        // Ports that don't have much available stack can make this filebuf static\n        #if MICROPY_PY_WEBREPL_STATIC_FILEBUF\n        static\n        #endif\n        byte filebuf[512];\n        filebuf[0] = *(byte*)buf;\n        mp_uint_t buf_sz = 1;\n        if (--self->data_to_recv != 0) {\n            size_t to_read = MIN(sizeof(filebuf) - 1, self->data_to_recv);\n            mp_uint_t sz = sock_stream->read(self->sock, filebuf + 1, to_read, errcode);\n            if (sz == MP_STREAM_ERROR) {\n                return sz;\n            }\n            self->data_to_recv -= sz;\n            buf_sz += sz;\n        }\n\n        if (self->hdr.type == PUT_FILE) {\n            DEBUG_printf(\"webrepl: Writing %lu bytes to file\\n\", buf_sz);\n            int err;\n            mp_uint_t res = mp_stream_write_exactly(self->cur_file, filebuf, buf_sz, &err);\n            if (err != 0 || res != buf_sz) {\n                assert(0);\n            }\n        } else if (self->hdr.type == GET_FILE) {\n            assert(buf_sz == 1);\n            assert(self->data_to_recv == 0);\n            assert(filebuf[0] == 0);\n            mp_uint_t out_sz = write_file_chunk(self);\n            if (out_sz != 0) {\n                self->data_to_recv = 1;\n            }\n        }\n\n        check_file_op_finished(self);\n\n        #ifdef MICROPY_PY_WEBREPL_DELAY\n        // Some platforms may have broken drivers and easily gets\n        // overloaded with modest traffic WebREPL file transfers\n        // generate. The basic workaround is a crude rate control\n        // done in such way.\n        mp_hal_delay_ms(MICROPY_PY_WEBREPL_DELAY);\n        #endif\n    }\n\n    return -2;\n}\n\nSTATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_webrepl_t *self = self_in;\n    if (self->state == STATE_PASSWD) {\n        // Don't forward output until passwd is entered\n        return size;\n    }\n    const mp_stream_p_t *stream_p = mp_get_stream(self->sock);\n    return stream_p->write(self->sock, buf, size, errcode);\n}\n\nSTATIC mp_uint_t webrepl_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(o_in);\n    (void)arg;\n    switch (request) {\n        case MP_STREAM_CLOSE:\n            // TODO: This is a place to do cleanup\n            mp_stream_close(self->sock);\n            return 0;\n\n        default:\n            *errcode = MP_EINVAL;\n            return MP_STREAM_ERROR;\n    }\n}\n\nSTATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) {\n    size_t len;\n    const char *passwd = mp_obj_str_get_data(passwd_in, &len);\n    if (len > sizeof(webrepl_passwd) - 1) {\n        mp_raise_ValueError(NULL);\n    }\n    strcpy(webrepl_passwd, passwd);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_set_password_obj, webrepl_set_password);\n\nSTATIC const mp_rom_map_elem_t webrepl_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(webrepl_locals_dict, webrepl_locals_dict_table);\n\nSTATIC const mp_stream_p_t webrepl_stream_p = {\n    .read = webrepl_read,\n    .write = webrepl_write,\n    .ioctl = webrepl_ioctl,\n};\n\nSTATIC const mp_obj_type_t webrepl_type = {\n    { &mp_type_type },\n    .name = MP_QSTR__webrepl,\n    .make_new = webrepl_make_new,\n    .protocol = &webrepl_stream_p,\n    .locals_dict = (mp_obj_dict_t*)&webrepl_locals_dict,\n};\n\nSTATIC const mp_rom_map_elem_t webrepl_module_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__webrepl) },\n    { MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&webrepl_type) },\n    { MP_ROM_QSTR(MP_QSTR_password), MP_ROM_PTR(&webrepl_set_password_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(webrepl_module_globals, webrepl_module_globals_table);\n\nconst mp_obj_module_t mp_module_webrepl = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&webrepl_module_globals,\n};\n\n#endif // MICROPY_PY_WEBREPL\n"
  },
  {
    "path": "extmod/modwebsocket.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n#include \"extmod/modwebsocket.h\"\n\n#if MICROPY_PY_WEBSOCKET\n\nenum { FRAME_HEADER, FRAME_OPT, PAYLOAD, CONTROL };\n\nenum { BLOCKING_WRITE = 0x80 };\n\ntypedef struct _mp_obj_websocket_t {\n    mp_obj_base_t base;\n    mp_obj_t sock;\n    uint32_t msg_sz;\n    byte mask[4];\n    byte state;\n    byte to_recv;\n    byte mask_pos;\n    byte buf_pos;\n    byte buf[6];\n    byte opts;\n    // Copy of last data frame flags\n    byte ws_flags;\n    // Copy of current frame flags\n    byte last_flags;\n} mp_obj_websocket_t;\n\nSTATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode);\n\nSTATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 1, 2, false);\n    mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);\n    mp_obj_websocket_t *o = m_new_obj(mp_obj_websocket_t);\n    o->base.type = type;\n    o->sock = args[0];\n    o->state = FRAME_HEADER;\n    o->to_recv = 2;\n    o->mask_pos = 0;\n    o->buf_pos = 0;\n    o->opts = FRAME_TXT;\n    if (n_args > 1 && args[1] == mp_const_true) {\n        o->opts |= BLOCKING_WRITE;\n    }\n    return  MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_websocket_t *self =  MP_OBJ_TO_PTR(self_in);\n    const mp_stream_p_t *stream_p = mp_get_stream(self->sock);\n    while (1) {\n        if (self->to_recv != 0) {\n            mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode);\n            if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {\n                return out_sz;\n            }\n            self->buf_pos += out_sz;\n            self->to_recv -= out_sz;\n            if (self->to_recv != 0) {\n                *errcode = MP_EAGAIN;\n                return MP_STREAM_ERROR;\n            }\n        }\n\n        switch (self->state) {\n            case FRAME_HEADER: {\n                // TODO: Split frame handling below is untested so far, so conservatively disable it\n                assert(self->buf[0] & 0x80);\n\n                // \"Control frames MAY be injected in the middle of a fragmented message.\"\n                // So, they must be processed before data frames (and not alter\n                // self->ws_flags)\n                byte frame_type = self->buf[0];\n                self->last_flags = frame_type;\n                frame_type &= FRAME_OPCODE_MASK;\n\n                if ((self->buf[0] & FRAME_OPCODE_MASK) == FRAME_CONT) {\n                    // Preserve previous frame type\n                    self->ws_flags = (self->ws_flags & FRAME_OPCODE_MASK) | (self->buf[0] & ~FRAME_OPCODE_MASK);\n                } else {\n                    self->ws_flags = self->buf[0];\n                }\n\n                // Reset mask in case someone will use \"simplified\" protocol\n                // without masks.\n                memset(self->mask, 0, sizeof(self->mask));\n\n                int to_recv = 0;\n                size_t sz = self->buf[1] & 0x7f;\n                if (sz == 126) {\n                    // Msg size is next 2 bytes\n                    to_recv += 2;\n                } else if (sz == 127) {\n                    // Msg size is next 8 bytes\n                    assert(0);\n                }\n                if (self->buf[1] & 0x80) {\n                    // Next 4 bytes is mask\n                    to_recv += 4;\n                }\n\n                self->buf_pos = 0;\n                self->to_recv = to_recv;\n                self->msg_sz = sz; // May be overridden by FRAME_OPT\n                if (to_recv != 0) {\n                    self->state = FRAME_OPT;\n                } else {\n                    if (frame_type >= FRAME_CLOSE) {\n                        self->state = CONTROL;\n                    } else {\n                        self->state = PAYLOAD;\n                    }\n                }\n                continue;\n            }\n\n            case FRAME_OPT: {\n                if ((self->buf_pos & 3) == 2) {\n                    // First two bytes are message length\n                    self->msg_sz = (self->buf[0] << 8) | self->buf[1];\n                }\n                if (self->buf_pos >= 4) {\n                    // Last 4 bytes is mask\n                    memcpy(self->mask, self->buf + self->buf_pos - 4, 4);\n                }\n                self->buf_pos = 0;\n                if ((self->last_flags & FRAME_OPCODE_MASK) >= FRAME_CLOSE) {\n                    self->state = CONTROL;\n                } else {\n                    self->state = PAYLOAD;\n                }\n                continue;\n            }\n\n            case PAYLOAD:\n            case CONTROL: {\n                mp_uint_t out_sz = 0;\n                if (self->msg_sz == 0) {\n                    // In case message had zero payload\n                    goto no_payload;\n                }\n\n                size_t sz = MIN(size, self->msg_sz);\n                out_sz = stream_p->read(self->sock, buf, sz, errcode);\n                if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {\n                    return out_sz;\n                }\n\n                sz = out_sz;\n                for (byte *p = buf; sz--; p++) {\n                    *p ^= self->mask[self->mask_pos++ & 3];\n                }\n\n                self->msg_sz -= out_sz;\n                if (self->msg_sz == 0) {\n                    byte last_state;\nno_payload:\n                    last_state = self->state;\n                    self->state = FRAME_HEADER;\n                    self->to_recv = 2;\n                    self->mask_pos = 0;\n                    self->buf_pos = 0;\n\n                    // Handle control frame\n                    if (last_state == CONTROL) {\n                        byte frame_type = self->last_flags & FRAME_OPCODE_MASK;\n                        if (frame_type == FRAME_CLOSE) {\n                            static char close_resp[2] = {0x88, 0};\n                            int err;\n                            websocket_write(self_in, close_resp, sizeof(close_resp), &err);\n                            return 0;\n                        }\n\n                        //DEBUG_printf(\"Finished receiving ctrl message %x, ignoring\\n\", self->last_flags);\n                        continue;\n                    }\n                }\n\n                if (out_sz != 0) {\n                    return out_sz;\n                }\n                // Empty (data) frame received is not EOF\n                continue;\n            }\n\n        }\n    }\n}\n\nSTATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_websocket_t *self =  MP_OBJ_TO_PTR(self_in);\n    assert(size < 0x10000);\n    byte header[4] = {0x80 | (self->opts & FRAME_OPCODE_MASK)};\n    int hdr_sz;\n    if (size < 126) {\n        header[1] = size;\n        hdr_sz = 2;\n    } else {\n        header[1] = 126;\n        header[2] = size >> 8;\n        header[3] = size & 0xff;\n        hdr_sz = 4;\n    }\n\n    mp_obj_t dest[3];\n    if (self->opts & BLOCKING_WRITE) {\n        mp_load_method(self->sock, MP_QSTR_setblocking, dest);\n        dest[2] = mp_const_true;\n        mp_call_method_n_kw(1, 0, dest);\n    }\n\n    mp_uint_t out_sz = mp_stream_write_exactly(self->sock, header, hdr_sz, errcode);\n    if (*errcode == 0) {\n        out_sz = mp_stream_write_exactly(self->sock, buf, size, errcode);\n    }\n\n    if (self->opts & BLOCKING_WRITE) {\n        dest[2] = mp_const_false;\n        mp_call_method_n_kw(1, 0, dest);\n    }\n\n    if (*errcode != 0) {\n        return MP_STREAM_ERROR;\n    }\n    return out_sz;\n}\n\nSTATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);\n    switch (request) {\n        case MP_STREAM_CLOSE:\n            // TODO: Send close signaling to the other side, otherwise it's\n            // abrupt close (connection abort).\n            mp_stream_close(self->sock);\n            return 0;\n        case MP_STREAM_GET_DATA_OPTS:\n            return self->ws_flags & FRAME_OPCODE_MASK;\n        case MP_STREAM_SET_DATA_OPTS: {\n            int cur = self->opts & FRAME_OPCODE_MASK;\n            self->opts = (self->opts & ~FRAME_OPCODE_MASK) | (arg & FRAME_OPCODE_MASK);\n            return cur;\n        }\n        default:\n            *errcode = MP_EINVAL;\n            return MP_STREAM_ERROR;\n    }\n}\n\nSTATIC const mp_rom_map_elem_t websocket_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table);\n\nSTATIC const mp_stream_p_t websocket_stream_p = {\n    .read = websocket_read,\n    .write = websocket_write,\n    .ioctl = websocket_ioctl,\n};\n\nSTATIC const mp_obj_type_t websocket_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_websocket,\n    .make_new = websocket_make_new,\n    .protocol = &websocket_stream_p,\n    .locals_dict = (void*)&websocket_locals_dict,\n};\n\nSTATIC const mp_rom_map_elem_t websocket_module_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_websocket) },\n    { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&websocket_type) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(websocket_module_globals, websocket_module_globals_table);\n\nconst mp_obj_module_t mp_module_websocket = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&websocket_module_globals,\n};\n\n#endif // MICROPY_PY_WEBSOCKET\n"
  },
  {
    "path": "extmod/modwebsocket.h",
    "content": "#ifndef MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H\n#define MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H\n\n#define FRAME_OPCODE_MASK 0x0f\nenum {\n    FRAME_CONT, FRAME_TXT, FRAME_BIN,\n    FRAME_CLOSE = 0x8, FRAME_PING, FRAME_PONG\n};\n\n#endif // MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H\n"
  },
  {
    "path": "extmod/re1.5/charclass.c",
    "content": "#include \"re1.5.h\"\n\nint _re1_5_classmatch(const char *pc, const char *sp)\n{\n    // pc points to \"cnt\" byte after opcode\n    int is_positive = (pc[-1] == Class);\n    int cnt = *pc++;\n    while (cnt--) {\n        if (*sp >= *pc && *sp <= pc[1]) return is_positive;\n        pc += 2;\n    }\n    return !is_positive;\n}\n\nint _re1_5_namedclassmatch(const char *pc, const char *sp)\n{\n    // pc points to name of class\n    int off = (*pc >> 5) & 1;\n    if ((*pc | 0x20) == 'd') {\n        if (!(*sp >= '0' && *sp <= '9')) {\n            off ^= 1;\n        }\n    } else if ((*pc | 0x20) == 's') {\n        if (!(*sp == ' ' || (*sp >= '\\t' && *sp <= '\\r'))) {\n            off ^= 1;\n        }\n    } else { // w\n        if (!((*sp >= 'A' && *sp <= 'Z') || (*sp >= 'a' && *sp <= 'z') || (*sp >= '0' && *sp <= '9') || *sp == '_')) {\n            off ^= 1;\n        }\n    }\n    return off;\n}\n"
  },
  {
    "path": "extmod/re1.5/compilecode.c",
    "content": "// Copyright 2014 Paul Sokolovsky.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n#include \"re1.5.h\"\n\n#define INSERT_CODE(at, num, pc) \\\n    ((code ? memmove(code + at + num, code + at, pc - at) : 0), pc += num)\n#define REL(at, to) (to - at - 2)\n#define EMIT(at, byte) (code ? (code[at] = byte) : (at))\n#define PC (prog->bytelen)\n\nstatic const char *_compilecode(const char *re, ByteProg *prog, int sizecode)\n{\n    char *code = sizecode ? NULL : prog->insts;\n    int start = PC;\n    int term = PC;\n    int alt_label = 0;\n\n    for (; *re && *re != ')'; re++) {\n        switch (*re) {\n        case '\\\\':\n            re++;\n            if (!*re) return NULL; // Trailing backslash\n            if ((*re | 0x20) == 'd' || (*re | 0x20) == 's' || (*re | 0x20) == 'w') {\n                term = PC;\n                EMIT(PC++, NamedClass);\n                EMIT(PC++, *re);\n                prog->len++;\n                break;\n            }\n        default:\n            term = PC;\n            EMIT(PC++, Char);\n            EMIT(PC++, *re);\n            prog->len++;\n            break;\n        case '.':\n            term = PC;\n            EMIT(PC++, Any);\n            prog->len++;\n            break;\n        case '[': {\n            int cnt;\n            term = PC;\n            re++;\n            if (*re == '^') {\n                EMIT(PC++, ClassNot);\n                re++;\n            } else {\n                EMIT(PC++, Class);\n            }\n            PC++; // Skip # of pair byte\n            prog->len++;\n            for (cnt = 0; *re != ']'; re++, cnt++) {\n                if (*re == '\\\\') {\n                    ++re;\n                }\n                if (!*re) return NULL;\n                EMIT(PC++, *re);\n                if (re[1] == '-' && re[2] != ']') {\n                    re += 2;\n                }\n                EMIT(PC++, *re);\n            }\n            EMIT(term + 1, cnt);\n            break;\n        }\n        case '(': {\n            term = PC;\n            int sub = 0;\n            int capture = re[1] != '?' || re[2] != ':';\n\n            if (capture) {\n                sub = ++prog->sub;\n                EMIT(PC++, Save);\n                EMIT(PC++, 2 * sub);\n                prog->len++;\n            } else {\n                    re += 2;\n            }\n\n            re = _compilecode(re + 1, prog, sizecode);\n            if (re == NULL || *re != ')') return NULL; // error, or no matching paren\n\n            if (capture) {\n                EMIT(PC++, Save);\n                EMIT(PC++, 2 * sub + 1);\n                prog->len++;\n            }\n\n            break;\n        }\n        case '?':\n            if (PC == term) return NULL; // nothing to repeat\n            INSERT_CODE(term, 2, PC);\n            if (re[1] == '?') {\n                EMIT(term, RSplit);\n                re++;\n            } else {\n                EMIT(term, Split);\n            }\n            EMIT(term + 1, REL(term, PC));\n            prog->len++;\n            term = PC;\n            break;\n        case '*':\n            if (PC == term) return NULL; // nothing to repeat\n            INSERT_CODE(term, 2, PC);\n            EMIT(PC, Jmp);\n            EMIT(PC + 1, REL(PC, term));\n            PC += 2;\n            if (re[1] == '?') {\n                EMIT(term, RSplit);\n                re++;\n            } else {\n                EMIT(term, Split);\n            }\n            EMIT(term + 1, REL(term, PC));\n            prog->len += 2;\n            term = PC;\n            break;\n        case '+':\n            if (PC == term) return NULL; // nothing to repeat\n            if (re[1] == '?') {\n                EMIT(PC, Split);\n                re++;\n            } else {\n                EMIT(PC, RSplit);\n            }\n            EMIT(PC + 1, REL(PC, term));\n            PC += 2;\n            prog->len++;\n            term = PC;\n            break;\n        case '|':\n            if (alt_label) {\n                EMIT(alt_label, REL(alt_label, PC) + 1);\n            }\n            INSERT_CODE(start, 2, PC);\n            EMIT(PC++, Jmp);\n            alt_label = PC++;\n            EMIT(start, Split);\n            EMIT(start + 1, REL(start, PC));\n            prog->len += 2;\n            term = PC;\n            break;\n        case '^':\n            EMIT(PC++, Bol);\n            prog->len++;\n            term = PC;\n            break;\n        case '$':\n            EMIT(PC++, Eol);\n            prog->len++;\n            term = PC;\n            break;\n        }\n    }\n\n    if (alt_label) {\n        EMIT(alt_label, REL(alt_label, PC) + 1);\n    }\n    return re;\n}\n\nint re1_5_sizecode(const char *re)\n{\n    ByteProg dummyprog = {\n         // Save 0, Save 1, Match; more bytes for \"search\" (vs \"match\") prefix code\n        .bytelen = 5 + NON_ANCHORED_PREFIX\n    };\n\n    if (_compilecode(re, &dummyprog, /*sizecode*/1) == NULL) return -1;\n\n    return dummyprog.bytelen;\n}\n\nint re1_5_compilecode(ByteProg *prog, const char *re)\n{\n    prog->len = 0;\n    prog->bytelen = 0;\n    prog->sub = 0;\n\n    // Add code to implement non-anchored operation (\"search\"),\n    // for anchored operation (\"match\"), this code will be just skipped.\n    // TODO: Implement search in much more efficient manner\n    prog->insts[prog->bytelen++] = RSplit;\n    prog->insts[prog->bytelen++] = 3;\n    prog->insts[prog->bytelen++] = Any;\n    prog->insts[prog->bytelen++] = Jmp;\n    prog->insts[prog->bytelen++] = -5;\n    prog->len += 3;\n\n    prog->insts[prog->bytelen++] = Save;\n    prog->insts[prog->bytelen++] = 0;\n    prog->len++;\n\n    re = _compilecode(re, prog, /*sizecode*/0);\n    if (re == NULL || *re) return 1;\n\n    prog->insts[prog->bytelen++] = Save;\n    prog->insts[prog->bytelen++] = 1;\n    prog->len++;\n\n    prog->insts[prog->bytelen++] = Match;\n    prog->len++;\n\n    return 0;\n}\n\n#if 0\nint main(int argc, char *argv[])\n{\n    int pc = 0;\n    ByteProg *code = re1_5_compilecode(argv[1]);\n    re1_5_dumpcode(code);\n}\n#endif\n"
  },
  {
    "path": "extmod/re1.5/dumpcode.c",
    "content": "// Copyright 2014 Paul Sokolovsky.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n#include \"re1.5.h\"\n\nvoid re1_5_dumpcode(ByteProg *prog)\n{\n    int pc = 0;\n    char *code = prog->insts;\n    while (pc < prog->bytelen) {\n                printf(\"%2d: \", pc);\n                switch(code[pc++]) {\n                default:\n                        assert(0);\n//                        re1_5_fatal(\"printprog\");\n                case Split:\n                        printf(\"split %d (%d)\\n\", pc + (signed char)code[pc] + 1, (signed char)code[pc]);\n                        pc++;\n                        break;\n                case RSplit:\n                        printf(\"rsplit %d (%d)\\n\", pc + (signed char)code[pc] + 1, (signed char)code[pc]);\n                        pc++;\n                        break;\n                case Jmp:\n                        printf(\"jmp %d (%d)\\n\", pc + (signed char)code[pc] + 1, (signed char)code[pc]);\n                        pc++;\n                        break;\n                case Char:\n                        printf(\"char %c\\n\", code[pc++]);\n                        break;\n                case Any:\n                        printf(\"any\\n\");\n                        break;\n                case Class:\n                case ClassNot: {\n                        int num = code[pc];\n                        printf(\"class%s %d\", (code[pc - 1] == ClassNot ? \"not\" : \"\"), num);\n                        pc++;\n                        while (num--) {\n                            printf(\" 0x%02x-0x%02x\", code[pc], code[pc + 1]);\n                            pc += 2;\n                        }\n                        printf(\"\\n\");\n                        break;\n                }\n                case NamedClass:\n                        printf(\"namedclass %c\\n\", code[pc++]);\n                        break;\n                case Match:\n                        printf(\"match\\n\");\n                        break;\n                case Save:\n                        printf(\"save %d\\n\", (unsigned char)code[pc++]);\n                        break;\n                case Bol:\n                        printf(\"assert bol\\n\");\n                        break;\n                case Eol:\n                        printf(\"assert eol\\n\");\n                        break;\n                }\n    }\n    printf(\"Bytes: %d, insts: %d\\n\", prog->bytelen, prog->len);\n}\n"
  },
  {
    "path": "extmod/re1.5/re1.5.h",
    "content": "// Copyright 2007-2009 Russ Cox.  All Rights Reserved.\n// Copyright 2014 Paul Sokolovsky.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n#ifndef _RE1_5_REGEXP__H\n#define _RE1_5_REGEXP__H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdarg.h>\n#include <assert.h>\n\n#define nil ((void*)0)\n#define nelem(x) (sizeof(x)/sizeof((x)[0]))\n\ntypedef struct Regexp Regexp;\ntypedef struct Prog Prog;\ntypedef struct ByteProg ByteProg;\ntypedef struct Inst Inst;\ntypedef struct Subject Subject;\n\nstruct Regexp\n{\n\tint type;\n\tint n;\n\tint ch;\n\tRegexp *left;\n\tRegexp *right;\n};\n\nenum\t/* Regexp.type */\n{\n\tAlt = 1,\n\tCat,\n\tLit,\n\tDot,\n\tParen,\n\tQuest,\n\tStar,\n\tPlus,\n};\n\nRegexp *parse(char*);\nRegexp *reg(int type, Regexp *left, Regexp *right);\nvoid printre(Regexp*);\n#ifndef re1_5_fatal\nvoid re1_5_fatal(char*);\n#endif\n#ifndef re1_5_stack_chk\n#define re1_5_stack_chk()\n#endif\nvoid *mal(int);\n\nstruct Prog\n{\n\tInst *start;\n\tint len;\n};\n\nstruct ByteProg\n{\n\tint bytelen;\n\tint len;\n\tint sub;\n\tchar insts[0];\n};\n\nstruct Inst\n{\n\tint opcode;\n\tint c;\n\tint n;\n\tInst *x;\n\tInst *y;\n\tint gen;\t// global state, oooh!\n};\n\nenum\t/* Inst.opcode */\n{\n\t// Instructions which consume input bytes (and thus fail if none left)\n\tCONSUMERS = 1,\n\tChar = CONSUMERS,\n\tAny,\n\tClass,\n\tClassNot,\n\tNamedClass,\n\n\tASSERTS = 0x50,\n\tBol = ASSERTS,\n\tEol,\n\n\t// Instructions which take relative offset as arg\n\tJUMPS = 0x60,\n\tJmp = JUMPS,\n\tSplit,\n\tRSplit,\n\n\t// Other (special) instructions\n\tSave = 0x7e,\n\tMatch = 0x7f,\n};\n\n#define inst_is_consumer(inst) ((inst) < ASSERTS)\n#define inst_is_jump(inst) ((inst) & 0x70 == JUMPS)\n\nProg *compile(Regexp*);\nvoid printprog(Prog*);\n\nextern int gen;\n\nenum {\n\tMAXSUB = 20\n};\n\ntypedef struct Sub Sub;\n\nstruct Sub\n{\n\tint ref;\n\tint nsub;\n\tconst char *sub[MAXSUB];\n};\n\nSub *newsub(int n);\nSub *incref(Sub*);\nSub *copy(Sub*);\nSub *update(Sub*, int, const char*);\nvoid decref(Sub*);\n\nstruct Subject {\n\tconst char *begin;\n\tconst char *end;\n};\n\n\n#define NON_ANCHORED_PREFIX 5\n#define HANDLE_ANCHORED(bytecode, is_anchored) ((is_anchored) ? (bytecode) + NON_ANCHORED_PREFIX : (bytecode))\n\nint re1_5_backtrack(ByteProg*, Subject*, const char**, int, int);\nint re1_5_pikevm(ByteProg*, Subject*, const char**, int, int);\nint re1_5_recursiveloopprog(ByteProg*, Subject*, const char**, int, int);\nint re1_5_recursiveprog(ByteProg*, Subject*, const char**, int, int);\nint re1_5_thompsonvm(ByteProg*, Subject*, const char**, int, int);\n\nint re1_5_sizecode(const char *re);\nint re1_5_compilecode(ByteProg *prog, const char *re);\nvoid re1_5_dumpcode(ByteProg *prog);\nvoid cleanmarks(ByteProg *prog);\nint _re1_5_classmatch(const char *pc, const char *sp);\nint _re1_5_namedclassmatch(const char *pc, const char *sp);\n\n#endif /*_RE1_5_REGEXP__H*/\n"
  },
  {
    "path": "extmod/re1.5/recursiveloop.c",
    "content": "// Copyright 2007-2009 Russ Cox.  All Rights Reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n#include \"re1.5.h\"\n\nstatic int\nrecursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int nsubp)\n{\n\tconst char *old;\n\tint off;\n\n\tre1_5_stack_chk();\n\n\tfor(;;) {\n\t\tif(inst_is_consumer(*pc)) {\n\t\t\t// If we need to match a character, but there's none left, it's fail\n\t\t\tif(sp >= input->end)\n\t\t\t\treturn 0;\n\t\t}\n\t\tswitch(*pc++) {\n\t\tcase Char:\n\t\t\tif(*sp != *pc++)\n\t\t\t\treturn 0;\n\t\tcase Any:\n\t\t\tsp++;\n\t\t\tcontinue;\n\t\tcase Class:\n\t\tcase ClassNot:\n\t\t\tif (!_re1_5_classmatch(pc, sp))\n\t\t\t\treturn 0;\n\t\t\tpc += *(unsigned char*)pc * 2 + 1;\n\t\t\tsp++;\n\t\t\tcontinue;\n                case NamedClass:\n\t\t\tif (!_re1_5_namedclassmatch(pc, sp))\n\t\t\t\treturn 0;\n\t\t\tpc++;\n\t\t\tsp++;\n\t\t\tcontinue;\n\t\tcase Match:\n\t\t\treturn 1;\n\t\tcase Jmp:\n\t\t\toff = (signed char)*pc++;\n\t\t\tpc = pc + off;\n\t\t\tcontinue;\n\t\tcase Split:\n\t\t\toff = (signed char)*pc++;\n\t\t\tif(recursiveloop(pc, sp, input, subp, nsubp))\n\t\t\t\treturn 1;\n\t\t\tpc = pc + off;\n\t\t\tcontinue;\n\t\tcase RSplit:\n\t\t\toff = (signed char)*pc++;\n\t\t\tif(recursiveloop(pc + off, sp, input, subp, nsubp))\n\t\t\t\treturn 1;\n\t\t\tcontinue;\n\t\tcase Save:\n\t\t\toff = (unsigned char)*pc++;\n\t\t\tif(off >= nsubp) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\told = subp[off];\n\t\t\tsubp[off] = sp;\n\t\t\tif(recursiveloop(pc, sp, input, subp, nsubp))\n\t\t\t\treturn 1;\n\t\t\tsubp[off] = old;\n\t\t\treturn 0;\n\t\tcase Bol:\n\t\t\tif(sp != input->begin)\n\t\t\t\treturn 0;\n\t\t\tcontinue;\n\t\tcase Eol:\n\t\t\tif(sp != input->end)\n\t\t\t\treturn 0;\n\t\t\tcontinue;\n\t\t}\n\t\tre1_5_fatal(\"recursiveloop\");\n\t}\n}\n\nint\nre1_5_recursiveloopprog(ByteProg *prog, Subject *input, const char **subp, int nsubp, int is_anchored)\n{\n\treturn recursiveloop(HANDLE_ANCHORED(prog->insts, is_anchored), input->begin, input, subp, nsubp);\n}\n"
  },
  {
    "path": "extmod/uos_dupterm.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n * Copyright (c) 2017-2019 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include \"py/mpconfig.h\"\n\n#include \"py/runtime.h\"\n#include \"py/objtuple.h\"\n#include \"py/objarray.h\"\n#include \"py/stream.h\"\n#include \"extmod/misc.h\"\n#include \"lib/utils/interrupt_char.h\"\n\n#if MICROPY_PY_OS_DUPTERM\n\nvoid mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) {\n    mp_obj_t term = MP_STATE_VM(dupterm_objs[dupterm_idx]);\n    MP_STATE_VM(dupterm_objs[dupterm_idx]) = MP_OBJ_NULL;\n    mp_printf(&mp_plat_print, msg);\n    if (exc != MP_OBJ_NULL) {\n        mp_obj_print_exception(&mp_plat_print, exc);\n    }\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        mp_stream_close(term);\n        nlr_pop();\n    } else {\n        // Ignore any errors during stream closing\n    }\n}\n\nuintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags) {\n    uintptr_t poll_flags_out = 0;\n\n    for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {\n        mp_obj_t s = MP_STATE_VM(dupterm_objs[idx]);\n        if (s == MP_OBJ_NULL) {\n            continue;\n        }\n\n        int errcode = 0;\n        mp_uint_t ret = 0;\n        const mp_stream_p_t *stream_p = mp_get_stream(s);\n        #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM\n        if (mp_uos_dupterm_is_builtin_stream(s)) {\n            ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode);\n        } else\n        #endif\n        {\n            nlr_buf_t nlr;\n            if (nlr_push(&nlr) == 0) {\n                ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode);\n                nlr_pop();\n            } else {\n                // Ignore error with ioctl\n            }\n        }\n\n        if (ret != MP_STREAM_ERROR) {\n            poll_flags_out |= ret;\n            if (poll_flags_out == poll_flags) {\n                // Finish early if all requested flags are set\n                break;\n            }\n        }\n    }\n\n    return poll_flags_out;\n}\n\nint mp_uos_dupterm_rx_chr(void) {\n    for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {\n        if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {\n            continue;\n        }\n\n        #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM\n        if (mp_uos_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) {\n            byte buf[1];\n            int errcode = 0;\n            const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));\n            mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode);\n            if (errcode == 0 && out_sz != 0) {\n                return buf[0];\n             } else {\n                continue;\n             }\n        }\n        #endif\n\n        nlr_buf_t nlr;\n        if (nlr_push(&nlr) == 0) {\n            byte buf[1];\n            int errcode;\n            const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));\n            mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode);\n            if (out_sz == 0) {\n                nlr_pop();\n                mp_uos_deactivate(idx, \"dupterm: EOF received, deactivating\\n\", MP_OBJ_NULL);\n            } else if (out_sz == MP_STREAM_ERROR) {\n                // errcode is valid\n                if (mp_is_nonblocking_error(errcode)) {\n                    nlr_pop();\n                } else {\n                    mp_raise_OSError(errcode);\n                }\n            } else {\n                // read 1 byte\n                nlr_pop();\n                if (buf[0] == mp_interrupt_char) {\n                    // Signal keyboard interrupt to be raised as soon as the VM resumes\n                    mp_keyboard_interrupt();\n                    return -2;\n                }\n                return buf[0];\n            }\n        } else {\n            mp_uos_deactivate(idx, \"dupterm: Exception in read() method, deactivating: \", MP_OBJ_FROM_PTR(nlr.ret_val));\n        }\n    }\n\n    // No chars available\n    return -1;\n}\n\nvoid mp_uos_dupterm_tx_strn(const char *str, size_t len) {\n    for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {\n        if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {\n            continue;\n        }\n\n        #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM\n        if (mp_uos_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) {\n            int errcode = 0;\n            const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));\n            stream_p->write(MP_STATE_VM(dupterm_objs[idx]), str, len, &errcode);\n            continue;\n        }\n        #endif\n\n        nlr_buf_t nlr;\n        if (nlr_push(&nlr) == 0) {\n            mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE);\n            nlr_pop();\n        } else {\n            mp_uos_deactivate(idx, \"dupterm: Exception in write() method, deactivating: \", MP_OBJ_FROM_PTR(nlr.ret_val));\n        }\n    }\n}\n\nSTATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) {\n    mp_int_t idx = 0;\n    if (n_args == 2) {\n        idx = mp_obj_get_int(args[1]);\n    }\n\n    if (idx < 0 || idx >= MICROPY_PY_OS_DUPTERM) {\n        mp_raise_ValueError(\"invalid dupterm index\");\n    }\n\n    mp_obj_t previous_obj = MP_STATE_VM(dupterm_objs[idx]);\n    if (previous_obj == MP_OBJ_NULL) {\n        previous_obj = mp_const_none;\n    }\n    if (args[0] == mp_const_none) {\n        MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;\n    } else {\n        mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);\n        MP_STATE_VM(dupterm_objs[idx]) = args[0];\n    }\n\n    return previous_obj;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 1, 2, mp_uos_dupterm);\n\n#endif\n"
  },
  {
    "path": "extmod/utime_mphal.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2016 Damien P. George\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_PY_UTIME_MP_HAL\n\n#include <string.h>\n\n#include \"py/obj.h\"\n#include \"py/mphal.h\"\n#include \"py/smallint.h\"\n#include \"py/runtime.h\"\n#include \"extmod/utime_mphal.h\"\n\nSTATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {\n    #if MICROPY_PY_BUILTINS_FLOAT\n    mp_hal_delay_ms((mp_uint_t)(1000 * mp_obj_get_float(seconds_o)));\n    #else\n    mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o));\n    #endif\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep);\n\nSTATIC mp_obj_t time_sleep_ms(mp_obj_t arg) {\n    mp_int_t ms = mp_obj_get_int(arg);\n    if (ms > 0) {\n        mp_hal_delay_ms(ms);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj, time_sleep_ms);\n\nSTATIC mp_obj_t time_sleep_us(mp_obj_t arg) {\n    mp_int_t us = mp_obj_get_int(arg);\n    if (us > 0) {\n        mp_hal_delay_us(us);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us);\n\nSTATIC mp_obj_t time_ticks_ms(void) {\n    return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));\n}\nMP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj, time_ticks_ms);\n\nSTATIC mp_obj_t time_ticks_us(void) {\n    return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));\n}\nMP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj, time_ticks_us);\n\nSTATIC mp_obj_t time_ticks_cpu(void) {\n    return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));\n}\nMP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj, time_ticks_cpu);\n\nSTATIC mp_obj_t time_ticks_diff(mp_obj_t end_in, mp_obj_t start_in) {\n    // we assume that the arguments come from ticks_xx so are small ints\n    mp_uint_t start = MP_OBJ_SMALL_INT_VALUE(start_in);\n    mp_uint_t end = MP_OBJ_SMALL_INT_VALUE(end_in);\n    // Optimized formula avoiding if conditions. We adjust difference \"forward\",\n    // wrap it around and adjust back.\n    mp_int_t diff = ((end - start + MICROPY_PY_UTIME_TICKS_PERIOD / 2) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1))\n                   - MICROPY_PY_UTIME_TICKS_PERIOD / 2;\n    return MP_OBJ_NEW_SMALL_INT(diff);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj, time_ticks_diff);\n\nSTATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) {\n    // we assume that first argument come from ticks_xx so is small int\n    mp_uint_t ticks = MP_OBJ_SMALL_INT_VALUE(ticks_in);\n    mp_uint_t delta = mp_obj_get_int(delta_in);\n    return MP_OBJ_NEW_SMALL_INT((ticks + delta) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj, time_ticks_add);\n\n#endif // MICROPY_PY_UTIME_MP_HAL\n"
  },
  {
    "path": "extmod/utime_mphal.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2016 Damien P. George\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H\n#define MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H\n\n#include \"py/obj.h\"\n\nMP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj);\n\n#endif // MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H\n"
  },
  {
    "path": "extmod/uzlib/adler32.c",
    "content": "/*\n * Adler-32 checksum\n *\n * Copyright (c) 2003 by Joergen Ibsen / Jibz\n * All Rights Reserved\n *\n * http://www.ibsensoftware.com/\n *\n * This software is provided 'as-is', without any express\n * or implied warranty.  In no event will the authors be\n * held liable for any damages arising from the use of\n * this software.\n *\n * Permission is granted to anyone to use this software\n * for any purpose, including commercial applications,\n * and to alter it and redistribute it freely, subject to\n * the following restrictions:\n *\n * 1. The origin of this software must not be\n *    misrepresented; you must not claim that you\n *    wrote the original software. If you use this\n *    software in a product, an acknowledgment in\n *    the product documentation would be appreciated\n *    but is not required.\n *\n * 2. Altered source versions must be plainly marked\n *    as such, and must not be misrepresented as\n *    being the original software.\n *\n * 3. This notice may not be removed or altered from\n *    any source distribution.\n */\n\n/*\n * Adler-32 algorithm taken from the zlib source, which is\n * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler\n */\n\n#include \"tinf.h\"\n\n#define A32_BASE 65521\n#define A32_NMAX 5552\n\nuint32_t uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum /* 1 */)\n{\n   const unsigned char *buf = (const unsigned char *)data;\n\n   unsigned int s1 = prev_sum & 0xffff;\n   unsigned int s2 = prev_sum >> 16;\n\n   while (length > 0)\n   {\n      int k = length < A32_NMAX ? length : A32_NMAX;\n      int i;\n\n      for (i = k / 16; i; --i, buf += 16)\n      {\n         s1 += buf[0];  s2 += s1; s1 += buf[1];  s2 += s1;\n         s1 += buf[2];  s2 += s1; s1 += buf[3];  s2 += s1;\n         s1 += buf[4];  s2 += s1; s1 += buf[5];  s2 += s1;\n         s1 += buf[6];  s2 += s1; s1 += buf[7];  s2 += s1;\n\n         s1 += buf[8];  s2 += s1; s1 += buf[9];  s2 += s1;\n         s1 += buf[10]; s2 += s1; s1 += buf[11]; s2 += s1;\n         s1 += buf[12]; s2 += s1; s1 += buf[13]; s2 += s1;\n         s1 += buf[14]; s2 += s1; s1 += buf[15]; s2 += s1;\n      }\n\n      for (i = k % 16; i; --i) { s1 += *buf++; s2 += s1; }\n\n      s1 %= A32_BASE;\n      s2 %= A32_BASE;\n\n      length -= k;\n   }\n\n   return (s2 << 16) | s1;\n}\n"
  },
  {
    "path": "extmod/uzlib/crc32.c",
    "content": "/*\n * CRC32 checksum\n *\n * Copyright (c) 1998-2003 by Joergen Ibsen / Jibz\n * All Rights Reserved\n *\n * http://www.ibsensoftware.com/\n *\n * This software is provided 'as-is', without any express\n * or implied warranty.  In no event will the authors be\n * held liable for any damages arising from the use of\n * this software.\n *\n * Permission is granted to anyone to use this software\n * for any purpose, including commercial applications,\n * and to alter it and redistribute it freely, subject to\n * the following restrictions:\n *\n * 1. The origin of this software must not be\n *    misrepresented; you must not claim that you\n *    wrote the original software. If you use this\n *    software in a product, an acknowledgment in\n *    the product documentation would be appreciated\n *    but is not required.\n *\n * 2. Altered source versions must be plainly marked\n *    as such, and must not be misrepresented as\n *    being the original software.\n *\n * 3. This notice may not be removed or altered from\n *    any source distribution.\n */\n\n/*\n * CRC32 algorithm taken from the zlib source, which is\n * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler\n */\n\n#include \"tinf.h\"\n\nstatic const unsigned int tinf_crc32tab[16] = {\n   0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190,\n   0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344,\n   0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278,\n   0xbdbdf21c\n};\n\n/* crc is previous value for incremental computation, 0xffffffff initially */\nuint32_t uzlib_crc32(const void *data, unsigned int length, uint32_t crc)\n{\n   const unsigned char *buf = (const unsigned char *)data;\n   unsigned int i;\n\n   for (i = 0; i < length; ++i)\n   {\n      crc ^= buf[i];\n      crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4);\n      crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4);\n   }\n\n   // return value suitable for passing in next time, for final value invert it\n   return crc/* ^ 0xffffffff*/;\n}\n"
  },
  {
    "path": "extmod/uzlib/defl_static.h",
    "content": "/*\n * Copyright (c) uzlib authors\n *\n * This software is provided 'as-is', without any express\n * or implied warranty.  In no event will the authors be\n * held liable for any damages arising from the use of\n * this software.\n *\n * Permission is granted to anyone to use this software\n * for any purpose, including commercial applications,\n * and to alter it and redistribute it freely, subject to\n * the following restrictions:\n *\n * 1. The origin of this software must not be\n *    misrepresented; you must not claim that you\n *    wrote the original software. If you use this\n *    software in a product, an acknowledgment in\n *    the product documentation would be appreciated\n *    but is not required.\n *\n * 2. Altered source versions must be plainly marked\n *    as such, and must not be misrepresented as\n *    being the original software.\n *\n * 3. This notice may not be removed or altered from\n *    any source distribution.\n */\n\n/* This files contains type declaration and prototypes for defl_static.c.\n   They may be altered/distinct from the originals used in PuTTY source\n   code. */\n\nstruct Outbuf {\n    unsigned char *outbuf;\n    int outlen, outsize;\n    unsigned long outbits;\n    int noutbits;\n    int comp_disabled;\n};\n\nvoid outbits(struct Outbuf *out, unsigned long bits, int nbits);\nvoid zlib_start_block(struct Outbuf *ctx);\nvoid zlib_finish_block(struct Outbuf *ctx);\nvoid zlib_literal(struct Outbuf *ectx, unsigned char c);\nvoid zlib_match(struct Outbuf *ectx, int distance, int len);\n"
  },
  {
    "path": "extmod/uzlib/tinf.h",
    "content": "/* Compatibility header for the original tinf lib/older versions of uzlib.\n   Note: may be removed in the future, please migrate to uzlib.h. */\n#include \"uzlib.h\"\n"
  },
  {
    "path": "extmod/uzlib/tinf_compat.h",
    "content": "/* This header contains compatibility defines for the original tinf API\n   and uzlib 2.x and below API. These defines are deprecated and going\n   to be removed in the future, so applications should migrate to new\n   uzlib API. */\n#define TINF_DATA struct uzlib_uncomp\n\n#define destSize dest_size\n#define destStart dest_start\n#define readSource source_read_cb\n"
  },
  {
    "path": "extmod/uzlib/tinfgzip.c",
    "content": "/*\n * uzlib  -  tiny deflate/inflate library (deflate, gzip, zlib)\n *\n * Copyright (c) 2003 by Joergen Ibsen / Jibz\n * All Rights Reserved\n *\n * http://www.ibsensoftware.com/\n *\n * Copyright (c) 2014-2018 by Paul Sokolovsky\n *\n * This software is provided 'as-is', without any express\n * or implied warranty.  In no event will the authors be\n * held liable for any damages arising from the use of\n * this software.\n *\n * Permission is granted to anyone to use this software\n * for any purpose, including commercial applications,\n * and to alter it and redistribute it freely, subject to\n * the following restrictions:\n *\n * 1. The origin of this software must not be\n *    misrepresented; you must not claim that you\n *    wrote the original software. If you use this\n *    software in a product, an acknowledgment in\n *    the product documentation would be appreciated\n *    but is not required.\n *\n * 2. Altered source versions must be plainly marked\n *    as such, and must not be misrepresented as\n *    being the original software.\n *\n * 3. This notice may not be removed or altered from\n *    any source distribution.\n */\n\n#include \"tinf.h\"\n\n#define FTEXT    1\n#define FHCRC    2\n#define FEXTRA   4\n#define FNAME    8\n#define FCOMMENT 16\n\nvoid tinf_skip_bytes(TINF_DATA *d, int num);\nuint16_t tinf_get_uint16(TINF_DATA *d);\n\nvoid tinf_skip_bytes(TINF_DATA *d, int num)\n{\n    while (num--) uzlib_get_byte(d);\n}\n\nuint16_t tinf_get_uint16(TINF_DATA *d)\n{\n    unsigned int v = uzlib_get_byte(d);\n    v = (uzlib_get_byte(d) << 8) | v;\n    return v;\n}\n\nint uzlib_gzip_parse_header(TINF_DATA *d)\n{\n    unsigned char flg;\n\n    /* -- check format -- */\n\n    /* check id bytes */\n    if (uzlib_get_byte(d) != 0x1f || uzlib_get_byte(d) != 0x8b) return TINF_DATA_ERROR;\n\n    /* check method is deflate */\n    if (uzlib_get_byte(d) != 8) return TINF_DATA_ERROR;\n\n    /* get flag byte */\n    flg = uzlib_get_byte(d);\n\n    /* check that reserved bits are zero */\n    if (flg & 0xe0) return TINF_DATA_ERROR;\n\n    /* -- find start of compressed data -- */\n\n    /* skip rest of base header of 10 bytes */\n    tinf_skip_bytes(d, 6);\n\n    /* skip extra data if present */\n    if (flg & FEXTRA)\n    {\n       unsigned int xlen = tinf_get_uint16(d);\n       tinf_skip_bytes(d, xlen);\n    }\n\n    /* skip file name if present */\n    if (flg & FNAME) { while (uzlib_get_byte(d)); }\n\n    /* skip file comment if present */\n    if (flg & FCOMMENT) { while (uzlib_get_byte(d)); }\n\n    /* check header crc if present */\n    if (flg & FHCRC)\n    {\n       /*unsigned int hcrc =*/ tinf_get_uint16(d);\n\n        // TODO: Check!\n//       if (hcrc != (tinf_crc32(src, start - src) & 0x0000ffff))\n//          return TINF_DATA_ERROR;\n    }\n\n    /* initialize for crc32 checksum */\n    d->checksum_type = TINF_CHKSUM_CRC;\n    d->checksum = ~0;\n\n    return TINF_OK;\n}\n"
  },
  {
    "path": "extmod/uzlib/tinflate.c",
    "content": "/*\n * uzlib  -  tiny deflate/inflate library (deflate, gzip, zlib)\n *\n * Copyright (c) 2003 by Joergen Ibsen / Jibz\n * All Rights Reserved\n * http://www.ibsensoftware.com/\n *\n * Copyright (c) 2014-2018 by Paul Sokolovsky\n *\n * This software is provided 'as-is', without any express\n * or implied warranty.  In no event will the authors be\n * held liable for any damages arising from the use of\n * this software.\n *\n * Permission is granted to anyone to use this software\n * for any purpose, including commercial applications,\n * and to alter it and redistribute it freely, subject to\n * the following restrictions:\n *\n * 1. The origin of this software must not be\n *    misrepresented; you must not claim that you\n *    wrote the original software. If you use this\n *    software in a product, an acknowledgment in\n *    the product documentation would be appreciated\n *    but is not required.\n *\n * 2. Altered source versions must be plainly marked\n *    as such, and must not be misrepresented as\n *    being the original software.\n *\n * 3. This notice may not be removed or altered from\n *    any source distribution.\n */\n\n#include <assert.h>\n#include \"tinf.h\"\n\n#define UZLIB_DUMP_ARRAY(heading, arr, size) \\\n    { \\\n        printf(\"%s\", heading); \\\n        for (int i = 0; i < size; ++i) { \\\n            printf(\" %d\", (arr)[i]); \\\n        } \\\n        printf(\"\\n\"); \\\n    }\n\nuint32_t tinf_get_le_uint32(TINF_DATA *d);\nuint32_t tinf_get_be_uint32(TINF_DATA *d);\n\n/* --------------------------------------------------- *\n * -- uninitialized global data (static structures) -- *\n * --------------------------------------------------- */\n\n#ifdef RUNTIME_BITS_TABLES\n\n/* extra bits and base tables for length codes */\nunsigned char length_bits[30];\nunsigned short length_base[30];\n\n/* extra bits and base tables for distance codes */\nunsigned char dist_bits[30];\nunsigned short dist_base[30];\n\n#else\n\nconst unsigned char length_bits[30] = {\n   0, 0, 0, 0, 0, 0, 0, 0,\n   1, 1, 1, 1, 2, 2, 2, 2,\n   3, 3, 3, 3, 4, 4, 4, 4,\n   5, 5, 5, 5\n};\nconst unsigned short length_base[30] = {\n   3, 4, 5, 6, 7, 8, 9, 10,\n   11, 13, 15, 17, 19, 23, 27, 31,\n   35, 43, 51, 59, 67, 83, 99, 115,\n   131, 163, 195, 227, 258\n};\n\nconst unsigned char dist_bits[30] = {\n   0, 0, 0, 0, 1, 1, 2, 2,\n   3, 3, 4, 4, 5, 5, 6, 6,\n   7, 7, 8, 8, 9, 9, 10, 10,\n   11, 11, 12, 12, 13, 13\n};\nconst unsigned short dist_base[30] = {\n   1, 2, 3, 4, 5, 7, 9, 13,\n   17, 25, 33, 49, 65, 97, 129, 193,\n   257, 385, 513, 769, 1025, 1537, 2049, 3073,\n   4097, 6145, 8193, 12289, 16385, 24577\n};\n\n#endif\n\n/* special ordering of code length codes */\nconst unsigned char clcidx[] = {\n   16, 17, 18, 0, 8, 7, 9, 6,\n   10, 5, 11, 4, 12, 3, 13, 2,\n   14, 1, 15\n};\n\n/* ----------------------- *\n * -- utility functions -- *\n * ----------------------- */\n\n#ifdef RUNTIME_BITS_TABLES\n/* build extra bits and base tables */\nstatic void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first)\n{\n   int i, sum;\n\n   /* build bits table */\n   for (i = 0; i < delta; ++i) bits[i] = 0;\n   for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta;\n\n   /* build base table */\n   for (sum = first, i = 0; i < 30; ++i)\n   {\n      base[i] = sum;\n      sum += 1 << bits[i];\n   }\n}\n#endif\n\n/* build the fixed huffman trees */\nstatic void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt)\n{\n   int i;\n\n   /* build fixed length tree */\n   for (i = 0; i < 7; ++i) lt->table[i] = 0;\n\n   lt->table[7] = 24;\n   lt->table[8] = 152;\n   lt->table[9] = 112;\n\n   for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i;\n   for (i = 0; i < 144; ++i) lt->trans[24 + i] = i;\n   for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i;\n   for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i;\n\n   /* build fixed distance tree */\n   for (i = 0; i < 5; ++i) dt->table[i] = 0;\n\n   dt->table[5] = 32;\n\n   for (i = 0; i < 32; ++i) dt->trans[i] = i;\n}\n\n/* given an array of code lengths, build a tree */\nstatic void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num)\n{\n   unsigned short offs[16];\n   unsigned int i, sum;\n\n   /* clear code length count table */\n   for (i = 0; i < 16; ++i) t->table[i] = 0;\n\n   /* scan symbol lengths, and sum code length counts */\n   for (i = 0; i < num; ++i) t->table[lengths[i]]++;\n\n   #if UZLIB_CONF_DEBUG_LOG >= 2\n   UZLIB_DUMP_ARRAY(\"codelen counts:\", t->table, TINF_ARRAY_SIZE(t->table));\n   #endif\n\n   /* In the lengths array, 0 means unused code. So, t->table[0] now contains\n      number of unused codes. But table's purpose is to contain # of codes of\n      particular length, and there're 0 codes of length 0. */\n   t->table[0] = 0;\n\n   /* compute offset table for distribution sort */\n   for (sum = 0, i = 0; i < 16; ++i)\n   {\n      offs[i] = sum;\n      sum += t->table[i];\n   }\n\n   #if UZLIB_CONF_DEBUG_LOG >= 2\n   UZLIB_DUMP_ARRAY(\"codelen offsets:\", offs, TINF_ARRAY_SIZE(offs));\n   #endif\n\n   /* create code->symbol translation table (symbols sorted by code) */\n   for (i = 0; i < num; ++i)\n   {\n      if (lengths[i]) t->trans[offs[lengths[i]]++] = i;\n   }\n}\n\n/* ---------------------- *\n * -- decode functions -- *\n * ---------------------- */\n\nunsigned char uzlib_get_byte(TINF_DATA *d)\n{\n    /* If end of source buffer is not reached, return next byte from source\n       buffer. */\n    if (d->source < d->source_limit) {\n        return *d->source++;\n    }\n\n    /* Otherwise if there's callback and we haven't seen EOF yet, try to\n       read next byte using it. (Note: the callback can also update ->source\n       and ->source_limit). */\n    if (d->readSource && !d->eof) {\n        int val = d->readSource(d);\n        if (val >= 0) {\n            return (unsigned char)val;\n        }\n    }\n\n    /* Otherwise, we hit EOF (either from ->readSource() or from exhaustion\n       of the buffer), and it will be \"sticky\", i.e. further calls to this\n       function will end up here too. */\n    d->eof = true;\n\n    return 0;\n}\n\nuint32_t tinf_get_le_uint32(TINF_DATA *d)\n{\n    uint32_t val = 0;\n    int i;\n    for (i = 4; i--;) {\n        val = val >> 8 | ((uint32_t)uzlib_get_byte(d)) << 24;\n    }\n    return val;\n}\n\nuint32_t tinf_get_be_uint32(TINF_DATA *d)\n{\n    uint32_t val = 0;\n    int i;\n    for (i = 4; i--;) {\n        val = val << 8 | uzlib_get_byte(d);\n    }\n    return val;\n}\n\n/* get one bit from source stream */\nstatic int tinf_getbit(TINF_DATA *d)\n{\n   unsigned int bit;\n\n   /* check if tag is empty */\n   if (!d->bitcount--)\n   {\n      /* load next tag */\n      d->tag = uzlib_get_byte(d);\n      d->bitcount = 7;\n   }\n\n   /* shift bit out of tag */\n   bit = d->tag & 0x01;\n   d->tag >>= 1;\n\n   return bit;\n}\n\n/* read a num bit value from a stream and add base */\nstatic unsigned int tinf_read_bits(TINF_DATA *d, int num, int base)\n{\n   unsigned int val = 0;\n\n   /* read num bits */\n   if (num)\n   {\n      unsigned int limit = 1 << (num);\n      unsigned int mask;\n\n      for (mask = 1; mask < limit; mask *= 2)\n         if (tinf_getbit(d)) val += mask;\n   }\n\n   return val + base;\n}\n\n/* given a data stream and a tree, decode a symbol */\nstatic int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)\n{\n   int sum = 0, cur = 0, len = 0;\n\n   /* get more bits while code value is above sum */\n   do {\n\n      cur = 2*cur + tinf_getbit(d);\n\n      if (++len == TINF_ARRAY_SIZE(t->table)) {\n         return TINF_DATA_ERROR;\n      }\n\n      sum += t->table[len];\n      cur -= t->table[len];\n\n   } while (cur >= 0);\n\n   sum += cur;\n   #if UZLIB_CONF_PARANOID_CHECKS\n   if (sum < 0 || sum >= TINF_ARRAY_SIZE(t->trans)) {\n      return TINF_DATA_ERROR;\n   }\n   #endif\n\n   return t->trans[sum];\n}\n\n/* given a data stream, decode dynamic trees from it */\nstatic int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)\n{\n   /* code lengths for 288 literal/len symbols and 32 dist symbols */\n   unsigned char lengths[288+32];\n   unsigned int hlit, hdist, hclen, hlimit;\n   unsigned int i, num, length;\n\n   /* get 5 bits HLIT (257-286) */\n   hlit = tinf_read_bits(d, 5, 257);\n\n   /* get 5 bits HDIST (1-32) */\n   hdist = tinf_read_bits(d, 5, 1);\n\n   /* get 4 bits HCLEN (4-19) */\n   hclen = tinf_read_bits(d, 4, 4);\n\n   for (i = 0; i < 19; ++i) lengths[i] = 0;\n\n   /* read code lengths for code length alphabet */\n   for (i = 0; i < hclen; ++i)\n   {\n      /* get 3 bits code length (0-7) */\n      unsigned int clen = tinf_read_bits(d, 3, 0);\n\n      lengths[clcidx[i]] = clen;\n   }\n\n   /* build code length tree, temporarily use length tree */\n   tinf_build_tree(lt, lengths, 19);\n\n   /* decode code lengths for the dynamic trees */\n   hlimit = hlit + hdist;\n   for (num = 0; num < hlimit; )\n   {\n      int sym = tinf_decode_symbol(d, lt);\n      unsigned char fill_value = 0;\n      int lbits, lbase = 3;\n\n      /* error decoding */\n      if (sym < 0) return sym;\n\n      switch (sym)\n      {\n      case 16:\n         /* copy previous code length 3-6 times (read 2 bits) */\n         if (num == 0) return TINF_DATA_ERROR;\n         fill_value = lengths[num - 1];\n         lbits = 2;\n         break;\n      case 17:\n         /* repeat code length 0 for 3-10 times (read 3 bits) */\n         lbits = 3;\n         break;\n      case 18:\n         /* repeat code length 0 for 11-138 times (read 7 bits) */\n         lbits = 7;\n         lbase = 11;\n         break;\n      default:\n         /* values 0-15 represent the actual code lengths */\n         lengths[num++] = sym;\n         /* continue the for loop */\n         continue;\n      }\n\n      /* special code length 16-18 are handled here */\n      length = tinf_read_bits(d, lbits, lbase);\n      if (num + length > hlimit) return TINF_DATA_ERROR;\n      for (; length; --length)\n      {\n         lengths[num++] = fill_value;\n      }\n   }\n\n   #if UZLIB_CONF_DEBUG_LOG >= 2\n   printf(\"lit code lengths (%d):\", hlit);\n   UZLIB_DUMP_ARRAY(\"\", lengths, hlit);\n   printf(\"dist code lengths (%d):\", hdist);\n   UZLIB_DUMP_ARRAY(\"\", lengths + hlit, hdist);\n   #endif\n\n   #if UZLIB_CONF_PARANOID_CHECKS\n   /* Check that there's \"end of block\" symbol */\n   if (lengths[256] == 0) {\n      return TINF_DATA_ERROR;\n   }\n   #endif\n\n   /* build dynamic trees */\n   tinf_build_tree(lt, lengths, hlit);\n   tinf_build_tree(dt, lengths + hlit, hdist);\n\n   return TINF_OK;\n}\n\n/* ----------------------------- *\n * -- block inflate functions -- *\n * ----------------------------- */\n\n/* given a stream and two trees, inflate next byte of output */\nstatic int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)\n{\n    if (d->curlen == 0) {\n        unsigned int offs;\n        int dist;\n        int sym = tinf_decode_symbol(d, lt);\n        //printf(\"huff sym: %02x\\n\", sym);\n\n        if (d->eof) {\n            return TINF_DATA_ERROR;\n        }\n\n        /* literal byte */\n        if (sym < 256) {\n            TINF_PUT(d, sym);\n            return TINF_OK;\n        }\n\n        /* end of block */\n        if (sym == 256) {\n            return TINF_DONE;\n        }\n\n        /* substring from sliding dictionary */\n        sym -= 257;\n        if (sym >= 29) {\n            return TINF_DATA_ERROR;\n        }\n\n        /* possibly get more bits from length code */\n        d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]);\n\n        dist = tinf_decode_symbol(d, dt);\n        if (dist >= 30) {\n            return TINF_DATA_ERROR;\n        }\n\n        /* possibly get more bits from distance code */\n        offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);\n\n        /* calculate and validate actual LZ offset to use */\n        if (d->dict_ring) {\n            if (offs > d->dict_size) {\n                return TINF_DICT_ERROR;\n            }\n            /* Note: unlike full-dest-in-memory case below, we don't\n               try to catch offset which points to not yet filled\n               part of the dictionary here. Doing so would require\n               keeping another variable to track \"filled in\" size\n               of the dictionary. Appearance of such an offset cannot\n               lead to accessing memory outside of the dictionary\n               buffer, and clients which don't want to leak unrelated\n               information, should explicitly initialize dictionary\n               buffer passed to uzlib. */\n\n            d->lzOff = d->dict_idx - offs;\n            if (d->lzOff < 0) {\n                d->lzOff += d->dict_size;\n            }\n        } else {\n            /* catch trying to point before the start of dest buffer */\n            if (offs > d->dest - d->destStart) {\n                return TINF_DATA_ERROR;\n            }\n            d->lzOff = -offs;\n        }\n    }\n\n    /* copy next byte from dict substring */\n    if (d->dict_ring) {\n        TINF_PUT(d, d->dict_ring[d->lzOff]);\n        if ((unsigned)++d->lzOff == d->dict_size) {\n            d->lzOff = 0;\n        }\n    } else {\n        d->dest[0] = d->dest[d->lzOff];\n        d->dest++;\n    }\n    d->curlen--;\n    return TINF_OK;\n}\n\n/* inflate next byte from uncompressed block of data */\nstatic int tinf_inflate_uncompressed_block(TINF_DATA *d)\n{\n    if (d->curlen == 0) {\n        unsigned int length, invlength;\n\n        /* get length */\n        length = uzlib_get_byte(d);\n        length += 256 * uzlib_get_byte(d);\n        /* get one's complement of length */\n        invlength = uzlib_get_byte(d);\n        invlength += 256 * uzlib_get_byte(d);\n        /* check length */\n        if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;\n\n        /* increment length to properly return TINF_DONE below, without\n           producing data at the same time */\n        d->curlen = length + 1;\n\n        /* make sure we start next block on a byte boundary */\n        d->bitcount = 0;\n    }\n\n    if (--d->curlen == 0) {\n        return TINF_DONE;\n    }\n\n    unsigned char c = uzlib_get_byte(d);\n    TINF_PUT(d, c);\n    return TINF_OK;\n}\n\n/* ---------------------- *\n * -- public functions -- *\n * ---------------------- */\n\n/* initialize global (static) data */\nvoid uzlib_init(void)\n{\n#ifdef RUNTIME_BITS_TABLES\n   /* build extra bits and base tables */\n   tinf_build_bits_base(length_bits, length_base, 4, 3);\n   tinf_build_bits_base(dist_bits, dist_base, 2, 1);\n\n   /* fix a special case */\n   length_bits[28] = 0;\n   length_base[28] = 258;\n#endif\n}\n\n/* initialize decompression structure */\nvoid uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen)\n{\n   d->eof = 0;\n   d->bitcount = 0;\n   d->bfinal = 0;\n   d->btype = -1;\n   d->dict_size = dictLen;\n   d->dict_ring = dict;\n   d->dict_idx = 0;\n   d->curlen = 0;\n}\n\n/* inflate next output bytes from compressed stream */\nint uzlib_uncompress(TINF_DATA *d)\n{\n    do {\n        int res;\n\n        /* start a new block */\n        if (d->btype == -1) {\nnext_blk:\n            /* read final block flag */\n            d->bfinal = tinf_getbit(d);\n            /* read block type (2 bits) */\n            d->btype = tinf_read_bits(d, 2, 0);\n\n            #if UZLIB_CONF_DEBUG_LOG >= 1\n            printf(\"Started new block: type=%d final=%d\\n\", d->btype, d->bfinal);\n            #endif\n\n            if (d->btype == 1) {\n                /* build fixed huffman trees */\n                tinf_build_fixed_trees(&d->ltree, &d->dtree);\n            } else if (d->btype == 2) {\n                /* decode trees from stream */\n                res = tinf_decode_trees(d, &d->ltree, &d->dtree);\n                if (res != TINF_OK) {\n                    return res;\n                }\n            }\n        }\n\n        /* process current block */\n        switch (d->btype)\n        {\n        case 0:\n            /* decompress uncompressed block */\n            res = tinf_inflate_uncompressed_block(d);\n            break;\n        case 1:\n        case 2:\n            /* decompress block with fixed/dynamic huffman trees */\n            /* trees were decoded previously, so it's the same routine for both */\n            res = tinf_inflate_block_data(d, &d->ltree, &d->dtree);\n            break;\n        default:\n            return TINF_DATA_ERROR;\n        }\n\n        if (res == TINF_DONE && !d->bfinal) {\n            /* the block has ended (without producing more data), but we\n               can't return without data, so start procesing next block */\n            goto next_blk;\n        }\n\n        if (res != TINF_OK) {\n            return res;\n        }\n\n    } while (d->dest < d->dest_limit);\n\n    return TINF_OK;\n}\n\n/* inflate next output bytes from compressed stream, updating\n   checksum, and at the end of stream, verify it */\nint uzlib_uncompress_chksum(TINF_DATA *d)\n{\n    int res;\n    unsigned char *data = d->dest;\n\n    res = uzlib_uncompress(d);\n\n    if (res < 0) return res;\n\n    switch (d->checksum_type) {\n\n    case TINF_CHKSUM_ADLER:\n        d->checksum = uzlib_adler32(data, d->dest - data, d->checksum);\n        break;\n\n    case TINF_CHKSUM_CRC:\n        d->checksum = uzlib_crc32(data, d->dest - data, d->checksum);\n        break;\n    }\n\n    if (res == TINF_DONE) {\n        unsigned int val;\n\n        switch (d->checksum_type) {\n\n        case TINF_CHKSUM_ADLER:\n            val = tinf_get_be_uint32(d);\n            if (d->checksum != val) {\n                return TINF_CHKSUM_ERROR;\n            }\n            break;\n\n        case TINF_CHKSUM_CRC:\n            val = tinf_get_le_uint32(d);\n            if (~d->checksum != val) {\n                return TINF_CHKSUM_ERROR;\n            }\n            // Uncompressed size. TODO: Check\n            val = tinf_get_le_uint32(d);\n            break;\n        }\n    }\n\n    return res;\n}\n"
  },
  {
    "path": "extmod/uzlib/tinfzlib.c",
    "content": "/*\n * uzlib  -  tiny deflate/inflate library (deflate, gzip, zlib)\n *\n * Copyright (c) 2003 by Joergen Ibsen / Jibz\n * All Rights Reserved\n *\n * http://www.ibsensoftware.com/\n *\n * Copyright (c) 2014-2018 by Paul Sokolovsky\n *\n * This software is provided 'as-is', without any express\n * or implied warranty.  In no event will the authors be\n * held liable for any damages arising from the use of\n * this software.\n *\n * Permission is granted to anyone to use this software\n * for any purpose, including commercial applications,\n * and to alter it and redistribute it freely, subject to\n * the following restrictions:\n *\n * 1. The origin of this software must not be\n *    misrepresented; you must not claim that you\n *    wrote the original software. If you use this\n *    software in a product, an acknowledgment in\n *    the product documentation would be appreciated\n *    but is not required.\n *\n * 2. Altered source versions must be plainly marked\n *    as such, and must not be misrepresented as\n *    being the original software.\n *\n * 3. This notice may not be removed or altered from\n *    any source distribution.\n */\n\n#include \"tinf.h\"\n\nint uzlib_zlib_parse_header(TINF_DATA *d)\n{\n   unsigned char cmf, flg;\n\n   /* -- get header bytes -- */\n\n   cmf = uzlib_get_byte(d);\n   flg = uzlib_get_byte(d);\n\n   /* -- check format -- */\n\n   /* check checksum */\n   if ((256*cmf + flg) % 31) return TINF_DATA_ERROR;\n\n   /* check method is deflate */\n   if ((cmf & 0x0f) != 8) return TINF_DATA_ERROR;\n\n   /* check window size is valid */\n   if ((cmf >> 4) > 7) return TINF_DATA_ERROR;\n\n   /* check there is no preset dictionary */\n   if (flg & 0x20) return TINF_DATA_ERROR;\n\n   /* initialize for adler32 checksum */\n   d->checksum_type = TINF_CHKSUM_ADLER;\n   d->checksum = 1;\n\n   return cmf >> 4;\n}\n"
  },
  {
    "path": "extmod/uzlib/uzlib.h",
    "content": "/*\n * uzlib  -  tiny deflate/inflate library (deflate, gzip, zlib)\n *\n * Copyright (c) 2003 by Joergen Ibsen / Jibz\n * All Rights Reserved\n * http://www.ibsensoftware.com/\n *\n * Copyright (c) 2014-2018 by Paul Sokolovsky\n *\n * This software is provided 'as-is', without any express\n * or implied warranty.  In no event will the authors be\n * held liable for any damages arising from the use of\n * this software.\n *\n * Permission is granted to anyone to use this software\n * for any purpose, including commercial applications,\n * and to alter it and redistribute it freely, subject to\n * the following restrictions:\n *\n * 1. The origin of this software must not be\n *    misrepresented; you must not claim that you\n *    wrote the original software. If you use this\n *    software in a product, an acknowledgment in\n *    the product documentation would be appreciated\n *    but is not required.\n *\n * 2. Altered source versions must be plainly marked\n *    as such, and must not be misrepresented as\n *    being the original software.\n *\n * 3. This notice may not be removed or altered from\n *    any source distribution.\n */\n\n#ifndef UZLIB_H_INCLUDED\n#define UZLIB_H_INCLUDED\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdbool.h>\n\n#include \"defl_static.h\"\n\n#include \"uzlib_conf.h\"\n#if UZLIB_CONF_DEBUG_LOG\n#include <stdio.h>\n#endif\n\n/* calling convention */\n#ifndef TINFCC\n #ifdef __WATCOMC__\n  #define TINFCC __cdecl\n #else\n  #define TINFCC\n #endif\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* ok status, more data produced */\n#define TINF_OK             0\n/* end of compressed stream reached */\n#define TINF_DONE           1\n#define TINF_DATA_ERROR    (-3)\n#define TINF_CHKSUM_ERROR  (-4)\n#define TINF_DICT_ERROR    (-5)\n\n/* checksum types */\n#define TINF_CHKSUM_NONE  0\n#define TINF_CHKSUM_ADLER 1\n#define TINF_CHKSUM_CRC   2\n\n/* helper macros */\n#define TINF_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr)))\n\n/* data structures */\n\ntypedef struct {\n   unsigned short table[16];  /* table of code length counts */\n   unsigned short trans[288]; /* code -> symbol translation table */\n} TINF_TREE;\n\nstruct uzlib_uncomp {\n    /* Pointer to the next byte in the input buffer */\n    const unsigned char *source;\n    /* Pointer to the next byte past the input buffer (source_limit = source + len) */\n    const unsigned char *source_limit;\n    /* If source_limit == NULL, or source >= source_limit, this function\n       will be used to read next byte from source stream. The function may\n       also return -1 in case of EOF (or irrecoverable error). Note that\n       besides returning the next byte, it may also update source and\n       source_limit fields, thus allowing for buffered operation. */\n    int (*source_read_cb)(struct uzlib_uncomp *uncomp);\n\n    unsigned int tag;\n    unsigned int bitcount;\n\n    /* Destination (output) buffer start */\n    unsigned char *dest_start;\n    /* Current pointer in dest buffer */\n    unsigned char *dest;\n    /* Pointer past the end of the dest buffer, similar to source_limit */\n    unsigned char *dest_limit;\n\n    /* Accumulating checksum */\n    unsigned int checksum;\n    char checksum_type;\n    bool eof;\n\n    int btype;\n    int bfinal;\n    unsigned int curlen;\n    int lzOff;\n    unsigned char *dict_ring;\n    unsigned int dict_size;\n    unsigned int dict_idx;\n\n    TINF_TREE ltree; /* dynamic length/symbol tree */\n    TINF_TREE dtree; /* dynamic distance tree */\n};\n\n#include \"tinf_compat.h\"\n\n#define TINF_PUT(d, c) \\\n    { \\\n        *d->dest++ = c; \\\n        if (d->dict_ring) { d->dict_ring[d->dict_idx++] = c; if (d->dict_idx == d->dict_size) d->dict_idx = 0; } \\\n    }\n\nunsigned char TINFCC uzlib_get_byte(TINF_DATA *d);\n\n/* Decompression API */\n\nvoid TINFCC uzlib_init(void);\nvoid TINFCC uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen);\nint  TINFCC uzlib_uncompress(TINF_DATA *d);\nint  TINFCC uzlib_uncompress_chksum(TINF_DATA *d);\n\nint TINFCC uzlib_zlib_parse_header(TINF_DATA *d);\nint TINFCC uzlib_gzip_parse_header(TINF_DATA *d);\n\n/* Compression API */\n\ntypedef const uint8_t *uzlib_hash_entry_t;\n\nstruct uzlib_comp {\n    struct Outbuf out;\n\n    uzlib_hash_entry_t *hash_table;\n    unsigned int hash_bits;\n    unsigned int dict_size;\n};\n\nvoid TINFCC uzlib_compress(struct uzlib_comp *c, const uint8_t *src, unsigned slen);\n\n/* Checksum API */\n\n/* prev_sum is previous value for incremental computation, 1 initially */\nuint32_t TINFCC uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum);\n/* crc is previous value for incremental computation, 0xffffffff initially */\nuint32_t TINFCC uzlib_crc32(const void *data, unsigned int length, uint32_t crc);\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /* UZLIB_H_INCLUDED */\n"
  },
  {
    "path": "extmod/uzlib/uzlib_conf.h",
    "content": "/*\n * uzlib  -  tiny deflate/inflate library (deflate, gzip, zlib)\n *\n * Copyright (c) 2014-2018 by Paul Sokolovsky\n */\n\n#ifndef UZLIB_CONF_H_INCLUDED\n#define UZLIB_CONF_H_INCLUDED\n\n#ifndef UZLIB_CONF_DEBUG_LOG\n/* Debug logging level 0, 1, 2, etc. */\n#define UZLIB_CONF_DEBUG_LOG 0\n#endif\n\n#ifndef UZLIB_CONF_PARANOID_CHECKS\n/* Perform extra checks on the input stream, even if they aren't proven\n   to be strictly required (== lack of them wasn't proven to lead to\n   crashes). */\n#define UZLIB_CONF_PARANOID_CHECKS 0\n#endif\n\n#endif /* UZLIB_CONF_H_INCLUDED */\n"
  },
  {
    "path": "extmod/vfs.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/objstr.h\"\n#include \"py/mperrno.h\"\n#include \"extmod/vfs.h\"\n\n#if MICROPY_VFS\n\n#if MICROPY_VFS_FAT\n#include \"extmod/vfs_fat.h\"\n#endif\n\n#if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2\n#include \"extmod/vfs_lfs.h\"\n#endif\n\n#if MICROPY_VFS_POSIX\n#include \"extmod/vfs_posix.h\"\n#endif\n\n// For mp_vfs_proxy_call, the maximum number of additional args that can be passed.\n// A fixed maximum size is used to avoid the need for a costly variable array.\n#define PROXY_MAX_ARGS (2)\n\n// path is the path to lookup and *path_out holds the path within the VFS\n// object (starts with / if an absolute path).\n// Returns MP_VFS_ROOT for root dir (and then path_out is undefined) and\n// MP_VFS_NONE for path not found.\nmp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out) {\n    if (*path == '/' || MP_STATE_VM(vfs_cur) == MP_VFS_ROOT) {\n        // an absolute path, or the current volume is root, so search root dir\n        bool is_abs = 0;\n        if (*path == '/') {\n            ++path;\n            is_abs = 1;\n        }\n        if (*path == '\\0') {\n            // path is \"\" or \"/\" so return virtual root\n            return MP_VFS_ROOT;\n        }\n        for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {\n            size_t len = vfs->len - 1;\n            if (len == 0) {\n                *path_out = path - is_abs;\n                return vfs;\n            }\n            if (strncmp(path, vfs->str + 1, len) == 0) {\n                if (path[len] == '/') {\n                    *path_out = path + len;\n                    return vfs;\n                } else if (path[len] == '\\0') {\n                    *path_out = \"/\";\n                    return vfs;\n                }\n            }\n        }\n\n        // if we get here then there's nothing mounted on /\n\n        if (is_abs) {\n            // path began with / and was not found\n            return MP_VFS_NONE;\n        }\n    }\n\n    // a relative path within a mounted device\n    *path_out = path;\n    return MP_STATE_VM(vfs_cur);\n}\n\n// Version of mp_vfs_lookup_path that takes and returns uPy string objects.\nSTATIC mp_vfs_mount_t *lookup_path(mp_obj_t path_in, mp_obj_t *path_out) {\n    const char *path = mp_obj_str_get_str(path_in);\n    const char *p_out;\n    mp_vfs_mount_t *vfs = mp_vfs_lookup_path(path, &p_out);\n    if (vfs != MP_VFS_NONE && vfs != MP_VFS_ROOT) {\n        *path_out = mp_obj_new_str_of_type(mp_obj_get_type(path_in),\n            (const byte*)p_out, strlen(p_out));\n    }\n    return vfs;\n}\n\nSTATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_args, const mp_obj_t *args) {\n    assert(n_args <= PROXY_MAX_ARGS);\n    if (vfs == MP_VFS_NONE) {\n        // mount point not found\n        mp_raise_OSError(MP_ENODEV);\n    }\n    if (vfs == MP_VFS_ROOT) {\n        // can't do operation on root dir\n        mp_raise_OSError(MP_EPERM);\n    }\n    mp_obj_t meth[2 + PROXY_MAX_ARGS];\n    mp_load_method(vfs->obj, meth_name, meth);\n    if (args != NULL) {\n        memcpy(meth + 2, args, n_args * sizeof(*args));\n    }\n    return mp_call_method_n_kw(n_args, 0, meth);\n}\n\nmp_import_stat_t mp_vfs_import_stat(const char *path) {\n    const char *path_out;\n    mp_vfs_mount_t *vfs = mp_vfs_lookup_path(path, &path_out);\n    if (vfs == MP_VFS_NONE || vfs == MP_VFS_ROOT) {\n        return MP_IMPORT_STAT_NO_EXIST;\n    }\n\n    // If the mounted object has the VFS protocol, call its import_stat helper\n    const mp_vfs_proto_t *proto = mp_obj_get_type(vfs->obj)->protocol;\n    if (proto != NULL) {\n        return proto->import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out);\n    }\n\n    // delegate to vfs.stat() method\n    mp_obj_t path_o = mp_obj_new_str(path_out, strlen(path_out));\n    mp_obj_t stat;\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        stat = mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_o);\n        nlr_pop();\n    } else {\n        // assume an exception means that the path is not found\n        return MP_IMPORT_STAT_NO_EXIST;\n    }\n    mp_obj_t *items;\n    mp_obj_get_array_fixed_n(stat, 10, &items);\n    mp_int_t st_mode = mp_obj_get_int(items[0]);\n    if (st_mode & MP_S_IFDIR) {\n        return MP_IMPORT_STAT_DIR;\n    } else {\n        return MP_IMPORT_STAT_FILE;\n    }\n}\n\nSTATIC mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) {\n    #if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        mp_obj_t vfs = MP_OBJ_NULL;\n        mp_vfs_blockdev_t blockdev;\n        mp_vfs_blockdev_init(&blockdev, bdev_obj);\n        uint8_t buf[44];\n        mp_vfs_blockdev_read_ext(&blockdev, 0, 8, sizeof(buf), buf);\n        #if MICROPY_VFS_LFS1\n        if (memcmp(&buf[32], \"littlefs\", 8) == 0) {\n            // LFS1\n            vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, 0, &bdev_obj);\n            nlr_pop();\n            return vfs;\n        }\n        #endif\n        #if MICROPY_VFS_LFS2\n        if (memcmp(&buf[0], \"littlefs\", 8) == 0) {\n            // LFS2\n            vfs = mp_type_vfs_lfs2.make_new(&mp_type_vfs_lfs2, 1, 0, &bdev_obj);\n            nlr_pop();\n            return vfs;\n        }\n        #endif\n        nlr_pop();\n    } else {\n        // Ignore exception (eg block device doesn't support extended readblocks)\n    }\n    #endif\n\n    #if MICROPY_VFS_FAT\n    return mp_fat_vfs_type.make_new(&mp_fat_vfs_type, 1, 0, &bdev_obj);\n    #endif\n\n    return bdev_obj;\n}\n\nmp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_readonly, ARG_mkfs };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} },\n        { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} },\n    };\n\n    // parse args\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n\n    // get the mount point\n    size_t mnt_len;\n    const char *mnt_str = mp_obj_str_get_data(pos_args[1], &mnt_len);\n\n    // see if we need to auto-detect and create the filesystem\n    mp_obj_t vfs_obj = pos_args[0];\n    mp_obj_t dest[2];\n    mp_load_method_maybe(vfs_obj, MP_QSTR_mount, dest);\n    if (dest[0] == MP_OBJ_NULL) {\n        // Input object has no mount method, assume it's a block device and try to\n        // auto-detect the filesystem and create the corresponding VFS entity.\n        vfs_obj = mp_vfs_autodetect(vfs_obj);\n    }\n\n    // create new object\n    mp_vfs_mount_t *vfs = m_new_obj(mp_vfs_mount_t);\n    vfs->str = mnt_str;\n    vfs->len = mnt_len;\n    vfs->obj = vfs_obj;\n    vfs->next = NULL;\n\n    // call the underlying object to do any mounting operation\n    mp_vfs_proxy_call(vfs, MP_QSTR_mount, 2, (mp_obj_t*)&args);\n\n    // check that the destination mount point is unused\n    const char *path_out;\n    mp_vfs_mount_t *existing_mount = mp_vfs_lookup_path(mp_obj_str_get_str(pos_args[1]), &path_out);\n    if (existing_mount != MP_VFS_NONE && existing_mount != MP_VFS_ROOT) {\n        if (vfs->len != 1 && existing_mount->len == 1) {\n            // if root dir is mounted, still allow to mount something within a subdir of root\n        } else {\n            // mount point in use\n            mp_raise_OSError(MP_EPERM);\n        }\n    }\n\n    // insert the vfs into the mount table\n    mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table);\n    while (*vfsp != NULL) {\n        if ((*vfsp)->len == 1) {\n            // make sure anything mounted at the root stays at the end of the list\n            vfs->next = *vfsp;\n            break;\n        }\n        vfsp = &(*vfsp)->next;\n    }\n    *vfsp = vfs;\n\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj, 2, mp_vfs_mount);\n\nmp_obj_t mp_vfs_umount(mp_obj_t mnt_in) {\n    // remove vfs from the mount table\n    mp_vfs_mount_t *vfs = NULL;\n    size_t mnt_len;\n    const char *mnt_str = NULL;\n    if (mp_obj_is_str(mnt_in)) {\n        mnt_str = mp_obj_str_get_data(mnt_in, &mnt_len);\n    }\n    for (mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table); *vfsp != NULL; vfsp = &(*vfsp)->next) {\n        if ((mnt_str != NULL && !memcmp(mnt_str, (*vfsp)->str, mnt_len + 1)) || (*vfsp)->obj == mnt_in) {\n            vfs = *vfsp;\n            *vfsp = (*vfsp)->next;\n            break;\n        }\n    }\n\n    if (vfs == NULL) {\n        mp_raise_OSError(MP_EINVAL);\n    }\n\n    // if we unmounted the current device then set current to root\n    if (MP_STATE_VM(vfs_cur) == vfs) {\n        MP_STATE_VM(vfs_cur) = MP_VFS_ROOT;\n    }\n\n    // call the underlying object to do any unmounting operation\n    mp_vfs_proxy_call(vfs, MP_QSTR_umount, 0, NULL);\n\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_umount_obj, mp_vfs_umount);\n\n// Note: buffering and encoding args are currently ignored\nmp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_file, ARG_mode, ARG_encoding };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },\n        { MP_QSTR_buffering, MP_ARG_INT, {.u_int = -1} },\n        { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n    };\n\n    // parse args\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n\n    #if MICROPY_VFS_POSIX\n    // If the file is an integer then delegate straight to the POSIX handler\n    if (mp_obj_is_small_int(args[ARG_file].u_obj)) {\n        return mp_vfs_posix_file_open(&mp_type_textio, args[ARG_file].u_obj, args[ARG_mode].u_obj);\n    }\n    #endif\n\n    mp_vfs_mount_t *vfs = lookup_path(args[ARG_file].u_obj, &args[ARG_file].u_obj);\n    return mp_vfs_proxy_call(vfs, MP_QSTR_open, 2, (mp_obj_t*)&args);\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_open_obj, 0, mp_vfs_open);\n\nmp_obj_t mp_vfs_chdir(mp_obj_t path_in) {\n    mp_obj_t path_out;\n    mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);\n    MP_STATE_VM(vfs_cur) = vfs;\n    if (vfs == MP_VFS_ROOT) {\n        // If we change to the root dir and a VFS is mounted at the root then\n        // we must change that VFS's current dir to the root dir so that any\n        // subsequent relative paths begin at the root of that VFS.\n        for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {\n            if (vfs->len == 1) {\n                mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_);\n                mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &root);\n                break;\n            }\n        }\n    } else {\n        mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &path_out);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj, mp_vfs_chdir);\n\nmp_obj_t mp_vfs_getcwd(void) {\n    if (MP_STATE_VM(vfs_cur) == MP_VFS_ROOT) {\n        return MP_OBJ_NEW_QSTR(MP_QSTR__slash_);\n    }\n    mp_obj_t cwd_o = mp_vfs_proxy_call(MP_STATE_VM(vfs_cur), MP_QSTR_getcwd, 0, NULL);\n    if (MP_STATE_VM(vfs_cur)->len == 1) {\n        // don't prepend \"/\" for vfs mounted at root\n        return cwd_o;\n    }\n    const char *cwd = mp_obj_str_get_str(cwd_o);\n    vstr_t vstr;\n    vstr_init(&vstr, MP_STATE_VM(vfs_cur)->len + strlen(cwd) + 1);\n    vstr_add_strn(&vstr, MP_STATE_VM(vfs_cur)->str, MP_STATE_VM(vfs_cur)->len);\n    if (!(cwd[0] == '/' && cwd[1] == 0)) {\n        vstr_add_str(&vstr, cwd);\n    }\n    return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_0(mp_vfs_getcwd_obj, mp_vfs_getcwd);\n\ntypedef struct _mp_vfs_ilistdir_it_t {\n    mp_obj_base_t base;\n    mp_fun_1_t iternext;\n    union {\n        mp_vfs_mount_t *vfs;\n        mp_obj_t iter;\n    } cur;\n    bool is_str;\n    bool is_iter;\n} mp_vfs_ilistdir_it_t;\n\nSTATIC mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in) {\n    mp_vfs_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->is_iter) {\n        // continue delegating to root dir\n        return mp_iternext(self->cur.iter);\n    } else if (self->cur.vfs == NULL) {\n        // finished iterating mount points and no root dir is mounted\n        return MP_OBJ_STOP_ITERATION;\n    } else {\n        // continue iterating mount points\n        mp_vfs_mount_t *vfs = self->cur.vfs;\n        self->cur.vfs = vfs->next;\n        if (vfs->len == 1) {\n            // vfs is mounted at root dir, delegate to it\n            mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_);\n            self->is_iter = true;\n            self->cur.iter = mp_vfs_proxy_call(vfs, MP_QSTR_ilistdir, 1, &root);\n            return mp_iternext(self->cur.iter);\n        } else {\n            // a mounted directory\n            mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));\n            t->items[0] = mp_obj_new_str_of_type(\n                self->is_str ? &mp_type_str : &mp_type_bytes,\n                (const byte*)vfs->str + 1, vfs->len - 1);\n            t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);\n            t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number\n            return MP_OBJ_FROM_PTR(t);\n        }\n    }\n}\n\nmp_obj_t mp_vfs_ilistdir(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t path_in;\n    if (n_args == 1) {\n        path_in = args[0];\n    } else {\n        path_in = MP_OBJ_NEW_QSTR(MP_QSTR_);\n    }\n\n    mp_obj_t path_out;\n    mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);\n\n    if (vfs == MP_VFS_ROOT) {\n        // list the root directory\n        mp_vfs_ilistdir_it_t *iter = m_new_obj(mp_vfs_ilistdir_it_t);\n        iter->base.type = &mp_type_polymorph_iter;\n        iter->iternext = mp_vfs_ilistdir_it_iternext;\n        iter->cur.vfs = MP_STATE_VM(vfs_mount_table);\n        iter->is_str = mp_obj_get_type(path_in) == &mp_type_str;\n        iter->is_iter = false;\n        return MP_OBJ_FROM_PTR(iter);\n    }\n\n    return mp_vfs_proxy_call(vfs, MP_QSTR_ilistdir, 1, &path_out);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_ilistdir_obj, 0, 1, mp_vfs_ilistdir);\n\nmp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t iter = mp_vfs_ilistdir(n_args, args);\n    mp_obj_t dir_list = mp_obj_new_list(0, NULL);\n    mp_obj_t next;\n    while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n        mp_obj_list_append(dir_list, mp_obj_subscr(next, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL));\n    }\n    return dir_list;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_listdir_obj, 0, 1, mp_vfs_listdir);\n\nmp_obj_t mp_vfs_mkdir(mp_obj_t path_in) {\n    mp_obj_t path_out;\n    mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);\n    if (vfs == MP_VFS_ROOT || (vfs != MP_VFS_NONE && !strcmp(mp_obj_str_get_str(path_out), \"/\"))) {\n        mp_raise_OSError(MP_EEXIST);\n    }\n    return mp_vfs_proxy_call(vfs, MP_QSTR_mkdir, 1, &path_out);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_mkdir_obj, mp_vfs_mkdir);\n\nmp_obj_t mp_vfs_remove(mp_obj_t path_in) {\n    mp_obj_t path_out;\n    mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);\n    return mp_vfs_proxy_call(vfs, MP_QSTR_remove, 1, &path_out);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_remove_obj, mp_vfs_remove);\n\nmp_obj_t mp_vfs_rename(mp_obj_t old_path_in, mp_obj_t new_path_in) {\n    mp_obj_t args[2];\n    mp_vfs_mount_t *old_vfs = lookup_path(old_path_in, &args[0]);\n    mp_vfs_mount_t *new_vfs = lookup_path(new_path_in, &args[1]);\n    if (old_vfs != new_vfs) {\n        // can't rename across filesystems\n        mp_raise_OSError(MP_EPERM);\n    }\n    return mp_vfs_proxy_call(old_vfs, MP_QSTR_rename, 2, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_vfs_rename_obj, mp_vfs_rename);\n\nmp_obj_t mp_vfs_rmdir(mp_obj_t path_in) {\n    mp_obj_t path_out;\n    mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);\n    return mp_vfs_proxy_call(vfs, MP_QSTR_rmdir, 1, &path_out);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_rmdir_obj, mp_vfs_rmdir);\n\nmp_obj_t mp_vfs_stat(mp_obj_t path_in) {\n    mp_obj_t path_out;\n    mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);\n    if (vfs == MP_VFS_ROOT) {\n        mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));\n        t->items[0] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); // st_mode\n        for (int i = 1; i <= 9; ++i) {\n            t->items[i] = MP_OBJ_NEW_SMALL_INT(0); // dev, nlink, uid, gid, size, atime, mtime, ctime\n        }\n        return MP_OBJ_FROM_PTR(t);\n    }\n    return mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_out);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_stat_obj, mp_vfs_stat);\n\nmp_obj_t mp_vfs_statvfs(mp_obj_t path_in) {\n    mp_obj_t path_out;\n    mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);\n    if (vfs == MP_VFS_ROOT) {\n        // statvfs called on the root directory, see if there's anything mounted there\n        for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {\n            if (vfs->len == 1) {\n                break;\n            }\n        }\n\n        // If there's nothing mounted at root then return a mostly-empty tuple\n        if (vfs == NULL) {\n            mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));\n\n            // fill in: bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flags\n            for (int i = 0; i <= 8; ++i) {\n                t->items[i] = MP_OBJ_NEW_SMALL_INT(0);\n            }\n\n            // Put something sensible in f_namemax\n            t->items[9] = MP_OBJ_NEW_SMALL_INT(MICROPY_ALLOC_PATH_MAX);\n\n            return MP_OBJ_FROM_PTR(t);\n        }\n\n        // VFS mounted at root so delegate the call to it\n        path_out = MP_OBJ_NEW_QSTR(MP_QSTR__slash_);\n    }\n    return mp_vfs_proxy_call(vfs, MP_QSTR_statvfs, 1, &path_out);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj, mp_vfs_statvfs);\n\n#endif // MICROPY_VFS\n"
  },
  {
    "path": "extmod/vfs.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_VFS_H\n#define MICROPY_INCLUDED_EXTMOD_VFS_H\n\n#include \"py/lexer.h\"\n#include \"py/obj.h\"\n\n// return values of mp_vfs_lookup_path\n// ROOT is 0 so that the default current directory is the root directory\n#define MP_VFS_NONE ((mp_vfs_mount_t*)1)\n#define MP_VFS_ROOT ((mp_vfs_mount_t*)0)\n\n// MicroPython's port-standardized versions of stat constants\n#define MP_S_IFDIR (0x4000)\n#define MP_S_IFREG (0x8000)\n\n// these are the values for mp_vfs_blockdev_t.flags\n#define MP_BLOCKDEV_FLAG_NATIVE         (0x0001) // readblocks[2]/writeblocks[2] contain native func\n#define MP_BLOCKDEV_FLAG_FREE_OBJ       (0x0002) // fs_user_mount_t obj should be freed on umount\n#define MP_BLOCKDEV_FLAG_HAVE_IOCTL     (0x0004) // new protocol with ioctl\n#define MP_BLOCKDEV_FLAG_NO_FILESYSTEM  (0x0008) // the block device has no filesystem on it\n\n// constants for block protocol ioctl\n#define MP_BLOCKDEV_IOCTL_INIT          (1)\n#define MP_BLOCKDEV_IOCTL_DEINIT        (2)\n#define MP_BLOCKDEV_IOCTL_SYNC          (3)\n#define MP_BLOCKDEV_IOCTL_BLOCK_COUNT   (4)\n#define MP_BLOCKDEV_IOCTL_BLOCK_SIZE    (5)\n#define MP_BLOCKDEV_IOCTL_BLOCK_ERASE   (6)\n\n// At the moment the VFS protocol just has import_stat, but could be extended to other methods\ntypedef struct _mp_vfs_proto_t {\n    mp_import_stat_t (*import_stat)(void *self, const char *path);\n} mp_vfs_proto_t;\n\ntypedef struct _mp_vfs_blockdev_t {\n    uint16_t flags;\n    size_t block_size;\n    mp_obj_t readblocks[5];\n    mp_obj_t writeblocks[5];\n    // new protocol uses just ioctl, old uses sync (optional) and count\n    union {\n        mp_obj_t ioctl[4];\n        struct {\n            mp_obj_t sync[2];\n            mp_obj_t count[2];\n        } old;\n    } u;\n} mp_vfs_blockdev_t;\n\ntypedef struct _mp_vfs_mount_t {\n    const char *str; // mount point with leading /\n    size_t len;\n    mp_obj_t obj;\n    struct _mp_vfs_mount_t *next;\n} mp_vfs_mount_t;\n\nvoid mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev);\nint mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf);\nint mp_vfs_blockdev_read_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, uint8_t *buf);\nint mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, const uint8_t *buf);\nint mp_vfs_blockdev_write_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, const uint8_t *buf);\nmp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg);\n\nmp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out);\nmp_import_stat_t mp_vfs_import_stat(const char *path);\nmp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);\nmp_obj_t mp_vfs_umount(mp_obj_t mnt_in);\nmp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);\nmp_obj_t mp_vfs_chdir(mp_obj_t path_in);\nmp_obj_t mp_vfs_getcwd(void);\nmp_obj_t mp_vfs_ilistdir(size_t n_args, const mp_obj_t *args);\nmp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args);\nmp_obj_t mp_vfs_mkdir(mp_obj_t path_in);\nmp_obj_t mp_vfs_remove(mp_obj_t path_in);\nmp_obj_t mp_vfs_rename(mp_obj_t old_path_in, mp_obj_t new_path_in);\nmp_obj_t mp_vfs_rmdir(mp_obj_t path_in);\nmp_obj_t mp_vfs_stat(mp_obj_t path_in);\nmp_obj_t mp_vfs_statvfs(mp_obj_t path_in);\n\nMP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_umount_obj);\nMP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_open_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(mp_vfs_getcwd_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_ilistdir_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_listdir_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_mkdir_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_remove_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_vfs_rename_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_rmdir_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_stat_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj);\n\n#endif // MICROPY_INCLUDED_EXTMOD_VFS_H\n"
  },
  {
    "path": "extmod/vfs_fat.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_VFS_FAT\n\n#if !MICROPY_VFS\n#error \"with MICROPY_VFS_FAT enabled, must also enable MICROPY_VFS\"\n#endif\n\n#include <string.h>\n#include \"py/runtime.h\"\n#include \"py/mperrno.h\"\n#include \"lib/oofatfs/ff.h\"\n#include \"extmod/vfs_fat.h\"\n#include \"lib/timeutils/timeutils.h\"\n\n#if FF_MAX_SS == FF_MIN_SS\n#define SECSIZE(fs) (FF_MIN_SS)\n#else\n#define SECSIZE(fs) ((fs)->ssize)\n#endif\n\n#define mp_obj_fat_vfs_t fs_user_mount_t\n\nSTATIC mp_import_stat_t fat_vfs_import_stat(void *vfs_in, const char *path) {\n    fs_user_mount_t *vfs = vfs_in;\n    FILINFO fno;\n    assert(vfs != NULL);\n    FRESULT res = f_stat(&vfs->fatfs, path, &fno);\n    if (res == FR_OK) {\n        if ((fno.fattrib & AM_DIR) != 0) {\n            return MP_IMPORT_STAT_DIR;\n        } else {\n            return MP_IMPORT_STAT_FILE;\n        }\n    }\n    return MP_IMPORT_STAT_NO_EXIST;\n}\n\nSTATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 1, 1, false);\n\n    // create new object\n    fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t);\n    vfs->base.type = type;\n    vfs->fatfs.drv = vfs;\n\n    // Initialise underlying block device\n    vfs->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ;\n    vfs->blockdev.block_size = FF_MIN_SS; // default, will be populated by call to MP_BLOCKDEV_IOCTL_BLOCK_SIZE\n    mp_vfs_blockdev_init(&vfs->blockdev, args[0]);\n\n    // mount the block device so the VFS methods can be used\n    FRESULT res = f_mount(&vfs->fatfs);\n    if (res == FR_NO_FILESYSTEM) {\n        // don't error out if no filesystem, to let mkfs()/mount() create one if wanted\n        vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_NO_FILESYSTEM;\n    } else if (res != FR_OK) {\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n\n    return MP_OBJ_FROM_PTR(vfs);\n}\n\n#if _FS_REENTRANT\nSTATIC mp_obj_t fat_vfs_del(mp_obj_t self_in) {\n    mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(self_in);\n    // f_umount only needs to be called to release the sync object\n    f_umount(&self->fatfs);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_del_obj, fat_vfs_del);\n#endif\n\nSTATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) {\n    // create new object\n    fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in));\n\n    // make the filesystem\n    uint8_t working_buf[FF_MAX_SS];\n    FRESULT res = f_mkfs(&vfs->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf));\n    if (res == FR_MKFS_ABORTED) { // Probably doesn't support FAT16\n        res = f_mkfs(&vfs->fatfs, FM_FAT32, 0, working_buf, sizeof(working_buf));\n    }\n    if (res != FR_OK) {\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs);\nSTATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mkfs_fun_obj));\n\ntypedef struct _mp_vfs_fat_ilistdir_it_t {\n    mp_obj_base_t base;\n    mp_fun_1_t iternext;\n    bool is_str;\n    FF_DIR dir;\n} mp_vfs_fat_ilistdir_it_t;\n\nSTATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) {\n    mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);\n\n    for (;;) {\n        FILINFO fno;\n        FRESULT res = f_readdir(&self->dir, &fno);\n        char *fn = fno.fname;\n        if (res != FR_OK || fn[0] == 0) {\n            // stop on error or end of dir\n            break;\n        }\n\n        // Note that FatFS already filters . and .., so we don't need to\n\n        // make 4-tuple with info about this entry\n        mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));\n        if (self->is_str) {\n            t->items[0] = mp_obj_new_str(fn, strlen(fn));\n        } else {\n            t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));\n        }\n        if (fno.fattrib & AM_DIR) {\n            // dir\n            t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);\n        } else {\n            // file\n            t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);\n        }\n        t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number\n        t->items[3] = mp_obj_new_int_from_uint(fno.fsize);\n\n        return MP_OBJ_FROM_PTR(t);\n    }\n\n    // ignore error because we may be closing a second time\n    f_closedir(&self->dir);\n\n    return MP_OBJ_STOP_ITERATION;\n}\n\nSTATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) {\n    mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(args[0]);\n    bool is_str_type = true;\n    const char *path;\n    if (n_args == 2) {\n        if (mp_obj_get_type(args[1]) == &mp_type_bytes) {\n            is_str_type = false;\n        }\n        path = mp_obj_str_get_str(args[1]);\n    } else {\n        path = \"\";\n    }\n\n    // Create a new iterator object to list the dir\n    mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t);\n    iter->base.type = &mp_type_polymorph_iter;\n    iter->iternext = mp_vfs_fat_ilistdir_it_iternext;\n    iter->is_str = is_str_type;\n    FRESULT res = f_opendir(&self->fatfs, &iter->dir, path);\n    if (res != FR_OK) {\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n\n    return MP_OBJ_FROM_PTR(iter);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_ilistdir_obj, 1, 2, fat_vfs_ilistdir_func);\n\nSTATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t vfs_in, mp_obj_t path_in, mp_int_t attr) {\n    mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);\n    const char *path = mp_obj_str_get_str(path_in);\n\n    FILINFO fno;\n    FRESULT res = f_stat(&self->fatfs, path, &fno);\n\n    if (res != FR_OK) {\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n\n    // check if path is a file or directory\n    if ((fno.fattrib & AM_DIR) == attr) {\n        res = f_unlink(&self->fatfs, path);\n\n        if (res != FR_OK) {\n            mp_raise_OSError(fresult_to_errno_table[res]);\n        }\n        return mp_const_none;\n    } else {\n        mp_raise_OSError(attr ? MP_ENOTDIR : MP_EISDIR);\n    }\n}\n\nSTATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) {\n    return fat_vfs_remove_internal(vfs_in, path_in, 0); // 0 == file attribute\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_remove_obj, fat_vfs_remove);\n\nSTATIC mp_obj_t fat_vfs_rmdir(mp_obj_t vfs_in, mp_obj_t path_in) {\n    return fat_vfs_remove_internal(vfs_in, path_in, AM_DIR);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_rmdir_obj, fat_vfs_rmdir);\n\nSTATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_out) {\n    mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);\n    const char *old_path = mp_obj_str_get_str(path_in);\n    const char *new_path = mp_obj_str_get_str(path_out);\n    FRESULT res = f_rename(&self->fatfs, old_path, new_path);\n    if (res == FR_EXIST) {\n        // if new_path exists then try removing it (but only if it's a file)\n        fat_vfs_remove_internal(vfs_in, path_out, 0); // 0 == file attribute\n        // try to rename again\n        res = f_rename(&self->fatfs, old_path, new_path);\n    }\n    if (res == FR_OK) {\n        return mp_const_none;\n    } else {\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_rename_obj, fat_vfs_rename);\n\nSTATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) {\n    mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);\n    const char *path = mp_obj_str_get_str(path_o);\n    FRESULT res = f_mkdir(&self->fatfs, path);\n    if (res == FR_OK) {\n        return mp_const_none;\n    } else {\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir);\n\n/// Change current directory.\nSTATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {\n    mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);\n    const char *path;\n    path = mp_obj_str_get_str(path_in);\n\n    FRESULT res = f_chdir(&self->fatfs, path);\n\n    if (res != FR_OK) {\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir);\n\n/// Get the current directory.\nSTATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {\n    mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);\n    char buf[MICROPY_ALLOC_PATH_MAX + 1];\n    FRESULT res = f_getcwd(&self->fatfs, buf, sizeof(buf));\n    if (res != FR_OK) {\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n    return mp_obj_new_str(buf, strlen(buf));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd);\n\n/// \\function stat(path)\n/// Get the status of a file or directory.\nSTATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {\n    mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);\n    const char *path = mp_obj_str_get_str(path_in);\n\n    FILINFO fno;\n    if (path[0] == 0 || (path[0] == '/' && path[1] == 0)) {\n        // stat root directory\n        fno.fsize = 0;\n        fno.fdate = 0x2821; // Jan 1, 2000\n        fno.ftime = 0;\n        fno.fattrib = AM_DIR;\n    } else {\n        FRESULT res = f_stat(&self->fatfs, path, &fno);\n        if (res != FR_OK) {\n            mp_raise_OSError(fresult_to_errno_table[res]);\n        }\n    }\n\n    mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));\n    mp_int_t mode = 0;\n    if (fno.fattrib & AM_DIR) {\n        mode |= MP_S_IFDIR;\n    } else {\n        mode |= MP_S_IFREG;\n    }\n    mp_int_t seconds = timeutils_seconds_since_2000(\n        1980 + ((fno.fdate >> 9) & 0x7f),\n        (fno.fdate >> 5) & 0x0f,\n        fno.fdate & 0x1f,\n        (fno.ftime >> 11) & 0x1f,\n        (fno.ftime >> 5) & 0x3f,\n        2 * (fno.ftime & 0x1f)\n    );\n    t->items[0] = MP_OBJ_NEW_SMALL_INT(mode); // st_mode\n    t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino\n    t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev\n    t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink\n    t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid\n    t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid\n    t->items[6] = mp_obj_new_int_from_uint(fno.fsize); // st_size\n    t->items[7] = MP_OBJ_NEW_SMALL_INT(seconds); // st_atime\n    t->items[8] = MP_OBJ_NEW_SMALL_INT(seconds); // st_mtime\n    t->items[9] = MP_OBJ_NEW_SMALL_INT(seconds); // st_ctime\n\n    return MP_OBJ_FROM_PTR(t);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_stat_obj, fat_vfs_stat);\n\n// Get the status of a VFS.\nSTATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) {\n    mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);\n    (void)path_in;\n\n    DWORD nclst;\n    FATFS *fatfs = &self->fatfs;\n    FRESULT res = f_getfree(fatfs, &nclst);\n    if (FR_OK != res) {\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n\n    mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));\n\n    t->items[0] = MP_OBJ_NEW_SMALL_INT(fatfs->csize * SECSIZE(fatfs)); // f_bsize\n    t->items[1] = t->items[0]; // f_frsize\n    t->items[2] = MP_OBJ_NEW_SMALL_INT((fatfs->n_fatent - 2)); // f_blocks\n    t->items[3] = MP_OBJ_NEW_SMALL_INT(nclst); // f_bfree\n    t->items[4] = t->items[3]; // f_bavail\n    t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files\n    t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree\n    t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail\n    t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags\n    t->items[9] = MP_OBJ_NEW_SMALL_INT(FF_MAX_LFN); // f_namemax\n\n    return MP_OBJ_FROM_PTR(t);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_statvfs_obj, fat_vfs_statvfs);\n\nSTATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {\n    fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in);\n\n    // Read-only device indicated by writeblocks[0] == MP_OBJ_NULL.\n    // User can specify read-only device by:\n    //  1. readonly=True keyword argument\n    //  2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already)\n    if (mp_obj_is_true(readonly)) {\n        self->blockdev.writeblocks[0] = MP_OBJ_NULL;\n    }\n\n    // check if we need to make the filesystem\n    FRESULT res = (self->blockdev.flags & MP_BLOCKDEV_FLAG_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK;\n    if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) {\n        uint8_t working_buf[FF_MAX_SS];\n        res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf));\n    }\n    if (res != FR_OK) {\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n    self->blockdev.flags &= ~MP_BLOCKDEV_FLAG_NO_FILESYSTEM;\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_fat_mount_obj, vfs_fat_mount);\n\nSTATIC mp_obj_t vfs_fat_umount(mp_obj_t self_in) {\n    (void)self_in;\n    // keep the FAT filesystem mounted internally so the VFS methods can still be used\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount);\n\nSTATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = {\n    #if _FS_REENTRANT\n    { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&fat_vfs_del_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) },\n    { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&fat_vfs_ilistdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&fat_vfs_mkdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&fat_vfs_rmdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&fat_vfs_chdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&fat_vfs_getcwd_obj) },\n    { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&fat_vfs_remove_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&fat_vfs_rename_obj) },\n    { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&fat_vfs_stat_obj) },\n    { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&fat_vfs_statvfs_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_fat_mount_obj) },\n    { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&fat_vfs_umount_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table);\n\nSTATIC const mp_vfs_proto_t fat_vfs_proto = {\n    .import_stat = fat_vfs_import_stat,\n};\n\nconst mp_obj_type_t mp_fat_vfs_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_VfsFat,\n    .make_new = fat_vfs_make_new,\n    .protocol = &fat_vfs_proto,\n    .locals_dict = (mp_obj_dict_t*)&fat_vfs_locals_dict,\n\n};\n\n#endif // MICROPY_VFS_FAT\n"
  },
  {
    "path": "extmod/vfs_fat.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_VFS_FAT_H\n#define MICROPY_INCLUDED_EXTMOD_VFS_FAT_H\n\n#include \"py/obj.h\"\n#include \"lib/oofatfs/ff.h\"\n#include \"extmod/vfs.h\"\n\ntypedef struct _fs_user_mount_t {\n    mp_obj_base_t base;\n    mp_vfs_blockdev_t blockdev;\n    FATFS fatfs;\n} fs_user_mount_t;\n\nextern const byte fresult_to_errno_table[20];\nextern const mp_obj_type_t mp_fat_vfs_type;\nextern const mp_obj_type_t mp_type_vfs_fat_fileio;\nextern const mp_obj_type_t mp_type_vfs_fat_textio;\n\nMP_DECLARE_CONST_FUN_OBJ_3(fat_vfs_open_obj);\n\n#endif // MICROPY_INCLUDED_EXTMOD_VFS_FAT_H\n"
  },
  {
    "path": "extmod/vfs_fat_diskio.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * Original template for this file comes from:\n * Low level disk I/O module skeleton for FatFs, (C)ChaN, 2013\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_VFS && MICROPY_VFS_FAT\n\n#include <stdint.h>\n#include <stdio.h>\n\n#include \"py/mphal.h\"\n\n#include \"py/runtime.h\"\n#include \"py/binary.h\"\n#include \"py/objarray.h\"\n#include \"py/mperrno.h\"\n#include \"lib/oofatfs/ff.h\"\n#include \"lib/oofatfs/diskio.h\"\n#include \"extmod/vfs_fat.h\"\n\ntypedef void *bdev_t;\nSTATIC fs_user_mount_t *disk_get_device(void *bdev) {\n    return (fs_user_mount_t*)bdev;\n}\n\n/*-----------------------------------------------------------------------*/\n/* Read Sector(s)                                                        */\n/*-----------------------------------------------------------------------*/\n\nDRESULT disk_read (\n    bdev_t pdrv,      /* Physical drive nmuber (0..) */\n    BYTE *buff,        /* Data buffer to store read data */\n    DWORD sector,    /* Sector address (LBA) */\n    UINT count        /* Number of sectors to read (1..128) */\n)\n{\n    fs_user_mount_t *vfs = disk_get_device(pdrv);\n    if (vfs == NULL) {\n        return RES_PARERR;\n    }\n\n    int ret = mp_vfs_blockdev_read(&vfs->blockdev, sector, count, buff);\n\n    return ret == 0 ? RES_OK : RES_ERROR;\n}\n\n/*-----------------------------------------------------------------------*/\n/* Write Sector(s)                                                       */\n/*-----------------------------------------------------------------------*/\n\nDRESULT disk_write (\n    bdev_t pdrv,          /* Physical drive nmuber (0..) */\n    const BYTE *buff,    /* Data to be written */\n    DWORD sector,        /* Sector address (LBA) */\n    UINT count            /* Number of sectors to write (1..128) */\n)\n{\n    fs_user_mount_t *vfs = disk_get_device(pdrv);\n    if (vfs == NULL) {\n        return RES_PARERR;\n    }\n\n    int ret = mp_vfs_blockdev_write(&vfs->blockdev, sector, count, buff);\n\n    if (ret == -MP_EROFS) {\n        // read-only block device\n        return RES_WRPRT;\n    }\n\n    return ret == 0 ? RES_OK : RES_ERROR;\n}\n\n\n/*-----------------------------------------------------------------------*/\n/* Miscellaneous Functions                                               */\n/*-----------------------------------------------------------------------*/\n\nDRESULT disk_ioctl (\n    bdev_t pdrv,      /* Physical drive nmuber (0..) */\n    BYTE cmd,        /* Control code */\n    void *buff        /* Buffer to send/receive control data */\n)\n{\n    fs_user_mount_t *vfs = disk_get_device(pdrv);\n    if (vfs == NULL) {\n        return RES_PARERR;\n    }\n\n    // First part: call the relevant method of the underlying block device\n    static const uint8_t op_map[8] = {\n        [CTRL_SYNC] = MP_BLOCKDEV_IOCTL_SYNC,\n        [GET_SECTOR_COUNT] = MP_BLOCKDEV_IOCTL_BLOCK_COUNT,\n        [GET_SECTOR_SIZE] = MP_BLOCKDEV_IOCTL_BLOCK_SIZE,\n        [IOCTL_INIT] = MP_BLOCKDEV_IOCTL_INIT,\n    };\n    uint8_t bp_op = op_map[cmd & 7];\n    mp_obj_t ret = mp_const_none;\n    if (bp_op != 0) {\n        ret = mp_vfs_blockdev_ioctl(&vfs->blockdev, bp_op, 0);\n    }\n\n    // Second part: convert the result for return\n    switch (cmd) {\n        case CTRL_SYNC:\n            return RES_OK;\n\n        case GET_SECTOR_COUNT: {\n            *((DWORD*)buff) = mp_obj_get_int(ret);\n            return RES_OK;\n        }\n\n        case GET_SECTOR_SIZE: {\n            if (ret == mp_const_none) {\n                // Default sector size\n                *((WORD*)buff) = 512;\n            } else {\n                *((WORD*)buff) = mp_obj_get_int(ret);\n            }\n            // need to store ssize because we use it in disk_read/disk_write\n            vfs->blockdev.block_size = *((WORD*)buff);\n            return RES_OK;\n        }\n\n        case GET_BLOCK_SIZE:\n            *((DWORD*)buff) = 1; // erase block size in units of sector size\n            return RES_OK;\n\n        case IOCTL_INIT:\n        case IOCTL_STATUS: {\n            DSTATUS stat;\n            if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) {\n                // error initialising\n                stat = STA_NOINIT;\n            } else if (vfs->blockdev.writeblocks[0] == MP_OBJ_NULL) {\n                stat = STA_PROTECT;\n            } else {\n                stat = 0;\n            }\n            *((DSTATUS*)buff) = stat;\n            return RES_OK;\n        }\n\n        default:\n            return RES_PARERR;\n    }\n}\n\n#endif // MICROPY_VFS && MICROPY_VFS_FAT\n"
  },
  {
    "path": "extmod/vfs_fat_file.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_VFS && MICROPY_VFS_FAT\n\n#include <stdio.h>\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n#include \"py/mperrno.h\"\n#include \"lib/oofatfs/ff.h\"\n#include \"extmod/vfs_fat.h\"\n\n// this table converts from FRESULT to POSIX errno\nconst byte fresult_to_errno_table[20] = {\n    [FR_OK] = 0,\n    [FR_DISK_ERR] = MP_EIO,\n    [FR_INT_ERR] = MP_EIO,\n    [FR_NOT_READY] = MP_EBUSY,\n    [FR_NO_FILE] = MP_ENOENT,\n    [FR_NO_PATH] = MP_ENOENT,\n    [FR_INVALID_NAME] = MP_EINVAL,\n    [FR_DENIED] = MP_EACCES,\n    [FR_EXIST] = MP_EEXIST,\n    [FR_INVALID_OBJECT] = MP_EINVAL,\n    [FR_WRITE_PROTECTED] = MP_EROFS,\n    [FR_INVALID_DRIVE] = MP_ENODEV,\n    [FR_NOT_ENABLED] = MP_ENODEV,\n    [FR_NO_FILESYSTEM] = MP_ENODEV,\n    [FR_MKFS_ABORTED] = MP_EIO,\n    [FR_TIMEOUT] = MP_EIO,\n    [FR_LOCKED] = MP_EIO,\n    [FR_NOT_ENOUGH_CORE] = MP_ENOMEM,\n    [FR_TOO_MANY_OPEN_FILES] = MP_EMFILE,\n    [FR_INVALID_PARAMETER] = MP_EINVAL,\n};\n\ntypedef struct _pyb_file_obj_t {\n    mp_obj_base_t base;\n    FIL fp;\n} pyb_file_obj_t;\n\nSTATIC void file_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_printf(print, \"<io.%s %p>\", mp_obj_get_type_str(self_in), MP_OBJ_TO_PTR(self_in));\n}\n\nSTATIC mp_uint_t file_obj_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {\n    pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    UINT sz_out;\n    FRESULT res = f_read(&self->fp, buf, size, &sz_out);\n    if (res != FR_OK) {\n        *errcode = fresult_to_errno_table[res];\n        return MP_STREAM_ERROR;\n    }\n    return sz_out;\n}\n\nSTATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {\n    pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    UINT sz_out;\n    FRESULT res = f_write(&self->fp, buf, size, &sz_out);\n    if (res != FR_OK) {\n        *errcode = fresult_to_errno_table[res];\n        return MP_STREAM_ERROR;\n    }\n    if (sz_out != size) {\n        // The FatFS documentation says that this means disk full.\n        *errcode = MP_ENOSPC;\n        return MP_STREAM_ERROR;\n    }\n    return sz_out;\n}\n\n\nSTATIC mp_obj_t file_obj___exit__(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n    return mp_stream_close(args[0]);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(file_obj___exit___obj, 4, 4, file_obj___exit__);\n\nSTATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    pyb_file_obj_t *self = MP_OBJ_TO_PTR(o_in);\n\n    if (request == MP_STREAM_SEEK) {\n        struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)(uintptr_t)arg;\n\n        switch (s->whence) {\n            case 0: // SEEK_SET\n                f_lseek(&self->fp, s->offset);\n                break;\n\n            case 1: // SEEK_CUR\n                f_lseek(&self->fp, f_tell(&self->fp) + s->offset);\n                break;\n\n            case 2: // SEEK_END\n                f_lseek(&self->fp, f_size(&self->fp) + s->offset);\n                break;\n        }\n\n        s->offset = f_tell(&self->fp);\n        return 0;\n\n    } else if (request == MP_STREAM_FLUSH) {\n        FRESULT res = f_sync(&self->fp);\n        if (res != FR_OK) {\n            *errcode = fresult_to_errno_table[res];\n            return MP_STREAM_ERROR;\n        }\n        return 0;\n\n    } else if (request == MP_STREAM_CLOSE) {\n        // if fs==NULL then the file is closed and in that case this method is a no-op\n        if (self->fp.obj.fs != NULL) {\n            FRESULT res = f_close(&self->fp);\n            if (res != FR_OK) {\n                *errcode = fresult_to_errno_table[res];\n                return MP_STREAM_ERROR;\n            }\n        }\n        return 0;\n\n    } else {\n        *errcode = MP_EINVAL;\n        return MP_STREAM_ERROR;\n    }\n}\n\n// Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO,\n// but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor\nSTATIC const mp_arg_t file_open_args[] = {\n    { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },\n    { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} },\n    { MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },\n};\n#define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args)\n\nSTATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_arg_val_t *args) {\n    int mode = 0;\n    const char *mode_s = mp_obj_str_get_str(args[1].u_obj);\n    // TODO make sure only one of r, w, x, a, and b, t are specified\n    while (*mode_s) {\n        switch (*mode_s++) {\n            case 'r':\n                mode |= FA_READ;\n                break;\n            case 'w':\n                mode |= FA_WRITE | FA_CREATE_ALWAYS;\n                break;\n            case 'x':\n                mode |= FA_WRITE | FA_CREATE_NEW;\n                break;\n            case 'a':\n                mode |= FA_WRITE | FA_OPEN_ALWAYS;\n                break;\n            case '+':\n                mode |= FA_READ | FA_WRITE;\n                break;\n            #if MICROPY_PY_IO_FILEIO\n            case 'b':\n                type = &mp_type_vfs_fat_fileio;\n                break;\n            #endif\n            case 't':\n                type = &mp_type_vfs_fat_textio;\n                break;\n        }\n    }\n\n    pyb_file_obj_t *o = m_new_obj_with_finaliser(pyb_file_obj_t);\n    o->base.type = type;\n\n    const char *fname = mp_obj_str_get_str(args[0].u_obj);\n    assert(vfs != NULL);\n    FRESULT res = f_open(&vfs->fatfs, &o->fp, fname, mode);\n    if (res != FR_OK) {\n        m_del_obj(pyb_file_obj_t, o);\n        mp_raise_OSError(fresult_to_errno_table[res]);\n    }\n\n    // for 'a' mode, we must begin at the end of the file\n    if ((mode & FA_OPEN_ALWAYS) != 0) {\n        f_lseek(&o->fp, f_size(&o->fp));\n    }\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t file_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];\n    mp_arg_parse_all_kw_array(n_args, n_kw, args, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals);\n    return file_open(NULL, type, arg_vals);\n}\n\n// TODO gc hook to close the file if not already closed\n\nSTATIC const mp_rom_map_elem_t vfs_fat_rawfile_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },\n    { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },\n    { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },\n    { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },\n    { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },\n    { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(vfs_fat_rawfile_locals_dict, vfs_fat_rawfile_locals_dict_table);\n\n#if MICROPY_PY_IO_FILEIO\nSTATIC const mp_stream_p_t vfs_fat_fileio_stream_p = {\n    .read = file_obj_read,\n    .write = file_obj_write,\n    .ioctl = file_obj_ioctl,\n};\n\nconst mp_obj_type_t mp_type_vfs_fat_fileio = {\n    { &mp_type_type },\n    .name = MP_QSTR_FileIO,\n    .print = file_obj_print,\n    .make_new = file_obj_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &vfs_fat_fileio_stream_p,\n    .locals_dict = (mp_obj_dict_t*)&vfs_fat_rawfile_locals_dict,\n};\n#endif\n\nSTATIC const mp_stream_p_t vfs_fat_textio_stream_p = {\n    .read = file_obj_read,\n    .write = file_obj_write,\n    .ioctl = file_obj_ioctl,\n    .is_text = true,\n};\n\nconst mp_obj_type_t mp_type_vfs_fat_textio = {\n    { &mp_type_type },\n    .name = MP_QSTR_TextIOWrapper,\n    .print = file_obj_print,\n    .make_new = file_obj_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &vfs_fat_textio_stream_p,\n    .locals_dict = (mp_obj_dict_t*)&vfs_fat_rawfile_locals_dict,\n};\n\n// Factory function for I/O stream classes\nSTATIC mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) {\n    // TODO: analyze buffering args and instantiate appropriate type\n    fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];\n    arg_vals[0].u_obj = path;\n    arg_vals[1].u_obj = mode;\n    arg_vals[2].u_obj = mp_const_none;\n    return file_open(self, &mp_type_vfs_fat_textio, arg_vals);\n}\nMP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self);\n\n#endif // MICROPY_VFS && MICROPY_VFS_FAT\n"
  },
  {
    "path": "extmod/vfs_posix.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017-2018 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/runtime.h\"\n#include \"py/mperrno.h\"\n#include \"extmod/vfs.h\"\n#include \"extmod/vfs_posix.h\"\n\n#if MICROPY_VFS_POSIX\n\n#include <stdio.h>\n#include <string.h>\n#include <sys/stat.h>\n#include <dirent.h>\n\ntypedef struct _mp_obj_vfs_posix_t {\n    mp_obj_base_t base;\n    vstr_t root;\n    size_t root_len;\n    bool readonly;\n} mp_obj_vfs_posix_t;\n\nSTATIC const char *vfs_posix_get_path_str(mp_obj_vfs_posix_t *self, mp_obj_t path) {\n    if (self->root_len == 0) {\n        return mp_obj_str_get_str(path);\n    } else {\n        self->root.len = self->root_len;\n        vstr_add_str(&self->root, mp_obj_str_get_str(path));\n        return vstr_null_terminated_str(&self->root);\n    }\n}\n\nSTATIC mp_obj_t vfs_posix_get_path_obj(mp_obj_vfs_posix_t *self, mp_obj_t path) {\n    if (self->root_len == 0) {\n        return path;\n    } else {\n        self->root.len = self->root_len;\n        vstr_add_str(&self->root, mp_obj_str_get_str(path));\n        return mp_obj_new_str(self->root.buf, self->root.len);\n    }\n}\n\nSTATIC mp_obj_t vfs_posix_fun1_helper(mp_obj_t self_in, mp_obj_t path_in, int (*f)(const char*)) {\n    mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);\n    int ret = f(vfs_posix_get_path_str(self, path_in));\n    if (ret != 0) {\n        mp_raise_OSError(errno);\n    }\n    return mp_const_none;\n}\n\nSTATIC mp_import_stat_t mp_vfs_posix_import_stat(void *self_in, const char *path) {\n    mp_obj_vfs_posix_t *self = self_in;\n    if (self->root_len != 0) {\n        self->root.len = self->root_len;\n        vstr_add_str(&self->root, path);\n        path = vstr_null_terminated_str(&self->root);\n    }\n    struct stat st;\n    if (stat(path, &st) == 0) {\n        if (S_ISDIR(st.st_mode)) {\n            return MP_IMPORT_STAT_DIR;\n        } else if (S_ISREG(st.st_mode)) {\n            return MP_IMPORT_STAT_FILE;\n        }\n    }\n    return MP_IMPORT_STAT_NO_EXIST;\n}\n\nSTATIC mp_obj_t vfs_posix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n\n    mp_obj_vfs_posix_t *vfs = m_new_obj(mp_obj_vfs_posix_t);\n    vfs->base.type = type;\n    vstr_init(&vfs->root, 0);\n    if (n_args == 1) {\n        vstr_add_str(&vfs->root, mp_obj_str_get_str(args[0]));\n        vstr_add_char(&vfs->root, '/');\n    }\n    vfs->root_len = vfs->root.len;\n    vfs->readonly = false;\n\n    return MP_OBJ_FROM_PTR(vfs);\n}\n\nSTATIC mp_obj_t vfs_posix_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {\n    mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);\n    if (mp_obj_is_true(readonly)) {\n        self->readonly = true;\n    }\n    if (mp_obj_is_true(mkfs)) {\n        mp_raise_OSError(MP_EPERM);\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_mount_obj, vfs_posix_mount);\n\nSTATIC mp_obj_t vfs_posix_umount(mp_obj_t self_in) {\n    (void)self_in;\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_umount_obj, vfs_posix_umount);\n\nSTATIC mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) {\n    mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);\n    const char *mode = mp_obj_str_get_str(mode_in);\n    if (self->readonly\n        && (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) {\n        mp_raise_OSError(MP_EROFS);\n    }\n    if (!mp_obj_is_small_int(path_in)) {\n        path_in = vfs_posix_get_path_obj(self, path_in);\n    }\n    return mp_vfs_posix_file_open(&mp_type_textio, path_in, mode_in);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_open_obj, vfs_posix_open);\n\nSTATIC mp_obj_t vfs_posix_chdir(mp_obj_t self_in, mp_obj_t path_in) {\n    return vfs_posix_fun1_helper(self_in, path_in, chdir);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_chdir_obj, vfs_posix_chdir);\n\nSTATIC mp_obj_t vfs_posix_getcwd(mp_obj_t self_in) {\n    mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);\n    char buf[MICROPY_ALLOC_PATH_MAX + 1];\n    const char *ret = getcwd(buf, sizeof(buf));\n    if (ret == NULL) {\n        mp_raise_OSError(errno);\n    }\n    ret += self->root_len;\n    return mp_obj_new_str(ret, strlen(ret));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_getcwd_obj, vfs_posix_getcwd);\n\ntypedef struct _vfs_posix_ilistdir_it_t {\n    mp_obj_base_t base;\n    mp_fun_1_t iternext;\n    bool is_str;\n    DIR *dir;\n} vfs_posix_ilistdir_it_t;\n\nSTATIC mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) {\n    vfs_posix_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (self->dir == NULL) {\n        return MP_OBJ_STOP_ITERATION;\n    }\n\n    for (;;) {\n        struct dirent *dirent = readdir(self->dir);\n        if (dirent == NULL) {\n            closedir(self->dir);\n            self->dir = NULL;\n            return MP_OBJ_STOP_ITERATION;\n        }\n        const char *fn = dirent->d_name;\n\n        if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) {\n            // skip . and ..\n            continue;\n        }\n\n        // make 3-tuple with info about this entry\n        mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));\n\n        if (self->is_str) {\n            t->items[0] = mp_obj_new_str(fn, strlen(fn));\n        } else {\n            t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));\n        }\n\n        #ifdef _DIRENT_HAVE_D_TYPE\n        #ifdef DTTOIF\n        t->items[1] = MP_OBJ_NEW_SMALL_INT(DTTOIF(dirent->d_type));\n        #else\n        if (dirent->d_type == DT_DIR) {\n            t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);\n        } else if (dirent->d_type == DT_REG) {\n            t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);\n        } else {\n            t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type);\n        }\n        #endif\n        #else\n        // DT_UNKNOWN should have 0 value on any reasonable system\n        t->items[1] = MP_OBJ_NEW_SMALL_INT(0);\n        #endif\n\n        #ifdef _DIRENT_HAVE_D_INO\n        t->items[2] = MP_OBJ_NEW_SMALL_INT(dirent->d_ino);\n        #else\n        t->items[2] = MP_OBJ_NEW_SMALL_INT(0);\n        #endif\n\n        return MP_OBJ_FROM_PTR(t);\n    }\n}\n\nSTATIC mp_obj_t vfs_posix_ilistdir(mp_obj_t self_in, mp_obj_t path_in) {\n    mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);\n    vfs_posix_ilistdir_it_t *iter = m_new_obj(vfs_posix_ilistdir_it_t);\n    iter->base.type = &mp_type_polymorph_iter;\n    iter->iternext = vfs_posix_ilistdir_it_iternext;\n    iter->is_str = mp_obj_get_type(path_in) == &mp_type_str;\n    const char *path = vfs_posix_get_path_str(self, path_in);\n    if (path[0] == '\\0') {\n        path = \".\";\n    }\n    iter->dir = opendir(path);\n    if (iter->dir == NULL) {\n        mp_raise_OSError(errno);\n    }\n    return MP_OBJ_FROM_PTR(iter);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_ilistdir_obj, vfs_posix_ilistdir);\n\ntypedef struct _mp_obj_listdir_t {\n    mp_obj_base_t base;\n    mp_fun_1_t iternext;\n    DIR *dir;\n} mp_obj_listdir_t;\n\nSTATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) {\n    mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);\n    int ret = mkdir(vfs_posix_get_path_str(self, path_in), 0777);\n    if (ret != 0) {\n        mp_raise_OSError(errno);\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir);\n\nSTATIC mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) {\n    return vfs_posix_fun1_helper(self_in, path_in, unlink);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove);\n\nSTATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) {\n    mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);\n    const char *old_path = vfs_posix_get_path_str(self, old_path_in);\n    const char *new_path = vfs_posix_get_path_str(self, new_path_in);\n    int ret = rename(old_path, new_path);\n    if (ret != 0) {\n        mp_raise_OSError(errno);\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename);\n\nSTATIC mp_obj_t vfs_posix_rmdir(mp_obj_t self_in, mp_obj_t path_in) {\n    return vfs_posix_fun1_helper(self_in, path_in, rmdir);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir);\n\nSTATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) {\n    mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);\n    struct stat sb;\n    int ret = stat(vfs_posix_get_path_str(self, path_in), &sb);\n    if (ret != 0) {\n        mp_raise_OSError(errno);\n    }\n    mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));\n    t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode);\n    t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino);\n    t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.st_dev);\n    t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink);\n    t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.st_uid);\n    t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.st_gid);\n    t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.st_size);\n    t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime);\n    t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime);\n    t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime);\n    return MP_OBJ_FROM_PTR(t);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat);\n\n#ifdef __ANDROID__\n#define USE_STATFS 1\n#endif\n\n#if USE_STATFS\n#include <sys/vfs.h>\n#define STRUCT_STATVFS struct statfs\n#define STATVFS statfs\n#define F_FAVAIL sb.f_ffree\n#define F_NAMEMAX sb.f_namelen\n#define F_FLAG sb.f_flags\n#else\n#include <sys/statvfs.h>\n#define STRUCT_STATVFS struct statvfs\n#define STATVFS statvfs\n#define F_FAVAIL sb.f_favail\n#define F_NAMEMAX sb.f_namemax\n#define F_FLAG sb.f_flag\n#endif\n\nSTATIC mp_obj_t vfs_posix_statvfs(mp_obj_t self_in, mp_obj_t path_in) {\n    mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);\n    STRUCT_STATVFS sb;\n    const char *path = vfs_posix_get_path_str(self, path_in);\n    int ret = STATVFS(path, &sb);\n    if (ret != 0) {\n        mp_raise_OSError(errno);\n    }\n    mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));\n    t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize);\n    t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize);\n    t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.f_blocks);\n    t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.f_bfree);\n    t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.f_bavail);\n    t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.f_files);\n    t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.f_ffree);\n    t->items[7] = MP_OBJ_NEW_SMALL_INT(F_FAVAIL);\n    t->items[8] = MP_OBJ_NEW_SMALL_INT(F_FLAG);\n    t->items[9] = MP_OBJ_NEW_SMALL_INT(F_NAMEMAX);\n    return MP_OBJ_FROM_PTR(t);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_statvfs_obj, vfs_posix_statvfs);\n\nSTATIC const mp_rom_map_elem_t vfs_posix_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_posix_mount_obj) },\n    { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&vfs_posix_umount_obj) },\n    { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&vfs_posix_open_obj) },\n\n    { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&vfs_posix_chdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&vfs_posix_getcwd_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&vfs_posix_ilistdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&vfs_posix_mkdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&vfs_posix_remove_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&vfs_posix_rename_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&vfs_posix_rmdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&vfs_posix_stat_obj) },\n    { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&vfs_posix_statvfs_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(vfs_posix_locals_dict, vfs_posix_locals_dict_table);\n\nSTATIC const mp_vfs_proto_t vfs_posix_proto = {\n    .import_stat = mp_vfs_posix_import_stat,\n};\n\nconst mp_obj_type_t mp_type_vfs_posix = {\n    { &mp_type_type },\n    .name = MP_QSTR_VfsPosix,\n    .make_new = vfs_posix_make_new,\n    .protocol = &vfs_posix_proto,\n    .locals_dict = (mp_obj_dict_t*)&vfs_posix_locals_dict,\n};\n\n#endif // MICROPY_VFS_POSIX\n"
  },
  {
    "path": "extmod/vfs_posix.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H\n#define MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H\n\n#include \"py/lexer.h\"\n#include \"py/obj.h\"\n\nextern const mp_obj_type_t mp_type_vfs_posix;\nextern const mp_obj_type_t mp_type_vfs_posix_fileio;\nextern const mp_obj_type_t mp_type_vfs_posix_textio;\n\nmp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in);\n\n#endif // MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H\n"
  },
  {
    "path": "extmod/vfs_posix_file.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2018 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n#include \"extmod/vfs_posix.h\"\n\n#if MICROPY_VFS_POSIX\n\n#include <fcntl.h>\n\n#ifdef _WIN32\n#define fsync _commit\n#endif\n\ntypedef struct _mp_obj_vfs_posix_file_t {\n    mp_obj_base_t base;\n    int fd;\n} mp_obj_vfs_posix_file_t;\n\n#ifdef MICROPY_CPYTHON_COMPAT\nSTATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {\n    if (o->fd < 0) {\n        mp_raise_msg(&mp_type_ValueError, \"I/O operation on closed file\");\n    }\n}\n#else\n#define check_fd_is_open(o)\n#endif\n\nSTATIC void vfs_posix_file_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<io.%s %d>\", mp_obj_get_type_str(self_in), self->fd);\n}\n\nmp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in) {\n    mp_obj_vfs_posix_file_t *o = m_new_obj(mp_obj_vfs_posix_file_t);\n    const char *mode_s = mp_obj_str_get_str(mode_in);\n\n    int mode_rw = 0, mode_x = 0;\n    while (*mode_s) {\n        switch (*mode_s++) {\n            case 'r':\n                mode_rw = O_RDONLY;\n                break;\n            case 'w':\n                mode_rw = O_WRONLY;\n                mode_x = O_CREAT | O_TRUNC;\n                break;\n            case 'a':\n                mode_rw = O_WRONLY;\n                mode_x = O_CREAT | O_APPEND;\n                break;\n            case '+':\n                mode_rw = O_RDWR;\n                break;\n            #if MICROPY_PY_IO_FILEIO\n            // If we don't have io.FileIO, then files are in text mode implicitly\n            case 'b':\n                type = &mp_type_vfs_posix_fileio;\n                break;\n            case 't':\n                type = &mp_type_vfs_posix_textio;\n                break;\n            #endif\n        }\n    }\n\n    o->base.type = type;\n\n    mp_obj_t fid = file_in;\n\n    if (mp_obj_is_small_int(fid)) {\n        o->fd = MP_OBJ_SMALL_INT_VALUE(fid);\n        return MP_OBJ_FROM_PTR(o);\n    }\n\n    const char *fname = mp_obj_str_get_str(fid);\n    int fd = open(fname, mode_x | mode_rw, 0644);\n    if (fd == -1) {\n        mp_raise_OSError(errno);\n    }\n    o->fd = fd;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },\n    };\n\n    mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals);\n    return mp_vfs_posix_file_open(type, arg_vals[0].u_obj, arg_vals[1].u_obj);\n}\n\nSTATIC mp_obj_t vfs_posix_file_fileno(mp_obj_t self_in) {\n    mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in);\n    check_fd_is_open(self);\n    return MP_OBJ_NEW_SMALL_INT(self->fd);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_file_fileno_obj, vfs_posix_file_fileno);\n\nSTATIC mp_obj_t vfs_posix_file___exit__(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n    return mp_stream_close(args[0]);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vfs_posix_file___exit__);\n\nSTATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);\n    check_fd_is_open(o);\n    mp_int_t r = read(o->fd, buf, size);\n    if (r == -1) {\n        *errcode = errno;\n        return MP_STREAM_ERROR;\n    }\n    return r;\n}\n\nSTATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);\n    check_fd_is_open(o);\n    #if MICROPY_PY_OS_DUPTERM\n    if (o->fd <= STDERR_FILENO) {\n        mp_hal_stdout_tx_strn(buf, size);\n        return size;\n    }\n    #endif\n    mp_int_t r = write(o->fd, buf, size);\n    while (r == -1 && errno == EINTR) {\n        if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {\n            mp_obj_t obj = MP_STATE_VM(mp_pending_exception);\n            MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;\n            nlr_raise(obj);\n        }\n        r = write(o->fd, buf, size);\n    }\n    if (r == -1) {\n        *errcode = errno;\n        return MP_STREAM_ERROR;\n    }\n    return r;\n}\n\nSTATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);\n    check_fd_is_open(o);\n    switch (request) {\n        case MP_STREAM_FLUSH:\n            if (fsync(o->fd) < 0) {\n                *errcode = errno;\n                return MP_STREAM_ERROR;\n            }\n            return 0;\n        case MP_STREAM_SEEK: {\n            struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg;\n            off_t off = lseek(o->fd, s->offset, s->whence);\n            if (off == (off_t)-1) {\n                *errcode = errno;\n                return MP_STREAM_ERROR;\n            }\n            s->offset = off;\n            return 0;\n        }\n        case MP_STREAM_CLOSE:\n            close(o->fd);\n            #ifdef MICROPY_CPYTHON_COMPAT\n            o->fd = -1;\n            #endif\n            return 0;\n        default:\n            *errcode = EINVAL;\n            return MP_STREAM_ERROR;\n    }\n}\n\nSTATIC const mp_rom_map_elem_t vfs_posix_rawfile_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&vfs_posix_file_fileno_obj) },\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },\n    { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },\n    { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },\n    { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },\n    { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(vfs_posix_rawfile_locals_dict, vfs_posix_rawfile_locals_dict_table);\n\n#if MICROPY_PY_IO_FILEIO\nSTATIC const mp_stream_p_t vfs_posix_fileio_stream_p = {\n    .read = vfs_posix_file_read,\n    .write = vfs_posix_file_write,\n    .ioctl = vfs_posix_file_ioctl,\n};\n\nconst mp_obj_type_t mp_type_vfs_posix_fileio = {\n    { &mp_type_type },\n    .name = MP_QSTR_FileIO,\n    .print = vfs_posix_file_print,\n    .make_new = vfs_posix_file_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &vfs_posix_fileio_stream_p,\n    .locals_dict = (mp_obj_dict_t*)&vfs_posix_rawfile_locals_dict,\n};\n#endif\n\nSTATIC const mp_stream_p_t vfs_posix_textio_stream_p = {\n    .read = vfs_posix_file_read,\n    .write = vfs_posix_file_write,\n    .ioctl = vfs_posix_file_ioctl,\n    .is_text = true,\n};\n\nconst mp_obj_type_t mp_type_vfs_posix_textio = {\n    { &mp_type_type },\n    .name = MP_QSTR_TextIOWrapper,\n    .print = vfs_posix_file_print,\n    .make_new = vfs_posix_file_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &vfs_posix_textio_stream_p,\n    .locals_dict = (mp_obj_dict_t*)&vfs_posix_rawfile_locals_dict,\n};\n\nconst mp_obj_vfs_posix_file_t mp_sys_stdin_obj  = {{&mp_type_textio}, STDIN_FILENO};\nconst mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO};\nconst mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO};\n\n#endif // MICROPY_VFS_POSIX\n"
  },
  {
    "path": "extmod/vfs_reader.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n#include \"py/reader.h\"\n#include \"extmod/vfs.h\"\n\n#if MICROPY_READER_VFS\n\ntypedef struct _mp_reader_vfs_t {\n    mp_obj_t file;\n    uint16_t len;\n    uint16_t pos;\n    byte buf[24];\n} mp_reader_vfs_t;\n\nSTATIC mp_uint_t mp_reader_vfs_readbyte(void *data) {\n    mp_reader_vfs_t *reader = (mp_reader_vfs_t*)data;\n    if (reader->pos >= reader->len) {\n        if (reader->len < sizeof(reader->buf)) {\n            return MP_READER_EOF;\n        } else {\n            int errcode;\n            reader->len = mp_stream_rw(reader->file, reader->buf, sizeof(reader->buf),\n                &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);\n            if (errcode != 0) {\n                // TODO handle errors properly\n                return MP_READER_EOF;\n            }\n            if (reader->len == 0) {\n                return MP_READER_EOF;\n            }\n            reader->pos = 0;\n        }\n    }\n    return reader->buf[reader->pos++];\n}\n\nSTATIC void mp_reader_vfs_close(void *data) {\n    mp_reader_vfs_t *reader = (mp_reader_vfs_t*)data;\n    mp_stream_close(reader->file);\n    m_del_obj(mp_reader_vfs_t, reader);\n}\n\nvoid mp_reader_new_file(mp_reader_t *reader, const char *filename) {\n    mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t);\n    mp_obj_t arg = mp_obj_new_str(filename, strlen(filename));\n    rf->file = mp_vfs_open(1, &arg, (mp_map_t*)&mp_const_empty_map);\n    int errcode;\n    rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);\n    if (errcode != 0) {\n        mp_raise_OSError(errcode);\n    }\n    rf->pos = 0;\n    reader->data = rf;\n    reader->readbyte = mp_reader_vfs_readbyte;\n    reader->close = mp_reader_vfs_close;\n}\n\n#endif // MICROPY_READER_VFS\n"
  },
  {
    "path": "extmod/virtpin.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"extmod/virtpin.h\"\n\nint mp_virtual_pin_read(mp_obj_t pin) {\n    mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(pin);\n    mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->protocol;\n    return pin_p->ioctl(pin, MP_PIN_READ, 0, NULL);\n}\n\nvoid mp_virtual_pin_write(mp_obj_t pin, int value) {\n    mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(pin);\n    mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->protocol;\n    pin_p->ioctl(pin, MP_PIN_WRITE, value, NULL);\n}\n"
  },
  {
    "path": "extmod/virtpin.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_EXTMOD_VIRTPIN_H\n#define MICROPY_INCLUDED_EXTMOD_VIRTPIN_H\n\n#include \"py/obj.h\"\n\n#define MP_PIN_READ   (1)\n#define MP_PIN_WRITE  (2)\n#define MP_PIN_INPUT  (3)\n#define MP_PIN_OUTPUT (4)\n\n// Pin protocol\ntypedef struct _mp_pin_p_t {\n    mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);\n} mp_pin_p_t;\n\nint mp_virtual_pin_read(mp_obj_t pin);\nvoid mp_virtual_pin_write(mp_obj_t pin, int value);\n\n// If a port exposes a Pin object, it's constructor should be like this\nmp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);\n\n#endif // MICROPY_INCLUDED_EXTMOD_VIRTPIN_H\n"
  },
  {
    "path": "extmod/webrepl/manifest.py",
    "content": "freeze('.', ('webrepl.py', 'webrepl_setup.py', 'websocket_helper.py',))\n"
  },
  {
    "path": "extmod/webrepl/webrepl.py",
    "content": "# This module should be imported from REPL, not run from command line.\nimport socket\nimport uos\nimport network\nimport uwebsocket\nimport websocket_helper\nimport _webrepl\n\nlisten_s = None\nclient_s = None\n\ndef setup_conn(port, accept_handler):\n    global listen_s\n    listen_s = socket.socket()\n    listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n\n    ai = socket.getaddrinfo(\"0.0.0.0\", port)\n    addr = ai[0][4]\n\n    listen_s.bind(addr)\n    listen_s.listen(1)\n    if accept_handler:\n        listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler)\n    for i in (network.AP_IF, network.STA_IF):\n        iface = network.WLAN(i)\n        if iface.active():\n            print(\"WebREPL daemon started on ws://%s:%d\" % (iface.ifconfig()[0], port))\n    return listen_s\n\n\ndef accept_conn(listen_sock):\n    global client_s\n    cl, remote_addr = listen_sock.accept()\n    prev = uos.dupterm(None)\n    uos.dupterm(prev)\n    if prev:\n        print(\"\\nConcurrent WebREPL connection from\", remote_addr, \"rejected\")\n        cl.close()\n        return\n    print(\"\\nWebREPL connection from:\", remote_addr)\n    client_s = cl\n    websocket_helper.server_handshake(cl)\n    ws = uwebsocket.websocket(cl, True)\n    ws = _webrepl._webrepl(ws)\n    cl.setblocking(False)\n    # notify REPL on socket incoming data (ESP32/ESP8266-only)\n    if hasattr(uos, 'dupterm_notify'):\n        cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify)\n    uos.dupterm(ws)\n\n\ndef stop():\n    global listen_s, client_s\n    uos.dupterm(None)\n    if client_s:\n        client_s.close()\n    if listen_s:\n        listen_s.close()\n\n\ndef start(port=8266, password=None):\n    stop()\n    if password is None:\n        try:\n            import webrepl_cfg\n            _webrepl.password(webrepl_cfg.PASS)\n            setup_conn(port, accept_conn)\n            print(\"Started webrepl in normal mode\")\n        except:\n            print(\"WebREPL is not configured, run 'import webrepl_setup'\")\n    else:\n        _webrepl.password(password)\n        setup_conn(port, accept_conn)\n        print(\"Started webrepl in manual override mode\")\n\n\ndef start_foreground(port=8266):\n    stop()\n    s = setup_conn(port, None)\n    accept_conn(s)\n"
  },
  {
    "path": "extmod/webrepl/webrepl_setup.py",
    "content": "import sys\n#import uos as os\nimport os\nimport machine\n\nRC = \"./boot.py\"\nCONFIG = \"./webrepl_cfg.py\"\n\ndef input_choice(prompt, choices):\n    while 1:\n        resp = input(prompt)\n        if resp in choices:\n            return resp\n\ndef getpass(prompt):\n    return input(prompt)\n\ndef input_pass():\n    while 1:\n        passwd1 = getpass(\"New password (4-9 chars): \")\n        if len(passwd1) < 4 or len(passwd1) > 9:\n            print(\"Invalid password length\")\n            continue\n        passwd2 = getpass(\"Confirm password: \")\n        if passwd1 == passwd2:\n            return passwd1\n        print(\"Passwords do not match\")\n\n\ndef exists(fname):\n    try:\n        with open(fname):\n            pass\n        return True\n    except OSError:\n        return False\n\n\ndef get_daemon_status():\n    with open(RC) as f:\n        for l in f:\n            if \"webrepl\" in l:\n                if l.startswith(\"#\"):\n                    return False\n                return True\n        return None\n\n\ndef change_daemon(action):\n    LINES = (\"import webrepl\", \"webrepl.start()\")\n    with open(RC) as old_f, open(RC + \".tmp\", \"w\") as new_f:\n        found = False\n        for l in old_f:\n            for patt in LINES:\n                if patt in l:\n                    found = True\n                    if action and l.startswith(\"#\"):\n                        l = l[1:]\n                    elif not action and not l.startswith(\"#\"):\n                        l = \"#\" + l\n            new_f.write(l)\n        if not found:\n            new_f.write(\"import webrepl\\nwebrepl.start()\\n\")\n    # FatFs rename() is not POSIX compliant, will raise OSError if\n    # dest file exists.\n    os.remove(RC)\n    os.rename(RC + \".tmp\", RC)\n\n\ndef main():\n    status = get_daemon_status()\n\n    print(\"WebREPL daemon auto-start status:\", \"enabled\" if status else \"disabled\")\n    print(\"\\nWould you like to (E)nable or (D)isable it running on boot?\")\n    print(\"(Empty line to quit)\")\n    resp = input(\"> \").upper()\n\n    if resp == \"E\":\n        if exists(CONFIG):\n            resp2 = input_choice(\"Would you like to change WebREPL password? (y/n) \", (\"y\", \"n\", \"\"))\n        else:\n            print(\"To enable WebREPL, you must set password for it\")\n            resp2 = \"y\"\n\n        if resp2 == \"y\":\n            passwd = input_pass()\n            with open(CONFIG, \"w\") as f:\n                f.write(\"PASS = %r\\n\" % passwd)\n\n\n    if resp not in (\"D\", \"E\") or (resp == \"D\" and not status) or (resp == \"E\" and status):\n        print(\"No further action required\")\n        sys.exit()\n\n    change_daemon(resp == \"E\")\n\n    print(\"Changes will be activated after reboot\")\n    resp = input_choice(\"Would you like to reboot now? (y/n) \", (\"y\", \"n\", \"\"))\n    if resp == \"y\":\n        machine.reset()\n\nmain()\n"
  },
  {
    "path": "extmod/webrepl/websocket_helper.py",
    "content": "import sys\ntry:\n    import ubinascii as binascii\nexcept:\n    import binascii\ntry:\n    import uhashlib as hashlib\nexcept:\n    import hashlib\n\nDEBUG = 0\n\ndef server_handshake(sock):\n    clr = sock.makefile(\"rwb\", 0)\n    l = clr.readline()\n    #sys.stdout.write(repr(l))\n\n    webkey = None\n\n    while 1:\n        l = clr.readline()\n        if not l:\n            raise OSError(\"EOF in headers\")\n        if l == b\"\\r\\n\":\n            break\n    #    sys.stdout.write(l)\n        h, v = [x.strip() for x in l.split(b\":\", 1)]\n        if DEBUG:\n            print((h, v))\n        if h == b'Sec-WebSocket-Key':\n            webkey = v\n\n    if not webkey:\n        raise OSError(\"Not a websocket request\")\n\n    if DEBUG:\n        print(\"Sec-WebSocket-Key:\", webkey, len(webkey))\n\n    d = hashlib.sha1(webkey)\n    d.update(b\"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\")\n    respkey = d.digest()\n    respkey = binascii.b2a_base64(respkey)[:-1]\n    if DEBUG:\n        print(\"respkey:\", respkey)\n\n    sock.send(b\"\"\"\\\nHTTP/1.1 101 Switching Protocols\\r\nUpgrade: websocket\\r\nConnection: Upgrade\\r\nSec-WebSocket-Accept: \"\"\")\n    sock.send(respkey)\n    sock.send(\"\\r\\n\\r\\n\")\n\n\n# Very simplified client handshake, works for MicroPython's\n# websocket server implementation, but probably not for other\n# servers.\ndef client_handshake(sock):\n    cl = sock.makefile(\"rwb\", 0)\n    cl.write(b\"\"\"\\\nGET / HTTP/1.1\\r\nHost: echo.websocket.org\\r\nConnection: Upgrade\\r\nUpgrade: websocket\\r\nSec-WebSocket-Key: foo\\r\n\\r\n\"\"\")\n    l = cl.readline()\n#    print(l)\n    while 1:\n        l = cl.readline()\n        if l == b\"\\r\\n\":\n            break\n#        sys.stdout.write(l)\n"
  },
  {
    "path": "lib/mp-readline/readline.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/mpstate.h\"\n#include \"py/repl.h\"\n#include \"py/mphal.h\"\n#include \"lib/mp-readline/readline.h\"\n\n#if 0 // print debugging info\n#define DEBUG_PRINT (1)\n#define DEBUG_printf printf\n#else // don't print debugging info\n#define DEBUG_printf(...) (void)0\n#endif\n\n#define READLINE_HIST_SIZE (MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist)))\n\nenum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O };\n\nvoid readline_init0(void) {\n    memset(MP_STATE_PORT(readline_hist), 0, READLINE_HIST_SIZE * sizeof(const char*));\n}\n\nSTATIC char *str_dup_maybe(const char *str) {\n    uint32_t len = strlen(str);\n    char *s2 = m_new_maybe(char, len + 1);\n    if (s2 == NULL) {\n        return NULL;\n    }\n    memcpy(s2, str, len + 1);\n    return s2;\n}\n\n// By default assume terminal which implements VT100 commands...\n#ifndef MICROPY_HAL_HAS_VT100\n#define MICROPY_HAL_HAS_VT100 (1)\n#endif\n\n// ...and provide the implementation using them\n#if MICROPY_HAL_HAS_VT100\nSTATIC void mp_hal_move_cursor_back(uint pos) {\n    if (pos <= 4) {\n        // fast path for most common case of 1 step back\n        mp_hal_stdout_tx_strn(\"\\b\\b\\b\\b\", pos);\n    } else {\n        char vt100_command[6];\n        // snprintf needs space for the terminating null character\n        int n = snprintf(&vt100_command[0], sizeof(vt100_command), \"\\x1b[%u\", pos);\n        if (n > 0) {\n            vt100_command[n] = 'D'; // replace null char\n            mp_hal_stdout_tx_strn(vt100_command, n + 1);\n        }\n    }\n}\n\nSTATIC void mp_hal_erase_line_from_cursor(uint n_chars_to_erase) {\n    (void)n_chars_to_erase;\n    mp_hal_stdout_tx_strn(\"\\x1b[K\", 3);\n}\n#endif\n\ntypedef struct _readline_t {\n    vstr_t *line;\n    size_t orig_line_len;\n    int escape_seq;\n    int hist_cur;\n    size_t cursor_pos;\n    char escape_seq_buf[1];\n    const char *prompt;\n} readline_t;\n\nSTATIC readline_t rl;\n\nint readline_process_char(int c) {\n    size_t last_line_len = rl.line->len;\n    int redraw_step_back = 0;\n    bool redraw_from_cursor = false;\n    int redraw_step_forward = 0;\n    if (rl.escape_seq == ESEQ_NONE) {\n        if (CHAR_CTRL_A <= c && c <= CHAR_CTRL_E && vstr_len(rl.line) == rl.orig_line_len) {\n            // control character with empty line\n            return c;\n        } else if (c == CHAR_CTRL_A) {\n            // CTRL-A with non-empty line is go-to-start-of-line\n            goto home_key;\n        #if MICROPY_REPL_EMACS_KEYS\n        } else if (c == CHAR_CTRL_B) {\n            // CTRL-B with non-empty line is go-back-one-char\n            goto left_arrow_key;\n        #endif\n        } else if (c == CHAR_CTRL_C) {\n            // CTRL-C with non-empty line is cancel\n            return c;\n        #if MICROPY_REPL_EMACS_KEYS\n        } else if (c == CHAR_CTRL_D) {\n            // CTRL-D with non-empty line is delete-at-cursor\n            goto delete_key;\n        #endif\n        } else if (c == CHAR_CTRL_E) {\n            // CTRL-E is go-to-end-of-line\n            goto end_key;\n        #if MICROPY_REPL_EMACS_KEYS\n        } else if (c == CHAR_CTRL_F) {\n            // CTRL-F with non-empty line is go-forward-one-char\n            goto right_arrow_key;\n        } else if (c == CHAR_CTRL_K) {\n            // CTRL-K is kill from cursor to end-of-line, inclusive\n            vstr_cut_tail_bytes(rl.line, last_line_len - rl.cursor_pos);\n            // set redraw parameters\n            redraw_from_cursor = true;\n        } else if (c == CHAR_CTRL_N) {\n            // CTRL-N is go to next line in history\n            goto down_arrow_key;\n        } else if (c == CHAR_CTRL_P) {\n            // CTRL-P is go to previous line in history\n            goto up_arrow_key;\n        } else if (c == CHAR_CTRL_U) {\n            // CTRL-U is kill from beginning-of-line up to cursor\n            vstr_cut_out_bytes(rl.line, rl.orig_line_len, rl.cursor_pos - rl.orig_line_len);\n            // set redraw parameters\n            redraw_step_back = rl.cursor_pos - rl.orig_line_len;\n            redraw_from_cursor = true;\n        #endif\n        } else if (c == '\\r') {\n            // newline\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            readline_push_history(vstr_null_terminated_str(rl.line) + rl.orig_line_len);\n            return 0;\n        } else if (c == 27) {\n            // escape sequence\n            rl.escape_seq = ESEQ_ESC;\n        } else if (c == 8 || c == 127) {\n            // backspace/delete\n            if (rl.cursor_pos > rl.orig_line_len) {\n                // work out how many chars to backspace\n                #if MICROPY_REPL_AUTO_INDENT\n                int nspace = 0;\n                for (size_t i = rl.orig_line_len; i < rl.cursor_pos; i++) {\n                    if (rl.line->buf[i] != ' ') {\n                        nspace = 0;\n                        break;\n                    }\n                    nspace += 1;\n                }\n                if (nspace < 4) {\n                    nspace = 1;\n                } else {\n                    nspace = 4;\n                }\n                #else\n                int nspace = 1;\n                #endif\n\n                // do the backspace\n                vstr_cut_out_bytes(rl.line, rl.cursor_pos - nspace, nspace);\n                // set redraw parameters\n                redraw_step_back = nspace;\n                redraw_from_cursor = true;\n            }\n        #if MICROPY_HELPER_REPL\n        } else if (c == 9) {\n            // tab magic\n            const char *compl_str;\n            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);\n            if (compl_len == 0) {\n                // no match\n            } else if (compl_len == (size_t)(-1)) {\n                // many matches\n                mp_hal_stdout_tx_str(rl.prompt);\n                mp_hal_stdout_tx_strn(rl.line->buf + rl.orig_line_len, rl.cursor_pos - rl.orig_line_len);\n                redraw_from_cursor = true;\n            } else {\n                // one match\n                for (size_t i = 0; i < compl_len; ++i) {\n                    vstr_ins_byte(rl.line, rl.cursor_pos + i, *compl_str++);\n                }\n                // set redraw parameters\n                redraw_from_cursor = true;\n                redraw_step_forward = compl_len;\n            }\n        #endif\n        } else if (32 <= c && c <= 126) {\n            // printable character\n            vstr_ins_char(rl.line, rl.cursor_pos, c);\n            // set redraw parameters\n            redraw_from_cursor = true;\n            redraw_step_forward = 1;\n        }\n    } else if (rl.escape_seq == ESEQ_ESC) {\n        switch (c) {\n            case '[':\n                rl.escape_seq = ESEQ_ESC_BRACKET;\n                break;\n            case 'O':\n                rl.escape_seq = ESEQ_ESC_O;\n                break;\n            default:\n                DEBUG_printf(\"(ESC %d)\", c);\n                rl.escape_seq = ESEQ_NONE;\n        }\n    } else if (rl.escape_seq == ESEQ_ESC_BRACKET) {\n        if ('0' <= c && c <= '9') {\n            rl.escape_seq = ESEQ_ESC_BRACKET_DIGIT;\n            rl.escape_seq_buf[0] = c;\n        } else {\n            rl.escape_seq = ESEQ_NONE;\n            if (c == 'A') {\n#if MICROPY_REPL_EMACS_KEYS\nup_arrow_key:\n#endif\n                // up arrow\n                if (rl.hist_cur + 1 < (int)READLINE_HIST_SIZE && MP_STATE_PORT(readline_hist)[rl.hist_cur + 1] != NULL) {\n                    // increase hist num\n                    rl.hist_cur += 1;\n                    // set line to history\n                    rl.line->len = rl.orig_line_len;\n                    vstr_add_str(rl.line, MP_STATE_PORT(readline_hist)[rl.hist_cur]);\n                    // set redraw parameters\n                    redraw_step_back = rl.cursor_pos - rl.orig_line_len;\n                    redraw_from_cursor = true;\n                    redraw_step_forward = rl.line->len - rl.orig_line_len;\n                }\n            } else if (c == 'B') {\n#if MICROPY_REPL_EMACS_KEYS\ndown_arrow_key:\n#endif\n                // down arrow\n                if (rl.hist_cur >= 0) {\n                    // decrease hist num\n                    rl.hist_cur -= 1;\n                    // set line to history\n                    vstr_cut_tail_bytes(rl.line, rl.line->len - rl.orig_line_len);\n                    if (rl.hist_cur >= 0) {\n                        vstr_add_str(rl.line, MP_STATE_PORT(readline_hist)[rl.hist_cur]);\n                    }\n                    // set redraw parameters\n                    redraw_step_back = rl.cursor_pos - rl.orig_line_len;\n                    redraw_from_cursor = true;\n                    redraw_step_forward = rl.line->len - rl.orig_line_len;\n                }\n            } else if (c == 'C') {\n#if MICROPY_REPL_EMACS_KEYS\nright_arrow_key:\n#endif\n                // right arrow\n                if (rl.cursor_pos < rl.line->len) {\n                    redraw_step_forward = 1;\n                }\n            } else if (c == 'D') {\n#if MICROPY_REPL_EMACS_KEYS\nleft_arrow_key:\n#endif\n                // left arrow\n                if (rl.cursor_pos > rl.orig_line_len) {\n                    redraw_step_back = 1;\n                }\n            } else if (c == 'H') {\n                // home\n                goto home_key;\n            } else if (c == 'F') {\n                // end\n                goto end_key;\n            } else {\n                DEBUG_printf(\"(ESC [ %d)\", c);\n            }\n        }\n    } else if (rl.escape_seq == ESEQ_ESC_BRACKET_DIGIT) {\n        if (c == '~') {\n            if (rl.escape_seq_buf[0] == '1' || rl.escape_seq_buf[0] == '7') {\nhome_key:\n                redraw_step_back = rl.cursor_pos - rl.orig_line_len;\n            } else if (rl.escape_seq_buf[0] == '4' || rl.escape_seq_buf[0] == '8') {\nend_key:\n                redraw_step_forward = rl.line->len - rl.cursor_pos;\n            } else if (rl.escape_seq_buf[0] == '3') {\n                // delete\n#if MICROPY_REPL_EMACS_KEYS\ndelete_key:\n#endif\n                if (rl.cursor_pos < rl.line->len) {\n                    vstr_cut_out_bytes(rl.line, rl.cursor_pos, 1);\n                    redraw_from_cursor = true;\n                }\n            } else {\n                DEBUG_printf(\"(ESC [ %c %d)\", rl.escape_seq_buf[0], c);\n            }\n        } else {\n            DEBUG_printf(\"(ESC [ %c %d)\", rl.escape_seq_buf[0], c);\n        }\n        rl.escape_seq = ESEQ_NONE;\n    } else if (rl.escape_seq == ESEQ_ESC_O) {\n        switch (c) {\n            case 'H':\n                goto home_key;\n            case 'F':\n                goto end_key;\n            default:\n                DEBUG_printf(\"(ESC O %d)\", c);\n                rl.escape_seq = ESEQ_NONE;\n        }\n    } else {\n        rl.escape_seq = ESEQ_NONE;\n    }\n\n    // redraw command prompt, efficiently\n    if (redraw_step_back > 0) {\n        mp_hal_move_cursor_back(redraw_step_back);\n        rl.cursor_pos -= redraw_step_back;\n    }\n    if (redraw_from_cursor) {\n        if (rl.line->len < last_line_len) {\n            // erase old chars\n            mp_hal_erase_line_from_cursor(last_line_len - rl.cursor_pos);\n        }\n        // draw new chars\n        mp_hal_stdout_tx_strn(rl.line->buf + rl.cursor_pos, rl.line->len - rl.cursor_pos);\n        // move cursor forward if needed (already moved forward by length of line, so move it back)\n        mp_hal_move_cursor_back(rl.line->len - (rl.cursor_pos + redraw_step_forward));\n        rl.cursor_pos += redraw_step_forward;\n    } else if (redraw_step_forward > 0) {\n        // draw over old chars to move cursor forwards\n        mp_hal_stdout_tx_strn(rl.line->buf + rl.cursor_pos, redraw_step_forward);\n        rl.cursor_pos += redraw_step_forward;\n    }\n\n    return -1;\n}\n\n#if MICROPY_REPL_AUTO_INDENT\nSTATIC void readline_auto_indent(void) {\n    vstr_t *line = rl.line;\n    if (line->len > 1 && line->buf[line->len - 1] == '\\n') {\n        int i;\n        for (i = line->len - 1; i > 0; i--) {\n            if (line->buf[i - 1] == '\\n') {\n                break;\n            }\n        }\n        size_t j;\n        for (j = i; j < line->len; j++) {\n            if (line->buf[j] != ' ') {\n                break;\n            }\n        }\n        // i=start of line; j=first non-space\n        if (i > 0 && j + 1 == line->len) {\n            // previous line is not first line and is all spaces\n            for (size_t k = i - 1; k > 0; --k) {\n                if (line->buf[k - 1] == '\\n') {\n                    // don't auto-indent if last 2 lines are all spaces\n                    return;\n                } else if (line->buf[k - 1] != ' ') {\n                    // 2nd previous line is not all spaces\n                    break;\n                }\n            }\n        }\n        int n = (j - i) / 4;\n        if (line->buf[line->len - 2] == ':') {\n            n += 1;\n        }\n        while (n-- > 0) {\n            vstr_add_strn(line, \"    \", 4);\n            mp_hal_stdout_tx_strn(\"    \", 4);\n            rl.cursor_pos += 4;\n        }\n    }\n}\n#endif\n\nvoid readline_note_newline(const char *prompt) {\n    rl.orig_line_len = rl.line->len;\n    rl.cursor_pos = rl.orig_line_len;\n    rl.prompt = prompt;\n    mp_hal_stdout_tx_str(prompt);\n    #if MICROPY_REPL_AUTO_INDENT\n    readline_auto_indent();\n    #endif\n}\n\nvoid readline_init(vstr_t *line, const char *prompt) {\n    rl.line = line;\n    rl.orig_line_len = line->len;\n    rl.escape_seq = ESEQ_NONE;\n    rl.escape_seq_buf[0] = 0;\n    rl.hist_cur = -1;\n    rl.cursor_pos = rl.orig_line_len;\n    rl.prompt = prompt;\n    mp_hal_stdout_tx_str(prompt);\n    #if MICROPY_REPL_AUTO_INDENT\n    readline_auto_indent();\n    #endif\n}\n\nint readline(vstr_t *line, const char *prompt) {\n    readline_init(line, prompt);\n    for (;;) {\n        int c = mp_hal_stdin_rx_chr();\n        int r = readline_process_char(c);\n        if (r >= 0) {\n            return r;\n        }\n    }\n}\n\nvoid readline_push_history(const char *line) {\n    if (line[0] != '\\0'\n        && (MP_STATE_PORT(readline_hist)[0] == NULL\n            || strcmp(MP_STATE_PORT(readline_hist)[0], line) != 0)) {\n        // a line which is not empty and different from the last one\n        // so update the history\n        char *most_recent_hist = str_dup_maybe(line);\n        if (most_recent_hist != NULL) {\n            for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {\n                MP_STATE_PORT(readline_hist)[i] = MP_STATE_PORT(readline_hist)[i - 1];\n            }\n            MP_STATE_PORT(readline_hist)[0] = most_recent_hist;\n        }\n    }\n}\n"
  },
  {
    "path": "lib/mp-readline/readline.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H\n#define MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H\n\n#define CHAR_CTRL_A (1)\n#define CHAR_CTRL_B (2)\n#define CHAR_CTRL_C (3)\n#define CHAR_CTRL_D (4)\n#define CHAR_CTRL_E (5)\n#define CHAR_CTRL_F (6)\n#define CHAR_CTRL_K (11)\n#define CHAR_CTRL_N (14)\n#define CHAR_CTRL_P (16)\n#define CHAR_CTRL_U (21)\n\nvoid readline_init0(void);\nint readline(vstr_t *line, const char *prompt);\nvoid readline_push_history(const char *line);\n\nvoid readline_init(vstr_t *line, const char *prompt);\nvoid readline_note_newline(const char *prompt);\nint readline_process_char(int c);\n\n#endif // MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H\n"
  },
  {
    "path": "lib/netutils/netutils.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2015 Daniel Campora\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"lib/netutils/netutils.h\"\n\n// Takes an array with a raw IPv4 address and returns something like '192.168.0.1'.\nmp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian) {\n    char ip_str[16];\n    mp_uint_t ip_len;\n    if (endian == NETUTILS_LITTLE) {\n        ip_len = snprintf(ip_str, 16, \"%u.%u.%u.%u\", ip[3], ip[2], ip[1], ip[0]);\n    } else {\n        ip_len = snprintf(ip_str, 16, \"%u.%u.%u.%u\", ip[0], ip[1], ip[2], ip[3]);\n    }\n    return mp_obj_new_str(ip_str, ip_len);\n}\n\n// Takes an array with a raw IP address, and a port, and returns a net-address\n// tuple such as ('192.168.0.1', 8080).\nmp_obj_t netutils_format_inet_addr(uint8_t *ip, mp_uint_t port, netutils_endian_t endian) {\n    mp_obj_t tuple[2] = {\n        tuple[0] = netutils_format_ipv4_addr(ip, endian),\n        tuple[1] = mp_obj_new_int(port),\n    };\n    return mp_obj_new_tuple(2, tuple);\n}\n\nvoid netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian) {\n    size_t addr_len;\n    const char *addr_str = mp_obj_str_get_data(addr_in, &addr_len);\n    if (addr_len == 0) {\n        // special case of no address given\n        memset(out_ip, 0, NETUTILS_IPV4ADDR_BUFSIZE);\n        return;\n    }\n    const char *s = addr_str;\n    const char *s_top = addr_str + addr_len;\n    for (mp_uint_t i = 3 ; ; i--) {\n        mp_uint_t val = 0;\n        for (; s < s_top && *s != '.'; s++) {\n            val = val * 10 + *s - '0';\n        }\n        if (endian == NETUTILS_LITTLE) {\n            out_ip[i] = val;\n        } else {\n            out_ip[NETUTILS_IPV4ADDR_BUFSIZE - 1 - i] = val;\n        }\n        if (i == 0 && s == s_top) {\n            return;\n        } else if (i > 0 && s < s_top && *s == '.') {\n            s++;\n        } else {\n            mp_raise_ValueError(\"invalid arguments\");\n        }\n    }\n}\n\n// Takes an address of the form ('192.168.0.1', 8080), returns the port and\n// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes).\nmp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian) {\n    mp_obj_t *addr_items;\n    mp_obj_get_array_fixed_n(addr_in, 2, &addr_items);\n    netutils_parse_ipv4_addr(addr_items[0], out_ip, endian);\n    return mp_obj_get_int(addr_items[1]);\n}\n"
  },
  {
    "path": "lib/netutils/netutils.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2015 Daniel Campora\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H\n#define MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H\n\n#define NETUTILS_IPV4ADDR_BUFSIZE    4\n\n#define NETUTILS_TRACE_IS_TX        (0x0001)\n#define NETUTILS_TRACE_PAYLOAD      (0x0002)\n#define NETUTILS_TRACE_NEWLINE      (0x0004)\n\ntypedef enum _netutils_endian_t {\n    NETUTILS_LITTLE,\n    NETUTILS_BIG,\n} netutils_endian_t;\n\n// Takes an array with a raw IPv4 address and returns something like '192.168.0.1'.\nmp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian);\n\n// Takes an array with a raw IP address, and a port, and returns a net-address\n// tuple such as ('192.168.0.1', 8080).\nmp_obj_t netutils_format_inet_addr(uint8_t *ip, mp_uint_t port, netutils_endian_t endian);\n\nvoid netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian);\n\n// Takes an address of the form ('192.168.0.1', 8080), returns the port and\n// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes).\nmp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian);\n\nvoid netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags);\n\n#endif // MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H\n"
  },
  {
    "path": "lib/oofatfs/diskio.h",
    "content": "/* This file is part of ooFatFs, a customised version of FatFs\n * See https://github.com/micropython/oofatfs for details\n */\n\n/*-----------------------------------------------------------------------/\n/  Low level disk interface modlue include file   (C)ChaN, 2014          /\n/-----------------------------------------------------------------------*/\n\n#ifndef _DISKIO_DEFINED\n#define _DISKIO_DEFINED\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n\n/* Status of Disk Functions */\ntypedef BYTE    DSTATUS;\n\n/* Results of Disk Functions */\ntypedef enum {\n    RES_OK = 0,     /* 0: Successful */\n    RES_ERROR,      /* 1: R/W Error */\n    RES_WRPRT,      /* 2: Write Protected */\n    RES_NOTRDY,     /* 3: Not Ready */\n    RES_PARERR      /* 4: Invalid Parameter */\n} DRESULT;\n\n\n/*---------------------------------------*/\n/* Prototypes for disk control functions */\n\n\nDRESULT disk_read (void *drv, BYTE* buff, DWORD sector, UINT count);\nDRESULT disk_write (void *drv, const BYTE* buff, DWORD sector, UINT count);\nDRESULT disk_ioctl (void *drv, BYTE cmd, void* buff);\n\n\n/* Disk Status Bits (DSTATUS) */\n\n#define STA_NOINIT      0x01    /* Drive not initialized */\n#define STA_NODISK      0x02    /* No medium in the drive */\n#define STA_PROTECT     0x04    /* Write protected */\n\n\n/* Command code for disk_ioctrl fucntion */\n\n/* Generic command (Used by FatFs) */\n#define CTRL_SYNC           0   /* Complete pending write process (needed at _FS_READONLY == 0) */\n#define GET_SECTOR_COUNT    1   /* Get media size (needed at _USE_MKFS == 1) */\n#define GET_SECTOR_SIZE     2   /* Get sector size (needed at _MAX_SS != _MIN_SS) */\n#define GET_BLOCK_SIZE      3   /* Get erase block size (needed at _USE_MKFS == 1) */\n#define CTRL_TRIM           4   /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */\n#define IOCTL_INIT          5\n#define IOCTL_STATUS        6\n\n/* Generic command (Not used by FatFs) */\n#define CTRL_POWER          5   /* Get/Set power status */\n#define CTRL_LOCK           6   /* Lock/Unlock media removal */\n#define CTRL_EJECT          7   /* Eject media */\n#define CTRL_FORMAT         8   /* Create physical format on the media */\n\n/* MMC/SDC specific ioctl command */\n#define MMC_GET_TYPE        10  /* Get card type */\n#define MMC_GET_CSD         11  /* Get CSD */\n#define MMC_GET_CID         12  /* Get CID */\n#define MMC_GET_OCR         13  /* Get OCR */\n#define MMC_GET_SDSTAT      14  /* Get SD status */\n#define ISDIO_READ          55  /* Read data form SD iSDIO register */\n#define ISDIO_WRITE         56  /* Write data to SD iSDIO register */\n#define ISDIO_MRITE         57  /* Masked write data to SD iSDIO register */\n\n/* ATA/CF specific ioctl command */\n#define ATA_GET_REV         20  /* Get F/W revision */\n#define ATA_GET_MODEL       21  /* Get model name */\n#define ATA_GET_SN          22  /* Get serial number */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "lib/oofatfs/ff.c",
    "content": "/* This file is part of ooFatFs, a customised version of FatFs\n * See https://github.com/micropython/oofatfs for details\n */\n\n/*----------------------------------------------------------------------------/\n/  FatFs - Generic FAT file system module  R0.12b                             /\n/-----------------------------------------------------------------------------/\n/\n/ Copyright (C) 2016, ChaN, all right reserved.\n/\n/ FatFs module is an open source software. Redistribution and use of FatFs in\n/ source and binary forms, with or without modification, are permitted provided\n/ that the following condition is met:\n\n/ 1. Redistributions of source code must retain the above copyright notice,\n/    this condition and the following disclaimer.\n/\n/ This software is provided by the copyright holder and contributors \"AS IS\"\n/ and any warranties related to this software are DISCLAIMED.\n/ The copyright owner or contributors be NOT LIABLE for any damages caused\n/ by use of this software.\n/----------------------------------------------------------------------------*/\n\n\n#include <string.h>\n\n#include \"ff.h\"         /* Declarations of FatFs API */\n#include \"diskio.h\"     /* Declarations of device I/O functions */\n\n// DIR has been renamed FF_DIR in the public API so it doesn't clash with POSIX\n#define DIR FF_DIR\n\n/*--------------------------------------------------------------------------\n\n   Module Private Definitions\n\n---------------------------------------------------------------------------*/\n\n#if _FATFS != 68020 /* Revision ID */\n#error Wrong include file (ff.h).\n#endif\n\n\n#define ABORT(fs, res)      { fp->err = (BYTE)(res); LEAVE_FF(fs, res); }\n\n\n/* Reentrancy related */\n#if _FS_REENTRANT\n#if _USE_LFN == 1\n#error Static LFN work area cannot be used at thread-safe configuration\n#endif\n#define ENTER_FF(fs)        { if (!lock_fs(fs)) return FR_TIMEOUT; }\n#define LEAVE_FF(fs, res)   { unlock_fs(fs, res); return res; }\n#else\n#define ENTER_FF(fs)\n#define LEAVE_FF(fs, res)   return res\n#endif\n\n\n\n/* Definitions of sector size */\n#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096)\n#error Wrong sector size configuration\n#endif\n#if _MAX_SS == _MIN_SS\n#define SS(fs)  ((UINT)_MAX_SS) /* Fixed sector size */\n#else\n#define SS(fs)  ((fs)->ssize)   /* Variable sector size */\n#endif\n\n\n/* Timestamp */\n#if _FS_NORTC == 1\n#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31\n#error Invalid _FS_NORTC settings\n#endif\n#define GET_FATTIME()   ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16)\n#else\n#define GET_FATTIME()   get_fattime()\n#endif\n\n\n/* File lock controls */\n#if _FS_LOCK != 0\n#if _FS_READONLY\n#error _FS_LOCK must be 0 at read-only configuration\n#endif\ntypedef struct {\n    FATFS *fs;      /* Object ID 1, volume (NULL:blank entry) */\n    DWORD clu;      /* Object ID 2, directory (0:root) */\n    DWORD ofs;      /* Object ID 3, directory offset */\n    WORD ctr;       /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */\n} FILESEM;\n#endif\n\n\n\n/* DBCS code ranges and SBCS upper conversion tables */\n\n#if _CODE_PAGE == 932   /* Japanese Shift-JIS */\n#define _DF1S   0x81    /* DBC 1st byte range 1 start */\n#define _DF1E   0x9F    /* DBC 1st byte range 1 end */\n#define _DF2S   0xE0    /* DBC 1st byte range 2 start */\n#define _DF2E   0xFC    /* DBC 1st byte range 2 end */\n#define _DS1S   0x40    /* DBC 2nd byte range 1 start */\n#define _DS1E   0x7E    /* DBC 2nd byte range 1 end */\n#define _DS2S   0x80    /* DBC 2nd byte range 2 start */\n#define _DS2E   0xFC    /* DBC 2nd byte range 2 end */\n\n#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */\n#define _DF1S   0x81\n#define _DF1E   0xFE\n#define _DS1S   0x40\n#define _DS1E   0x7E\n#define _DS2S   0x80\n#define _DS2E   0xFE\n\n#elif _CODE_PAGE == 949 /* Korean */\n#define _DF1S   0x81\n#define _DF1E   0xFE\n#define _DS1S   0x41\n#define _DS1E   0x5A\n#define _DS2S   0x61\n#define _DS2E   0x7A\n#define _DS3S   0x81\n#define _DS3E   0xFE\n\n#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */\n#define _DF1S   0x81\n#define _DF1E   0xFE\n#define _DS1S   0x40\n#define _DS1E   0x7E\n#define _DS2S   0xA1\n#define _DS2E   0xFE\n\n#elif _CODE_PAGE == 437 /* U.S. */\n#define _DF1S   0\n#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \\\n                0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n                0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 720 /* Arabic */\n#define _DF1S   0\n#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n                0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 737 /* Greek */\n#define _DF1S   0\n#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n                0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \\\n                0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 771 /* KBL */\n#define _DF1S   0\n#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n                0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n                0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \\\n                0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n                0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF}\n\n#elif _CODE_PAGE == 775 /* Baltic */\n#define _DF1S   0\n#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \\\n                0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \\\n                0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 850 /* Latin 1 */\n#define _DF1S   0\n#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \\\n                0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \\\n                0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \\\n                0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 852 /* Latin 2 */\n#define _DF1S   0\n#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \\\n                0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \\\n                0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}\n\n#elif _CODE_PAGE == 855 /* Cyrillic */\n#define _DF1S   0\n#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \\\n                0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \\\n                0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \\\n                0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \\\n                0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 857 /* Turkish */\n#define _DF1S   0\n#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \\\n                0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \\\n                0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 860 /* Portuguese */\n#define _DF1S   0\n#define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \\\n                0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n                0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 861 /* Icelandic */\n#define _DF1S   0\n#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \\\n                0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \\\n                0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 862 /* Hebrew */\n#define _DF1S   0\n#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n                0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n                0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 863 /* Canadian-French */\n#define _DF1S   0\n#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \\\n                0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \\\n                0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 864 /* Arabic */\n#define _DF1S   0\n#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \\\n                0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n                0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 865 /* Nordic */\n#define _DF1S   0\n#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \\\n                0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n                0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n                0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 866 /* Russian */\n#define _DF1S   0\n#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n                0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n                0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n                0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n                0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n\n#elif _CODE_PAGE == 869 /* Greek 2 */\n#define _DF1S   0\n#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n                0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \\\n                0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n                0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n                0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \\\n                0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \\\n                0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF}\n\n#elif _CODE_PAGE == 1   /* ASCII (for only non-LFN cfg) */\n#if _USE_LFN != 0\n#error Cannot enable LFN without valid code page.\n#endif\n#define _DF1S   0\n\n#else\n#error Unknown code page\n\n#endif\n\n\n/* Character code support macros */\n#define IsUpper(c)  (((c)>='A')&&((c)<='Z'))\n#define IsLower(c)  (((c)>='a')&&((c)<='z'))\n#define IsDigit(c)  (((c)>='0')&&((c)<='9'))\n\n#if _DF1S != 0  /* Code page is DBCS */\n\n#ifdef _DF2S    /* Two 1st byte areas */\n#define IsDBCS1(c)  (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))\n#else           /* One 1st byte area */\n#define IsDBCS1(c)  ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)\n#endif\n\n#ifdef _DS3S    /* Three 2nd byte areas */\n#define IsDBCS2(c)  (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))\n#else           /* Two 2nd byte areas */\n#define IsDBCS2(c)  (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))\n#endif\n\n#else           /* Code page is SBCS */\n\n#define IsDBCS1(c)  0\n#define IsDBCS2(c)  0\n\n#endif /* _DF1S */\n\n\n/* File attribute bits (internal use) */\n#define AM_VOL      0x08    /* Volume label */\n#define AM_LFN      0x0F    /* LFN entry */\n#define AM_MASK     0x3F    /* Mask of defined bits */\n\n\n/* File access control and file status flags (internal use) */\n#define FA_SEEKEND  0x20    /* Seek to end of the file on file open */\n#define FA_MODIFIED 0x40    /* File has been modified */\n#define FA_DIRTY    0x80    /* FIL.buf[] needs to be written-back */\n\n\n/* Name status flags */\n#define NSFLAG      11      /* Index of name status byte in fn[] */\n#define NS_LOSS     0x01    /* Out of 8.3 format */\n#define NS_LFN      0x02    /* Force to create LFN entry */\n#define NS_LAST     0x04    /* Last segment */\n#define NS_BODY     0x08    /* Lower case flag (body) */\n#define NS_EXT      0x10    /* Lower case flag (ext) */\n#define NS_DOT      0x20    /* Dot entry */\n#define NS_NOLFN    0x40    /* Do not find LFN */\n#define NS_NONAME   0x80    /* Not followed */\n\n\n/* Limits and boundaries (differ from specs but correct for real DOS/Windows) */\n#define MAX_FAT12   0xFF5           /* Maximum number of FAT12 clusters */\n#define MAX_FAT16   0xFFF5          /* Maximum number of FAT16 clusters */\n#define MAX_FAT32   0xFFFFFF5       /* Maximum number of FAT32 clusters */\n#define MAX_EXFAT   0x7FFFFFFD      /* Maximum number of exFAT clusters (limited by implementation) */\n#define MAX_DIR     0x200000        /* Maximum size of FAT directory */\n#define MAX_DIR_EX  0x10000000      /* Maximum size of exFAT directory */\n\n\n/* FatFs refers the members in the FAT structures as byte array instead of\n/ structure members because the structure is not binary compatible between\n/ different platforms */\n\n#define BS_JmpBoot          0       /* x86 jump instruction (3-byte) */\n#define BS_OEMName          3       /* OEM name (8-byte) */\n#define BPB_BytsPerSec      11      /* Sector size [byte] (WORD) */\n#define BPB_SecPerClus      13      /* Cluster size [sector] (BYTE) */\n#define BPB_RsvdSecCnt      14      /* Size of reserved area [sector] (WORD) */\n#define BPB_NumFATs         16      /* Number of FATs (BYTE) */\n#define BPB_RootEntCnt      17      /* Size of root directory area for FAT12/16 [entry] (WORD) */\n#define BPB_TotSec16        19      /* Volume size (16-bit) [sector] (WORD) */\n#define BPB_Media           21      /* Media descriptor byte (BYTE) */\n#define BPB_FATSz16         22      /* FAT size (16-bit) [sector] (WORD) */\n#define BPB_SecPerTrk       24      /* Track size for int13h [sector] (WORD) */\n#define BPB_NumHeads        26      /* Number of heads for int13h (WORD) */\n#define BPB_HiddSec         28      /* Volume offset from top of the drive (DWORD) */\n#define BPB_TotSec32        32      /* Volume size (32-bit) [sector] (DWORD) */\n#define BS_DrvNum           36      /* Physical drive number for int13h (BYTE) */\n#define BS_NTres            37      /* Error flag (BYTE) */\n#define BS_BootSig          38      /* Extended boot signature (BYTE) */\n#define BS_VolID            39      /* Volume serial number (DWORD) */\n#define BS_VolLab           43      /* Volume label string (8-byte) */\n#define BS_FilSysType       54      /* File system type string (8-byte) */\n#define BS_BootCode         62      /* Boot code (448-byte) */\n#define BS_55AA             510     /* Signature word (WORD) */\n\n#define BPB_FATSz32         36      /* FAT32: FAT size [sector] (DWORD) */\n#define BPB_ExtFlags32      40      /* FAT32: Extended flags (WORD) */\n#define BPB_FSVer32         42      /* FAT32: File system version (WORD) */\n#define BPB_RootClus32      44      /* FAT32: Root directory cluster (DWORD) */\n#define BPB_FSInfo32        48      /* FAT32: Offset of FSINFO sector (WORD) */\n#define BPB_BkBootSec32     50      /* FAT32: Offset of backup boot sector (WORD) */\n#define BS_DrvNum32         64      /* FAT32: Physical drive number for int13h (BYTE) */\n#define BS_NTres32          65      /* FAT32: Error flag (BYTE) */\n#define BS_BootSig32        66      /* FAT32: Extended boot signature (BYTE) */\n#define BS_VolID32          67      /* FAT32: Volume serial number (DWORD) */\n#define BS_VolLab32         71      /* FAT32: Volume label string (8-byte) */\n#define BS_FilSysType32     82      /* FAT32: File system type string (8-byte) */\n#define BS_BootCode32       90      /* FAT32: Boot code (420-byte) */\n\n#define BPB_ZeroedEx        11      /* exFAT: MBZ field (53-byte) */\n#define BPB_VolOfsEx        64      /* exFAT: Volume offset from top of the drive [sector] (QWORD) */\n#define BPB_TotSecEx        72      /* exFAT: Volume size [sector] (QWORD) */\n#define BPB_FatOfsEx        80      /* exFAT: FAT offset from top of the volume [sector] (DWORD) */\n#define BPB_FatSzEx         84      /* exFAT: FAT size [sector] (DWORD) */\n#define BPB_DataOfsEx       88      /* exFAT: Data offset from top of the volume [sector] (DWORD) */\n#define BPB_NumClusEx       92      /* exFAT: Number of clusters (DWORD) */\n#define BPB_RootClusEx      96      /* exFAT: Root directory cluster (DWORD) */\n#define BPB_VolIDEx         100     /* exFAT: Volume serial number (DWORD) */\n#define BPB_FSVerEx         104     /* exFAT: File system version (WORD) */\n#define BPB_VolFlagEx       106     /* exFAT: Volume flags (BYTE) */\n#define BPB_ActFatEx        107     /* exFAT: Active FAT flags (BYTE) */\n#define BPB_BytsPerSecEx    108     /* exFAT: Log2 of sector size in byte (BYTE) */\n#define BPB_SecPerClusEx    109     /* exFAT: Log2 of cluster size in sector (BYTE) */\n#define BPB_NumFATsEx       110     /* exFAT: Number of FATs (BYTE) */\n#define BPB_DrvNumEx        111     /* exFAT: Physical drive number for int13h (BYTE) */\n#define BPB_PercInUseEx     112     /* exFAT: Percent in use (BYTE) */\n#define BPB_RsvdEx          113     /* exFAT: Reserved (7-byte) */\n#define BS_BootCodeEx       120     /* exFAT: Boot code (390-byte) */\n\n#define FSI_LeadSig         0       /* FAT32 FSI: Leading signature (DWORD) */\n#define FSI_StrucSig        484     /* FAT32 FSI: Structure signature (DWORD) */\n#define FSI_Free_Count      488     /* FAT32 FSI: Number of free clusters (DWORD) */\n#define FSI_Nxt_Free        492     /* FAT32 FSI: Last allocated cluster (DWORD) */\n\n#define MBR_Table           446     /* MBR: Offset of partition table in the MBR */\n#define SZ_PTE              16      /* MBR: Size of a partition table entry */\n#define PTE_Boot            0       /* MBR PTE: Boot indicator */\n#define PTE_StHead          1       /* MBR PTE: Start head */\n#define PTE_StSec           2       /* MBR PTE: Start sector */\n#define PTE_StCyl           3       /* MBR PTE: Start cylinder */\n#define PTE_System          4       /* MBR PTE: System ID */\n#define PTE_EdHead          5       /* MBR PTE: End head */\n#define PTE_EdSec           6       /* MBR PTE: End sector */\n#define PTE_EdCyl           7       /* MBR PTE: End cylinder */\n#define PTE_StLba           8       /* MBR PTE: Start in LBA */\n#define PTE_SizLba          12      /* MBR PTE: Size in LBA */\n\n#define DIR_Name            0       /* Short file name (11-byte) */\n#define DIR_Attr            11      /* Attribute (BYTE) */\n#define DIR_NTres           12      /* Lower case flag (BYTE) */\n#define DIR_CrtTime10       13      /* Created time sub-second (BYTE) */\n#define DIR_CrtTime         14      /* Created time (DWORD) */\n#define DIR_LstAccDate      18      /* Last accessed date (WORD) */\n#define DIR_FstClusHI       20      /* Higher 16-bit of first cluster (WORD) */\n#define DIR_ModTime         22      /* Modified time (DWORD) */\n#define DIR_FstClusLO       26      /* Lower 16-bit of first cluster (WORD) */\n#define DIR_FileSize        28      /* File size (DWORD) */\n#define LDIR_Ord            0       /* LFN entry order and LLE flag (BYTE) */\n#define LDIR_Attr           11      /* LFN attribute (BYTE) */\n#define LDIR_Type           12      /* LFN type (BYTE) */\n#define LDIR_Chksum         13      /* Checksum of the SFN entry (BYTE) */\n#define LDIR_FstClusLO      26      /* Must be zero (WORD) */\n#define XDIR_Type           0       /* Type of exFAT directory entry (BYTE) */\n#define XDIR_NumLabel       1       /* Number of volume label characters (BYTE) */\n#define XDIR_Label          2       /* Volume label (11-WORD) */\n#define XDIR_CaseSum        4       /* Sum of case conversion table (DWORD) */\n#define XDIR_NumSec         1       /* Number of secondary entries (BYTE) */\n#define XDIR_SetSum         2       /* Sum of the set of directory entries (WORD) */\n#define XDIR_Attr           4       /* File attribute (WORD) */\n#define XDIR_CrtTime        8       /* Created time (DWORD) */\n#define XDIR_ModTime        12      /* Modified time (DWORD) */\n#define XDIR_AccTime        16      /* Last accessed time (DWORD) */\n#define XDIR_CrtTime10      20      /* Created time subsecond (BYTE) */\n#define XDIR_ModTime10      21      /* Modified time subsecond (BYTE) */\n#define XDIR_CrtTZ          22      /* Created timezone (BYTE) */\n#define XDIR_ModTZ          23      /* Modified timezone (BYTE) */\n#define XDIR_AccTZ          24      /* Last accessed timezone (BYTE) */\n#define XDIR_GenFlags       33      /* Gneral secondary flags (WORD) */\n#define XDIR_NumName        35      /* Number of file name characters (BYTE) */\n#define XDIR_NameHash       36      /* Hash of file name (WORD) */\n#define XDIR_ValidFileSize  40      /* Valid file size (QWORD) */\n#define XDIR_FstClus        52      /* First cluster of the file data (DWORD) */\n#define XDIR_FileSize       56      /* File/Directory size (QWORD) */\n\n#define SZDIRE              32      /* Size of a directory entry */\n#define LLEF                0x40    /* Last long entry flag in LDIR_Ord */\n#define DDEM                0xE5    /* Deleted directory entry mark set to DIR_Name[0] */\n#define RDDEM               0x05    /* Replacement of the character collides with DDEM */\n\n\n\n\n\n/*--------------------------------------------------------------------------\n\n   Module Private Work Area\n\n---------------------------------------------------------------------------*/\n\n/* Remark: Variables here without initial value shall be guaranteed zero/null\n/  at start-up. If not, either the linker or start-up routine being used is\n/  not compliance with C standard. */\n\n#if _VOLUMES < 1 || _VOLUMES > 9\n#error Wrong _VOLUMES setting\n#endif\nstatic WORD Fsid;               /* File system mount ID */\n\n#if _FS_LOCK != 0\nstatic FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */\n#endif\n\n#if _USE_LFN == 0           /* Non-LFN configuration */\n#define DEF_NAMBUF\n#define INIT_NAMBUF(fs)\n#define FREE_NAMBUF()\n#else\n#if _MAX_LFN < 12 || _MAX_LFN > 255\n#error Wrong _MAX_LFN setting\n#endif\n\n#if _USE_LFN == 1       /* LFN enabled with static working buffer */\n#if _FS_EXFAT\nstatic BYTE DirBuf[SZDIRE*19];  /* Directory entry block scratchpad buffer (19 entries in size) */\n#endif\nstatic WCHAR LfnBuf[_MAX_LFN+1];    /* LFN enabled with static working buffer */\n#define DEF_NAMBUF\n#define INIT_NAMBUF(fs)\n#define FREE_NAMBUF()\n\n#elif _USE_LFN == 2     /* LFN enabled with dynamic working buffer on the stack */\n#if _FS_EXFAT\n#define DEF_NAMBUF      WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[SZDIRE*19];\n#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; }\n#define FREE_NAMBUF()\n#else\n#define DEF_NAMBUF      WCHAR lbuf[_MAX_LFN+1];\n#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; }\n#define FREE_NAMBUF()\n#endif\n\n#elif _USE_LFN == 3     /* LFN enabled with dynamic working buffer on the heap */\n#if _FS_EXFAT\n#define DEF_NAMBUF      WCHAR *lfn;\n#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2 + SZDIRE*19); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); }\n#define FREE_NAMBUF()   ff_memfree(lfn)\n#else\n#define DEF_NAMBUF      WCHAR *lfn;\n#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; }\n#define FREE_NAMBUF()   ff_memfree(lfn)\n#endif\n\n#else\n#error Wrong _USE_LFN setting\n#endif\n#endif\n\n#ifdef _EXCVT\nstatic const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */\n#endif\n\n\n\n\n\n\n/*--------------------------------------------------------------------------\n\n   Module Private Functions\n\n---------------------------------------------------------------------------*/\n\n\n/*-----------------------------------------------------------------------*/\n/* Load/Store multi-byte word in the FAT structure                       */\n/*-----------------------------------------------------------------------*/\n\nstatic\nWORD ld_word (const BYTE* ptr)  /*   Load a 2-byte little-endian word */\n{\n    WORD rv;\n\n    rv = ptr[1];\n    rv = rv << 8 | ptr[0];\n    return rv;\n}\n\nstatic\nDWORD ld_dword (const BYTE* ptr)    /* Load a 4-byte little-endian word */\n{\n    DWORD rv;\n\n    rv = ptr[3];\n    rv = rv << 8 | ptr[2];\n    rv = rv << 8 | ptr[1];\n    rv = rv << 8 | ptr[0];\n    return rv;\n}\n\n#if _FS_EXFAT\nstatic\nQWORD ld_qword (const BYTE* ptr)    /* Load an 8-byte little-endian word */\n{\n    QWORD rv;\n\n    rv = ptr[7];\n    rv = rv << 8 | ptr[6];\n    rv = rv << 8 | ptr[5];\n    rv = rv << 8 | ptr[4];\n    rv = rv << 8 | ptr[3];\n    rv = rv << 8 | ptr[2];\n    rv = rv << 8 | ptr[1];\n    rv = rv << 8 | ptr[0];\n    return rv;\n}\n#endif\n\n#if !_FS_READONLY\nstatic\nvoid st_word (BYTE* ptr, WORD val)  /* Store a 2-byte word in little-endian */\n{\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val;\n}\n\nstatic\nvoid st_dword (BYTE* ptr, DWORD val)    /* Store a 4-byte word in little-endian */\n{\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val;\n}\n\n#if _FS_EXFAT\nstatic\nvoid st_qword (BYTE* ptr, QWORD val)    /* Store an 8-byte word in little-endian */\n{\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val; val >>= 8;\n    *ptr++ = (BYTE)val;\n}\n#endif\n#endif  /* !_FS_READONLY */\n\n\n\n/*-----------------------------------------------------------------------*/\n/* String functions                                                      */\n/*-----------------------------------------------------------------------*/\n\n// These were originally provided by the FatFs library but we use externally\n// provided versions from C stdlib to (hopefully) reduce code size and use\n// more efficient versions.\n#define mem_cpy memcpy\n#define mem_set memset\n#define mem_cmp memcmp\n\n/* Check if chr is contained in the string */\nstatic\nint chk_chr (const char* str, int chr) {    /* NZ:contained, ZR:not contained */\n    while (*str && *str != chr) str++;\n    return *str;\n}\n\n\n\n\n#if _FS_REENTRANT\n/*-----------------------------------------------------------------------*/\n/* Request/Release grant to access the volume                            */\n/*-----------------------------------------------------------------------*/\nstatic\nint lock_fs (\n    FATFS* fs       /* File system object */\n)\n{\n    return ff_req_grant(fs->sobj);\n}\n\n\nstatic\nvoid unlock_fs (\n    FATFS* fs,      /* File system object */\n    FRESULT res     /* Result code to be returned */\n)\n{\n    if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) {\n        ff_rel_grant(fs->sobj);\n    }\n}\n\n#endif\n\n\n\n#if _FS_LOCK != 0\n/*-----------------------------------------------------------------------*/\n/* File lock control functions                                           */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT chk_lock (  /* Check if the file can be accessed */\n    DIR* dp,        /* Directory object pointing the file to be checked */\n    int acc         /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */\n)\n{\n    UINT i, be;\n\n    /* Search file semaphore table */\n    for (i = be = 0; i < _FS_LOCK; i++) {\n        if (Files[i].fs) {  /* Existing entry */\n            if (Files[i].fs == dp->obj.fs &&        /* Check if the object matched with an open object */\n                Files[i].clu == dp->obj.sclust &&\n                Files[i].ofs == dp->dptr) break;\n        } else {            /* Blank entry */\n            be = 1;\n        }\n    }\n    if (i == _FS_LOCK) {    /* The object is not opened */\n        return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES;   /* Is there a blank entry for new object? */\n    }\n\n    /* The object has been opened. Reject any open against writing file and all write mode open */\n    return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;\n}\n\n\nstatic\nint enq_lock (void) /* Check if an entry is available for a new object */\n{\n    UINT i;\n\n    for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;\n    return (i == _FS_LOCK) ? 0 : 1;\n}\n\n\nstatic\nUINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */\n    DIR* dp,    /* Directory object pointing the file to register or increment */\n    int acc     /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */\n)\n{\n    UINT i;\n\n\n    for (i = 0; i < _FS_LOCK; i++) {    /* Find the object */\n        if (Files[i].fs == dp->obj.fs &&\n            Files[i].clu == dp->obj.sclust &&\n            Files[i].ofs == dp->dptr) break;\n    }\n\n    if (i == _FS_LOCK) {                /* Not opened. Register it as new. */\n        for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;\n        if (i == _FS_LOCK) return 0;    /* No free entry to register (int err) */\n        Files[i].fs = dp->obj.fs;\n        Files[i].clu = dp->obj.sclust;\n        Files[i].ofs = dp->dptr;\n        Files[i].ctr = 0;\n    }\n\n    if (acc && Files[i].ctr) return 0;  /* Access violation (int err) */\n\n    Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1;  /* Set semaphore value */\n\n    return i + 1;\n}\n\n\nstatic\nFRESULT dec_lock (  /* Decrement object open counter */\n    UINT i          /* Semaphore index (1..) */\n)\n{\n    WORD n;\n    FRESULT res;\n\n\n    if (--i < _FS_LOCK) {   /* Shift index number origin from 0 */\n        n = Files[i].ctr;\n        if (n == 0x100) n = 0;      /* If write mode open, delete the entry */\n        if (n > 0) n--;             /* Decrement read mode open count */\n        Files[i].ctr = n;\n        if (n == 0) Files[i].fs = 0;    /* Delete the entry if open count gets zero */\n        res = FR_OK;\n    } else {\n        res = FR_INT_ERR;           /* Invalid index nunber */\n    }\n    return res;\n}\n\n\nstatic\nvoid clear_lock (   /* Clear lock entries of the volume */\n    FATFS *fs\n)\n{\n    UINT i;\n\n    for (i = 0; i < _FS_LOCK; i++) {\n        if (Files[i].fs == fs) Files[i].fs = 0;\n    }\n}\n\n#endif  /* _FS_LOCK != 0 */\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Move/Flush disk access window in the file system object               */\n/*-----------------------------------------------------------------------*/\n#if !_FS_READONLY\nstatic\nFRESULT sync_window (   /* Returns FR_OK or FR_DISK_ERROR */\n    FATFS* fs           /* File system object */\n)\n{\n    DWORD wsect;\n    UINT nf;\n    FRESULT res = FR_OK;\n\n\n    if (fs->wflag) {    /* Write back the sector if it is dirty */\n        wsect = fs->winsect;    /* Current sector number */\n        if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) {\n            res = FR_DISK_ERR;\n        } else {\n            fs->wflag = 0;\n            if (wsect - fs->fatbase < fs->fsize) {      /* Is it in the FAT area? */\n                for (nf = fs->n_fats; nf >= 2; nf--) {  /* Reflect the change to all FAT copies */\n                    wsect += fs->fsize;\n                    disk_write(fs->drv, fs->win, wsect, 1);\n                }\n            }\n        }\n    }\n    return res;\n}\n#endif\n\n\nstatic\nFRESULT move_window (   /* Returns FR_OK or FR_DISK_ERROR */\n    FATFS* fs,          /* File system object */\n    DWORD sector        /* Sector number to make appearance in the fs->win[] */\n)\n{\n    FRESULT res = FR_OK;\n\n\n    if (sector != fs->winsect) {    /* Window offset changed? */\n#if !_FS_READONLY\n        res = sync_window(fs);      /* Write-back changes */\n#endif\n        if (res == FR_OK) {         /* Fill sector window with new data */\n            if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) {\n                sector = 0xFFFFFFFF;    /* Invalidate window if data is not reliable */\n                res = FR_DISK_ERR;\n            }\n            fs->winsect = sector;\n        }\n    }\n    return res;\n}\n\n\n\n\n#if !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Synchronize file system and strage device                             */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT sync_fs (   /* FR_OK:succeeded, !=0:error */\n    FATFS* fs       /* File system object */\n)\n{\n    FRESULT res;\n\n\n    res = sync_window(fs);\n    if (res == FR_OK) {\n        /* Update FSInfo sector if needed */\n        if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {\n            /* Create FSInfo structure */\n            mem_set(fs->win, 0, SS(fs));\n            st_word(fs->win + BS_55AA, 0xAA55);\n            st_dword(fs->win + FSI_LeadSig, 0x41615252);\n            st_dword(fs->win + FSI_StrucSig, 0x61417272);\n            st_dword(fs->win + FSI_Free_Count, fs->free_clst);\n            st_dword(fs->win + FSI_Nxt_Free, fs->last_clst);\n            /* Write it into the FSInfo sector */\n            fs->winsect = fs->volbase + 1;\n            disk_write(fs->drv, fs->win, fs->winsect, 1);\n            fs->fsi_flag = 0;\n        }\n        /* Make sure that no pending write process in the physical drive */\n        if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR;\n    }\n\n    return res;\n}\n\n#endif\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Get sector# from cluster#                                             */\n/*-----------------------------------------------------------------------*/\n\nstatic\nDWORD clust2sect (  /* !=0:Sector number, 0:Failed (invalid cluster#) */\n    FATFS* fs,      /* File system object */\n    DWORD clst      /* Cluster# to be converted */\n)\n{\n    clst -= 2;\n    if (clst >= fs->n_fatent - 2) return 0;     /* Invalid cluster# */\n    return clst * fs->csize + fs->database;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* FAT access - Read value of a FAT entry                                */\n/*-----------------------------------------------------------------------*/\n\nstatic\nDWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */\n    _FDID* obj, /* Corresponding object */\n    DWORD clst  /* Cluster number to get the value */\n)\n{\n    UINT wc, bc;\n    DWORD val;\n    FATFS *fs = obj->fs;\n\n\n    if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */\n        val = 1;    /* Internal error */\n\n    } else {\n        val = 0xFFFFFFFF;   /* Default value falls on disk error */\n\n        switch (fs->fs_type) {\n        case FS_FAT12 :\n            bc = (UINT)clst; bc += bc / 2;\n            if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;\n            wc = fs->win[bc++ % SS(fs)];\n            if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;\n            wc |= fs->win[bc % SS(fs)] << 8;\n            val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF);\n            break;\n\n        case FS_FAT16 :\n            if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break;\n            val = ld_word(fs->win + clst * 2 % SS(fs));\n            break;\n\n        case FS_FAT32 :\n            if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;\n            val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF;\n            break;\n#if _FS_EXFAT\n        case FS_EXFAT :\n            if (obj->objsize) {\n                DWORD cofs = clst - obj->sclust;    /* Offset from start cluster */\n                DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize;  /* Number of clusters - 1 */\n\n                if (obj->stat == 2) {   /* Is there no valid chain on the FAT? */\n                    if (cofs <= clen) {\n                        val = (cofs == clen) ? 0x7FFFFFFF : clst + 1;   /* Generate the value */\n                        break;\n                    }\n                }\n                if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the contiguous part? */\n                    val = clst + 1;     /* Generate the value */\n                    break;\n                }\n                if (obj->stat != 2) {   /* Get value from FAT if FAT chain is valid */\n                    if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;\n                    val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF;\n                    break;\n                }\n            }\n            /* go next */\n#endif\n        default:\n            val = 1;    /* Internal error */\n        }\n    }\n\n    return val;\n}\n\n\n\n\n#if !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* FAT access - Change value of a FAT entry                              */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT put_fat (   /* FR_OK(0):succeeded, !=0:error */\n    FATFS* fs,      /* Corresponding file system object */\n    DWORD clst,     /* FAT index number (cluster number) to be changed */\n    DWORD val       /* New value to be set to the entry */\n)\n{\n    UINT bc;\n    BYTE *p;\n    FRESULT res = FR_INT_ERR;\n\n\n    if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */\n        switch (fs->fs_type) {\n        case FS_FAT12 : /* Bitfield items */\n            bc = (UINT)clst; bc += bc / 2;\n            res = move_window(fs, fs->fatbase + (bc / SS(fs)));\n            if (res != FR_OK) break;\n            p = fs->win + bc++ % SS(fs);\n            *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;\n            fs->wflag = 1;\n            res = move_window(fs, fs->fatbase + (bc / SS(fs)));\n            if (res != FR_OK) break;\n            p = fs->win + bc % SS(fs);\n            *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));\n            fs->wflag = 1;\n            break;\n\n        case FS_FAT16 : /* WORD aligned items */\n            res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));\n            if (res != FR_OK) break;\n            st_word(fs->win + clst * 2 % SS(fs), (WORD)val);\n            fs->wflag = 1;\n            break;\n\n        case FS_FAT32 : /* DWORD aligned items */\n#if _FS_EXFAT\n        case FS_EXFAT :\n#endif\n            res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));\n            if (res != FR_OK) break;\n            if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) {\n                val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000);\n            }\n            st_dword(fs->win + clst * 4 % SS(fs), val);\n            fs->wflag = 1;\n            break;\n        }\n    }\n    return res;\n}\n\n#endif /* !_FS_READONLY */\n\n\n\n\n#if _FS_EXFAT && !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* exFAT: Accessing FAT and Allocation Bitmap                            */\n/*-----------------------------------------------------------------------*/\n\n/*---------------------------------------------*/\n/* exFAT: Find a contiguous free cluster block */\n/*---------------------------------------------*/\n\nstatic\nDWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Disk error */\n    FATFS* fs,  /* File system object */\n    DWORD clst, /* Cluster number to scan from */\n    DWORD ncl   /* Number of contiguous clusters to find (1..) */\n)\n{\n    BYTE bm, bv;\n    UINT i;\n    DWORD val, scl, ctr;\n\n\n    clst -= 2;  /* The first bit in the bitmap corresponds to cluster #2 */\n    if (clst >= fs->n_fatent - 2) clst = 0;\n    scl = val = clst; ctr = 0;\n    for (;;) {\n        if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF;   /* (assuming bitmap is located top of the cluster heap) */\n        i = val / 8 % SS(fs); bm = 1 << (val % 8);\n        do {\n            do {\n                bv = fs->win[i] & bm; bm <<= 1;     /* Get bit value */\n                if (++val >= fs->n_fatent - 2) {    /* Next cluster (with wrap-around) */\n                    val = 0; bm = 0; i = 4096;\n                }\n                if (!bv) {  /* Is it a free cluster? */\n                    if (++ctr == ncl) return scl + 2;   /* Check run length */\n                } else {\n                    scl = val; ctr = 0;     /* Encountered a live cluster, restart to scan */\n                }\n                if (val == clst) return 0;  /* All cluster scanned? */\n            } while (bm);\n            bm = 1;\n        } while (++i < SS(fs));\n    }\n}\n\n\n/*------------------------------------*/\n/* exFAT: Set/Clear a block of bitmap */\n/*------------------------------------*/\n\nstatic\nFRESULT change_bitmap (\n    FATFS* fs,  /* File system object */\n    DWORD clst, /* Cluster number to change from */\n    DWORD ncl,  /* Number of clusters to be changed */\n    int bv      /* bit value to be set (0 or 1) */\n)\n{\n    BYTE bm;\n    UINT i;\n    DWORD sect;\n\n\n    clst -= 2;  /* The first bit corresponds to cluster #2 */\n    sect = fs->database + clst / 8 / SS(fs);    /* Sector address (assuming bitmap is located top of the cluster heap) */\n    i = clst / 8 % SS(fs);                      /* Byte offset in the sector */\n    bm = 1 << (clst % 8);                       /* Bit mask in the byte */\n    for (;;) {\n        if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR;\n        do {\n            do {\n                if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */\n                fs->win[i] ^= bm;   /* Flip the bit */\n                fs->wflag = 1;\n                if (--ncl == 0) return FR_OK;   /* All bits processed? */\n            } while (bm <<= 1);     /* Next bit */\n            bm = 1;\n        } while (++i < SS(fs));     /* Next byte */\n        i = 0;\n    }\n}\n\n\n/*---------------------------------------------*/\n/* Complement contiguous part of the FAT chain */\n/*---------------------------------------------*/\n\nstatic\nFRESULT fill_fat_chain (\n    _FDID* obj  /* Pointer to the corresponding object */\n)\n{\n    FRESULT res;\n    DWORD cl, n;\n\n    if (obj->stat == 3) {   /* Has the object been changed 'fragmented'? */\n        for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */\n            res = put_fat(obj->fs, cl, cl + 1);\n            if (res != FR_OK) return res;\n        }\n        obj->stat = 0;  /* Change status 'FAT chain is valid' */\n    }\n    return FR_OK;\n}\n\n#endif  /* _FS_EXFAT && !_FS_READONLY */\n\n\n\n#if !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* FAT handling - Remove a cluster chain                                 */\n/*-----------------------------------------------------------------------*/\nstatic\nFRESULT remove_chain (  /* FR_OK(0):succeeded, !=0:error */\n    _FDID* obj,         /* Corresponding object */\n    DWORD clst,         /* Cluster to remove a chain from */\n    DWORD pclst         /* Previous cluster of clst (0:an entire chain) */\n)\n{\n    FRESULT res = FR_OK;\n    DWORD nxt;\n    FATFS *fs = obj->fs;\n#if _FS_EXFAT || _USE_TRIM\n    DWORD scl = clst, ecl = clst;\n#endif\n#if _USE_TRIM\n    DWORD rt[2];\n#endif\n\n    if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR;    /* Check if in valid range */\n\n    /* Mark the previous cluster 'EOC' on the FAT if it exists */\n    if (pclst && (!_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) {\n        res = put_fat(fs, pclst, 0xFFFFFFFF);\n        if (res != FR_OK) return res;\n    }\n\n    /* Remove the chain */\n    do {\n        nxt = get_fat(obj, clst);           /* Get cluster status */\n        if (nxt == 0) break;                /* Empty cluster? */\n        if (nxt == 1) return FR_INT_ERR;    /* Internal error? */\n        if (nxt == 0xFFFFFFFF) return FR_DISK_ERR;  /* Disk error? */\n        if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) {\n            res = put_fat(fs, clst, 0);     /* Mark the cluster 'free' on the FAT */\n            if (res != FR_OK) return res;\n        }\n        if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */\n            fs->free_clst++;\n            fs->fsi_flag |= 1;\n        }\n#if _FS_EXFAT || _USE_TRIM\n        if (ecl + 1 == nxt) {   /* Is next cluster contiguous? */\n            ecl = nxt;\n        } else {                /* End of contiguous cluster block */\n#if _FS_EXFAT\n            if (fs->fs_type == FS_EXFAT) {\n                res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */\n                if (res != FR_OK) return res;\n            }\n#endif\n#if _USE_TRIM\n            rt[0] = clust2sect(fs, scl);                    /* Start sector */\n            rt[1] = clust2sect(fs, ecl) + fs->csize - 1;    /* End sector */\n            disk_ioctl(fs->drv, CTRL_TRIM, rt);             /* Inform device the block can be erased */\n#endif\n            scl = ecl = nxt;\n        }\n#endif\n        clst = nxt;                 /* Next cluster */\n    } while (clst < fs->n_fatent);  /* Repeat while not the last link */\n\n#if _FS_EXFAT\n    if (fs->fs_type == FS_EXFAT) {\n        if (pclst == 0) {   /* Does object have no chain? */\n            obj->stat = 0;      /* Change the object status 'initial' */\n        } else {\n            if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain got contiguous? */\n                obj->stat = 2;  /* Change the object status 'contiguous' */\n            }\n        }\n    }\n#endif\n    return FR_OK;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* FAT handling - Stretch a chain or Create a new chain                  */\n/*-----------------------------------------------------------------------*/\nstatic\nDWORD create_chain (    /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */\n    _FDID* obj,         /* Corresponding object */\n    DWORD clst          /* Cluster# to stretch, 0:Create a new chain */\n)\n{\n    DWORD cs, ncl, scl;\n    FRESULT res;\n    FATFS *fs = obj->fs;\n\n\n    if (clst == 0) {    /* Create a new chain */\n        scl = fs->last_clst;                /* Get suggested cluster to start from */\n        if (scl == 0 || scl >= fs->n_fatent) scl = 1;\n    }\n    else {              /* Stretch current chain */\n        cs = get_fat(obj, clst);            /* Check the cluster status */\n        if (cs < 2) return 1;               /* Invalid value */\n        if (cs == 0xFFFFFFFF) return cs;    /* A disk error occurred */\n        if (cs < fs->n_fatent) return cs;   /* It is already followed by next cluster */\n        scl = clst;\n    }\n\n#if _FS_EXFAT\n    if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */\n        ncl = find_bitmap(fs, scl, 1);              /* Find a free cluster */\n        if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl;  /* No free cluster or hard error? */\n        res = change_bitmap(fs, ncl, 1, 1);         /* Mark the cluster 'in use' */\n        if (res == FR_INT_ERR) return 1;\n        if (res == FR_DISK_ERR) return 0xFFFFFFFF;\n        if (clst == 0) {                            /* Is it a new chain? */\n            obj->stat = 2;                          /* Set status 'contiguous chain' */\n        } else {                                    /* This is a stretched chain */\n            if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */\n                obj->n_cont = scl - obj->sclust;    /* Set size of the contiguous part */\n                obj->stat = 3;                      /* Change status 'just fragmented' */\n            }\n        }\n    } else\n#endif\n    {   /* On the FAT12/16/32 volume */\n        ncl = scl;  /* Start cluster */\n        for (;;) {\n            ncl++;                          /* Next cluster */\n            if (ncl >= fs->n_fatent) {      /* Check wrap-around */\n                ncl = 2;\n                if (ncl > scl) return 0;    /* No free cluster */\n            }\n            cs = get_fat(obj, ncl);         /* Get the cluster status */\n            if (cs == 0) break;             /* Found a free cluster */\n            if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* An error occurred */\n            if (ncl == scl) return 0;       /* No free cluster */\n        }\n    }\n\n    if (_FS_EXFAT && fs->fs_type == FS_EXFAT && obj->stat == 2) {   /* Is it a contiguous chain? */\n        res = FR_OK;                        /* FAT does not need to be written */\n    } else {\n        res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */\n        if (res == FR_OK && clst) {\n            res = put_fat(fs, clst, ncl);   /* Link it from the previous one if needed */\n        }\n    }\n\n    if (res == FR_OK) {         /* Update FSINFO if function succeeded. */\n        fs->last_clst = ncl;\n        if (fs->free_clst < fs->n_fatent - 2) fs->free_clst--;\n        fs->fsi_flag |= 1;\n    } else {\n        ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;    /* Failed. Create error status */\n    }\n\n    return ncl;     /* Return new cluster number or error status */\n}\n\n#endif /* !_FS_READONLY */\n\n\n\n\n#if _USE_FASTSEEK\n/*-----------------------------------------------------------------------*/\n/* FAT handling - Convert offset into cluster with link map table        */\n/*-----------------------------------------------------------------------*/\n\nstatic\nDWORD clmt_clust (  /* <2:Error, >=2:Cluster number */\n    FIL* fp,        /* Pointer to the file object */\n    FSIZE_t ofs     /* File offset to be converted to cluster# */\n)\n{\n    DWORD cl, ncl, *tbl;\n    FATFS *fs = fp->obj.fs;\n\n\n    tbl = fp->cltbl + 1;    /* Top of CLMT */\n    cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */\n    for (;;) {\n        ncl = *tbl++;           /* Number of cluters in the fragment */\n        if (ncl == 0) return 0; /* End of table? (error) */\n        if (cl < ncl) break;    /* In this fragment? */\n        cl -= ncl; tbl++;       /* Next fragment */\n    }\n    return cl + *tbl;   /* Return the cluster number */\n}\n\n#endif  /* _USE_FASTSEEK */\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Directory handling - Set directory index                              */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT dir_sdi (   /* FR_OK(0):succeeded, !=0:error */\n    DIR* dp,        /* Pointer to directory object */\n    DWORD ofs       /* Offset of directory table */\n)\n{\n    DWORD csz, clst;\n    FATFS *fs = dp->obj.fs;\n\n\n    if (ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) {    /* Check range of offset and alignment */\n        return FR_INT_ERR;\n    }\n    dp->dptr = ofs;             /* Set current offset */\n    clst = dp->obj.sclust;      /* Table start cluster (0:root) */\n    if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */\n        clst = fs->dirbase;\n        if (_FS_EXFAT) dp->obj.stat = 0;    /* exFAT: Root dir has an FAT chain */\n    }\n\n    if (clst == 0) {    /* Static table (root-directory in FAT12/16) */\n        if (ofs / SZDIRE >= fs->n_rootdir)  return FR_INT_ERR;  /* Is index out of range? */\n        dp->sect = fs->dirbase;\n\n    } else {            /* Dynamic table (sub-directory or root-directory in FAT32+) */\n        csz = (DWORD)fs->csize * SS(fs);    /* Bytes per cluster */\n        while (ofs >= csz) {                /* Follow cluster chain */\n            clst = get_fat(&dp->obj, clst);             /* Get next cluster */\n            if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */\n            if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR;    /* Reached to end of table or internal error */\n            ofs -= csz;\n        }\n        dp->sect = clust2sect(fs, clst);\n    }\n    dp->clust = clst;                   /* Current cluster# */\n    if (!dp->sect) return FR_INT_ERR;\n    dp->sect += ofs / SS(fs);           /* Sector# of the directory entry */\n    dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */\n\n    return FR_OK;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Directory handling - Move directory table index next                  */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT dir_next (  /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */\n    DIR* dp,        /* Pointer to the directory object */\n    int stretch     /* 0: Do not stretch table, 1: Stretch table if needed */\n)\n{\n    DWORD ofs, clst;\n    FATFS *fs = dp->obj.fs;\n#if !_FS_READONLY\n    UINT n;\n#endif\n\n    ofs = dp->dptr + SZDIRE;    /* Next entry */\n    if (!dp->sect || ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE;  /* Report EOT when offset has reached max value */\n\n    if (ofs % SS(fs) == 0) {    /* Sector changed? */\n        dp->sect++;             /* Next sector */\n\n        if (!dp->clust) {       /* Static table */\n            if (ofs / SZDIRE >= fs->n_rootdir) {    /* Report EOT if it reached end of static table */\n                dp->sect = 0; return FR_NO_FILE;\n            }\n        }\n        else {                  /* Dynamic table */\n            if ((ofs / SS(fs) & (fs->csize - 1)) == 0) {        /* Cluster changed? */\n                clst = get_fat(&dp->obj, dp->clust);            /* Get next cluster */\n                if (clst <= 1) return FR_INT_ERR;               /* Internal error */\n                if (clst == 0xFFFFFFFF) return FR_DISK_ERR;     /* Disk error */\n                if (clst >= fs->n_fatent) {                     /* Reached end of dynamic table */\n#if !_FS_READONLY\n                    if (!stretch) {                             /* If no stretch, report EOT */\n                        dp->sect = 0; return FR_NO_FILE;\n                    }\n                    clst = create_chain(&dp->obj, dp->clust);   /* Allocate a cluster */\n                    if (clst == 0) return FR_DENIED;            /* No free cluster */\n                    if (clst == 1) return FR_INT_ERR;           /* Internal error */\n                    if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */\n                    /* Clean-up the stretched table */\n                    if (_FS_EXFAT) dp->obj.stat |= 4;           /* The directory needs to be updated */\n                    if (sync_window(fs) != FR_OK) return FR_DISK_ERR;   /* Flush disk access window */\n                    mem_set(fs->win, 0, SS(fs));                /* Clear window buffer */\n                    for (n = 0, fs->winsect = clust2sect(fs, clst); n < fs->csize; n++, fs->winsect++) {    /* Fill the new cluster with 0 */\n                        fs->wflag = 1;\n                        if (sync_window(fs) != FR_OK) return FR_DISK_ERR;\n                    }\n                    fs->winsect -= n;                           /* Restore window offset */\n#else\n                    if (!stretch) dp->sect = 0;                 /* If no stretch, report EOT (this is to suppress warning) */\n                    dp->sect = 0; return FR_NO_FILE;            /* Report EOT */\n#endif\n                }\n                dp->clust = clst;       /* Initialize data for new cluster */\n                dp->sect = clust2sect(fs, clst);\n            }\n        }\n    }\n    dp->dptr = ofs;                     /* Current entry */\n    dp->dir = fs->win + ofs % SS(fs);   /* Pointer to the entry in the win[] */\n\n    return FR_OK;\n}\n\n\n\n\n#if !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Directory handling - Reserve a block of directory entries             */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */\n    DIR* dp,        /* Pointer to the directory object */\n    UINT nent       /* Number of contiguous entries to allocate */\n)\n{\n    FRESULT res;\n    UINT n;\n    FATFS *fs = dp->obj.fs;\n\n\n    res = dir_sdi(dp, 0);\n    if (res == FR_OK) {\n        n = 0;\n        do {\n            res = move_window(fs, dp->sect);\n            if (res != FR_OK) break;\n#if _FS_EXFAT\n            if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) {\n#else\n            if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) {\n#endif\n                if (++n == nent) break; /* A block of contiguous free entries is found */\n            } else {\n                n = 0;                  /* Not a blank entry. Restart to search */\n            }\n            res = dir_next(dp, 1);\n        } while (res == FR_OK); /* Next entry with table stretch enabled */\n    }\n\n    if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */\n    return res;\n}\n\n#endif  /* !_FS_READONLY */\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* FAT: Directory handling - Load/Store start cluster number             */\n/*-----------------------------------------------------------------------*/\n\nstatic\nDWORD ld_clust (    /* Returns the top cluster value of the SFN entry */\n    FATFS* fs,      /* Pointer to the fs object */\n    const BYTE* dir /* Pointer to the key entry */\n)\n{\n    DWORD cl;\n\n    cl = ld_word(dir + DIR_FstClusLO);\n    if (fs->fs_type == FS_FAT32) {\n        cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16;\n    }\n\n    return cl;\n}\n\n\n#if !_FS_READONLY\nstatic\nvoid st_clust (\n    FATFS* fs,  /* Pointer to the fs object */\n    BYTE* dir,  /* Pointer to the key entry */\n    DWORD cl    /* Value to be set */\n)\n{\n    st_word(dir + DIR_FstClusLO, (WORD)cl);\n    if (fs->fs_type == FS_FAT32) {\n        st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16));\n    }\n}\n#endif\n\n\n\n#if _USE_LFN != 0\n/*------------------------------------------------------------------------*/\n/* FAT-LFN: LFN handling                                                  */\n/*------------------------------------------------------------------------*/\nstatic\nconst BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30};  /* Offset of LFN characters in the directory entry */\n\n\n/*--------------------------------------------------------*/\n/* FAT-LFN: Compare a part of file name with an LFN entry */\n/*--------------------------------------------------------*/\nstatic\nint cmp_lfn (               /* 1:matched, 0:not matched */\n    const WCHAR* lfnbuf,    /* Pointer to the LFN working buffer to be compared */\n    BYTE* dir               /* Pointer to the directory entry containing the part of LFN */\n)\n{\n    UINT i, s;\n    WCHAR wc, uc;\n\n\n    if (ld_word(dir + LDIR_FstClusLO) != 0) return 0;   /* Check LDIR_FstClusLO */\n\n    i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13;  /* Offset in the LFN buffer */\n\n    for (wc = 1, s = 0; s < 13; s++) {      /* Process all characters in the entry */\n        uc = ld_word(dir + LfnOfs[s]);      /* Pick an LFN character */\n        if (wc) {\n            if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */\n                return 0;                   /* Not matched */\n            }\n            wc = uc;\n        } else {\n            if (uc != 0xFFFF) return 0;     /* Check filler */\n        }\n    }\n\n    if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0;    /* Last segment matched but different length */\n\n    return 1;       /* The part of LFN matched */\n}\n\n\n#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT\n/*-----------------------------------------------------*/\n/* FAT-LFN: Pick a part of file name from an LFN entry */\n/*-----------------------------------------------------*/\nstatic\nint pick_lfn (          /* 1:succeeded, 0:buffer overflow or invalid LFN entry */\n    WCHAR* lfnbuf,      /* Pointer to the LFN working buffer */\n    BYTE* dir           /* Pointer to the LFN entry */\n)\n{\n    UINT i, s;\n    WCHAR wc, uc;\n\n\n    if (ld_word(dir + LDIR_FstClusLO) != 0) return 0;   /* Check LDIR_FstClusLO */\n\n    i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13;  /* Offset in the LFN buffer */\n\n    for (wc = 1, s = 0; s < 13; s++) {      /* Process all characters in the entry */\n        uc = ld_word(dir + LfnOfs[s]);      /* Pick an LFN character */\n        if (wc) {\n            if (i >= _MAX_LFN) return 0;    /* Buffer overflow? */\n            lfnbuf[i++] = wc = uc;          /* Store it */\n        } else {\n            if (uc != 0xFFFF) return 0;     /* Check filler */\n        }\n    }\n\n    if (dir[LDIR_Ord] & LLEF) {             /* Put terminator if it is the last LFN part */\n        if (i >= _MAX_LFN) return 0;        /* Buffer overflow? */\n        lfnbuf[i] = 0;\n    }\n\n    return 1;       /* The part of LFN is valid */\n}\n#endif\n\n\n#if !_FS_READONLY\n/*-----------------------------------------*/\n/* FAT-LFN: Create an entry of LFN entries */\n/*-----------------------------------------*/\nstatic\nvoid put_lfn (\n    const WCHAR* lfn,   /* Pointer to the LFN */\n    BYTE* dir,          /* Pointer to the LFN entry to be created */\n    BYTE ord,           /* LFN order (1-20) */\n    BYTE sum            /* Checksum of the corresponding SFN */\n)\n{\n    UINT i, s;\n    WCHAR wc;\n\n\n    dir[LDIR_Chksum] = sum;         /* Set checksum */\n    dir[LDIR_Attr] = AM_LFN;        /* Set attribute. LFN entry */\n    dir[LDIR_Type] = 0;\n    st_word(dir + LDIR_FstClusLO, 0);\n\n    i = (ord - 1) * 13;             /* Get offset in the LFN working buffer */\n    s = wc = 0;\n    do {\n        if (wc != 0xFFFF) wc = lfn[i++];    /* Get an effective character */\n        st_word(dir + LfnOfs[s], wc);       /* Put it */\n        if (wc == 0) wc = 0xFFFF;       /* Padding characters for left locations */\n    } while (++s < 13);\n    if (wc == 0xFFFF || !lfn[i]) ord |= LLEF;   /* Last LFN part is the start of LFN sequence */\n    dir[LDIR_Ord] = ord;            /* Set the LFN order */\n}\n\n#endif  /* !_FS_READONLY */\n#endif  /* _USE_LFN != 0 */\n\n\n\n#if _USE_LFN != 0 && !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* FAT-LFN: Create a Numbered SFN                                        */\n/*-----------------------------------------------------------------------*/\n\nstatic\nvoid gen_numname (\n    BYTE* dst,          /* Pointer to the buffer to store numbered SFN */\n    const BYTE* src,    /* Pointer to SFN */\n    const WCHAR* lfn,   /* Pointer to LFN */\n    UINT seq            /* Sequence number */\n)\n{\n    BYTE ns[8], c;\n    UINT i, j;\n    WCHAR wc;\n    DWORD sr;\n\n\n    mem_cpy(dst, src, 11);\n\n    if (seq > 5) {  /* In case of many collisions, generate a hash number instead of sequential number */\n        sr = seq;\n        while (*lfn) {  /* Create a CRC */\n            wc = *lfn++;\n            for (i = 0; i < 16; i++) {\n                sr = (sr << 1) + (wc & 1);\n                wc >>= 1;\n                if (sr & 0x10000) sr ^= 0x11021;\n            }\n        }\n        seq = (UINT)sr;\n    }\n\n    /* itoa (hexdecimal) */\n    i = 7;\n    do {\n        c = (BYTE)((seq % 16) + '0');\n        if (c > '9') c += 7;\n        ns[i--] = c;\n        seq /= 16;\n    } while (seq);\n    ns[i] = '~';\n\n    /* Append the number */\n    for (j = 0; j < i && dst[j] != ' '; j++) {\n        if (IsDBCS1(dst[j])) {\n            if (j == i - 1) break;\n            j++;\n        }\n    }\n    do {\n        dst[j++] = (i < 8) ? ns[i++] : ' ';\n    } while (j < 8);\n}\n#endif  /* _USE_LFN != 0 && !_FS_READONLY */\n\n\n\n#if _USE_LFN != 0\n/*-----------------------------------------------------------------------*/\n/* FAT-LFN: Calculate checksum of an SFN entry                           */\n/*-----------------------------------------------------------------------*/\n\nstatic\nBYTE sum_sfn (\n    const BYTE* dir     /* Pointer to the SFN entry */\n)\n{\n    BYTE sum = 0;\n    UINT n = 11;\n\n    do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);\n    return sum;\n}\n\n#endif  /* _USE_LFN != 0 */\n\n\n\n#if _FS_EXFAT\n/*-----------------------------------------------------------------------*/\n/* exFAT: Checksum                                                       */\n/*-----------------------------------------------------------------------*/\n\nstatic\nWORD xdir_sum (         /* Get checksum of the directoly block */\n    const BYTE* dir     /* Directory entry block to be calculated */\n)\n{\n    UINT i, szblk;\n    WORD sum;\n\n\n    szblk = (dir[XDIR_NumSec] + 1) * SZDIRE;\n    for (i = sum = 0; i < szblk; i++) {\n        if (i == XDIR_SetSum) { /* Skip sum field */\n            i++;\n        } else {\n            sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i];\n        }\n    }\n    return sum;\n}\n\n\n\nstatic\nWORD xname_sum (        /* Get check sum (to be used as hash) of the name */\n    const WCHAR* name   /* File name to be calculated */\n)\n{\n    WCHAR chr;\n    WORD sum = 0;\n\n\n    while ((chr = *name++) != 0) {\n        chr = ff_wtoupper(chr);     /* File name needs to be ignored case */\n        sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF);\n        sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8);\n    }\n    return sum;\n}\n\n\n#if !_FS_READONLY && _USE_MKFS\nstatic\nDWORD xsum32 (\n    BYTE  dat,  /* Data to be sumed */\n    DWORD sum   /* Previous value */\n)\n{\n    sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat;\n    return sum;\n}\n#endif\n\n\n#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2\n/*------------------------------------------------------*/\n/* exFAT: Get object information from a directory block */\n/*------------------------------------------------------*/\n\nstatic\nvoid get_xdir_info (\n    BYTE* dirb,         /* Pointer to the direcotry entry block 85+C0+C1s */\n    FILINFO* fno        /* Buffer to store the extracted file information */\n)\n{\n    UINT di, si;\n    WCHAR w;\n#if !_LFN_UNICODE\n    UINT nc;\n#endif\n\n    /* Get file name */\n#if _LFN_UNICODE\n    if (dirb[XDIR_NumName] <= _MAX_LFN) {\n        for (si = SZDIRE * 2, di = 0; di < dirb[XDIR_NumName]; si += 2, di++) {\n            if ((si % SZDIRE) == 0) si += 2;    /* Skip entry type field */\n            w = ld_word(dirb + si);             /* Get a character */\n            fno->fname[di] = w;                 /* Store it */\n        }\n    } else {\n        di = 0; /* Buffer overflow and inaccessible object */\n    }\n#else\n    for (si = SZDIRE * 2, di = nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) {\n        if ((si % SZDIRE) == 0) si += 2;    /* Skip entry type field */\n        w = ld_word(dirb + si);             /* Get a character */\n        w = ff_convert(w, 0);               /* Unicode -> OEM */\n        if (w == 0) { di = 0; break; }      /* Could not be converted and inaccessible object */\n        if (_DF1S && w >= 0x100) {          /* Put 1st byte if it is a DBC (always false at SBCS cfg) */\n            fno->fname[di++] = (char)(w >> 8);\n        }\n        if (di >= _MAX_LFN) { di = 0; break; }  /* Buffer overflow and inaccessible object */\n        fno->fname[di++] = (char)w;\n    }\n#endif\n    if (di == 0) fno->fname[di++] = '?';    /* Inaccessible object? */\n    fno->fname[di] = 0;                     /* Terminate file name */\n\n    fno->altname[0] = 0;                            /* No SFN */\n    fno->fattrib = dirb[XDIR_Attr];                 /* Attribute */\n    fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize);  /* Size */\n    fno->ftime = ld_word(dirb + XDIR_ModTime + 0);  /* Time */\n    fno->fdate = ld_word(dirb + XDIR_ModTime + 2);  /* Date */\n}\n\n#endif  /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */\n\n\n/*-----------------------------------*/\n/* exFAT: Get a directry entry block */\n/*-----------------------------------*/\n\nstatic\nFRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */\n    DIR* dp         /* Pointer to the reading direcotry object pointing the 85 entry */\n)\n{\n    FRESULT res;\n    UINT i, nent;\n    BYTE* dirb = dp->obj.fs->dirbuf;    /* Pointer to the on-memory direcotry entry block 85+C0+C1s */\n\n\n    /* Load 85 entry */\n    res = move_window(dp->obj.fs, dp->sect);\n    if (res != FR_OK) return res;\n    if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR;\n    mem_cpy(dirb, dp->dir, SZDIRE);\n    nent = dirb[XDIR_NumSec] + 1;\n\n    /* Load C0 entry */\n    res = dir_next(dp, 0);\n    if (res != FR_OK) return res;\n    res = move_window(dp->obj.fs, dp->sect);\n    if (res != FR_OK) return res;\n    if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR;\n    mem_cpy(dirb + SZDIRE, dp->dir, SZDIRE);\n\n    /* Load C1 entries */\n    if (nent < 3 || nent > 19) return FR_NO_FILE;\n    i = SZDIRE * 2; nent *= SZDIRE;\n    do {\n        res = dir_next(dp, 0);\n        if (res != FR_OK) return res;\n        res = move_window(dp->obj.fs, dp->sect);\n        if (res != FR_OK) return res;\n        if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR;\n        mem_cpy(dirb + i, dp->dir, SZDIRE);\n        i += SZDIRE;\n    } while (i < nent);\n\n    /* Sanity check */\n    if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR;\n\n    return FR_OK;\n}\n\n\n#if !_FS_READONLY || _FS_RPATH != 0\n/*------------------------------------------------*/\n/* exFAT: Load the object's directory entry block */\n/*------------------------------------------------*/\nstatic\nFRESULT load_obj_dir (\n    DIR* dp,            /* Blank directory object to be used to access containing direcotry */\n    const _FDID* obj    /* Object with containing directory information */\n)\n{\n    FRESULT res;\n\n\n    /* Open object containing directory */\n    dp->obj.fs = obj->fs;\n    dp->obj.sclust = obj->c_scl;\n    dp->obj.stat = (BYTE)obj->c_size;\n    dp->obj.objsize = obj->c_size & 0xFFFFFF00;\n    dp->blk_ofs = obj->c_ofs;\n\n    res = dir_sdi(dp, dp->blk_ofs); /* Goto the block location */\n    if (res == FR_OK) {\n        res = load_xdir(dp);        /* Load the object's entry block */\n    }\n    return res;\n}\n#endif\n\n\n#if !_FS_READONLY\n/*-----------------------------------------------*/\n/* exFAT: Store the directory block to the media */\n/*-----------------------------------------------*/\nstatic\nFRESULT store_xdir (\n    DIR* dp             /* Pointer to the direcotry object */\n)\n{\n    FRESULT res;\n    UINT nent;\n    BYTE* dirb = dp->obj.fs->dirbuf;    /* Pointer to the direcotry entry block 85+C0+C1s */\n\n    /* Create set sum */\n    st_word(dirb + XDIR_SetSum, xdir_sum(dirb));\n    nent = dirb[XDIR_NumSec] + 1;\n\n    /* Store the set of directory to the volume */\n    res = dir_sdi(dp, dp->blk_ofs);\n    while (res == FR_OK) {\n        res = move_window(dp->obj.fs, dp->sect);\n        if (res != FR_OK) break;\n        mem_cpy(dp->dir, dirb, SZDIRE);\n        dp->obj.fs->wflag = 1;\n        if (--nent == 0) break;\n        dirb += SZDIRE;\n        res = dir_next(dp, 0);\n    }\n    return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR;\n}\n\n\n\n/*-------------------------------------------*/\n/* exFAT: Create a new directory enrty block */\n/*-------------------------------------------*/\n\nstatic\nvoid create_xdir (\n    BYTE* dirb,         /* Pointer to the direcotry entry block buffer */\n    const WCHAR* lfn    /* Pointer to the nul terminated file name */\n)\n{\n    UINT i;\n    BYTE nb, nc;\n    WCHAR chr;\n\n\n    mem_set(dirb, 0, 2 * SZDIRE);           /* Initialize 85+C0 entry */\n    dirb[XDIR_Type] = 0x85;\n    dirb[XDIR_Type + SZDIRE] = 0xC0;\n    st_word(dirb + XDIR_NameHash, xname_sum(lfn));  /* Set name hash */\n\n    i = SZDIRE * 2; /* C1 offset */\n    nc = 0; nb = 1; chr = 1;\n    do {\n        dirb[i++] = 0xC1; dirb[i++] = 0;    /* Entry type C1 */\n        do {    /* Fill name field */\n            if (chr && (chr = lfn[nc]) != 0) nc++;  /* Get a character if exist */\n            st_word(dirb + i, chr); i += 2; /* Store it */\n        } while (i % SZDIRE);\n        nb++;\n    } while (lfn[nc]);  /* Fill next entry if any char follows */\n\n    dirb[XDIR_NumName] = nc;    /* Set name length */\n    dirb[XDIR_NumSec] = nb;     /* Set number of C0+C1s */\n}\n\n#endif  /* !_FS_READONLY */\n#endif  /* _FS_EXFAT */\n\n\n\n#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT\n/*-----------------------------------------------------------------------*/\n/* Read an object from the directory                                     */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT dir_read (\n    DIR* dp,        /* Pointer to the directory object */\n    int vol         /* Filtered by 0:file/directory or 1:volume label */\n)\n{\n    FRESULT res = FR_NO_FILE;\n    FATFS *fs = dp->obj.fs;\n    BYTE a, c;\n#if _USE_LFN != 0\n    BYTE ord = 0xFF, sum = 0xFF;\n#endif\n\n    while (dp->sect) {\n        res = move_window(fs, dp->sect);\n        if (res != FR_OK) break;\n        c = dp->dir[DIR_Name];  /* Test for the entry type */\n        if (c == 0) { res = FR_NO_FILE; break; }    /* Reached to end of the directory */\n#if _FS_EXFAT\n        if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */\n            if (_USE_LABEL && vol) {\n                if (c == 0x83) break;   /* Volume label entry? */\n            } else {\n                if (c == 0x85) {        /* Start of the file entry block? */\n                    dp->blk_ofs = dp->dptr; /* Get location of the block */\n                    res = load_xdir(dp);    /* Load the entry block */\n                    if (res == FR_OK) {\n                        dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */\n                    }\n                    break;\n                }\n            }\n        } else\n#endif\n        {   /* On the FAT12/16/32 volume */\n            dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */\n#if _USE_LFN != 0   /* LFN configuration */\n            if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) {   /* An entry without valid data */\n                ord = 0xFF;\n            } else {\n                if (a == AM_LFN) {          /* An LFN entry is found */\n                    if (c & LLEF) {         /* Is it start of an LFN sequence? */\n                        sum = dp->dir[LDIR_Chksum];\n                        c &= (BYTE)~LLEF; ord = c;\n                        dp->blk_ofs = dp->dptr;\n                    }\n                    /* Check LFN validity and capture it */\n                    ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;\n                } else {                    /* An SFN entry is found */\n                    if (ord || sum != sum_sfn(dp->dir)) {   /* Is there a valid LFN? */\n                        dp->blk_ofs = 0xFFFFFFFF;           /* It has no LFN. */\n                    }\n                    break;\n                }\n            }\n#else       /* Non LFN configuration */\n            if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) {    /* Is it a valid entry? */\n                break;\n            }\n#endif\n        }\n        res = dir_next(dp, 0);      /* Next entry */\n        if (res != FR_OK) break;\n    }\n\n    if (res != FR_OK) dp->sect = 0;     /* Terminate the read operation on error or EOT */\n    return res;\n}\n\n#endif  /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Directory handling - Find an object in the directory                  */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT dir_find (  /* FR_OK(0):succeeded, !=0:error */\n    DIR* dp         /* Pointer to the directory object with the file name */\n)\n{\n    FRESULT res;\n    FATFS *fs = dp->obj.fs;\n    BYTE c;\n#if _USE_LFN != 0\n    BYTE a, ord, sum;\n#endif\n\n    res = dir_sdi(dp, 0);           /* Rewind directory object */\n    if (res != FR_OK) return res;\n#if _FS_EXFAT\n    if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */\n        BYTE nc;\n        UINT di, ni;\n        WORD hash = xname_sum(fs->lfnbuf);      /* Hash value of the name to find */\n\n        while ((res = dir_read(dp, 0)) == FR_OK) {  /* Read an item */\n            if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue;  /* Skip the comparison if hash value mismatched */\n            for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */\n                if ((di % SZDIRE) == 0) di += 2;\n                if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break;\n            }\n            if (nc == 0 && !fs->lfnbuf[ni]) break;  /* Name matched? */\n        }\n        return res;\n    }\n#endif\n    /* On the FAT12/16/32 volume */\n#if _USE_LFN != 0\n    ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */\n#endif\n    do {\n        res = move_window(fs, dp->sect);\n        if (res != FR_OK) break;\n        c = dp->dir[DIR_Name];\n        if (c == 0) { res = FR_NO_FILE; break; }    /* Reached to end of table */\n#if _USE_LFN != 0   /* LFN configuration */\n        dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK;\n        if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) {   /* An entry without valid data */\n            ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF;   /* Reset LFN sequence */\n        } else {\n            if (a == AM_LFN) {          /* An LFN entry is found */\n                if (!(dp->fn[NSFLAG] & NS_NOLFN)) {\n                    if (c & LLEF) {     /* Is it start of LFN sequence? */\n                        sum = dp->dir[LDIR_Chksum];\n                        c &= (BYTE)~LLEF; ord = c;  /* LFN start order */\n                        dp->blk_ofs = dp->dptr; /* Start offset of LFN */\n                    }\n                    /* Check validity of the LFN entry and compare it with given name */\n                    ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;\n                }\n            } else {                    /* An SFN entry is found */\n                if (!ord && sum == sum_sfn(dp->dir)) break; /* LFN matched? */\n                if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break;    /* SFN matched? */\n                ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF;   /* Reset LFN sequence */\n            }\n        }\n#else       /* Non LFN configuration */\n        dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK;\n        if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break;  /* Is it a valid entry? */\n#endif\n        res = dir_next(dp, 0);  /* Next entry */\n    } while (res == FR_OK);\n\n    return res;\n}\n\n\n\n\n#if !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Register an object to the directory                                   */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT dir_register (  /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */\n    DIR* dp             /* Target directory with object name to be created */\n)\n{\n    FRESULT res;\n    FATFS *fs = dp->obj.fs;\n#if _USE_LFN != 0   /* LFN configuration */\n    UINT n, nlen, nent;\n    BYTE sn[12], sum;\n\n\n    if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME;  /* Check name validity */\n    for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ;  /* Get lfn length */\n\n#if _FS_EXFAT\n    if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */\n        DIR dj;\n\n        nent = (nlen + 14) / 15 + 2;    /* Number of entries to allocate (85+C0+C1s) */\n        res = dir_alloc(dp, nent);      /* Allocate entries */\n        if (res != FR_OK) return res;\n        dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1);           /* Set block position */\n\n        if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) {    /* Has the sub-directory been stretched? */\n            dp->obj.stat &= 3;\n            dp->obj.objsize += (DWORD)fs->csize * SS(fs);   /* Increase object size by cluster size */\n            res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */\n            if (res != FR_OK) return res;\n            res = load_obj_dir(&dj, &dp->obj);\n            if (res != FR_OK) return res;   /* Load the object status */\n            st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize);      /* Update the allocation status */\n            st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize);\n            fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1;\n            res = store_xdir(&dj);          /* Store the object status */\n            if (res != FR_OK) return res;\n        }\n\n        create_xdir(fs->dirbuf, fs->lfnbuf);    /* Create on-memory directory block to be written later */\n        return FR_OK;\n    }\n#endif\n    /* On the FAT12/16/32 volume */\n    mem_cpy(sn, dp->fn, 12);\n    if (sn[NSFLAG] & NS_LOSS) {         /* When LFN is out of 8.3 format, generate a numbered name */\n        dp->fn[NSFLAG] = NS_NOLFN;      /* Find only SFN */\n        for (n = 1; n < 100; n++) {\n            gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */\n            res = dir_find(dp);             /* Check if the name collides with existing SFN */\n            if (res != FR_OK) break;\n        }\n        if (n == 100) return FR_DENIED;     /* Abort if too many collisions */\n        if (res != FR_NO_FILE) return res;  /* Abort if the result is other than 'not collided' */\n        dp->fn[NSFLAG] = sn[NSFLAG];\n    }\n\n    /* Create an SFN with/without LFNs. */\n    nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1;    /* Number of entries to allocate */\n    res = dir_alloc(dp, nent);      /* Allocate entries */\n    if (res == FR_OK && --nent) {   /* Set LFN entry if needed */\n        res = dir_sdi(dp, dp->dptr - nent * SZDIRE);\n        if (res == FR_OK) {\n            sum = sum_sfn(dp->fn);  /* Checksum value of the SFN tied to the LFN */\n            do {                    /* Store LFN entries in bottom first */\n                res = move_window(fs, dp->sect);\n                if (res != FR_OK) break;\n                put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum);\n                fs->wflag = 1;\n                res = dir_next(dp, 0);  /* Next entry */\n            } while (res == FR_OK && --nent);\n        }\n    }\n\n#else   /* Non LFN configuration */\n    res = dir_alloc(dp, 1);     /* Allocate an entry for SFN */\n\n#endif\n\n    /* Set SFN entry */\n    if (res == FR_OK) {\n        res = move_window(fs, dp->sect);\n        if (res == FR_OK) {\n            mem_set(dp->dir, 0, SZDIRE);    /* Clean the entry */\n            mem_cpy(dp->dir + DIR_Name, dp->fn, 11);    /* Put SFN */\n#if _USE_LFN != 0\n            dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT);   /* Put NT flag */\n#endif\n            fs->wflag = 1;\n        }\n    }\n\n    return res;\n}\n\n#endif /* !_FS_READONLY */\n\n\n\n#if !_FS_READONLY && _FS_MINIMIZE == 0\n/*-----------------------------------------------------------------------*/\n/* Remove an object from the directory                                   */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT dir_remove (    /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */\n    DIR* dp             /* Directory object pointing the entry to be removed */\n)\n{\n    FRESULT res;\n    FATFS *fs = dp->obj.fs;\n#if _USE_LFN != 0   /* LFN configuration */\n    DWORD last = dp->dptr;\n\n    res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs);   /* Goto top of the entry block if LFN is exist */\n    if (res == FR_OK) {\n        do {\n            res = move_window(fs, dp->sect);\n            if (res != FR_OK) break;\n            /* Mark an entry 'deleted' */\n            if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */\n                dp->dir[XDIR_Type] &= 0x7F;\n            } else {                                    /* On the FAT12/16/32 volume */\n                dp->dir[DIR_Name] = DDEM;\n            }\n            fs->wflag = 1;\n            if (dp->dptr >= last) break;    /* If reached last entry then all entries of the object has been deleted. */\n            res = dir_next(dp, 0);  /* Next entry */\n        } while (res == FR_OK);\n        if (res == FR_NO_FILE) res = FR_INT_ERR;\n    }\n#else           /* Non LFN configuration */\n\n    res = move_window(fs, dp->sect);\n    if (res == FR_OK) {\n        dp->dir[DIR_Name] = DDEM;\n        fs->wflag = 1;\n    }\n#endif\n\n    return res;\n}\n\n#endif /* !_FS_READONLY && _FS_MINIMIZE == 0 */\n\n\n\n#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2\n/*-----------------------------------------------------------------------*/\n/* Get file information from directory entry                             */\n/*-----------------------------------------------------------------------*/\n\nstatic\nvoid get_fileinfo (     /* No return code */\n    DIR* dp,            /* Pointer to the directory object */\n    FILINFO* fno        /* Pointer to the file information to be filled */\n)\n{\n    UINT i, j;\n    TCHAR c;\n    DWORD tm;\n#if _USE_LFN != 0\n    WCHAR w, lfv;\n    FATFS *fs = dp->obj.fs;\n#endif\n\n\n    fno->fname[0] = 0;      /* Invaidate file info */\n    if (!dp->sect) return;  /* Exit if read pointer has reached end of directory */\n\n#if _USE_LFN != 0   /* LFN configuration */\n#if _FS_EXFAT\n    if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */\n        get_xdir_info(fs->dirbuf, fno);\n        return;\n    } else\n#endif\n    {   /* On the FAT12/16/32 volume */\n        if (dp->blk_ofs != 0xFFFFFFFF) {    /* Get LFN if available */\n            i = j = 0;\n            while ((w = fs->lfnbuf[j++]) != 0) {    /* Get an LFN character */\n#if !_LFN_UNICODE\n                w = ff_convert(w, 0);       /* Unicode -> OEM */\n                if (w == 0) { i = 0; break; }   /* No LFN if it could not be converted */\n                if (_DF1S && w >= 0x100) {  /* Put 1st byte if it is a DBC (always false at SBCS cfg) */\n                    fno->fname[i++] = (char)(w >> 8);\n                }\n#endif\n                if (i >= _MAX_LFN) { i = 0; break; }    /* No LFN if buffer overflow */\n                fno->fname[i++] = (TCHAR)w;\n            }\n            fno->fname[i] = 0;  /* Terminate the LFN */\n        }\n    }\n\n    i = j = 0;\n    lfv = fno->fname[i];    /* LFN is exist if non-zero */\n    while (i < 11) {        /* Copy name body and extension */\n        c = (TCHAR)dp->dir[i++];\n        if (c == ' ') continue;             /* Skip padding spaces */\n        if (c == RDDEM) c = (TCHAR)DDEM;    /* Restore replaced DDEM character */\n        if (i == 9) {                       /* Insert a . if extension is exist */\n            if (!lfv) fno->fname[j] = '.';\n            fno->altname[j++] = '.';\n        }\n#if _LFN_UNICODE\n        if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dp->dir[i])) {\n            c = c << 8 | dp->dir[i++];\n        }\n        c = ff_convert(c, 1);   /* OEM -> Unicode */\n        if (!c) c = '?';\n#endif\n        fno->altname[j] = c;\n        if (!lfv) {\n            if (IsUpper(c) && (dp->dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) {\n                c += 0x20;          /* To lower */\n            }\n            fno->fname[j] = c;\n        }\n        j++;\n    }\n    if (!lfv) {\n        fno->fname[j] = 0;\n        if (!dp->dir[DIR_NTres]) j = 0; /* Altname is no longer needed if neither LFN nor case info is exist. */\n    }\n    fno->altname[j] = 0;    /* Terminate the SFN */\n\n#else   /* Non-LFN configuration */\n    i = j = 0;\n    while (i < 11) {        /* Copy name body and extension */\n        c = (TCHAR)dp->dir[i++];\n        if (c == ' ') continue;             /* Skip padding spaces */\n        if (c == RDDEM) c = (TCHAR)DDEM;    /* Restore replaced DDEM character */\n        if (i == 9) fno->fname[j++] = '.';  /* Insert a . if extension is exist */\n        fno->fname[j++] = c;\n    }\n    fno->fname[j] = 0;\n#endif\n\n    fno->fattrib = dp->dir[DIR_Attr];               /* Attribute */\n    fno->fsize = ld_dword(dp->dir + DIR_FileSize);  /* Size */\n    tm = ld_dword(dp->dir + DIR_ModTime);           /* Timestamp */\n    fno->ftime = (WORD)tm; fno->fdate = (WORD)(tm >> 16);\n}\n\n#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */\n\n\n\n#if _USE_FIND && _FS_MINIMIZE <= 1\n/*-----------------------------------------------------------------------*/\n/* Pattern matching                                                      */\n/*-----------------------------------------------------------------------*/\n\nstatic\nWCHAR get_achar (       /* Get a character and advances ptr 1 or 2 */\n    const TCHAR** ptr   /* Pointer to pointer to the SBCS/DBCS/Unicode string */\n)\n{\n#if !_LFN_UNICODE\n    WCHAR chr;\n\n    chr = (BYTE)*(*ptr)++;                  /* Get a byte */\n    if (IsLower(chr)) chr -= 0x20;          /* To upper ASCII char */\n#ifdef _EXCVT\n    if (chr >= 0x80) chr = ExCvt[chr - 0x80];   /* To upper SBCS extended char */\n#else\n    if (IsDBCS1(chr) && IsDBCS2(**ptr)) {       /* Get DBC 2nd byte if needed */\n        chr = chr << 8 | (BYTE)*(*ptr)++;\n    }\n#endif\n    return chr;\n#else\n    return ff_wtoupper(*(*ptr)++);          /* Get a word and to upper */\n#endif\n}\n\n\nstatic\nint pattern_matching (  /* 0:not matched, 1:matched */\n    const TCHAR* pat,   /* Matching pattern */\n    const TCHAR* nam,   /* String to be tested */\n    int skip,           /* Number of pre-skip chars (number of ?s) */\n    int inf             /* Infinite search (* specified) */\n)\n{\n    const TCHAR *pp, *np;\n    WCHAR pc, nc;\n    int nm, nx;\n\n\n    while (skip--) {                /* Pre-skip name chars */\n        if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */\n    }\n    if (!*pat && inf) return 1;     /* (short circuit) */\n\n    do {\n        pp = pat; np = nam;         /* Top of pattern and name to match */\n        for (;;) {\n            if (*pp == '?' || *pp == '*') { /* Wildcard? */\n                nm = nx = 0;\n                do {                /* Analyze the wildcard chars */\n                    if (*pp++ == '?') nm++; else nx = 1;\n                } while (*pp == '?' || *pp == '*');\n                if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */\n                nc = *np; break;    /* Branch mismatched */\n            }\n            pc = get_achar(&pp);    /* Get a pattern char */\n            nc = get_achar(&np);    /* Get a name char */\n            if (pc != nc) break;    /* Branch mismatched? */\n            if (pc == 0) return 1;  /* Branch matched? (matched at end of both strings) */\n        }\n        get_achar(&nam);            /* nam++ */\n    } while (inf && nc);            /* Retry until end of name if infinite search is specified */\n\n    return 0;\n}\n\n#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Pick a top segment and create the object name in directory form       */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT create_name (   /* FR_OK: successful, FR_INVALID_NAME: could not create */\n    DIR* dp,            /* Pointer to the directory object */\n    const TCHAR** path  /* Pointer to pointer to the segment in the path string */\n)\n{\n#if _USE_LFN != 0   /* LFN configuration */\n    BYTE b, cf;\n    WCHAR w, *lfn;\n    UINT i, ni, si, di;\n    const TCHAR *p;\n\n    /* Create LFN in Unicode */\n    p = *path; lfn = dp->obj.fs->lfnbuf; si = di = 0;\n    for (;;) {\n        w = p[si++];                    /* Get a character */\n        if (w < ' ') break;             /* Break if end of the path name */\n        if (w == '/' || w == '\\\\') {    /* Break if a separator is found */\n            while (p[si] == '/' || p[si] == '\\\\') si++; /* Skip duplicated separator if exist */\n            break;\n        }\n        if (di >= _MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */\n#if !_LFN_UNICODE\n        w &= 0xFF;\n        if (IsDBCS1(w)) {               /* Check if it is a DBC 1st byte (always false on SBCS cfg) */\n            b = (BYTE)p[si++];          /* Get 2nd byte */\n            w = (w << 8) + b;           /* Create a DBC */\n            if (!IsDBCS2(b)) return FR_INVALID_NAME;    /* Reject invalid sequence */\n        }\n        w = ff_convert(w, 1);           /* Convert ANSI/OEM to Unicode */\n        if (!w) return FR_INVALID_NAME; /* Reject invalid code */\n#endif\n        if (w < 0x80 && chk_chr(\"\\\"*:<>\\?|\\x7F\", w)) return FR_INVALID_NAME;    /* Reject illegal characters for LFN */\n        lfn[di++] = w;                  /* Store the Unicode character */\n    }\n    *path = &p[si];                     /* Return pointer to the next segment */\n    cf = (w < ' ') ? NS_LAST : 0;       /* Set last segment flag if end of the path */\n#if _FS_RPATH != 0\n    if ((di == 1 && lfn[di - 1] == '.') ||\n        (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {    /* Is this segment a dot name? */\n        lfn[di] = 0;\n        for (i = 0; i < 11; i++)        /* Create dot name for SFN entry */\n            dp->fn[i] = (i < di) ? '.' : ' ';\n        dp->fn[i] = cf | NS_DOT;        /* This is a dot entry */\n        return FR_OK;\n    }\n#endif\n    while (di) {                        /* Snip off trailing spaces and dots if exist */\n        w = lfn[di - 1];\n        if (w != ' ' && w != '.') break;\n        di--;\n    }\n    lfn[di] = 0;                        /* LFN is created */\n    if (di == 0) return FR_INVALID_NAME;    /* Reject nul name */\n\n    /* Create SFN in directory form */\n    mem_set(dp->fn, ' ', 11);\n    for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ;  /* Strip leading spaces and dots */\n    if (si) cf |= NS_LOSS | NS_LFN;\n    while (di && lfn[di - 1] != '.') di--;  /* Find extension (di<=si: no extension) */\n\n    i = b = 0; ni = 8;\n    for (;;) {\n        w = lfn[si++];                  /* Get an LFN character */\n        if (!w) break;                  /* Break on end of the LFN */\n        if (w == ' ' || (w == '.' && si != di)) {   /* Remove spaces and dots */\n            cf |= NS_LOSS | NS_LFN; continue;\n        }\n\n        if (i >= ni || si == di) {      /* Extension or end of SFN */\n            if (ni == 11) {             /* Long extension */\n                cf |= NS_LOSS | NS_LFN; break;\n            }\n            if (si != di) cf |= NS_LOSS | NS_LFN;   /* Out of 8.3 format */\n            if (si > di) break;         /* No extension */\n            si = di; i = 8; ni = 11;    /* Enter extension section */\n            b <<= 2; continue;\n        }\n\n        if (w >= 0x80) {                /* Non ASCII character */\n#ifdef _EXCVT\n            w = ff_convert(w, 0);       /* Unicode -> OEM code */\n            if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */\n#else\n            w = ff_convert(ff_wtoupper(w), 0);  /* Upper converted Unicode -> OEM code */\n#endif\n            cf |= NS_LFN;               /* Force create LFN entry */\n        }\n\n        if (_DF1S && w >= 0x100) {      /* Is this DBC? (always false at SBCS cfg) */\n            if (i >= ni - 1) {\n                cf |= NS_LOSS | NS_LFN; i = ni; continue;\n            }\n            dp->fn[i++] = (BYTE)(w >> 8);\n        } else {                        /* SBC */\n            if (!w || chk_chr(\"+,;=[]\", w)) {   /* Replace illegal characters for SFN */\n                w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */\n            } else {\n                if (IsUpper(w)) {       /* ASCII large capital */\n                    b |= 2;\n                } else {\n                    if (IsLower(w)) {   /* ASCII small capital */\n                        b |= 1; w -= 0x20;\n                    }\n                }\n            }\n        }\n        dp->fn[i++] = (BYTE)w;\n    }\n\n    if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM;   /* If the first character collides with DDEM, replace it with RDDEM */\n\n    if (ni == 8) b <<= 2;\n    if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* Create LFN entry when there are composite capitals */\n    if (!(cf & NS_LFN)) {                       /* When LFN is in 8.3 format without extended character, NT flags are created */\n        if ((b & 0x03) == 0x01) cf |= NS_EXT;   /* NT flag (Extension has only small capital) */\n        if ((b & 0x0C) == 0x04) cf |= NS_BODY;  /* NT flag (Filename has only small capital) */\n    }\n\n    dp->fn[NSFLAG] = cf;    /* SFN is created */\n\n    return FR_OK;\n\n\n#else   /* _USE_LFN != 0 : Non-LFN configuration */\n    BYTE c, d, *sfn;\n    UINT ni, si, i;\n    const char *p;\n\n    /* Create file name in directory form */\n    p = *path; sfn = dp->fn;\n    mem_set(sfn, ' ', 11);\n    si = i = 0; ni = 8;\n#if _FS_RPATH != 0\n    if (p[si] == '.') { /* Is this a dot entry? */\n        for (;;) {\n            c = (BYTE)p[si++];\n            if (c != '.' || si >= 3) break;\n            sfn[i++] = c;\n        }\n        if (c != '/' && c != '\\\\' && c > ' ') return FR_INVALID_NAME;\n        *path = p + si;                             /* Return pointer to the next segment */\n        sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT;   /* Set last segment flag if end of the path */\n        return FR_OK;\n    }\n#endif\n    for (;;) {\n        c = (BYTE)p[si++];\n        if (c <= ' ') break;            /* Break if end of the path name */\n        if (c == '/' || c == '\\\\') {    /* Break if a separator is found */\n            while (p[si] == '/' || p[si] == '\\\\') si++; /* Skip duplicated separator if exist */\n            break;\n        }\n        if (c == '.' || i >= ni) {      /* End of body or over size? */\n            if (ni == 11 || c != '.') return FR_INVALID_NAME;   /* Over size or invalid dot */\n            i = 8; ni = 11;             /* Goto extension */\n            continue;\n        }\n        if (c >= 0x80) {                /* Extended character? */\n#ifdef _EXCVT\n            c = ExCvt[c - 0x80];        /* To upper extended characters (SBCS cfg) */\n#else\n#if !_DF1S\n            return FR_INVALID_NAME;     /* Reject extended characters (ASCII only cfg) */\n#endif\n#endif\n        }\n        if (IsDBCS1(c)) {               /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */\n            d = (BYTE)p[si++];          /* Get 2nd byte */\n            if (!IsDBCS2(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */\n            sfn[i++] = c;\n            sfn[i++] = d;\n        } else {                        /* SBC */\n            if (chk_chr(\"\\\"*+,:;<=>\\?[]|\\x7F\", c)) return FR_INVALID_NAME;  /* Reject illegal chrs for SFN */\n            if (IsLower(c)) c -= 0x20;  /* To upper */\n            sfn[i++] = c;\n        }\n    }\n    *path = p + si;                     /* Return pointer to the next segment */\n    if (i == 0) return FR_INVALID_NAME; /* Reject nul string */\n\n    if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */\n    sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0;     /* Set last segment flag if end of the path */\n\n    return FR_OK;\n#endif /* _USE_LFN != 0 */\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Follow a file path                                                    */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT follow_path (   /* FR_OK(0): successful, !=0: error code */\n    DIR* dp,            /* Directory object to return last directory and found object */\n    const TCHAR* path   /* Full-path string to find a file or directory */\n)\n{\n    FRESULT res;\n    BYTE ns;\n    _FDID *obj = &dp->obj;\n    FATFS *fs = obj->fs;\n\n\n#if _FS_RPATH != 0\n    if (*path != '/' && *path != '\\\\') {    /* Without heading separator */\n        obj->sclust = fs->cdir;             /* Start from the current directory */\n    } else\n#endif\n    {                                       /* With heading separator */\n        while (*path == '/' || *path == '\\\\') path++;   /* Strip heading separator */\n        obj->sclust = 0;                    /* Start from the root directory */\n    }\n#if _FS_EXFAT && _FS_RPATH != 0\n    if (fs->fs_type == FS_EXFAT && obj->sclust) {   /* Retrieve the sub-directory status if needed */\n        DIR dj;\n\n        obj->c_scl = fs->cdc_scl;\n        obj->c_size = fs->cdc_size;\n        obj->c_ofs = fs->cdc_ofs;\n        res = load_obj_dir(&dj, obj);\n        if (res != FR_OK) return res;\n        obj->objsize = ld_dword(fs->dirbuf + XDIR_FileSize);\n        obj->stat = fs->dirbuf[XDIR_GenFlags] & 2;\n    }\n#endif\n\n    if ((UINT)*path < ' ') {                /* Null path name is the origin directory itself */\n        dp->fn[NSFLAG] = NS_NONAME;\n        res = dir_sdi(dp, 0);\n\n    } else {                                /* Follow path */\n        for (;;) {\n            res = create_name(dp, &path);   /* Get a segment name of the path */\n            if (res != FR_OK) break;\n            res = dir_find(dp);             /* Find an object with the segment name */\n            ns = dp->fn[NSFLAG];\n            if (res != FR_OK) {             /* Failed to find the object */\n                if (res == FR_NO_FILE) {    /* Object is not found */\n                    if (_FS_RPATH && (ns & NS_DOT)) {   /* If dot entry is not exist, stay there */\n                        if (!(ns & NS_LAST)) continue;  /* Continue to follow if not last segment */\n                        dp->fn[NSFLAG] = NS_NONAME;\n                        res = FR_OK;\n                    } else {                            /* Could not find the object */\n                        if (!(ns & NS_LAST)) res = FR_NO_PATH;  /* Adjust error code if not last segment */\n                    }\n                }\n                break;\n            }\n            if (ns & NS_LAST) break;            /* Last segment matched. Function completed. */\n            /* Get into the sub-directory */\n            if (!(obj->attr & AM_DIR)) {        /* It is not a sub-directory and cannot follow */\n                res = FR_NO_PATH; break;\n            }\n#if _FS_EXFAT\n            if (fs->fs_type == FS_EXFAT) {\n                obj->c_scl = obj->sclust;       /* Save containing directory information for next dir */\n                obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat;\n                obj->c_ofs = dp->blk_ofs;\n                obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus);  /* Open next directory */\n                obj->stat = fs->dirbuf[XDIR_GenFlags] & 2;\n                obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize);\n            } else\n#endif\n            {\n                obj->sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs));    /* Open next directory */\n            }\n        }\n    }\n\n    return res;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Load a sector and check if it is an FAT boot sector                   */\n/*-----------------------------------------------------------------------*/\n\nstatic\nBYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */\n    FATFS* fs,  /* File system object */\n    DWORD sect  /* Sector# (lba) to check if it is an FAT-VBR or not */\n)\n{\n    fs->wflag = 0; fs->winsect = 0xFFFFFFFF;        /* Invaidate window */\n    if (move_window(fs, sect) != FR_OK) return 4;   /* Load boot record */\n\n    if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */\n\n    if (fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) {\n        if ((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0;   /* Check \"FAT\" string */\n        if (ld_dword(fs->win + BS_FilSysType32) == 0x33544146) return 0;            /* Check \"FAT3\" string */\n    }\n#if _FS_EXFAT\n    if (!mem_cmp(fs->win + BS_JmpBoot, \"\\xEB\\x76\\x90\" \"EXFAT   \", 11)) return 1;\n#endif\n    return 2;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Find logical drive and check if the volume is mounted                 */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT find_volume (   /* FR_OK(0): successful, !=0: any error occurred */\n    FATFS* fs,          /* Pointer to the file system object */\n    BYTE mode           /* !=0: Check write protection for write access */\n)\n{\n    BYTE fmt, *pt;\n    DSTATUS stat;\n    DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4];\n    WORD nrsv;\n    UINT i;\n\n\n    ENTER_FF(fs);                       /* Lock the volume */\n\n    mode &= (BYTE)~FA_READ;             /* Desired access mode, write access or not */\n    if (fs->fs_type) {                  /* If the volume has been mounted */\n        disk_ioctl(fs->drv, IOCTL_STATUS, &stat);\n        if (!(stat & STA_NOINIT)) {     /* and the physical drive is kept initialized */\n            if (!_FS_READONLY && mode && (stat & STA_PROTECT)) {    /* Check write protection if needed */\n                return FR_WRITE_PROTECTED;\n            }\n            return FR_OK;               /* The file system object is valid */\n        }\n    }\n\n    /* The file system object is not valid. */\n    /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */\n\n    fs->fs_type = 0;                    /* Clear the file system object */\n    disk_ioctl(fs->drv, IOCTL_INIT, &stat); /* Initialize the physical drive */\n    if (stat & STA_NOINIT) {            /* Check if the initialization succeeded */\n        return FR_NOT_READY;            /* Failed to initialize due to no medium or hard error */\n    }\n    if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */\n        return FR_WRITE_PROTECTED;\n    }\n#if _MAX_SS != _MIN_SS                      /* Get sector size (multiple sector size cfg only) */\n    if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR;\n    if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;\n#endif\n    /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */\n    bsect = 0;\n    fmt = check_fs(fs, bsect);          /* Load sector 0 and check if it is an FAT-VBR as SFD */\n    if (fmt == 2 || (fmt < 2 && LD2PT(fs) != 0)) { /* Not an FAT-VBR or forced partition number */\n        for (i = 0; i < 4; i++) {           /* Get partition offset */\n            pt = fs->win + (MBR_Table + i * SZ_PTE);\n            br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0;\n        }\n        i = LD2PT(fs);                      /* Partition number: 0:auto, 1-4:forced */\n        if (i) i--;\n        do {                                /* Find an FAT volume */\n            bsect = br[i];\n            fmt = bsect ? check_fs(fs, bsect) : 3;  /* Check the partition */\n        } while (!LD2PT(fs) && fmt >= 2 && ++i < 4);\n    }\n    if (fmt == 4) return FR_DISK_ERR;       /* An error occured in the disk I/O layer */\n    if (fmt >= 2) return FR_NO_FILESYSTEM;  /* No FAT volume is found */\n\n    /* An FAT volume is found. Following code initializes the file system object */\n\n#if _FS_EXFAT\n    if (fmt == 1) {\n        QWORD maxlba;\n\n        for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */\n        if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;\n\n        if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM;   /* Check exFAT revision (Must be 1.0) */\n\n        if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs))   /* (BPB_BytsPerSecEx must be equal to the physical sector size) */\n            return FR_NO_FILESYSTEM;\n\n        maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect;  /* Last LBA + 1 of the volume */\n        if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */\n\n        fs->fsize = ld_dword(fs->win + BPB_FatSzEx);    /* Number of sectors per FAT */\n\n        fs->n_fats = fs->win[BPB_NumFATsEx];            /* Number of FATs */\n        if (fs->n_fats != 1) return FR_NO_FILESYSTEM;   /* (Supports only 1 FAT) */\n\n        fs->csize = 1 << fs->win[BPB_SecPerClusEx];     /* Cluster size */\n        if (fs->csize == 0) return FR_NO_FILESYSTEM;    /* (Must be 1..32768) */\n\n        nclst = ld_dword(fs->win + BPB_NumClusEx);      /* Number of clusters */\n        if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */\n        fs->n_fatent = nclst + 2;\n\n        /* Boundaries and Limits */\n        fs->volbase = bsect;\n        fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);\n        fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);\n        if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM;  /* (Volume size must not be smaller than the size requiered) */\n        fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);\n\n        /* Check if bitmap location is in assumption (at the first cluster) */\n        if (move_window(fs, clust2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR;\n        for (i = 0; i < SS(fs); i += SZDIRE) {\n            if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break;   /* 81 entry with cluster #2? */\n        }\n        if (i == SS(fs)) return FR_NO_FILESYSTEM;\n#if !_FS_READONLY\n        fs->last_clst = fs->free_clst = 0xFFFFFFFF;     /* Initialize cluster allocation information */\n#endif\n        fmt = FS_EXFAT;         /* FAT sub-type */\n    } else\n#endif  /* _FS_EXFAT */\n    {\n        if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM;   /* (BPB_BytsPerSec must be equal to the physical sector size) */\n\n        fasize = ld_word(fs->win + BPB_FATSz16);            /* Number of sectors per FAT */\n        if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32);\n        fs->fsize = fasize;\n\n        fs->n_fats = fs->win[BPB_NumFATs];                  /* Number of FATs */\n        if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM;    /* (Must be 1 or 2) */\n        fasize *= fs->n_fats;                               /* Number of sectors for FAT area */\n\n        fs->csize = fs->win[BPB_SecPerClus];                /* Cluster size */\n        if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM;   /* (Must be power of 2) */\n\n        fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt);  /* Number of root directory entries */\n        if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */\n\n        tsect = ld_word(fs->win + BPB_TotSec16);            /* Number of sectors on the volume */\n        if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);\n\n        nrsv = ld_word(fs->win + BPB_RsvdSecCnt);           /* Number of reserved sectors */\n        if (nrsv == 0) return FR_NO_FILESYSTEM;             /* (Must not be 0) */\n\n        /* Determine the FAT sub type */\n        sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */\n        if (tsect < sysect) return FR_NO_FILESYSTEM;        /* (Invalid volume size) */\n        nclst = (tsect - sysect) / fs->csize;               /* Number of clusters */\n        if (nclst == 0) return FR_NO_FILESYSTEM;            /* (Invalid volume size) */\n        fmt = FS_FAT32;\n        if (nclst <= MAX_FAT16) fmt = FS_FAT16;\n        if (nclst <= MAX_FAT12) fmt = FS_FAT12;\n\n        /* Boundaries and Limits */\n        fs->n_fatent = nclst + 2;                           /* Number of FAT entries */\n        fs->volbase = bsect;                                /* Volume start sector */\n        fs->fatbase = bsect + nrsv;                         /* FAT start sector */\n        fs->database = bsect + sysect;                      /* Data start sector */\n        if (fmt == FS_FAT32) {\n            if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM;   /* (Must be FAT32 revision 0.0) */\n            if (fs->n_rootdir) return FR_NO_FILESYSTEM;     /* (BPB_RootEntCnt must be 0) */\n            fs->dirbase = ld_dword(fs->win + BPB_RootClus32);   /* Root directory start cluster */\n            szbfat = fs->n_fatent * 4;                      /* (Needed FAT size) */\n        } else {\n            if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */\n            fs->dirbase = fs->fatbase + fasize;             /* Root directory start sector */\n            szbfat = (fmt == FS_FAT16) ?                    /* (Needed FAT size) */\n                fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);\n        }\n        if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM;  /* (BPB_FATSz must not be less than the size needed) */\n\n#if !_FS_READONLY\n        /* Get FSINFO if available */\n        fs->last_clst = fs->free_clst = 0xFFFFFFFF;     /* Initialize cluster allocation information */\n        fs->fsi_flag = 0x80;\n#if (_FS_NOFSINFO & 3) != 3\n        if (fmt == FS_FAT32             /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */\n            && ld_word(fs->win + BPB_FSInfo32) == 1\n            && move_window(fs, bsect + 1) == FR_OK)\n        {\n            fs->fsi_flag = 0;\n            if (ld_word(fs->win + BS_55AA) == 0xAA55    /* Load FSINFO data if available */\n                && ld_dword(fs->win + FSI_LeadSig) == 0x41615252\n                && ld_dword(fs->win + FSI_StrucSig) == 0x61417272)\n            {\n#if (_FS_NOFSINFO & 1) == 0\n                fs->free_clst = ld_dword(fs->win + FSI_Free_Count);\n#endif\n#if (_FS_NOFSINFO & 2) == 0\n                fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free);\n#endif\n            }\n        }\n#endif  /* (_FS_NOFSINFO & 3) != 3 */\n#endif  /* !_FS_READONLY */\n    }\n\n    fs->fs_type = fmt;  /* FAT sub-type */\n    fs->id = ++Fsid;    /* File system mount ID */\n#if _USE_LFN == 1\n    fs->lfnbuf = LfnBuf;    /* Static LFN working buffer */\n#if _FS_EXFAT\n    fs->dirbuf = DirBuf;    /* Static directory block working buuffer */\n#endif\n#endif\n#if _FS_RPATH != 0\n    fs->cdir = 0;       /* Initialize current directory */\n#endif\n#if _FS_LOCK != 0       /* Clear file lock semaphores */\n    clear_lock(fs);\n#endif\n    return FR_OK;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Check if the file/directory object is valid or not                    */\n/*-----------------------------------------------------------------------*/\n\nstatic\nFRESULT validate (  /* Returns FR_OK or FR_INVALID_OBJECT */\n    _FDID* obj,     /* Pointer to the _OBJ, the 1st member in the FIL/DIR object, to check validity */\n    FATFS** fs      /* Pointer to pointer to the owner file system object to return */\n)\n{\n    FRESULT res;\n    DSTATUS stat;\n\n\n    if (!obj || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) != RES_OK || (stat & STA_NOINIT)) {\n        *fs = 0;                /* The object is invalid */\n        res = FR_INVALID_OBJECT;\n    } else {\n        *fs = obj->fs;          /* Owner file sytem object */\n        ENTER_FF(obj->fs);      /* Lock file system */\n        res = FR_OK;\n    }\n    return res;\n}\n\n\n\n\n/*---------------------------------------------------------------------------\n\n   Public Functions (FatFs API)\n\n----------------------------------------------------------------------------*/\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Mount/Unmount a Logical Drive                                         */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_mount (\n    FATFS* fs           /* Pointer to the file system object to mount */\n)\n{\n    FRESULT res;\n\n    fs->fs_type = 0;                    /* Clear new fs object */\n#if _FS_REENTRANT                       /* Create sync object for the new volume */\n    if (!ff_cre_syncobj(fs, &fs->sobj)) return FR_INT_ERR;\n#endif\n\n    res = find_volume(fs, 0);           /* Force mounted the volume */\n    LEAVE_FF(fs, res);\n}\n\n\nFRESULT f_umount (\n    FATFS* fs                   /* Pointer to the file system object to unmount */\n)\n{\n#if _FS_LOCK\n    clear_lock(fs);\n#endif\n#if _FS_REENTRANT               /* Discard sync object of the current volume */\n    if (!ff_del_syncobj(fs->sobj)) return FR_INT_ERR;\n#endif\n    fs->fs_type = 0;            /* Clear old fs object */\n\n    return FR_OK;\n}\n\n\n/*-----------------------------------------------------------------------*/\n/* Open or Create a File                                                 */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_open (\n    FATFS *fs,\n    FIL* fp,            /* Pointer to the blank file object */\n    const TCHAR* path,  /* Pointer to the file name */\n    BYTE mode           /* Access mode and file open mode flags */\n)\n{\n    FRESULT res;\n    DIR dj;\n#if !_FS_READONLY\n    DWORD dw, cl, bcs, clst, sc;\n    FSIZE_t ofs;\n#endif\n    DEF_NAMBUF\n\n\n    if (!fp) return FR_INVALID_OBJECT;\n\n    /* Get logical drive */\n    mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND;\n    res = find_volume(fs, mode);\n    if (res == FR_OK) {\n        dj.obj.fs = fs;\n        INIT_NAMBUF(fs);\n        res = follow_path(&dj, path);   /* Follow the file path */\n#if !_FS_READONLY   /* R/W configuration */\n        if (res == FR_OK) {\n            if (dj.fn[NSFLAG] & NS_NONAME) {    /* Origin directory itself? */\n                res = FR_INVALID_NAME;\n            }\n#if _FS_LOCK != 0\n            else {\n                res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);\n            }\n#endif\n        }\n        /* Create or Open a file */\n        if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {\n            if (res != FR_OK) {                 /* No file, create new */\n                if (res == FR_NO_FILE)          /* There is no file to open, create a new entry */\n#if _FS_LOCK != 0\n                    res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;\n#else\n                    res = dir_register(&dj);\n#endif\n                mode |= FA_CREATE_ALWAYS;       /* File is created */\n            }\n            else {                              /* Any object is already existing */\n                if (dj.obj.attr & (AM_RDO | AM_DIR)) {  /* Cannot overwrite it (R/O or DIR) */\n                    res = FR_DENIED;\n                } else {\n                    if (mode & FA_CREATE_NEW) res = FR_EXIST;   /* Cannot create as new file */\n                }\n            }\n            if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) {    /* Truncate it if overwrite mode */\n                dw = GET_FATTIME();\n#if _FS_EXFAT\n                if (fs->fs_type == FS_EXFAT) {\n                    /* Get current allocation info */\n                    fp->obj.fs = fs;\n                    fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus);\n                    fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize);\n                    fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2;\n                    /* Initialize directory entry block */\n                    st_dword(fs->dirbuf + XDIR_CrtTime, dw);    /* Set created time */\n                    fs->dirbuf[XDIR_CrtTime10] = 0;\n                    st_dword(fs->dirbuf + XDIR_ModTime, dw);    /* Set modified time */\n                    fs->dirbuf[XDIR_ModTime10] = 0;\n                    fs->dirbuf[XDIR_Attr] = AM_ARC;             /* Reset attribute */\n                    st_dword(fs->dirbuf + XDIR_FstClus, 0);     /* Reset file allocation info */\n                    st_qword(fs->dirbuf + XDIR_FileSize, 0);\n                    st_qword(fs->dirbuf + XDIR_ValidFileSize, 0);\n                    fs->dirbuf[XDIR_GenFlags] = 1;\n                    res = store_xdir(&dj);\n                    if (res == FR_OK && fp->obj.sclust) {       /* Remove the cluster chain if exist */\n                        res = remove_chain(&fp->obj, fp->obj.sclust, 0);\n                        fs->last_clst = fp->obj.sclust - 1;     /* Reuse the cluster hole */\n                    }\n                } else\n#endif\n                {\n                    /* Clean directory info */\n                    st_dword(dj.dir + DIR_CrtTime, dw); /* Set created time */\n                    st_dword(dj.dir + DIR_ModTime, dw); /* Set modified time */\n                    dj.dir[DIR_Attr] = AM_ARC;          /* Reset attribute */\n                    cl = ld_clust(fs, dj.dir);          /* Get cluster chain */\n                    st_clust(fs, dj.dir, 0);            /* Reset file allocation info */\n                    st_dword(dj.dir + DIR_FileSize, 0);\n                    fs->wflag = 1;\n\n                    if (cl) {                           /* Remove the cluster chain if exist */\n                        dw = fs->winsect;\n                        res = remove_chain(&dj.obj, cl, 0);\n                        if (res == FR_OK) {\n                            res = move_window(fs, dw);\n                            fs->last_clst = cl - 1;     /* Reuse the cluster hole */\n                        }\n                    }\n                }\n            }\n        }\n        else {  /* Open an existing file */\n            if (res == FR_OK) {                 /* Following succeeded */\n                if (dj.obj.attr & AM_DIR) {     /* It is a directory */\n                    res = FR_NO_FILE;\n                } else {\n                    if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* R/O violation */\n                        res = FR_DENIED;\n                    }\n                }\n            }\n        }\n        if (res == FR_OK) {\n            if (mode & FA_CREATE_ALWAYS)        /* Set file change flag if created or overwritten */\n                mode |= FA_MODIFIED;\n            fp->dir_sect = fs->winsect;         /* Pointer to the directory entry */\n            fp->dir_ptr = dj.dir;\n#if _FS_LOCK != 0\n            fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);\n            if (!fp->obj.lockid) res = FR_INT_ERR;\n#endif\n        }\n#else       /* R/O configuration */\n        if (res == FR_OK) {\n            if (dj.fn[NSFLAG] & NS_NONAME) {    /* Origin directory itself? */\n                res = FR_INVALID_NAME;\n            } else {\n                if (dj.obj.attr & AM_DIR) {     /* It is a directory */\n                    res = FR_NO_FILE;\n                }\n            }\n        }\n#endif\n\n        if (res == FR_OK) {\n#if _FS_EXFAT\n            if (fs->fs_type == FS_EXFAT) {\n                fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus);       /* Get allocation info */\n                fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize);\n                fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2;\n                fp->obj.c_scl = dj.obj.sclust;\n                fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat;\n                fp->obj.c_ofs = dj.blk_ofs;\n            } else\n#endif\n            {\n                fp->obj.sclust = ld_clust(fs, dj.dir);              /* Get allocation info */\n                fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize);\n            }\n#if _USE_FASTSEEK\n            fp->cltbl = 0;          /* Disable fast seek mode */\n#endif\n            fp->obj.fs = fs;        /* Validate the file object */\n            fp->obj.id = fs->id;\n            fp->flag = mode;        /* Set file access mode */\n            fp->err = 0;            /* Clear error flag */\n            fp->sect = 0;           /* Invalidate current data sector */\n            fp->fptr = 0;           /* Set file pointer top of the file */\n#if !_FS_READONLY\n#if !_FS_TINY\n            mem_set(fp->buf, 0, _MAX_SS);   /* Clear sector buffer */\n#endif\n            if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) {   /* Seek to end of file if FA_OPEN_APPEND is specified */\n                fp->fptr = fp->obj.objsize;         /* Offset to seek */\n                bcs = (DWORD)fs->csize * SS(fs);    /* Cluster size in byte */\n                clst = fp->obj.sclust;              /* Follow the cluster chain */\n                for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) {\n                    clst = get_fat(&fp->obj, clst);\n                    if (clst <= 1) res = FR_INT_ERR;\n                    if (clst == 0xFFFFFFFF) res = FR_DISK_ERR;\n                }\n                fp->clust = clst;\n                if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */\n                    if ((sc = clust2sect(fs, clst)) == 0) {\n                        res = FR_INT_ERR;\n                    } else {\n                        fp->sect = sc + (DWORD)(ofs / SS(fs));\n#if !_FS_TINY\n                        if (disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR;\n#endif\n                    }\n                }\n            }\n#endif\n        }\n\n        FREE_NAMBUF();\n    }\n\n    if (res != FR_OK) fp->obj.fs = 0;   /* Invalidate file object on error */\n\n    LEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Read File                                                             */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_read (\n    FIL* fp,    /* Pointer to the file object */\n    void* buff, /* Pointer to data buffer */\n    UINT btr,   /* Number of bytes to read */\n    UINT* br    /* Pointer to number of bytes read */\n)\n{\n    FRESULT res;\n    FATFS *fs;\n    DWORD clst, sect;\n    FSIZE_t remain;\n    UINT rcnt, cc, csect;\n    BYTE *rbuff = (BYTE*)buff;\n\n\n    *br = 0;    /* Clear read byte counter */\n    res = validate(&fp->obj, &fs);              /* Check validity of the file object */\n    if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);   /* Check validity */\n    if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */\n    remain = fp->obj.objsize - fp->fptr;\n    if (btr > remain) btr = (UINT)remain;       /* Truncate btr by remaining bytes */\n\n    for ( ;  btr;                               /* Repeat until all data read */\n        rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {\n        if (fp->fptr % SS(fs) == 0) {           /* On the sector boundary? */\n            csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1));    /* Sector offset in the cluster */\n            if (csect == 0) {                   /* On the cluster boundary? */\n                if (fp->fptr == 0) {            /* On the top of the file? */\n                    clst = fp->obj.sclust;      /* Follow cluster chain from the origin */\n                } else {                        /* Middle or end of the file */\n#if _USE_FASTSEEK\n                    if (fp->cltbl) {\n                        clst = clmt_clust(fp, fp->fptr);    /* Get cluster# from the CLMT */\n                    } else\n#endif\n                    {\n                        clst = get_fat(&fp->obj, fp->clust);    /* Follow cluster chain on the FAT */\n                    }\n                }\n                if (clst < 2) ABORT(fs, FR_INT_ERR);\n                if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);\n                fp->clust = clst;               /* Update current cluster */\n            }\n            sect = clust2sect(fs, fp->clust);   /* Get current sector */\n            if (!sect) ABORT(fs, FR_INT_ERR);\n            sect += csect;\n            cc = btr / SS(fs);                  /* When remaining bytes >= sector size, */\n            if (cc) {                           /* Read maximum contiguous sectors directly */\n                if (csect + cc > fs->csize) {   /* Clip at cluster boundary */\n                    cc = fs->csize - csect;\n                }\n                if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);\n#if !_FS_READONLY && _FS_MINIMIZE <= 2          /* Replace one of the read sectors with cached data if it contains a dirty sector */\n#if _FS_TINY\n                if (fs->wflag && fs->winsect - sect < cc) {\n                    mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs));\n                }\n#else\n                if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) {\n                    mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs));\n                }\n#endif\n#endif\n                rcnt = SS(fs) * cc;             /* Number of bytes transferred */\n                continue;\n            }\n#if !_FS_TINY\n            if (fp->sect != sect) {         /* Load data sector if not in cache */\n#if !_FS_READONLY\n                if (fp->flag & FA_DIRTY) {      /* Write-back dirty sector cache */\n                    if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n                    fp->flag &= (BYTE)~FA_DIRTY;\n                }\n#endif\n                if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */\n            }\n#endif\n            fp->sect = sect;\n        }\n        rcnt = SS(fs) - (UINT)fp->fptr % SS(fs);    /* Number of bytes left in the sector */\n        if (rcnt > btr) rcnt = btr;                 /* Clip it by btr if needed */\n#if _FS_TINY\n        if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */\n        mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt);  /* Extract partial sector */\n#else\n        mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt);  /* Extract partial sector */\n#endif\n    }\n\n    LEAVE_FF(fs, FR_OK);\n}\n\n\n\n\n#if !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Write File                                                            */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_write (\n    FIL* fp,            /* Pointer to the file object */\n    const void* buff,   /* Pointer to the data to be written */\n    UINT btw,           /* Number of bytes to write */\n    UINT* bw            /* Pointer to number of bytes written */\n)\n{\n    FRESULT res;\n    FATFS *fs;\n    DWORD clst, sect;\n    UINT wcnt, cc, csect;\n    const BYTE *wbuff = (const BYTE*)buff;\n\n\n    *bw = 0;    /* Clear write byte counter */\n    res = validate(&fp->obj, &fs);          /* Check validity of the file object */\n    if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);   /* Check validity */\n    if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);    /* Check access mode */\n\n    /* Check fptr wrap-around (file size cannot reach 4GiB on FATxx) */\n    if ((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {\n        btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);\n    }\n\n    for ( ;  btw;                           /* Repeat until all data written */\n        wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) {\n        if (fp->fptr % SS(fs) == 0) {       /* On the sector boundary? */\n            csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1);    /* Sector offset in the cluster */\n            if (csect == 0) {               /* On the cluster boundary? */\n                if (fp->fptr == 0) {        /* On the top of the file? */\n                    clst = fp->obj.sclust;  /* Follow from the origin */\n                    if (clst == 0) {        /* If no cluster is allocated, */\n                        clst = create_chain(&fp->obj, 0);   /* create a new cluster chain */\n                    }\n                } else {                    /* On the middle or end of the file */\n#if _USE_FASTSEEK\n                    if (fp->cltbl) {\n                        clst = clmt_clust(fp, fp->fptr);    /* Get cluster# from the CLMT */\n                    } else\n#endif\n                    {\n                        clst = create_chain(&fp->obj, fp->clust);   /* Follow or stretch cluster chain on the FAT */\n                    }\n                }\n                if (clst == 0) break;       /* Could not allocate a new cluster (disk full) */\n                if (clst == 1) ABORT(fs, FR_INT_ERR);\n                if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);\n                fp->clust = clst;           /* Update current cluster */\n                if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */\n            }\n#if _FS_TINY\n            if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR);    /* Write-back sector cache */\n#else\n            if (fp->flag & FA_DIRTY) {      /* Write-back sector cache */\n                if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n                fp->flag &= (BYTE)~FA_DIRTY;\n            }\n#endif\n            sect = clust2sect(fs, fp->clust);   /* Get current sector */\n            if (!sect) ABORT(fs, FR_INT_ERR);\n            sect += csect;\n            cc = btw / SS(fs);              /* When remaining bytes >= sector size, */\n            if (cc) {                       /* Write maximum contiguous sectors directly */\n                if (csect + cc > fs->csize) {   /* Clip at cluster boundary */\n                    cc = fs->csize - csect;\n                }\n                if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);\n#if _FS_MINIMIZE <= 2\n#if _FS_TINY\n                if (fs->winsect - sect < cc) {  /* Refill sector cache if it gets invalidated by the direct write */\n                    mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs));\n                    fs->wflag = 0;\n                }\n#else\n                if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */\n                    mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs));\n                    fp->flag &= (BYTE)~FA_DIRTY;\n                }\n#endif\n#endif\n                wcnt = SS(fs) * cc;     /* Number of bytes transferred */\n                continue;\n            }\n#if _FS_TINY\n            if (fp->fptr >= fp->obj.objsize) {  /* Avoid silly cache filling on the growing edge */\n                if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR);\n                fs->winsect = sect;\n            }\n#else\n            if (fp->sect != sect &&         /* Fill sector cache with file data */\n                fp->fptr < fp->obj.objsize &&\n                disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) {\n                    ABORT(fs, FR_DISK_ERR);\n            }\n#endif\n            fp->sect = sect;\n        }\n        wcnt = SS(fs) - (UINT)fp->fptr % SS(fs);    /* Number of bytes left in the sector */\n        if (wcnt > btw) wcnt = btw;                 /* Clip it by btw if needed */\n#if _FS_TINY\n        if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */\n        mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt);  /* Fit data to the sector */\n        fs->wflag = 1;\n#else\n        mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt);  /* Fit data to the sector */\n        fp->flag |= FA_DIRTY;\n#endif\n    }\n\n    fp->flag |= FA_MODIFIED;                /* Set file change flag */\n\n    LEAVE_FF(fs, FR_OK);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Synchronize the File                                                  */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_sync (\n    FIL* fp     /* Pointer to the file object */\n)\n{\n    FRESULT res;\n    FATFS *fs;\n    DWORD tm;\n    BYTE *dir;\n#if _FS_EXFAT\n    DEF_NAMBUF\n#endif\n\n\n    res = validate(&fp->obj, &fs);  /* Check validity of the file object */\n    if (res == FR_OK) {\n        if (fp->flag & FA_MODIFIED) {   /* Is there any change to the file? */\n#if !_FS_TINY\n            if (fp->flag & FA_DIRTY) {  /* Write-back cached data if needed */\n                if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR);\n                fp->flag &= (BYTE)~FA_DIRTY;\n            }\n#endif\n            /* Update the directory entry */\n            tm = GET_FATTIME();             /* Modified time */\n#if _FS_EXFAT\n            if (fs->fs_type == FS_EXFAT) {\n                res = fill_fat_chain(&fp->obj); /* Create FAT chain if needed */\n                if (res == FR_OK) {\n                    DIR dj;\n\n                    INIT_NAMBUF(fs);\n                    res = load_obj_dir(&dj, &fp->obj);  /* Load directory entry block */\n                    if (res == FR_OK) {\n                        fs->dirbuf[XDIR_Attr] |= AM_ARC;                /* Set archive bit */\n                        fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1;   /* Update file allocation info */\n                        st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust);\n                        st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize);\n                        st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize);\n                        st_dword(fs->dirbuf + XDIR_ModTime, tm);        /* Update modified time */\n                        fs->dirbuf[XDIR_ModTime10] = 0;\n                        st_dword(fs->dirbuf + XDIR_AccTime, 0);\n                        res = store_xdir(&dj);  /* Restore it to the directory */\n                        if (res == FR_OK) {\n                            res = sync_fs(fs);\n                            fp->flag &= (BYTE)~FA_MODIFIED;\n                        }\n                    }\n                    FREE_NAMBUF();\n                }\n            } else\n#endif\n            {\n                res = move_window(fs, fp->dir_sect);\n                if (res == FR_OK) {\n                    dir = fp->dir_ptr;\n                    dir[DIR_Attr] |= AM_ARC;                        /* Set archive bit */\n                    st_clust(fp->obj.fs, dir, fp->obj.sclust);      /* Update file allocation info  */\n                    st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize);   /* Update file size */\n                    st_dword(dir + DIR_ModTime, tm);                /* Update modified time */\n                    st_word(dir + DIR_LstAccDate, 0);\n                    fs->wflag = 1;\n                    res = sync_fs(fs);                  /* Restore it to the directory */\n                    fp->flag &= (BYTE)~FA_MODIFIED;\n                }\n            }\n        }\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n#endif /* !_FS_READONLY */\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Close File                                                            */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_close (\n    FIL* fp     /* Pointer to the file object to be closed */\n)\n{\n    FRESULT res;\n    FATFS *fs;\n\n#if !_FS_READONLY\n    res = f_sync(fp);                   /* Flush cached data */\n    if (res == FR_OK)\n#endif\n    {\n        res = validate(&fp->obj, &fs);  /* Lock volume */\n        if (res == FR_OK) {\n#if _FS_LOCK != 0\n            res = dec_lock(fp->obj.lockid); /* Decrement file open counter */\n            if (res == FR_OK)\n#endif\n            {\n                fp->obj.fs = 0;         /* Invalidate file object */\n            }\n#if _FS_REENTRANT\n            unlock_fs(fs, FR_OK);       /* Unlock volume */\n#endif\n        }\n    }\n    return res;\n}\n\n\n\n\n#if _FS_RPATH >= 1\n/*-----------------------------------------------------------------------*/\n/* Change Current Directory or Current Drive, Get Current Directory      */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_chdir (\n    FATFS *fs,\n    const TCHAR* path   /* Pointer to the directory path */\n)\n{\n    FRESULT res;\n    DIR dj;\n    DEF_NAMBUF\n\n    /* Get logical drive */\n    res = find_volume(fs, 0);\n    if (res == FR_OK) {\n        dj.obj.fs = fs;\n        INIT_NAMBUF(fs);\n        res = follow_path(&dj, path);       /* Follow the path */\n        if (res == FR_OK) {                 /* Follow completed */\n            if (dj.fn[NSFLAG] & NS_NONAME) {\n                fs->cdir = dj.obj.sclust;   /* It is the start directory itself */\n#if _FS_EXFAT\n                if (fs->fs_type == FS_EXFAT) {\n                    fs->cdc_scl = dj.obj.c_scl;\n                    fs->cdc_size = dj.obj.c_size;\n                    fs->cdc_ofs = dj.obj.c_ofs;\n                }\n#endif\n            } else {\n                if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */\n#if _FS_EXFAT\n                    if (fs->fs_type == FS_EXFAT) {\n                        fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus);     /* Sub-directory cluster */\n                        fs->cdc_scl = dj.obj.sclust;                        /* Save containing directory information */\n                        fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat;\n                        fs->cdc_ofs = dj.blk_ofs;\n                    } else\n#endif\n                    {\n                        fs->cdir = ld_clust(fs, dj.dir);                    /* Sub-directory cluster */\n                    }\n                } else {\n                    res = FR_NO_PATH;       /* Reached but a file */\n                }\n            }\n        }\n        FREE_NAMBUF();\n        if (res == FR_NO_FILE) res = FR_NO_PATH;\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n\n#if _FS_RPATH >= 2\nFRESULT f_getcwd (\n    FATFS *fs,\n    TCHAR* buff,    /* Pointer to the directory path */\n    UINT len        /* Size of path */\n)\n{\n    FRESULT res;\n    DIR dj;\n    UINT i, n;\n    DWORD ccl;\n    TCHAR *tp;\n    FILINFO fno;\n    DEF_NAMBUF\n\n\n    *buff = 0;\n    /* Get logical drive */\n    res = find_volume(fs, 0);   /* Get current volume */\n    if (res == FR_OK) {\n        dj.obj.fs = fs;\n        INIT_NAMBUF(fs);\n        i = len;            /* Bottom of buffer (directory stack base) */\n        if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) {    /* (Cannot do getcwd on exFAT and returns root path) */\n            dj.obj.sclust = fs->cdir;               /* Start to follow upper directory from current directory */\n            while ((ccl = dj.obj.sclust) != 0) {    /* Repeat while current directory is a sub-directory */\n                res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */\n                if (res != FR_OK) break;\n                res = move_window(fs, dj.sect);\n                if (res != FR_OK) break;\n                dj.obj.sclust = ld_clust(fs, dj.dir);   /* Goto parent directory */\n                res = dir_sdi(&dj, 0);\n                if (res != FR_OK) break;\n                do {                            /* Find the entry links to the child directory */\n                    res = dir_read(&dj, 0);\n                    if (res != FR_OK) break;\n                    if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */\n                    res = dir_next(&dj, 0);\n                } while (res == FR_OK);\n                if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */\n                if (res != FR_OK) break;\n                get_fileinfo(&dj, &fno);        /* Get the directory name and push it to the buffer */\n                for (n = 0; fno.fname[n]; n++) ;\n                if (i < n + 3) {\n                    res = FR_NOT_ENOUGH_CORE; break;\n                }\n                while (n) buff[--i] = fno.fname[--n];\n                buff[--i] = '/';\n            }\n        }\n        tp = buff;\n        if (res == FR_OK) {\n            if (i == len) {                 /* Root-directory */\n                *tp++ = '/';\n            } else {                        /* Sub-directroy */\n                do      /* Add stacked path str */\n                    *tp++ = buff[i++];\n                while (i < len);\n            }\n        }\n        *tp = 0;\n        FREE_NAMBUF();\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n#endif /* _FS_RPATH >= 2 */\n#endif /* _FS_RPATH >= 1 */\n\n\n\n#if _FS_MINIMIZE <= 2\n/*-----------------------------------------------------------------------*/\n/* Seek File R/W Pointer                                                 */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_lseek (\n    FIL* fp,        /* Pointer to the file object */\n    FSIZE_t ofs     /* File pointer from top of file */\n)\n{\n    FRESULT res;\n    FATFS *fs;\n    DWORD clst, bcs, nsect;\n    FSIZE_t ifptr;\n#if _USE_FASTSEEK\n    DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;\n#endif\n\n    res = validate(&fp->obj, &fs);      /* Check validity of the file object */\n    if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);   /* Check validity */\n#if _USE_FASTSEEK\n    if (fp->cltbl) {    /* Fast seek */\n        if (ofs == CREATE_LINKMAP) {    /* Create CLMT */\n            tbl = fp->cltbl;\n            tlen = *tbl++; ulen = 2;    /* Given table size and required table size */\n            cl = fp->obj.sclust;        /* Origin of the chain */\n            if (cl) {\n                do {\n                    /* Get a fragment */\n                    tcl = cl; ncl = 0; ulen += 2;   /* Top, length and used items */\n                    do {\n                        pcl = cl; ncl++;\n                        cl = get_fat(&fp->obj, cl);\n                        if (cl <= 1) ABORT(fs, FR_INT_ERR);\n                        if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);\n                    } while (cl == pcl + 1);\n                    if (ulen <= tlen) {     /* Store the length and top of the fragment */\n                        *tbl++ = ncl; *tbl++ = tcl;\n                    }\n                } while (cl < fs->n_fatent);    /* Repeat until end of chain */\n            }\n            *fp->cltbl = ulen;  /* Number of items used */\n            if (ulen <= tlen) {\n                *tbl = 0;       /* Terminate table */\n            } else {\n                res = FR_NOT_ENOUGH_CORE;   /* Given table size is smaller than required */\n            }\n        } else {                        /* Fast seek */\n            if (ofs > fp->obj.objsize) ofs = fp->obj.objsize;   /* Clip offset at the file size */\n            fp->fptr = ofs;             /* Set file pointer */\n            if (ofs) {\n                fp->clust = clmt_clust(fp, ofs - 1);\n                dsc = clust2sect(fs, fp->clust);\n                if (!dsc) ABORT(fs, FR_INT_ERR);\n                dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1);\n                if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */\n#if !_FS_TINY\n#if !_FS_READONLY\n                    if (fp->flag & FA_DIRTY) {      /* Write-back dirty sector cache */\n                        if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n                        fp->flag &= (BYTE)~FA_DIRTY;\n                    }\n#endif\n                    if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);  /* Load current sector */\n#endif\n                    fp->sect = dsc;\n                }\n            }\n        }\n    } else\n#endif\n\n    /* Normal Seek */\n    {\n#if _FS_EXFAT\n        if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF;    /* Clip at 4GiB-1 if at FATxx */\n#endif\n        if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) {    /* In read-only mode, clip offset with the file size */\n            ofs = fp->obj.objsize;\n        }\n        ifptr = fp->fptr;\n        fp->fptr = nsect = 0;\n        if (ofs) {\n            bcs = (DWORD)fs->csize * SS(fs);    /* Cluster size (byte) */\n            if (ifptr > 0 &&\n                (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */\n                fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1);   /* start from the current cluster */\n                ofs -= fp->fptr;\n                clst = fp->clust;\n            } else {                                    /* When seek to back cluster, */\n                clst = fp->obj.sclust;                  /* start from the first cluster */\n#if !_FS_READONLY\n                if (clst == 0) {                        /* If no cluster chain, create a new chain */\n                    clst = create_chain(&fp->obj, 0);\n                    if (clst == 1) ABORT(fs, FR_INT_ERR);\n                    if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);\n                    fp->obj.sclust = clst;\n                }\n#endif\n                fp->clust = clst;\n            }\n            if (clst != 0) {\n                while (ofs > bcs) {                     /* Cluster following loop */\n                    ofs -= bcs; fp->fptr += bcs;\n#if !_FS_READONLY\n                    if (fp->flag & FA_WRITE) {          /* Check if in write mode or not */\n                        if (_FS_EXFAT && fp->fptr > fp->obj.objsize) {  /* No FAT chain object needs correct objsize to generate FAT value */\n                            fp->obj.objsize = fp->fptr;\n                            fp->flag |= FA_MODIFIED;\n                        }\n                        clst = create_chain(&fp->obj, clst);    /* Follow chain with forceed stretch */\n                        if (clst == 0) {                /* Clip file size in case of disk full */\n                            ofs = 0; break;\n                        }\n                    } else\n#endif\n                    {\n                        clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */\n                    }\n                    if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);\n                    if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR);\n                    fp->clust = clst;\n                }\n                fp->fptr += ofs;\n                if (ofs % SS(fs)) {\n                    nsect = clust2sect(fs, clst);   /* Current sector */\n                    if (!nsect) ABORT(fs, FR_INT_ERR);\n                    nsect += (DWORD)(ofs / SS(fs));\n                }\n            }\n        }\n        if (!_FS_READONLY && fp->fptr > fp->obj.objsize) {      /* Set file change flag if the file size is extended */\n            fp->obj.objsize = fp->fptr;\n            fp->flag |= FA_MODIFIED;\n        }\n        if (fp->fptr % SS(fs) && nsect != fp->sect) {   /* Fill sector cache if needed */\n#if !_FS_TINY\n#if !_FS_READONLY\n            if (fp->flag & FA_DIRTY) {          /* Write-back dirty sector cache */\n                if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n                fp->flag &= (BYTE)~FA_DIRTY;\n            }\n#endif\n            if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);    /* Fill sector cache */\n#endif\n            fp->sect = nsect;\n        }\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n\n\n#if _FS_MINIMIZE <= 1\n/*-----------------------------------------------------------------------*/\n/* Create a Directory Object                                             */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_opendir (\n    FATFS *fs,\n    DIR* dp,            /* Pointer to directory object to create */\n    const TCHAR* path   /* Pointer to the directory path */\n)\n{\n    FRESULT res;\n    _FDID *obj;\n    DEF_NAMBUF\n\n\n    if (!dp) return FR_INVALID_OBJECT;\n\n    /* Get logical drive */\n    obj = &dp->obj;\n    res = find_volume(fs, 0);\n    if (res == FR_OK) {\n        obj->fs = fs;\n        INIT_NAMBUF(fs);\n        res = follow_path(dp, path);            /* Follow the path to the directory */\n        if (res == FR_OK) {                     /* Follow completed */\n            if (!(dp->fn[NSFLAG] & NS_NONAME)) {    /* It is not the origin directory itself */\n                if (obj->attr & AM_DIR) {       /* This object is a sub-directory */\n#if _FS_EXFAT\n                    if (fs->fs_type == FS_EXFAT) {\n                        obj->c_scl = obj->sclust;   /* Save containing directory inforamation */\n                        obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat;\n                        obj->c_ofs = dp->blk_ofs;\n                        obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus);  /* Get object location and status */\n                        obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize);\n                        obj->stat = fs->dirbuf[XDIR_GenFlags] & 2;\n                    } else\n#endif\n                    {\n                        obj->sclust = ld_clust(fs, dp->dir);    /* Get object location */\n                    }\n                } else {                        /* This object is a file */\n                    res = FR_NO_PATH;\n                }\n            }\n            if (res == FR_OK) {\n                obj->id = fs->id;\n                res = dir_sdi(dp, 0);           /* Rewind directory */\n#if _FS_LOCK != 0\n                if (res == FR_OK) {\n                    if (obj->sclust) {\n                        obj->lockid = inc_lock(dp, 0);  /* Lock the sub directory */\n                        if (!obj->lockid) res = FR_TOO_MANY_OPEN_FILES;\n                    } else {\n                        obj->lockid = 0;    /* Root directory need not to be locked */\n                    }\n                }\n#endif\n            }\n        }\n        FREE_NAMBUF();\n        if (res == FR_NO_FILE) res = FR_NO_PATH;\n    }\n    if (res != FR_OK) obj->fs = 0;      /* Invalidate the directory object if function faild */\n\n    LEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Close Directory                                                       */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_closedir (\n    DIR *dp     /* Pointer to the directory object to be closed */\n)\n{\n    FRESULT res;\n    FATFS *fs;\n\n\n    res = validate(&dp->obj, &fs);          /* Check validity of the file object */\n    if (res == FR_OK) {\n#if _FS_LOCK != 0\n        if (dp->obj.lockid) {               /* Decrement sub-directory open counter */\n            res = dec_lock(dp->obj.lockid);\n        }\n        if (res == FR_OK)\n#endif\n        {\n            dp->obj.fs = 0;         /* Invalidate directory object */\n        }\n#if _FS_REENTRANT\n        unlock_fs(fs, FR_OK);       /* Unlock volume */\n#endif\n    }\n    return res;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Read Directory Entries in Sequence                                    */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_readdir (\n    DIR* dp,            /* Pointer to the open directory object */\n    FILINFO* fno        /* Pointer to file information to return */\n)\n{\n    FRESULT res;\n    FATFS *fs;\n    DEF_NAMBUF\n\n\n    res = validate(&dp->obj, &fs);  /* Check validity of the directory object */\n    if (res == FR_OK) {\n        if (!fno) {\n            res = dir_sdi(dp, 0);           /* Rewind the directory object */\n        } else {\n            INIT_NAMBUF(fs);\n            res = dir_read(dp, 0);          /* Read an item */\n            if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */\n            if (res == FR_OK) {             /* A valid entry is found */\n                get_fileinfo(dp, fno);      /* Get the object information */\n                res = dir_next(dp, 0);      /* Increment index for next */\n                if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */\n            }\n            FREE_NAMBUF();\n        }\n    }\n    LEAVE_FF(fs, res);\n}\n\n\n\n#if _USE_FIND\n/*-----------------------------------------------------------------------*/\n/* Find Next File                                                        */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_findnext (\n    DIR* dp,        /* Pointer to the open directory object */\n    FILINFO* fno    /* Pointer to the file information structure */\n)\n{\n    FRESULT res;\n\n\n    for (;;) {\n        res = f_readdir(dp, fno);       /* Get a directory item */\n        if (res != FR_OK || !fno || !fno->fname[0]) break;  /* Terminate if any error or end of directory */\n        if (pattern_matching(dp->pat, fno->fname, 0, 0)) break;     /* Test for the file name */\n#if _USE_LFN != 0 && _USE_FIND == 2\n        if (pattern_matching(dp->pat, fno->altname, 0, 0)) break;   /* Test for alternative name if exist */\n#endif\n    }\n    return res;\n}\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Find First File                                                       */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_findfirst (\n    DIR* dp,                /* Pointer to the blank directory object */\n    FILINFO* fno,           /* Pointer to the file information structure */\n    const TCHAR* path,      /* Pointer to the directory to open */\n    const TCHAR* pattern    /* Pointer to the matching pattern */\n)\n{\n    FRESULT res;\n\n\n    dp->pat = pattern;      /* Save pointer to pattern string */\n    res = f_opendir(dp, path);      /* Open the target directory */\n    if (res == FR_OK) {\n        res = f_findnext(dp, fno);  /* Find the first item */\n    }\n    return res;\n}\n\n#endif  /* _USE_FIND */\n\n\n\n#if _FS_MINIMIZE == 0\n/*-----------------------------------------------------------------------*/\n/* Get File Status                                                       */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_stat (\n    FATFS *fs,\n    const TCHAR* path,  /* Pointer to the file path */\n    FILINFO* fno        /* Pointer to file information to return */\n)\n{\n    FRESULT res;\n    DIR dj;\n    DEF_NAMBUF\n\n\n    /* Get logical drive */\n    res = find_volume(fs, 0);\n    dj.obj.fs = fs;\n    if (res == FR_OK) {\n        INIT_NAMBUF(dj.obj.fs);\n        res = follow_path(&dj, path);   /* Follow the file path */\n        if (res == FR_OK) {             /* Follow completed */\n            if (dj.fn[NSFLAG] & NS_NONAME) {    /* It is origin directory */\n                res = FR_INVALID_NAME;\n            } else {                            /* Found an object */\n                if (fno) get_fileinfo(&dj, fno);\n            }\n        }\n        FREE_NAMBUF();\n    }\n\n    LEAVE_FF(dj.obj.fs, res);\n}\n\n\n\n#if !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Get Number of Free Clusters                                           */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_getfree (\n    FATFS *fs,\n    DWORD* nclst        /* Pointer to a variable to return number of free clusters */\n)\n{\n    FRESULT res;\n    DWORD nfree, clst, sect, stat;\n    UINT i;\n    BYTE *p;\n    _FDID obj;\n\n\n    /* Get logical drive */\n    res = find_volume(fs, 0);\n    if (res == FR_OK) {\n        /* If free_clst is valid, return it without full cluster scan */\n        if (fs->free_clst <= fs->n_fatent - 2) {\n            *nclst = fs->free_clst;\n        } else {\n            /* Get number of free clusters */\n            nfree = 0;\n            if (fs->fs_type == FS_FAT12) {  /* FAT12: Sector unalighed FAT entries */\n                clst = 2; obj.fs = fs;\n                do {\n                    stat = get_fat(&obj, clst);\n                    if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }\n                    if (stat == 1) { res = FR_INT_ERR; break; }\n                    if (stat == 0) nfree++;\n                } while (++clst < fs->n_fatent);\n            } else {\n#if _FS_EXFAT\n                if (fs->fs_type == FS_EXFAT) {  /* exFAT: Scan bitmap table */\n                    BYTE bm;\n                    UINT b;\n\n                    clst = fs->n_fatent - 2;\n                    sect = fs->database;\n                    i = 0;\n                    do {\n                        if (i == 0 && (res = move_window(fs, sect++)) != FR_OK) break;\n                        for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) {\n                            if (!(bm & 1)) nfree++;\n                            bm >>= 1;\n                        }\n                        i = (i + 1) % SS(fs);\n                    } while (clst);\n                } else\n#endif\n                {   /* FAT16/32: Sector alighed FAT entries */\n                    clst = fs->n_fatent; sect = fs->fatbase;\n                    i = 0; p = 0;\n                    do {\n                        if (i == 0) {\n                            res = move_window(fs, sect++);\n                            if (res != FR_OK) break;\n                            p = fs->win;\n                            i = SS(fs);\n                        }\n                        if (fs->fs_type == FS_FAT16) {\n                            if (ld_word(p) == 0) nfree++;\n                            p += 2; i -= 2;\n                        } else {\n                            if ((ld_dword(p) & 0x0FFFFFFF) == 0) nfree++;\n                            p += 4; i -= 4;\n                        }\n                    } while (--clst);\n                }\n            }\n            *nclst = nfree;         /* Return the free clusters */\n            fs->free_clst = nfree;  /* Now free_clst is valid */\n            fs->fsi_flag |= 1;      /* FSInfo is to be updated */\n        }\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Truncate File                                                         */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_truncate (\n    FIL* fp     /* Pointer to the file object */\n)\n{\n    FRESULT res;\n    FATFS *fs;\n    DWORD ncl;\n\n\n    res = validate(&fp->obj, &fs);  /* Check validity of the file object */\n    if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);\n    if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);    /* Check access mode */\n\n    if (fp->obj.objsize > fp->fptr) {\n        if (fp->fptr == 0) {    /* When set file size to zero, remove entire cluster chain */\n            res = remove_chain(&fp->obj, fp->obj.sclust, 0);\n            fp->obj.sclust = 0;\n        } else {                /* When truncate a part of the file, remove remaining clusters */\n            ncl = get_fat(&fp->obj, fp->clust);\n            res = FR_OK;\n            if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;\n            if (ncl == 1) res = FR_INT_ERR;\n            if (res == FR_OK && ncl < fs->n_fatent) {\n                res = remove_chain(&fp->obj, ncl, fp->clust);\n            }\n        }\n        fp->obj.objsize = fp->fptr; /* Set file size to current R/W point */\n        fp->flag |= FA_MODIFIED;\n#if !_FS_TINY\n        if (res == FR_OK && (fp->flag & FA_DIRTY)) {\n            if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) {\n                res = FR_DISK_ERR;\n            } else {\n                fp->flag &= (BYTE)~FA_DIRTY;\n            }\n        }\n#endif\n        if (res != FR_OK) ABORT(fs, res);\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Delete a File/Directory                                               */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_unlink (\n    FATFS *fs,\n    const TCHAR* path       /* Pointer to the file or directory path */\n)\n{\n    FRESULT res;\n    DIR dj, sdj;\n    DWORD dclst = 0;\n#if _FS_EXFAT\n    _FDID obj;\n#endif\n    DEF_NAMBUF\n\n\n    /* Get logical drive */\n    res = find_volume(fs, FA_WRITE);\n    dj.obj.fs = fs;\n    if (res == FR_OK) {\n        INIT_NAMBUF(fs);\n        res = follow_path(&dj, path);       /* Follow the file path */\n        if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) {\n            res = FR_INVALID_NAME;          /* Cannot remove dot entry */\n        }\n#if _FS_LOCK != 0\n        if (res == FR_OK) res = chk_lock(&dj, 2);   /* Check if it is an open object */\n#endif\n        if (res == FR_OK) {                 /* The object is accessible */\n            if (dj.fn[NSFLAG] & NS_NONAME) {\n                res = FR_INVALID_NAME;      /* Cannot remove the origin directory */\n            } else {\n                if (dj.obj.attr & AM_RDO) {\n                    res = FR_DENIED;        /* Cannot remove R/O object */\n                }\n            }\n            if (res == FR_OK) {\n#if _FS_EXFAT\n                obj.fs = fs;\n                if (fs->fs_type == FS_EXFAT) {\n                    obj.sclust = dclst = ld_dword(fs->dirbuf + XDIR_FstClus);\n                    obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize);\n                    obj.stat = fs->dirbuf[XDIR_GenFlags] & 2;\n                } else\n#endif\n                {\n                    dclst = ld_clust(fs, dj.dir);\n                }\n                if (dj.obj.attr & AM_DIR) {         /* Is it a sub-directory ? */\n#if _FS_RPATH != 0\n                    if (dclst == fs->cdir) {                /* Is it the current directory? */\n                        res = FR_DENIED;\n                    } else\n#endif\n                    {\n                        sdj.obj.fs = fs;                        /* Open the sub-directory */\n                        sdj.obj.sclust = dclst;\n#if _FS_EXFAT\n                        if (fs->fs_type == FS_EXFAT) {\n                            sdj.obj.objsize = obj.objsize;\n                            sdj.obj.stat = obj.stat;\n                        }\n#endif\n                        res = dir_sdi(&sdj, 0);\n                        if (res == FR_OK) {\n                            res = dir_read(&sdj, 0);            /* Read an item */\n                            if (res == FR_OK) res = FR_DENIED;  /* Not empty? */\n                            if (res == FR_NO_FILE) res = FR_OK; /* Empty? */\n                        }\n                    }\n                }\n            }\n            if (res == FR_OK) {\n                res = dir_remove(&dj);          /* Remove the directory entry */\n                if (res == FR_OK && dclst) {    /* Remove the cluster chain if exist */\n#if _FS_EXFAT\n                    res = remove_chain(&obj, dclst, 0);\n#else\n                    res = remove_chain(&dj.obj, dclst, 0);\n#endif\n                }\n                if (res == FR_OK) res = sync_fs(fs);\n            }\n        }\n        FREE_NAMBUF();\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Create a Directory                                                    */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_mkdir (\n    FATFS *fs,\n    const TCHAR* path       /* Pointer to the directory path */\n)\n{\n    FRESULT res;\n    DIR dj;\n    BYTE *dir;\n    UINT n;\n    DWORD dsc, dcl, pcl, tm;\n    DEF_NAMBUF\n\n\n    /* Get logical drive */\n    res = find_volume(fs, FA_WRITE);\n    dj.obj.fs = fs;\n    if (res == FR_OK) {\n        INIT_NAMBUF(fs);\n        res = follow_path(&dj, path);           /* Follow the file path */\n        if (res == FR_OK) res = FR_EXIST;       /* Any object with same name is already existing */\n        if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) {\n            res = FR_INVALID_NAME;\n        }\n        if (res == FR_NO_FILE) {                /* Can create a new directory */\n            dcl = create_chain(&dj.obj, 0);     /* Allocate a cluster for the new directory table */\n            dj.obj.objsize = (DWORD)fs->csize * SS(fs);\n            res = FR_OK;\n            if (dcl == 0) res = FR_DENIED;      /* No space to allocate a new cluster */\n            if (dcl == 1) res = FR_INT_ERR;\n            if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;\n            if (res == FR_OK) res = sync_window(fs);    /* Flush FAT */\n            tm = GET_FATTIME();\n            if (res == FR_OK) {                 /* Initialize the new directory table */\n                dsc = clust2sect(fs, dcl);\n                dir = fs->win;\n                mem_set(dir, 0, SS(fs));\n                if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) {\n                    mem_set(dir + DIR_Name, ' ', 11);   /* Create \".\" entry */\n                    dir[DIR_Name] = '.';\n                    dir[DIR_Attr] = AM_DIR;\n                    st_dword(dir + DIR_ModTime, tm);\n                    st_clust(fs, dir, dcl);\n                    mem_cpy(dir + SZDIRE, dir, SZDIRE);     /* Create \"..\" entry */\n                    dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;\n                    if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) pcl = 0;\n                    st_clust(fs, dir + SZDIRE, pcl);\n                }\n                for (n = fs->csize; n; n--) {   /* Write dot entries and clear following sectors */\n                    fs->winsect = dsc++;\n                    fs->wflag = 1;\n                    res = sync_window(fs);\n                    if (res != FR_OK) break;\n                    mem_set(dir, 0, SS(fs));\n                }\n            }\n            if (res == FR_OK) res = dir_register(&dj);  /* Register the object to the directoy */\n            if (res == FR_OK) {\n#if _FS_EXFAT\n                if (fs->fs_type == FS_EXFAT) {  /* Initialize directory entry block */\n                    st_dword(fs->dirbuf + XDIR_ModTime, tm);    /* Created time */\n                    st_dword(fs->dirbuf + XDIR_FstClus, dcl);   /* Table start cluster */\n                    st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize);    /* File size needs to be valid */\n                    st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize);\n                    fs->dirbuf[XDIR_GenFlags] = 3;              /* Initialize the object flag (contiguous) */\n                    fs->dirbuf[XDIR_Attr] = AM_DIR;             /* Attribute */\n                    res = store_xdir(&dj);\n                } else\n#endif\n                {\n                    dir = dj.dir;\n                    st_dword(dir + DIR_ModTime, tm);    /* Created time */\n                    st_clust(fs, dir, dcl);             /* Table start cluster */\n                    dir[DIR_Attr] = AM_DIR;             /* Attribute */\n                    fs->wflag = 1;\n                }\n                if (res == FR_OK) res = sync_fs(fs);\n            } else {\n                remove_chain(&dj.obj, dcl, 0);      /* Could not register, remove cluster chain */\n            }\n        }\n        FREE_NAMBUF();\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Rename a File/Directory                                               */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_rename (\n    FATFS *fs,\n    const TCHAR* path_old,  /* Pointer to the object name to be renamed */\n    const TCHAR* path_new   /* Pointer to the new name */\n)\n{\n    FRESULT res;\n    DIR djo, djn;\n    BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir;\n    DWORD dw;\n    DEF_NAMBUF\n\n\n    res = find_volume(fs, FA_WRITE);\n    if (res == FR_OK) {\n        djo.obj.fs = fs;\n        INIT_NAMBUF(fs);\n        res = follow_path(&djo, path_old);      /* Check old object */\n        if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */\n#if _FS_LOCK != 0\n        if (res == FR_OK) res = chk_lock(&djo, 2);\n#endif\n        if (res == FR_OK) {                     /* Object to be renamed is found */\n#if _FS_EXFAT\n            if (fs->fs_type == FS_EXFAT) {  /* At exFAT */\n                BYTE nf, nn;\n                WORD nh;\n\n                mem_cpy(buf, fs->dirbuf, SZDIRE * 2);   /* Save 85+C0 entry of old object */\n                mem_cpy(&djn, &djo, sizeof djo);\n                res = follow_path(&djn, path_new);      /* Make sure if new object name is not in use */\n                if (res == FR_OK) {                     /* Is new name already in use by any other object? */\n                    res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;\n                }\n                if (res == FR_NO_FILE) {                /* It is a valid path and no name collision */\n                    res = dir_register(&djn);           /* Register the new entry */\n                    if (res == FR_OK) {\n                        nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName];\n                        nh = ld_word(fs->dirbuf + XDIR_NameHash);\n                        mem_cpy(fs->dirbuf, buf, SZDIRE * 2);\n                        fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn;\n                        st_word(fs->dirbuf + XDIR_NameHash, nh);\n/* Start of critical section where any interruption can cause a cross-link */\n                        res = store_xdir(&djn);\n                    }\n                }\n            } else\n#endif\n            {   /* At FAT12/FAT16/FAT32 */\n                mem_cpy(buf, djo.dir + DIR_Attr, 21);   /* Save information about the object except name */\n                mem_cpy(&djn, &djo, sizeof (DIR));      /* Duplicate the directory object */\n                res = follow_path(&djn, path_new);      /* Make sure if new object name is not in use */\n                if (res == FR_OK) {                     /* Is new name already in use by any other object? */\n                    res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;\n                }\n                if (res == FR_NO_FILE) {                /* It is a valid path and no name collision */\n                    res = dir_register(&djn);           /* Register the new entry */\n                    if (res == FR_OK) {\n                        dir = djn.dir;                  /* Copy information about object except name */\n                        mem_cpy(dir + 13, buf + 2, 19);\n                        dir[DIR_Attr] = buf[0] | AM_ARC;\n                        fs->wflag = 1;\n                        if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */\n                            dw = clust2sect(fs, ld_clust(fs, dir));\n                            if (!dw) {\n                                res = FR_INT_ERR;\n                            } else {\n/* Start of critical section where any interruption can cause a cross-link */\n                                res = move_window(fs, dw);\n                                dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */\n                                if (res == FR_OK && dir[1] == '.') {\n                                    st_clust(fs, dir, djn.obj.sclust);\n                                    fs->wflag = 1;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            if (res == FR_OK) {\n                res = dir_remove(&djo);     /* Remove old entry */\n                if (res == FR_OK) {\n                    res = sync_fs(fs);\n                }\n            }\n/* End of critical section */\n        }\n        FREE_NAMBUF();\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n#endif /* !_FS_READONLY */\n#endif /* _FS_MINIMIZE == 0 */\n#endif /* _FS_MINIMIZE <= 1 */\n#endif /* _FS_MINIMIZE <= 2 */\n\n\n\n#if _USE_CHMOD && !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Change Attribute                                                      */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_chmod (\n    FATFS *fs,\n    const TCHAR* path,  /* Pointer to the file path */\n    BYTE attr,          /* Attribute bits */\n    BYTE mask           /* Attribute mask to change */\n)\n{\n    FRESULT res;\n    DIR dj;\n    DEF_NAMBUF\n\n\n    res = find_volume(fs, FA_WRITE);    /* Get logical drive */\n    dj.obj.fs = fs;\n    if (res == FR_OK) {\n        INIT_NAMBUF(fs);\n        res = follow_path(&dj, path);   /* Follow the file path */\n        if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME;  /* Check object validity */\n        if (res == FR_OK) {\n            mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;    /* Valid attribute mask */\n#if _FS_EXFAT\n            if (fs->fs_type == FS_EXFAT) {\n                fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask);  /* Apply attribute change */\n                res = store_xdir(&dj);\n            } else\n#endif\n            {\n                dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask);    /* Apply attribute change */\n                fs->wflag = 1;\n            }\n            if (res == FR_OK) res = sync_fs(fs);\n        }\n        FREE_NAMBUF();\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Change Timestamp                                                      */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_utime (\n    FATFS *fs,\n    const TCHAR* path,  /* Pointer to the file/directory name */\n    const FILINFO* fno  /* Pointer to the time stamp to be set */\n)\n{\n    FRESULT res;\n    DIR dj;\n    DEF_NAMBUF\n\n\n    res = find_volume(fs, FA_WRITE);    /* Get logical drive */\n    dj.obj.fs = fs;\n    if (res == FR_OK) {\n        INIT_NAMBUF(fs);\n        res = follow_path(&dj, path);   /* Follow the file path */\n        if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME;  /* Check object validity */\n        if (res == FR_OK) {\n#if _FS_EXFAT\n            if (fs->fs_type == FS_EXFAT) {\n                st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime);\n                res = store_xdir(&dj);\n            } else\n#endif\n            {\n                st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime);\n                fs->wflag = 1;\n            }\n            if (res == FR_OK) res = sync_fs(fs);\n        }\n        FREE_NAMBUF();\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n#endif  /* _USE_CHMOD && !_FS_READONLY */\n\n\n\n#if _USE_LABEL\n/*-----------------------------------------------------------------------*/\n/* Get Volume Label                                                      */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_getlabel (\n    FATFS *fs,\n    TCHAR* label,       /* Pointer to a buffer to return the volume label */\n    DWORD* vsn          /* Pointer to a variable to return the volume serial number */\n)\n{\n    FRESULT res;\n    DIR dj;\n    UINT si, di;\n#if _LFN_UNICODE || _FS_EXFAT\n    WCHAR w;\n#endif\n\n    /* Get logical drive */\n    res = find_volume(fs, 0);\n\n    /* Get volume label */\n    if (res == FR_OK && label) {\n        dj.obj.fs = fs; dj.obj.sclust = 0;  /* Open root directory */\n        res = dir_sdi(&dj, 0);\n        if (res == FR_OK) {\n            res = dir_read(&dj, 1);         /* Find a volume label entry */\n            if (res == FR_OK) {\n#if _FS_EXFAT\n                if (fs->fs_type == FS_EXFAT) {\n                    for (si = di = 0; si < dj.dir[XDIR_NumLabel]; si++) {   /* Extract volume label from 83 entry */\n                        w = ld_word(dj.dir + XDIR_Label + si * 2);\n#if _LFN_UNICODE\n                        label[di++] = w;\n#else\n                        w = ff_convert(w, 0);   /* Unicode -> OEM */\n                        if (w == 0) w = '?';    /* Replace wrong character */\n                        if (_DF1S && w >= 0x100) label[di++] = (char)(w >> 8);\n                        label[di++] = (char)w;\n#endif\n                    }\n                    label[di] = 0;\n                } else\n#endif\n                {\n                    si = di = 0;        /* Extract volume label from AM_VOL entry with code comversion */\n                    do {\n#if _LFN_UNICODE\n                        w = (si < 11) ? dj.dir[si++] : ' ';\n                        if (IsDBCS1(w) && si < 11 && IsDBCS2(dj.dir[si])) {\n                            w = w << 8 | dj.dir[si++];\n                        }\n                        label[di++] = ff_convert(w, 1); /* OEM -> Unicode */\n#else\n                        label[di++] = dj.dir[si++];\n#endif\n                    } while (di < 11);\n                    do {                /* Truncate trailing spaces */\n                        label[di] = 0;\n                        if (di == 0) break;\n                    } while (label[--di] == ' ');\n                }\n            }\n        }\n        if (res == FR_NO_FILE) {    /* No label entry and return nul string */\n            label[0] = 0;\n            res = FR_OK;\n        }\n    }\n\n    /* Get volume serial number */\n    if (res == FR_OK && vsn) {\n        res = move_window(fs, fs->volbase);\n        if (res == FR_OK) {\n            switch (fs->fs_type) {\n            case FS_EXFAT: di = BPB_VolIDEx; break;\n            case FS_FAT32: di = BS_VolID32; break;\n            default:       di = BS_VolID;\n            }\n            *vsn = ld_dword(fs->win + di);\n        }\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n\n\n#if !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Set Volume Label                                                      */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_setlabel (\n    FATFS *fs,\n    const TCHAR* label  /* Pointer to the volume label to set */\n)\n{\n    FRESULT res;\n    DIR dj;\n    BYTE dirvn[22];\n    UINT i, j, slen;\n    WCHAR w;\n    static const char badchr[] = \"\\\"*+,.:;<=>\\?[]|\\x7F\";\n\n\n    /* Get logical drive */\n    res = find_volume(fs, FA_WRITE);\n    if (res != FR_OK) LEAVE_FF(fs, res);\n    dj.obj.fs = fs;\n\n    /* Get length of given volume label */\n    for (slen = 0; (UINT)label[slen] >= ' '; slen++) { } /* Get name length */\n\n#if _FS_EXFAT\n    if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */\n        for (i = j = 0; i < slen; ) {   /* Create volume label in directory form */\n            w = label[i++];\n#if !_LFN_UNICODE\n            if (IsDBCS1(w)) {\n                w = (i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0;\n            }\n            w = ff_convert(w, 1);\n#endif\n            if (w == 0 || chk_chr(badchr, w) || j == 22) {  /* Check validity check validity of the volume label */\n                LEAVE_FF(fs, FR_INVALID_NAME);\n            }\n            st_word(dirvn + j, w); j += 2;\n        }\n        slen = j;\n    } else\n#endif\n    {   /* On the FAT12/16/32 volume */\n        for ( ; slen && label[slen - 1] == ' '; slen--) ;   /* Remove trailing spaces */\n        if (slen) {     /* Is there a volume label to be set? */\n            dirvn[0] = 0; i = j = 0;    /* Create volume label in directory form */\n            do {\n#if _LFN_UNICODE\n                w = ff_convert(ff_wtoupper(label[i++]), 0);\n#else\n                w = (BYTE)label[i++];\n                if (IsDBCS1(w)) {\n                    w = (j < 10 && i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0;\n                }\n#if _USE_LFN != 0\n                w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0);\n#else\n                if (IsLower(w)) w -= 0x20;          /* To upper ASCII characters */\n#ifdef _EXCVT\n                if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */\n#else\n                if (!_DF1S && w >= 0x80) w = 0;     /* Reject extended characters (ASCII cfg) */\n#endif\n#endif\n#endif\n                if (w == 0 || chk_chr(badchr, w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) {  /* Reject invalid characters for volume label */\n                    LEAVE_FF(fs, FR_INVALID_NAME);\n                }\n                if (w >= 0x100) dirvn[j++] = (BYTE)(w >> 8);\n                dirvn[j++] = (BYTE)w;\n            } while (i < slen);\n            while (j < 11) dirvn[j++] = ' ';    /* Fill remaining name field */\n            if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME);    /* Reject illegal name (heading DDEM) */\n        }\n    }\n\n    /* Set volume label */\n    dj.obj.sclust = 0;      /* Open root directory */\n    res = dir_sdi(&dj, 0);\n    if (res == FR_OK) {\n        res = dir_read(&dj, 1); /* Get volume label entry */\n        if (res == FR_OK) {\n            if (_FS_EXFAT && fs->fs_type == FS_EXFAT) {\n                dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2);   /* Change the volume label */\n                mem_cpy(dj.dir + XDIR_Label, dirvn, slen);\n            } else {\n                if (slen) {\n                    mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */\n                } else {\n                    dj.dir[DIR_Name] = DDEM;    /* Remove the volume label */\n                }\n            }\n            fs->wflag = 1;\n            res = sync_fs(fs);\n        } else {            /* No volume label entry is found or error */\n            if (res == FR_NO_FILE) {\n                res = FR_OK;\n                if (slen) { /* Create a volume label entry */\n                    res = dir_alloc(&dj, 1);    /* Allocate an entry */\n                    if (res == FR_OK) {\n                        mem_set(dj.dir, 0, SZDIRE); /* Clear the entry */\n                        if (_FS_EXFAT && fs->fs_type == FS_EXFAT) {\n                            dj.dir[XDIR_Type] = 0x83;       /* Create 83 entry */\n                            dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2);\n                            mem_cpy(dj.dir + XDIR_Label, dirvn, slen);\n                        } else {\n                            dj.dir[DIR_Attr] = AM_VOL;      /* Create volume label entry */\n                            mem_cpy(dj.dir, dirvn, 11);\n                        }\n                        fs->wflag = 1;\n                        res = sync_fs(fs);\n                    }\n                }\n            }\n        }\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n#endif /* !_FS_READONLY */\n#endif /* _USE_LABEL */\n\n\n\n#if _USE_EXPAND && !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Allocate a Contiguous Blocks to the File                              */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_expand (\n    FIL* fp,        /* Pointer to the file object */\n    FSIZE_t fsz,    /* File size to be expanded to */\n    BYTE opt        /* Operation mode 0:Find and prepare or 1:Find and allocate */\n)\n{\n    FRESULT res;\n    FATFS *fs;\n    DWORD n, clst, stcl, scl, ncl, tcl, lclst;\n\n\n    res = validate(&fp->obj, &fs);      /* Check validity of the file object */\n    if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);\n    if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);\n#if _FS_EXFAT\n    if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */\n#endif\n    n = (DWORD)fs->csize * SS(fs);  /* Cluster size */\n    tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */\n    stcl = fs->last_clst; lclst = 0;\n    if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2;\n\n#if _FS_EXFAT\n    if (fs->fs_type == FS_EXFAT) {\n        scl = find_bitmap(fs, stcl, tcl);           /* Find a contiguous cluster block */\n        if (scl == 0) res = FR_DENIED;              /* No contiguous cluster block was found */\n        if (scl == 0xFFFFFFFF) res = FR_DISK_ERR;\n        if (res == FR_OK) {\n            if (opt) {\n                res = change_bitmap(fs, scl, tcl, 1);   /* Mark the cluster block 'in use' */\n                lclst = scl + tcl - 1;\n            } else {\n                lclst = scl - 1;\n            }\n        }\n    } else\n#endif\n    {\n        scl = clst = stcl; ncl = 0;\n        for (;;) {  /* Find a contiguous cluster block */\n            n = get_fat(&fp->obj, clst);\n            if (++clst >= fs->n_fatent) clst = 2;\n            if (n == 1) { res = FR_INT_ERR; break; }\n            if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }\n            if (n == 0) {   /* Is it a free cluster? */\n                if (++ncl == tcl) break;    /* Break if a contiguous cluster block is found */\n            } else {\n                scl = clst; ncl = 0;        /* Not a free cluster */\n            }\n            if (clst == stcl) { res = FR_DENIED; break; }   /* No contiguous cluster? */\n        }\n        if (res == FR_OK) {\n            if (opt) {\n                for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */\n                    res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1);\n                    if (res != FR_OK) break;\n                    lclst = clst;\n                }\n            } else {\n                lclst = scl - 1;\n            }\n        }\n    }\n\n    if (res == FR_OK) {\n        fs->last_clst = lclst;      /* Set suggested start cluster to start next */\n        if (opt) {\n            fp->obj.sclust = scl;       /* Update object allocation information */\n            fp->obj.objsize = fsz;\n            if (_FS_EXFAT) fp->obj.stat = 2;    /* Set status 'contiguous chain' */\n            fp->flag |= FA_MODIFIED;\n            if (fs->free_clst  < fs->n_fatent - 2) {    /* Update FSINFO */\n                fs->free_clst -= tcl;\n                fs->fsi_flag |= 1;\n            }\n        }\n    }\n\n    LEAVE_FF(fs, res);\n}\n\n#endif /* _USE_EXPAND && !_FS_READONLY */\n\n\n\n#if _USE_FORWARD\n/*-----------------------------------------------------------------------*/\n/* Forward data to the stream directly                                   */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_forward (\n    FIL* fp,                        /* Pointer to the file object */\n    UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */\n    UINT btf,                       /* Number of bytes to forward */\n    UINT* bf                        /* Pointer to number of bytes forwarded */\n)\n{\n    FRESULT res;\n    FATFS *fs;\n    DWORD clst, sect;\n    FSIZE_t remain;\n    UINT rcnt, csect;\n    BYTE *dbuf;\n\n\n    *bf = 0;    /* Clear transfer byte counter */\n    res = validate(&fp->obj, &fs);      /* Check validity of the file object */\n    if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);\n    if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */\n\n    remain = fp->obj.objsize - fp->fptr;\n    if (btf > remain) btf = (UINT)remain;           /* Truncate btf by remaining bytes */\n\n    for ( ;  btf && (*func)(0, 0);                  /* Repeat until all data transferred or stream goes busy */\n        fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) {\n        csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1));    /* Sector offset in the cluster */\n        if (fp->fptr % SS(fs) == 0) {               /* On the sector boundary? */\n            if (csect == 0) {                       /* On the cluster boundary? */\n                clst = (fp->fptr == 0) ?            /* On the top of the file? */\n                    fp->obj.sclust : get_fat(&fp->obj, fp->clust);\n                if (clst <= 1) ABORT(fs, FR_INT_ERR);\n                if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);\n                fp->clust = clst;                   /* Update current cluster */\n            }\n        }\n        sect = clust2sect(fs, fp->clust);           /* Get current data sector */\n        if (!sect) ABORT(fs, FR_INT_ERR);\n        sect += csect;\n#if _FS_TINY\n        if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */\n        dbuf = fs->win;\n#else\n        if (fp->sect != sect) {     /* Fill sector cache with file data */\n#if !_FS_READONLY\n            if (fp->flag & FA_DIRTY) {      /* Write-back dirty sector cache */\n                if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n                fp->flag &= (BYTE)~FA_DIRTY;\n            }\n#endif\n            if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n        }\n        dbuf = fp->buf;\n#endif\n        fp->sect = sect;\n        rcnt = SS(fs) - (UINT)fp->fptr % SS(fs);    /* Number of bytes left in the sector */\n        if (rcnt > btf) rcnt = btf;                 /* Clip it by btr if needed */\n        rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */\n        if (!rcnt) ABORT(fs, FR_INT_ERR);\n    }\n\n    LEAVE_FF(fs, FR_OK);\n}\n#endif /* _USE_FORWARD */\n\n\n\n#if _USE_MKFS && !_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Create FAT file system on the logical drive                           */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_mkfs (\n    FATFS *fs,\n    BYTE opt,           /* Format option */\n    DWORD au,           /* Size of allocation unit [byte] */\n    void* work,         /* Pointer to working buffer */\n    UINT len            /* Size of working buffer */\n)\n{\n    const UINT n_fats = 1;      /* Number of FATs for FAT12/16/32 volume (1 or 2) */\n    const UINT n_rootdir = 512; /* Number of root directory entries for FAT12/16 volume */\n    static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0};  /* Cluster size boundary for FAT12/16 volume (4Ks unit) */\n    static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0};    /* Cluster size boundary for FAT32 volume (128Ks unit) */\n    BYTE fmt, sys, *buf, *pte, part; void *pdrv;\n    WORD ss;\n    DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n;\n    DWORD b_vol, b_fat, b_data;             /* Base LBA for volume, fat, data */\n    DWORD sz_vol, sz_rsv, sz_fat, sz_dir;   /* Size for volume, fat, dir, data */\n    UINT i;\n    DSTATUS stat;\n#if _USE_TRIM || _FS_EXFAT\n    DWORD tbl[3];\n#endif\n\n\n    /* Check mounted drive and clear work area */\n    fs->fs_type = 0;    /* Clear mounted volume */\n    pdrv = fs->drv;     /* Physical drive */\n    part = LD2PT(fs);   /* Partition (0:create as new, 1-4:get from partition table) */\n\n    /* Check physical drive status */\n    disk_ioctl(pdrv, IOCTL_INIT, &stat);\n    if (stat & STA_NOINIT) return FR_NOT_READY;\n    if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;\n    if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1;    /* Erase block to align data area */\n#if _MAX_SS != _MIN_SS      /* Get sector size of the medium */\n    if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR;\n    if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR;\n#else\n    ss = _MAX_SS;\n#endif\n    if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */\n    au /= ss;   /* Cluster size in unit of sector */\n\n    /* Get working buffer */\n    buf = (BYTE*)work;      /* Working buffer */\n    sz_buf = len / ss;      /* Size of working buffer (sector) */\n    szb_buf = sz_buf * ss;  /* Size of working buffer (byte) */\n    if (!szb_buf) return FR_MKFS_ABORTED;\n\n    /* Determine where the volume to be located (b_vol, sz_vol) */\n    if (_MULTI_PARTITION && part != 0) {\n        /* Get partition information from partition table in the MBR */\n        if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR;   /* Load MBR */\n        if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;   /* Check if MBR is valid */\n        pte = buf + (MBR_Table + (part - 1) * SZ_PTE);\n        if (!pte[PTE_System]) return FR_MKFS_ABORTED;   /* No partition? */\n        b_vol = ld_dword(pte + PTE_StLba);      /* Get volume start sector */\n        sz_vol = ld_dword(pte + PTE_SizLba);    /* Get volume size */\n    } else {\n        /* Create a single-partition in this function */\n        if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR;\n        b_vol = (opt & FM_SFD) ? 0 : 63;        /* Volume start sector */\n        if (sz_vol < b_vol) return FR_MKFS_ABORTED;\n        sz_vol -= b_vol;                        /* Volume size */\n    }\n    if (sz_vol < 50) return FR_MKFS_ABORTED;   /* Check if volume size is >=50s */\n\n    /* Pre-determine the FAT type */\n    do {\n        if (_FS_EXFAT && (opt & FM_EXFAT)) {    /* exFAT possible? */\n            if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) {    /* exFAT only, vol >= 64Ms or au > 128s ? */\n                fmt = FS_EXFAT; break;\n            }\n        }\n        if (au > 128) return FR_INVALID_PARAMETER;  /* Too large au for FAT/FAT32 */\n        if (opt & FM_FAT32) {   /* FAT32 possible? */\n            if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) {    /* FAT32 only or no-FAT? */\n                fmt = FS_FAT32; break;\n            }\n        }\n        if (!(opt & FM_FAT)) return FR_INVALID_PARAMETER;   /* no-FAT? */\n        fmt = FS_FAT16;\n    } while (0);\n\n#if _FS_EXFAT\n    if (fmt == FS_EXFAT) {  /* Create an exFAT volume */\n        DWORD szb_bit, szb_case, sum, nb, cl;\n        WCHAR ch, si;\n        UINT j, st;\n        BYTE b;\n\n        if (sz_vol < 0x1000) return FR_MKFS_ABORTED;    /* Too small volume? */\n#if _USE_TRIM\n        tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1;    /* Inform the device the volume area can be erased */\n        disk_ioctl(pdrv, CTRL_TRIM, tbl);\n#endif\n        /* Determine FAT location, data location and number of clusters */\n        if (!au) {  /* au auto-selection */\n            au = 8;\n            if (sz_vol >= 0x80000) au = 64;     /* >= 512Ks */\n            if (sz_vol >= 0x4000000) au = 256;  /* >= 64Ms */\n        }\n        b_fat = b_vol + 32;                                     /* FAT start at offset 32 */\n        sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss;         /* Number of FAT sectors */\n        b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */\n        if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED;       /* Too small volume? */\n        n_clst = (sz_vol - (b_data - b_vol)) / au;              /* Number of clusters */\n        if (n_clst <16) return FR_MKFS_ABORTED;                 /* Too few clusters? */\n        if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED;         /* Too many clusters? */\n\n        szb_bit = (n_clst + 7) / 8;                     /* Size of allocation bitmap */\n        tbl[0] = (szb_bit + au * ss - 1) / (au * ss);   /* Number of allocation bitmap clusters */\n\n        /* Create a compressed up-case table */\n        sect = b_data + au * tbl[0];    /* Table start sector */\n        sum = 0;                        /* Table checksum to be stored in the 82 entry */\n        st = si = i = j = szb_case = 0;\n        do {\n            switch (st) {\n            case 0:\n                ch = ff_wtoupper(si);   /* Get an up-case char */\n                if (ch != si) {\n                    si++; break;        /* Store the up-case char if exist */\n                }\n                for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ;  /* Get run length of no-case block */\n                if (j >= 128) {\n                    ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */\n                }\n                st = 1;         /* Do not compress short run */\n                /* continue */\n            case 1:\n                ch = si++;      /* Fill the short run */\n                if (--j == 0) st = 0;\n                break;\n            default:\n                ch = (WCHAR)j; si += j; /* Number of chars to skip */\n                st = 0;\n            }\n            sum = xsum32(buf[i + 0] = (BYTE)ch, sum);       /* Put it into the write buffer */\n            sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum);\n            i += 2; szb_case += 2;\n            if (!si || i == szb_buf) {      /* Write buffered data when buffer full or end of process */\n                n = (i + ss - 1) / ss;\n                if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;\n                sect += n; i = 0;\n            }\n        } while (si);\n        tbl[1] = (szb_case + au * ss - 1) / (au * ss);  /* Number of up-case table clusters */\n        tbl[2] = 1;                                     /* Number of root dir clusters */\n\n        /* Initialize the allocation bitmap */\n        sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */\n        nb = tbl[0] + tbl[1] + tbl[2];                  /* Number of clusters in-use by system */\n        do {\n            mem_set(buf, 0, szb_buf);\n            for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ;\n            for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ;\n            n = (nsect > sz_buf) ? sz_buf : nsect;      /* Write the buffered data */\n            if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;\n            sect += n; nsect -= n;\n        } while (nsect);\n\n        /* Initialize the FAT */\n        sect = b_fat; nsect = sz_fat;   /* Start of FAT and number of FAT sectors */\n        j = nb = cl = 0;\n        do {\n            mem_set(buf, 0, szb_buf); i = 0;    /* Clear work area and reset write index */\n            if (cl == 0) {  /* Set entry 0 and 1 */\n                st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++;\n                st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++;\n            }\n            do {            /* Create chains of bitmap, up-case and root dir */\n                while (nb && i < szb_buf) {         /* Create a chain */\n                    st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF);\n                    i += 4; cl++; nb--;\n                }\n                if (!nb && j < 3) nb = tbl[j++];    /* Next chain */\n            } while (nb && i < szb_buf);\n            n = (nsect > sz_buf) ? sz_buf : nsect;  /* Write the buffered data */\n            if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;\n            sect += n; nsect -= n;\n        } while (nsect);\n\n        /* Initialize the root directory */\n        mem_set(buf, 0, szb_buf);\n        buf[SZDIRE * 0 + 0] = 0x83;     /* 83 entry (volume label) */\n        buf[SZDIRE * 1 + 0] = 0x81;     /* 81 entry (allocation bitmap) */\n        st_dword(buf + SZDIRE * 1 + 20, 2);\n        st_dword(buf + SZDIRE * 1 + 24, szb_bit);\n        buf[SZDIRE * 2 + 0] = 0x82;     /* 82 entry (up-case table) */\n        st_dword(buf + SZDIRE * 2 + 4, sum);\n        st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]);\n        st_dword(buf + SZDIRE * 2 + 24, szb_case);\n        sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */\n        do {    /* Fill root directory sectors */\n            n = (nsect > sz_buf) ? sz_buf : nsect;\n            if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;\n            mem_set(buf, 0, ss);\n            sect += n; nsect -= n;\n        } while (nsect);\n\n        /* Create two set of the exFAT VBR blocks */\n        sect = b_vol;\n        for (n = 0; n < 2; n++) {\n            /* Main record (+0) */\n            mem_set(buf, 0, ss);\n            mem_cpy(buf + BS_JmpBoot, \"\\xEB\\x76\\x90\" \"EXFAT   \", 11);   /* Boot jump code (x86), OEM name */\n            st_dword(buf + BPB_VolOfsEx, b_vol);                    /* Volume offset in the physical drive [sector] */\n            st_dword(buf + BPB_TotSecEx, sz_vol);                   /* Volume size [sector] */\n            st_dword(buf + BPB_FatOfsEx, b_fat - b_vol);            /* FAT offset [sector] */\n            st_dword(buf + BPB_FatSzEx, sz_fat);                    /* FAT size [sector] */\n            st_dword(buf + BPB_DataOfsEx, b_data - b_vol);          /* Data offset [sector] */\n            st_dword(buf + BPB_NumClusEx, n_clst);                  /* Number of clusters */\n            st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]);    /* Root dir cluster # */\n            st_dword(buf + BPB_VolIDEx, GET_FATTIME());             /* VSN */\n            st_word(buf + BPB_FSVerEx, 0x100);                      /* File system version (1.00) */\n            for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */\n            for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */\n            buf[BPB_NumFATsEx] = 1;                 /* Number of FATs */\n            buf[BPB_DrvNumEx] = 0x80;               /* Drive number (for int13) */\n            st_word(buf + BS_BootCodeEx, 0xFEEB);   /* Boot code (x86) */\n            st_word(buf + BS_55AA, 0xAA55);         /* Signature (placed here regardless of sector size) */\n            for (i = sum = 0; i < ss; i++) {        /* VBR checksum */\n                if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum);\n            }\n            if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;\n            /* Extended bootstrap record (+1..+8) */\n            mem_set(buf, 0, ss);\n            st_word(buf + ss - 2, 0xAA55);  /* Signature (placed at end of sector) */\n            for (j = 1; j < 9; j++) {\n                for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ;  /* VBR checksum */\n                if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;\n            }\n            /* OEM/Reserved record (+9..+10) */\n            mem_set(buf, 0, ss);\n            for ( ; j < 11; j++) {\n                for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ;  /* VBR checksum */\n                if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;\n            }\n            /* Sum record (+11) */\n            for (i = 0; i < ss; i += 4) st_dword(buf + i, sum);     /* Fill with checksum value */\n            if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;\n        }\n\n    } else\n#endif  /* _FS_EXFAT */\n    {   /* Create an FAT12/16/32 volume */\n        do {\n            pau = au;\n            /* Pre-determine number of clusters and FAT sub-type */\n            if (fmt == FS_FAT32) {  /* FAT32 volume */\n                if (!pau) { /* au auto-selection */\n                    n = sz_vol / 0x20000;   /* Volume size in unit of 128KS */\n                    for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ;   /* Get from table */\n                }\n                n_clst = sz_vol / pau;  /* Number of clusters */\n                sz_fat = (n_clst * 4 + 8 + ss - 1) / ss;    /* FAT size [sector] */\n                sz_rsv = 32;    /* Number of reserved sectors */\n                sz_dir = 0;     /* No static directory */\n                if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED;\n            } else {                /* FAT12/16 volume */\n                if (!pau) { /* au auto-selection */\n                    n = sz_vol / 0x1000;    /* Volume size in unit of 4KS */\n                    for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ;   /* Get from table */\n                }\n                n_clst = sz_vol / pau;\n                if (n_clst > MAX_FAT12) {\n                    n = n_clst * 2 + 4;     /* FAT size [byte] */\n                } else {\n                    fmt = FS_FAT12;\n                    n = (n_clst * 3 + 1) / 2 + 3;   /* FAT size [byte] */\n                }\n                sz_fat = (n + ss - 1) / ss;     /* FAT size [sector] */\n                sz_rsv = 1;                     /* Number of reserved sectors */\n                sz_dir = (DWORD)n_rootdir * SZDIRE / ss;    /* Rootdir size [sector] */\n            }\n            b_fat = b_vol + sz_rsv;                     /* FAT base */\n            b_data = b_fat + sz_fat * n_fats + sz_dir;  /* Data base */\n\n            /* Align data base to erase block boundary (for flash memory media) */\n            n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data;   /* Next nearest erase block from current data base */\n            if (fmt == FS_FAT32) {      /* FAT32: Move FAT base */\n                sz_rsv += n; b_fat += n;\n            } else {                    /* FAT12/16: Expand FAT size */\n                sz_fat += n / n_fats;\n            }\n\n            /* Determine number of clusters and final check of validity of the FAT sub-type */\n            if (sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED; /* Too small volume */\n            n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau;\n            if (fmt == FS_FAT32) {\n                if (n_clst <= MAX_FAT16) {  /* Too few clusters for FAT32 */\n                    if (!au && (au = pau / 2) != 0) continue;   /* Adjust cluster size and retry */\n                    return FR_MKFS_ABORTED;\n                }\n            }\n            if (fmt == FS_FAT16) {\n                if (n_clst > MAX_FAT16) {   /* Too many clusters for FAT16 */\n                    if (!au && (pau * 2) <= 64) {\n                        au = pau * 2; continue;     /* Adjust cluster size and retry */\n                    }\n                    if ((opt & FM_FAT32)) {\n                        fmt = FS_FAT32; continue;   /* Switch type to FAT32 and retry */\n                    }\n                    if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */\n                    return FR_MKFS_ABORTED;\n                }\n                if  (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */\n                    if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */\n                    return FR_MKFS_ABORTED;\n                }\n            }\n            if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED;  /* Too many clusters for FAT12 */\n\n            /* Ok, it is the valid cluster configuration */\n            break;\n        } while (1);\n\n#if _USE_TRIM\n        tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1;    /* Inform the device the volume area can be erased */\n        disk_ioctl(pdrv, CTRL_TRIM, tbl);\n#endif\n        /* Create FAT VBR */\n        mem_set(buf, 0, ss);\n        mem_cpy(buf + BS_JmpBoot, \"\\xEB\\xFE\\x90\" \"MSDOS5.0\", 11);/* Boot jump code (x86), OEM name */\n        st_word(buf + BPB_BytsPerSec, ss);              /* Sector size [byte] */\n        buf[BPB_SecPerClus] = (BYTE)pau;                /* Cluster size [sector] */\n        st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv);    /* Size of reserved area */\n        buf[BPB_NumFATs] = (BYTE)n_fats;                /* Number of FATs */\n        st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir));   /* Number of root directory entries */\n        if (sz_vol < 0x10000) {\n            st_word(buf + BPB_TotSec16, (WORD)sz_vol);  /* Volume size in 16-bit LBA */\n        } else {\n            st_dword(buf + BPB_TotSec32, sz_vol);       /* Volume size in 32-bit LBA */\n        }\n        buf[BPB_Media] = 0xF8;                          /* Media descriptor byte */\n        st_word(buf + BPB_SecPerTrk, 63);               /* Number of sectors per track (for int13) */\n        st_word(buf + BPB_NumHeads, 255);               /* Number of heads (for int13) */\n        st_dword(buf + BPB_HiddSec, b_vol);             /* Volume offset in the physical drive [sector] */\n        if (fmt == FS_FAT32) {\n            st_dword(buf + BS_VolID32, GET_FATTIME());  /* VSN */\n            st_dword(buf + BPB_FATSz32, sz_fat);        /* FAT size [sector] */\n            st_dword(buf + BPB_RootClus32, 2);          /* Root directory cluster # (2) */\n            st_word(buf + BPB_FSInfo32, 1);             /* Offset of FSINFO sector (VBR + 1) */\n            st_word(buf + BPB_BkBootSec32, 6);          /* Offset of backup VBR (VBR + 6) */\n            buf[BS_DrvNum32] = 0x80;                    /* Drive number (for int13) */\n            buf[BS_BootSig32] = 0x29;                   /* Extended boot signature */\n            mem_cpy(buf + BS_VolLab32, \"NO NAME    \" \"FAT32   \", 19);   /* Volume label, FAT signature */\n        } else {\n            st_dword(buf + BS_VolID, GET_FATTIME());    /* VSN */\n            st_word(buf + BPB_FATSz16, (WORD)sz_fat);   /* FAT size [sector] */\n            buf[BS_DrvNum] = 0x80;                      /* Drive number (for int13) */\n            buf[BS_BootSig] = 0x29;                     /* Extended boot signature */\n            mem_cpy(buf + BS_VolLab, \"NO NAME    \" \"FAT     \", 19); /* Volume label, FAT signature */\n        }\n        st_word(buf + BS_55AA, 0xAA55);                 /* Signature (offset is fixed here regardless of sector size) */\n        if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR;  /* Write it to the VBR sector */\n\n        /* Create FSINFO record if needed */\n        if (fmt == FS_FAT32) {\n            disk_write(pdrv, buf, b_vol + 6, 1);        /* Write backup VBR (VBR + 6) */\n            mem_set(buf, 0, ss);\n            st_dword(buf + FSI_LeadSig, 0x41615252);\n            st_dword(buf + FSI_StrucSig, 0x61417272);\n            st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */\n            st_dword(buf + FSI_Nxt_Free, 2);            /* Last allocated cluster# */\n            st_word(buf + BS_55AA, 0xAA55);\n            disk_write(pdrv, buf, b_vol + 7, 1);        /* Write backup FSINFO (VBR + 7) */\n            disk_write(pdrv, buf, b_vol + 1, 1);        /* Write original FSINFO (VBR + 1) */\n        }\n\n        /* Initialize FAT area */\n        mem_set(buf, 0, (UINT)szb_buf);\n        sect = b_fat;       /* FAT start sector */\n        for (i = 0; i < n_fats; i++) {          /* Initialize FATs each */\n            if (fmt == FS_FAT32) {\n                st_dword(buf + 0, 0xFFFFFFF8);  /* Entry 0 */\n                st_dword(buf + 4, 0xFFFFFFFF);  /* Entry 1 */\n                st_dword(buf + 8, 0x0FFFFFFF);  /* Entry 2 (root directory) */\n            } else {\n                st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8);   /* Entry 0 and 1 */\n            }\n            nsect = sz_fat;     /* Number of FAT sectors */\n            do {    /* Fill FAT sectors */\n                n = (nsect > sz_buf) ? sz_buf : nsect;\n                if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR;\n                mem_set(buf, 0, ss);\n                sect += n; nsect -= n;\n            } while (nsect);\n        }\n\n        /* Initialize root directory (fill with zero) */\n        nsect = (fmt == FS_FAT32) ? pau : sz_dir;   /* Number of root directory sectors */\n        do {\n            n = (nsect > sz_buf) ? sz_buf : nsect;\n            if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR;\n            sect += n; nsect -= n;\n        } while (nsect);\n    }\n\n    /* Determine system ID in the partition table */\n    if (_FS_EXFAT && fmt == FS_EXFAT) {\n        sys = 0x07;         /* HPFS/NTFS/exFAT */\n    } else {\n        if (fmt == FS_FAT32) {\n            sys = 0x0C;     /* FAT32X */\n        } else {\n            if (sz_vol >= 0x10000) {\n                sys = 0x06; /* FAT12/16 (>=64KS) */\n            } else {\n                sys = (fmt == FS_FAT16) ? 0x04 : 0x01;  /* FAT16 (<64KS) : FAT12 (<64KS) */\n            }\n        }\n    }\n\n    if (_MULTI_PARTITION && part != 0) {\n        /* Update system ID in the partition table */\n        if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR;   /* Read the MBR */\n        buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys;        /* Set system type */\n        if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR;  /* Write it back to the MBR */\n    } else {\n        if (!(opt & FM_SFD)) {\n            /* Create partition table in FDISK format */\n            mem_set(buf, 0, ss);\n            st_word(buf + BS_55AA, 0xAA55);     /* MBR signature */\n            pte = buf + MBR_Table;              /* Create partition table for single partition in the drive */\n            pte[PTE_Boot] = 0;                  /* Boot indicator */\n            pte[PTE_StHead] = 1;                /* Start head */\n            pte[PTE_StSec] = 1;                 /* Start sector */\n            pte[PTE_StCyl] = 0;                 /* Start cylinder */\n            pte[PTE_System] = sys;              /* System type */\n            n = (b_vol + sz_vol) / (63 * 255);  /* (End CHS is incorrect) */\n            pte[PTE_EdHead] = 254;              /* End head */\n            pte[PTE_EdSec] = (BYTE)(n >> 2 | 63);   /* End sector */\n            pte[PTE_EdCyl] = (BYTE)n;           /* End cylinder */\n            st_dword(pte + PTE_StLba, b_vol);   /* Start offset in LBA */\n            st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */\n            if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR;  /* Write it to the MBR */\n        }\n    }\n\n    if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) return FR_DISK_ERR;\n\n    return FR_OK;\n}\n\n\n\n#if _MULTI_PARTITION\n/*-----------------------------------------------------------------------*/\n/* Create partition table on the physical drive                          */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_fdisk (\n    void *pdrv,         /* Physical drive number */\n    const DWORD* szt,   /* Pointer to the size table for each partitions */\n    void* work          /* Pointer to the working buffer */\n)\n{\n    UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;\n    BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;\n    DSTATUS stat;\n    DWORD sz_disk, sz_part, s_part;\n\n\n    disk_ioctl(pdrv, IOCTL_INIT, &stat);\n    if (stat & STA_NOINIT) return FR_NOT_READY;\n    if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;\n    if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;\n\n    /* Determine the CHS without any care of the drive geometry */\n    for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ;\n    if (n == 256) n--;\n    e_hd = n - 1;\n    sz_cyl = 63 * n;\n    tot_cyl = sz_disk / sz_cyl;\n\n    /* Create partition table */\n    mem_set(buf, 0, _MAX_SS);\n    p = buf + MBR_Table; b_cyl = 0;\n    for (i = 0; i < 4; i++, p += SZ_PTE) {\n        p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl;\n        if (!p_cyl) continue;\n        s_part = (DWORD)sz_cyl * b_cyl;\n        sz_part = (DWORD)sz_cyl * p_cyl;\n        if (i == 0) {   /* Exclude first track of cylinder 0 */\n            s_hd = 1;\n            s_part += 63; sz_part -= 63;\n        } else {\n            s_hd = 0;\n        }\n        e_cyl = b_cyl + p_cyl - 1;\n        if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER;\n\n        /* Set partition table */\n        p[1] = s_hd;                        /* Start head */\n        p[2] = (BYTE)((b_cyl >> 2) + 1);    /* Start sector */\n        p[3] = (BYTE)b_cyl;                 /* Start cylinder */\n        p[4] = 0x06;                        /* System type (temporary setting) */\n        p[5] = e_hd;                        /* End head */\n        p[6] = (BYTE)((e_cyl >> 2) + 63);   /* End sector */\n        p[7] = (BYTE)e_cyl;                 /* End cylinder */\n        st_dword(p + 8, s_part);            /* Start sector in LBA */\n        st_dword(p + 12, sz_part);          /* Partition size */\n\n        /* Next partition */\n        b_cyl += p_cyl;\n    }\n    st_word(p, 0xAA55);\n\n    /* Write it to the MBR */\n    return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK;\n}\n\n#endif /* _MULTI_PARTITION */\n#endif /* _USE_MKFS && !_FS_READONLY */\n"
  },
  {
    "path": "lib/oofatfs/ff.h",
    "content": "/* This file is part of ooFatFs, a customised version of FatFs\n * See https://github.com/micropython/oofatfs for details\n */\n\n/*----------------------------------------------------------------------------/\n/  FatFs - Generic FAT file system module  R0.12b                             /\n/-----------------------------------------------------------------------------/\n/\n/ Copyright (C) 2016, ChaN, all right reserved.\n/\n/ FatFs module is an open source software. Redistribution and use of FatFs in\n/ source and binary forms, with or without modification, are permitted provided\n/ that the following condition is met:\n\n/ 1. Redistributions of source code must retain the above copyright notice,\n/    this condition and the following disclaimer.\n/\n/ This software is provided by the copyright holder and contributors \"AS IS\"\n/ and any warranties related to this software are DISCLAIMED.\n/ The copyright owner or contributors be NOT LIABLE for any damages caused\n/ by use of this software.\n/----------------------------------------------------------------------------*/\n\n\n#ifndef _FATFS\n#define _FATFS  68020   /* Revision ID */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdint.h>\n\n/* This type MUST be 8-bit */\ntypedef uint8_t BYTE;\n\n/* These types MUST be 16-bit */\ntypedef int16_t SHORT;\ntypedef uint16_t WORD;\ntypedef uint16_t WCHAR;\n\n/* These types MUST be 16-bit or 32-bit */\ntypedef int INT;\ntypedef unsigned int UINT;\n\n/* These types MUST be 32-bit */\ntypedef int32_t LONG;\ntypedef uint32_t DWORD;\n\n/* This type MUST be 64-bit (Remove this for C89 compatibility) */\ntypedef uint64_t QWORD;\n\n#include FFCONF_H          /* FatFs configuration options */\n\n#if _FATFS != _FFCONF\n#error Wrong configuration file (ffconf.h).\n#endif\n\n\n\n/* Definitions of volume management */\n\n#if _MULTI_PARTITION            /* Multiple partition configuration */\n#define LD2PT(fs) (fs->part)    /* Get partition index */\n#else                           /* Single partition configuration */\n#define LD2PT(fs) 0             /* Find first valid partition or in SFD */\n#endif\n\n\n\n/* Type of path name strings on FatFs API */\n\n#if _LFN_UNICODE            /* Unicode (UTF-16) string */\n#if _USE_LFN == 0\n#error _LFN_UNICODE must be 0 at non-LFN cfg.\n#endif\n#ifndef _INC_TCHAR\ntypedef WCHAR TCHAR;\n#define _T(x) L ## x\n#define _TEXT(x) L ## x\n#endif\n#else                       /* ANSI/OEM string */\n#ifndef _INC_TCHAR\ntypedef char TCHAR;\n#define _T(x) x\n#define _TEXT(x) x\n#endif\n#endif\n\n\n\n/* Type of file size variables */\n\n#if _FS_EXFAT\n#if _USE_LFN == 0\n#error LFN must be enabled when enable exFAT\n#endif\ntypedef QWORD FSIZE_t;\n#else\ntypedef DWORD FSIZE_t;\n#endif\n\n\n\n/* File system object structure (FATFS) */\n\ntypedef struct {\n    void    *drv;           // block device underlying this filesystem\n#if _MULTI_PARTITION        /* Multiple partition configuration */\n    BYTE    part;           // Partition: 0:Auto detect, 1-4:Forced partition\n#endif\n    BYTE    fs_type;        /* File system type (0:N/A) */\n    BYTE    n_fats;         /* Number of FATs (1 or 2) */\n    BYTE    wflag;          /* win[] flag (b0:dirty) */\n    BYTE    fsi_flag;       /* FSINFO flags (b7:disabled, b0:dirty) */\n    WORD    id;             /* File system mount ID */\n    WORD    n_rootdir;      /* Number of root directory entries (FAT12/16) */\n    WORD    csize;          /* Cluster size [sectors] */\n#if _MAX_SS != _MIN_SS\n    WORD    ssize;          /* Sector size (512, 1024, 2048 or 4096) */\n#endif\n#if _USE_LFN != 0\n    WCHAR*  lfnbuf;         /* LFN working buffer */\n#endif\n#if _FS_EXFAT\n    BYTE*   dirbuf;         /* Directory entry block scratchpad buffer */\n#endif\n#if _FS_REENTRANT\n    _SYNC_t sobj;           /* Identifier of sync object */\n#endif\n#if !_FS_READONLY\n    DWORD   last_clst;      /* Last allocated cluster */\n    DWORD   free_clst;      /* Number of free clusters */\n#endif\n#if _FS_RPATH != 0\n    DWORD   cdir;           /* Current directory start cluster (0:root) */\n#if _FS_EXFAT\n    DWORD   cdc_scl;        /* Containing directory start cluster (invalid when cdir is 0) */\n    DWORD   cdc_size;       /* b31-b8:Size of containing directory, b7-b0: Chain status */\n    DWORD   cdc_ofs;        /* Offset in the containing directory (invalid when cdir is 0) */\n#endif\n#endif\n    DWORD   n_fatent;       /* Number of FAT entries (number of clusters + 2) */\n    DWORD   fsize;          /* Size of an FAT [sectors] */\n    DWORD   volbase;        /* Volume base sector */\n    DWORD   fatbase;        /* FAT base sector */\n    DWORD   dirbase;        /* Root directory base sector/cluster */\n    DWORD   database;       /* Data base sector */\n    DWORD   winsect;        /* Current sector appearing in the win[] */\n    BYTE    win[_MAX_SS];   /* Disk access window for Directory, FAT (and file data at tiny cfg) */\n} FATFS;\n\n\n\n/* Object ID and allocation information (_FDID) */\n\ntypedef struct {\n    FATFS*  fs;         /* Pointer to the owner file system object */\n    WORD    id;         /* Owner file system mount ID */\n    BYTE    attr;       /* Object attribute */\n    BYTE    stat;       /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */\n    DWORD   sclust;     /* Object start cluster (0:no cluster or root directory) */\n    FSIZE_t objsize;    /* Object size (valid when sclust != 0) */\n#if _FS_EXFAT\n    DWORD   n_cont;     /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */\n    DWORD   c_scl;      /* Containing directory start cluster (valid when sclust != 0) */\n    DWORD   c_size;     /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */\n    DWORD   c_ofs;      /* Offset in the containing directory (valid when sclust != 0) */\n#endif\n#if _FS_LOCK != 0\n    UINT    lockid;     /* File lock ID origin from 1 (index of file semaphore table Files[]) */\n#endif\n} _FDID;\n\n\n\n/* File object structure (FIL) */\n\ntypedef struct {\n    _FDID   obj;            /* Object identifier (must be the 1st member to detect invalid object pointer) */\n    BYTE    flag;           /* File status flags */\n    BYTE    err;            /* Abort flag (error code) */\n    FSIZE_t fptr;           /* File read/write pointer (Zeroed on file open) */\n    DWORD   clust;          /* Current cluster of fpter (invalid when fprt is 0) */\n    DWORD   sect;           /* Sector number appearing in buf[] (0:invalid) */\n#if !_FS_READONLY\n    DWORD   dir_sect;       /* Sector number containing the directory entry */\n    BYTE*   dir_ptr;        /* Pointer to the directory entry in the win[] */\n#endif\n#if _USE_FASTSEEK\n    DWORD*  cltbl;          /* Pointer to the cluster link map table (nulled on open, set by application) */\n#endif\n#if !_FS_TINY\n    BYTE    buf[_MAX_SS];   /* File private data read/write window */\n#endif\n} FIL;\n\n\n\n/* Directory object structure (FF_DIR) */\n\ntypedef struct {\n    _FDID   obj;            /* Object identifier */\n    DWORD   dptr;           /* Current read/write offset */\n    DWORD   clust;          /* Current cluster */\n    DWORD   sect;           /* Current sector */\n    BYTE*   dir;            /* Pointer to the directory item in the win[] */\n    BYTE    fn[12];         /* SFN (in/out) {body[8],ext[3],status[1]} */\n#if _USE_LFN != 0\n    DWORD   blk_ofs;        /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */\n#endif\n#if _USE_FIND\n    const TCHAR* pat;       /* Pointer to the name matching pattern */\n#endif\n} FF_DIR;\n\n\n\n/* File information structure (FILINFO) */\n\ntypedef struct {\n    FSIZE_t fsize;          /* File size */\n    WORD    fdate;          /* Modified date */\n    WORD    ftime;          /* Modified time */\n    BYTE    fattrib;        /* File attribute */\n#if _USE_LFN != 0\n    TCHAR   altname[13];            /* Altenative file name */\n    TCHAR   fname[_MAX_LFN + 1];    /* Primary file name */\n#else\n    TCHAR   fname[13];      /* File name */\n#endif\n} FILINFO;\n\n\n\n/* File function return code (FRESULT) */\n\ntypedef enum {\n    FR_OK = 0,              /* (0) Succeeded */\n    FR_DISK_ERR,            /* (1) A hard error occurred in the low level disk I/O layer */\n    FR_INT_ERR,             /* (2) Assertion failed */\n    FR_NOT_READY,           /* (3) The physical drive cannot work */\n    FR_NO_FILE,             /* (4) Could not find the file */\n    FR_NO_PATH,             /* (5) Could not find the path */\n    FR_INVALID_NAME,        /* (6) The path name format is invalid */\n    FR_DENIED,              /* (7) Access denied due to prohibited access or directory full */\n    FR_EXIST,               /* (8) Access denied due to prohibited access */\n    FR_INVALID_OBJECT,      /* (9) The file/directory object is invalid */\n    FR_WRITE_PROTECTED,     /* (10) The physical drive is write protected */\n    FR_INVALID_DRIVE,       /* (11) The logical drive number is invalid */\n    FR_NOT_ENABLED,         /* (12) The volume has no work area */\n    FR_NO_FILESYSTEM,       /* (13) There is no valid FAT volume */\n    FR_MKFS_ABORTED,        /* (14) The f_mkfs() aborted due to any problem */\n    FR_TIMEOUT,             /* (15) Could not get a grant to access the volume within defined period */\n    FR_LOCKED,              /* (16) The operation is rejected according to the file sharing policy */\n    FR_NOT_ENOUGH_CORE,     /* (17) LFN working buffer could not be allocated */\n    FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */\n    FR_INVALID_PARAMETER    /* (19) Given parameter is invalid */\n} FRESULT;\n\n\n\n/*--------------------------------------------------------------*/\n/* FatFs module application interface                           */\n\nFRESULT f_open (FATFS *fs, FIL* fp, const TCHAR* path, BYTE mode);  /* Open or create a file */\nFRESULT f_close (FIL* fp);                                          /* Close an open file object */\nFRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br);           /* Read data from the file */\nFRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw);    /* Write data to the file */\nFRESULT f_lseek (FIL* fp, FSIZE_t ofs);                             /* Move file pointer of the file object */\nFRESULT f_truncate (FIL* fp);                                       /* Truncate the file */\nFRESULT f_sync (FIL* fp);                                           /* Flush cached data of the writing file */\nFRESULT f_opendir (FATFS *fs, FF_DIR* dp, const TCHAR* path);       /* Open a directory */\nFRESULT f_closedir (FF_DIR* dp);                                    /* Close an open directory */\nFRESULT f_readdir (FF_DIR* dp, FILINFO* fno);                       /* Read a directory item */\nFRESULT f_findfirst (FF_DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */\nFRESULT f_findnext (FF_DIR* dp, FILINFO* fno);                      /* Find next file */\nFRESULT f_mkdir (FATFS *fs, const TCHAR* path);                     /* Create a sub directory */\nFRESULT f_unlink (FATFS *fs, const TCHAR* path);                    /* Delete an existing file or directory */\nFRESULT f_rename (FATFS *fs, const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */\nFRESULT f_stat (FATFS *fs, const TCHAR* path, FILINFO* fno);        /* Get file status */\nFRESULT f_chmod (FATFS *fs, const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */\nFRESULT f_utime (FATFS *fs, const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */\nFRESULT f_chdir (FATFS *fs, const TCHAR* path);                     /* Change current directory */\nFRESULT f_getcwd (FATFS *fs, TCHAR* buff, UINT len);                /* Get current directory */\nFRESULT f_getfree (FATFS *fs, DWORD* nclst);                        /* Get number of free clusters on the drive */\nFRESULT f_getlabel (FATFS *fs, TCHAR* label, DWORD* vsn);           /* Get volume label */\nFRESULT f_setlabel (FATFS *fs, const TCHAR* label);                 /* Set volume label */\nFRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */\nFRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt);                  /* Allocate a contiguous block to the file */\nFRESULT f_mount (FATFS* fs);                                        /* Mount/Unmount a logical drive */\nFRESULT f_umount (FATFS* fs);                                       /* Unmount a logical drive */\nFRESULT f_mkfs (FATFS *fs, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */\nFRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work);         /* Divide a physical drive into some partitions */\n\n#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))\n#define f_error(fp) ((fp)->err)\n#define f_tell(fp) ((fp)->fptr)\n#define f_size(fp) ((fp)->obj.objsize)\n#define f_rewind(fp) f_lseek((fp), 0)\n#define f_rewinddir(dp) f_readdir((dp), 0)\n\n#ifndef EOF\n#define EOF (-1)\n#endif\n\n\n\n\n/*--------------------------------------------------------------*/\n/* Additional user defined functions                            */\n\n/* RTC function */\n#if !_FS_READONLY && !_FS_NORTC\nDWORD get_fattime (void);\n#endif\n\n/* Unicode support functions */\n#if _USE_LFN != 0                       /* Unicode - OEM code conversion */\nWCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */\nWCHAR ff_wtoupper (WCHAR chr);          /* Unicode upper-case conversion */\n#if _USE_LFN == 3                       /* Memory functions */\nvoid* ff_memalloc (UINT msize);         /* Allocate memory block */\nvoid ff_memfree (void* mblock);         /* Free memory block */\n#endif\n#endif\n\n/* Sync functions */\n#if _FS_REENTRANT\nint ff_cre_syncobj (FATFS *fatfs, _SYNC_t* sobj); /* Create a sync object */\nint ff_req_grant (_SYNC_t sobj);                /* Lock sync object */\nvoid ff_rel_grant (_SYNC_t sobj);               /* Unlock sync object */\nint ff_del_syncobj (_SYNC_t sobj);              /* Delete a sync object */\n#endif\n\n\n\n\n/*--------------------------------------------------------------*/\n/* Flags and offset address                                     */\n\n\n/* File access mode and open method flags (3rd argument of f_open) */\n#define FA_READ             0x01\n#define FA_WRITE            0x02\n#define FA_OPEN_EXISTING    0x00\n#define FA_CREATE_NEW       0x04\n#define FA_CREATE_ALWAYS    0x08\n#define FA_OPEN_ALWAYS      0x10\n#define FA_OPEN_APPEND      0x30\n\n/* Fast seek controls (2nd argument of f_lseek) */\n#define CREATE_LINKMAP  ((FSIZE_t)0 - 1)\n\n/* Format options (2nd argument of f_mkfs) */\n#define FM_FAT      0x01\n#define FM_FAT32    0x02\n#define FM_EXFAT    0x04\n#define FM_ANY      0x07\n#define FM_SFD      0x08\n\n/* Filesystem type (FATFS.fs_type) */\n#define FS_FAT12    1\n#define FS_FAT16    2\n#define FS_FAT32    3\n#define FS_EXFAT    4\n\n/* File attribute bits for directory entry (FILINFO.fattrib) */\n#define AM_RDO  0x01    /* Read only */\n#define AM_HID  0x02    /* Hidden */\n#define AM_SYS  0x04    /* System */\n#define AM_DIR  0x10    /* Directory */\n#define AM_ARC  0x20    /* Archive */\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _FATFS */\n"
  },
  {
    "path": "lib/oofatfs/ffconf.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * Original file from:\n * FatFs - FAT file system module configuration file R0.12a (C)ChaN, 2016\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n\n/*---------------------------------------------------------------------------/\n/  FatFs - FAT file system module configuration file\n/---------------------------------------------------------------------------*/\n\n#define _FFCONF 68020   /* Revision ID */\n\n/*---------------------------------------------------------------------------/\n/ Function Configurations\n/---------------------------------------------------------------------------*/\n\n#define _FS_READONLY    0\n/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)\n/  Read-only configuration removes writing API functions, f_write(), f_sync(),\n/  f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()\n/  and optional writing functions as well. */\n\n\n#define _FS_MINIMIZE    0\n/* This option defines minimization level to remove some basic API functions.\n/\n/   0: All basic functions are enabled.\n/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()\n/      are removed.\n/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.\n/   3: f_lseek() function is removed in addition to 2. */\n\n\n#define _USE_STRFUNC    0\n/* This option switches string functions, f_gets(), f_putc(), f_puts() and\n/  f_printf().\n/\n/  0: Disable string functions.\n/  1: Enable without LF-CRLF conversion.\n/  2: Enable with LF-CRLF conversion. */\n\n\n#define _USE_FIND       0\n/* This option switches filtered directory read functions, f_findfirst() and\n/  f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */\n\n\n#define _USE_MKFS       1\n/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */\n\n\n#define _USE_FASTSEEK   0\n/* This option switches fast seek function. (0:Disable or 1:Enable) */\n\n\n#define _USE_EXPAND     0\n/* This option switches f_expand function. (0:Disable or 1:Enable) */\n\n\n#define _USE_CHMOD      1\n/* This option switches attribute manipulation functions, f_chmod() and f_utime().\n/  (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */\n\n\n#ifdef MICROPY_FATFS_USE_LABEL\n#define _USE_LABEL      (MICROPY_FATFS_USE_LABEL)\n#else\n#define _USE_LABEL      0\n#endif\n/* This option switches volume label functions, f_getlabel() and f_setlabel().\n/  (0:Disable or 1:Enable) */\n\n\n#define _USE_FORWARD    0\n/* This option switches f_forward() function. (0:Disable or 1:Enable) */\n\n\n/*---------------------------------------------------------------------------/\n/ Locale and Namespace Configurations\n/---------------------------------------------------------------------------*/\n\n#ifdef MICROPY_FATFS_LFN_CODE_PAGE\n#define _CODE_PAGE  (MICROPY_FATFS_LFN_CODE_PAGE)\n#else\n#define _CODE_PAGE  1\n#endif\n/* This option specifies the OEM code page to be used on the target system.\n/  Incorrect setting of the code page can cause a file open failure.\n/\n/   1   - ASCII (No extended character. Non-LFN cfg. only)\n/   437 - U.S.\n/   720 - Arabic\n/   737 - Greek\n/   771 - KBL\n/   775 - Baltic\n/   850 - Latin 1\n/   852 - Latin 2\n/   855 - Cyrillic\n/   857 - Turkish\n/   860 - Portuguese\n/   861 - Icelandic\n/   862 - Hebrew\n/   863 - Canadian French\n/   864 - Arabic\n/   865 - Nordic\n/   866 - Russian\n/   869 - Greek 2\n/   932 - Japanese (DBCS)\n/   936 - Simplified Chinese (DBCS)\n/   949 - Korean (DBCS)\n/   950 - Traditional Chinese (DBCS)\n*/\n\n\n#ifdef MICROPY_FATFS_ENABLE_LFN\n#define _USE_LFN    (MICROPY_FATFS_ENABLE_LFN)\n#else\n#define _USE_LFN    0\n#endif\n#ifdef MICROPY_FATFS_MAX_LFN\n#define _MAX_LFN    (MICROPY_FATFS_MAX_LFN)\n#else\n#define _MAX_LFN    255\n#endif\n/* The _USE_LFN switches the support of long file name (LFN).\n/\n/   0: Disable support of LFN. _MAX_LFN has no effect.\n/   1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.\n/   2: Enable LFN with dynamic working buffer on the STACK.\n/   3: Enable LFN with dynamic working buffer on the HEAP.\n/\n/  To enable the LFN, Unicode handling functions (option/unicode.c) must be added\n/  to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and\n/  additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255.\n/  It should be set 255 to support full featured LFN operations.\n/  When use stack for the working buffer, take care on stack overflow. When use heap\n/  memory for the working buffer, memory management functions, ff_memalloc() and\n/  ff_memfree(), must be added to the project. */\n\n\n#define _LFN_UNICODE    0\n/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)\n/  To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.\n/  This option also affects behavior of string I/O functions. */\n\n\n#define _STRF_ENCODE    3\n/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to\n/  be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().\n/\n/  0: ANSI/OEM\n/  1: UTF-16LE\n/  2: UTF-16BE\n/  3: UTF-8\n/\n/  This option has no effect when _LFN_UNICODE == 0. */\n\n\n#ifdef MICROPY_FATFS_RPATH\n#define _FS_RPATH   (MICROPY_FATFS_RPATH)\n#else\n#define _FS_RPATH   0\n#endif\n/* This option configures support of relative path.\n/\n/   0: Disable relative path and remove related functions.\n/   1: Enable relative path. f_chdir() and f_chdrive() are available.\n/   2: f_getcwd() function is available in addition to 1.\n*/\n\n\n/*---------------------------------------------------------------------------/\n/ Drive/Volume Configurations\n/---------------------------------------------------------------------------*/\n\n#define _VOLUMES    1\n/* Number of volumes (logical drives) to be used. */\n\n\n#define _STR_VOLUME_ID  0\n#define _VOLUME_STRS    \"RAM\",\"NAND\",\"CF\",\"SD\",\"SD2\",\"USB\",\"USB2\",\"USB3\"\n/* _STR_VOLUME_ID switches string support of volume ID.\n/  When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive\n/  number in the path name. _VOLUME_STRS defines the drive ID strings for each\n/  logical drives. Number of items must be equal to _VOLUMES. Valid characters for\n/  the drive ID strings are: A-Z and 0-9. */\n\n\n#ifdef MICROPY_FATFS_MULTI_PARTITION\n#define _MULTI_PARTITION    (MICROPY_FATFS_MULTI_PARTITION)\n#else\n#define _MULTI_PARTITION    0\n#endif\n/* This option switches support of multi-partition on a physical drive.\n/  By default (0), each logical drive number is bound to the same physical drive\n/  number and only an FAT volume found on the physical drive will be mounted.\n/  When multi-partition is enabled (1), each logical drive number can be bound to\n/  arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()\n/  funciton will be available. */\n\n\n#define _MIN_SS     512\n#ifdef MICROPY_FATFS_MAX_SS\n#define _MAX_SS     (MICROPY_FATFS_MAX_SS)\n#else\n#define _MAX_SS     512\n#endif\n/* These options configure the range of sector size to be supported. (512, 1024,\n/  2048 or 4096) Always set both 512 for most systems, all type of memory cards and\n/  harddisk. But a larger value may be required for on-board flash memory and some\n/  type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured\n/  to variable sector size and GET_SECTOR_SIZE command must be implemented to the\n/  disk_ioctl() function. */\n\n\n#define _USE_TRIM   0\n/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)\n/  To enable Trim function, also CTRL_TRIM command should be implemented to the\n/  disk_ioctl() function. */\n\n\n#define _FS_NOFSINFO    0\n/* If you need to know correct free space on the FAT32 volume, set bit 0 of this\n/  option, and f_getfree() function at first time after volume mount will force\n/  a full FAT scan. Bit 1 controls the use of last allocated cluster number.\n/\n/  bit0=0: Use free cluster count in the FSINFO if available.\n/  bit0=1: Do not trust free cluster count in the FSINFO.\n/  bit1=0: Use last allocated cluster number in the FSINFO if available.\n/  bit1=1: Do not trust last allocated cluster number in the FSINFO.\n*/\n\n\n\n/*---------------------------------------------------------------------------/\n/ System Configurations\n/---------------------------------------------------------------------------*/\n\n#define _FS_TINY    1\n/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)\n/  At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes.\n/  Instead of private sector buffer eliminated from the file object, common sector\n/  buffer in the file system object (FATFS) is used for the file data transfer. */\n\n\n#ifdef MICROPY_FATFS_EXFAT\n#define _FS_EXFAT   (MICROPY_FATFS_EXFAT)\n#else\n#define _FS_EXFAT   0\n#endif\n/* This option switches support of exFAT file system. (0:Disable or 1:Enable)\n/  When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)\n/  Note that enabling exFAT discards C89 compatibility. */\n\n\n#ifdef MICROPY_FATFS_NORTC\n#define _FS_NORTC   (MICROPY_FATFS_NORTC)\n#else\n#define _FS_NORTC   0\n#endif\n#define _NORTC_MON  1\n#define _NORTC_MDAY 1\n#define _NORTC_YEAR 2016\n/* The option _FS_NORTC switches timestamp functiton. If the system does not have\n/  any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable\n/  the timestamp function. All objects modified by FatFs will have a fixed timestamp\n/  defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.\n/  To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be\n/  added to the project to get current time form real-time clock. _NORTC_MON,\n/  _NORTC_MDAY and _NORTC_YEAR have no effect.\n/  These options have no effect at read-only configuration (_FS_READONLY = 1). */\n\n\n#define _FS_LOCK    0\n/* The option _FS_LOCK switches file lock function to control duplicated file open\n/  and illegal operation to open objects. This option must be 0 when _FS_READONLY\n/  is 1.\n/\n/  0:  Disable file lock function. To avoid volume corruption, application program\n/      should avoid illegal open, remove and rename to the open objects.\n/  >0: Enable file lock function. The value defines how many files/sub-directories\n/      can be opened simultaneously under file lock control. Note that the file\n/      lock control is independent of re-entrancy. */\n\n\n#ifdef MICROPY_FATFS_REENTRANT\n#define _FS_REENTRANT   (MICROPY_FATFS_REENTRANT)\n#else\n#define _FS_REENTRANT   0\n#endif\n\n// milliseconds\n#ifdef MICROPY_FATFS_TIMEOUT\n#define _FS_TIMEOUT     (MICROPY_FATFS_TIMEOUT)\n#else\n#define _FS_TIMEOUT     1000\n#endif\n\n#ifdef MICROPY_FATFS_SYNC_T\n#define _SYNC_t         MICROPY_FATFS_SYNC_T\n#else\n#define _SYNC_t         HANDLE\n#endif\n/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs\n/  module itself. Note that regardless of this option, file access to different\n/  volume is always re-entrant and volume control functions, f_mount(), f_mkfs()\n/  and f_fdisk() function, are always not re-entrant. Only file/directory access\n/  to the same volume is under control of this function.\n/\n/   0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.\n/   1: Enable re-entrancy. Also user provided synchronization handlers,\n/      ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()\n/      function, must be added to the project. Samples are available in\n/      option/syscall.c.\n/\n/  The _FS_TIMEOUT defines timeout period in unit of time tick.\n/  The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,\n/  SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be\n/  included somewhere in the scope of ff.h. */\n\n/* #include <windows.h> // O/S definitions  */\n\n\n/*--- End of configuration options ---*/\n"
  },
  {
    "path": "lib/oofatfs/option/ccsbcs.c",
    "content": "/*------------------------------------------------------------------------*/\n/* Unicode - Local code bidirectional converter  (C)ChaN, 2015            */\n/* (SBCS code pages)                                                      */\n/*------------------------------------------------------------------------*/\n/*  437   U.S.\n/   720   Arabic\n/   737   Greek\n/   771   KBL\n/   775   Baltic\n/   850   Latin 1\n/   852   Latin 2\n/   855   Cyrillic\n/   857   Turkish\n/   860   Portuguese\n/   861   Icelandic\n/   862   Hebrew\n/   863   Canadian French\n/   864   Arabic\n/   865   Nordic\n/   866   Russian\n/   869   Greek 2\n*/\n\n#include \"../ff.h\"\n\n\n#if _CODE_PAGE == 437\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP437(0x80-0xFF) to Unicode conversion table */\n    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,\n    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,\n    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 720\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP720(0x80-0xFF) to Unicode conversion table */\n    0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,\n    0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,\n    0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n    0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,\n    0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 737\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP737(0x80-0xFF) to Unicode conversion table */\n    0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,\n    0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,\n    0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n    0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,\n    0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 771\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP771(0x80-0xFF) to Unicode conversion table */\n    0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,\n    0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,\n    0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,\n    0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,\n    0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 775\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP775(0x80-0xFF) to Unicode conversion table */\n    0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,\n    0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,\n    0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,\n    0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n    0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,\n    0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 850\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP850(0x80-0xFF) to Unicode conversion table */\n    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,\n    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,\n    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,\n    0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,\n    0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,\n    0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 852\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP852(0x80-0xFF) to Unicode conversion table */\n    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,\n    0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,\n    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,\n    0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,\n    0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,\n    0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 855\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP855(0x80-0xFF) to Unicode conversion table */\n    0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,\n    0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,\n    0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,\n    0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,\n    0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,\n    0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 857\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP857(0x80-0xFF) to Unicode conversion table */\n    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,\n    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,\n    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,\n    0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,\n    0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,\n    0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 860\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP860(0x80-0xFF) to Unicode conversion table */\n    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,\n    0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,\n    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 861\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP861(0x80-0xFF) to Unicode conversion table */\n    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,\n    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,\n    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 862\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP862(0x80-0xFF) to Unicode conversion table */\n    0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,\n    0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,\n    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 863\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP863(0x80-0xFF) to Unicode conversion table */\n    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,\n    0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,\n    0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,\n    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 864\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP864(0x80-0xFF) to Unicode conversion table */\n    0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,\n    0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,\n    0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,\n    0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,\n    0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,\n    0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,\n    0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,\n    0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000\n};\n\n#elif _CODE_PAGE == 865\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP865(0x80-0xFF) to Unicode conversion table */\n    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,\n    0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,\n    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 866\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP866(0x80-0xFF) to Unicode conversion table */\n    0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,\n    0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,\n    0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n    0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,\n    0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0\n};\n\n#elif _CODE_PAGE == 869\n#define _TBLDEF 1\nstatic\nconst WCHAR Tbl[] = {   /*  CP869(0x80-0xFF) to Unicode conversion table */\n    0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,\n    0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,\n    0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,\n    0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,\n    0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,\n    0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0\n};\n\n#endif\n\n\n#if !_TBLDEF || !_USE_LFN\n#error This file is not needed at current configuration. Remove from the project.\n#endif\n\n\n\n\nWCHAR ff_convert (  /* Converted character, Returns zero on error */\n    WCHAR   chr,    /* Character code to be converted */\n    UINT    dir     /* 0: Unicode to OEM code, 1: OEM code to Unicode */\n)\n{\n    WCHAR c;\n\n\n    if (chr < 0x80) {   /* ASCII */\n        c = chr;\n\n    } else {\n        if (dir) {      /* OEM code to Unicode */\n            c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80];\n\n        } else {        /* Unicode to OEM code */\n            for (c = 0; c < 0x80; c++) {\n                if (chr == Tbl[c]) break;\n            }\n            c = (c + 0x80) & 0xFF;\n        }\n    }\n\n    return c;\n}\n\n\n\nWCHAR ff_wtoupper ( /* Returns upper converted character */\n    WCHAR chr       /* Unicode character to be upper converted (BMP only) */\n)\n{\n    /* Compressed upper conversion table */\n    static const WCHAR cvt1[] = {   /* U+0000 - U+0FFF */\n        /* Basic Latin */\n        0x0061,0x031A,\n        /* Latin-1 Supplement */\n        0x00E0,0x0317,  0x00F8,0x0307,  0x00FF,0x0001,0x0178,\n        /* Latin Extended-A */\n        0x0100,0x0130,  0x0132,0x0106,  0x0139,0x0110,  0x014A,0x012E,  0x0179,0x0106,\n        /* Latin Extended-B */\n        0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA,\n        0x01CD,0x0110,  0x01DD,0x0001,0x018E,  0x01DE,0x0112,  0x01F3,0x0003,0x01F1,0x01F4,0x01F4,  0x01F8,0x0128,\n        0x0222,0x0112,  0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241,  0x0246,0x010A,\n        /* IPA Extensions */\n        0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7,\n        /* Greek, Coptic */\n        0x037B,0x0003,0x03FD,0x03FE,0x03FF,  0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A,  0x03B1,0x0311,\n        0x03C2,0x0002,0x03A3,0x03A3,  0x03C4,0x0308,  0x03CC,0x0003,0x038C,0x038E,0x038F,  0x03D8,0x0118,\n        0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA,\n        /* Cyrillic */\n        0x0430,0x0320,  0x0450,0x0710,  0x0460,0x0122,  0x048A,0x0136,  0x04C1,0x010E,  0x04CF,0x0001,0x04C0,  0x04D0,0x0144,\n        /* Armenian */\n        0x0561,0x0426,\n\n        0x0000\n    };\n    static const WCHAR cvt2[] = {   /* U+1000 - U+FFFF */\n        /* Phonetic Extensions */\n        0x1D7D,0x0001,0x2C63,\n        /* Latin Extended Additional */\n        0x1E00,0x0196,  0x1EA0,0x015A,\n        /* Greek Extended */\n        0x1F00,0x0608,  0x1F10,0x0606,  0x1F20,0x0608,  0x1F30,0x0608,  0x1F40,0x0606,\n        0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F,  0x1F60,0x0608,\n        0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB,\n        0x1F80,0x0608,  0x1F90,0x0608,  0x1FA0,0x0608,  0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,\n        0x1FCC,0x0001,0x1FC3,  0x1FD0,0x0602,  0x1FE0,0x0602,  0x1FE5,0x0001,0x1FEC,  0x1FF2,0x0001,0x1FFC,\n        /* Letterlike Symbols */\n        0x214E,0x0001,0x2132,\n        /* Number forms */\n        0x2170,0x0210,  0x2184,0x0001,0x2183,\n        /* Enclosed Alphanumerics */\n        0x24D0,0x051A,  0x2C30,0x042F,\n        /* Latin Extended-C */\n        0x2C60,0x0102,  0x2C67,0x0106, 0x2C75,0x0102,\n        /* Coptic */\n        0x2C80,0x0164,\n        /* Georgian Supplement */\n        0x2D00,0x0826,\n        /* Full-width */\n        0xFF41,0x031A,\n\n        0x0000\n    };\n    const WCHAR *p;\n    WCHAR bc, nc, cmd;\n\n\n    p = chr < 0x1000 ? cvt1 : cvt2;\n    for (;;) {\n        bc = *p++;                              /* Get block base */\n        if (!bc || chr < bc) break;\n        nc = *p++; cmd = nc >> 8; nc &= 0xFF;   /* Get processing command and block size */\n        if (chr < bc + nc) {    /* In the block? */\n            switch (cmd) {\n            case 0: chr = p[chr - bc]; break;       /* Table conversion */\n            case 1: chr -= (chr - bc) & 1; break;   /* Case pairs */\n            case 2: chr -= 16; break;               /* Shift -16 */\n            case 3: chr -= 32; break;               /* Shift -32 */\n            case 4: chr -= 48; break;               /* Shift -48 */\n            case 5: chr -= 26; break;               /* Shift -26 */\n            case 6: chr += 8; break;                /* Shift +8 */\n            case 7: chr -= 80; break;               /* Shift -80 */\n            case 8: chr -= 0x1C60; break;           /* Shift -0x1C60 */\n            }\n            break;\n        }\n        if (!cmd) p += nc;\n    }\n\n    return chr;\n}\n\n"
  },
  {
    "path": "lib/oofatfs/option/unicode.c",
    "content": "#include \"../ff.h\"\n\n#if _USE_LFN != 0\n\n#if   _CODE_PAGE == 932 /* Japanese Shift_JIS */\n#include \"cc932.c\"\n#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */\n#include \"cc936.c\"\n#elif _CODE_PAGE == 949 /* Korean */\n#include \"cc949.c\"\n#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */\n#include \"cc950.c\"\n#else                   /* Single Byte Character-Set */\n#include \"ccsbcs.c\"\n#endif\n\n#endif\n"
  },
  {
    "path": "lib/timeutils/timeutils.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2015 Daniel Campora\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/obj.h\"\n\n#include \"lib/timeutils/timeutils.h\"\n\n// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately\n// after Feb 29. We calculate seconds as a signed integer relative to that.\n//\n// Our timebase is relative to 2000-01-01.\n\n#define LEAPOCH ((31 + 29) * 86400)\n\n#define DAYS_PER_400Y (365*400 + 97)\n#define DAYS_PER_100Y (365*100 + 24)\n#define DAYS_PER_4Y   (365*4   + 1)\n\nSTATIC const uint16_t days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };\n\nbool timeutils_is_leap_year(mp_uint_t year) {\n    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;\n}\n\n// month is one based\nmp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month) {\n    mp_uint_t mdays = days_since_jan1[month] - days_since_jan1[month - 1];\n    if (month == 2 && timeutils_is_leap_year(year)) {\n        mdays++;\n    }\n    return mdays;\n}\n\n// compute the day of the year, between 1 and 366\n// month should be between 1 and 12, date should start at 1\nmp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) {\n    mp_uint_t yday = days_since_jan1[month - 1] + date;\n    if (month >= 3 && timeutils_is_leap_year(year)) {\n        yday += 1;\n    }\n    return yday;\n}\n\nvoid timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) {\n    // The following algorithm was adapted from musl's __secs_to_tm and adapted\n    // for differences in MicroPython's timebase.\n\n    mp_int_t seconds = t - LEAPOCH;\n\n    mp_int_t days = seconds / 86400;\n    seconds %= 86400;\n    if (seconds < 0) {\n        seconds += 86400;\n        days -= 1;\n    }\n    tm->tm_hour = seconds / 3600;\n    tm->tm_min = seconds / 60 % 60;\n    tm->tm_sec = seconds % 60;\n\n    mp_int_t wday = (days + 2) % 7;   // Mar 1, 2000 was a Wednesday (2)\n    if (wday < 0) {\n        wday += 7;\n    }\n    tm->tm_wday = wday;\n\n    mp_int_t qc_cycles = days / DAYS_PER_400Y;\n    days %= DAYS_PER_400Y;\n    if (days < 0) {\n        days += DAYS_PER_400Y;\n        qc_cycles--;\n    }\n    mp_int_t c_cycles = days / DAYS_PER_100Y;\n    if (c_cycles == 4) {\n        c_cycles--;\n    }\n    days -= (c_cycles * DAYS_PER_100Y);\n\n    mp_int_t q_cycles = days / DAYS_PER_4Y;\n    if (q_cycles == 25) {\n        q_cycles--;\n    }\n    days -= q_cycles * DAYS_PER_4Y;\n\n    mp_int_t years = days / 365;\n    if (years == 4) {\n        years--;\n    }\n    days -= (years * 365);\n\n    /* We will compute tm_yday at the very end\n    mp_int_t leap = !years && (q_cycles || !c_cycles);\n\n    tm->tm_yday = days + 31 + 28 + leap;\n    if (tm->tm_yday >= 365 + leap) {\n        tm->tm_yday -= 365 + leap;\n    }\n\n    tm->tm_yday++;  // Make one based\n    */\n\n    tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;\n\n    // Note: days_in_month[0] corresponds to March\n    STATIC const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29};\n\n    mp_int_t month;\n    for (month = 0; days_in_month[month] <= days; month++) {\n        days -= days_in_month[month];\n    }\n\n    tm->tm_mon = month + 2;\n    if (tm->tm_mon >= 12) {\n        tm->tm_mon -= 12;\n        tm->tm_year++;\n    }\n    tm->tm_mday = days + 1; // Make one based\n    tm->tm_mon++;   // Make one based\n\n    tm->tm_yday = timeutils_year_day(tm->tm_year, tm->tm_mon, tm->tm_mday);\n}\n\n// returns the number of seconds, as an integer, since 2000-01-01\nmp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month,\n    mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {\n    return\n        second\n        + minute * 60\n        + hour * 3600\n        + (timeutils_year_day(year, month, date) - 1\n            + ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001\n            - ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001\n            + ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001\n            ) * 86400\n        + (year - 2000) * 31536000;\n}\n\nmp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,\n    mp_int_t hours, mp_int_t minutes, mp_int_t seconds) {\n\n    // Normalize the tuple. This allows things like:\n    //\n    // tm_tomorrow = list(time.localtime())\n    // tm_tomorrow[2] += 1 # Adds 1 to mday\n    // tomorrow = time.mktime(tm_tomorrow)\n    //\n    // And not have to worry about all the weird overflows.\n    //\n    // You can subtract dates/times this way as well.\n\n    minutes += seconds / 60;\n    if ((seconds = seconds % 60) < 0) {\n        seconds += 60;\n        minutes--;\n    }\n\n    hours += minutes / 60;\n    if ((minutes = minutes % 60) < 0) {\n        minutes += 60;\n        hours--;\n    }\n\n    mday += hours / 24;\n    if ((hours = hours % 24) < 0) {\n        hours += 24;\n        mday--;\n    }\n\n    month--; // make month zero based\n    year += month / 12;\n    if ((month = month % 12) < 0) {\n        month += 12;\n        year--;\n    }\n    month++; // back to one based\n\n    while (mday < 1) {\n        if (--month == 0) {\n            month = 12;\n            year--;\n        }\n        mday += timeutils_days_in_month(year, month);\n    }\n    while ((mp_uint_t)mday > timeutils_days_in_month(year, month)) {\n        mday -= timeutils_days_in_month(year, month);\n        if (++month == 13) {\n            month = 1;\n            year++;\n        }\n    }\n    return timeutils_seconds_since_2000(year, month, mday, hours, minutes, seconds);\n}\n"
  },
  {
    "path": "lib/timeutils/timeutils.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2015 Daniel Campora\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H\n#define MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H\n\ntypedef struct _timeutils_struct_time_t {\n    uint16_t    tm_year;    // i.e. 2014\n    uint8_t     tm_mon;     // 1..12\n    uint8_t     tm_mday;    // 1..31\n    uint8_t     tm_hour;    // 0..23\n    uint8_t     tm_min;     // 0..59\n    uint8_t     tm_sec;     // 0..59\n    uint8_t     tm_wday;    // 0..6  0 = Monday\n    uint16_t    tm_yday;    // 1..366\n} timeutils_struct_time_t;\n\nbool timeutils_is_leap_year(mp_uint_t year);\nmp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month);\nmp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date);\n\nvoid timeutils_seconds_since_2000_to_struct_time(mp_uint_t t,\n    timeutils_struct_time_t *tm);\n\nmp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month,\n    mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second);\n\nmp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,\n    mp_int_t hours, mp_int_t minutes, mp_int_t seconds);\n\n#endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H\n"
  },
  {
    "path": "lib/utils/gchelper.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H\n#define MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H\n\n#include <stdint.h>\n\n#if MICROPY_GCREGS_SETJMP\n#include <setjmp.h>\ntypedef jmp_buf gc_helper_regs_t;\n#else\n\n#if defined(__x86_64__)\ntypedef uintptr_t gc_helper_regs_t[6];\n#elif defined(__i386__)\ntypedef uintptr_t gc_helper_regs_t[4];\n#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)\ntypedef uintptr_t gc_helper_regs_t[10];\n#endif\n\n#endif\n\nvoid gc_helper_collect_regs_and_stack(void);\n\n#endif // MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H\n"
  },
  {
    "path": "lib/utils/gchelper_m0.s",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n    .syntax unified\n    .cpu cortex-m0\n    .thumb\n\n    .section .text\n    .align 2\n\n    .global gc_helper_get_regs_and_sp\n    .type gc_helper_get_regs_and_sp, %function\n\n@ uint gc_helper_get_regs_and_sp(r0=uint regs[10])\ngc_helper_get_regs_and_sp:\n    @ store registers into given array\n    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\n    @ return the sp\n    mov    r0, sp\n    bx     lr\n\n    .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp\n"
  },
  {
    "path": "lib/utils/gchelper_m3.s",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n    .syntax unified\n    .cpu cortex-m3\n    .thumb\n\n    .section .text\n    .align  2\n\n    .global gc_helper_get_regs_and_sp\n    .type gc_helper_get_regs_and_sp, %function\n\n@ uint gc_helper_get_regs_and_sp(r0=uint regs[10])\ngc_helper_get_regs_and_sp:\n    @ store registers into given array\n    str     r4, [r0], #4\n    str     r5, [r0], #4\n    str     r6, [r0], #4\n    str     r7, [r0], #4\n    str     r8, [r0], #4\n    str     r9, [r0], #4\n    str     r10, [r0], #4\n    str     r11, [r0], #4\n    str     r12, [r0], #4\n    str     r13, [r0], #4\n\n    @ return the sp\n    mov     r0, sp\n    bx      lr\n\n    .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp\n"
  },
  {
    "path": "lib/utils/interrupt_char.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/obj.h\"\n#include \"py/mpstate.h\"\n\n#if MICROPY_KBD_EXCEPTION\n\nint mp_interrupt_char = -1;\n\nvoid mp_hal_set_interrupt_char(int c) {\n    mp_interrupt_char = c;\n}\n\n#endif\n"
  },
  {
    "path": "lib/utils/interrupt_char.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_LIB_UTILS_INTERRUPT_CHAR_H\n#define MICROPY_INCLUDED_LIB_UTILS_INTERRUPT_CHAR_H\n\nextern int mp_interrupt_char;\nvoid mp_hal_set_interrupt_char(int c);\n\n#endif // MICROPY_INCLUDED_LIB_UTILS_INTERRUPT_CHAR_H\n"
  },
  {
    "path": "lib/utils/mpirq.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 Daniel Campora\n *               2018 Tobias Badertscher\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n\n#include \"py/runtime.h\"\n#include \"py/gc.h\"\n#include \"lib/utils/mpirq.h\"\n\n#if MICROPY_ENABLE_SCHEDULER\n\n/******************************************************************************\n DECLARE PUBLIC DATA\n ******************************************************************************/\n\nconst mp_arg_t mp_irq_init_args[] = {\n    { MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n    { MP_QSTR_trigger, MP_ARG_INT, {.u_int = 0} },\n    { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },\n};\n\n/******************************************************************************\n DECLARE PRIVATE DATA\n ******************************************************************************/\n\n/******************************************************************************\n DEFINE PUBLIC FUNCTIONS\n ******************************************************************************/\n\nmp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent) {\n    mp_irq_obj_t *self = m_new0(mp_irq_obj_t, 1);\n    mp_irq_init(self, methods, parent);\n    return self;\n}\n\nvoid mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent) {\n    self->base.type = &mp_irq_type;\n    self->methods = (mp_irq_methods_t *)methods;\n    self->parent = parent;\n    self->handler = mp_const_none;\n    self->ishard = false;\n}\n\nvoid mp_irq_handler(mp_irq_obj_t *self) {\n    if (self->handler != mp_const_none) {\n        if (self->ishard) {\n            // When executing code within a handler we must lock the scheduler to\n            // prevent any scheduled callbacks from running, and lock the GC to\n            // prevent any memory allocations.\n            mp_sched_lock();\n            gc_lock();\n            nlr_buf_t nlr;\n            if (nlr_push(&nlr) == 0) {\n                mp_call_function_1(self->handler, self->parent);\n                nlr_pop();\n            } else {\n                // Uncaught exception; disable the callback so that it doesn't run again\n                self->methods->trigger(self->parent, 0);\n                self->handler = mp_const_none;\n                printf(\"Uncaught exception in IRQ callback handler\\n\");\n                mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));\n            }\n            gc_unlock();\n            mp_sched_unlock();\n        } else {\n            // Schedule call to user function\n            mp_sched_schedule(self->handler, self->parent);\n        }\n    }\n}\n\n/******************************************************************************/\n// MicroPython bindings\n\nSTATIC mp_obj_t mp_irq_flags(mp_obj_t self_in) {\n    mp_irq_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    return mp_obj_new_int(self->methods->info(self->parent, MP_IRQ_INFO_FLAGS));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_flags_obj, mp_irq_flags);\n\nSTATIC mp_obj_t mp_irq_trigger(size_t n_args, const mp_obj_t *args) {\n    mp_irq_obj_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_obj_t ret_obj = mp_obj_new_int(self->methods->info(self->parent, MP_IRQ_INFO_TRIGGERS));\n    if (n_args == 2) {\n        // Set trigger\n        self->methods->trigger(self->parent, mp_obj_get_int(args[1]));\n    }\n    return ret_obj;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_irq_trigger_obj, 1, 2, mp_irq_trigger);\n\nSTATIC mp_obj_t mp_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 0, 0, false);\n    mp_irq_handler(MP_OBJ_TO_PTR(self_in));\n    return mp_const_none;\n}\n\nSTATIC const mp_rom_map_elem_t mp_irq_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_flags),               MP_ROM_PTR(&mp_irq_flags_obj) },\n    { MP_ROM_QSTR(MP_QSTR_trigger),             MP_ROM_PTR(&mp_irq_trigger_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(mp_irq_locals_dict, mp_irq_locals_dict_table);\n\nconst mp_obj_type_t mp_irq_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_irq,\n    .call = mp_irq_call,\n    .locals_dict = (mp_obj_dict_t *)&mp_irq_locals_dict,\n};\n\n#endif // MICROPY_ENABLE_SCHEDULER\n"
  },
  {
    "path": "lib/utils/mpirq.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 Daniel Campora\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H\n#define MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H\n\n#include \"py/runtime.h\"\n\n/******************************************************************************\n DEFINE CONSTANTS\n ******************************************************************************/\n\nenum {\n    MP_IRQ_ARG_INIT_handler = 0,\n    MP_IRQ_ARG_INIT_trigger,\n    MP_IRQ_ARG_INIT_hard,\n    MP_IRQ_ARG_INIT_NUM_ARGS,\n};\n\n/******************************************************************************\n DEFINE TYPES\n ******************************************************************************/\n\ntypedef mp_uint_t (*mp_irq_trigger_fun_t)(mp_obj_t self, mp_uint_t trigger);\ntypedef mp_uint_t (*mp_irq_info_fun_t)(mp_obj_t self, mp_uint_t info_type);\n\nenum {\n    MP_IRQ_INFO_FLAGS,\n    MP_IRQ_INFO_TRIGGERS,\n};\n\ntypedef struct _mp_irq_methods_t {\n    mp_irq_trigger_fun_t trigger;\n    mp_irq_info_fun_t info;\n} mp_irq_methods_t;\n\ntypedef struct _mp_irq_obj_t {\n    mp_obj_base_t base;\n    mp_irq_methods_t *methods;\n    mp_obj_t parent;\n    mp_obj_t handler;\n    bool ishard;\n} mp_irq_obj_t;\n\n/******************************************************************************\n DECLARE EXPORTED DATA\n ******************************************************************************/\n\nextern const mp_arg_t mp_irq_init_args[];\nextern const mp_obj_type_t mp_irq_type;\n\n/******************************************************************************\n DECLARE PUBLIC FUNCTIONS\n ******************************************************************************/\n\nmp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent);\nvoid mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent);\nvoid mp_irq_handler(mp_irq_obj_t *self);\n\n#endif // MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H\n"
  },
  {
    "path": "lib/utils/printf.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n\n#include <stdint.h>\n#include <string.h>\n#include <stdarg.h>\n\n#include \"py/obj.h\"\n#include \"py/mphal.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT\n#include \"py/formatfloat.h\"\n#endif\n\n#if MICROPY_DEBUG_PRINTERS\nint DEBUG_printf(const char *fmt, ...) {\n    va_list ap;\n    va_start(ap, fmt);\n    int ret = mp_vprintf(MICROPY_DEBUG_PRINTER, fmt, ap);\n    va_end(ap);\n    return ret;\n}\n#endif\n\n#if MICROPY_USE_INTERNAL_PRINTF\n\n#undef putchar  // Some stdlibs have a #define for putchar\nint printf(const char *fmt, ...);\nint vprintf(const char *fmt, va_list ap);\nint putchar(int c);\nint puts(const char *s);\nint vsnprintf(char *str, size_t size, const char *fmt, va_list ap);\nint snprintf(char *str, size_t size, const char *fmt, ...);\n\nint printf(const char *fmt, ...) {\n    va_list ap;\n    va_start(ap, fmt);\n    int ret = mp_vprintf(&mp_plat_print, fmt, ap);\n    va_end(ap);\n    return ret;\n}\n\nint vprintf(const char *fmt, va_list ap) {\n    return mp_vprintf(&mp_plat_print, fmt, ap);\n}\n\n// need this because gcc optimises printf(\"%c\", c) -> putchar(c), and printf(\"a\") -> putchar('a')\nint putchar(int c) {\n    char chr = c;\n    mp_hal_stdout_tx_strn_cooked(&chr, 1);\n    return chr;\n}\n\n// need this because gcc optimises printf(\"string\\n\") -> puts(\"string\")\nint puts(const char *s) {\n    mp_hal_stdout_tx_strn_cooked(s, strlen(s));\n    char chr = '\\n';\n    mp_hal_stdout_tx_strn_cooked(&chr, 1);\n    return 1;\n}\n\ntypedef struct _strn_print_env_t {\n    char *cur;\n    size_t remain;\n} strn_print_env_t;\n\nSTATIC void strn_print_strn(void *data, const char *str, size_t len) {\n    strn_print_env_t *strn_print_env = data;\n    if (len > strn_print_env->remain) {\n        len = strn_print_env->remain;\n    }\n    memcpy(strn_print_env->cur, str, len);\n    strn_print_env->cur += len;\n    strn_print_env->remain -= len;\n}\n\n#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 9\n// uClibc requires this alias to be defined, or there may be link errors\n// when linkings against it statically.\n// GCC 9 gives a warning about missing attributes so it's excluded until\n// uClibc+GCC9 support is needed.\nint __GI_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) __attribute__((weak, alias(\"vsnprintf\")));\n#endif\n\nint vsnprintf(char *str, size_t size, const char *fmt, va_list ap) {\n    strn_print_env_t strn_print_env = {str, size};\n    mp_print_t print = {&strn_print_env, strn_print_strn};\n    int len = mp_vprintf(&print, fmt, ap);\n    // add terminating null byte\n    if (size > 0) {\n        if (strn_print_env.remain == 0) {\n            strn_print_env.cur[-1] = 0;\n        } else {\n            strn_print_env.cur[0] = 0;\n        }\n    }\n    return len;\n}\n\nint snprintf(char *str, size_t size, const char *fmt, ...) {\n    va_list ap;\n    va_start(ap, fmt);\n    int ret = vsnprintf(str, size, fmt, ap);\n    va_end(ap);\n    return ret;\n}\n\n#endif // MICROPY_USE_INTERNAL_PRINTF\n"
  },
  {
    "path": "lib/utils/pyexec.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/compile.h\"\n#include \"py/runtime.h\"\n#include \"py/repl.h\"\n#include \"py/gc.h\"\n#include \"py/frozenmod.h\"\n#include \"py/mphal.h\"\n#if MICROPY_HW_ENABLE_USB\n#include \"irq.h\"\n#include \"usb.h\"\n#endif\n#include \"lib/mp-readline/readline.h\"\n#include \"lib/utils/pyexec.h\"\n#include \"genhdr/mpversion.h\"\n\npyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;\nint pyexec_system_exit = 0;\n\n#if MICROPY_REPL_INFO\nSTATIC bool repl_display_debugging_info = 0;\n#endif\n\n#define EXEC_FLAG_PRINT_EOF (1)\n#define EXEC_FLAG_ALLOW_DEBUGGING (2)\n#define EXEC_FLAG_IS_REPL (4)\n#define EXEC_FLAG_RERAISE (8)\n#define EXEC_FLAG_SOURCE_IS_RAW_CODE (16)\n#define EXEC_FLAG_SOURCE_IS_VSTR (32)\n#define EXEC_FLAG_SOURCE_IS_FILENAME (64)\n\n// parses, compiles and executes the code in the lexer\n// frees the lexer before returning\n// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output\n// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code\n// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)\nSTATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags) {\n    int ret = 0;\n    #if MICROPY_REPL_INFO\n    uint32_t start = 0;\n    #endif\n\n    // by default a SystemExit exception returns 0\n    pyexec_system_exit = 0;\n\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        mp_obj_t module_fun;\n        #if MICROPY_MODULE_FROZEN_MPY\n        if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) {\n            // source is a raw_code object, create the function\n            module_fun = mp_make_function_from_raw_code(source, MP_OBJ_NULL, MP_OBJ_NULL);\n        } else\n        #endif\n        {\n            #if MICROPY_ENABLE_COMPILER\n            mp_lexer_t *lex;\n            if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) {\n                const vstr_t *vstr = source;\n                lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0);\n            } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) {\n                lex = mp_lexer_new_from_file(source);\n            } else {\n                lex = (mp_lexer_t *)source;\n            }\n            // source is a lexer, parse and compile the script\n            qstr source_name = lex->source_name;\n            mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);\n            module_fun = mp_compile(&parse_tree, source_name, exec_flags & EXEC_FLAG_IS_REPL);\n            #else\n            mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"script compilation not supported\"));\n            #endif\n        }\n\n        // execute code\n        mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us\n        #if MICROPY_REPL_INFO\n        start = mp_hal_ticks_ms();\n        #endif\n        mp_call_function_0(module_fun);\n        mp_hal_set_interrupt_char(-1); // disable interrupt\n        mp_handle_pending(true); // handle any pending exceptions (and any callbacks)\n        nlr_pop();\n        ret = 1;\n        if (exec_flags & EXEC_FLAG_PRINT_EOF) {\n            mp_hal_stdout_tx_strn(\"\\x04\", 1);\n        }\n    } else {\n        // uncaught exception\n        mp_hal_set_interrupt_char(-1); // disable interrupt\n        mp_handle_pending(false); // clear any pending exceptions (and run any callbacks)\n        // print EOF after normal output\n        if (exec_flags & EXEC_FLAG_PRINT_EOF) {\n            mp_hal_stdout_tx_strn(\"\\x04\", 1);\n        }\n        // check for SystemExit\n        if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {\n            // at the moment, the value of SystemExit is unused\n            ret = pyexec_system_exit;\n        } else {\n            mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));\n            ret = 0;\n        }\n    }\n\n    #if MICROPY_REPL_INFO\n    // display debugging info if wanted\n    if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {\n        mp_uint_t ticks = mp_hal_ticks_ms() - start; // TODO implement a function that does this properly\n        printf(\"took \" UINT_FMT \" ms\\n\", ticks);\n        // qstr info\n        {\n            size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;\n            qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);\n            printf(\"qstr:\\n  n_pool=%u\\n  n_qstr=%u\\n  \"\n                \"n_str_data_bytes=%u\\n  n_total_bytes=%u\\n\",\n                (unsigned)n_pool, (unsigned)n_qstr, (unsigned)n_str_data_bytes, (unsigned)n_total_bytes);\n        }\n\n        #if MICROPY_ENABLE_GC\n        // run collection and print GC info\n        gc_collect();\n        gc_dump_info();\n        #endif\n    }\n    #endif\n\n    if (exec_flags & EXEC_FLAG_PRINT_EOF) {\n        mp_hal_stdout_tx_strn(\"\\x04\", 1);\n    }\n\n    return ret;\n}\n\n#if MICROPY_ENABLE_COMPILER\n#if MICROPY_REPL_EVENT_DRIVEN\n\ntypedef struct _repl_t {\n    // This structure originally also held current REPL line,\n    // but it was moved to MP_STATE_VM(repl_line) as containing\n    // root pointer. Still keep structure in case more state\n    // will be added later.\n    // vstr_t line;\n    bool cont_line;\n    bool paste_mode;\n} repl_t;\n\nrepl_t repl;\n\nSTATIC int pyexec_raw_repl_process_char(int c);\nSTATIC int pyexec_friendly_repl_process_char(int c);\n\nvoid pyexec_event_repl_init(void) {\n    MP_STATE_VM(repl_line) = vstr_new(32);\n    repl.cont_line = false;\n    repl.paste_mode = false;\n    // no prompt before printing friendly REPL banner or entering raw REPL\n    readline_init(MP_STATE_VM(repl_line), \"\");\n    if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {\n        pyexec_raw_repl_process_char(CHAR_CTRL_A);\n    } else {\n        pyexec_friendly_repl_process_char(CHAR_CTRL_B);\n    }\n}\n\nSTATIC int pyexec_raw_repl_process_char(int c) {\n    if (c == CHAR_CTRL_A) {\n        // reset raw REPL\n        mp_hal_stdout_tx_str(\"raw REPL; CTRL-B to exit\\r\\n\");\n        goto reset;\n    } else if (c == CHAR_CTRL_B) {\n        // change to friendly REPL\n        pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;\n        vstr_reset(MP_STATE_VM(repl_line));\n        repl.cont_line = false;\n        repl.paste_mode = false;\n        pyexec_friendly_repl_process_char(CHAR_CTRL_B);\n        return 0;\n    } else if (c == CHAR_CTRL_C) {\n        // clear line\n        vstr_reset(MP_STATE_VM(repl_line));\n        return 0;\n    } else if (c == CHAR_CTRL_D) {\n        // input finished\n    } else {\n        // let through any other raw 8-bit value\n        vstr_add_byte(MP_STATE_VM(repl_line), c);\n        return 0;\n    }\n\n    // indicate reception of command\n    mp_hal_stdout_tx_str(\"OK\");\n\n    if (MP_STATE_VM(repl_line)->len == 0) {\n        // exit for a soft reset\n        mp_hal_stdout_tx_str(\"\\r\\n\");\n        vstr_clear(MP_STATE_VM(repl_line));\n        return PYEXEC_FORCED_EXIT;\n    }\n\n    int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR);\n    if (ret & PYEXEC_FORCED_EXIT) {\n        return ret;\n    }\n\nreset:\n    vstr_reset(MP_STATE_VM(repl_line));\n    mp_hal_stdout_tx_str(\">\");\n\n    return 0;\n}\n\nSTATIC int pyexec_friendly_repl_process_char(int c) {\n    if (repl.paste_mode) {\n        if (c == CHAR_CTRL_C) {\n            // cancel everything\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            goto input_restart;\n        } else if (c == CHAR_CTRL_D) {\n            // end of input\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_FILE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR);\n            if (ret & PYEXEC_FORCED_EXIT) {\n                return ret;\n            }\n            goto input_restart;\n        } else {\n            // add char to buffer and echo\n            vstr_add_byte(MP_STATE_VM(repl_line), c);\n            if (c == '\\r') {\n                mp_hal_stdout_tx_str(\"\\r\\n=== \");\n            } else {\n                char buf[1] = {c};\n                mp_hal_stdout_tx_strn(buf, 1);\n            }\n            return 0;\n        }\n    }\n\n    int ret = readline_process_char(c);\n\n    if (!repl.cont_line) {\n\n        if (ret == CHAR_CTRL_A) {\n            // change to raw REPL\n            pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            pyexec_raw_repl_process_char(CHAR_CTRL_A);\n            return 0;\n        } else if (ret == CHAR_CTRL_B) {\n            // reset friendly REPL\n            mp_hal_stdout_tx_str(\"\\r\\n\");\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\");\n            #if MICROPY_PY_BUILTINS_HELP\n            mp_hal_stdout_tx_str(\"Type \\\"help()\\\" for more information.\\r\\n\");\n            #endif\n            goto input_restart;\n        } else if (ret == CHAR_CTRL_C) {\n            // break\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            goto input_restart;\n        } else if (ret == CHAR_CTRL_D) {\n            // exit for a soft reset\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            vstr_clear(MP_STATE_VM(repl_line));\n            return PYEXEC_FORCED_EXIT;\n        } else if (ret == CHAR_CTRL_E) {\n            // paste mode\n            mp_hal_stdout_tx_str(\"\\r\\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\\r\\n=== \");\n            vstr_reset(MP_STATE_VM(repl_line));\n            repl.paste_mode = true;\n            return 0;\n        }\n\n        if (ret < 0) {\n            return 0;\n        }\n\n        if (!mp_repl_continue_with_input(vstr_null_terminated_str(MP_STATE_VM(repl_line)))) {\n            goto exec;\n        }\n\n        vstr_add_byte(MP_STATE_VM(repl_line), '\\n');\n        repl.cont_line = true;\n        readline_note_newline(\"... \");\n        return 0;\n\n    } else {\n\n        if (ret == CHAR_CTRL_C) {\n            // cancel everything\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            repl.cont_line = false;\n            goto input_restart;\n        } else if (ret == CHAR_CTRL_D) {\n            // stop entering compound statement\n            goto exec;\n        }\n\n        if (ret < 0) {\n            return 0;\n        }\n\n        if (mp_repl_continue_with_input(vstr_null_terminated_str(MP_STATE_VM(repl_line)))) {\n            vstr_add_byte(MP_STATE_VM(repl_line), '\\n');\n            readline_note_newline(\"... \");\n            return 0;\n        }\n\n    exec:;\n        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);\n        if (ret & PYEXEC_FORCED_EXIT) {\n            return ret;\n        }\n\n    input_restart:\n        vstr_reset(MP_STATE_VM(repl_line));\n        repl.cont_line = false;\n        repl.paste_mode = false;\n        readline_init(MP_STATE_VM(repl_line), \">>> \");\n        return 0;\n    }\n}\n\nuint8_t pyexec_repl_active;\nint pyexec_event_repl_process_char(int c) {\n    pyexec_repl_active = 1;\n    int res;\n    if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {\n        res = pyexec_raw_repl_process_char(c);\n    } else {\n        res = pyexec_friendly_repl_process_char(c);\n    }\n    pyexec_repl_active = 0;\n    return res;\n}\n\n#else // MICROPY_REPL_EVENT_DRIVEN\n\nint pyexec_raw_repl(void) {\n    vstr_t line;\n    vstr_init(&line, 32);\n\nraw_repl_reset:\n    mp_hal_stdout_tx_str(\"raw REPL; CTRL-B to exit\\r\\n\");\n\n    for (;;) {\n        vstr_reset(&line);\n        mp_hal_stdout_tx_str(\">\");\n        for (;;) {\n            int c = mp_hal_stdin_rx_chr();\n            if (c == CHAR_CTRL_A) {\n                // reset raw REPL\n                goto raw_repl_reset;\n            } else if (c == CHAR_CTRL_B) {\n                // change to friendly REPL\n                mp_hal_stdout_tx_str(\"\\r\\n\");\n                vstr_clear(&line);\n                pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;\n                return 0;\n            } else if (c == CHAR_CTRL_C) {\n                // clear line\n                vstr_reset(&line);\n            } else if (c == CHAR_CTRL_D) {\n                // input finished\n                break;\n            } else {\n                // let through any other raw 8-bit value\n                vstr_add_byte(&line, c);\n            }\n        }\n\n        // indicate reception of command\n        mp_hal_stdout_tx_str(\"OK\");\n\n        if (line.len == 0) {\n            // exit for a soft reset\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            vstr_clear(&line);\n            return PYEXEC_FORCED_EXIT;\n        }\n\n        int ret = parse_compile_execute(&line, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR);\n        if (ret & PYEXEC_FORCED_EXIT) {\n            return ret;\n        }\n    }\n}\n\nint pyexec_friendly_repl(void) {\n    vstr_t line;\n    vstr_init(&line, 32);\n\n    #if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD\n    // in host mode, we enable the LCD for the repl\n    mp_obj_t lcd_o = mp_call_function_0(mp_load_name(qstr_from_str(\"LCD\")));\n    mp_call_function_1(mp_load_attr(lcd_o, qstr_from_str(\"light\")), mp_const_true);\n    #endif\n\nfriendly_repl_reset:\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\");\n    #if MICROPY_PY_BUILTINS_HELP\n    mp_hal_stdout_tx_str(\"Type \\\"help()\\\" for more information.\\r\\n\");\n    #endif\n\n    // to test ctrl-C\n    /*\n    {\n        uint32_t x[4] = {0x424242, 0xdeaddead, 0x242424, 0xdeadbeef};\n        for (;;) {\n            nlr_buf_t nlr;\n            printf(\"pyexec_repl: %p\\n\", x);\n            mp_hal_set_interrupt_char(CHAR_CTRL_C);\n            if (nlr_push(&nlr) == 0) {\n                for (;;) {\n                }\n            } else {\n                printf(\"break\\n\");\n            }\n        }\n    }\n    */\n\n    for (;;) {\n    input_restart:\n\n        #if MICROPY_HW_ENABLE_USB\n        if (usb_vcp_is_enabled()) {\n            // If the user gets to here and interrupts are disabled then\n            // they'll never see the prompt, traceback etc. The USB REPL needs\n            // interrupts to be enabled or no transfers occur. So we try to\n            // do the user a favor and reenable interrupts.\n            if (query_irq() == IRQ_STATE_DISABLED) {\n                enable_irq(IRQ_STATE_ENABLED);\n                mp_hal_stdout_tx_str(\"MPY: enabling IRQs\\r\\n\");\n            }\n        }\n        #endif\n\n        // If the GC is locked at this point there is no way out except a reset,\n        // so force the GC to be unlocked to help the user debug what went wrong.\n        if (MP_STATE_MEM(gc_lock_depth) != 0) {\n            MP_STATE_MEM(gc_lock_depth) = 0;\n        }\n\n        vstr_reset(&line);\n        int ret = readline(&line, \">>> \");\n        mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT;\n\n        if (ret == CHAR_CTRL_A) {\n            // change to raw REPL\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            vstr_clear(&line);\n            pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;\n            return 0;\n        } else if (ret == CHAR_CTRL_B) {\n            // reset friendly REPL\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            goto friendly_repl_reset;\n        } else if (ret == CHAR_CTRL_C) {\n            // break\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            continue;\n        } else if (ret == CHAR_CTRL_D) {\n            // exit for a soft reset\n            mp_hal_stdout_tx_str(\"\\r\\n\");\n            vstr_clear(&line);\n            return PYEXEC_FORCED_EXIT;\n        } else if (ret == CHAR_CTRL_E) {\n            // paste mode\n            mp_hal_stdout_tx_str(\"\\r\\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\\r\\n=== \");\n            vstr_reset(&line);\n            for (;;) {\n                char c = mp_hal_stdin_rx_chr();\n                if (c == CHAR_CTRL_C) {\n                    // cancel everything\n                    mp_hal_stdout_tx_str(\"\\r\\n\");\n                    goto input_restart;\n                } else if (c == CHAR_CTRL_D) {\n                    // end of input\n                    mp_hal_stdout_tx_str(\"\\r\\n\");\n                    break;\n                } else {\n                    // add char to buffer and echo\n                    vstr_add_byte(&line, c);\n                    if (c == '\\r') {\n                        mp_hal_stdout_tx_str(\"\\r\\n=== \");\n                    } else {\n                        mp_hal_stdout_tx_strn(&c, 1);\n                    }\n                }\n            }\n            parse_input_kind = MP_PARSE_FILE_INPUT;\n        } else if (vstr_len(&line) == 0) {\n            continue;\n        } else {\n            // got a line with non-zero length, see if it needs continuing\n            while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {\n                vstr_add_byte(&line, '\\n');\n                ret = readline(&line, \"... \");\n                if (ret == CHAR_CTRL_C) {\n                    // cancel everything\n                    mp_hal_stdout_tx_str(\"\\r\\n\");\n                    goto input_restart;\n                } else if (ret == CHAR_CTRL_D) {\n                    // stop entering compound statement\n                    break;\n                }\n            }\n        }\n\n        ret = parse_compile_execute(&line, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR);\n        if (ret & PYEXEC_FORCED_EXIT) {\n            return ret;\n        }\n    }\n}\n\n#endif // MICROPY_REPL_EVENT_DRIVEN\n#endif // MICROPY_ENABLE_COMPILER\n\nint pyexec_file(const char *filename) {\n    return parse_compile_execute(filename, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_FILENAME);\n}\nint pyexec_str(vstr_t *str) {\n    return parse_compile_execute(str, MP_PARSE_FILE_INPUT, EXEC_FLAG_RERAISE | EXEC_FLAG_SOURCE_IS_VSTR);\n}\n\nint pyexec_file_if_exists(const char *filename) {\n    #if MICROPY_MODULE_FROZEN\n    if (mp_frozen_stat(filename) == MP_IMPORT_STAT_FILE) {\n        return pyexec_frozen_module(filename);\n    }\n    #endif\n    if (mp_import_stat(filename) != MP_IMPORT_STAT_FILE) {\n        return 1; // success (no file is the same as an empty file executing without fail)\n    }\n    return pyexec_file(filename);\n}\n\n#if MICROPY_MODULE_FROZEN\nint pyexec_frozen_module(const char *name) {\n    void *frozen_data;\n    int frozen_type = mp_find_frozen_module(name, strlen(name), &frozen_data);\n\n    switch (frozen_type) {\n        #if MICROPY_MODULE_FROZEN_STR\n        case MP_FROZEN_STR:\n            return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, 0);\n        #endif\n\n        #if MICROPY_MODULE_FROZEN_MPY\n        case MP_FROZEN_MPY:\n            return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_RAW_CODE);\n        #endif\n\n        default:\n            printf(\"could not find module '%s'\\n\", name);\n            return false;\n    }\n}\n#endif\n\n#if MICROPY_REPL_INFO\nmp_obj_t pyb_set_repl_info(mp_obj_t o_value) {\n    repl_display_debugging_info = mp_obj_get_int(o_value);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info);\n#endif\n"
  },
  {
    "path": "lib/utils/pyexec.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H\n#define MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H\n\n#include \"py/obj.h\"\n\ntypedef enum {\n    PYEXEC_MODE_FRIENDLY_REPL,\n    PYEXEC_MODE_RAW_REPL,\n} pyexec_mode_kind_t;\n\nextern pyexec_mode_kind_t pyexec_mode_kind;\n\n// Set this to the value (eg PYEXEC_FORCED_EXIT) that will be propagated through\n// the pyexec functions if a SystemExit exception is raised by the running code.\n// It will reset to 0 at the start of each execution (eg each REPL entry).\nextern int pyexec_system_exit;\n\n#define PYEXEC_FORCED_EXIT (0x100)\n#define PYEXEC_SWITCH_MODE (0x200)\n\nint pyexec_raw_repl(void);\nint pyexec_friendly_repl(void);\nint pyexec_file(const char *filename);\nint pyexec_file_if_exists(const char *filename);\nint pyexec_frozen_module(const char *name);\nvoid pyexec_event_repl_init(void);\nint pyexec_event_repl_process_char(int c);\nextern uint8_t pyexec_repl_active;\n\n#if MICROPY_REPL_INFO\nmp_obj_t pyb_set_repl_info(mp_obj_t o_value);\nMP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj);\n#endif\n\n#endif // MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H\n"
  },
  {
    "path": "lib/utils/stdout_helpers.c",
    "content": "#include <string.h>\n#include <unistd.h>\n#include \"py/mpconfig.h\"\n#include \"py/mphal.h\"\n\n/*\n * Extra stdout functions\n * These can be either optimized for a particular port, or reference\n * implementation below can be used.\n */\n\n// Send \"cooked\" string of given length, where every occurrence of\n// LF character is replaced with CR LF.\nvoid mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {\n    while (len--) {\n        if (*str == '\\n') {\n            mp_hal_stdout_tx_strn(\"\\r\", 1);\n        }\n        mp_hal_stdout_tx_strn(str++, 1);\n    }\n}\n\n// Send zero-terminated string\nvoid mp_hal_stdout_tx_str(const char *str) {\n    mp_hal_stdout_tx_strn(str, strlen(str));\n}\n"
  },
  {
    "path": "lib/utils/sys_stdio_mphal.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2019 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/obj.h\"\n#include \"py/stream.h\"\n#include \"py/mperrno.h\"\n#include \"py/mphal.h\"\n\n// TODO make stdin, stdout and stderr writable objects so they can\n// be changed by Python code.  This requires some changes, as these\n// objects are in a read-only module (py/modsys.c).\n\n/******************************************************************************/\n// MicroPython bindings\n\n#define STDIO_FD_IN  (0)\n#define STDIO_FD_OUT (1)\n#define STDIO_FD_ERR (2)\n\ntypedef struct _sys_stdio_obj_t {\n    mp_obj_base_t base;\n    int fd;\n} sys_stdio_obj_t;\n\n#if MICROPY_PY_SYS_STDIO_BUFFER\nSTATIC const sys_stdio_obj_t stdio_buffer_obj;\n#endif\n\nvoid stdio_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    sys_stdio_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<io.FileIO %d>\", self->fd);\n}\n\nSTATIC mp_uint_t stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {\n    sys_stdio_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->fd == STDIO_FD_IN) {\n        for (uint i = 0; i < size; i++) {\n            int c = mp_hal_stdin_rx_chr();\n            if (c == '\\r') {\n                c = '\\n';\n            }\n            ((byte *)buf)[i] = c;\n        }\n        return size;\n    } else {\n        *errcode = MP_EPERM;\n        return MP_STREAM_ERROR;\n    }\n}\n\nSTATIC mp_uint_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {\n    sys_stdio_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->fd == STDIO_FD_OUT || self->fd == STDIO_FD_ERR) {\n        mp_hal_stdout_tx_strn_cooked(buf, size);\n        return size;\n    } else {\n        *errcode = MP_EPERM;\n        return MP_STREAM_ERROR;\n    }\n}\n\n// TODO NOT IMPLEMENT STDIO_IOCTL ON RT-THREAD YET\n// STATIC mp_uint_t stdio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n//     (void)self_in;\n//     if (request == MP_STREAM_POLL) {\n//         return mp_hal_stdio_poll(arg);\n//     } else {\n//         *errcode = MP_EINVAL;\n//         return MP_STREAM_ERROR;\n//     }\n// }\n\nSTATIC mp_obj_t stdio_obj___exit__(size_t n_args, const mp_obj_t *args) {\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stdio_obj___exit___obj, 4, 4, stdio_obj___exit__);\n\n// TODO gc hook to close the file if not already closed\n\nSTATIC const mp_rom_map_elem_t stdio_locals_dict_table[] = {\n    #if MICROPY_PY_SYS_STDIO_BUFFER\n    { MP_ROM_QSTR(MP_QSTR_buffer), MP_ROM_PTR(&stdio_buffer_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},\n    { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)},\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_identity_obj) },\n    { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_identity_obj) },\n    { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },\n    { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stdio_obj___exit___obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(stdio_locals_dict, stdio_locals_dict_table);\n\nSTATIC const mp_stream_p_t stdio_obj_stream_p = {\n    .read = stdio_read,\n    .write = stdio_write,\n    //.ioctl = stdio_ioctl,\n    .is_text = true,\n};\n\nSTATIC const mp_obj_type_t stdio_obj_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_FileIO,\n    // TODO .make_new?\n    .print = stdio_obj_print,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &stdio_obj_stream_p,\n    .locals_dict = (mp_obj_dict_t *)&stdio_locals_dict,\n};\n\nconst sys_stdio_obj_t mp_sys_stdin_obj = {{&stdio_obj_type}, .fd = STDIO_FD_IN};\nconst sys_stdio_obj_t mp_sys_stdout_obj = {{&stdio_obj_type}, .fd = STDIO_FD_OUT};\nconst sys_stdio_obj_t mp_sys_stderr_obj = {{&stdio_obj_type}, .fd = STDIO_FD_ERR};\n\n#if MICROPY_PY_SYS_STDIO_BUFFER\nSTATIC mp_uint_t stdio_buffer_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {\n    for (uint i = 0; i < size; i++) {\n        ((byte *)buf)[i] = mp_hal_stdin_rx_chr();\n    }\n    return size;\n}\n\nSTATIC mp_uint_t stdio_buffer_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {\n    mp_hal_stdout_tx_strn(buf, size);\n    return size;\n}\n\nSTATIC const mp_stream_p_t stdio_buffer_obj_stream_p = {\n    .read = stdio_buffer_read,\n    .write = stdio_buffer_write,\n    .ioctl = stdio_ioctl,\n    .is_text = false,\n};\n\nSTATIC const mp_obj_type_t stdio_buffer_obj_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_FileIO,\n    .print = stdio_obj_print,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &stdio_buffer_obj_stream_p,\n    .locals_dict = (mp_obj_dict_t *)&stdio_locals_dict,\n};\n\nSTATIC const sys_stdio_obj_t stdio_buffer_obj = {{&stdio_buffer_obj_type}, .fd = 0}; // fd unused\n#endif\n"
  },
  {
    "path": "port/frozen_mpy.c",
    "content": "#include \"py/mpconfig.h\"\n#include \"py/objint.h\"\n#include \"py/objstr.h\"\n#include \"py/emitglue.h\"\n#include \"py/nativeglue.h\"\n\n#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE != 0\n#error \"incompatible MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE\"\n#endif\n\n#if MICROPY_LONGINT_IMPL != 2\n#error \"incompatible MICROPY_LONGINT_IMPL\"\n#endif\n\n#if MICROPY_PY_BUILTINS_FLOAT\ntypedef struct _mp_obj_float_t {\n    mp_obj_base_t base;\n    mp_float_t value;\n} mp_obj_float_t;\n#endif\n\n#if MICROPY_PY_BUILTINS_COMPLEX\ntypedef struct _mp_obj_complex_t {\n    mp_obj_base_t base;\n    mp_float_t real;\n    mp_float_t imag;\n} mp_obj_complex_t;\n#endif\n\nenum {\n    MP_QSTR_frozentest_dot_py = MP_QSTRnumber_of,\n    MP_QSTR_uPy,\n    //MP_QSTR_i,\n};\n\nextern const qstr_pool_t mp_qstr_const_pool;\nconst qstr_pool_t mp_qstr_frozen_const_pool = {\n    (qstr_pool_t*)&mp_qstr_const_pool, // previous pool\n    MP_QSTRnumber_of, // previous pool size\n    3, // allocated entries\n    3, // used entries\n    {\n        (const byte*)\"\\xfe\\x0d\" \"frozentest.py\",\n        (const byte*)\"\\xf9\\x03\" \"uPy\",\n        (const byte*)\"\\xcc\\x01\" \"i\",\n    },\n};\n\n// frozen bytecode for file frozentest.py, scope frozentest_<module>\nSTATIC const byte fun_data_frozentest__lt_module_gt_[85] = {\n    0x10, 0x16,\n    MP_QSTR__lt_module_gt_ & 0xff, MP_QSTR__lt_module_gt_ >> 8,\n    MP_QSTR_frozentest_dot_py & 0xff, MP_QSTR_frozentest_dot_py >> 8,\n    0x29, 0x28, 0x28, 0x28, 0x2b, 0x28, 0x00,\n    0x11, MP_QSTR_print & 0xff, MP_QSTR_print >> 8, \n    0x10, MP_QSTR_uPy & 0xff, MP_QSTR_uPy >> 8, \n    0x34, 0x01, \n    0x59, \n    0x11, MP_QSTR_print & 0xff, MP_QSTR_print >> 8, \n    0x23, 0x00, \n    0x34, 0x01, \n    0x59, \n    0x11, MP_QSTR_print & 0xff, MP_QSTR_print >> 8, \n    0x23, 0x01, \n    0x34, 0x01, \n    0x59, \n    0x11, MP_QSTR_print & 0xff, MP_QSTR_print >> 8, \n    0x23, 0x02, \n    0x34, 0x01, \n    0x59, \n    0x11, MP_QSTR_print & 0xff, MP_QSTR_print >> 8, \n    0x22, 0xba, 0xef, 0x9a, 0x15, \n    0x34, 0x01, \n    0x59, \n    0x80, \n    0x42, 0x0f, 0x80, \n    0x57, \n    0x16, MP_QSTR_i & 0xff, MP_QSTR_i >> 8, \n    0x11, MP_QSTR_print & 0xff, MP_QSTR_print >> 8, \n    0x11, MP_QSTR_i & 0xff, MP_QSTR_i >> 8, \n    0x34, 0x01, \n    0x59, \n    0x81, \n    0xe5, \n    0x57, \n    0x84, \n    0xd7, \n    0x43, 0xeb, 0x7f, \n    0x59, \n    0x51, \n    0x63, \n};\nSTATIC const mp_obj_str_t const_obj_frozentest__lt_module_gt__0 = {{&mp_type_str}, 246, 34, (const byte*)\"\\x61\\x20\\x6c\\x6f\\x6e\\x67\\x20\\x73\\x74\\x72\\x69\\x6e\\x67\\x20\\x74\\x68\\x61\\x74\\x20\\x69\\x73\\x20\\x6e\\x6f\\x74\\x20\\x69\\x6e\\x74\\x65\\x72\\x6e\\x65\\x64\"};\nSTATIC const mp_obj_str_t const_obj_frozentest__lt_module_gt__1 = {{&mp_type_str}, 200, 38, (const byte*)\"\\x61\\x20\\x73\\x74\\x72\\x69\\x6e\\x67\\x20\\x74\\x68\\x61\\x74\\x20\\x68\\x61\\x73\\x20\\x75\\x6e\\x69\\x63\\x6f\\x64\\x65\\x20\\xce\\xb1\\xce\\xb2\\xce\\xb3\\x20\\x63\\x68\\x61\\x72\\x73\"};\nSTATIC const mp_obj_str_t const_obj_frozentest__lt_module_gt__2 = {{&mp_type_bytes}, 57, 11, (const byte*)\"\\x62\\x79\\x74\\x65\\x73\\x20\\x31\\x32\\x33\\x34\\x01\"};\nSTATIC const mp_rom_obj_t const_table_data_frozentest__lt_module_gt_[3] = {\n    MP_ROM_PTR(&const_obj_frozentest__lt_module_gt__0),\n    MP_ROM_PTR(&const_obj_frozentest__lt_module_gt__1),\n    MP_ROM_PTR(&const_obj_frozentest__lt_module_gt__2),\n};\nconst mp_raw_code_t raw_code_frozentest__lt_module_gt_ = {\n    .kind = MP_CODE_BYTECODE,\n    .scope_flags = 0x00,\n    .n_pos_args = 0,\n    .fun_data = fun_data_frozentest__lt_module_gt_,\n    .const_table = (mp_uint_t*)const_table_data_frozentest__lt_module_gt_,\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    .fun_data_len = 85,\n    .n_obj = 3,\n    .n_raw_code = 0,\n    #if MICROPY_PY_SYS_SETTRACE\n    .prelude = {\n        .n_state = 3,\n        .n_exc_stack = 0,\n        .scope_flags = 0,\n        .n_pos_args = 0,\n        .n_kwonly_args = 0,\n        .n_def_pos_args = 0,\n        .qstr_block_name = MP_QSTR__lt_module_gt_,\n        .qstr_source_file = MP_QSTR_frozentest_dot_py,\n        .line_info = fun_data_frozentest__lt_module_gt_ + 0,\n        .opcodes = fun_data_frozentest__lt_module_gt_ + 13,\n    },\n    .line_of_definition = 0,\n    #endif\n    #if MICROPY_EMIT_MACHINE_CODE\n    .prelude_offset = 0,\n    .n_qstr = 0,\n    .qstr_link = NULL,\n    #endif\n    #endif\n    #if MICROPY_EMIT_MACHINE_CODE\n    .type_sig = 0,\n    #endif\n};\n\nconst char mp_frozen_mpy_names[] = {\n\"frozentest.py\\0\"\n\"\\0\"};\nconst mp_raw_code_t *const mp_frozen_mpy_content[] = {\n    &raw_code_frozentest__lt_module_gt_,\n};"
  },
  {
    "path": "port/gccollect.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdio.h>\n\n#include \"py/mpstate.h\"\n#include \"py/gc.h\"\n\nvoid gc_collect(void) {\n    gc_collect_start();\n\n#if MICROPY_PY_THREAD\n    // trace root pointers from any threads\n    mp_thread_gc_others();\n#else\n    // gc the main thread stack\n    gc_collect_root(rt_thread_self()->stack_addr, ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)rt_thread_self()->stack_addr) / 4);\n#endif\n\n    gc_collect_end();\n    // gc_dump_info();\n}\n"
  },
  {
    "path": "port/genhdr/gen_qstr.py",
    "content": "#\n# This file is part of the MicroPython project, http://micropython.org/\n#\n# The MIT License (MIT)\n#\n# Copyright (c) 2017 SummerGift <zhangyuan@rt-thread.com>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n#\n \nfrom __future__ import print_function\n\nimport re\nimport sys\n\nimport platform\nif platform.python_version_tuple()[0] == '2':\n    bytes_cons = lambda val, enc=None: bytearray(val)\n    from htmlentitydefs import codepoint2name\nelif platform.python_version_tuple()[0] == '3':\n    bytes_cons = bytes\n    from html.entities import codepoint2name\n# end compatibility code\n\n# this must match the equivalent function in qstr.c\ndef compute_hash(qstr, bytes_hash):\n    hash = 5381\n    for b in qstr:\n        hash = (hash * 33) ^ b\n    # Make sure that valid hash is never zero, zero means \"hash not computed\"\n    return (hash & ((1 << (8 * bytes_hash)) - 1)) or 1\n    \ndef make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr):\n   \n    #print(\"qstr:\",qstr)\n    #print(\"cfg_bytes_hash:\",cfg_bytes_hash)\n    #print(\"cfg_bytes_len:\",cfg_bytes_len)\n\n    qbytes = bytes_cons(qstr, 'utf8')\n    \n    #print(\"qbytes:\",qbytes)\n    \n    qlen = len(qbytes)\n    qhash = compute_hash(qbytes, cfg_bytes_hash)\n    \n    #print(\"qlen:\",qlen)\n    #print(\"cfg_bytes_hash:\",cfg_bytes_hash)\n    #print(\"qhash:\",qhash)\n    \n    if all(32 <= ord(c) <= 126 and c != '\\\\' and c != '\"' for c in qstr):\n        # qstr is all printable ASCII so render it as-is (for easier debugging)\n        qdata = qstr\n    else:\n        # qstr contains non-printable codes so render entire thing as hex pairs\n        qdata = ''.join(('\\\\x%02x' % b) for b in qbytes)\n    if qlen >= (1 << (8 * cfg_bytes_len)):\n        print('qstr is too long:', qstr)\n        assert False\n    qlen_str = ('\\\\x%02x' * cfg_bytes_len) % tuple(((qlen >> (8 * i)) & 0xff) for i in range(cfg_bytes_len))\n    qhash_str = ('\\\\x%02x' * cfg_bytes_hash) % tuple(((qhash >> (8 * i)) & 0xff) for i in range(cfg_bytes_hash))\n    return 'QDEF(MP_QSTR_%s, (const byte*)\"%s%s\" \"%s\")' % (qdata,qhash_str, qlen_str, qdata)\n    \nif __name__ == \"__main__\":\n    print (\"This program will gen qstr for micropython:\")\n    \n    for arg in sys.argv:\n        if arg == 'gen_qstr.py':\n            continue\n        qstr_computer = make_bytes(1, 1, arg)\n        print (qstr_computer)\n\n"
  },
  {
    "path": "port/genhdr/moduledefs.h",
    "content": ""
  },
  {
    "path": "port/genhdr/mpversion.h",
    "content": "// This file was generated by py/makeversionhdr.py\n#define MICROPY_GIT_TAG \"v1.13-148-ged7ddd4\"\n#define MICROPY_GIT_HASH \"ed7ddd4\"\n#define MICROPY_BUILD_DATE \"2020-11-03\"\n"
  },
  {
    "path": "port/genhdr/qstrdefs.generated.h",
    "content": "// This file was automatically generated by makeqstrdata.py\n\nQDEF(MP_QSTRnull, (const byte*)\"\\x00\\x00\" \"\")\nQDEF(MP_QSTR_, (const byte*)\"\\x05\\x00\" \"\")\nQDEF(MP_QSTR___abs__, (const byte*)\"\\x95\\x07\" \"__abs__\")\nQDEF(MP_QSTR___add__, (const byte*)\"\\xc4\\x07\" \"__add__\")\nQDEF(MP_QSTR___and__, (const byte*)\"\\x0e\\x07\" \"__and__\")\nQDEF(MP_QSTR___bool__, (const byte*)\"\\x2b\\x08\" \"__bool__\")\nQDEF(MP_QSTR___build_class__, (const byte*)\"\\x42\\x0f\" \"__build_class__\")\nQDEF(MP_QSTR___call__, (const byte*)\"\\xa7\\x08\" \"__call__\")\nQDEF(MP_QSTR___class__, (const byte*)\"\\x2b\\x09\" \"__class__\")\nQDEF(MP_QSTR___contains__, (const byte*)\"\\xc6\\x0c\" \"__contains__\")\nQDEF(MP_QSTR___del__, (const byte*)\"\\x68\\x07\" \"__del__\")\nQDEF(MP_QSTR___delitem__, (const byte*)\"\\xfd\\x0b\" \"__delitem__\")\nQDEF(MP_QSTR___divmod__, (const byte*)\"\\x78\\x0a\" \"__divmod__\")\nQDEF(MP_QSTR___enter__, (const byte*)\"\\x6d\\x09\" \"__enter__\")\nQDEF(MP_QSTR___eq__, (const byte*)\"\\x71\\x06\" \"__eq__\")\nQDEF(MP_QSTR___exit__, (const byte*)\"\\x45\\x08\" \"__exit__\")\nQDEF(MP_QSTR___file__, (const byte*)\"\\x03\\x08\" \"__file__\")\nQDEF(MP_QSTR___floordiv__, (const byte*)\"\\x46\\x0c\" \"__floordiv__\")\nQDEF(MP_QSTR___ge__, (const byte*)\"\\xa7\\x06\" \"__ge__\")\nQDEF(MP_QSTR___getattr__, (const byte*)\"\\x40\\x0b\" \"__getattr__\")\nQDEF(MP_QSTR___getitem__, (const byte*)\"\\x26\\x0b\" \"__getitem__\")\nQDEF(MP_QSTR___gt__, (const byte*)\"\\xb6\\x06\" \"__gt__\")\nQDEF(MP_QSTR___hash__, (const byte*)\"\\xf7\\x08\" \"__hash__\")\nQDEF(MP_QSTR___iadd__, (const byte*)\"\\x6d\\x08\" \"__iadd__\")\nQDEF(MP_QSTR___import__, (const byte*)\"\\x38\\x0a\" \"__import__\")\nQDEF(MP_QSTR___init__, (const byte*)\"\\x5f\\x08\" \"__init__\")\nQDEF(MP_QSTR___invert__, (const byte*)\"\\xf7\\x0a\" \"__invert__\")\nQDEF(MP_QSTR___isub__, (const byte*)\"\\x08\\x08\" \"__isub__\")\nQDEF(MP_QSTR___iter__, (const byte*)\"\\xcf\\x08\" \"__iter__\")\nQDEF(MP_QSTR___le__, (const byte*)\"\\xcc\\x06\" \"__le__\")\nQDEF(MP_QSTR___len__, (const byte*)\"\\xe2\\x07\" \"__len__\")\nQDEF(MP_QSTR___lshift__, (const byte*)\"\\x09\\x0a\" \"__lshift__\")\nQDEF(MP_QSTR___lt__, (const byte*)\"\\x5d\\x06\" \"__lt__\")\nQDEF(MP_QSTR___main__, (const byte*)\"\\x8e\\x08\" \"__main__\")\nQDEF(MP_QSTR___mod__, (const byte*)\"\\x63\\x07\" \"__mod__\")\nQDEF(MP_QSTR___module__, (const byte*)\"\\xff\\x0a\" \"__module__\")\nQDEF(MP_QSTR___mul__, (const byte*)\"\\x31\\x07\" \"__mul__\")\nQDEF(MP_QSTR___name__, (const byte*)\"\\xe2\\x08\" \"__name__\")\nQDEF(MP_QSTR___neg__, (const byte*)\"\\x69\\x07\" \"__neg__\")\nQDEF(MP_QSTR___new__, (const byte*)\"\\x79\\x07\" \"__new__\")\nQDEF(MP_QSTR___next__, (const byte*)\"\\x02\\x08\" \"__next__\")\nQDEF(MP_QSTR___or__, (const byte*)\"\\x38\\x06\" \"__or__\")\nQDEF(MP_QSTR___path__, (const byte*)\"\\xc8\\x08\" \"__path__\")\nQDEF(MP_QSTR___pos__, (const byte*)\"\\x29\\x07\" \"__pos__\")\nQDEF(MP_QSTR___pow__, (const byte*)\"\\x2d\\x07\" \"__pow__\")\nQDEF(MP_QSTR___qualname__, (const byte*)\"\\x6b\\x0c\" \"__qualname__\")\nQDEF(MP_QSTR___repl_print__, (const byte*)\"\\x01\\x0e\" \"__repl_print__\")\nQDEF(MP_QSTR___repr__, (const byte*)\"\\x10\\x08\" \"__repr__\")\nQDEF(MP_QSTR___reversed__, (const byte*)\"\\x61\\x0c\" \"__reversed__\")\nQDEF(MP_QSTR___rshift__, (const byte*)\"\\x57\\x0a\" \"__rshift__\")\nQDEF(MP_QSTR___setitem__, (const byte*)\"\\x32\\x0b\" \"__setitem__\")\nQDEF(MP_QSTR___str__, (const byte*)\"\\xd0\\x07\" \"__str__\")\nQDEF(MP_QSTR___sub__, (const byte*)\"\\x21\\x07\" \"__sub__\")\nQDEF(MP_QSTR___traceback__, (const byte*)\"\\x4f\\x0d\" \"__traceback__\")\nQDEF(MP_QSTR___truediv__, (const byte*)\"\\x88\\x0b\" \"__truediv__\")\nQDEF(MP_QSTR___xor__, (const byte*)\"\\x20\\x07\" \"__xor__\")\nQDEF(MP_QSTR__star_, (const byte*)\"\\x8f\\x01\" \"*\")\nQDEF(MP_QSTR__, (const byte*)\"\\xfa\\x01\" \"_\")\nQDEF(MP_QSTR__slash_, (const byte*)\"\\x8a\\x01\" \"/\")\nQDEF(MP_QSTR__percent__hash_o, (const byte*)\"\\x6c\\x03\" \"%#o\")\nQDEF(MP_QSTR__percent__hash_x, (const byte*)\"\\x7b\\x03\" \"%#x\")\nQDEF(MP_QSTR__brace_open__colon__hash_b_brace_close_, (const byte*)\"\\x58\\x05\" \"{:#b}\")\nQDEF(MP_QSTR__0x0a_, (const byte*)\"\\xaf\\x01\" \"\\x0a\")\nQDEF(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded, (const byte*)\"\\x73\\x20\" \"maximum recursion depth exceeded\")\nQDEF(MP_QSTR__lt_module_gt_, (const byte*)\"\\xbd\\x08\" \"<module>\")\nQDEF(MP_QSTR__lt_lambda_gt_, (const byte*)\"\\x80\\x08\" \"<lambda>\")\nQDEF(MP_QSTR__lt_listcomp_gt_, (const byte*)\"\\xd4\\x0a\" \"<listcomp>\")\nQDEF(MP_QSTR__lt_dictcomp_gt_, (const byte*)\"\\xcc\\x0a\" \"<dictcomp>\")\nQDEF(MP_QSTR__lt_setcomp_gt_, (const byte*)\"\\x54\\x09\" \"<setcomp>\")\nQDEF(MP_QSTR__lt_genexpr_gt_, (const byte*)\"\\x34\\x09\" \"<genexpr>\")\nQDEF(MP_QSTR__lt_string_gt_, (const byte*)\"\\x52\\x08\" \"<string>\")\nQDEF(MP_QSTR__lt_stdin_gt_, (const byte*)\"\\xe3\\x07\" \"<stdin>\")\nQDEF(MP_QSTR_utf_hyphen_8, (const byte*)\"\\xb7\\x05\" \"utf-8\")\nQDEF(MP_QSTR_ALT_OD, (const byte*)\"\\x88\\x06\" \"ALT_OD\")\nQDEF(MP_QSTR_ALT_PP, (const byte*)\"\\xe3\\x06\" \"ALT_PP\")\nQDEF(MP_QSTR_ANALOG, (const byte*)\"\\xaf\\x06\" \"ANALOG\")\nQDEF(MP_QSTR_ARRAY, (const byte*)\"\\x5c\\x05\" \"ARRAY\")\nQDEF(MP_QSTR_ArithmeticError, (const byte*)\"\\x2d\\x0f\" \"ArithmeticError\")\nQDEF(MP_QSTR_AssertionError, (const byte*)\"\\x97\\x0e\" \"AssertionError\")\nQDEF(MP_QSTR_AttributeError, (const byte*)\"\\x21\\x0e\" \"AttributeError\")\nQDEF(MP_QSTR_BFINT16, (const byte*)\"\\x95\\x07\" \"BFINT16\")\nQDEF(MP_QSTR_BFINT32, (const byte*)\"\\x53\\x07\" \"BFINT32\")\nQDEF(MP_QSTR_BFINT8, (const byte*)\"\\x4a\\x06\" \"BFINT8\")\nQDEF(MP_QSTR_BFUINT16, (const byte*)\"\\x40\\x08\" \"BFUINT16\")\nQDEF(MP_QSTR_BFUINT32, (const byte*)\"\\x06\\x08\" \"BFUINT32\")\nQDEF(MP_QSTR_BFUINT8, (const byte*)\"\\xbf\\x07\" \"BFUINT8\")\nQDEF(MP_QSTR_BF_LEN, (const byte*)\"\\x19\\x06\" \"BF_LEN\")\nQDEF(MP_QSTR_BF_POS, (const byte*)\"\\x52\\x06\" \"BF_POS\")\nQDEF(MP_QSTR_BIG_ENDIAN, (const byte*)\"\\xff\\x0a\" \"BIG_ENDIAN\")\nQDEF(MP_QSTR_BaseException, (const byte*)\"\\x07\\x0d\" \"BaseException\")\nQDEF(MP_QSTR_BytesIO, (const byte*)\"\\x1a\\x07\" \"BytesIO\")\nQDEF(MP_QSTR_DEBUG, (const byte*)\"\\x34\\x05\" \"DEBUG\")\nQDEF(MP_QSTR_DEEPSLEEP_RESET, (const byte*)\"\\x14\\x0f\" \"DEEPSLEEP_RESET\")\nQDEF(MP_QSTR_DecompIO, (const byte*)\"\\x93\\x08\" \"DecompIO\")\nQDEF(MP_QSTR_EOFError, (const byte*)\"\\x91\\x08\" \"EOFError\")\nQDEF(MP_QSTR_Ellipsis, (const byte*)\"\\xf0\\x08\" \"Ellipsis\")\nQDEF(MP_QSTR_Exception, (const byte*)\"\\xf2\\x09\" \"Exception\")\nQDEF(MP_QSTR_FLOAT32, (const byte*)\"\\xb4\\x07\" \"FLOAT32\")\nQDEF(MP_QSTR_FLOAT64, (const byte*)\"\\x17\\x07\" \"FLOAT64\")\nQDEF(MP_QSTR_GeneratorExit, (const byte*)\"\\x16\\x0d\" \"GeneratorExit\")\nQDEF(MP_QSTR_HARD_RESET, (const byte*)\"\\xb0\\x0a\" \"HARD_RESET\")\nQDEF(MP_QSTR_IN, (const byte*)\"\\x22\\x02\" \"IN\")\nQDEF(MP_QSTR_INT16, (const byte*)\"\\x91\\x05\" \"INT16\")\nQDEF(MP_QSTR_INT32, (const byte*)\"\\x57\\x05\" \"INT32\")\nQDEF(MP_QSTR_INT64, (const byte*)\"\\xf4\\x05\" \"INT64\")\nQDEF(MP_QSTR_INT8, (const byte*)\"\\xce\\x04\" \"INT8\")\nQDEF(MP_QSTR_IRQ_FALLING, (const byte*)\"\\x37\\x0b\" \"IRQ_FALLING\")\nQDEF(MP_QSTR_IRQ_RISING, (const byte*)\"\\x78\\x0a\" \"IRQ_RISING\")\nQDEF(MP_QSTR_IRQ_RISING_FALLING, (const byte*)\"\\x60\\x12\" \"IRQ_RISING_FALLING\")\nQDEF(MP_QSTR_ImportError, (const byte*)\"\\x20\\x0b\" \"ImportError\")\nQDEF(MP_QSTR_IndentationError, (const byte*)\"\\x5c\\x10\" \"IndentationError\")\nQDEF(MP_QSTR_IndexError, (const byte*)\"\\x83\\x0a\" \"IndexError\")\nQDEF(MP_QSTR_KeyError, (const byte*)\"\\xea\\x08\" \"KeyError\")\nQDEF(MP_QSTR_KeyboardInterrupt, (const byte*)\"\\xaf\\x11\" \"KeyboardInterrupt\")\nQDEF(MP_QSTR_LITTLE_ENDIAN, (const byte*)\"\\xbf\\x0d\" \"LITTLE_ENDIAN\")\nQDEF(MP_QSTR_LookupError, (const byte*)\"\\xff\\x0b\" \"LookupError\")\nQDEF(MP_QSTR_MemoryError, (const byte*)\"\\xdc\\x0b\" \"MemoryError\")\nQDEF(MP_QSTR_NATIVE, (const byte*)\"\\x04\\x06\" \"NATIVE\")\nQDEF(MP_QSTR_NameError, (const byte*)\"\\xba\\x09\" \"NameError\")\nQDEF(MP_QSTR_NoneType, (const byte*)\"\\x17\\x08\" \"NoneType\")\nQDEF(MP_QSTR_NotImplementedError, (const byte*)\"\\xc6\\x13\" \"NotImplementedError\")\nQDEF(MP_QSTR_OSError, (const byte*)\"\\xa1\\x07\" \"OSError\")\nQDEF(MP_QSTR_OUT_OD, (const byte*)\"\\x1f\\x06\" \"OUT_OD\")\nQDEF(MP_QSTR_OUT_PP, (const byte*)\"\\x34\\x06\" \"OUT_PP\")\nQDEF(MP_QSTR_OrderedDict, (const byte*)\"\\xf0\\x0b\" \"OrderedDict\")\nQDEF(MP_QSTR_OverflowError, (const byte*)\"\\x81\\x0d\" \"OverflowError\")\nQDEF(MP_QSTR_PTR, (const byte*)\"\\xb3\\x03\" \"PTR\")\nQDEF(MP_QSTR_PULL_DOWN, (const byte*)\"\\xad\\x09\" \"PULL_DOWN\")\nQDEF(MP_QSTR_PULL_NONE, (const byte*)\"\\x55\\x09\" \"PULL_NONE\")\nQDEF(MP_QSTR_PULL_UP, (const byte*)\"\\xba\\x07\" \"PULL_UP\")\nQDEF(MP_QSTR_PWRON_RESET, (const byte*)\"\\xdb\\x0b\" \"PWRON_RESET\")\nQDEF(MP_QSTR_Pin, (const byte*)\"\\x12\\x03\" \"Pin\")\nQDEF(MP_QSTR_PinBase, (const byte*)\"\\x47\\x07\" \"PinBase\")\nQDEF(MP_QSTR_RuntimeError, (const byte*)\"\\x61\\x0c\" \"RuntimeError\")\nQDEF(MP_QSTR_SOFT_RESET, (const byte*)\"\\x01\\x0a\" \"SOFT_RESET\")\nQDEF(MP_QSTR_Signal, (const byte*)\"\\x9b\\x06\" \"Signal\")\nQDEF(MP_QSTR_StopIteration, (const byte*)\"\\xea\\x0d\" \"StopIteration\")\nQDEF(MP_QSTR_StringIO, (const byte*)\"\\x76\\x08\" \"StringIO\")\nQDEF(MP_QSTR_SyntaxError, (const byte*)\"\\x94\\x0b\" \"SyntaxError\")\nQDEF(MP_QSTR_SystemExit, (const byte*)\"\\x20\\x0a\" \"SystemExit\")\nQDEF(MP_QSTR_TypeError, (const byte*)\"\\x25\\x09\" \"TypeError\")\nQDEF(MP_QSTR_UINT16, (const byte*)\"\\xc4\\x06\" \"UINT16\")\nQDEF(MP_QSTR_UINT32, (const byte*)\"\\x82\\x06\" \"UINT32\")\nQDEF(MP_QSTR_UINT64, (const byte*)\"\\x61\\x06\" \"UINT64\")\nQDEF(MP_QSTR_UINT8, (const byte*)\"\\xbb\\x05\" \"UINT8\")\nQDEF(MP_QSTR_UnicodeError, (const byte*)\"\\x22\\x0c\" \"UnicodeError\")\nQDEF(MP_QSTR_VOID, (const byte*)\"\\x31\\x04\" \"VOID\")\nQDEF(MP_QSTR_ValueError, (const byte*)\"\\x96\\x0a\" \"ValueError\")\nQDEF(MP_QSTR_WDT_RESET, (const byte*)\"\\x08\\x09\" \"WDT_RESET\")\nQDEF(MP_QSTR_ZeroDivisionError, (const byte*)\"\\xb6\\x11\" \"ZeroDivisionError\")\nQDEF(MP_QSTR_a2b_base64, (const byte*)\"\\x3c\\x0a\" \"a2b_base64\")\nQDEF(MP_QSTR_abs, (const byte*)\"\\x95\\x03\" \"abs\")\nQDEF(MP_QSTR_acos, (const byte*)\"\\x1b\\x04\" \"acos\")\nQDEF(MP_QSTR_acosh, (const byte*)\"\\x13\\x05\" \"acosh\")\nQDEF(MP_QSTR_add, (const byte*)\"\\x44\\x03\" \"add\")\nQDEF(MP_QSTR_addressof, (const byte*)\"\\x5a\\x09\" \"addressof\")\nQDEF(MP_QSTR_all, (const byte*)\"\\x44\\x03\" \"all\")\nQDEF(MP_QSTR_any, (const byte*)\"\\x13\\x03\" \"any\")\nQDEF(MP_QSTR_append, (const byte*)\"\\x6b\\x06\" \"append\")\nQDEF(MP_QSTR_args, (const byte*)\"\\xc2\\x04\" \"args\")\nQDEF(MP_QSTR_array, (const byte*)\"\\x7c\\x05\" \"array\")\nQDEF(MP_QSTR_asin, (const byte*)\"\\x50\\x04\" \"asin\")\nQDEF(MP_QSTR_asinh, (const byte*)\"\\x38\\x05\" \"asinh\")\nQDEF(MP_QSTR_atan, (const byte*)\"\\x1f\\x04\" \"atan\")\nQDEF(MP_QSTR_atan2, (const byte*)\"\\xcd\\x05\" \"atan2\")\nQDEF(MP_QSTR_atanh, (const byte*)\"\\x97\\x05\" \"atanh\")\nQDEF(MP_QSTR_b2a_base64, (const byte*)\"\\x3c\\x0a\" \"b2a_base64\")\nQDEF(MP_QSTR_bin, (const byte*)\"\\xe0\\x03\" \"bin\")\nQDEF(MP_QSTR_bool, (const byte*)\"\\xeb\\x04\" \"bool\")\nQDEF(MP_QSTR_bound_method, (const byte*)\"\\x97\\x0c\" \"bound_method\")\nQDEF(MP_QSTR_builtins, (const byte*)\"\\xf7\\x08\" \"builtins\")\nQDEF(MP_QSTR_bytearray, (const byte*)\"\\x76\\x09\" \"bytearray\")\nQDEF(MP_QSTR_bytearray_at, (const byte*)\"\\x9c\\x0c\" \"bytearray_at\")\nQDEF(MP_QSTR_bytecode, (const byte*)\"\\x22\\x08\" \"bytecode\")\nQDEF(MP_QSTR_bytes, (const byte*)\"\\x5c\\x05\" \"bytes\")\nQDEF(MP_QSTR_bytes_at, (const byte*)\"\\xb6\\x08\" \"bytes_at\")\nQDEF(MP_QSTR_callable, (const byte*)\"\\x0d\\x08\" \"callable\")\nQDEF(MP_QSTR_ceil, (const byte*)\"\\x06\\x04\" \"ceil\")\nQDEF(MP_QSTR_center, (const byte*)\"\\x4e\\x06\" \"center\")\nQDEF(MP_QSTR_choice, (const byte*)\"\\x2e\\x06\" \"choice\")\nQDEF(MP_QSTR_chr, (const byte*)\"\\xdc\\x03\" \"chr\")\nQDEF(MP_QSTR_classmethod, (const byte*)\"\\xb4\\x0b\" \"classmethod\")\nQDEF(MP_QSTR_clear, (const byte*)\"\\x7c\\x05\" \"clear\")\nQDEF(MP_QSTR_close, (const byte*)\"\\x33\\x05\" \"close\")\nQDEF(MP_QSTR_closure, (const byte*)\"\\x74\\x07\" \"closure\")\nQDEF(MP_QSTR_cmath, (const byte*)\"\\xb6\\x05\" \"cmath\")\nQDEF(MP_QSTR_code, (const byte*)\"\\x68\\x04\" \"code\")\nQDEF(MP_QSTR_collect, (const byte*)\"\\x9b\\x07\" \"collect\")\nQDEF(MP_QSTR_compile, (const byte*)\"\\xf4\\x07\" \"compile\")\nQDEF(MP_QSTR_complex, (const byte*)\"\\xc5\\x07\" \"complex\")\nQDEF(MP_QSTR_const, (const byte*)\"\\xc0\\x05\" \"const\")\nQDEF(MP_QSTR_copy, (const byte*)\"\\xe0\\x04\" \"copy\")\nQDEF(MP_QSTR_copysign, (const byte*)\"\\x33\\x08\" \"copysign\")\nQDEF(MP_QSTR_cos, (const byte*)\"\\x7a\\x03\" \"cos\")\nQDEF(MP_QSTR_cosh, (const byte*)\"\\xd2\\x04\" \"cosh\")\nQDEF(MP_QSTR_count, (const byte*)\"\\xa6\\x05\" \"count\")\nQDEF(MP_QSTR_current_tid, (const byte*)\"\\xca\\x0b\" \"current_tid\")\nQDEF(MP_QSTR_decompress, (const byte*)\"\\x62\\x0a\" \"decompress\")\nQDEF(MP_QSTR_deepsleep, (const byte*)\"\\x9e\\x09\" \"deepsleep\")\nQDEF(MP_QSTR_default, (const byte*)\"\\xce\\x07\" \"default\")\nQDEF(MP_QSTR_degrees, (const byte*)\"\\x02\\x07\" \"degrees\")\nQDEF(MP_QSTR_delay, (const byte*)\"\\x50\\x05\" \"delay\")\nQDEF(MP_QSTR_deleter, (const byte*)\"\\x6e\\x07\" \"deleter\")\nQDEF(MP_QSTR_dict, (const byte*)\"\\x3f\\x04\" \"dict\")\nQDEF(MP_QSTR_dict_view, (const byte*)\"\\x2d\\x09\" \"dict_view\")\nQDEF(MP_QSTR_difference, (const byte*)\"\\x72\\x0a\" \"difference\")\nQDEF(MP_QSTR_difference_update, (const byte*)\"\\x9c\\x11\" \"difference_update\")\nQDEF(MP_QSTR_digest, (const byte*)\"\\xcd\\x06\" \"digest\")\nQDEF(MP_QSTR_dir, (const byte*)\"\\xfa\\x03\" \"dir\")\nQDEF(MP_QSTR_disable, (const byte*)\"\\x91\\x07\" \"disable\")\nQDEF(MP_QSTR_disable_irq, (const byte*)\"\\x04\\x0b\" \"disable_irq\")\nQDEF(MP_QSTR_discard, (const byte*)\"\\x0f\\x07\" \"discard\")\nQDEF(MP_QSTR_divmod, (const byte*)\"\\xb8\\x06\" \"divmod\")\nQDEF(MP_QSTR_doc, (const byte*)\"\\x2d\\x03\" \"doc\")\nQDEF(MP_QSTR_dump, (const byte*)\"\\xe9\\x04\" \"dump\")\nQDEF(MP_QSTR_dumps, (const byte*)\"\\x7a\\x05\" \"dumps\")\nQDEF(MP_QSTR_e, (const byte*)\"\\xc0\\x01\" \"e\")\nQDEF(MP_QSTR_elapsed_micros, (const byte*)\"\\x39\\x0e\" \"elapsed_micros\")\nQDEF(MP_QSTR_elapsed_millis, (const byte*)\"\\x8e\\x0e\" \"elapsed_millis\")\nQDEF(MP_QSTR_enable, (const byte*)\"\\x04\\x06\" \"enable\")\nQDEF(MP_QSTR_enable_irq, (const byte*)\"\\x91\\x0a\" \"enable_irq\")\nQDEF(MP_QSTR_end, (const byte*)\"\\x0a\\x03\" \"end\")\nQDEF(MP_QSTR_endswith, (const byte*)\"\\x1b\\x08\" \"endswith\")\nQDEF(MP_QSTR_enumerate, (const byte*)\"\\x71\\x09\" \"enumerate\")\nQDEF(MP_QSTR_erf, (const byte*)\"\\x94\\x03\" \"erf\")\nQDEF(MP_QSTR_erfc, (const byte*)\"\\x77\\x04\" \"erfc\")\nQDEF(MP_QSTR_eval, (const byte*)\"\\x9b\\x04\" \"eval\")\nQDEF(MP_QSTR_exec, (const byte*)\"\\x1e\\x04\" \"exec\")\nQDEF(MP_QSTR_execfile, (const byte*)\"\\x58\\x08\" \"execfile\")\nQDEF(MP_QSTR_exp, (const byte*)\"\\xc8\\x03\" \"exp\")\nQDEF(MP_QSTR_expm1, (const byte*)\"\\x74\\x05\" \"expm1\")\nQDEF(MP_QSTR_extend, (const byte*)\"\\x63\\x06\" \"extend\")\nQDEF(MP_QSTR_fabs, (const byte*)\"\\x93\\x04\" \"fabs\")\nQDEF(MP_QSTR_fault_debug, (const byte*)\"\\x61\\x0b\" \"fault_debug\")\nQDEF(MP_QSTR_filter, (const byte*)\"\\x25\\x06\" \"filter\")\nQDEF(MP_QSTR_find, (const byte*)\"\\x01\\x04\" \"find\")\nQDEF(MP_QSTR_float, (const byte*)\"\\x35\\x05\" \"float\")\nQDEF(MP_QSTR_floor, (const byte*)\"\\x7d\\x05\" \"floor\")\nQDEF(MP_QSTR_flush, (const byte*)\"\\x61\\x05\" \"flush\")\nQDEF(MP_QSTR_fmod, (const byte*)\"\\xe5\\x04\" \"fmod\")\nQDEF(MP_QSTR_format, (const byte*)\"\\x26\\x06\" \"format\")\nQDEF(MP_QSTR_freq, (const byte*)\"\\xe5\\x04\" \"freq\")\nQDEF(MP_QSTR_frexp, (const byte*)\"\\x1c\\x05\" \"frexp\")\nQDEF(MP_QSTR_from_bytes, (const byte*)\"\\x35\\x0a\" \"from_bytes\")\nQDEF(MP_QSTR_fromkeys, (const byte*)\"\\x37\\x08\" \"fromkeys\")\nQDEF(MP_QSTR_frozenset, (const byte*)\"\\xed\\x09\" \"frozenset\")\nQDEF(MP_QSTR_function, (const byte*)\"\\x27\\x08\" \"function\")\nQDEF(MP_QSTR_gamma, (const byte*)\"\\x02\\x05\" \"gamma\")\nQDEF(MP_QSTR_gc, (const byte*)\"\\x61\\x02\" \"gc\")\nQDEF(MP_QSTR_generator, (const byte*)\"\\x96\\x09\" \"generator\")\nQDEF(MP_QSTR_get, (const byte*)\"\\x33\\x03\" \"get\")\nQDEF(MP_QSTR_getattr, (const byte*)\"\\xc0\\x07\" \"getattr\")\nQDEF(MP_QSTR_getrandbits, (const byte*)\"\\x66\\x0b\" \"getrandbits\")\nQDEF(MP_QSTR_getter, (const byte*)\"\\x90\\x06\" \"getter\")\nQDEF(MP_QSTR_getvalue, (const byte*)\"\\x78\\x08\" \"getvalue\")\nQDEF(MP_QSTR_globals, (const byte*)\"\\x9d\\x07\" \"globals\")\nQDEF(MP_QSTR_group, (const byte*)\"\\xba\\x05\" \"group\")\nQDEF(MP_QSTR_hard_reset, (const byte*)\"\\xd0\\x0a\" \"hard_reset\")\nQDEF(MP_QSTR_hasattr, (const byte*)\"\\x8c\\x07\" \"hasattr\")\nQDEF(MP_QSTR_hash, (const byte*)\"\\xb7\\x04\" \"hash\")\nQDEF(MP_QSTR_heap_lock, (const byte*)\"\\xad\\x09\" \"heap_lock\")\nQDEF(MP_QSTR_heap_unlock, (const byte*)\"\\x56\\x0b\" \"heap_unlock\")\nQDEF(MP_QSTR_heapify, (const byte*)\"\\xaf\\x07\" \"heapify\")\nQDEF(MP_QSTR_heappop, (const byte*)\"\\xd6\\x07\" \"heappop\")\nQDEF(MP_QSTR_heappush, (const byte*)\"\\x87\\x08\" \"heappush\")\nQDEF(MP_QSTR_help, (const byte*)\"\\x94\\x04\" \"help\")\nQDEF(MP_QSTR_hex, (const byte*)\"\\x70\\x03\" \"hex\")\nQDEF(MP_QSTR_hexlify, (const byte*)\"\\x2a\\x07\" \"hexlify\")\nQDEF(MP_QSTR_id, (const byte*)\"\\x28\\x02\" \"id\")\nQDEF(MP_QSTR_idle, (const byte*)\"\\xa1\\x04\" \"idle\")\nQDEF(MP_QSTR_imag, (const byte*)\"\\x47\\x04\" \"imag\")\nQDEF(MP_QSTR_index, (const byte*)\"\\x7b\\x05\" \"index\")\nQDEF(MP_QSTR_info, (const byte*)\"\\xeb\\x04\" \"info\")\nQDEF(MP_QSTR_init, (const byte*)\"\\x1f\\x04\" \"init\")\nQDEF(MP_QSTR_input, (const byte*)\"\\x73\\x05\" \"input\")\nQDEF(MP_QSTR_insert, (const byte*)\"\\x12\\x06\" \"insert\")\nQDEF(MP_QSTR_int, (const byte*)\"\\x16\\x03\" \"int\")\nQDEF(MP_QSTR_intersection, (const byte*)\"\\x28\\x0c\" \"intersection\")\nQDEF(MP_QSTR_intersection_update, (const byte*)\"\\x06\\x13\" \"intersection_update\")\nQDEF(MP_QSTR_invert, (const byte*)\"\\xb7\\x06\" \"invert\")\nQDEF(MP_QSTR_is_preempt_thread, (const byte*)\"\\x1a\\x11\" \"is_preempt_thread\")\nQDEF(MP_QSTR_isalpha, (const byte*)\"\\xeb\\x07\" \"isalpha\")\nQDEF(MP_QSTR_isdigit, (const byte*)\"\\xa8\\x07\" \"isdigit\")\nQDEF(MP_QSTR_isdisjoint, (const byte*)\"\\xf7\\x0a\" \"isdisjoint\")\nQDEF(MP_QSTR_isenabled, (const byte*)\"\\x9a\\x09\" \"isenabled\")\nQDEF(MP_QSTR_isfinite, (const byte*)\"\\xa6\\x08\" \"isfinite\")\nQDEF(MP_QSTR_isinf, (const byte*)\"\\x3e\\x05\" \"isinf\")\nQDEF(MP_QSTR_isinstance, (const byte*)\"\\xb6\\x0a\" \"isinstance\")\nQDEF(MP_QSTR_islower, (const byte*)\"\\xfc\\x07\" \"islower\")\nQDEF(MP_QSTR_isnan, (const byte*)\"\\x9e\\x05\" \"isnan\")\nQDEF(MP_QSTR_isspace, (const byte*)\"\\x5b\\x07\" \"isspace\")\nQDEF(MP_QSTR_issubclass, (const byte*)\"\\xb5\\x0a\" \"issubclass\")\nQDEF(MP_QSTR_issubset, (const byte*)\"\\xb9\\x08\" \"issubset\")\nQDEF(MP_QSTR_issuperset, (const byte*)\"\\xfc\\x0a\" \"issuperset\")\nQDEF(MP_QSTR_isupper, (const byte*)\"\\xdd\\x07\" \"isupper\")\nQDEF(MP_QSTR_items, (const byte*)\"\\xe3\\x05\" \"items\")\nQDEF(MP_QSTR_iter, (const byte*)\"\\x8f\\x04\" \"iter\")\nQDEF(MP_QSTR_iterator, (const byte*)\"\\x47\\x08\" \"iterator\")\nQDEF(MP_QSTR_join, (const byte*)\"\\xa7\\x04\" \"join\")\nQDEF(MP_QSTR_kbd_intr, (const byte*)\"\\xf6\\x08\" \"kbd_intr\")\nQDEF(MP_QSTR_keepends, (const byte*)\"\\x62\\x08\" \"keepends\")\nQDEF(MP_QSTR_key, (const byte*)\"\\x32\\x03\" \"key\")\nQDEF(MP_QSTR_keys, (const byte*)\"\\x01\\x04\" \"keys\")\nQDEF(MP_QSTR_ldexp, (const byte*)\"\\x40\\x05\" \"ldexp\")\nQDEF(MP_QSTR_len, (const byte*)\"\\x62\\x03\" \"len\")\nQDEF(MP_QSTR_lgamma, (const byte*)\"\\xce\\x06\" \"lgamma\")\nQDEF(MP_QSTR_list, (const byte*)\"\\x27\\x04\" \"list\")\nQDEF(MP_QSTR_little, (const byte*)\"\\x89\\x06\" \"little\")\nQDEF(MP_QSTR_load, (const byte*)\"\\x63\\x04\" \"load\")\nQDEF(MP_QSTR_loads, (const byte*)\"\\xb0\\x05\" \"loads\")\nQDEF(MP_QSTR_locals, (const byte*)\"\\x3b\\x06\" \"locals\")\nQDEF(MP_QSTR_log, (const byte*)\"\\x21\\x03\" \"log\")\nQDEF(MP_QSTR_log10, (const byte*)\"\\x40\\x05\" \"log10\")\nQDEF(MP_QSTR_log2, (const byte*)\"\\x73\\x04\" \"log2\")\nQDEF(MP_QSTR_lower, (const byte*)\"\\xc6\\x05\" \"lower\")\nQDEF(MP_QSTR_lstrip, (const byte*)\"\\xe5\\x06\" \"lstrip\")\nQDEF(MP_QSTR_machine, (const byte*)\"\\x60\\x07\" \"machine\")\nQDEF(MP_QSTR_map, (const byte*)\"\\xb9\\x03\" \"map\")\nQDEF(MP_QSTR_match, (const byte*)\"\\x96\\x05\" \"match\")\nQDEF(MP_QSTR_math, (const byte*)\"\\x35\\x04\" \"math\")\nQDEF(MP_QSTR_max, (const byte*)\"\\xb1\\x03\" \"max\")\nQDEF(MP_QSTR_mem, (const byte*)\"\\x20\\x03\" \"mem\")\nQDEF(MP_QSTR_mem_alloc, (const byte*)\"\\x52\\x09\" \"mem_alloc\")\nQDEF(MP_QSTR_mem_free, (const byte*)\"\\xcb\\x08\" \"mem_free\")\nQDEF(MP_QSTR_mem_info, (const byte*)\"\\xd1\\x08\" \"mem_info\")\nQDEF(MP_QSTR_memoryview, (const byte*)\"\\x69\\x0a\" \"memoryview\")\nQDEF(MP_QSTR_micropython, (const byte*)\"\\x0b\\x0b\" \"micropython\")\nQDEF(MP_QSTR_micros, (const byte*)\"\\xac\\x06\" \"micros\")\nQDEF(MP_QSTR_millis, (const byte*)\"\\x5b\\x06\" \"millis\")\nQDEF(MP_QSTR_min, (const byte*)\"\\xaf\\x03\" \"min\")\nQDEF(MP_QSTR_mode, (const byte*)\"\\x26\\x04\" \"mode\")\nQDEF(MP_QSTR_modf, (const byte*)\"\\x25\\x04\" \"modf\")\nQDEF(MP_QSTR_module, (const byte*)\"\\xbf\\x06\" \"module\")\nQDEF(MP_QSTR_modules, (const byte*)\"\\xec\\x07\" \"modules\")\nQDEF(MP_QSTR_mount, (const byte*)\"\\xa8\\x05\" \"mount\")\nQDEF(MP_QSTR_name, (const byte*)\"\\xa2\\x04\" \"name\")\nQDEF(MP_QSTR_namedtuple, (const byte*)\"\\x1e\\x0a\" \"namedtuple\")\nQDEF(MP_QSTR_next, (const byte*)\"\\x42\\x04\" \"next\")\nQDEF(MP_QSTR_object, (const byte*)\"\\x90\\x06\" \"object\")\nQDEF(MP_QSTR_oct, (const byte*)\"\\xfd\\x03\" \"oct\")\nQDEF(MP_QSTR_off, (const byte*)\"\\x8a\\x03\" \"off\")\nQDEF(MP_QSTR_on, (const byte*)\"\\x64\\x02\" \"on\")\nQDEF(MP_QSTR_open, (const byte*)\"\\xd1\\x04\" \"open\")\nQDEF(MP_QSTR_opt_level, (const byte*)\"\\x87\\x09\" \"opt_level\")\nQDEF(MP_QSTR_ord, (const byte*)\"\\x1c\\x03\" \"ord\")\nQDEF(MP_QSTR_partition, (const byte*)\"\\x87\\x09\" \"partition\")\nQDEF(MP_QSTR_peektime, (const byte*)\"\\x8b\\x08\" \"peektime\")\nQDEF(MP_QSTR_phase, (const byte*)\"\\x6a\\x05\" \"phase\")\nQDEF(MP_QSTR_pi, (const byte*)\"\\x1c\\x02\" \"pi\")\nQDEF(MP_QSTR_pin, (const byte*)\"\\xf2\\x03\" \"pin\")\nQDEF(MP_QSTR_polar, (const byte*)\"\\x05\\x05\" \"polar\")\nQDEF(MP_QSTR_pop, (const byte*)\"\\x2a\\x03\" \"pop\")\nQDEF(MP_QSTR_popitem, (const byte*)\"\\xbf\\x07\" \"popitem\")\nQDEF(MP_QSTR_pow, (const byte*)\"\\x2d\\x03\" \"pow\")\nQDEF(MP_QSTR_print, (const byte*)\"\\x54\\x05\" \"print\")\nQDEF(MP_QSTR_property, (const byte*)\"\\xc2\\x08\" \"property\")\nQDEF(MP_QSTR_pull, (const byte*)\"\\x80\\x04\" \"pull\")\nQDEF(MP_QSTR_push, (const byte*)\"\\xbb\\x04\" \"push\")\nQDEF(MP_QSTR_pyb, (const byte*)\"\\xee\\x03\" \"pyb\")\nQDEF(MP_QSTR_qstr_info, (const byte*)\"\\xb0\\x09\" \"qstr_info\")\nQDEF(MP_QSTR_radians, (const byte*)\"\\x87\\x07\" \"radians\")\nQDEF(MP_QSTR_randint, (const byte*)\"\\xaf\\x07\" \"randint\")\nQDEF(MP_QSTR_random, (const byte*)\"\\xbe\\x06\" \"random\")\nQDEF(MP_QSTR_randrange, (const byte*)\"\\xa3\\x09\" \"randrange\")\nQDEF(MP_QSTR_range, (const byte*)\"\\x1a\\x05\" \"range\")\nQDEF(MP_QSTR_read, (const byte*)\"\\xb7\\x04\" \"read\")\nQDEF(MP_QSTR_readinto, (const byte*)\"\\x4b\\x08\" \"readinto\")\nQDEF(MP_QSTR_readline, (const byte*)\"\\xf9\\x08\" \"readline\")\nQDEF(MP_QSTR_real, (const byte*)\"\\xbf\\x04\" \"real\")\nQDEF(MP_QSTR_rect, (const byte*)\"\\xe5\\x04\" \"rect\")\nQDEF(MP_QSTR_remove, (const byte*)\"\\x63\\x06\" \"remove\")\nQDEF(MP_QSTR_repl_info, (const byte*)\"\\xbf\\x09\" \"repl_info\")\nQDEF(MP_QSTR_replace, (const byte*)\"\\x49\\x07\" \"replace\")\nQDEF(MP_QSTR_repr, (const byte*)\"\\xd0\\x04\" \"repr\")\nQDEF(MP_QSTR_reset, (const byte*)\"\\x10\\x05\" \"reset\")\nQDEF(MP_QSTR_reset_cause, (const byte*)\"\\xce\\x0b\" \"reset_cause\")\nQDEF(MP_QSTR_reverse, (const byte*)\"\\x25\\x07\" \"reverse\")\nQDEF(MP_QSTR_reversed, (const byte*)\"\\xa1\\x08\" \"reversed\")\nQDEF(MP_QSTR_rfind, (const byte*)\"\\xd2\\x05\" \"rfind\")\nQDEF(MP_QSTR_rindex, (const byte*)\"\\xe9\\x06\" \"rindex\")\nQDEF(MP_QSTR_round, (const byte*)\"\\xe7\\x05\" \"round\")\nQDEF(MP_QSTR_rpartition, (const byte*)\"\\x15\\x0a\" \"rpartition\")\nQDEF(MP_QSTR_rsplit, (const byte*)\"\\xa5\\x06\" \"rsplit\")\nQDEF(MP_QSTR_rstrip, (const byte*)\"\\x3b\\x06\" \"rstrip\")\nQDEF(MP_QSTR_rtthread, (const byte*)\"\\x6d\\x08\" \"rtthread\")\nQDEF(MP_QSTR_search, (const byte*)\"\\xab\\x06\" \"search\")\nQDEF(MP_QSTR_seed, (const byte*)\"\\x92\\x04\" \"seed\")\nQDEF(MP_QSTR_seek, (const byte*)\"\\x9d\\x04\" \"seek\")\nQDEF(MP_QSTR_send, (const byte*)\"\\xb9\\x04\" \"send\")\nQDEF(MP_QSTR_sep, (const byte*)\"\\x23\\x03\" \"sep\")\nQDEF(MP_QSTR_set, (const byte*)\"\\x27\\x03\" \"set\")\nQDEF(MP_QSTR_setattr, (const byte*)\"\\xd4\\x07\" \"setattr\")\nQDEF(MP_QSTR_setdefault, (const byte*)\"\\x6c\\x0a\" \"setdefault\")\nQDEF(MP_QSTR_setter, (const byte*)\"\\x04\\x06\" \"setter\")\nQDEF(MP_QSTR_sha256, (const byte*)\"\\x2e\\x06\" \"sha256\")\nQDEF(MP_QSTR_sin, (const byte*)\"\\xb1\\x03\" \"sin\")\nQDEF(MP_QSTR_single, (const byte*)\"\\x3f\\x06\" \"single\")\nQDEF(MP_QSTR_sinh, (const byte*)\"\\xb9\\x04\" \"sinh\")\nQDEF(MP_QSTR_sizeof, (const byte*)\"\\x49\\x06\" \"sizeof\")\nQDEF(MP_QSTR_sleep, (const byte*)\"\\xea\\x05\" \"sleep\")\nQDEF(MP_QSTR_sleep_ms, (const byte*)\"\\x0b\\x08\" \"sleep_ms\")\nQDEF(MP_QSTR_sleep_us, (const byte*)\"\\x13\\x08\" \"sleep_us\")\nQDEF(MP_QSTR_slice, (const byte*)\"\\xb5\\x05\" \"slice\")\nQDEF(MP_QSTR_soft_reset, (const byte*)\"\\xe1\\x0a\" \"soft_reset\")\nQDEF(MP_QSTR_sort, (const byte*)\"\\xbf\\x04\" \"sort\")\nQDEF(MP_QSTR_sorted, (const byte*)\"\\x5e\\x06\" \"sorted\")\nQDEF(MP_QSTR_split, (const byte*)\"\\xb7\\x05\" \"split\")\nQDEF(MP_QSTR_splitlines, (const byte*)\"\\x6a\\x0a\" \"splitlines\")\nQDEF(MP_QSTR_sqrt, (const byte*)\"\\x21\\x04\" \"sqrt\")\nQDEF(MP_QSTR_stack_use, (const byte*)\"\\x97\\x09\" \"stack_use\")\nQDEF(MP_QSTR_stacks_analyze, (const byte*)\"\\x63\\x0e\" \"stacks_analyze\")\nQDEF(MP_QSTR_standby, (const byte*)\"\\xd2\\x07\" \"standby\")\nQDEF(MP_QSTR_start, (const byte*)\"\\x85\\x05\" \"start\")\nQDEF(MP_QSTR_startswith, (const byte*)\"\\x74\\x0a\" \"startswith\")\nQDEF(MP_QSTR_staticmethod, (const byte*)\"\\x62\\x0c\" \"staticmethod\")\nQDEF(MP_QSTR_step, (const byte*)\"\\x57\\x04\" \"step\")\nQDEF(MP_QSTR_stop, (const byte*)\"\\x9d\\x04\" \"stop\")\nQDEF(MP_QSTR_str, (const byte*)\"\\x50\\x03\" \"str\")\nQDEF(MP_QSTR_strip, (const byte*)\"\\x29\\x05\" \"strip\")\nQDEF(MP_QSTR_struct, (const byte*)\"\\x12\\x06\" \"struct\")\nQDEF(MP_QSTR_sum, (const byte*)\"\\x2e\\x03\" \"sum\")\nQDEF(MP_QSTR_super, (const byte*)\"\\xc4\\x05\" \"super\")\nQDEF(MP_QSTR_symmetric_difference, (const byte*)\"\\xce\\x14\" \"symmetric_difference\")\nQDEF(MP_QSTR_symmetric_difference_update, (const byte*)\"\\x60\\x1b\" \"symmetric_difference_update\")\nQDEF(MP_QSTR_sync, (const byte*)\"\\xa2\\x04\" \"sync\")\nQDEF(MP_QSTR_tan, (const byte*)\"\\xfe\\x03\" \"tan\")\nQDEF(MP_QSTR_tanh, (const byte*)\"\\xd6\\x04\" \"tanh\")\nQDEF(MP_QSTR_throw, (const byte*)\"\\xb3\\x05\" \"throw\")\nQDEF(MP_QSTR_ticks_add, (const byte*)\"\\x9d\\x09\" \"ticks_add\")\nQDEF(MP_QSTR_ticks_cpu, (const byte*)\"\\x1a\\x09\" \"ticks_cpu\")\nQDEF(MP_QSTR_ticks_diff, (const byte*)\"\\xb1\\x0a\" \"ticks_diff\")\nQDEF(MP_QSTR_ticks_ms, (const byte*)\"\\x42\\x08\" \"ticks_ms\")\nQDEF(MP_QSTR_ticks_us, (const byte*)\"\\x5a\\x08\" \"ticks_us\")\nQDEF(MP_QSTR_time, (const byte*)\"\\xf0\\x04\" \"time\")\nQDEF(MP_QSTR_to_bytes, (const byte*)\"\\xd8\\x08\" \"to_bytes\")\nQDEF(MP_QSTR_trunc, (const byte*)\"\\x5b\\x05\" \"trunc\")\nQDEF(MP_QSTR_tuple, (const byte*)\"\\xfd\\x05\" \"tuple\")\nQDEF(MP_QSTR_type, (const byte*)\"\\x9d\\x04\" \"type\")\nQDEF(MP_QSTR_ubinascii, (const byte*)\"\\xc4\\x09\" \"ubinascii\")\nQDEF(MP_QSTR_ucollections, (const byte*)\"\\x15\\x0c\" \"ucollections\")\nQDEF(MP_QSTR_uctypes, (const byte*)\"\\xf8\\x07\" \"uctypes\")\nQDEF(MP_QSTR_udelay, (const byte*)\"\\x25\\x06\" \"udelay\")\nQDEF(MP_QSTR_uhashlib, (const byte*)\"\\x65\\x08\" \"uhashlib\")\nQDEF(MP_QSTR_uheapq, (const byte*)\"\\x1d\\x06\" \"uheapq\")\nQDEF(MP_QSTR_uio, (const byte*)\"\\xb6\\x03\" \"uio\")\nQDEF(MP_QSTR_ujson, (const byte*)\"\\xe8\\x05\" \"ujson\")\nQDEF(MP_QSTR_umachine, (const byte*)\"\\x95\\x08\" \"umachine\")\nQDEF(MP_QSTR_unhexlify, (const byte*)\"\\xb1\\x09\" \"unhexlify\")\nQDEF(MP_QSTR_uniform, (const byte*)\"\\x01\\x07\" \"uniform\")\nQDEF(MP_QSTR_union, (const byte*)\"\\xf6\\x05\" \"union\")\nQDEF(MP_QSTR_unique_id, (const byte*)\"\\x04\\x09\" \"unique_id\")\nQDEF(MP_QSTR_update, (const byte*)\"\\xb4\\x06\" \"update\")\nQDEF(MP_QSTR_upper, (const byte*)\"\\x27\\x05\" \"upper\")\nQDEF(MP_QSTR_urandom, (const byte*)\"\\xab\\x07\" \"urandom\")\nQDEF(MP_QSTR_ure, (const byte*)\"\\x87\\x03\" \"ure\")\nQDEF(MP_QSTR_utime, (const byte*)\"\\xe5\\x05\" \"utime\")\nQDEF(MP_QSTR_utimeq, (const byte*)\"\\xf4\\x06\" \"utimeq\")\nQDEF(MP_QSTR_uzlib, (const byte*)\"\\x6d\\x05\" \"uzlib\")\nQDEF(MP_QSTR_value, (const byte*)\"\\x4e\\x05\" \"value\")\nQDEF(MP_QSTR_values, (const byte*)\"\\x7d\\x06\" \"values\")\nQDEF(MP_QSTR_wfi, (const byte*)\"\\x9d\\x03\" \"wfi\")\nQDEF(MP_QSTR_write, (const byte*)\"\\x98\\x05\" \"write\")\nQDEF(MP_QSTR_zip, (const byte*)\"\\xe6\\x03\" \"zip\")\nQDEF(MP_QSTR_ustruct, (const byte*)\"\\x47\\x07\" \"ustruct\")\nQDEF(MP_QSTR_unpack, (const byte*)\"\\x07\\x06\" \"unpack\")\nQDEF(MP_QSTR_unpack_from, (const byte*)\"\\x0e\\x0b\" \"unpack_from\")\nQDEF(MP_QSTR_exit, (const byte*)\"\\x85\\x04\" \"exit\")\nQDEF(MP_QSTR_byteorder, (const byte*)\"\\x61\\x09\" \"byteorder\")\nQDEF(MP_QSTR_version_info, (const byte*)\"\\x6e\\x0c\" \"version_info\")\nQDEF(MP_QSTR_sys, (const byte*)\"\\xbc\\x03\" \"sys\")\nQDEF(MP_QSTR_usys, (const byte*)\"\\xc9\\x04\" \"usys\")\nQDEF(MP_QSTR_fileno, (const byte*)\"\\x82\\x06\" \"fileno\")\nQDEF(MP_QSTR_makefile, (const byte*)\"\\xc1\\x08\" \"makefile\")\nQDEF(MP_QSTR_usocket, (const byte*)\"\\x75\\x07\" \"usocket\")\nQDEF(MP_QSTR_getaddrinfo, (const byte*)\"\\x6e\\x0b\" \"getaddrinfo\")\nQDEF(MP_QSTR_inet_pton, (const byte*)\"\\xc9\\x09\" \"inet_pton\")\nQDEF(MP_QSTR_inet_ntop, (const byte*)\"\\x89\\x09\" \"inet_ntop\")\nQDEF(MP_QSTR_sockaddr, (const byte*)\"\\x62\\x08\" \"sockaddr\")\nQDEF(MP_QSTR_MSG_DONTROUTE, (const byte*)\"\\xeb\\x0d\" \"MSG_DONTROUTE\")\nQDEF(MP_QSTR_MSG_DONTWAIT, (const byte*)\"\\x99\\x0c\" \"MSG_DONTWAIT\")\nQDEF(MP_QSTR_SO_BROADCAST, (const byte*)\"\\xf9\\x0c\" \"SO_BROADCAST\")\nQDEF(MP_QSTR_AF_UNIX, (const byte*)\"\\xf7\\x07\" \"AF_UNIX\")\nQDEF(MP_QSTR_SO_ERROR, (const byte*)\"\\x3e\\x08\" \"SO_ERROR\")\nQDEF(MP_QSTR_uos, (const byte*)\"\\xec\\x03\" \"uos\")\nQDEF(MP_QSTR_stat, (const byte*)\"\\xd7\\x04\" \"stat\")\nQDEF(MP_QSTR_statvfs, (const byte*)\"\\x14\\x07\" \"statvfs\")\nQDEF(MP_QSTR_unlink, (const byte*)\"\\xfe\\x06\" \"unlink\")\nQDEF(MP_QSTR_chdir, (const byte*)\"\\xb1\\x05\" \"chdir\")\nQDEF(MP_QSTR_getcwd, (const byte*)\"\\x03\\x06\" \"getcwd\")\nQDEF(MP_QSTR_dupterm, (const byte*)\"\\xaa\\x07\" \"dupterm\")\nQDEF(MP_QSTR_umount, (const byte*)\"\\xdd\\x06\" \"umount\")\nQDEF(MP_QSTR_uname, (const byte*)\"\\xb7\\x05\" \"uname\")\nQDEF(MP_QSTR_sysname, (const byte*)\"\\x9b\\x07\" \"sysname\")\nQDEF(MP_QSTR_unregister, (const byte*)\"\\x17\\x0a\" \"unregister\")\nQDEF(MP_QSTR_uselect, (const byte*)\"\\x58\\x07\" \"uselect\")\nQDEF(MP_QSTR_writeblocks, (const byte*)\"\\x02\\x0b\" \"writeblocks\")\nQDEF(MP_QSTR_writebyte, (const byte*)\"\\xd2\\x09\" \"writebyte\")\nQDEF(MP_QSTR_tell, (const byte*)\"\\x14\\x04\" \"tell\")\nQDEF(MP_QSTR_listdir, (const byte*)\"\\x98\\x07\" \"listdir\")\nQDEF(MP_QSTR_ilistdir, (const byte*)\"\\x71\\x08\" \"ilistdir\")\nQDEF(MP_QSTR_mkdir, (const byte*)\"\\x9c\\x05\" \"mkdir\")\nQDEF(MP_QSTR_VfsFat, (const byte*)\"\\x15\\x06\" \"VfsFat\")\nQDEF(MP_QSTR_rename, (const byte*)\"\\x35\\x06\" \"rename\")\nQDEF(MP_QSTR_rmdir, (const byte*)\"\\x45\\x05\" \"rmdir\")\nQDEF(MP_QSTR_mkfs, (const byte*)\"\\x76\\x04\" \"mkfs\")\nQDEF(MP_QSTR_socket, (const byte*)\"\\x60\\x06\" \"socket\")\nQDEF(MP_QSTR_AF_INET6, (const byte*)\"\\x7d\\x08\" \"AF_INET6\")\nQDEF(MP_QSTR_SOCK_STREAM, (const byte*)\"\\x32\\x0b\" \"SOCK_STREAM\")\nQDEF(MP_QSTR_SOCK_DGRAM, (const byte*)\"\\xb3\\x0a\" \"SOCK_DGRAM\")\nQDEF(MP_QSTR_SOCK_RAW, (const byte*)\"\\xca\\x08\" \"SOCK_RAW\")\nQDEF(MP_QSTR_AF_INET, (const byte*)\"\\xeb\\x07\" \"AF_INET\")\nQDEF(MP_QSTR_connect, (const byte*)\"\\xdb\\x07\" \"connect\")\nQDEF(MP_QSTR_bind, (const byte*)\"\\x84\\x04\" \"bind\")\nQDEF(MP_QSTR_listen, (const byte*)\"\\xcc\\x06\" \"listen\")\nQDEF(MP_QSTR_accept, (const byte*)\"\\x85\\x06\" \"accept\")\nQDEF(MP_QSTR_recv, (const byte*)\"\\xe7\\x04\" \"recv\")\nQDEF(MP_QSTR_sendto, (const byte*)\"\\x22\\x06\" \"sendto\")\nQDEF(MP_QSTR_recvfrom, (const byte*)\"\\x91\\x08\" \"recvfrom\")\nQDEF(MP_QSTR_setsockopt, (const byte*)\"\\x38\\x0a\" \"setsockopt\")\nQDEF(MP_QSTR_settimeout, (const byte*)\"\\xdc\\x0a\" \"settimeout\")\nQDEF(MP_QSTR_setblocking, (const byte*)\"\\x6e\\x0b\" \"setblocking\")\nQDEF(MP_QSTR_calcsize, (const byte*)\"\\x4d\\x08\" \"calcsize\")\nQDEF(MP_QSTR_pack, (const byte*)\"\\xbc\\x04\" \"pack\")\nQDEF(MP_QSTR_pack_into, (const byte*)\"\\x1f\\x09\" \"pack_into\")\nQDEF(MP_QSTR_os, (const byte*)\"\\x79\\x02\" \"os\")\nQDEF(MP_QSTR_zlib, (const byte*)\"\\xf8\\x04\" \"zlib\")\nQDEF(MP_QSTR_hashlib, (const byte*)\"\\x10\\x07\" \"hashlib\")\nQDEF(MP_QSTR_binascii, (const byte*)\"\\x91\\x08\" \"binascii\")\nQDEF(MP_QSTR_collections, (const byte*)\"\\xe0\\x0b\" \"collections\")\nQDEF(MP_QSTR_re, (const byte*)\"\\xd2\\x02\" \"re\")\nQDEF(MP_QSTR_json, (const byte*)\"\\xfd\\x04\" \"json\")\nQDEF(MP_QSTR_heapq, (const byte*)\"\\x68\\x05\" \"heapq\")\nQDEF(MP_QSTR_path, (const byte*)\"\\x88\\x04\" \"path\")\nQDEF(MP_QSTR_argv, (const byte*)\"\\xc7\\x04\" \"argv\")\nQDEF(MP_QSTR_version, (const byte*)\"\\xbf\\x07\" \"version\")\nQDEF(MP_QSTR_implementation, (const byte*)\"\\x17\\x0e\" \"implementation\")\nQDEF(MP_QSTR_print_exception, (const byte*)\"\\x1c\\x0f\" \"print_exception\")\nQDEF(MP_QSTR_uerrno, (const byte*)\"\\xb4\\x06\" \"uerrno\")\nQDEF(MP_QSTR_errno, (const byte*)\"\\xc1\\x05\" \"errno\")\nQDEF(MP_QSTR_errorcode, (const byte*)\"\\x10\\x09\" \"errorcode\")\nQDEF(MP_QSTR_EPERM, (const byte*)\"\\xea\\x05\" \"EPERM\")\nQDEF(MP_QSTR_ENOBUFS, (const byte*)\"\\xe3\\x07\" \"ENOBUFS\")\nQDEF(MP_QSTR_ENODEV, (const byte*)\"\\xb6\\x06\" \"ENODEV\")\nQDEF(MP_QSTR_ENOENT, (const byte*)\"\\x5e\\x06\" \"ENOENT\")\nQDEF(MP_QSTR_ENOMEM, (const byte*)\"\\xa4\\x06\" \"ENOMEM\")\nQDEF(MP_QSTR_ENOTCONN, (const byte*)\"\\x79\\x08\" \"ENOTCONN\")\nQDEF(MP_QSTR_EOPNOTSUPP, (const byte*)\"\\xac\\x0a\" \"EOPNOTSUPP\")\nQDEF(MP_QSTR_ETIMEDOUT, (const byte*)\"\\xff\\x09\" \"ETIMEDOUT\")\nQDEF(MP_QSTR_EIO, (const byte*)\"\\x86\\x03\" \"EIO\")\nQDEF(MP_QSTR_EBADF, (const byte*)\"\\x61\\x05\" \"EBADF\")\nQDEF(MP_QSTR_EAGAIN, (const byte*)\"\\x20\\x06\" \"EAGAIN\")\nQDEF(MP_QSTR_EACCES, (const byte*)\"\\x37\\x06\" \"EACCES\")\nQDEF(MP_QSTR_EEXIST, (const byte*)\"\\x53\\x06\" \"EEXIST\")\nQDEF(MP_QSTR_EISDIR, (const byte*)\"\\xa5\\x06\" \"EISDIR\")\nQDEF(MP_QSTR_EINVAL, (const byte*)\"\\x5c\\x06\" \"EINVAL\")\nQDEF(MP_QSTR_EADDRINUSE, (const byte*)\"\\x17\\x0a\" \"EADDRINUSE\")\nQDEF(MP_QSTR_ECONNABORTED, (const byte*)\"\\x27\\x0c\" \"ECONNABORTED\")\nQDEF(MP_QSTR_ECONNREFUSED, (const byte*)\"\\x3a\\x0c\" \"ECONNREFUSED\")\nQDEF(MP_QSTR_ECONNRESET, (const byte*)\"\\x19\\x0a\" \"ECONNRESET\")\nQDEF(MP_QSTR_EHOSTUNREACH, (const byte*)\"\\x86\\x0c\" \"EHOSTUNREACH\")\nQDEF(MP_QSTR_EALREADY, (const byte*)\"\\x46\\x08\" \"EALREADY\")\nQDEF(MP_QSTR_EINPROGRESS, (const byte*)\"\\x9a\\x0b\" \"EINPROGRESS\")\nQDEF(MP_QSTR_ussl, (const byte*)\"\\x1c\\x04\" \"ussl\")\nQDEF(MP_QSTR_ssl, (const byte*)\"\\xe9\\x03\" \"ssl\")\nQDEF(MP_QSTR_wrap_socket, (const byte*)\"\\xcb\\x0b\" \"wrap_socket\")\nQDEF(MP_QSTR_getpeercert, (const byte*)\"\\xb1\\x0b\" \"getpeercert\")\nQDEF(MP_QSTR_cert, (const byte*)\"\\x25\\x04\" \"cert\")\nQDEF(MP_QSTR_server_side, (const byte*)\"\\x64\\x0b\" \"server_side\")\nQDEF(MP_QSTR_server_hostname, (const byte*)\"\\x58\\x0f\" \"server_hostname\")\nQDEF(MP_QSTR_readlines, (const byte*)\"\\x6a\\x09\" \"readlines\")\nQDEF(MP_QSTR_decode, (const byte*)\"\\xa9\\x06\" \"decode\")\nQDEF(MP_QSTR_delattr, (const byte*)\"\\xdb\\x07\" \"delattr\")\nQDEF(MP_QSTR_FileIO, (const byte*)\"\\xc5\\x06\" \"FileIO\")\nQDEF(MP_QSTR_TextIOWrapper, (const byte*)\"\\xad\\x0d\" \"TextIOWrapper\")\nQDEF(MP_QSTR_io, (const byte*)\"\\x23\\x02\" \"io\")\nQDEF(MP_QSTR_stdin, (const byte*)\"\\x21\\x05\" \"stdin\")\nQDEF(MP_QSTR_stdout, (const byte*)\"\\x08\\x06\" \"stdout\")\nQDEF(MP_QSTR_stderr, (const byte*)\"\\xa3\\x06\" \"stderr\")\nQDEF(MP_QSTR_platform, (const byte*)\"\\x3a\\x08\" \"platform\")\nQDEF(MP_QSTR_deque, (const byte*)\"\\x05\\x05\" \"deque\")\nQDEF(MP_QSTR_select, (const byte*)\"\\x8d\\x06\" \"select\")\nQDEF(MP_QSTR_poll, (const byte*)\"\\x9a\\x04\" \"poll\")\nQDEF(MP_QSTR_POLLERR, (const byte*)\"\\xdf\\x07\" \"POLLERR\")\nQDEF(MP_QSTR_POLLHUP, (const byte*)\"\\x77\\x07\" \"POLLHUP\")\nQDEF(MP_QSTR_POLLIN, (const byte*)\"\\x7d\\x06\" \"POLLIN\")\nQDEF(MP_QSTR_POLLOUT, (const byte*)\"\\x74\\x07\" \"POLLOUT\")\nQDEF(MP_QSTR_ipoll, (const byte*)\"\\x53\\x05\" \"ipoll\")\nQDEF(MP_QSTR_register, (const byte*)\"\\xac\\x08\" \"register\")\nQDEF(MP_QSTR_modify, (const byte*)\"\\xf5\\x06\" \"modify\")\nQDEF(MP_QSTR_SOL_SOCKET, (const byte*)\"\\x0f\\x0a\" \"SOL_SOCKET\")\nQDEF(MP_QSTR_SO_REUSEADDR, (const byte*)\"\\x21\\x0c\" \"SO_REUSEADDR\")\nQDEF(MP_QSTR_pend_throw, (const byte*)\"\\xf3\\x0a\" \"pend_throw\")\nQDEF(MP_QSTR__space_, (const byte*)\"\\xe1\\x01\" \" \")\nQDEF(MP_QSTR_encode, (const byte*)\"\\x43\\x06\" \"encode\")\nQDEF(MP_QSTR_nodename, (const byte*)\"\\x62\\x08\" \"nodename\")\nQDEF(MP_QSTR_file, (const byte*)\"\\xc3\\x04\" \"file\")\nQDEF(MP_QSTR_r, (const byte*)\"\\xd7\\x01\" \"r\")\nQDEF(MP_QSTR_buffering, (const byte*)\"\\x25\\x09\" \"buffering\")\nQDEF(MP_QSTR_encoding, (const byte*)\"\\x06\\x08\" \"encoding\")\nQDEF(MP_QSTR___dict__, (const byte*)\"\\x7f\\x08\" \"__dict__\")\nQDEF(MP_QSTR_release, (const byte*)\"\\xec\\x07\" \"release\")\nQDEF(MP_QSTR_iterable, (const byte*)\"\\x25\\x08\" \"iterable\")\nQDEF(MP_QSTR_quit, (const byte*)\"\\x5c\\x04\" \"quit\")\nQDEF(MP_QSTR_addr, (const byte*)\"\\xb6\\x04\" \"addr\")\nQDEF(MP_QSTR_addrsize, (const byte*)\"\\x93\\x08\" \"addrsize\")\nQDEF(MP_QSTR_I2C, (const byte*)\"\\x5d\\x03\" \"I2C\")\nQDEF(MP_QSTR_memaddr, (const byte*)\"\\x93\\x07\" \"memaddr\")\nQDEF(MP_QSTR_readfrom_into, (const byte*)\"\\x82\\x0d\" \"readfrom_into\")\nQDEF(MP_QSTR_readfrom_mem, (const byte*)\"\\x3b\\x0c\" \"readfrom_mem\")\nQDEF(MP_QSTR_readfrom_mem_into, (const byte*)\"\\x38\\x11\" \"readfrom_mem_into\")\nQDEF(MP_QSTR_readfrom, (const byte*)\"\\x41\\x08\" \"readfrom\")\nQDEF(MP_QSTR_scan, (const byte*)\"\\x1a\\x04\" \"scan\")\nQDEF(MP_QSTR_sck, (const byte*)\"\\xfe\\x03\" \"sck\")\nQDEF(MP_QSTR_scl, (const byte*)\"\\xf9\\x03\" \"scl\")\nQDEF(MP_QSTR_sda, (const byte*)\"\\x53\\x03\" \"sda\")\nQDEF(MP_QSTR_arg, (const byte*)\"\\x91\\x03\" \"arg\")\nQDEF(MP_QSTR_timeout, (const byte*)\"\\x3e\\x07\" \"timeout\")\nQDEF(MP_QSTR_writeto_mem, (const byte*)\"\\x79\\x0b\" \"writeto_mem\")\nQDEF(MP_QSTR_writeto, (const byte*)\"\\x03\\x07\" \"writeto\")\nQDEF(MP_QSTR_deinit, (const byte*)\"\\x9e\\x06\" \"deinit\")\nQDEF(MP_QSTR_firstbit, (const byte*)\"\\x20\\x08\" \"firstbit\")\nQDEF(MP_QSTR_mosi, (const byte*)\"\\x1d\\x04\" \"mosi\")\nQDEF(MP_QSTR_polarity, (const byte*)\"\\x41\\x08\" \"polarity\")\nQDEF(MP_QSTR_SPI, (const byte*)\"\\xef\\x03\" \"SPI\")\nQDEF(MP_QSTR_baudrate, (const byte*)\"\\xf5\\x08\" \"baudrate\")\nQDEF(MP_QSTR_bits, (const byte*)\"\\x49\\x04\" \"bits\")\nQDEF(MP_QSTR_miso, (const byte*)\"\\x9d\\x04\" \"miso\")\nQDEF(MP_QSTR_MSB, (const byte*)\"\\x59\\x03\" \"MSB\")\nQDEF(MP_QSTR_SoftSPI, (const byte*)\"\\x21\\x07\" \"SoftSPI\")\nQDEF(MP_QSTR_write_readinto, (const byte*)\"\\x89\\x0e\" \"write_readinto\")\nQDEF(MP_QSTR_LSB, (const byte*)\"\\xd8\\x03\" \"LSB\")\nQDEF(MP_QSTR__thread, (const byte*)\"\\xd4\\x07\" \"_thread\")\nQDEF(MP_QSTR_acquire, (const byte*)\"\\x1d\\x07\" \"acquire\")\nQDEF(MP_QSTR_locked, (const byte*)\"\\x0f\\x06\" \"locked\")\nQDEF(MP_QSTR_lock, (const byte*)\"\\xae\\x04\" \"lock\")\nQDEF(MP_QSTR_LockType, (const byte*)\"\\x36\\x08\" \"LockType\")\nQDEF(MP_QSTR_get_ident, (const byte*)\"\\xfe\\x09\" \"get_ident\")\nQDEF(MP_QSTR_stack_size, (const byte*)\"\\x31\\x0a\" \"stack_size\")\nQDEF(MP_QSTR_start_new_thread, (const byte*)\"\\xd7\\x10\" \"start_new_thread\")\nQDEF(MP_QSTR_allocate_lock, (const byte*)\"\\xec\\x0d\" \"allocate_lock\")\nQDEF(MP_QSTR_UART, (const byte*)\"\\xb7\\x04\" \"UART\")\nQDEF(MP_QSTR_writechar, (const byte*)\"\\x40\\x09\" \"writechar\")\nQDEF(MP_QSTR_readchar, (const byte*)\"\\xef\\x08\" \"readchar\")\nQDEF(MP_QSTR_sendbreak, (const byte*)\"\\xc6\\x09\" \"sendbreak\")\nQDEF(MP_QSTR_RTS, (const byte*)\"\\xb0\\x03\" \"RTS\")\nQDEF(MP_QSTR_CTS, (const byte*)\"\\x61\\x03\" \"CTS\")\nQDEF(MP_QSTR_parity, (const byte*)\"\\x42\\x06\" \"parity\")\nQDEF(MP_QSTR_flow, (const byte*)\"\\x37\\x04\" \"flow\")\nQDEF(MP_QSTR_timeout_char, (const byte*)\"\\x79\\x0c\" \"timeout_char\")\nQDEF(MP_QSTR_read_buf_len, (const byte*)\"\\xa1\\x0c\" \"read_buf_len\")\nQDEF(MP_QSTR_mktime, (const byte*)\"\\x96\\x06\" \"mktime\")\nQDEF(MP_QSTR_localtime, (const byte*)\"\\x7d\\x09\" \"localtime\")\nQDEF(MP_QSTR_IPPROTO_IP, (const byte*)\"\\x0c\\x0a\" \"IPPROTO_IP\")\nQDEF(MP_QSTR_IPPROTO_ICMP, (const byte*)\"\\xa2\\x0c\" \"IPPROTO_ICMP\")\nQDEF(MP_QSTR_IPPROTO_IPV4, (const byte*)\"\\x2e\\x0c\" \"IPPROTO_IPV4\")\nQDEF(MP_QSTR_IPPROTO_TCP, (const byte*)\"\\xb2\\x0b\" \"IPPROTO_TCP\")\nQDEF(MP_QSTR_IPPROTO_UDP, (const byte*)\"\\x54\\x0b\" \"IPPROTO_UDP\")\nQDEF(MP_QSTR_IPPROTO_IPV6, (const byte*)\"\\x2c\\x0c\" \"IPPROTO_IPV6\")\nQDEF(MP_QSTR_IPPROTO_RAW, (const byte*)\"\\xf1\\x0b\" \"IPPROTO_RAW\")\nQDEF(MP_QSTR_websocket, (const byte*)\"\\x90\\x09\" \"websocket\")\nQDEF(MP_QSTR__webrepl, (const byte*)\"\\x21\\x08\" \"_webrepl\")\nQDEF(MP_QSTR_ioctl, (const byte*)\"\\x78\\x05\" \"ioctl\")\nQDEF(MP_QSTR_password, (const byte*)\"\\x9a\\x08\" \"password\")\nQDEF(MP_QSTR_rb, (const byte*)\"\\xd5\\x02\" \"rb\")\nQDEF(MP_QSTR_wb, (const byte*)\"\\x70\\x02\" \"wb\")\nQDEF(MP_QSTR_IP_ADD_MEMBERSHIP, (const byte*)\"\\x6f\\x11\" \"IP_ADD_MEMBERSHIP\")\nQDEF(MP_QSTR_sendall, (const byte*)\"\\x38\\x07\" \"sendall\")\nQDEF(MP_QSTR_sha1, (const byte*)\"\\x8e\\x04\" \"sha1\")\nQDEF(MP_QSTR_readbit, (const byte*)\"\\x08\\x07\" \"readbit\")\nQDEF(MP_QSTR_readbyte, (const byte*)\"\\x7d\\x08\" \"readbyte\")\nQDEF(MP_QSTR_writebit, (const byte*)\"\\xc7\\x08\" \"writebit\")\nQDEF(MP_QSTR_flags, (const byte*)\"\\xfa\\x05\" \"flags\")\nQDEF(MP_QSTR_trigger, (const byte*)\"\\x9d\\x07\" \"trigger\")\nQDEF(MP_QSTR_handler, (const byte*)\"\\xdd\\x07\" \"handler\")\nQDEF(MP_QSTR_crc8, (const byte*)\"\\xcf\\x04\" \"crc8\")\nQDEF(MP_QSTR_hard, (const byte*)\"\\xda\\x04\" \"hard\")\nQDEF(MP_QSTR_irq, (const byte*)\"\\x8f\\x03\" \"irq\")\nQDEF(MP_QSTR_onewire, (const byte*)\"\\x28\\x07\" \"onewire\")\nQDEF(MP_QSTR___dir__, (const byte*)\"\\x7a\\x07\" \"__dir__\")\nQDEF(MP_QSTR___int__, (const byte*)\"\\x16\\x07\" \"__int__\")\nQDEF(MP_QSTR_schedule, (const byte*)\"\\xe0\\x08\" \"schedule\")\nQDEF(MP_QSTR_SHORT, (const byte*)\"\\xf7\\x05\" \"SHORT\")\nQDEF(MP_QSTR_USHORT, (const byte*)\"\\xa2\\x06\" \"USHORT\")\nQDEF(MP_QSTR_INT, (const byte*)\"\\x36\\x03\" \"INT\")\nQDEF(MP_QSTR_UINT, (const byte*)\"\\x23\\x04\" \"UINT\")\nQDEF(MP_QSTR_LONG, (const byte*)\"\\x0f\\x04\" \"LONG\")\nQDEF(MP_QSTR_ULONG, (const byte*)\"\\x7a\\x05\" \"ULONG\")\nQDEF(MP_QSTR_LONGLONG, (const byte*)\"\\x85\\x08\" \"LONGLONG\")\nQDEF(MP_QSTR_ULONGLONG, (const byte*)\"\\x70\\x09\" \"ULONGLONG\")\nQDEF(MP_QSTR_ffi, (const byte*)\"\\x8c\\x03\" \"ffi\")\nQDEF(MP_QSTR_callback, (const byte*)\"\\x4c\\x08\" \"callback\")\nQDEF(MP_QSTR_func, (const byte*)\"\\x1b\\x04\" \"func\")\nQDEF(MP_QSTR_as_bytearray, (const byte*)\"\\x1b\\x0c\" \"as_bytearray\")\nQDEF(MP_QSTR_var, (const byte*)\"\\xe0\\x03\" \"var\")\nQDEF(MP_QSTR_ffimod, (const byte*)\"\\xca\\x06\" \"ffimod\")\nQDEF(MP_QSTR_ffifunc, (const byte*)\"\\x92\\x07\" \"ffifunc\")\nQDEF(MP_QSTR_fficallback, (const byte*)\"\\xc5\\x0b\" \"fficallback\")\nQDEF(MP_QSTR_ffivar, (const byte*)\"\\x49\\x06\" \"ffivar\")\nQDEF(MP_QSTR_ADC, (const byte*)\"\\x63\\x03\" \"ADC\")\nQDEF(MP_QSTR_duty, (const byte*)\"\\x19\\x04\" \"duty\")\nQDEF(MP_QSTR_PWM, (const byte*)\"\\x4f\\x03\" \"PWM\")\nQDEF(MP_QSTR_network, (const byte*)\"\\x5b\\x07\" \"network\")\nQDEF(MP_QSTR_isconnected, (const byte*)\"\\x80\\x0b\" \"isconnected\")\nQDEF(MP_QSTR_WLAN, (const byte*)\"\\x11\\x04\" \"WLAN\")\nQDEF(MP_QSTR_disconnect, (const byte*)\"\\xa5\\x0a\" \"disconnect\")\nQDEF(MP_QSTR_active, (const byte*)\"\\x69\\x06\" \"active\")\nQDEF(MP_QSTR_STA_IF, (const byte*)\"\\xb3\\x06\" \"STA_IF\")\nQDEF(MP_QSTR_AP_IF, (const byte*)\"\\x04\\x05\" \"AP_IF\")\nQDEF(MP_QSTR_bssid, (const byte*)\"\\x4a\\x05\" \"bssid\")\nQDEF(MP_QSTR_status, (const byte*)\"\\x71\\x06\" \"status\")\nQDEF(MP_QSTR_rssi, (const byte*)\"\\x7e\\x04\" \"rssi\")\nQDEF(MP_QSTR_config, (const byte*)\"\\x4f\\x06\" \"config\")\nQDEF(MP_QSTR_ifconfig, (const byte*)\"\\xe0\\x08\" \"ifconfig\")\nQDEF(MP_QSTR_mac, (const byte*)\"\\xaa\\x03\" \"mac\")\nQDEF(MP_QSTR_essid, (const byte*)\"\\x4d\\x05\" \"essid\")\nQDEF(MP_QSTR_hidden, (const byte*)\"\\xef\\x06\" \"hidden\")\nQDEF(MP_QSTR_authmode, (const byte*)\"\\xce\\x08\" \"authmode\")\nQDEF(MP_QSTR_channel, (const byte*)\"\\x26\\x07\" \"channel\")\nQDEF(MP_QSTR_dhcp_hostname, (const byte*)\"\\xa2\\x0d\" \"dhcp_hostname\")\nQDEF(MP_QSTR_STAT_GOT_IP, (const byte*)\"\\xb2\\x0b\" \"STAT_GOT_IP\")\nQDEF(MP_QSTR_STAT_CONNECT_FAIL, (const byte*)\"\\x0b\\x11\" \"STAT_CONNECT_FAIL\")\nQDEF(MP_QSTR_STAT_NO_AP_FOUND, (const byte*)\"\\xee\\x10\" \"STAT_NO_AP_FOUND\")\nQDEF(MP_QSTR_STAT_WRONG_PASSWORD, (const byte*)\"\\x0b\\x13\" \"STAT_WRONG_PASSWORD\")\nQDEF(MP_QSTR_STAT_CONNECTING, (const byte*)\"\\xf6\\x0f\" \"STAT_CONNECTING\")\nQDEF(MP_QSTR_STAT_IDLE, (const byte*)\"\\x0c\\x09\" \"STAT_IDLE\")\nQDEF(MP_QSTR_now, (const byte*)\"\\xb3\\x03\" \"now\")\nQDEF(MP_QSTR_RTC, (const byte*)\"\\xa0\\x03\" \"RTC\")\nQDEF(MP_QSTR_command, (const byte*)\"\\x02\\x07\" \"command\")\nQDEF(MP_QSTR_contrast, (const byte*)\"\\x07\\x08\" \"contrast\")\nQDEF(MP_QSTR_light, (const byte*)\"\\xfb\\x05\" \"light\")\nQDEF(MP_QSTR_fill, (const byte*)\"\\xca\\x04\" \"fill\")\nQDEF(MP_QSTR_pixel, (const byte*)\"\\x4d\\x05\" \"pixel\")\nQDEF(MP_QSTR_show, (const byte*)\"\\x86\\x04\" \"show\")\nQDEF(MP_QSTR_LCD, (const byte*)\"\\xce\\x03\" \"LCD\")\nQDEF(MP_QSTR_text, (const byte*)\"\\x98\\x04\" \"text\")\nQDEF(MP_QSTR_WHITE, (const byte*)\"\\xa2\\x05\" \"WHITE\")\nQDEF(MP_QSTR_BLACK, (const byte*)\"\\x82\\x05\" \"BLACK\")\nQDEF(MP_QSTR_BLUE, (const byte*)\"\\x3b\\x04\" \"BLUE\")\nQDEF(MP_QSTR_BRED, (const byte*)\"\\x34\\x04\" \"BRED\")\nQDEF(MP_QSTR_GRED, (const byte*)\"\\x91\\x04\" \"GRED\")\nQDEF(MP_QSTR_GBLUE, (const byte*)\"\\x5c\\x05\" \"GBLUE\")\nQDEF(MP_QSTR_RED, (const byte*)\"\\x96\\x03\" \"RED\")\nQDEF(MP_QSTR_MAGENTA, (const byte*)\"\\xf0\\x07\" \"MAGENTA\")\nQDEF(MP_QSTR_GREEN, (const byte*)\"\\xde\\x05\" \"GREEN\")\nQDEF(MP_QSTR_CYAN, (const byte*)\"\\x10\\x04\" \"CYAN\")\nQDEF(MP_QSTR_YELLOW, (const byte*)\"\\x41\\x06\" \"YELLOW\")\nQDEF(MP_QSTR_BROWN, (const byte*)\"\\xc3\\x05\" \"BROWN\")\nQDEF(MP_QSTR_BRRED, (const byte*)\"\\x06\\x05\" \"BRRED\")\nQDEF(MP_QSTR_GRAY, (const byte*)\"\\x08\\x04\" \"GRAY\")\nQDEF(MP_QSTR_GRAY175, (const byte*)\"\\x1b\\x07\" \"GRAY175\")\nQDEF(MP_QSTR_GRAY151, (const byte*)\"\\xdd\\x07\" \"GRAY151\")\nQDEF(MP_QSTR_GRAY187, (const byte*)\"\\xb6\\x07\" \"GRAY187\")\nQDEF(MP_QSTR_GRAY240, (const byte*)\"\\x3e\\x07\" \"GRAY240\")\nQDEF(MP_QSTR_line, (const byte*)\"\\xcb\\x04\" \"line\")\nQDEF(MP_QSTR_rectangle, (const byte*)\"\\xa4\\x09\" \"rectangle\")\nQDEF(MP_QSTR_circle, (const byte*)\"\\xb7\\x06\" \"circle\")\nQDEF(MP_QSTR_WDT, (const byte*)\"\\x62\\x03\" \"WDT\")\nQDEF(MP_QSTR_feed, (const byte*)\"\\xa7\\x04\" \"feed\")\nQDEF(MP_QSTR_Timer, (const byte*)\"\\xa2\\x05\" \"Timer\")\nQDEF(MP_QSTR_ONE_SHOT, (const byte*)\"\\x5e\\x08\" \"ONE_SHOT\")\nQDEF(MP_QSTR_PERIODIC, (const byte*)\"\\x0a\\x08\" \"PERIODIC\")\nQDEF(MP_QSTR_period, (const byte*)\"\\xa0\\x06\" \"period\")\nQDEF(MP_QSTR_set_color, (const byte*)\"\\x25\\x09\" \"set_color\")\nQDEF(MP_QSTR_file_crc32, (const byte*)\"\\x6f\\x0a\" \"file_crc32\")\nQDEF(MP_QSTR_list_device, (const byte*)\"\\x20\\x0b\" \"list_device\")\nQDEF(MP_QSTR_show_image, (const byte*)\"\\xde\\x0a\" \"show_image\")\nQDEF(MP_QSTR_IRQ, (const byte*)\"\\xaf\\x03\" \"IRQ\")\nQDEF(MP_QSTR_IRQ_HIGH_LEVEL, (const byte*)\"\\x57\\x0e\" \"IRQ_HIGH_LEVEL\")\nQDEF(MP_QSTR_IRQ_LOW_LEVEL, (const byte*)\"\\x8d\\x0d\" \"IRQ_LOW_LEVEL\")\nQDEF(MP_QSTR_show_bmp, (const byte*)\"\\xe6\\x08\" \"show_bmp\")\nQDEF(MP_QSTR_userfunc, (const byte*)\"\\x4a\\x08\" \"userfunc\")\nQDEF(MP_QSTR_uarray, (const byte*)\"\\x89\\x06\" \"uarray\")\nQDEF(MP_QSTR_mpy, (const byte*)\"\\xc1\\x03\" \"mpy\")\nQDEF(MP_QSTR___matmul__, (const byte*)\"\\x49\\x0a\" \"__matmul__\")\nQDEF(MP_QSTR___bases__, (const byte*)\"\\x03\\x09\" \"__bases__\")\nQDEF(MP_QSTR_writevto, (const byte*)\"\\x75\\x08\" \"writevto\")\nQDEF(MP_QSTR_do_handshake, (const byte*)\"\\x86\\x0c\" \"do_handshake\")\nQDEF(MP_QSTR___ne__, (const byte*)\"\\x0e\\x06\" \"__ne__\")\nQDEF(MP_QSTR_i, (const byte*)\"\\xcc\\x01\" \"i\")\n\n#if MICROPY_USER_EXTMODS\n#include \"qstrdefs.user.extmods.h\"\n#endif\n"
  },
  {
    "path": "port/modules/machine/machine_adc.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 ChenYong (chenyong@rt-thread.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/nlr.h\"\n#include \"py/runtime.h\"\n#include \"modmachine.h\"\n#include \"mphalport.h\"\n\n#ifdef MICROPYTHON_USING_MACHINE_ADC\n\n#include <rtthread.h>\n#include <rtdevice.h>\n\nextern const mp_obj_type_t machine_adc_type;\n\ntypedef struct _machine_adc_obj_t {\n    mp_obj_base_t base;\n    struct rt_adc_device *adc_device;\n    uint8_t channel;\n    uint8_t is_init;\n} machine_adc_obj_t;\n\nSTATIC void error_check(bool status, const char *msg) {\n    if (!status) {\n        nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg));\n    }\n}\n\nSTATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type,\n                                  size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    // create ADC object from the given pin\n    machine_adc_obj_t *self = m_new_obj(machine_adc_obj_t);\n    struct rt_adc_device *adc_device = RT_NULL;\n    char adc_dev_name[RT_NAME_MAX] = {0};\n    rt_err_t result = RT_EOK;\n\n    // init machine adc object information\n    self->channel = 0;\n    self->is_init = RT_FALSE;\n    self->base.type = &machine_adc_type;\n\n    mp_arg_check_num(n_args, n_kw, 1, 2, true);\n\n    // check input ADC device name or ID\n    if (mp_obj_is_small_int(args[0])) {\n        rt_snprintf(adc_dev_name, sizeof(adc_dev_name), \"adc%d\", mp_obj_get_int(args[0]));\n    } else if (mp_obj_is_qstr(args[0])) {\n        rt_strncpy(adc_dev_name, mp_obj_str_get_str(args[0]), RT_NAME_MAX);\n    } else {\n        error_check(0, \"Input ADC device name or ID error.\");\n    }\n\n    adc_device = (struct rt_adc_device *) rt_device_find(adc_dev_name);\n    if (adc_device == RT_NULL || adc_device->parent.type != RT_Device_Class_Miscellaneous) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,\n                                                \"ADC(%s) don't exist\", adc_dev_name));\n    }\n    self->adc_device = adc_device;\n\n    if (n_args == 2) {\n        self->channel = mp_obj_get_int(args[1]);\n        result = rt_adc_enable(self->adc_device, self->channel);\n        error_check(result == RT_EOK, \"ADC enable error\");\n        self->is_init = RT_TRUE;\n    }\n\n    return MP_OBJ_FROM_PTR(self);\n}\n\nSTATIC mp_obj_t machine_adc_init(size_t n_args, const mp_obj_t *args) {\n    machine_adc_obj_t *self = MP_OBJ_TO_PTR(args[0]);\n    rt_err_t result = RT_EOK;\n\n    result = rt_adc_enable(self->adc_device, mp_obj_get_int(args[1]));\n    error_check(result == RT_EOK, \"ADC enable error\");\n    self->channel = mp_obj_get_int(args[1]);\n    self->is_init = RT_TRUE;\n\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_adc_init_obj, 2, 2, machine_adc_init);\n\nSTATIC mp_obj_t machine_adc_deinit(mp_obj_t self_in) {\n    machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    rt_err_t result = RT_EOK;\n\n    if (self->is_init == RT_TRUE) {\n        result = rt_adc_disable(self->adc_device, self->channel);\n        error_check(result == RT_EOK, \"ADC disable error\");\n        self->is_init = RT_FALSE;\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_deinit_obj, machine_adc_deinit);\n\nSTATIC mp_obj_t machine_adc_read(mp_obj_t self_in) {\n    machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    int tval = 0;\n\n    error_check(self->is_init == RT_TRUE, \"ADC device uninitialized\");\n\n    tval = rt_adc_read(self->adc_device, self->channel);\n    return MP_OBJ_NEW_SMALL_INT(tval);\n}\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_obj, machine_adc_read);\n\nSTATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_init),    MP_ROM_PTR(&machine_adc_init_obj) },\n    { MP_ROM_QSTR(MP_QSTR_deinit),  MP_ROM_PTR(&machine_adc_deinit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_read),    MP_ROM_PTR(&machine_adc_read_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict,\n                            machine_adc_locals_dict_table);\n\nconst mp_obj_type_t machine_adc_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_ADC,\n    .make_new = machine_adc_make_new,\n    .locals_dict = (mp_obj_dict_t *) &machine_adc_locals_dict,\n};\n\n#endif // MICROPYTHON_USING_MACHINE_adc\n"
  },
  {
    "path": "port/modules/machine/machine_adc.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 ChenYong (chenyong@rt-thread.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef MICROPY_INCLUDED_MACHINE_ADC_H\n#define MICROPY_INCLUDED_MACHINE_ADC_H\n\n#include \"py/obj.h\"\n#include <rtthread.h>\n\nextern const mp_obj_type_t machine_adc_type;\n\n#endif // MICROPY_INCLUDED_MACHINE_ADC_H\n"
  },
  {
    "path": "port/modules/machine/machine_hw_i2c.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 SummerGift <zhangyuan@rt-thread.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <rtdevice.h>\n\n#include \"py/runtime.h\"\n#include \"py/mphal.h\"\n#include \"py/mperrno.h\"\n#include \"extmod/machine_i2c.h\"\n\n#ifdef MICROPYTHON_USING_MACHINE_I2C\n\nSTATIC const mp_obj_type_t machine_hard_i2c_type;\n\nSTATIC const mp_arg_t machine_i2c_mem_allowed_args[] = {\n    { MP_QSTR_addr,    MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },\n    { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },\n    { MP_QSTR_arg,     MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },\n    { MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },\n};\n\ntypedef struct _machine_hard_i2c_obj_t {\n    mp_obj_base_t base;\n    struct rt_i2c_bus_device *i2c_bus;\n} machine_hard_i2c_obj_t;\n\n#ifndef RT_USING_I2C\n#error \"Please define the RT_USING_I2C on 'rtconfig.h'\"\n#endif\n\nSTATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print,\"I2C(%s, timeout=%u)\",\n            self->i2c_bus->parent.parent.name,\n            self->i2c_bus->timeout);\n    return;\n}\n\nSTATIC int write_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, const uint8_t *buf, size_t len) {\n    machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)MP_OBJ_TO_PTR(self_in);\n\n    // Create buffer with memory address\n    size_t memaddr_len = 0;\n    uint8_t memaddr_buf[4];\n    for (int16_t i = addrsize - 8; i >= 0; i -= 8) {\n        memaddr_buf[memaddr_len++] = memaddr >> i;\n    }\n\n    struct rt_i2c_msg msg[2];\n\n    msg[0].buf = memaddr_buf;\n    msg[0].len = (addrsize + 7)/8;\n    msg[0].flags = RT_I2C_WR;\n    msg[0].addr = addr;\n\n    msg[1].buf = (rt_uint8_t*)buf;\n    msg[1].len = len;\n    msg[1].flags = RT_I2C_WR;\n    msg[1].addr = addr;\n\n    if (rt_i2c_transfer(self->i2c_bus, msg, 2) != 2)\n        return -MP_EIO;\n\n    return len;\n}\n\nSTATIC int read_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, uint8_t *buf, size_t len) {\n    machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)MP_OBJ_TO_PTR(self_in);\n    uint8_t memaddr_buf[4];\n    size_t memaddr_len = 0;\n    for (int16_t i = addrsize - 8; i >= 0; i -= 8) {\n        memaddr_buf[memaddr_len++] = memaddr >> i;\n    }\n\n    struct rt_i2c_msg msg[2];\n\n    msg[0].buf = memaddr_buf;\n    msg[0].len = (addrsize + 7)/8;\n    msg[0].flags = RT_I2C_WR;\n    msg[0].addr = addr;\n\n    msg[1].buf = buf;\n    msg[1].len = len;\n    msg[1].flags = RT_I2C_RD;\n    msg[1].addr = addr;\n\n    if (rt_i2c_transfer(self->i2c_bus, msg, 2) != 2)\n        return -MP_EIO;\n\n    return len;\n}\n\nSTATIC int mp_machine_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) {\n    machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    return rt_i2c_master_recv(self->i2c_bus, addr, 0, dest, len);\n}\n\nSTATIC int mp_machine_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) {\n    uint8_t buf[1] = {0};\n    machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    if (len == 0){\n        len = 1;\n        if (src == NULL){\n            src = buf;\n        }\n        return !rt_i2c_master_send(self->i2c_bus, addr, 0, src, len);\n    } else if (src == NULL){\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, \"buf must not NULL\"));\n    }\n    return rt_i2c_master_send(self->i2c_bus, addr, 0, src, len);\n}\n\nSTATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) {\n    mp_obj_base_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t list = mp_obj_new_list(0, NULL);\n    // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved\n    for (int addr = 0x08; addr < 0x78; ++addr) {\n        int ret = mp_machine_i2c_writeto(self, addr, NULL, 0, true);\n        if (ret == 0) {\n            mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));\n        }\n    }\n    return list;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_scan_obj, machine_i2c_scan);\n\nSTATIC mp_obj_t machine_i2c_readfrom(size_t n_args, const mp_obj_t *args) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n    mp_int_t addr = mp_obj_get_int(args[1]);\n    vstr_t vstr;\n    vstr_init_len(&vstr, mp_obj_get_int(args[2]));\n    bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);\n    int ret = mp_machine_i2c_readfrom(self, addr, (uint8_t*)vstr.buf, vstr.len, stop);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_obj, 3, 4, machine_i2c_readfrom);\n\nSTATIC mp_obj_t machine_i2c_readfrom_into(size_t n_args, const mp_obj_t *args) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n    mp_int_t addr = mp_obj_get_int(args[1]);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);\n    bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);\n    int ret = mp_machine_i2c_readfrom(self, addr, bufinfo.buf, bufinfo.len, stop);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_into_obj, 3, 4, machine_i2c_readfrom_into);\n\nSTATIC mp_obj_t machine_i2c_writeto(size_t n_args, const mp_obj_t *args) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n    mp_int_t addr = mp_obj_get_int(args[1]);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);\n    bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);\n    int ret = mp_machine_i2c_writeto(self, addr, bufinfo.buf, bufinfo.len, stop);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n    // return number of acks received\n    return MP_OBJ_NEW_SMALL_INT(ret);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writeto_obj, 3, 4, machine_i2c_writeto);\n\nSTATIC mp_obj_t machine_i2c_writevto(size_t n_args, const mp_obj_t *args) {\n    mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);\n    mp_int_t addr = mp_obj_get_int(args[1]);\n\n    // Get the list of data buffer(s) to write\n    size_t nitems;\n    const mp_obj_t *items;\n    mp_obj_get_array(args[2], &nitems, (mp_obj_t**)&items);\n\n    // Get the stop argument\n    bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);\n\n    // Extract all buffer data, skipping zero-length buffers\n    size_t alloc = nitems == 0 ? 1 : nitems;\n    size_t nbufs = 0;\n    struct rt_i2c_msg *bufs = mp_local_alloc(alloc * sizeof(struct rt_i2c_msg));\n    for (; nitems--; ++items) {\n        mp_buffer_info_t bufinfo;\n        mp_get_buffer_raise(*items, &bufinfo, MP_BUFFER_READ);\n        if (bufinfo.len > 0) {\n            bufs[nbufs].addr = addr;\n            bufs[nbufs].flags = RT_I2C_WR;\n            bufs[nbufs].len = bufinfo.len;\n            bufs[nbufs++].buf = bufinfo.buf;\n        }\n    }\n\n    // Make sure there is at least one buffer, empty if needed\n    if (nbufs == 0) {\n        bufs[0].len = 0;\n        bufs[0].buf = NULL;\n        nbufs = 1;\n    }\n\n    // Do the I2C transfer\n    machine_hard_i2c_obj_t *i2c_p = (machine_hard_i2c_obj_t*)self;\n    int ret = rt_i2c_transfer(i2c_p->i2c_bus, bufs, nbufs);\n    mp_local_free(bufs);\n\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n\n    // Return number of acks received\n    return MP_OBJ_NEW_SMALL_INT(ret);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writevto_obj, 3, 4, machine_i2c_writevto);\n\nSTATIC mp_obj_t machine_i2c_readfrom_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_addr, ARG_memaddr, ARG_n, ARG_addrsize };\n    mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,\n        MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);\n\n    // create the buffer to store data into\n    vstr_t vstr;\n    vstr_init_len(&vstr, mp_obj_get_int(args[ARG_n].u_obj));\n\n    // do the transfer\n    int ret = read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,\n        args[ARG_addrsize].u_int, (uint8_t*)vstr.buf, vstr.len);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_obj, 1, machine_i2c_readfrom_mem);\n\nSTATIC mp_obj_t machine_i2c_readfrom_mem_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize };\n    mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,\n        MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);\n\n    // get the buffer to store data into\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_WRITE);\n\n    // do the transfer\n    int ret = read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,\n        args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_into_obj, 1, machine_i2c_readfrom_mem_into);\n\nSTATIC mp_obj_t machine_i2c_writeto_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize };\n    mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,\n        MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);\n\n    // get the buffer to write the data from\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ);\n\n    // do the transfer\n    int ret = write_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,\n        args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);\n    if (ret < 0) {\n        mp_raise_OSError(-ret);\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_mem_obj, 1, machine_i2c_writeto_mem);\n\nSTATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&machine_i2c_scan_obj) },\n\n    // standard bus operations\n    { MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&machine_i2c_readfrom_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&machine_i2c_readfrom_into_obj) },\n    { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&machine_i2c_writeto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_writevto), MP_ROM_PTR(&machine_i2c_writevto_obj) },\n\n    // memory operations\n    { MP_ROM_QSTR(MP_QSTR_readfrom_mem), MP_ROM_PTR(&machine_i2c_readfrom_mem_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readfrom_mem_into), MP_ROM_PTR(&machine_i2c_readfrom_mem_into_obj) },\n    { MP_ROM_QSTR(MP_QSTR_writeto_mem), MP_ROM_PTR(&machine_i2c_writeto_mem_obj) },\n};\n\n/******************************************************************************/\n/* MicroPython bindings for machine API                                       */\n\nmp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {\n    char iic_device[RT_NAME_MAX];\n\n    snprintf(iic_device, sizeof(iic_device), \"i2c%d\", mp_obj_get_int(all_args[0]));\n    struct rt_i2c_bus_device *i2c_bus = rt_i2c_bus_device_find(iic_device);\n\n    if (i2c_bus == RT_NULL) {\n        mp_printf(&mp_plat_print, \"can't find %s device\\r\\n\", iic_device);\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, \"I2C(%s) doesn't exist\", iic_device));\n    }\n\n    // create new hard I2C object\n    machine_hard_i2c_obj_t *self = m_new_obj(machine_hard_i2c_obj_t);\n    self->base.type = &machine_hard_i2c_type;\n    self->i2c_bus = i2c_bus;\n    return (mp_obj_t) self;\n}\n\nMP_DEFINE_CONST_DICT(mp_machine_hard_i2c_locals_dict, machine_i2c_locals_dict_table);\n\nSTATIC const mp_machine_i2c_p_t machine_hard_i2c_p = {\n    .start = NULL,\n    .stop = NULL,\n    .read = NULL,\n    .write = NULL,\n    .transfer = NULL,\n    .transfer_single = NULL,\n};\n\nSTATIC const mp_obj_type_t machine_hard_i2c_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_I2C,\n    .print = machine_hard_i2c_print,\n    .make_new = machine_hard_i2c_make_new,\n    .protocol = &machine_hard_i2c_p,\n    .locals_dict = (mp_obj_dict_t*)&mp_machine_hard_i2c_locals_dict,\n};\n\n#endif // MICROPYTHON_USING_MACHINE_I2C\n"
  },
  {
    "path": "port/modules/machine/machine_hw_spi.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 SummerGift <zhangyuan@rt-thread.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <rtdevice.h>\n\n#include \"py/runtime.h\"\n#include \"py/mphal.h\"\n#include \"extmod/machine_spi.h\"\n\n#ifdef MICROPYTHON_USING_MACHINE_SPI\n\n#ifndef RT_USING_SPI\n#error \"Please define the RT_USING_SPI on 'rtconfig.h'\"\n#endif\n\nSTATIC const mp_obj_type_t machine_hard_spi_type;\n\ntypedef struct _machine_hard_spi_obj_t {\n    mp_obj_base_t base;\n    struct rt_spi_device *spi_device;\n} machine_hard_spi_obj_t;\n\nSTATIC void machine_hard_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in;\n    mp_printf(print,\"SPI(device port : %s)\",self->spi_device->parent.parent.name);\n}\n\nmp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {\n    char spi_dev_name[RT_NAME_MAX];\n\n    snprintf(spi_dev_name, sizeof(spi_dev_name), \"spi%d\", mp_obj_get_int(all_args[0]));\n\n    struct rt_spi_device *rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);\n    if (rt_spi_device == RT_NULL || rt_spi_device->parent.type != RT_Device_Class_SPIDevice) {\n        mp_printf(&mp_plat_print, \"ERROR: SPI device %s not found!\\n\", spi_dev_name);\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, \"SPI(%s) doesn't exist\", spi_dev_name));\n    }\n\n    // create new hard SPI object\n    machine_hard_spi_obj_t *self = m_new_obj(machine_hard_spi_obj_t);\n    self->base.type = &machine_hard_spi_type;\n    self->spi_device = rt_spi_device;\n    return (mp_obj_t) self;\n}\n\n//SPI.init( baudrate=100000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB/LSB )\nSTATIC void machine_hard_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in;\n    rt_uint8_t mode = 0;\n    int baudrate = mp_obj_get_int(pos_args[0]);\n    int polarity = mp_obj_get_int(pos_args[1]);\n    int phase = mp_obj_get_int(pos_args[2]);\n    int bits = mp_obj_get_int(pos_args[3]);\n    int firstbit = mp_obj_get_int(pos_args[4]);\n\n    if(!polarity && !phase)\n    {\n        mode = RT_SPI_MODE_0;\n    }\n\n    if(!polarity && phase)\n    {\n        mode = RT_SPI_MODE_1;\n    }\n\n    if(polarity && !phase)\n    {\n        mode = RT_SPI_MODE_2;\n    }\n\n    if(polarity && phase)\n    {\n        mode = RT_SPI_MODE_3;\n    }\n\n    if(firstbit)\n    {\n        mode |= RT_SPI_MSB;\n    } else {\n        mode |= RT_SPI_LSB;\n    }\n\n    /* config spi */\n    {\n        struct rt_spi_configuration cfg;\n        cfg.data_width = bits;\n        cfg.mode = mode;\n        cfg.max_hz = baudrate;\n        rt_spi_configure(self->spi_device, &cfg);\n    }\n}\n\nSTATIC void machine_hard_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {\n    machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in;\n\n    if (src && dest) {\n        rt_spi_send_then_recv(self->spi_device, src, len, dest, len);\n    } else if (src) {\n        rt_spi_send(self->spi_device, src, len);\n    } else {\n        rt_spi_recv(self->spi_device, dest, len);\n    }\n}\n\nSTATIC const mp_machine_spi_p_t machine_hard_spi_p = {\n    .init = machine_hard_spi_init,\n    .deinit = NULL,\n    .transfer = machine_hard_spi_transfer,\n};\n\nSTATIC const mp_obj_type_t machine_hard_spi_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_SPI,\n    .print = machine_hard_spi_print,\n    .make_new = machine_hard_spi_make_new,\n    .protocol = &machine_hard_spi_p,\n    .locals_dict = (mp_obj_t)&mp_machine_spi_locals_dict,\n};\n\n#endif // MICROPYTHON_USING_MACHINE_SPI\n\n"
  },
  {
    "path": "port/modules/machine/machine_lcd.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 SummerGift <SummerGift@qq.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include \"py/mphal.h\"\n#include \"py/runtime.h\"\n#include \"py/mperrno.h\"\n\n#if MICROPY_PY_MACHINE_LCD\n#include <dfs_posix.h>\n#include \"machine_lcd.h\"\n#include <drv_lcd.h>\n\n#define MAX_CO (2400 - 1)\n\ntypedef struct _machine_lcd_obj_t {\n    mp_obj_base_t base;\n} machine_lcd_obj_t;\n\nSTATIC void error_check(bool status, const char *msg) {\n    if (!status) {\n        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, msg));\n    }\n}\n\n/// \\classmethod \\constructor(skin_position)\n///\n/// Construct an LCD object.  \nSTATIC mp_obj_t machine_lcd_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    // check arguments\n    mp_arg_check_num(n_args, n_kw, 0, 0, false);\n    \n    // create lcd object\n    machine_lcd_obj_t *lcd = m_new_obj(machine_lcd_obj_t);\n    lcd->base.type = &machine_lcd_type;\n\n    return MP_OBJ_FROM_PTR(lcd);\n}\n\n/// \\method light(value)\n///\n/// Turn the backlight on/off.  True or 1 turns it on, False or 0 turns it off.\nSTATIC mp_obj_t machine_lcd_light(mp_obj_t self_in, mp_obj_t value) {\n    if (mp_obj_is_true(value)) {\n        lcd_display_on(); // set pin high to turn backlight on\n    } else {\n        lcd_display_off();// set pin low to turn backlight off\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_lcd_light_obj, machine_lcd_light);\n\n/// \\method fill(colour)\n///\n/// Fill the screen with the given colour.\n///\nSTATIC mp_obj_t machine_lcd_fill(mp_obj_t self_in, mp_obj_t col_in) {\n    int col = mp_obj_get_int(col_in);\n    lcd_clear(col);\n    \n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_lcd_fill_obj, machine_lcd_fill);\n\n/// \\method pixel(x, y, colour)\n///\n/// Set the pixel at `(x, y)` to the given colour.\n///\nSTATIC mp_obj_t machine_lcd_pixel(size_t n_args, const mp_obj_t *args) {\n    int x = mp_obj_get_int(args[1]);\n    int y = mp_obj_get_int(args[2]);\n    \n    error_check((x >= 0 && x <= MAX_CO) && (y >= 0 && y <= MAX_CO) , \"The min/max X/Y coordinates is 0/239\");\n\n    int col = mp_obj_get_int(args[3]);\n    lcd_draw_point_color(x, y, col);\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lcd_pixel_obj, 4, 4, machine_lcd_pixel);\n\n/// \\method text(str, x, y, size)\n///\n/// Draw the given text to the position `(x, y)` using the given size (16 24 32).\n///\nSTATIC mp_obj_t machine_lcd_text(size_t n_args, const mp_obj_t *args) {\n    size_t len;\n    const char *data = mp_obj_str_get_data(args[1], &len);\n    int x = mp_obj_get_int(args[2]);\n    int y = mp_obj_get_int(args[3]);\n    int size = mp_obj_get_int(args[4]);\n    \n    error_check((x >= 0 && x <= MAX_CO) && (y >= 0 && y <= MAX_CO) , \"The min/max X/Y coordinates is 0/239\");\n    \n    error_check(size == 16 || size == 24 || size == 32, \"lcd only support font size 16 24 32\");\n    \n    lcd_show_string(x, y, size, data);\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lcd_text_obj, 5, 5, machine_lcd_text);\n\n/// \\method line(x1, y1, x2, y2)\n///\n/// display a line on the lcd, from (x1, y1) to (x2, y2).\n///\nSTATIC mp_obj_t machine_lcd_line(size_t n_args, const mp_obj_t *args) {\n    int x1 = mp_obj_get_int(args[1]);\n    int y1 = mp_obj_get_int(args[2]);\n    int x2 = mp_obj_get_int(args[3]);\n    int y2 = mp_obj_get_int(args[4]);\n    \n    error_check((x1 >= 0 && x1 <= MAX_CO) && (y1 >= 0 && y1 <= MAX_CO) , \"The min/max X/Y coordinates is 0/239\");\n    error_check((x2 >= 0 && x2 <= MAX_CO) && (y2 >= 0 && y2 <= MAX_CO) , \"The min/max X/Y coordinates is 0/239\");\n\n    lcd_draw_line(x1, y1, x2, y2);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lcd_line_obj, 5, 5, machine_lcd_line);\n\n/// \\method rectangle(x1, y1, x2, y2)\n///\n/// display a rectangle on the lcd, from (x1, y1) to (x2, y2).\n///\nSTATIC mp_obj_t machine_lcd_rectangle(size_t n_args, const mp_obj_t *args) {\n    int x1 = mp_obj_get_int(args[1]);\n    int y1 = mp_obj_get_int(args[2]);\n    int x2 = mp_obj_get_int(args[3]);\n    int y2 = mp_obj_get_int(args[4]);\n\n    error_check((x1 >= 0 && x1 <= MAX_CO) && (y1 >= 0 && y1 <= MAX_CO) , \"The min/max X/Y coordinates is 0/239\");\n    error_check((x2 >= 0 && x2 <= MAX_CO) && (y2 >= 0 && y2 <= MAX_CO) , \"The min/max X/Y coordinates is 0/239\");\n\n    lcd_draw_rectangle(x1, y1, x2, y2);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lcd_rectangle_obj, 5, 5, machine_lcd_rectangle);\n\n/// \\method circle(x1, y1, r)\n///\n/// display a circle on the lcd, center(x1, y1) R = r.\n///\nSTATIC mp_obj_t machine_lcd_circle(size_t n_args, const mp_obj_t *args) {\n    int x1 = mp_obj_get_int(args[1]);\n    int y1 = mp_obj_get_int(args[2]);\n    int r  = mp_obj_get_int(args[3]);\n\n    error_check((x1 >= 0 && x1 <= MAX_CO) && (y1 >= 0 && y1 <= MAX_CO) , \"The min/max X/Y coordinates is 0/239\");\n\n    lcd_draw_circle(x1, y1, r);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lcd_circle_obj, 4, 4, machine_lcd_circle);\n\n/// \\method set_color(back, fore)\n///\n/// Set background color and foreground color.\n///\nSTATIC mp_obj_t machine_lcd_set_color(size_t n_args, const mp_obj_t *args) {\n    rt_uint16_t back = mp_obj_get_int(args[1]);\n    rt_uint16_t fore = mp_obj_get_int(args[2]);\n\n    lcd_set_color(back, fore);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lcd_set_color_obj, 3, 3, machine_lcd_set_color);\n\n/// \\method show_image array\n///\n/// display the image on the lcd..\n/// @param   x       x position\n/// @param   y       y position\n/// @param   length  length of image\n/// @param   wide    wide of image\n/// @param   p       image_array\nSTATIC mp_obj_t machine_lcd_show_image(size_t n_args, const mp_obj_t *args) {\n    rt_uint16_t x = mp_obj_get_int(args[1]);\n    rt_uint16_t y = mp_obj_get_int(args[2]);\n    rt_uint16_t length = mp_obj_get_int(args[3]);\n    rt_uint16_t wide = mp_obj_get_int(args[4]);\n\n    mp_buffer_info_t bufinfo;\n    if (mp_get_buffer(args[5], &bufinfo, MP_BUFFER_READ)) \n    {\n        lcd_show_image( x, y, length, wide, (const rt_uint8_t *)bufinfo.buf);\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lcd_show_image_obj, 6, 6, machine_lcd_show_image);\n\nSTATIC rt_uint16_t rgb888to565(rt_uint32_t RGB) \n{\n     int R, G, B; \n     R = (RGB >> 19) & 0x1F; \n     G = (RGB >> 10) & 0x3F; \n     B = (RGB >> 3) & 0x1F; \n     return (R << 11) | (G << 5) | B; \n} \n\n/// \\method show_image array\n///\n/// display the image on the lcd.\n/// @param   x       x position\n/// @param   y       y position\n/// @param   file    bmp file pathname\nSTATIC mp_obj_t machine_lcd_show_bmp(size_t n_args, const mp_obj_t *args) {\n    #define BMP_INFO_SIZE 54\n    rt_uint16_t x = mp_obj_get_int(args[1]);\n    rt_uint16_t y = mp_obj_get_int(args[2]);\n    const char *pathname = mp_obj_str_get_str(args[3]);\n\n    int fd, len;\n    fd = open(pathname, O_RDONLY, 0);\n    if (fd < 0)\n    {\n         mp_raise_OSError(MP_EINVAL);\n    }\n\n    void *bmp_info = rt_malloc(BMP_INFO_SIZE);\n    if (bmp_info == RT_NULL)\n    {\n        mp_raise_OSError(MP_ENOMEM);\n    }\n\n    len = read(fd, bmp_info, BMP_INFO_SIZE);\n    if (len < 0)\n    {\n        close(fd);\n        mp_raise_OSError(MP_EINVAL);\n    }\n\n    rt_uint32_t width  = *(rt_uint32_t *)(bmp_info + 18);\n    rt_uint32_t heigth = *(rt_uint32_t *)(bmp_info + 22);\n    rt_uint16_t bit_count = *(rt_uint16_t *)(bmp_info + 28);\n    \n    if (bit_count != 32)\n    {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,\n              \"bit count : %d, only support 32-bit bmp picture\", bit_count));\n    }\n\n    void *image_buf = rt_malloc(2 * width);\n    if (image_buf == RT_NULL)\n    {\n        mp_raise_OSError(MP_ENOMEM);\n    }\n\n    void *row_buf = rt_malloc(4 * width);\n    if (row_buf == RT_NULL)\n    {\n        mp_raise_OSError(MP_ENOMEM);\n    }\n\n    int image_index, row_index;\n    rt_uint16_t rgb565_temp;\n\n    for(int i = 0; i < heigth; i++)\n    {\n        image_index = 0;\n        row_index = 0;\n\n        len = read(fd, row_buf, 4 * width);\n        if (len < 0)\n        {\n            close(fd);\n            mp_raise_OSError(MP_EINVAL);\n        }\n\n        while(row_index < (4 * width))\n        {\n            rgb565_temp = rgb888to565(*(rt_uint32_t *)(row_buf + row_index));\n            *(rt_uint8_t *)(image_buf + image_index) = (rgb565_temp >> 8);\n            *(rt_uint8_t *)(image_buf + image_index + 1) = rgb565_temp & 0xff;\n            \n            row_index   += 4;\n            image_index += 2;\n        }\n\n        lcd_show_image( x, y--, width, 1, (const rt_uint8_t *)image_buf);\n    }\n\n    close(fd);\n    rt_free(bmp_info);\n    rt_free(image_buf);\n    rt_free(row_buf);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lcd_show_bmp_obj, 4, 4, machine_lcd_show_bmp);\n\nSTATIC const mp_rom_map_elem_t machine_lcd_locals_dict_table[] = {\n    // instance methods\n    { MP_ROM_QSTR(MP_QSTR_light), MP_ROM_PTR(&machine_lcd_light_obj) },\n    { MP_ROM_QSTR(MP_QSTR_fill),  MP_ROM_PTR(&machine_lcd_fill_obj)  },\n    { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&machine_lcd_pixel_obj) },\n    { MP_ROM_QSTR(MP_QSTR_text),  MP_ROM_PTR(&machine_lcd_text_obj)  },\n    { MP_ROM_QSTR(MP_QSTR_line),  MP_ROM_PTR(&machine_lcd_line_obj)  },\n    { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&machine_lcd_rectangle_obj) },\n    { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&machine_lcd_circle_obj) }, \n    { MP_ROM_QSTR(MP_QSTR_set_color), MP_ROM_PTR(&machine_lcd_set_color_obj) }, \n    { MP_ROM_QSTR(MP_QSTR_show_image), MP_ROM_PTR(&machine_lcd_show_image_obj) }, \n    { MP_ROM_QSTR(MP_QSTR_show_bmp), MP_ROM_PTR(&machine_lcd_show_bmp_obj) }, \n    // color\n    { MP_ROM_QSTR(MP_QSTR_WHITE), MP_ROM_INT(WHITE) },\n    { MP_ROM_QSTR(MP_QSTR_BLACK), MP_ROM_INT(BLACK) },\n    { MP_ROM_QSTR(MP_QSTR_BLUE), MP_ROM_INT(BLUE) },\n    { MP_ROM_QSTR(MP_QSTR_BRED), MP_ROM_INT(BRED) },\n    { MP_ROM_QSTR(MP_QSTR_GRED), MP_ROM_INT(GRED) },\n    { MP_ROM_QSTR(MP_QSTR_GBLUE), MP_ROM_INT(GBLUE) },\n    { MP_ROM_QSTR(MP_QSTR_RED), MP_ROM_INT(RED) },\n    { MP_ROM_QSTR(MP_QSTR_MAGENTA), MP_ROM_INT(MAGENTA) },\n    { MP_ROM_QSTR(MP_QSTR_GREEN), MP_ROM_INT(GREEN) },\n    { MP_ROM_QSTR(MP_QSTR_CYAN), MP_ROM_INT(CYAN) },\n    { MP_ROM_QSTR(MP_QSTR_YELLOW), MP_ROM_INT(YELLOW) },\n    { MP_ROM_QSTR(MP_QSTR_BROWN), MP_ROM_INT(BROWN) },\n    { MP_ROM_QSTR(MP_QSTR_BRRED), MP_ROM_INT(BRRED) },\n    { MP_ROM_QSTR(MP_QSTR_GRAY), MP_ROM_INT(GRAY) },\n    { MP_ROM_QSTR(MP_QSTR_GRAY175), MP_ROM_INT(GRAY175) },\n    { MP_ROM_QSTR(MP_QSTR_GRAY151), MP_ROM_INT(GRAY151) },\n    { MP_ROM_QSTR(MP_QSTR_GRAY187), MP_ROM_INT(GRAY187) },\n    { MP_ROM_QSTR(MP_QSTR_GRAY240), MP_ROM_INT(GRAY240) },\n};\nSTATIC MP_DEFINE_CONST_DICT(machine_lcd_locals_dict, machine_lcd_locals_dict_table);\n\nconst mp_obj_type_t machine_lcd_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_LCD,\n    .make_new = machine_lcd_make_new,\n    .locals_dict = (mp_obj_dict_t*)&machine_lcd_locals_dict,\n};\n\n#endif // MICROPY_PY_MACHINE_LCD\n"
  },
  {
    "path": "port/modules/machine/machine_lcd.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 SummerGift <SummerGift@qq.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_MACHINE_LCD_H\n#define MICROPY_INCLUDED_MACHINE_LCD_H\n\nextern const mp_obj_type_t machine_lcd_type;\n\n#endif // MICROPY_INCLUDED_MACHINE_LCD_H\n"
  },
  {
    "path": "port/modules/machine/machine_pin.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n#include <rtthread.h>\n#include <rtdevice.h>\n#include \"py/runtime.h\"\n#include \"py/gc.h\"\n#include \"py/mphal.h\"\n#include \"py/mperrno.h\"\n#include \"py/stream.h\"\n#include \"modmachine.h\"\n\n#if MICROPY_PY_PIN\n\n#define GPIO_MODE_IN                           ((uint32_t)0x00000000)   /*!< Input Floating Mode                   */\n#define GPIO_MODE_OUT_PP                       ((uint32_t)0x00000001)   /*!< Output Push Pull Mode                 */\n#define GPIO_MODE_OUT_OD                       ((uint32_t)0x00000011)   /*!< Output Open Drain Mode                */\n#define GPIO_MODE_AF_PP                        ((uint32_t)0x00000002)   /*!< Alternate Function Push Pull Mode     */\n#define GPIO_MODE_AF_OD                        ((uint32_t)0x00000012)   /*!< Alternate Function Open Drain Mode    */\n#define GPIO_MODE_ANALOG                       ((uint32_t)0x00000003)   /*!< Analog Mode  */\n#define GPIO_NOPULL                            ((uint32_t)0x00000000)   /*!< No Pull-up or Pull-down activation  */\n#define GPIO_PULLUP                            ((uint32_t)0x00000001)   /*!< Pull-up activation                  */\n#define GPIO_PULLDOWN                          ((uint32_t)0x00000002)   /*!< Pull-down activation                */\n#define GPIO_MODE_IT_RISING                    ((uint32_t)0x10110000)   /*!< External Interrupt Mode with Rising edge trigger detection          */\n#define GPIO_MODE_IT_FALLING                   ((uint32_t)0x10210000)   /*!< External Interrupt Mode with Falling edge trigger detection         */\n#define GPIO_MODE_IT_RISING_FALLING            ((uint32_t)0x10310000)   /*!< External Interrupt Mode with Rising/Falling edge trigger detection  */\n\nconst mp_obj_base_t machine_pin_obj_template = {&machine_pin_type};\n\nvoid mp_pin_od_write(void *machine_pin, int stat) {\n    if (stat == PIN_LOW) {\n        rt_pin_mode(((machine_pin_obj_t *)machine_pin)->pin, PIN_MODE_OUTPUT);\n        rt_pin_write(((machine_pin_obj_t *)machine_pin)->pin, stat);\n    } else {\n        rt_pin_mode(((machine_pin_obj_t *)machine_pin)->pin, PIN_MODE_INPUT_PULLUP);\n    }\n}\n\nvoid mp_hal_pin_open_set(void *machine_pin, int mode) {\n    rt_pin_mode(((machine_pin_obj_t *)machine_pin)->pin, mode);\n}\n\nchar* mp_hal_pin_get_name(void *machine_pin) {\n    return ((machine_pin_obj_t *)machine_pin)->name;\n}\n\nSTATIC mp_obj_t machine_pin_obj_init_helper(machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);\n\nSTATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    machine_pin_obj_t *self = self_in;\n    mp_printf(print, \"<Pin %d>\", self->pin);\n}\n\n// constructor(drv_name, pin, ...)\nmp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);\n\n    // get the wanted port\n    if (!MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)) {\n        mp_raise_ValueError(\"Pin id must be tuple of (\\\"GPIO_x\\\", pin#)\");\n    }\n    mp_obj_t *items;\n    mp_obj_get_array_fixed_n(args[0], 2, &items);\n    const char *pin_name = mp_obj_str_get_str(items[0]);\n    int wanted_pin = mp_obj_get_int(items[1]);\n\n    machine_pin_obj_t *pin = m_new_obj(machine_pin_obj_t);\n    if (!pin) {\n        mp_raise_OSError(MP_ENOMEM);\n    }\n\n    strncpy(pin->name, pin_name, sizeof(pin->name));\n    pin->base = machine_pin_obj_template;\n    pin->pin = wanted_pin;\n\n    if (n_args > 1 || n_kw > 0) {\n        // pin mode given, so configure this GPIO\n        mp_map_t kw_args;\n        mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);\n        machine_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);\n    }\n\n    return (mp_obj_t)pin;\n}\n\n// pin.init(mode, pull=None, *, value)\nSTATIC mp_obj_t machine_pin_obj_init_helper(machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_mode, ARG_pull, ARG_value };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },\n        { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}},\n        { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},\n    };\n\n    // parse args\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n\n    // get io mode\n    uint mode = args[ARG_mode].u_int;\n\n    // get pull mode\n    uint pull = GPIO_NOPULL;\n\n    if (args[ARG_pull].u_obj != mp_const_none) {\n        pull = mp_obj_get_int(args[ARG_pull].u_obj);\n    }\n\n    switch(mode) {\n    case GPIO_MODE_IN: {\n        if (pull == GPIO_PULLUP) {\n            mode = PIN_MODE_INPUT_PULLUP;\n        } else if (pull == GPIO_PULLDOWN) {\n            mode = PIN_MODE_INPUT_PULLDOWN;\n        } else {\n            mode = PIN_MODE_INPUT;\n        }\n        break;\n    }\n    case GPIO_MODE_OUT_PP : {\n        mode = PIN_MODE_OUTPUT;\n        break;\n    }\n    case GPIO_MODE_OUT_OD : {\n        mode = PIN_MODE_OUTPUT_OD;\n        break;\n    }\n    case GPIO_MODE_AF_PP :\n    case GPIO_MODE_AF_OD :\n    case GPIO_MODE_ANALOG :\n        //TODO\n        mp_raise_NotImplementedError(\"not implemented pin mode\");\n    }\n\n    rt_pin_mode(self->pin, mode);\n\n    // get initial value\n    if (args[ARG_value].u_obj != MP_OBJ_NULL) {\n        rt_pin_write(self->pin, mp_obj_is_true(args[ARG_value].u_obj));\n    }\n\n    return mp_const_none;\n}\n\n// fast method for getting/setting pin value\nSTATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n    machine_pin_obj_t *self = self_in;\n    if (n_args == 0) {\n        return mp_obj_new_bool(rt_pin_read(self->pin));\n    } else {\n        rt_pin_write(self->pin, mp_obj_is_true(args[0]));\n        return mp_const_none;\n    }\n}\n\n// pin.init(mode, pull)\nSTATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {\n    return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init);\n\n// pin.value([value])\nSTATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) {\n    return machine_pin_call(args[0], n_args - 1, 0, args + 1);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value);\n\n// pin.name()\nSTATIC mp_obj_t machine_pin_name(size_t n_args, const mp_obj_t *args) {\n    machine_pin_obj_t *self = (machine_pin_obj_t *)args[0];\n    return mp_obj_new_str(self->name, strlen(self->name));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_name_obj, 1, 2, machine_pin_name);\n\n// pin.pin()\nSTATIC mp_obj_t machine_pin_pin(size_t n_args, const mp_obj_t *args) {\n    return MP_OBJ_NEW_SMALL_INT(((machine_pin_obj_t *)args[0])->pin);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_pin_obj, 1, 2, machine_pin_pin);\n\nSTATIC mp_uint_t machine_pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    (void)errcode;\n    machine_pin_obj_t *self = self_in;\n\n    switch (request) {\n        case MP_PIN_READ: {\n            uint32_t pin_val = rt_pin_read(self->pin);\n            return pin_val;\n        }\n        case MP_PIN_WRITE: {\n            rt_pin_write(self->pin, arg);\n            return 0;\n        }\n    }\n\n    *errcode = MP_EINVAL;\n    return MP_STREAM_ERROR;\n}\n\nSTATIC void machine_pin_isr_handler(void *arg) {\n    machine_pin_obj_t *self = arg;\n    mp_sched_schedule(self->pin_isr_cb, MP_OBJ_FROM_PTR(self));\n}\n\n// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING)\nSTATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_handler, ARG_trigger, ARG_wake };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },\n        { MP_QSTR_trigger, MP_ARG_INT, {.u_int = PIN_IRQ_MODE_RISING} },\n    };\n    machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n\n    if (n_args > 1 || kw_args->used != 0) {\n        // configure irq\n        self->pin_isr_cb = args[ARG_handler].u_obj;\n        uint32_t trigger = args[ARG_trigger].u_int;\n\n        rt_pin_mode(self->pin, PIN_MODE_INPUT_PULLUP);\n        rt_pin_attach_irq(self->pin, trigger, machine_pin_isr_handler, (void*)self);\n        rt_pin_irq_enable(self->pin, PIN_IRQ_ENABLE);\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq);\n\nSTATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {\n    // instance methods\n    { MP_ROM_QSTR(MP_QSTR_init),    MP_ROM_PTR(&machine_pin_init_obj) },\n    { MP_ROM_QSTR(MP_QSTR_value),   MP_ROM_PTR(&machine_pin_value_obj) },\n    { MP_ROM_QSTR(MP_QSTR_name),    MP_ROM_PTR(&machine_pin_name_obj) },\n    { MP_ROM_QSTR(MP_QSTR_pin),     MP_ROM_PTR(&machine_pin_pin_obj) },\n    { MP_ROM_QSTR(MP_QSTR_irq),     MP_ROM_PTR(&machine_pin_irq_obj) },\n\n    // class constants\n    { MP_ROM_QSTR(MP_QSTR_ALT_OD),    MP_ROM_INT(GPIO_MODE_AF_OD) },\n    { MP_ROM_QSTR(MP_QSTR_ALT_PP),    MP_ROM_INT(GPIO_MODE_AF_PP) },\n    { MP_ROM_QSTR(MP_QSTR_ANALOG),    MP_ROM_INT(GPIO_MODE_ANALOG) },\n    { MP_ROM_QSTR(MP_QSTR_IN),        MP_ROM_INT(GPIO_MODE_IN) },\n    { MP_ROM_QSTR(MP_QSTR_OUT_PP),    MP_ROM_INT(GPIO_MODE_OUT_PP) },\n    { MP_ROM_QSTR(MP_QSTR_OUT_OD),    MP_ROM_INT(GPIO_MODE_OUT_OD) },\n    { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN) },\n    { MP_ROM_QSTR(MP_QSTR_PULL_NONE), MP_ROM_INT(GPIO_NOPULL) },\n    { MP_ROM_QSTR(MP_QSTR_PULL_UP),   MP_ROM_INT(GPIO_PULLUP) },\n    { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(PIN_IRQ_MODE_RISING) },\n    { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(PIN_IRQ_MODE_FALLING) },\n    { MP_ROM_QSTR(MP_QSTR_IRQ_RISING_FALLING), MP_ROM_INT(PIN_IRQ_MODE_RISING_FALLING) },\n    { MP_ROM_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_ROM_INT(PIN_IRQ_MODE_LOW_LEVEL) },\n    { MP_ROM_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_ROM_INT(PIN_IRQ_MODE_HIGH_LEVEL) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);\n\nSTATIC const mp_pin_p_t machine_pin_pin_p = {\n    .ioctl = machine_pin_ioctl,\n};\n\nconst mp_obj_type_t machine_pin_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_Pin,\n    .print = machine_pin_print,\n    .make_new = mp_pin_make_new,\n    .call = machine_pin_call,\n    .protocol = &machine_pin_pin_p,\n    .locals_dict = (mp_obj_t)&machine_pin_locals_dict,\n};\n\n#endif\n"
  },
  {
    "path": "port/modules/machine/machine_pwm.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 ChenYong (chenyong@rt-thread.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/nlr.h\"\n#include \"py/runtime.h\"\n#include \"modmachine.h\"\n#include \"mphalport.h\"\n\n#ifdef MICROPYTHON_USING_MACHINE_PWM\n\n#include <rtthread.h>\n#include <rtdevice.h>\n\n#define MP_PWM_PULSE_MAX               255\n#define MP_PWM_PERIOD_GET(freq)        (1000000000 / (freq))\n#define MP_PWM_PULSE_GET(period, duty) ((period) / MP_PWM_PULSE_MAX * (duty))\n\nextern const mp_obj_type_t machine_pwm_type;\n\ntypedef struct _machine_pwm_obj_t {\n    mp_obj_base_t base;\n    struct rt_device_pwm *pwm_device;\n    char dev_name[RT_NAME_MAX];\n    uint8_t is_init;\n    int8_t id;\n    uint8_t channel;\n    uint8_t duty;\n    uint32_t freq;\n} machine_pwm_obj_t;\n\nSTATIC void machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    machine_pwm_obj_t *self = self_in;\n\n    mp_printf(print, \"PWM(%p; \", self);\n    if (self->id >= 0) {\n        mp_printf(print, \"pwm_id=%d, \", self->id);\n    } else {\n        mp_printf(print, \"pwm_name=%s, \", self->dev_name);\n    }\n    mp_printf(print, \"channel=%d, \", self->channel);\n    mp_printf(print, \"freq=%d, \", self->freq);\n    mp_printf(print, \"duty=%d)\", self->duty);\n}\n\nSTATIC void error_check(bool status, const char *msg) {\n    if (!status) {\n        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, msg));\n    }\n}\n\nSTATIC void machine_pwm_init_helper(machine_pwm_obj_t *self,\n                                 size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    rt_err_t result = RT_EOK;\n    uint32_t period = 0, pulse = 0;\n    char pwm_dev_name[RT_NAME_MAX];\n    struct rt_device_pwm *pwm_device = RT_NULL;\n    enum { ARG_channel, ARG_freq, ARG_duty };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_channel,  MP_ARG_INT, {.u_int = 0} },\n        { MP_QSTR_freq, MP_ARG_INT, {.u_int = 1} },\n        { MP_QSTR_duty, MP_ARG_INT, {.u_int = 0} },\n    };\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args, pos_args, kw_args,\n                     MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n\n    int tval = args[ARG_channel].u_int;\n    if ((tval < 0) || (tval > 4)) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,\n                                                \"Bad channel %d\", tval));\n    }\n    self->channel = tval;\n\n    tval = args[ARG_freq].u_int;\n    if ((tval < 1) || (tval > 156250)) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,\n                                                \"Bad frequency %d\", tval));\n    }\n    self->freq = tval;\n\n    tval = args[ARG_duty].u_int;\n    if ((tval < 0) || (tval > 255)) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,\n                                                \"Bad duty %d\", tval));\n    }\n    self->duty = tval;\n\n    if (self->id >= 0) {\n        rt_snprintf(pwm_dev_name, sizeof(pwm_dev_name), \"pwm%d\", self->id);\n    } else {\n        rt_strncpy(pwm_dev_name, self->dev_name, RT_NAME_MAX);\n    }\n\n    pwm_device = (struct rt_device_pwm *) rt_device_find(pwm_dev_name);\n    if (pwm_device == RT_NULL || pwm_device->parent.type != RT_Device_Class_Miscellaneous) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,\n                                                \"PWM(%s) don't exist\", pwm_dev_name));\n    }\n    self->pwm_device = pwm_device;\n\n    // get period number by frequency\n    period = MP_PWM_PERIOD_GET(self->freq);\n    // get pulse number by duty\n    pulse = MP_PWM_PULSE_GET(period, self->duty);\n\n    result = rt_pwm_set(pwm_device, self->channel, period, pulse);\n    error_check(result == RT_EOK, \"PWM set information error\");\n\n    result = rt_pwm_enable(pwm_device, self->channel);\n    error_check(result == RT_EOK, \"PWM enable error\");\n\n    self->is_init = RT_TRUE;\n}\n\nSTATIC mp_obj_t machine_pwm_make_new(const mp_obj_type_t *type,\n                                  size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);\n\n    // create PWM object from the given pin\n    machine_pwm_obj_t *self = m_new_obj(machine_pwm_obj_t);\n    self->base.type = &machine_pwm_type;\n    self->is_init = RT_FALSE;\n\n    // check input PWM device name or ID\n    if (mp_obj_is_small_int(args[0])) {\n        self->id = mp_obj_get_int(args[0]);\n    } else if (mp_obj_is_qstr(args[0])) {\n        self->id = -1;\n        rt_strncpy(self->dev_name, mp_obj_str_get_str(args[0]), RT_NAME_MAX);\n    } else {\n        error_check(0, \"Input PWM device name or ID error.\");\n    }\n\n    self->channel = 0;\n    self->freq = 1;\n    self->duty = 0;\n\n    mp_map_t kw_args;\n    mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);\n    machine_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);\n\n    return MP_OBJ_FROM_PTR(self);\n}\n\nSTATIC mp_obj_t machine_pwm_init(size_t n_args,\n                              const mp_obj_t *args, mp_map_t *kw_args) {\n    machine_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(machine_pwm_init_obj, 1, machine_pwm_init);\n\nSTATIC mp_obj_t machine_pwm_deinit(mp_obj_t self_in) {\n    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    rt_err_t result = RT_EOK;\n\n    if (self->is_init == RT_TRUE) {\n        result = rt_pwm_disable(self->pwm_device, self->channel);\n        error_check(result == RT_EOK, \"PWM disable error\");\n        self->is_init = RT_FALSE;\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pwm_deinit_obj, machine_pwm_deinit);\n\nSTATIC mp_obj_t machine_pwm_freq(size_t n_args, const mp_obj_t *args) {\n    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);\n    uint32_t period = 0, pulse = 0;\n    rt_err_t result = RT_EOK;\n\n    error_check(self->is_init == RT_TRUE, \"PWM device uninitialized\");\n\n    if (n_args == 1) {\n        // get\n        return MP_OBJ_NEW_SMALL_INT(self->freq);\n    }\n\n    // set\n    int tval = mp_obj_get_int(args[1]);\n    if ((tval < 1) || (tval > 156250)) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,\n                                                \"Bad frequency %d\", tval));\n    }\n\n    // get period number by frequency\n    period = MP_PWM_PERIOD_GET(tval);\n    // get pulse number by duty\n    pulse = MP_PWM_PULSE_GET(period, self->duty);\n\n    result = rt_pwm_set(self->pwm_device, self->channel, period, pulse);\n    error_check(result == RT_EOK, \"PWM set information error\");\n    self->freq = tval;\n\n    return mp_const_none;\n}\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_freq_obj, 1, 2, machine_pwm_freq);\n\nSTATIC mp_obj_t machine_pwm_duty(size_t n_args, const mp_obj_t *args) {\n    machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);\n    uint32_t period = 0, pulse = 0;\n    rt_err_t result = RT_EOK;\n\n    error_check(self->is_init == RT_TRUE, \"PWM device uninitialized\");\n\n    if (n_args == 1) {\n        // get\n        return MP_OBJ_NEW_SMALL_INT(self->duty);\n    }\n\n    // set\n    int tval = mp_obj_get_int(args[1]);\n    if ((tval < 0) || (tval > 255)) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,\n                                                \"Bad duty %d\", tval));\n    }\n\n    // get period number by frequency\n    period = MP_PWM_PERIOD_GET(self->freq);\n    // get pulse number by duty\n    pulse = MP_PWM_PULSE_GET(period, tval);\n\n    result = rt_pwm_set(self->pwm_device, self->channel, period, pulse);\n    error_check(result == RT_EOK, \"PWM set information error\");\n    self->duty = tval;\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_obj,\n        1, 2, machine_pwm_duty);\n\nSTATIC const mp_rom_map_elem_t machine_pwm_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pwm_init_obj) },\n    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pwm_deinit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_pwm_freq_obj) },\n    { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&machine_pwm_duty_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(machine_pwm_locals_dict,\n                            machine_pwm_locals_dict_table);\n\nconst mp_obj_type_t machine_pwm_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_PWM,\n    .print = machine_pwm_print,\n    .make_new = machine_pwm_make_new,\n    .locals_dict = (mp_obj_dict_t *) &machine_pwm_locals_dict,\n};\n\n#endif // MICROPYTHON_USING_MACHINE_PWM\n"
  },
  {
    "path": "port/modules/machine/machine_pwm.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 ChenYong (chenyong@rt-thread.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef MICROPY_INCLUDED_MACHINE_PWM_H\n#define MICROPY_INCLUDED_MACHINE_PWM_H\n\n#include \"py/obj.h\"\n#include <rtthread.h>\n\nextern const mp_obj_type_t machine_pwm_type;\n\n#endif // MICROPY_INCLUDED_MACHINE_PWM_H\n"
  },
  {
    "path": "port/modules/machine/machine_rtc.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 ChenYong (chenyong@rt-thread.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/nlr.h\"\n#include \"py/obj.h\"\n#include \"py/runtime.h\"\n#include \"py/mphal.h\"\n#include \"lib/timeutils/timeutils.h\"\n#include \"modmachine.h\"\n\n#ifdef MICROPYTHON_USING_MACHINE_RTC\n\n#include <rtthread.h>\n#include <rtdevice.h>\n#include <time.h>\n\n#define MP_YEAR_BASE   1900\n\nconst mp_obj_type_t machine_rtc_type;\n\n// singleton RTC object\nSTATIC const mp_obj_base_t machine_rtc_obj = {&machine_rtc_type};\n\nSTATIC void error_check(bool status, const char *msg) {\n    if (!status) {\n        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, msg));\n    }\n}\n\nSTATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n#define MP_RTC_DEV_NAME \"rtc\"\n    rt_device_t rtc_deivce = RT_NULL;\n\n    // check arguments\n    mp_arg_check_num(n_args, n_kw, 0, 0, false);\n\n    // check RTC device\n    rtc_deivce = rt_device_find(MP_RTC_DEV_NAME);\n    if (rtc_deivce == RT_NULL || rtc_deivce->type != RT_Device_Class_RTC) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, \"RTC(%s) don't exist\", MP_RTC_DEV_NAME)); \n    }\n\n    // return constant object\n    return (mp_obj_t)&machine_rtc_obj;\n}\n\nSTATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args) {\n    if (n_args == 1) {\n        struct tm *tblock;\n        time_t t;\n        // Get time\n        t = time(RT_NULL);\n        tblock = localtime(&t);\n\n        mp_uint_t seconds = timeutils_mktime(tblock->tm_year + MP_YEAR_BASE, tblock->tm_mon + 1, tblock->tm_mday,\n                                             tblock->tm_hour, tblock->tm_min, tblock->tm_sec);\n        timeutils_struct_time_t tm;\n        timeutils_seconds_since_2000_to_struct_time(seconds, &tm);\n\n        mp_obj_t tuple[8] = {\n            mp_obj_new_int(tm.tm_year),\n            mp_obj_new_int(tm.tm_mon),\n            mp_obj_new_int(tm.tm_mday),\n            mp_obj_new_int(tm.tm_wday),\n            mp_obj_new_int(tm.tm_hour),\n            mp_obj_new_int(tm.tm_min),\n            mp_obj_new_int(tm.tm_sec),\n            mp_obj_new_int(0)\n        };\n\n        return mp_obj_new_tuple(8, tuple);\n    } else {\n        // Set time\n        rt_err_t result;\n        mp_obj_t *items;\n\n        mp_obj_get_array_fixed_n(args[1], 8, &items);\n        result = set_date(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]));\n        error_check(result == RT_EOK, \"Set date error\");\n        result = set_time(mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6]));\n        error_check(result == RT_EOK, \"Set time error\");\n        return mp_const_none;\n    }\n}\n\nSTATIC mp_obj_t machine_rtc_now(mp_uint_t n_args, const mp_obj_t *args) {\n    return machine_rtc_datetime_helper(1, args);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_now_obj, 0, 1, machine_rtc_now);\n\nSTATIC mp_obj_t machine_rtc_init(mp_uint_t n_args, const mp_obj_t *args) {\n    return machine_rtc_datetime_helper(n_args, args);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_init_obj, 1, 2, machine_rtc_init);\n\nSTATIC mp_obj_t machine_rtc_deinit(mp_uint_t n_args, const mp_obj_t *args) {\n    rt_err_t result;\n    struct tm tblock;\n\n    tblock.tm_year = 2015 - MP_YEAR_BASE;\n    tblock.tm_mon = 0;\n    tblock.tm_mday = 1;\n    tblock.tm_hour = 0;\n    tblock.tm_min = 0;\n    tblock.tm_sec = 0;\n    result = set_date(tblock.tm_year + MP_YEAR_BASE, tblock.tm_mon + 1, tblock.tm_mday);\n    error_check(result == RT_EOK, \"Set date error\");\n    result = set_time(tblock.tm_hour, tblock.tm_min, tblock.tm_sec);\n    error_check(result == RT_EOK, \"Set time error\");\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_deinit_obj, 0, 1, machine_rtc_deinit);\n\nSTATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_rtc_init_obj) },\n    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_rtc_deinit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_now), MP_ROM_PTR(&machine_rtc_now_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table);\n\nconst mp_obj_type_t machine_rtc_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_RTC,\n    .make_new = machine_rtc_make_new,\n    .locals_dict = (mp_obj_t) &machine_rtc_locals_dict,\n};\n\n#endif // MICROPYTHON_USING_MACHINE_RTC\n"
  },
  {
    "path": "port/modules/machine/machine_rtc.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 ChenYong (chenyong@rt-thread.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef MICROPY_INCLUDED_MACHINE_RTC_H\n#define MICROPY_INCLUDED_MACHINE_RTC_H\n\n#include \"py/obj.h\"\n#include <rtthread.h>\n\nextern const mp_obj_type_t machine_rtc_type;\n\n#endif // MICROPY_INCLUDED_MACHINE_RTC_H\n"
  },
  {
    "path": "port/modules/machine/machine_timer.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 ChenYong (chenyong@rt-thread.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/obj.h\"\n#include \"py/runtime.h\"\n#include \"modmachine.h\"\n#include \"mphalport.h\"\n\n#ifdef MICROPYTHON_USING_MACHINE_TIMER\n\n#include <rtthread.h>\n#include <rtdevice.h>\n#include \"machine_timer.h\"\n\n#define  MAX_TIMER  17\n\ntypedef struct _machine_timer_obj_t {\n    mp_obj_base_t base;\n    rt_device_t timer_device;\n    char dev_name[RT_NAME_MAX];\n    mp_obj_t timeout_cb;\n    int8_t timerid;\n    uint32_t timeout;\n    rt_bool_t is_repeat;\n    rt_bool_t is_init;\n} machine_timer_obj_t;\n\nconst mp_obj_type_t machine_timer_type;\n\nSTATIC void error_check(bool status, const char *msg) {\n    if (!status) {\n        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, msg));\n    }\n}\n\nSTATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    machine_timer_obj_t *self = self_in;\n\n    mp_printf(print, \"Timer(%p; \", self);\n\n    if (self->timerid >= 0) {\n        mp_printf(print, \"timer_id=%d, \", self->timerid);\n    } else {\n        mp_printf(print, \"timer_name=%s, \", self->dev_name);\n    }\n    mp_printf(print, \"period=%d, \", self->timeout);\n    mp_printf(print, \"auto_reload=%d)\", self->is_repeat);\n}\n\nSTATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t);\n    char timer_dev_name[RT_NAME_MAX] = {0};\n\n    // check arguments\n    mp_arg_check_num(n_args, n_kw, 1, 1, true);\n\n    // check input timer device name or ID\n    if (mp_obj_is_small_int(args[0])) {\n        int device_id = mp_obj_get_int(args[0]);\n        self->timerid = device_id;\n        self->timer_device->device_id = device_id;\n        rt_snprintf(timer_dev_name, sizeof(timer_dev_name), \"timer%d\", mp_obj_get_int(args[0]));\n    } else if (mp_obj_is_qstr(args[0])) {\n        static int device_id = 0;\n        self->timerid = -1;\n        self->timer_device->device_id = device_id++;\n        rt_strncpy(self->dev_name, mp_obj_str_get_str(args[0]), RT_NAME_MAX);\n        rt_strncpy(timer_dev_name, self->dev_name, RT_NAME_MAX);\n    } else {\n        error_check(0, \"Input ADC device name or ID error.\");\n    }\n\n    // find timer device\n    self->timer_device = rt_device_find(timer_dev_name);\n    if (self->timer_device == RT_NULL || self->timer_device->type != RT_Device_Class_Timer) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, \"Timer(%s) don't exist\", timer_dev_name));\n    }\n\n    // initialize timer device\n    self->base.type = &machine_timer_type;\n    self->timeout = 0;\n    self->timeout_cb = RT_NULL;\n    self->is_repeat = RT_TRUE;\n    self->is_init = RT_FALSE;\n\n    // return constant object\n    return MP_OBJ_FROM_PTR(self);\n}\n\nstatic machine_timer_obj_t *timer_self[MAX_TIMER] = {RT_NULL};\n\nSTATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) {\n    machine_timer_obj_t *self = self_in;\n    rt_err_t result = RT_EOK;\n\n    if (self->is_init == RT_TRUE) {\n        result = rt_device_close(self->timer_device);\n        error_check(result == RT_EOK, \"Timer device close error\");\n        self->is_init = RT_FALSE;\n        timer_self[self->timer_device->device_id] = RT_NULL;\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit);\n\nSTATIC rt_err_t timer_event_handler(rt_device_t dev, rt_size_t size) {\n    machine_timer_obj_t *self = timer_self[dev->device_id];\n\n    mp_sched_schedule(self->timeout_cb, MP_OBJ_FROM_PTR(self));\n    return RT_EOK;\n}\n\nSTATIC mp_obj_t machine_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {\n    machine_timer_obj_t *self = (machine_timer_obj_t *)args[0];\n    rt_bool_t result = RT_EOK;\n    int mode = 0;\n\n    enum {\n        ARG_mode,\n        ARG_period,\n        ARG_callback,\n    };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_mode,         MP_ARG_INT, {.u_int = 1} },\n        { MP_QSTR_period,       MP_ARG_INT, {.u_int = 0xffffffff} },\n        { MP_QSTR_callback,     MP_ARG_OBJ, {.u_obj = mp_const_none} },\n    };\n\n    mp_arg_val_t dargs[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, dargs);\n\n    if (2 == n_args) {\n        self->timeout = dargs[0].u_int;\n    } else if (3 == n_args) {\n        self->is_repeat = dargs[ARG_mode].u_int;\n        self->timeout = dargs[ARG_period].u_int;\n    } else if (4 == n_args) {\n        self->is_repeat = dargs[ARG_mode].u_int;\n        self->timeout = dargs[ARG_period].u_int;\n        self->timeout_cb = dargs[ARG_callback].u_obj;\n    } else {\n        mp_raise_ValueError(\"invalid format\");\n    }\n\n    error_check(self->timeout > 0, \"Set timeout value error\");\n\n    if (self->is_init == RT_FALSE)\n    {\n        // open timer device\n        result = rt_device_open(self->timer_device, RT_DEVICE_OFLAG_RDWR);\n        error_check(result == RT_EOK, \"Timer device open error\");\n    }\n\n    if (self->timeout_cb != RT_NULL) {\n        // set callback timer\n        if (timer_self[self->timer_device->device_id] && timer_self[self->timer_device->device_id] != self) {\n            error_check(result == RT_EOK, \"Timer device callback function already exists\");\n        } else {\n            timer_self[self->timer_device->device_id] = self;\n        }\n        result = rt_device_set_rx_indicate(self->timer_device, timer_event_handler);\n        error_check(result == RT_EOK, \"Timer set timout callback error\");\n    }\n\n    // set timer mode\n    mode = self->is_repeat ? HWTIMER_MODE_PERIOD : HWTIMER_MODE_ONESHOT;\n    result = rt_device_control(self->timer_device, HWTIMER_CTRL_MODE_SET, &mode);\n    error_check(result == RT_EOK, \"Timer set mode error\");\n\n    if (self->timeout) {\n        rt_hwtimerval_t timeout_s;\n        rt_size_t len;\n\n        timeout_s.sec = self->timeout / 1000;      // second\n        timeout_s.usec = self->timeout % 1000;     // microsecond\n\n        len = rt_device_write(self->timer_device, 0, &timeout_s, sizeof(timeout_s));\n        error_check(len == sizeof(timeout_s), \"Timer set timout error\");\n    }\n\n    self->is_init = RT_TRUE;\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init);\n\n\nSTATIC mp_obj_t machine_timer_callback(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {\n    machine_timer_obj_t *self = (machine_timer_obj_t *)args[0];\n    rt_bool_t result = RT_EOK;\n\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_callback,     MP_ARG_OBJ, {.u_obj = mp_const_none} },\n    };\n\n    mp_arg_val_t dargs[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, dargs);\n\n    self->timeout_cb = dargs[0].u_obj;\n\n    if(n_args == 1)\n    {\n        self->timeout_cb = RT_NULL;\n        self->timer_device->rx_indicate = RT_NULL;//Log-off callback function\n    }\n    else if(n_args == 2)\n    {\n        if(self->timeout_cb != mp_const_none)\n        {\n            timer_self[self->timer_device->device_id] = self;\n            result = rt_device_set_rx_indicate(self->timer_device, timer_event_handler); //set callback timer\n            error_check(result == RT_EOK, \"Timer set timout callback error\");\n        }\n        else\n        {\n            self->timeout_cb = RT_NULL;\n            self->timer_device->rx_indicate = RT_NULL;//Log-off callback function\n        }\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_callback_obj, 0,machine_timer_callback);\n\nSTATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) },\n    { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&machine_timer_callback_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(RT_FALSE) },\n    { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(RT_TRUE) },\n};\nSTATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table);\n\nconst mp_obj_type_t machine_timer_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_Timer,\n    .print = machine_timer_print,\n    .make_new = machine_timer_make_new,\n    .locals_dict = (mp_obj_t) &machine_timer_locals_dict,\n};\n\n#endif // MICROPYTHON_USING_MACHINE_TIMER\n\n"
  },
  {
    "path": "port/modules/machine/machine_timer.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 ChenYong (chenyong@rt-thread.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef MICROPY_INCLUDED_MACHINE_TIMER_H\n#define MICROPY_INCLUDED_MACHINE_TIMER_H\n\n#include \"py/obj.h\"\n#include <rtthread.h>\n\nextern const mp_obj_type_t machine_timer_type;\n\n#endif // MICROPY_INCLUDED_MACHINE_TIMER_H\n\n"
  },
  {
    "path": "port/modules/machine/machine_uart.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 SummerGift <zhangyuan@rt-thread.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/mphal.h\"\n#include \"py/mperrno.h\"\n#include \"py/stream.h\"\n\n#include <stdarg.h>\n#include \"machine_uart.h\"\n#include \"rtdevice.h\"\n\n#ifdef MICROPYTHON_USING_MACHINE_UART\n\n#ifndef RT_USING_SERIAL\n#error \"Please define the RT_USING_SERIAL on 'rtconfig.h'\"\n#endif\n\ntypedef struct _machine_uart_obj_t {\n    mp_obj_base_t base;\n    struct rt_serial_device *uart_device;\n}machine_uart_obj_t;\n\nSTATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    machine_uart_obj_t *self = (machine_uart_obj_t*) self_in;\n    mp_printf(print, \"uart( device port : %s,baud_rate = %d, data_bits = %d, parity = %d, stop_bits = %d )\",\n            self->uart_device->parent.parent.name,\n            self->uart_device->config.baud_rate,\n            self->uart_device->config.data_bits,\n            self->uart_device->config.parity,\n            self->uart_device->config.stop_bits);\n}\n\nSTATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);\n    char uart_dev_name[RT_NAME_MAX];\n    snprintf(uart_dev_name, sizeof(uart_dev_name), \"uart%d\", mp_obj_get_int(args[0]));\n\n    struct rt_serial_device *rt_serial_device = (struct rt_serial_device *) rt_device_find(uart_dev_name);\n    if (rt_serial_device == RT_NULL || rt_serial_device->parent.type != RT_Device_Class_Char) {\n        mp_printf(&mp_plat_print, \"ERROR: UART device %s not found!\\n\", uart_dev_name);\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, \"UART(%s) doesn't exist\", uart_dev_name));\n    }\n\t\n    rt_err_t result;\n    result = rt_device_open((rt_device_t)rt_serial_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX );\n    if (result != RT_EOK)\n    {\n        mp_printf(&mp_plat_print, \"ERROR: UART device %s can't open!\\n\", uart_dev_name);\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, \"UART(%s) can't open\", uart_dev_name));\n    }\n\n    // create new uart object\n    machine_uart_obj_t *self = m_new_obj(machine_uart_obj_t);\n    self->base.type = &machine_uart_type;\n    self->uart_device = rt_serial_device;\n    return (mp_obj_t) self;\n}\n\n/// \\method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0, flow=0, read_buf_len=64)\n///\n/// Initialise the UART bus with the given parameters:\n///\n///   - `baudrate` is the clock rate.\n///   - `bits` is the number of bits per byte, 7, 8 or 9.\n///   - `parity` is the parity, `None`, 0 (even) or 1 (odd).\n///   - `stop` is the number of stop bits, 1 or 2.\n///   - `timeout` is the timeout in milliseconds to wait for the first character.\n///   - `timeout_char` is the timeout in milliseconds to wait between characters.\n///   - `flow` is RTS | CTS where RTS == 256, CTS == 512\n///   - `read_buf_len` is the character length of the read buffer (0 to disable).\n///\nSTATIC mp_obj_t machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} },\n        { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },\n        { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} },\n        { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} },\n        { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },        // rt-thread does not support\n        { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} },\n        { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },\n        { MP_QSTR_read_buf_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },\n    };\n\n    // parse args\n    struct {\n        mp_arg_val_t baudrate, bits, parity, stop, flow, timeout, timeout_char, read_buf_len;\n    } args;\n    mp_arg_parse_all(n_args, pos_args, kw_args,\n        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);\n\n    // set the UART configuration values\n    struct rt_serial_device *uart_p = self->uart_device;\n    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;\n\n    // baudrate\n    config.baud_rate = args.baudrate.u_int;\n\n    // parity\n    mp_int_t bits = args.bits.u_int;\n    if (args.parity.u_obj == mp_const_none) {\n        config.parity = PARITY_NONE;\n    } else {\n        mp_int_t parity = mp_obj_get_int(args.parity.u_obj);\n        config.parity = (parity & 1) ? PARITY_ODD : PARITY_EVEN;\n        //bits += 1; // STs convention has bits including parity, not all mcu\n    }\n\n    // number of bits\n    if (bits == 8) {\n        config.data_bits = DATA_BITS_8;\n    } else if (bits == 9) {\n        config.data_bits = DATA_BITS_9;\n    } else if (bits == 7) {\n        config.data_bits = DATA_BITS_7;\n    } else {\n        mp_raise_ValueError(\"unsupported combination of bits and parity\");\n    }\n\n    // stop bits\n    switch (args.stop.u_int) {\n        case 1: config.stop_bits = STOP_BITS_1; break;\n        default: config.stop_bits = STOP_BITS_2; break;\n    }\n\n    //buffer size\n#if defined(RT_USING_SERIAL_V1)\n    config.bufsz        = args.read_buf_len.u_int;\n\n#elif defined(RT_USING_SERIAL_V2)\n    config.rx_bufsz     = args.read_buf_len.u_int;\n    config.tx_bufsz     = args.read_buf_len.u_int;\n#endif\n    rt_device_control((struct rt_device *) uart_p, RT_DEVICE_CTRL_CONFIG, &config);\n    return mp_const_none;\n}\n\n\nSTATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {\n    return machine_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init);\n\nSTATIC mp_obj_t machine_uart_deinit(mp_obj_t self_in) {\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_deinit_obj, machine_uart_deinit);\n\n#define RETRY_TIMES 500\n\nSTATIC mp_obj_t machine_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {\n    machine_uart_obj_t *self = self_in;\n    uint16_t data = mp_obj_get_int(char_in);\n    rt_size_t len = 0;\n    rt_uint32_t timeout = 0;\n    do\n    {\n        len = rt_device_write((struct rt_device *)(self->uart_device), 0, &data, 1);\n        timeout++;\n    }\n    while (len != 1 && timeout < RETRY_TIMES);\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_uart_writechar_obj, machine_uart_writechar);\n\n#define UART_RX_EVENT (1 << 0)\nstatic struct rt_event event;\n\nSTATIC mp_obj_t machine_uart_readchar(mp_obj_t self_in) {\n    machine_uart_obj_t *self = self_in;\n    rt_uint32_t e;\n    rt_uint8_t ch;\n\n    while (rt_device_read((struct rt_device *)(self->uart_device), 0, &ch, 1) != 1) {\n        rt_event_recv(&event, UART_RX_EVENT, RT_EVENT_FLAG_AND |\n        RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e);\n    }\n\n    return MP_OBJ_NEW_SMALL_INT(ch);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_readchar_obj, machine_uart_readchar);\n\nSTATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = {\n    // instance methods\n\n    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) },\n    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_uart_deinit_obj) },\n//    { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) },\n\n    /// \\method read([nbytes])\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    /// \\method readline()\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},\n    /// \\method readinto(buf[, nbytes])\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    /// \\method write(buf)\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n\n    { MP_ROM_QSTR(MP_QSTR_writechar), MP_ROM_PTR(&machine_uart_writechar_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readchar), MP_ROM_PTR(&machine_uart_readchar_obj) },\n//    { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&pyb_uart_sendbreak_obj) },\n\n//    class constants\n//    { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) },\n//    { MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) },\n};\nSTATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table);\n\nSTATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {\n    machine_uart_obj_t *self = self_in;\n    byte *buf = buf_in;\n    //TODO dfs sync read\n    //MP_RTT_NOT_IMPL_PRINT;\n    return rt_device_read((struct rt_device *)(self->uart_device), -1, buf, size);\n}\n\nSTATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {\n    machine_uart_obj_t *self = self_in;\n    const byte *buf = buf_in;\n    //TODO dfs sync write\n    //MP_RTT_NOT_IMPL_PRINT;\n    return rt_device_write((struct rt_device *)(self->uart_device), -1, buf, size);\n}\n\nSTATIC mp_uint_t machine_uart_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode) {\n    return NULL;\n}\n\nSTATIC const mp_stream_p_t uart_stream_p = {\n    .read = machine_uart_read,\n    .write = machine_uart_write,\n    .ioctl = machine_uart_ioctl,\n    .is_text = false,\n};\n\nconst mp_obj_type_t machine_uart_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_UART,\n    .print = machine_uart_print,\n    .make_new = machine_uart_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &uart_stream_p,\n    .locals_dict = (mp_obj_dict_t*)&machine_uart_locals_dict,\n};\n\n#endif // MICROPYTHON_USING_MACHINE_UART\n"
  },
  {
    "path": "port/modules/machine/machine_uart.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 SummerGift <zhangyuan@rt-thread.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef MICROPY_INCLUDED_MACHINE_UART_H\n#define MICROPY_INCLUDED_MACHINE_UART_H\n\n#include \"py/obj.h\"\n#include <rtthread.h>\n\nextern const mp_obj_type_t machine_uart_type;\n\n#endif // _MACHINE_UART_H\n"
  },
  {
    "path": "port/modules/machine/machine_wdt.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 ChenYong (chenyong@rt-thread.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n\n#include \"py/nlr.h\"\n#include \"py/obj.h\"\n#include \"py/runtime.h\"\n#include \"modmachine.h\"\n#include \"mphalport.h\"\n\n#ifdef MICROPYTHON_USING_MACHINE_WDT\n\n#include <rtthread.h>\n#include <rtdevice.h>\n#include \"machine_wdt.h\"\n\ntypedef struct _machine_wdt_obj_t {\n    mp_obj_base_t base;\n    rt_device_t wdt_device;\n}machine_wdt_obj_t;\n\nconst mp_obj_type_t machine_wdt_type;\n\nSTATIC void error_check(bool status, const char *msg) {\n    if (!status) {\n        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, msg));\n    }\n}\n\nSTATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n#define MP_WDT_DEV_NAME \"wdt\"\n    machine_wdt_obj_t *self = m_new_obj(machine_wdt_obj_t);\n    char wdt_dev_name[RT_NAME_MAX] = {0};\n    rt_err_t result = RT_EOK;\n    mp_int_t timeout = 5;\n\n    // check arguments\n    mp_arg_check_num(n_args, n_kw, 0, 2, false);\n\n    if (n_args == 2) {\n        // check input WDT device name or ID\n        if (mp_obj_is_small_int(args[0])) {\n            rt_snprintf(wdt_dev_name, sizeof(wdt_dev_name), \"wdt%d\", mp_obj_get_int(args[0]));\n        } else if (mp_obj_is_qstr(args[0])) {\n            rt_strncpy(wdt_dev_name, mp_obj_str_get_str(args[0]), RT_NAME_MAX);\n        } else {\n            error_check(0, \"Input WDT device name or ID error.\");\n        }\n        timeout = mp_obj_get_int(args[1]);\n        error_check(timeout >= 1, \"input timeout value error\");\n    } else if (n_args == 1) {\n        if (mp_obj_is_small_int(args[0])) {\n            timeout = mp_obj_get_int(args[0]);\n            error_check(timeout >= 1, \"input timeout value error\");\n        } else if (mp_obj_is_qstr(args[0])) {\n            rt_strncpy(wdt_dev_name, mp_obj_str_get_str(args[0]), RT_NAME_MAX);\n        } else {\n            error_check(0, \"Input WDT device name or ID error.\");\n        }\n    } else {\n        rt_strncpy(wdt_dev_name, MP_WDT_DEV_NAME, RT_NAME_MAX);\n    }\n\n    self->base.type = &machine_wdt_type;\n    // find WDT device\n    self->wdt_device = rt_device_find(wdt_dev_name);\n    if (self->wdt_device == RT_NULL || self->wdt_device->type != RT_Device_Class_Security) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, \"WDT(%s) don't exist\", wdt_dev_name));\n    }\n\n    result = rt_device_init(self->wdt_device);\n    error_check(result == RT_EOK, \"WDT init error\");\n\n    // set WDT device timout\n    result = rt_device_control(self->wdt_device, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, (void *)&timeout);\n    error_check(result == RT_EOK, \"WDT set timout error\");\n\n    result = rt_device_control(self->wdt_device, RT_DEVICE_CTRL_WDT_START, RT_NULL);\n    error_check(result == RT_EOK, \"WDT start error\");\n\n    // return constant object\n    return MP_OBJ_FROM_PTR(self);\n}\n\nSTATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) {\n    /* idle task feed */\n    machine_wdt_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    rt_err_t result = RT_EOK;\n\n    result = rt_device_control(self->wdt_device, RT_DEVICE_CTRL_WDT_KEEPALIVE, RT_NULL);\n    error_check(result == RT_EOK, \"WDT feed failed\");\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed);\n\nSTATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table);\n\nconst mp_obj_type_t machine_wdt_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_WDT,\n    .make_new = machine_wdt_make_new,\n    .locals_dict = (mp_obj_t) &machine_wdt_locals_dict,\n};\n\n#endif // MICROPYTHON_USING_MACHINE_WDT\n\n"
  },
  {
    "path": "port/modules/machine/machine_wdt.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 ChenYong (chenyong@rt-thread.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef MICROPY_INCLUDED_MACHINE_WDT_H\n#define MICROPY_INCLUDED_MACHINE_WDT_H\n\n#include \"py/obj.h\"\n#include <rtthread.h>\n\nextern const mp_obj_type_t machine_wdt_type;\n\n#endif // MICROPY_INCLUDED_MACHINE_WDT_H\n\n"
  },
  {
    "path": "port/modules/machine/modmachine.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n\n#include \"py/obj.h\"\n#include \"py/runtime.h\"\n#include \"py/gc.h\"\n#include \"lib/utils/pyexec.h\"\n#include \"extmod/machine_mem.h\"\n#include \"extmod/machine_signal.h\"\n#include \"extmod/machine_pulse.h\"\n#include \"extmod/machine_i2c.h\"\n#include \"extmod/machine_spi.h\"\n#include \"modmachine.h\"\n#include \"machine_uart.h\"\n#include \"machine_adc.h\"\n#include \"machine_pwm.h\"\n#include \"machine_lcd.h\"\n#include \"machine_rtc.h\"\n#include \"machine_wdt.h\"\n#include \"machine_timer.h\"\n\n#include <rthw.h>\n\n#if MICROPY_PY_MACHINE\n\nSTATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) {\n#ifdef RT_USING_FINSH\n    extern long list_thread(void);\n#endif\n    // RT-Thread info\n    {\n        mp_printf(&mp_plat_print, \"---------------------------------------------\\n\");\n        mp_printf(&mp_plat_print, \"RT-Thread\\n\");\n        mp_printf(&mp_plat_print, \"---------------------------------------------\\n\");\n\n#ifdef RT_USING_FINSH\n        extern void list_memheap(void);\n        extern void list_mempool(void);\n\n#if defined(RT_USING_MEMHEAP_AS_HEAP)\n        list_memheap();\n#elif defined(RT_USING_MEMPOOL)\n        list_mempool();\n#endif\n\n        list_thread();\n#endif\n        mp_printf(&mp_plat_print, \"---------------------------------------------\\n\");\n    }\n\n    // qstr info\n    {\n        mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;\n        qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);\n        mp_printf(&mp_plat_print, \"qstr:\\n  n_pool=\" UINT_FMT \"\\n  n_qstr=\" UINT_FMT \"\\n  n_str_data_bytes=\" UINT_FMT \"\\n  n_total_bytes=\" UINT_FMT \"\\n\", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);\n    }\n    mp_printf(&mp_plat_print, \"---------------------------------------------\\n\");\n\n    // GC info\n    {\n        gc_info_t info;\n        gc_info(&info);\n        mp_printf(&mp_plat_print, \"GC:\\n\");\n        mp_printf(&mp_plat_print, \"  \" UINT_FMT \" total\\n\", info.total);\n        mp_printf(&mp_plat_print, \"  \" UINT_FMT \" : \" UINT_FMT \"\\n\", info.used, info.free);\n        mp_printf(&mp_plat_print, \"  1=\" UINT_FMT \" 2=\" UINT_FMT \" m=\" UINT_FMT \"\\n\", info.num_1block, info.num_2block, info.max_block);\n    }\n\n    // free space on flash\n    {\n        //TODO\n    }\n\n    if (n_args == 1) {\n        // arg given means dump gc allocation table\n        gc_dump_alloc_table();\n    }\n\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info);\n\nSTATIC mp_obj_t machine_unique_id(void) {\n    //TODO\n    MP_RTT_NOT_IMPL_PRINT;\n    return 0;\n}\nMP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);\n\nSTATIC mp_obj_t machine_reset(void) {\n    //TODO\n    MP_RTT_NOT_IMPL_PRINT;\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);\n\nSTATIC mp_obj_t machine_soft_reset(void) {\n    pyexec_system_exit = PYEXEC_FORCED_EXIT;\n    nlr_raise(mp_obj_new_exception(&mp_type_SystemExit));\n}\nMP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset);\n\n/*\n* @param clkid - range 0~127 (e.g 0:SYSCLK 1:HCLK 2:PCLK1 etc)\n*\n* @return 0 - ok, -1 - no such clock\n*/\nMP_WEAK int mp_port_get_freq(int clkid, int *freq)\n{\n    return -1;\n}\n\nSTATIC mp_obj_t machine_freq(void) {\n    int i;\n    mp_obj_list_t *ret_list = m_new(mp_obj_list_t, 1);\n    mp_obj_list_init(ret_list, 0);\n    int freq;\n\n    for (i = 0; i < 128; i ++)\n    {\n        if (mp_port_get_freq(i, &freq) != 0)\n            break;\n\n        mp_obj_list_append(ret_list, mp_obj_new_int(freq));\n    }\n\n    return MP_OBJ_FROM_PTR(ret_list);\n}\nMP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);\n\nSTATIC mp_obj_t pyb_wfi(void) {\n    //TODO __WFI();\n    MP_RTT_NOT_IMPL_PRINT;\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_0(pyb_wfi_obj, pyb_wfi);\n\nstatic rt_base_t int_lvl;\nSTATIC mp_obj_t pyb_disable_irq(void) {\n    int_lvl = rt_hw_interrupt_disable();\n    return mp_obj_new_bool(1);\n}\nMP_DEFINE_CONST_FUN_OBJ_0(pyb_disable_irq_obj, pyb_disable_irq);\n\nSTATIC mp_obj_t pyb_enable_irq(size_t n_args, const mp_obj_t *arg) {\n    if (n_args == 0) {\n        rt_hw_interrupt_enable(int_lvl);\n    } else {\n        if (mp_obj_is_true(arg[0])) {\n            rt_hw_interrupt_enable(int_lvl);\n        } else {\n            int_lvl = rt_hw_interrupt_disable();\n        }\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_enable_irq_obj, 0, 1, pyb_enable_irq);\n\nSTATIC mp_obj_t machine_sleep (void) {\n    //TODO\n    MP_RTT_NOT_IMPL_PRINT;\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep);\n\nSTATIC mp_obj_t machine_deepsleep (void) {\n    //TODO\n    MP_RTT_NOT_IMPL_PRINT;\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep);\n\nSTATIC mp_obj_t machine_reset_cause(void) {\n    //TODO\n    MP_RTT_NOT_IMPL_PRINT;\n    return MP_OBJ_NEW_SMALL_INT(42);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);\n\nSTATIC const mp_rom_map_elem_t machine_module_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__),            MP_ROM_QSTR(MP_QSTR_umachine) },\n    { MP_ROM_QSTR(MP_QSTR_info),                MP_ROM_PTR(&machine_info_obj) },\n    { MP_ROM_QSTR(MP_QSTR_unique_id),           MP_ROM_PTR(&machine_unique_id_obj) },\n    { MP_ROM_QSTR(MP_QSTR_reset),               MP_ROM_PTR(&machine_reset_obj) },\n    { MP_ROM_QSTR(MP_QSTR_soft_reset),          MP_ROM_PTR(&machine_soft_reset_obj) },\n    { MP_ROM_QSTR(MP_QSTR_freq),                MP_ROM_PTR(&machine_freq_obj) },\n    { MP_ROM_QSTR(MP_QSTR_idle),                MP_ROM_PTR(&pyb_wfi_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sleep),               MP_ROM_PTR(&machine_sleep_obj) },\n    { MP_ROM_QSTR(MP_QSTR_deepsleep),           MP_ROM_PTR(&machine_deepsleep_obj) },\n    { MP_ROM_QSTR(MP_QSTR_reset_cause),         MP_ROM_PTR(&machine_reset_cause_obj) },\n    { MP_ROM_QSTR(MP_QSTR_disable_irq),         MP_ROM_PTR(&pyb_disable_irq_obj) },\n    { MP_ROM_QSTR(MP_QSTR_enable_irq),          MP_ROM_PTR(&pyb_enable_irq_obj) },\n//    { MP_ROM_QSTR(MP_QSTR_time_pulse_us),       MP_ROM_PTR(&machine_time_pulse_us_obj) },\n#if MICROPY_PY_PIN\n    { MP_ROM_QSTR(MP_QSTR_Pin),                 MP_ROM_PTR(&machine_pin_type) },\n#endif\n    { MP_ROM_QSTR(MP_QSTR_Signal),              MP_ROM_PTR(&machine_signal_type) },\n#if MICROPY_PY_MACHINE_I2C\n    { MP_ROM_QSTR(MP_QSTR_I2C),                 MP_ROM_PTR(&machine_i2c_type) },\n#endif\n#if MICROPY_PY_MACHINE_SPI\n    { MP_ROM_QSTR(MP_QSTR_SPI),                 MP_ROM_PTR(&mp_machine_soft_spi_type) },\n#endif\n#if MICROPY_PY_MACHINE_UART\n    { MP_ROM_QSTR(MP_QSTR_UART),                MP_ROM_PTR(&machine_uart_type) },\n#endif\n#if MICROPY_PY_MACHINE_RTC\n    { MP_ROM_QSTR(MP_QSTR_RTC),                 MP_ROM_PTR(&machine_rtc_type) },\n#endif\n#if MICROPY_PY_MACHINE_LCD\n    { MP_ROM_QSTR(MP_QSTR_LCD),                 MP_ROM_PTR(&machine_lcd_type ) },\n#endif\n#if MICROPY_PY_MACHINE_PWM\n    { MP_ROM_QSTR(MP_QSTR_PWM),                 MP_ROM_PTR(&machine_pwm_type) },\n#endif\n#if MICROPY_PY_MACHINE_ADC\n    { MP_ROM_QSTR(MP_QSTR_ADC),                 MP_ROM_PTR(&machine_adc_type) },\n#endif\n#if MICROPY_PY_MACHINE_WDT\n    { MP_ROM_QSTR(MP_QSTR_WDT),                 MP_ROM_PTR(&machine_wdt_type) },\n#endif\n#if MICROPY_PY_MACHINE_TIMER\n    { MP_ROM_QSTR(MP_QSTR_Timer),               MP_ROM_PTR(&machine_timer_type) },\n#endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);\n\nconst mp_obj_module_t mp_module_machine = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&machine_module_globals,\n};\n\n#endif // MICROPY_PY_MACHINE\n"
  },
  {
    "path": "port/modules/machine/modmachine.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef _MODMACHINE_H\n#define _MODMACHINE_H\n\n#include \"py/obj.h\"\n#include <rtthread.h>\n\nextern const mp_obj_type_t machine_pin_type;\n\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(machine_bootloader_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(machine_freq_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(pyb_wfi_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(pyb_disable_irq_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_enable_irq_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(machine_sleep_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(machine_deepsleep_obj);\n\ntypedef struct _machine_pin_obj_t {\n    mp_obj_base_t base;\n    char name[RT_NAME_MAX];\n    uint32_t pin;\n    mp_obj_t pin_isr_cb;\n} machine_pin_obj_t;\n\n#endif // _MODMACHINE_H\n"
  },
  {
    "path": "port/modules/modffi.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n * Copyright (c) 2019 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <string.h>\n#include <errno.h>\n#include <stdint.h>\n\n#include \"py/runtime.h\"\n#include \"py/binary.h\"\n#include \"py/mperrno.h\"\n\n#ifdef MICROPYTHON_USING_FFI\n\n#if !defined(__GNUC__) \n#error \"The ffi module only supports GCC toolchain at present\"\n#endif\n\n#include <dlfcn.h>\n#include <dlmodule.h>\n\ntypedef enum {\n    FFI_TYPE_UNKNOWN,\n    FFI_TYPE_SCHAR,\n    FFI_TYPE_UCHAR,\n    FFI_TYPE_SSHORT,\n    FFI_TYPE_USHORT,\n    FFI_TYPE_SINT,\n    FFI_TYPE_UINT,\n    FFI_TYPE_SLONG,\n    FFI_TYPE_ULONG,\n    FFI_TYPE_SINT64,\n    FFI_TYPE_UINT64,\n    FFI_TYPE_FLOAT,\n    FFI_TYPE_DOUBLE,\n    FFI_TYPE_POINTER,\n    FFI_TYPE_VOID,\n} ffi_type_t;\n\ntypedef struct _mp_obj_opaque_t {\n    mp_obj_base_t base;\n    void *val;\n} mp_obj_opaque_t;\n\ntypedef struct _mp_obj_ffimod_t {\n    mp_obj_base_t base;\n    void *handle;\n} mp_obj_ffimod_t;\n\ntypedef struct _mp_obj_ffivar_t {\n    mp_obj_base_t base;\n    void *var;\n    char type;\n} mp_obj_ffivar_t;\n\ntypedef struct _mp_obj_ffifunc_t {\n    mp_obj_base_t base;\n    void *func;\n    char rettype;\n    uint32_t argc;\n    const char *argtypes;\n    ffi_type_t *params;\n} mp_obj_ffifunc_t;\n\ntypedef struct _mp_obj_fficallback_t {\n    mp_obj_base_t base;\n    void *func;\n    char rettype;\n    ffi_type_t *params;\n} mp_obj_fficallback_t;\n\ntypedef unsigned long ffi_arg;\n\nSTATIC const mp_obj_type_t ffimod_type;\nSTATIC const mp_obj_type_t ffifunc_type;\nSTATIC const mp_obj_type_t fficallback_type;\nSTATIC const mp_obj_type_t ffivar_type;\n\nSTATIC ffi_type_t char2ffi_type(char c)\n{\n    switch (c) {\n        case 'b': return FFI_TYPE_SCHAR;\n        case 'B': return FFI_TYPE_UCHAR;\n        case 'h': return FFI_TYPE_SSHORT;\n        case 'H': return FFI_TYPE_USHORT;\n        case 'i': return FFI_TYPE_SINT;\n        case 'I': return FFI_TYPE_UINT;\n        case 'l': return FFI_TYPE_SLONG;\n        case 'L': return FFI_TYPE_ULONG;\n        case 'q': return FFI_TYPE_SINT64;\n        case 'Q': return FFI_TYPE_UINT64;\n        #if MICROPY_PY_BUILTINS_FLOAT\n        case 'f': return FFI_TYPE_FLOAT;\n        case 'd': return FFI_TYPE_DOUBLE;\n        #endif\n        case 'O': // mp_obj_t\n        case 'C': // (*)()\n        case 'P': // const void*\n        case 'p': // void*\n        case 's': return FFI_TYPE_POINTER;\n        case 'v': return FFI_TYPE_VOID;\n        default: return FFI_TYPE_UNKNOWN;\n    }\n}\n\nSTATIC ffi_type_t get_ffi_type(mp_obj_t o_in)\n{\n    if (MP_OBJ_IS_STR(o_in)) {\n        const char *s = mp_obj_str_get_str(o_in);\n        ffi_type_t t = char2ffi_type(*s);\n        if (t != FFI_TYPE_UNKNOWN) {\n            return t;\n        }\n    }\n    // TODO: Support actual libffi type objects\n\n    mp_raise_TypeError(\"Unknown type\");\n}\n\nSTATIC mp_obj_t return_ffi_value(void *val, char type)\n{\n    switch (type) {\n        case 's': {\n            const char *s = (const char *)(intptr_t)val;\n            if (!s) {\n                return mp_const_none;\n            }\n            return mp_obj_new_str(s, strlen(s));\n        }\n        case 'v':\n            return mp_const_none;\n        #if MICROPY_PY_BUILTINS_FLOAT\n        case 'f': {\n            union { void *ffi; float flt; } val_union = { .ffi = val };\n            return mp_obj_new_float(val_union.flt);\n        }\n        case 'd': {\n            double *p = (double*)&val;\n            mp_raise_NotImplementedError(\"The double return type NOT supported\");\n            return mp_obj_new_float(*p);\n        }\n        #endif\n        case 'O':\n            return (mp_obj_t)(intptr_t)val;\n        default:\n            return mp_obj_new_int((mp_int_t)val);\n    }\n}\n\n// FFI module\n\nSTATIC void ffimod_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<ffimod %p>\", self->handle);\n}\n\nSTATIC mp_obj_t ffimod_close(mp_obj_t self_in) {\n    mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);\n\n    dlclose(self->handle);\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(ffimod_close_obj, ffimod_close);\n\nSTATIC mp_obj_t make_func(mp_obj_t rettype_in, void *func, mp_obj_t argtypes_in) {\n    const char *rettype = mp_obj_str_get_str(rettype_in);\n    const char *argtypes = mp_obj_str_get_str(argtypes_in);\n\n    mp_int_t nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(argtypes_in));\n    mp_obj_ffifunc_t *o = m_new_obj_var(mp_obj_ffifunc_t, ffi_type_t, nparams);\n    o->base.type = &ffifunc_type;\n    o->func = func;\n    o->rettype = *rettype;\n    o->argtypes = argtypes;\n    o->argc = nparams;\n    o->params = (uint8_t *)o + sizeof(mp_obj_ffifunc_t);\n\n    mp_obj_iter_buf_t iter_buf;\n    mp_obj_t iterable = mp_getiter(argtypes_in, &iter_buf);\n    mp_obj_t item;\n    int i = 0;\n    while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n        o->params[i++] = get_ffi_type(item);\n    }\n    /* when param is void change the argc to 0 */\n    if (o->argc == 1 && o->params[0] == FFI_TYPE_VOID) {\n        o->argc = 0;\n    }\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t ffimod_func(size_t n_args, const mp_obj_t *args) {\n    (void)n_args; // always 4\n    mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(args[0]);\n    const char *symname = mp_obj_str_get_str(args[2]);\n\n    void *sym = dlsym(self->handle, symname);\n    if (sym == NULL) {\n        mp_raise_ValueError(\"input symbol NOT found\");\n    }\n    return make_func(args[1], sym, args[3]);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ffimod_func_obj, 4, 4, ffimod_func);\n\nSTATIC mp_obj_t mod_ffi_func(mp_obj_t rettype, mp_obj_t addr_in, mp_obj_t argtypes) {\n    void *addr;\n    /* find the built-in function address when address is string type */\n    if (mp_obj_is_str(addr_in)) {\n        addr = (void *) dlmodule_symbol_find(mp_obj_str_get_str(addr_in));\n        if (addr == NULL) {\n            mp_raise_ValueError(\"input symbol NOT found\");\n        }\n    } else {\n        addr = (void*) MP_OBJ_TO_PTR(mp_obj_int_get_truncated(addr_in));\n    }\n\n    return make_func(rettype, addr, argtypes);\n}\nMP_DEFINE_CONST_FUN_OBJ_3(mod_ffi_func_obj, mod_ffi_func);\n\nSTATIC void call_py_func(void *ret, int argc, void** args, void *func) {\n    mp_obj_t *pyargs = m_new(mp_obj_t, argc);\n    for (int i = 0; i < argc; i++) {\n        pyargs[i] = mp_obj_new_int(*(mp_int_t*)args[i]);\n    }\n    mp_obj_t res = mp_call_function_n_kw(MP_OBJ_FROM_PTR(func), argc, 0, pyargs);\n\n    m_free(pyargs);\n\n    if (res != mp_const_none) {\n        *(ffi_arg*)ret = mp_obj_int_get_truncated(res);\n    }\n}\n\nSTATIC mp_obj_t mod_ffi_callback(mp_obj_t rettype_in, mp_obj_t func_in, mp_obj_t paramtypes_in) {\n    const char *rettype = mp_obj_str_get_str(rettype_in);\n\n    mp_int_t nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(paramtypes_in));\n\n    mp_obj_fficallback_t *o = m_new_obj_var(mp_obj_fficallback_t, ffi_type_t, nparams);\n\n    //TODO add callback impl\n    mp_raise_NotImplementedError(\"The callback NOT supported\");\n\n    return MP_OBJ_FROM_PTR(o);\n}\nMP_DEFINE_CONST_FUN_OBJ_3(mod_ffi_callback_obj, mod_ffi_callback);\n\nSTATIC mp_obj_t ffimod_var(mp_obj_t self_in, mp_obj_t vartype_in, mp_obj_t symname_in) {\n    mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);\n    const char *rettype = mp_obj_str_get_str(vartype_in);\n    const char *symname = mp_obj_str_get_str(symname_in);\n\n    void *sym = dlsym(self->handle, symname);\n    if (sym == NULL) {\n        mp_raise_OSError(MP_ENOENT);\n    }\n    mp_obj_ffivar_t *o = m_new_obj(mp_obj_ffivar_t);\n    o->base.type = &ffivar_type;\n\n    o->var = sym;\n    o->type = *rettype;\n    return MP_OBJ_FROM_PTR(o);\n}\nMP_DEFINE_CONST_FUN_OBJ_3(ffimod_var_obj, ffimod_var);\n\nSTATIC mp_obj_t ffimod_addr(mp_obj_t self_in, mp_obj_t symname_in) {\n    mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);\n    const char *symname = mp_obj_str_get_str(symname_in);\n\n    void *sym = dlsym(self->handle, symname);\n    if (sym == NULL) {\n        mp_raise_OSError(MP_ENOENT);\n    }\n    return mp_obj_new_int((uintptr_t)sym);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(ffimod_addr_obj, ffimod_addr);\n\nSTATIC mp_obj_t ffimod_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    (void)n_args;\n    (void)n_kw;\n\n    const char *fname = NULL;\n    if (args[0] != mp_const_none) {\n        fname = mp_obj_str_get_str(args[0]);\n    }\n    void *mod = dlopen(fname, RTLD_NOW | RTLD_LOCAL);\n\n    if (mod == NULL) {\n        mp_raise_OSError(errno);\n    }\n    mp_obj_ffimod_t *o = m_new_obj(mp_obj_ffimod_t);\n    o->base.type = type;\n    o->handle = mod;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC const mp_rom_map_elem_t ffimod_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_func), MP_ROM_PTR(&ffimod_func_obj) },\n    { MP_ROM_QSTR(MP_QSTR_var), MP_ROM_PTR(&ffimod_var_obj) },\n    { MP_ROM_QSTR(MP_QSTR_addr), MP_ROM_PTR(&ffimod_addr_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&ffimod_close_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(ffimod_locals_dict, ffimod_locals_dict_table);\n\nSTATIC const mp_obj_type_t ffimod_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_ffimod,\n    .print = ffimod_print,\n    .make_new = ffimod_make_new,\n    .locals_dict = (mp_obj_dict_t*)&ffimod_locals_dict,\n};\n\n// FFI function\n\nSTATIC void ffifunc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<ffifunc %p>\", self->func);\n}\n\nSTATIC void ffi_call(void *func, ffi_arg *retval, uint32_t argc, ffi_arg *argv)\n{\n    typedef ffi_arg(*f6_t)(ffi_arg, ffi_arg, ffi_arg, ffi_arg, ffi_arg, ffi_arg);\n\n    ffi_arg dummy = 0;\n    ffi_arg args[6];\n    uint32_t i;\n\n    for (i = 0; i < sizeof(args) / sizeof(args[0]); i ++) {\n        if (i < argc) {\n            args[i] = argv[i];\n        } else {\n            args[i] = (ffi_arg)&dummy;\n        }\n    }\n\n    *retval = ((f6_t)(func))(args[0], args[1], args[2], args[3], args[4], args[5]);\n}\n\nSTATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    (void)n_kw;\n    mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in);\n    assert(n_kw == 0);\n\n    if (self->argc > n_args) {\n        mp_raise_ValueError(\"input function parameter number mismatch\");\n    }\n\n    ffi_arg *values = m_new(ffi_arg, n_args);\n    const char *argtype = self->argtypes;\n    for (uint i = 0; i < n_args; i++, argtype++) {\n        mp_obj_t a = args[i];\n        if (*argtype == 'O') {\n            values[i] = (ffi_arg)(intptr_t)a;\n        #if MICROPY_PY_BUILTINS_FLOAT\n        } else if (*argtype == 'f') {\n            float *p = (float*)&values[i];\n            *p = mp_obj_get_float(a);\n        } else if (*argtype == 'd') {\n            double *p = (double*)&values[i];\n            *p = mp_obj_get_float(a);\n            //TODO add double and long long supported\n            mp_raise_NotImplementedError(\"The double parameter NOT supported\");\n        #endif\n        } else if (a == mp_const_none) {\n            values[i] = 0;\n        } else if (mp_obj_is_int(a)) {\n            values[i] = mp_obj_int_get_truncated(a);\n        } else if (mp_obj_is_str(a)) {\n            const char *s = mp_obj_str_get_str(a);\n            values[i] = (ffi_arg)(intptr_t)s;\n        } else if (((mp_obj_base_t*)MP_OBJ_TO_PTR(a))->type->buffer_p.get_buffer != NULL) {\n            mp_obj_base_t *o = (mp_obj_base_t*)MP_OBJ_TO_PTR(a);\n            mp_buffer_info_t bufinfo;\n            int ret = o->type->buffer_p.get_buffer(MP_OBJ_FROM_PTR(o), &bufinfo, MP_BUFFER_READ); // TODO: MP_BUFFER_READ?\n            if (ret != 0) {\n                goto __error;\n            }\n            values[i] = (ffi_arg)(intptr_t)bufinfo.buf;\n        } else if (mp_obj_is_type(a, &fficallback_type)) {\n            mp_obj_fficallback_t *p = MP_OBJ_TO_PTR(a);\n            values[i] = (ffi_arg)(intptr_t)p->func;\n        } else {\n            goto __error;\n        }\n    }\n\n    // If ffi_arg is not big enough to hold a double, then we must pass along a\n    // pointer to a memory location of the correct size.\n    // TODO check if this needs to be done for other types which don't fit into\n    // ffi_arg.\n    #if MICROPY_PY_BUILTINS_FLOAT\n    if (sizeof(ffi_arg) == 4 && self->rettype == 'd') {\n        double retval;\n        //TODO add double supported\n        mp_raise_NotImplementedError(\"The double return type NOT supported\");\n//        ffi_call(self->func, &retval, n_args, values);\n        return mp_obj_new_float(retval);\n    } else\n    #endif\n    {\n        ffi_arg retval;\n        ffi_call(self->func, &retval, n_args, values);\n        m_free(values);\n        return return_ffi_value((void *)retval, self->rettype);\n    }\n\n__error:\n    mp_raise_TypeError(\"Don't know how to pass object to native function\");\n    m_free(values);\n}\n\nSTATIC const mp_obj_type_t ffifunc_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_ffifunc,\n    .print = ffifunc_print,\n    .call = ffifunc_call,\n};\n\n// FFI callback for Python function\n\nSTATIC void fficallback_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_fficallback_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<fficallback %p>\", self->func);\n}\n\nSTATIC const mp_obj_type_t fficallback_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_fficallback,\n    .print = fficallback_print,\n};\n\n// FFI variable\n\nSTATIC void ffivar_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in);\n    // Variable value printed as cast to int\n    mp_printf(print, \"<ffivar @%p: 0x%x>\", self->var, *(int*)self->var);\n}\n\nSTATIC mp_obj_t ffivar_get(mp_obj_t self_in) {\n    mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in);\n    return mp_binary_get_val_array(self->type, self->var, 0);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(ffivar_get_obj, ffivar_get);\n\nSTATIC mp_obj_t ffivar_set(mp_obj_t self_in, mp_obj_t val_in) {\n    mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_binary_set_val_array(self->type, self->var, 0, val_in);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_2(ffivar_set_obj, ffivar_set);\n\nSTATIC const mp_rom_map_elem_t ffivar_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&ffivar_get_obj) },\n    { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&ffivar_set_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(ffivar_locals_dict, ffivar_locals_dict_table);\n\nSTATIC const mp_obj_type_t ffivar_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_ffivar,\n    .print = ffivar_print,\n    .locals_dict = (mp_obj_dict_t*)&ffivar_locals_dict,\n};\n\nSTATIC mp_obj_t mod_ffi_open(size_t n_args, const mp_obj_t *args) {\n    return ffimod_make_new(&ffimod_type, n_args, 0, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_ffi_open_obj, 1, 2, mod_ffi_open);\n\nSTATIC mp_obj_t mod_ffi_as_bytearray(mp_obj_t ptr, mp_obj_t size) {\n    return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void*)(uintptr_t)mp_obj_int_get_truncated(ptr));\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mod_ffi_as_bytearray_obj, mod_ffi_as_bytearray);\n\nSTATIC const mp_rom_map_elem_t mp_module_ffi_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ffi) },\n    { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_ffi_open_obj) },\n    { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&mod_ffi_callback_obj) },\n    { MP_ROM_QSTR(MP_QSTR_func), MP_ROM_PTR(&mod_ffi_func_obj) },\n    { MP_ROM_QSTR(MP_QSTR_as_bytearray), MP_ROM_PTR(&mod_ffi_as_bytearray_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_ffi_globals, mp_module_ffi_globals_table);\n\nconst mp_obj_module_t mp_module_ffi = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_ffi_globals,\n};\n\n#endif /* MICROPY_PY_FFI */\n"
  },
  {
    "path": "port/modules/modfile.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_PY_IO\n\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n#include \"py/builtin.h\"\n#include \"py/mphal.h\"\n\n#include <stdio.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n\n#ifdef _WIN32\n#define fsync _commit\n#endif\n\ntypedef struct _mp_obj_fdfile_t {\n    mp_obj_base_t base;\n    int fd;\n} mp_obj_fdfile_t;\n\n#ifdef MICROPY_CPYTHON_COMPAT\nSTATIC void check_fd_is_open(const mp_obj_fdfile_t *o) {\n    if (o->fd < 0) {\n        mp_raise_ValueError(\"I/O operation on closed file\");\n    }\n}\n#else\n#define check_fd_is_open(o)\n#endif\n\nextern const mp_obj_type_t mp_type_fileio;\nextern const mp_obj_type_t mp_type_textio;\n\nSTATIC void fdfile_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_fdfile_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<io.%s %d>\", mp_obj_get_type_str(self_in), self->fd);\n}\n\nSTATIC mp_uint_t fdfile_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_fdfile_t *o = MP_OBJ_TO_PTR(o_in);\n    check_fd_is_open(o);\n    mp_int_t r = read(o->fd, buf, size);\n    if (r == -1) {\n        *errcode = errno;\n        return MP_STREAM_ERROR;\n    }\n    return r;\n}\n\nSTATIC mp_uint_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_fdfile_t *o = MP_OBJ_TO_PTR(o_in);\n    check_fd_is_open(o);\n    #if MICROPY_PY_OS_DUPTERM\n    if (o->fd <= STDERR_FILENO) {\n        mp_hal_stdout_tx_strn(buf, size);\n        return size;\n    }\n    #endif\n    mp_int_t r = write(o->fd, buf, size);\n    while (r == -1 && errno == MP_EINTR) {\n        if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {\n            mp_obj_t obj = MP_STATE_VM(mp_pending_exception);\n            MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;\n            nlr_raise(obj);\n        }\n        r = write(o->fd, buf, size);\n    }\n    if (r == -1) {\n        *errcode = errno;\n        return MP_STREAM_ERROR;\n    }\n    return r;\n}\n\nSTATIC mp_uint_t fdfile_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    mp_obj_fdfile_t *o = MP_OBJ_TO_PTR(o_in);\n    check_fd_is_open(o);\n    switch (request) {\n        case MP_STREAM_SEEK: {\n            struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg;\n            off_t off = lseek(o->fd, s->offset, s->whence);\n            if (off == (off_t)-1) {\n                *errcode = errno;\n                return MP_STREAM_ERROR;\n            }\n            s->offset = off;\n            return 0;\n        }\n        case MP_STREAM_FLUSH:\n            if (fsync(o->fd) < 0) {\n                *errcode = errno;\n                return MP_STREAM_ERROR;\n            }\n            return 0;\n        default:\n            *errcode = EINVAL;\n            return MP_STREAM_ERROR;\n    }\n}\n\nSTATIC mp_obj_t fdfile_close(mp_obj_t self_in) {\n    mp_obj_fdfile_t *self = MP_OBJ_TO_PTR(self_in);\n    close(self->fd);\n#ifdef MICROPY_CPYTHON_COMPAT\n    self->fd = -1;\n#endif\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_close_obj, fdfile_close);\n\nSTATIC mp_obj_t fdfile___exit__(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n    return fdfile_close(args[0]);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fdfile___exit___obj, 4, 4, fdfile___exit__);\n\nSTATIC mp_obj_t fdfile_fileno(mp_obj_t self_in) {\n    mp_obj_fdfile_t *self = MP_OBJ_TO_PTR(self_in);\n    check_fd_is_open(self);\n    return MP_OBJ_NEW_SMALL_INT(self->fd);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno);\n\n// Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO,\n// but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor\nSTATIC const mp_arg_t file_open_args[] = {\n    { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },\n    { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} },\n    { MP_QSTR_buffering, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n    { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n};\n#define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args)\n\nSTATIC mp_obj_t fdfile_open(const mp_obj_type_t *type, mp_arg_val_t *args) {\n    mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t);\n    const char *mode_s = mp_obj_str_get_str(args[1].u_obj);\n\n    int mode_rw = 0, mode_x = 0;\n    while (*mode_s) {\n        switch (*mode_s++) {\n            case 'r':\n                mode_rw = O_RDONLY;\n                break;\n            case 'w':\n                mode_rw = O_WRONLY;\n                mode_x = O_CREAT | O_TRUNC;\n                break;\n            case 'a':\n                mode_rw = O_WRONLY;\n                mode_x = O_CREAT | O_APPEND;\n                break;\n            case '+':\n                mode_rw = O_RDWR;\n                break;\n            #if MICROPY_PY_IO_FILEIO\n            // If we don't have io.FileIO, then files are in text mode implicitly\n            case 'b':\n                type = &mp_type_fileio;\n                break;\n            case 't':\n                type = &mp_type_textio;\n                break;\n            #endif\n        }\n    }\n\n    o->base.type = type;\n\n    mp_obj_t fid = args[0].u_obj;\n\n    if (MP_OBJ_IS_SMALL_INT(fid)) {\n        o->fd = MP_OBJ_SMALL_INT_VALUE(fid);\n        return MP_OBJ_FROM_PTR(o);\n    }\n\n    const char *fname = mp_obj_str_get_str(fid);\n    int fd = open(fname, mode_x | mode_rw, 0644);\n    if (fd == -1) {\n        mp_raise_OSError(errno);\n    }\n    o->fd = fd;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t fdfile_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];\n    mp_arg_parse_all_kw_array(n_args, n_kw, args, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals);\n    return fdfile_open(type, arg_vals);\n}\n\nSTATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&fdfile_fileno_obj) },\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },\n    { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },\n    { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&fdfile_close_obj) },\n    { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },\n    { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&fdfile___exit___obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);\n\n#if MICROPY_PY_IO_FILEIO\nSTATIC const mp_stream_p_t fileio_stream_p = {\n    .read = fdfile_read,\n    .write = fdfile_write,\n    .ioctl = fdfile_ioctl,\n};\n\nconst mp_obj_type_t mp_type_fileio = {\n    { &mp_type_type },\n    .name = MP_QSTR_FileIO,\n    .print = fdfile_print,\n    .make_new = fdfile_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &fileio_stream_p,\n    .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,\n};\n#endif\n\nSTATIC const mp_stream_p_t textio_stream_p = {\n    .read = fdfile_read,\n    .write = fdfile_write,\n    .ioctl = fdfile_ioctl,\n    .is_text = true,\n};\n\nconst mp_obj_type_t mp_type_textio = {\n    { &mp_type_type },\n    .name = MP_QSTR_TextIOWrapper,\n    .print = fdfile_print,\n    .make_new = fdfile_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &textio_stream_p,\n    .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,\n};\n\n// Factory function for I/O stream classes\nmp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {\n    // TODO: analyze buffering args and instantiate appropriate type\n    mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];\n    mp_arg_parse_all(n_args, args, kwargs, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals);\n    return fdfile_open(&mp_type_textio, arg_vals);\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);\n\n#endif // MICROPY_PY_IO\n"
  },
  {
    "path": "port/modules/modnetwork.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/objlist.h\"\n#include \"py/runtime.h\"\n#include \"py/mphal.h\"\n#include \"lib/netutils/netutils.h\"\n#include \"modnetwork.h\"\n\n#if MICROPY_PY_NETWORK\n\nSTATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },\n    \n#if defined(MICROPY_PY_WLAN)\n    { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },\n    { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(STATION_IF)},\n    { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(SOFTAP_IF)},\n#endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);\n\nconst mp_obj_module_t mp_module_network = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_network_globals,\n};\n\n#endif  // MICROPY_PY_NETWORK\n"
  },
  {
    "path": "port/modules/modnetwork.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_MODNETWORK_H\n#define MICROPY_INCLUDED_MODNETWORK_H\n\n#define STATION_IF   0\n#define SOFTAP_IF    1\n\n#define MOD_NETWORK_AF_INET (2)\n#define MOD_NETWORK_AF_INET6 (10)\n\n#define MOD_NETWORK_SOCK_STREAM (1)\n#define MOD_NETWORK_SOCK_DGRAM (2)\n#define MOD_NETWORK_SOCK_RAW (3)\n\n#define MODNETWORK_INCLUDE_CONSTANTS (1)\n\nMP_DECLARE_CONST_FUN_OBJ_KW(get_wlan_obj);\n\n#endif // MICROPY_INCLUDED_MODNETWORK_H\n"
  },
  {
    "path": "port/modules/modnetwork_wlan.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 SummerGift <SummerGift@qq.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/objlist.h\"\n#include \"py/runtime.h\"\n#include \"py/mphal.h\"\n#include \"lib/netutils/netutils.h\"\n\n#if MICROPY_PY_WLAN\n#include <rtdbg.h>\n#include <rtthread.h>\n#include <wlan_mgnt.h>\n#include <wlan_cfg.h>\n#include <wlan_prot.h>\n#include <arpa/inet.h>\n#include <netdev.h>     \n#include \"modnetwork.h\"\n\nextern struct netdev *netdev_default;\n\ntypedef struct _wlan_if_obj_t {\n    mp_obj_base_t base;\n    int if_id;\n} wlan_if_obj_t;\n\nenum {\n    STATION_IDLE = 0,\n    STATION_CONNECTING,\n    STATION_WRONG_PASSWORD,\n    STATION_NO_AP_FOUND,\n    STATION_CONNECT_FAIL,\n    STATION_GOT_IP,\n};\n\nconst mp_obj_type_t wlan_if_type;\nSTATIC struct rt_wlan_info _ap_info;\nSTATIC char _ap_password[RT_WLAN_PASSWORD_MAX_LENGTH];\n\nSTATIC void error_check(bool status, const char *msg) {\n    if (!status) {\n        nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg));\n    }\n}\n\nSTATIC const wlan_if_obj_t wlan_objs[] = {\n    {{&wlan_if_type}, STATION_IF},\n    {{&wlan_if_type}, SOFTAP_IF},\n};\n\nSTATIC void require_if(mp_obj_t wlan_if, int if_no) {\n    wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);\n    if (self->if_id != if_no) {\n        error_check(false, if_no == STATION_IF ? \"STA required\" : \"AP required\");\n    }\n}\n\nSTATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) {\n    int idx = 0;\n    if (n_args > 0) {\n        idx = mp_obj_get_int(args[0]);\n        if (idx < 0 || idx >= sizeof(wlan_objs)) {\n            mp_raise_ValueError(NULL);\n        }\n    }\n    return MP_OBJ_FROM_PTR(&wlan_objs[idx]);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan);\n\nSTATIC mp_obj_t wlan_active(size_t n_args, const mp_obj_t *args) {\n\n    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);\n\n    if (n_args > 1) {\n\n        if (self->if_id == STATION_IF)\n        {\n            if (mp_obj_get_int(args[1]) == RT_TRUE)\n            {\n                error_check(netdev_set_up(netdev_default) == RT_EOK, \"Cannot active wlan device\");\n            }\n            else\n            {\n                error_check(netdev_set_down(netdev_default) == RT_EOK, \"Cannot disable wlan device\");\n            }\n        }\n        else\n        {\n            if (mp_obj_get_int(args[1]) == RT_TRUE)\n            {\n                error_check(rt_wlan_start_ap((char *)&_ap_info.ssid.val, _ap_password) == RT_EOK, \"Cannot start AP\");\n            }\n            else\n            {\n                error_check(rt_wlan_ap_stop() == RT_EOK, \"Cannot stop AP\");\n            }\n        }\n\n        return mp_const_none;\n    }\n\n    if (self->if_id == STATION_IF)\n    {\n        return mp_obj_new_bool(rt_wlan_get_mode(\"wlan0\") == RT_WLAN_STATION);\n    }\n    else\n    {\n        return mp_obj_new_bool(rt_wlan_get_mode(\"wlan1\") == RT_WLAN_AP);\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_active_obj, 1, 2, wlan_active);\n\nSTATIC mp_obj_t wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_ssid, ARG_password, ARG_bssid };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },\n        { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },\n        { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },\n    };\n\n    // parse args\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n\n    require_if(pos_args[0], STATION_IF);\n    \n    const char *ssid = RT_NULL;\n    const char *key = RT_NULL;\n    size_t len;\n    const char *p;\n\n    // set parameters based on given args\n    if (args[ARG_ssid].u_obj != mp_const_none) {\n        p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len);\n        ssid = p;\n    }\n\n    if (args[ARG_password].u_obj != mp_const_none) {\n        p = mp_obj_str_get_data(args[ARG_password].u_obj, &len);\n        key = p;\n    }\n\n    error_check(rt_wlan_connect(ssid, key) == RT_EOK, \"Cannot connect to AP\");\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_connect_obj, 1, wlan_connect);\n\nSTATIC mp_obj_t wlan_disconnect(mp_obj_t self_in) {\n    require_if(self_in, STATION_IF);\n    error_check(rt_wlan_disconnect() == RT_EOK, \"Cannot disconnect from AP\");\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_disconnect_obj, wlan_disconnect);\n\nSTATIC mp_obj_t wlan_status(size_t n_args, const mp_obj_t *args) {\n    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);\n    if (n_args == 1) {\n        // Get link status\n        if (self->if_id == STATION_IF) {\n            \n            if(rt_wlan_is_ready() == RT_EOK)\n            {\n                return MP_OBJ_NEW_SMALL_INT(STATION_GOT_IP);\n            }\n            else\n            {\n                return MP_OBJ_NEW_SMALL_INT(STATION_IDLE);\n            }\n        }\n        return MP_OBJ_NEW_SMALL_INT(-1);\n    } else {\n        // Get specific status parameter\n        switch (mp_obj_str_get_qstr(args[1])) {\n            case MP_QSTR_rssi:\n                if (self->if_id == STATION_IF) {\n                    return MP_OBJ_NEW_SMALL_INT(rt_wlan_get_rssi());\n                }\n        }\n        mp_raise_ValueError(\"unknown status param\");\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_status_obj, 1, 2, wlan_status);\n\n#if (RTTHREAD_VERSION >= RT_VERSION_CHECK(4, 1, 0)) && defined(RT_USING_WIFI)\n#include <wlan_mgnt.h>\n#include <wlan_prot.h>\n#include <wlan_cfg.h>\n\nstatic struct rt_semaphore scan_done;\nstruct rt_wlan_scan_result *scan_result_cache = RT_NULL;\n\nstatic void wlan_scan_report_hander(int event,struct rt_wlan_buff *buff,void *parameter)\n{\n    struct rt_wlan_info *info = RT_NULL;\n    int index = 0;\n    int ret = RT_EOK;\n    RT_ASSERT(event == RT_WLAN_EVT_SCAN_REPORT);\n    RT_ASSERT(buff != RT_NULL);\n    RT_ASSERT(parameter != RT_NULL);\n\n    info = (struct rt_wlan_info *)buff->data;\n    index = *((int *)(parameter));\n    if (scan_result_cache == RT_NULL)\n    {\n        RT_ASSERT(index == 0);\n        scan_result_cache = rt_malloc(sizeof(struct rt_wlan_scan_result) + (rt_ubase_t)sizeof(struct rt_wlan_info));\n        scan_result_cache->num = 0;\n        scan_result_cache->info = (struct rt_wlan_info *)(rt_ubase_t)((rt_ubase_t)&scan_result_cache->info + sizeof(struct rt_wlan_info *));\n    }\n    else\n    {\n        scan_result_cache = rt_realloc(scan_result_cache, sizeof(struct rt_wlan_scan_result) +\n                              (uint32_t)sizeof(struct rt_wlan_info) * (index + 1));\n        scan_result_cache->info = (struct rt_wlan_info *)(rt_ubase_t)((rt_ubase_t)&scan_result_cache->info + sizeof(struct rt_wlan_info *));\n    }\n    if (scan_result_cache == RT_NULL)\n    {\n        LOG_E(\"malloc failed!\");\n    }\n    rt_memcpy(&(scan_result_cache->info)[index], info, sizeof(struct rt_wlan_info));\n    scan_result_cache->num = index + 1;\n    ++ *((int *)(parameter));\n}\n\nstatic void wlan_scan_done_hander(int event,struct rt_wlan_buff *buff,void *parameter)\n{\n    RT_ASSERT(event == RT_WLAN_EVT_SCAN_DONE);\n    rt_sem_release(&scan_done);\n}\n\nstruct rt_wlan_scan_result *rt_wlan_scan_sync(void)\n{\n    static int _init = 0;\n    static int i = 0;\n\n    LOG_D(\"start to scan ap ...\");\n    if (!_init)\n    {\n        _init = 1;\n        rt_sem_init(&scan_done, \"scan_done\", 0 , RT_IPC_FLAG_FIFO);\n    }\n    rt_wlan_register_event_handler(RT_WLAN_EVT_SCAN_REPORT, wlan_scan_report_hander,&i);\n    rt_wlan_register_event_handler(RT_WLAN_EVT_SCAN_DONE, wlan_scan_done_hander,RT_NULL);\n    if(rt_wlan_scan() == RT_EOK)\n    {\n        LOG_D(\"the scan is started... \");\n    }\n    else\n    {\n        LOG_E(\"scan failed\");\n    }\n    rt_sem_take(&scan_done, RT_WAITING_FOREVER);\n    i = 0;\n    return scan_result_cache;\n}\n\nvoid rt_wlan_scan_result_clean(void)\n{\n    if(scan_result_cache)\n    {\n        rt_free(scan_result_cache);\n        scan_result_cache = 0;\n    }\n}\n#endif\n\nSTATIC mp_obj_t *wlan_scan_list = NULL;\n\nvoid wlan_station_scan(void)\n{\n    if (wlan_scan_list == NULL) {\n        // called unexpectedly\n        return;\n    }\n    \n    struct rt_wlan_scan_result *scan_result = RT_NULL;\n\n    /* scan ap info */\n    scan_result = rt_wlan_scan_sync();\n    if (scan_result)\n    {\n        int index, num;\n        char *security;\n\n        num = scan_result->num;\n        for (index = 0; index < num; index ++)\n        {\n            switch (scan_result->info[index].security)\n            {\n            case SECURITY_OPEN:\n                security = \"OPEN\";\n                break;\n            case SECURITY_WEP_PSK:\n                security = \"WEP_PSK\";\n                break;\n            case SECURITY_WEP_SHARED:\n                security = \"WEP_SHARED\";\n                break;\n            case SECURITY_WPA_TKIP_PSK:\n                security = \"WPA_TKIP_PSK\";\n                break;\n            case SECURITY_WPA_AES_PSK:\n                security = \"WPA_AES_PSK\";\n                break;\n            case SECURITY_WPA2_AES_PSK:\n                security = \"WPA2_AES_PSK\";\n                break;\n            case SECURITY_WPA2_TKIP_PSK:\n                security = \"WPA2_TKIP_PSK\";\n                break;\n            case SECURITY_WPA2_MIXED_PSK:\n                security = \"WPA2_MIXED_PSK\";\n                break;\n            case SECURITY_WPS_OPEN:\n                security = \"WPS_OPEN\";\n                break;\n            case SECURITY_WPS_SECURE:\n                security = \"WPS_SECURE\";\n                break;\n            default:\n                security = \"UNKNOWN\";\n                break;\n            }\n\n            mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);\n            t->items[0] = mp_obj_new_bytes(&scan_result->info[index].ssid.val[0], strlen((char *)(&scan_result->info[index].ssid.val[0])));\n            t->items[1] = mp_obj_new_bytes(&scan_result->info[index].bssid[0], strlen((char *)(&scan_result->info[index].bssid[0])));\n            t->items[2] = MP_OBJ_NEW_SMALL_INT(scan_result->info[index].channel);\n            t->items[3] = MP_OBJ_NEW_SMALL_INT(scan_result->info[index].rssi);\n            t->items[4] = mp_obj_new_bytes((const byte *)security, strlen(security));\n            t->items[5] = MP_OBJ_NEW_SMALL_INT(scan_result->info[index].hidden);\n            \n            mp_obj_list_append(*wlan_scan_list, MP_OBJ_FROM_PTR(t));\n\n        }\n        rt_wlan_scan_result_clean();\n    }\n    else\n    {\n        mp_printf(&mp_plat_print, (\"wifi scan result is null\\n\"));\n        *wlan_scan_list = MP_OBJ_NULL;\n    }\n}\n\nSTATIC mp_obj_t wlan_scan(mp_obj_t self_in) {\n    require_if(self_in, STATION_IF);\n\n    mp_obj_t list = mp_obj_new_list(0, NULL);\n    wlan_scan_list = &list;\n    wlan_station_scan();\n\n    if (list == MP_OBJ_NULL) {\n        nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, \"scan failed\"));\n    }\n    return list;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_scan_obj, wlan_scan);\n\n/// \\method isconnected()\n/// Return True if connected to an AP and an IP address has been assigned,\n/// false otherwise.\nSTATIC mp_obj_t wlan_isconnected(mp_obj_t self_in) {\n    wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->if_id == STATION_IF) {\n        if (rt_wlan_is_connected() == RT_TRUE) {\n            return mp_const_true;\n        }\n    } else {\n        if (rt_wlan_ap_get_sta_num() > 0) {\n            return mp_const_true;\n        }\n    }\n    return mp_const_false;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_isconnected_obj, wlan_isconnected);\n\nSTATIC mp_obj_t wlan_ifconfig(size_t n_args, const mp_obj_t *args) {\n    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);\n    \n    struct netdev *netdev = netdev_default;\n    if (netdev == RT_NULL)\n    {\n        mp_printf(&mp_plat_print, (\"not find wlan interface device.\\n\"));\n        return MP_OBJ_NEW_SMALL_INT(-1);\n    }\n\n    if (n_args == 1) {\n        // get\n        mp_obj_t tuple[4] = {\n            mp_obj_new_str((const char *)inet_ntoa(netdev->ip_addr), strlen((char *)(inet_ntoa(netdev->ip_addr)))),\n            mp_obj_new_str((const char *)inet_ntoa(netdev->netmask), strlen((char *)(inet_ntoa(netdev->netmask)))),\n            mp_obj_new_str((const char *)inet_ntoa(netdev->gw), strlen((char *)(inet_ntoa(netdev->gw)))),\n            mp_obj_new_str((const char *)inet_ntoa(netdev->dns_servers), strlen((char *)(inet_ntoa(netdev->dns_servers)))),\n        };\n        return mp_obj_new_tuple(4, tuple);\n    } \n    else \n    {\n        // set\n        mp_obj_t *items;\n        uint8_t ip_addr[4];\n        uint8_t netmask[4];\n        uint8_t gw[4];\n        uint8_t dns_server[4];\n        \n        mp_obj_get_array_fixed_n(args[1], 4, &items);\n\n        netutils_parse_ipv4_addr(items[0], (uint8_t *)ip_addr,    NETUTILS_BIG);\n        netutils_parse_ipv4_addr(items[1], (uint8_t *)netmask,    NETUTILS_BIG);\n        netutils_parse_ipv4_addr(items[2], (uint8_t *)gw     ,    NETUTILS_BIG);\n        netutils_parse_ipv4_addr(items[3], (uint8_t *)dns_server, NETUTILS_BIG);\n\n        // To set a static IP we have to disable DHCP first\n        if (self->if_id == STATION_IF) {\n            if(netdev_dhcp_enabled(netdev, 0) == RT_EOK)\n            {\n                if (netdev_set_ipaddr(netdev, (const ip_addr_t *)ip_addr) != RT_EOK)\n                {\n                    nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, \"netdev_set_ipaddr() failed\"));         \n                }\n            }\n            else\n            {\n                nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, \"netdev_dhcp_enabled() failed\"));  \n            }\n        }\n        else \n        {\n            // TODO modify IP netmask gw under AP mode\n            netdev_set_dns_server(netdev, 0, (const ip_addr_t *)dns_server);\n            return mp_const_none;\n        }\n\n        netdev_set_netmask(netdev, (const ip_addr_t *)netmask);\n        netdev_set_gw(netdev, (const ip_addr_t *)gw);\n        netdev_set_dns_server(netdev, 0, (const ip_addr_t *)dns_server);\n    }\n    \n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_ifconfig_obj, 1, 2, wlan_ifconfig);\n\nSTATIC mp_obj_t wlan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {\n    if (n_args != 1 && kwargs->used != 0) {\n        mp_raise_TypeError(\"either pos or kw args are allowed\");\n    }\n\n    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);\n    struct rt_wlan_info cfg = {0};\n\n    if (self->if_id == STATION_IF) {\n        error_check(rt_wlan_get_info(&cfg) == RT_EOK, \"can't get STA config\");\n    } else {\n        error_check(rt_wlan_ap_get_info(&cfg) == RT_EOK, \"can't get AP config\");\n    }\n\n    int req_if = -1;\n\n    if (kwargs->used != 0) {\n\n        for (mp_uint_t i = 0; i < kwargs->alloc; i++) {\n            if (mp_map_slot_is_filled(kwargs, i)) {\n                #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)\n                switch ((uintptr_t)kwargs->table[i].key) {\n                    case QS(MP_QSTR_mac): {\n                        mp_buffer_info_t bufinfo;\n                        mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);\n                        if (bufinfo.len != 6) {\n                            mp_raise_ValueError(\"invalid buffer length\");\n                        }\n                        error_check(rt_wlan_set_mac((rt_uint8_t *)bufinfo.buf) == RT_EOK, \"can't set MAC\");\n\n                        break;\n                    }\n                    case QS(MP_QSTR_essid): { \n                        req_if = SOFTAP_IF;\n                        size_t len;\n                        const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);\n                        len = MIN(len, sizeof(_ap_info.ssid.val));\n                        memcpy(_ap_info.ssid.val, s, len);\n                        _ap_info.ssid.len = len;\n                        break;\n                    }\n                    case QS(MP_QSTR_hidden): {\n                        req_if = SOFTAP_IF;\n                        _ap_info.hidden = mp_obj_is_true(kwargs->table[i].value);\n                        break;\n                    }\n//                    case QS(MP_QSTR_authmode): {\n//                        req_if = SOFTAP_IF;\n//                        cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);\n//                        break;\n//                    }\n                    case QS(MP_QSTR_password): {\n                        req_if = SOFTAP_IF;\n                        size_t len;\n                        const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);\n                        len = MIN(len, sizeof(_ap_password) - 1);\n                        memcpy(_ap_password, s, len);\n                        _ap_password[len] = 0;\n                        break;\n                    }\n                    case QS(MP_QSTR_channel): {\n                        req_if = SOFTAP_IF;\n                        _ap_info.channel = mp_obj_get_int(kwargs->table[i].value);\n                        break;\n                    }\n//                    case QS(MP_QSTR_dhcp_hostname): {\n//                        req_if = STATION_IF;\n//                        if (self->if_id == STATION_IF) {\n//                            const char *s = mp_obj_str_get_str(kwargs->table[i].value);\n//                            wifi_station_set_hostname((char*)s);\n//                        }\n//                        break;\n//                    }\n                    default:\n                        goto unknown;\n                }\n                #undef QS\n            }\n        }\n\n        // We post-check interface requirements to save on code size\n        if (req_if >= 0) {\n            require_if(args[0], req_if);\n        }\n\n        return mp_const_none;\n    }\n\n    // Get config\n    if (n_args != 2) {\n        mp_raise_TypeError(\"can query only one param\");\n    }\n\n    mp_obj_t val;\n\n    qstr key = mp_obj_str_get_qstr(args[1]);\n    switch (key) {\n        case MP_QSTR_mac: {\n            uint8_t mac[6];\n            error_check(rt_wlan_get_mac(mac) == RT_EOK, \"can't get mac config\");\n            return mp_obj_new_bytes(mac, sizeof(mac));\n        }\n        case MP_QSTR_essid:\n            if (self->if_id == STATION_IF) {\n                val = mp_obj_new_str((char*)cfg.ssid.val, strlen((char*)cfg.ssid.val));\n            } else {\n                val = mp_obj_new_str((char*)_ap_info.ssid.val, _ap_info.ssid.len);\n            }\n            break;\n        case MP_QSTR_hidden:\n            req_if = SOFTAP_IF;\n            val = mp_obj_new_bool(cfg.hidden);\n            break;\n//        case MP_QSTR_authmode:\n//            req_if = SOFTAP_IF;\n//            val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);\n//            break;\n        case MP_QSTR_channel:\n            req_if = SOFTAP_IF;\n            val = MP_OBJ_NEW_SMALL_INT(cfg.channel);\n            break;\n//        case MP_QSTR_dhcp_hostname: {\n//            req_if = STATION_IF;\n//            char* s = wifi_station_get_hostname();\n//            if (s == NULL) {\n//                val = MP_OBJ_NEW_QSTR(MP_QSTR_);\n//            } else {\n//                val = mp_obj_new_str(s, strlen(s));\n//            }\n//            break;\n//        }\n        default:\n            goto unknown;\n    }\n\n    // We post-check interface requirements to save on code size\n    if (req_if >= 0) {\n        require_if(args[0], req_if);\n    }\n\n    return val;\n\nunknown:\n    mp_raise_ValueError(\"unknown config param\");\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_config_obj, 1, wlan_config);\n\nSTATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&wlan_active_obj) },\n    { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&wlan_connect_obj) },\n    { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&wlan_disconnect_obj) },\n    { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&wlan_status_obj) },\n    { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&wlan_scan_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wlan_isconnected_obj) },\n    { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&wlan_config_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wlan_ifconfig_obj) },\n    \n#if MODNETWORK_INCLUDE_CONSTANTS\n    { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STATION_IDLE)},\n    { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STATION_CONNECTING)},\n    { MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(STATION_WRONG_PASSWORD)},\n    { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(STATION_NO_AP_FOUND)},\n    { MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(STATION_CONNECT_FAIL)},\n    { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STATION_GOT_IP)},\n\n//    { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(PHY_MODE_11B) },\n//    { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(PHY_MODE_11G) },\n//    { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(PHY_MODE_11N) },\n\n//    { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(AUTH_OPEN) },\n//    { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(AUTH_WEP) },\n//    { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(AUTH_WPA_PSK) },\n//    { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(AUTH_WPA2_PSK) },\n//    { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(AUTH_WPA_WPA2_PSK) },\n#endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);\n\nconst mp_obj_type_t wlan_if_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_WLAN,\n    .locals_dict = (mp_obj_dict_t*)&wlan_if_locals_dict,\n};\n\n#endif\n"
  },
  {
    "path": "port/modules/modpyb.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n\n#include \"py/runtime.h\"\n#include \"py/gc.h\"\n#include \"py/builtin.h\"\n#include \"py/mphal.h\"\n#include \"lib/utils/pyexec.h\"\n#include \"modmachine.h\"\n#include \"extmod/vfs.h\"\n#include \"extmod/utime_mphal.h\"\n\n/// \\function elapsed_millis(start)\n/// Returns the number of milliseconds which have elapsed since `start`.\n///\n/// This function takes care of counter wrap, and always returns a positive\n/// number. This means it can be used to measure periods upto about 12.4 days.\n///\n/// Example:\n///     start = pyb.millis()\n///     while pyb.elapsed_millis(start) < 1000:\n///         # Perform some operation\nSTATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) {\n    uint32_t startMillis = mp_obj_get_int(start);\n    uint32_t currMillis = mp_hal_ticks_ms();\n    return MP_OBJ_NEW_SMALL_INT((currMillis - startMillis) & 0x3fffffff);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_millis_obj, pyb_elapsed_millis);\n\n/// \\function elapsed_micros(start)\n/// Returns the number of microseconds which have elapsed since `start`.\n///\n/// This function takes care of counter wrap, and always returns a positive\n/// number. This means it can be used to measure periods upto about 17.8 minutes.\n///\n/// Example:\n///     start = pyb.micros()\n///     while pyb.elapsed_micros(start) < 1000:\n///         # Perform some operation\nSTATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) {\n    uint32_t startMicros = mp_obj_get_int(start);\n    uint32_t currMicros = mp_hal_ticks_us();\n    return MP_OBJ_NEW_SMALL_INT((currMicros - startMicros) & 0x3fffffff);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_micros_obj, pyb_elapsed_micros);\n\nMP_DECLARE_CONST_FUN_OBJ_KW(pyb_main_obj); // defined in main.c\n\nSTATIC const mp_rom_map_elem_t pyb_module_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyb) },\n\n    { MP_ROM_QSTR(MP_QSTR_hard_reset), MP_ROM_PTR(&machine_reset_obj) },\n    { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_info_obj) },\n    { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },\n    { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) },\n    #if MICROPY_REPL_INFO\n    { MP_ROM_QSTR(MP_QSTR_repl_info), MP_ROM_PTR(&pyb_set_repl_info_obj) },\n    #endif\n\n    { MP_ROM_QSTR(MP_QSTR_wfi), MP_ROM_PTR(&pyb_wfi_obj) },\n    { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&pyb_disable_irq_obj) },\n    { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&pyb_enable_irq_obj) },\n\n    { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_sleep_obj) },\n    { MP_ROM_QSTR(MP_QSTR_standby), MP_ROM_PTR(&machine_deepsleep_obj) },\n//    { MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&pyb_main_obj) },\n//    { MP_ROM_QSTR(MP_QSTR_repl_uart), MP_ROM_PTR(&pyb_repl_uart_obj) },\n\n    { MP_ROM_QSTR(MP_QSTR_millis), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },\n    { MP_ROM_QSTR(MP_QSTR_elapsed_millis), MP_ROM_PTR(&pyb_elapsed_millis_obj) },\n    { MP_ROM_QSTR(MP_QSTR_micros), MP_ROM_PTR(&mp_utime_ticks_us_obj) },\n    { MP_ROM_QSTR(MP_QSTR_elapsed_micros), MP_ROM_PTR(&pyb_elapsed_micros_obj) },\n    { MP_ROM_QSTR(MP_QSTR_delay), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },\n    { MP_ROM_QSTR(MP_QSTR_udelay), MP_ROM_PTR(&mp_utime_sleep_us_obj) },\n//    { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_os_mount_obj) },\n\n//    { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) },\n\n//#if MICROPY_HW_ENABLE_RNG\n//    { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&pyb_rng_get_obj) },\n//#endif\n//\n//#if MICROPY_HW_ENABLE_RTC\n//    { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) },\n//#endif\n//\n#if MICROPY_PY_PIN\n    { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) },\n#endif\n//    { MP_ROM_QSTR(MP_QSTR_ExtInt), MP_ROM_PTR(&extint_type) },\n//\n//#if MICROPY_HW_ENABLE_SERVO\n//    { MP_ROM_QSTR(MP_QSTR_pwm), MP_ROM_PTR(&pyb_pwm_set_obj) },\n//    { MP_ROM_QSTR(MP_QSTR_servo), MP_ROM_PTR(&pyb_servo_set_obj) },\n//    { MP_ROM_QSTR(MP_QSTR_Servo), MP_ROM_PTR(&pyb_servo_type) },\n//#endif\n//\n//#if MICROPY_HW_HAS_SWITCH\n//    { MP_ROM_QSTR(MP_QSTR_Switch), MP_ROM_PTR(&pyb_switch_type) },\n//#endif\n//\n//#if MICROPY_HW_HAS_FLASH\n//    { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&pyb_flash_type) },\n//#endif\n//\n//#if MICROPY_HW_HAS_SDCARD\n//    { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sdcard_obj) }, // now obsolete\n//    { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&pyb_sdcard_type) },\n//#endif\n//\n//#if defined(MICROPY_HW_LED1)\n//    { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) },\n//#endif\n//    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) },\n//    { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) },\n//    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },\n//#if MICROPY_HW_ENABLE_CAN\n//    { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&pyb_can_type) },\n//#endif\n//\n//    { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) },\n//    { MP_ROM_QSTR(MP_QSTR_ADCAll), MP_ROM_PTR(&pyb_adc_all_type) },\n//\n//#if MICROPY_HW_ENABLE_DAC\n//    { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pyb_dac_type) },\n//#endif\n//\n//#if MICROPY_HW_HAS_MMA7660\n//    { MP_ROM_QSTR(MP_QSTR_Accel), MP_ROM_PTR(&pyb_accel_type) },\n//#endif\n//\n//#if MICROPY_HW_HAS_LCD\n//    { MP_ROM_QSTR(MP_QSTR_LCD), MP_ROM_PTR(&pyb_lcd_type) },\n//#endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table);\n\nconst mp_obj_module_t pyb_module = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&pyb_module_globals,\n};\n"
  },
  {
    "path": "port/modules/modrtthread.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_PY_RTTHREAD\n\n#include <rtthread.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n\nrt_bool_t rt_is_preempt_thread(void) {\n    if (rt_interrupt_get_nest() || rt_critical_level()) {\n        return RT_FALSE;\n    } else {\n        return RT_TRUE;\n    }\n}\n\nSTATIC mp_obj_t mod_is_preempt_thread(void) {\n    return mp_obj_new_bool(rt_is_preempt_thread());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_is_preempt_thread_obj, mod_is_preempt_thread);\n\nSTATIC mp_obj_t mod_current_tid(void) {\n    return MP_OBJ_NEW_SMALL_INT(rt_thread_self());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_current_tid_obj, mod_current_tid);\n\nSTATIC mp_obj_t mod_stacks_analyze(void) {\n#ifdef RT_USING_FINSH\n    extern long list_thread(void);\n    list_thread();\n#else\n    mp_printf(&mp_plat_print, \"Not available when FINSH module disable\\n\");\n#endif\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_stacks_analyze_obj, mod_stacks_analyze);\n\nSTATIC mp_obj_t mod_list_device(void) {\n    struct rt_device *device;\n    struct rt_list_node *node;\n\n    struct rt_object_information *info = rt_object_get_information(RT_Object_Class_Device);\n    struct rt_list_node *list = &info->object_list;\n    mp_obj_t mp_list = mp_obj_new_list(0, NULL);\n\n    rt_enter_critical();\n\n    for (node = list->next; node != list; node = node->next)\n    {\n        device = (struct rt_device *)(rt_list_entry(node, struct rt_object, list));\n\n        mp_obj_tuple_t *t = mp_obj_new_tuple(2, NULL);\n        t->items[0] = mp_obj_new_str(device->parent.name, strlen((char *)device->parent.name));\n        t->items[1] = MP_OBJ_NEW_SMALL_INT((device->type <= RT_Device_Class_Unknown) ? device->type : RT_Device_Class_Unknown);\n        mp_obj_list_append(mp_list, MP_OBJ_FROM_PTR(t));\n    }\n\n    rt_exit_critical();\n\n    return mp_list;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_list_device_obj, mod_list_device);\n\nSTATIC const mp_rom_map_elem_t mp_module_rtthread_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rtthread) },\n    { MP_ROM_QSTR(MP_QSTR_is_preempt_thread), MP_ROM_PTR(&mod_is_preempt_thread_obj) },\n    { MP_ROM_QSTR(MP_QSTR_current_tid), MP_ROM_PTR(&mod_current_tid_obj) },\n    { MP_ROM_QSTR(MP_QSTR_stacks_analyze), MP_ROM_PTR(&mod_stacks_analyze_obj) },\n    { MP_ROM_QSTR(MP_QSTR_list_device), MP_ROM_PTR(&mod_list_device_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_rtthread_globals, mp_module_rtthread_globals_table);\n\nconst mp_obj_module_t mp_module_rtthread = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_rtthread_globals,\n};\n\n#endif // MICROPY_PY_RTTHREAD\n"
  },
  {
    "path": "port/modules/moduos.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 SummerGift <zhangyuan@rt-thread.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_PY_MODUOS\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/objtuple.h\"\n#include \"py/objstr.h\"\n#include \"py/mperrno.h\"\n#include \"lib/timeutils/timeutils.h\"\n#include \"extmod/misc.h\"\n#include \"genhdr/mpversion.h\"\n\n#if !MICROPY_VFS\n#if MICROPY_PY_MODUOS_FILE\n#include \"moduos_file.h\"\n#endif\n#else\n#include \"extmod/vfs.h\"\n#if MICROPY_VFS_FAT\n#include \"extmod/vfs_fat.h\"\n#endif\n#endif\n\nSTATIC const qstr os_uname_info_fields[] = {\n    MP_QSTR_sysname, MP_QSTR_nodename,\n    MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine\n};\nSTATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, \"pyboard\");\nSTATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, \"pyboard\");\nSTATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING);\nSTATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG \" on \" MICROPY_BUILD_DATE);\nSTATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME \" with \" MICROPY_HW_MCU_NAME);\nSTATIC MP_DEFINE_ATTRTUPLE(\n    os_uname_info_obj,\n    os_uname_info_fields,\n    5,\n    (mp_obj_t)&os_uname_info_sysname_obj,\n    (mp_obj_t)&os_uname_info_nodename_obj,\n    (mp_obj_t)&os_uname_info_release_obj,\n    (mp_obj_t)&os_uname_info_version_obj,\n    (mp_obj_t)&os_uname_info_machine_obj\n);\n\nSTATIC mp_obj_t os_uname(void) {\n    return (mp_obj_t)&os_uname_info_obj;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);\n\nSTATIC mp_obj_t os_sync(void) {\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync);\n\n#if MICROPY_HW_ENABLE_RNG\n/// \\function urandom(n)\n/// Return a bytes object with n random bytes, generated by the hardware\n/// random number generator.\nSTATIC mp_obj_t os_urandom(mp_obj_t num) {\n    mp_int_t n = mp_obj_get_int(num);\n    vstr_t vstr;\n    vstr_init_len(&vstr, n);\n    for (int i = 0; i < n; i++) {\n        vstr.buf[i] = rng_get();\n    }\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);\n#endif\n\nSTATIC const mp_rom_map_elem_t os_module_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },\n    { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },\n    { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_posix_chdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_posix_getcwd_obj) },\n    { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_posix_listdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_posix_listdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_posix_mkdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_posix_remove_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rename),MP_ROM_PTR(&mp_posix_rename_obj)},\n    { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_posix_rmdir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_posix_stat_obj) },\n    { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_posix_remove_obj) },     // unlink aliases to remove\n    { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) },\n    { MP_ROM_QSTR(MP_QSTR_file_crc32), MP_ROM_PTR(&mp_posix_file_crc32_obj) },\n\n    /// \\constant sep - separation character used in paths\n    //{ MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) },\n\n#if MICROPY_HW_ENABLE_RNG\n    { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) },\n#endif\n\n    // these are MicroPython extensions\n    { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_posix_mount_obj) },\n    { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_posix_umount_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&mp_posix_mkfs_obj) },\n    //{ MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);\n\nconst mp_obj_module_t mp_module_uos = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&os_module_globals,\n};\n\n#endif /* MICROPY_PY_MODUOS */\n"
  },
  {
    "path": "port/modules/moduos_file.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 SummerGift <zhangyuan@rt-thread.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_PY_MODUOS_FILE\n\n#include <stdint.h>\n#include <string.h>\n#include <dfs_posix.h>\n#include \"py/runtime.h\"\n#include \"py/objstr.h\"\n#include \"py/mperrno.h\"\n#include \"moduos_file.h\"\n\nmp_obj_t mp_posix_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(mp_posix_mount_obj, 2, mp_posix_mount);\n\nmp_obj_t mp_posix_umount(mp_obj_t mnt_in) {\n\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_posix_umount_obj, mp_posix_umount);\n\nmp_obj_t mp_posix_mkfs(size_t n_args, const mp_obj_t *args)  {\n\n    int result = RT_EOK;\n    char *type = \"elm\"; /* use the default file system type as 'fatfs' */\n\n    if (n_args == 1)\n    {\n        result = dfs_mkfs(type, mp_obj_str_get_str(args[0]));\n    }else if (n_args == 2)\n    {\n        type = (char *)mp_obj_str_get_str(args[0]);\n        result = dfs_mkfs(type, mp_obj_str_get_str(args[1]));\n    }\n\n    if (result != RT_EOK)\n    {\n        mp_raise_ValueError(\"mkfs failed, please check filesystem type and device name.\");\n    }\n\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_posix_mkfs_obj, 1, 2, mp_posix_mkfs);\n\nmp_obj_t mp_posix_chdir(mp_obj_t path_in) {\n    const char *changepath = mp_obj_str_get_str(path_in);\n    if (chdir(changepath) != 0) {\n        mp_printf(&mp_plat_print, \"No such directory: %s\\n\", changepath);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_posix_chdir_obj, mp_posix_chdir);\n\nmp_obj_t mp_posix_getcwd(void) {\n    char buf[MICROPY_ALLOC_PATH_MAX + 1];\n    getcwd(buf, sizeof(buf));\n    return mp_obj_new_str(buf, strlen(buf));\n}\nMP_DEFINE_CONST_FUN_OBJ_0(mp_posix_getcwd_obj, mp_posix_getcwd);\n\n#include <dfs_file.h>\nstatic struct dfs_fd fd;\nstatic struct dirent dirent;\nmp_obj_t mp_posix_listdir(size_t n_args, const mp_obj_t *args) {\n\n    mp_obj_t dir_list = mp_obj_new_list(0, NULL);\n\n    struct stat stat;\n    int length;\n    char *fullpath, *path;\n    const char *pathname;\n\n    if (n_args == 0) {\n#ifdef DFS_USING_WORKDIR\n        extern char working_directory[];\n        pathname = working_directory;\n#else\n        pathname = \"/\";\n#endif\n    } else {\n       pathname = mp_obj_str_get_str(args[0]);\n    }\n\n    fullpath = NULL;\n    if (pathname == NULL)\n    {\n#ifdef DFS_USING_WORKDIR\n        extern char working_directory[];\n        /* open current working directory */\n        path = rt_strdup(working_directory);\n#else\n        path = rt_strdup(\"/\");\n#endif\n        if (path == NULL)\n            mp_raise_OSError(MP_ENOMEM); /* out of memory */\n    }\n    else\n    {\n        path = (char *)pathname;\n    }\n\n    /* list directory */\n    if (dfs_file_open(&fd, path, O_DIRECTORY) == 0)\n    {\n        do {\n            memset(&dirent, 0, sizeof(struct dirent));\n            length = dfs_file_getdents(&fd, &dirent, sizeof(struct dirent));\n            if (length > 0) {\n                memset(&stat, 0, sizeof(struct stat));\n\n                /* build full path for each file */\n                fullpath = dfs_normalize_path(path, dirent.d_name);\n                if (fullpath == NULL)\n                    break;\n\n                if (dfs_file_stat(fullpath, &stat) == 0) {\n                    mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));\n                    t->items[0] = mp_obj_new_str(dirent.d_name, strlen(dirent.d_name));\n                    t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);\n                    t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number\n                    mp_obj_t next = MP_OBJ_FROM_PTR(t);\n                    mp_obj_t *items;\n                    mp_obj_get_array_fixed_n(next, 3, &items);\n                    mp_obj_list_append(dir_list, items[0]);\n                } else {\n                    mp_printf(&mp_plat_print, \"BAD file: %s\\n\", dirent.d_name);\n                }\n                rt_free(fullpath);\n            }\n        } while (length > 0);\n\n        dfs_file_close(&fd);\n    }\n    else\n    {\n//        mp_printf(&mp_plat_print, \"No such directory\\n\");\n    }\n    if (pathname == NULL)\n        rt_free(path);\n\n    return dir_list;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_posix_listdir_obj, 0, 1, mp_posix_listdir);\n\nmp_obj_t mp_posix_mkdir(mp_obj_t path_in) {\n    const char *createpath = mp_obj_str_get_str(path_in);\n    int res = mkdir(createpath, 0);\n    if (res != 0) {\n        mp_raise_OSError(MP_EEXIST);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_posix_mkdir_obj, mp_posix_mkdir);\n\nmp_obj_t mp_posix_remove(uint n_args, const mp_obj_t *arg) {\n    int index;\n    if (n_args == 0) {\n        mp_printf(&mp_plat_print, \"Usage: rm FILE...\\n\");\n        mp_printf(&mp_plat_print, \"Remove (unlink) the FILE(s).\\n\");\n        return mp_const_none;\n    }\n    for (index = 0; index < n_args; index++) {\n        //mp_printf(&mp_plat_print, \"Remove %s.\\n\", mp_obj_str_get_str(arg[index]));\n        unlink(mp_obj_str_get_str(arg[index]));\n    }\n    // TODO  recursive deletion\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR(mp_posix_remove_obj, 0, mp_posix_remove);\n\nmp_obj_t mp_posix_rename(mp_obj_t old_path_in, mp_obj_t new_path_in) {\n    const char *old_path = mp_obj_str_get_str(old_path_in);\n    const char *new_path = mp_obj_str_get_str(new_path_in);\n    int res = rename(old_path, new_path);\n    if (res != 0) {\n        mp_raise_OSError(MP_EPERM);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_posix_rename_obj, mp_posix_rename);\n\nmp_obj_t mp_posix_rmdir(uint n_args, const mp_obj_t *arg) {\n    int index;\n    if (n_args == 0) {\n        mp_printf(&mp_plat_print, \"Usage: rm FILE...\\n\");\n        mp_printf(&mp_plat_print, \"Remove (unlink) the FILE(s).\\n\");\n        return mp_const_none;\n    }\n    for (index = 0; index < n_args; index++) {\n        //mp_printf(&mp_plat_print, \"Remove %s.\\n\", mp_obj_str_get_str(arg[index]));\n        rmdir(mp_obj_str_get_str(arg[index]));\n    }\n    // TODO  recursive deletion\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR(mp_posix_rmdir_obj, 0, mp_posix_rmdir);\n\nmp_obj_t mp_posix_stat(mp_obj_t path_in) {\n    struct stat buf;\n    const char *createpath = mp_obj_str_get_str(path_in);\n    int res = stat(createpath, &buf);\n    if (res != 0) {\n        mp_raise_OSError(MP_EPERM);\n    }\n    mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));\n    t->items[0] = MP_OBJ_NEW_SMALL_INT(buf.st_mode); // st_mode\n    t->items[1] = MP_OBJ_NEW_SMALL_INT(buf.st_ino); // st_ino\n    t->items[2] = MP_OBJ_NEW_SMALL_INT(buf.st_dev); // st_dev\n    t->items[3] = MP_OBJ_NEW_SMALL_INT(buf.st_nlink); // st_nlink\n    t->items[4] = MP_OBJ_NEW_SMALL_INT(buf.st_uid); // st_uid\n    t->items[5] = MP_OBJ_NEW_SMALL_INT(buf.st_gid); // st_gid\n    t->items[6] = mp_obj_new_int_from_uint(buf.st_size); // st_size\n    t->items[7] = MP_OBJ_NEW_SMALL_INT(buf.st_atime); // st_atime\n    t->items[8] = MP_OBJ_NEW_SMALL_INT(buf.st_mtime); // st_mtime\n    t->items[9] = MP_OBJ_NEW_SMALL_INT(buf.st_ctime); // st_ctime\n    return MP_OBJ_FROM_PTR(t);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_posix_stat_obj, mp_posix_stat);\n\nstatic uint32_t calc_crc32(const char* pathname)\n{\n    #define CALC_BUFFER_SIZE 512\n    extern uint32_t mp_calc_crc32(uint32_t crc, const void *buf, size_t len);\n\n    int fd;\n    uint32_t temp_crc = 0;\n    void *buffer = malloc(CALC_BUFFER_SIZE);\n\n    if (buffer == RT_NULL)\n    {\n        mp_raise_OSError(MP_ENOMEM);\n    }\n\n    fd = open(pathname, O_RDONLY, 0);\n    if (fd < 0)\n    {\n        return -MP_EINVAL;\n    }\n\n    while (1)\n    {\n        int len = read(fd, buffer, CALC_BUFFER_SIZE);\n        if (len < 0)\n        {\n            close(fd);\n            return -MP_EIO;\n        }\n        else if (len == 0)\n            break;\n\n        temp_crc = mp_calc_crc32(temp_crc, buffer, len);\n    }\n\n    close(fd);\n    free(buffer);\n\n    return temp_crc;\n}\n\nmp_obj_t mp_posix_file_crc32(mp_obj_t path_in) {\n    extern void mp_hex_to_str(char *pbDest, char *pbSrc, int nLen);\n    \n    uint32_t value = 0;\n    char str[9];\n    const char *createpath = mp_obj_str_get_str(path_in);\n\n    value = calc_crc32((char *)createpath);\n    mp_hex_to_str(str,(char *)&value, 4);\n\n    return mp_obj_new_str(str, strlen(str));\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_posix_file_crc32_obj, mp_posix_file_crc32);\n\nmp_import_stat_t mp_posix_import_stat(const char *path) {\n\n    struct stat stat;\n\n    if (dfs_file_stat(path, &stat) == 0) {\n        if (S_ISDIR(stat.st_mode)) {\n            return MP_IMPORT_STAT_DIR;\n        } else {\n            return MP_IMPORT_STAT_FILE;\n        }\n    } else {\n        return MP_IMPORT_STAT_NO_EXIST;\n    }\n}\n\n#endif //MICROPY_MODUOS_FILE\n"
  },
  {
    "path": "port/modules/moduos_file.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 SummerGift <zhangyuan@rt-thread.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_MODUOS_FILE_H\n#define MICROPY_INCLUDED_PY_MODUOS_FILE_H\n\n#include \"py/lexer.h\"\n#include \"py/obj.h\"\n\n// MicroPython's port-standardized versions of stat constants\n#define MP_S_IFDIR (0x4000)\n#define MP_S_IFREG (0x8000)\n\n// constants for block protocol ioctl\n#define BP_IOCTL_INIT           (1)\n#define BP_IOCTL_DEINIT         (2)\n#define BP_IOCTL_SYNC           (3)\n#define BP_IOCTL_SEC_COUNT      (4)\n#define BP_IOCTL_SEC_SIZE       (5)\n\nmp_obj_t mp_posix_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);\nmp_obj_t mp_posix_umount(mp_obj_t mnt_in);\nmp_obj_t mp_posix_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);\nmp_obj_t mp_posix_chdir(mp_obj_t path_in);\nmp_obj_t mp_posix_getcwd(void);\nmp_obj_t mp_posix_listdir(size_t n_args, const mp_obj_t *args);\nmp_obj_t mp_posix_mkdir(mp_obj_t path_in);\nmp_obj_t mp_posix_remove(uint n_args, const mp_obj_t *arg);\nmp_obj_t mp_posix_rename(mp_obj_t old_path_in, mp_obj_t new_path_in);\nmp_obj_t mp_posix_rmdir(uint n_args, const mp_obj_t *arg);\nmp_obj_t mp_posix_stat(mp_obj_t path_in);\nmp_obj_t mp_posix_statvfs(mp_obj_t path_in);\nmp_obj_t mp_posix_file_crc32(mp_obj_t path_in);\nmp_obj_t mp_posix_mkfs(size_t n_args, const mp_obj_t *args);\n\nMP_DECLARE_CONST_FUN_OBJ_KW(mp_posix_mount_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_posix_umount_obj);\nMP_DECLARE_CONST_FUN_OBJ_KW(mp_posix_open_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_posix_chdir_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(mp_posix_getcwd_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_posix_listdir_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_posix_mkdir_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR(mp_posix_remove_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_posix_rename_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR(mp_posix_rmdir_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_posix_stat_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_posix_statvfs_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_posix_file_crc32_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_posix_mkfs_obj);\n#endif // MICROPY_INCLUDED_PY_MODUOS_FILE_H\n"
  },
  {
    "path": "port/modules/modusocket.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_PY_USOCKET\n\n#include <stdio.h>\n#include <string.h>\n#include <stdio.h>\n#include <netdb.h>\n#include <sys/socket.h>\n#include <fcntl.h>\n#include <sys/time.h>\n#include <sys/select.h>\n#include <errno.h>\n\n#include \"py/objtuple.h\"\n#include \"py/objlist.h\"\n#include \"py/runtime.h\"\n#include \"py/mperrno.h\"\n#include \"py/stream.h\"\n#include \"py/objstr.h\"\n#include \"py/builtin.h\"\n\n#include \"lib/netutils/netutils.h\"\n#include \"modnetwork.h\"\n\n#define SOCKET_POLL_US (100000)\n\n// socket class\ntypedef struct _socket_obj_t {\n    mp_obj_base_t base;\n    int fd;\n    uint8_t domain;\n    uint8_t type;\n    uint8_t proto;\n    bool peer_closed;\n    unsigned int retries;\n} socket_obj_t;\n\nSTATIC const mp_obj_type_t socket_type;\n\nSTATIC void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms);\n\nNORETURN static void exception_from_errno(int _errno) {\n    // Here we need to convert from lwip errno values to MicroPython's standard ones\n    if (_errno == EINPROGRESS) {\n        _errno = MP_EINPROGRESS;\n    }\n    mp_raise_OSError(_errno);\n}\n\nstatic inline void check_for_exceptions(void) {\n    mp_handle_pending(true);\n}\n\nstatic int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) {\n    const struct addrinfo hints = {\n        .ai_family = AF_INET,\n        .ai_socktype = SOCK_STREAM,\n    };\n\n    mp_obj_t port = portx;\n    if (MP_OBJ_IS_SMALL_INT(port)) {\n        // This is perverse, because lwip_getaddrinfo promptly converts it back to an int, but\n        // that's the API we have to work with ...\n        port = mp_obj_str_binary_op(MP_BINARY_OP_MODULO, mp_obj_new_str_via_qstr(\"%s\", 2), port);\n    }\n\n    const char *host_str = mp_obj_str_get_str(host);\n    const char *port_str = mp_obj_str_get_str(port);\n\n    if (host_str[0] == '\\0') {\n        // a host of \"\" is equivalent to the default/all-local IP address\n        host_str = \"0.0.0.0\";\n    }\n\n    MP_THREAD_GIL_EXIT();\n    int res = getaddrinfo(host_str, port_str, &hints, resp);\n    MP_THREAD_GIL_ENTER();\n\n    return res;\n}\n\nint _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) {\n    mp_uint_t len = 0;\n    mp_obj_t *elem;\n    mp_obj_get_array(addrtuple, &len, &elem);\n    if (len != 2) return -1;\n    return _socket_getaddrinfo2(elem[0], elem[1], resp);\n}\n\nSTATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) {\n    socket_obj_t *self = MP_OBJ_TO_PTR(arg0);\n    struct addrinfo *res;\n    _socket_getaddrinfo(arg1, &res);\n    int r = bind(self->fd, res->ai_addr, res->ai_addrlen);\n    freeaddrinfo(res);\n    if (r < 0) exception_from_errno(errno);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);\n\nSTATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) {\n    socket_obj_t *self = MP_OBJ_TO_PTR(arg0);\n    int backlog = mp_obj_get_int(arg1);\n    int r = listen(self->fd, backlog);\n    if (r < 0) exception_from_errno(errno);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen);\n\nSTATIC mp_obj_t socket_accept(const mp_obj_t arg0) {\n    socket_obj_t *self = MP_OBJ_TO_PTR(arg0);\n\n    struct sockaddr addr;\n    socklen_t addr_len = sizeof(addr);\n\n    int new_fd = -1;\n    for (int i = 0; i <= self->retries; i++) {\n        MP_THREAD_GIL_EXIT();\n        new_fd = accept(self->fd, &addr, &addr_len);\n        MP_THREAD_GIL_ENTER();\n        if (new_fd >= 0) break;\n//        if (errno != EAGAIN) exception_from_errno(errno);\n        check_for_exceptions();\n    }\n    if (new_fd < 0) mp_raise_OSError(MP_ETIMEDOUT);\n\n    // create new socket object\n    socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t);\n    sock->base.type = self->base.type;\n    sock->fd = new_fd;\n    sock->domain = self->domain;\n    sock->type = self->type;\n    sock->proto = self->proto;\n    sock->peer_closed = false;\n    _socket_settimeout(sock, UINT64_MAX);\n\n    // make the return value\n    uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&addr)->sin_addr;\n    mp_uint_t port = ntohs(((struct sockaddr_in*)&addr)->sin_port);\n    mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);\n    client->items[0] = sock;\n    client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);\n\n    return client;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept);\n\nSTATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) {\n    socket_obj_t *self = MP_OBJ_TO_PTR(arg0);\n    struct addrinfo *res;\n    _socket_getaddrinfo(arg1, &res);\n    MP_THREAD_GIL_EXIT();\n    int r = connect(self->fd, res->ai_addr, res->ai_addrlen);\n    MP_THREAD_GIL_ENTER();\n    freeaddrinfo(res);\n    if (r != 0) {\n        exception_from_errno(errno);\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);\n\nSTATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {\n    (void)n_args; // always 4\n    socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);\n\n    int opt = mp_obj_get_int(args[2]);\n\n    switch (opt) {\n        // level: SOL_SOCKET\n        case SO_REUSEADDR: {\n            int val = mp_obj_get_int(args[3]);\n            int ret = setsockopt(self->fd, SOL_SOCKET, opt, &val, sizeof(int));\n            if (ret != 0) {\n                exception_from_errno(errno);\n            }\n            break;\n        }\n\n        // level: IPPROTO_IP\n        case IP_ADD_MEMBERSHIP: {\n            mp_buffer_info_t bufinfo;\n            mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);\n            if (bufinfo.len != sizeof(ip4_addr_t) * 2) {\n                mp_raise_ValueError(NULL);\n            }\n\n//            // POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa\n//            err_t err = igmp_joingroup((const ip4_addr_t*)bufinfo.buf + 1, bufinfo.buf);\n//            if (err != ERR_OK) {\n//                mp_raise_OSError(-err);\n//            }\n            break;\n        }\n\n        default:\n            mp_printf(&mp_plat_print, \"Warning: setsockopt() option not implemented\\n\");\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);\n\nSTATIC void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms) {\n    // Rather than waiting for the entire timeout specified, we wait sock->retries times\n    // for SOCKET_POLL_US each, checking for a MicroPython interrupt between timeouts.\n    // with SOCKET_POLL_MS == 100ms, sock->retries allows for timeouts up to 13 years.\n    // if timeout_ms == UINT64_MAX, wait forever.\n    sock->retries = (timeout_ms == UINT64_MAX) ? UINT_MAX : timeout_ms * 1000 / SOCKET_POLL_US;\n\n    struct timeval timeout = {\n        .tv_sec = 0,\n        .tv_usec = timeout_ms ? SOCKET_POLL_US : 0\n    };\n    setsockopt(sock->fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout));\n    setsockopt(sock->fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout));\n    fcntl(sock->fd, F_SETFL, timeout_ms ? 0 : O_NONBLOCK);\n}\n\nSTATIC mp_obj_t socket_settimeout(const mp_obj_t arg0, const mp_obj_t arg1) {\n    socket_obj_t *self = MP_OBJ_TO_PTR(arg0);\n    if (arg1 == mp_const_none) _socket_settimeout(self, UINT64_MAX);\n    else _socket_settimeout(self, mp_obj_get_float(arg1) * 1000L);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);\n\nSTATIC mp_obj_t socket_setblocking(const mp_obj_t arg0, const mp_obj_t arg1) {\n    socket_obj_t *self = MP_OBJ_TO_PTR(arg0);\n    if (mp_obj_is_true(arg1)) _socket_settimeout(self, UINT64_MAX);\n    else _socket_settimeout(self, 0);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);\n\n// XXX this can end up waiting a very long time if the content is dribbled in one character\n// at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not\n// good behaviour.\nSTATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size,\n    struct sockaddr *from, socklen_t *from_len, int *errcode) {\n    socket_obj_t *sock = MP_OBJ_TO_PTR(self_in);\n\n    // If the peer closed the connection then the lwIP socket API will only return \"0\" once\n    // from lwip_recvfrom_r and then block on subsequent calls.  To emulate POSIX behaviour,\n    // which continues to return \"0\" for each call on a closed socket, we set a flag when\n    // the peer closed the socket.\n    if (sock->peer_closed) {\n        return 0;\n    }\n\n    // XXX Would be nicer to use RTC to handle timeouts\n    for (int i = 0; i <= sock->retries; ++i) {\n        MP_THREAD_GIL_EXIT();\n        int r = recvfrom(sock->fd, buf, size, 0, from, from_len);\n        MP_THREAD_GIL_ENTER();\n        if (r == 0) {\n            sock->peer_closed = true;\n        }\n        if (r >= 0) {\n            return r;\n        }\n//        if (errno != EWOULDBLOCK) {\n//            *errcode = errno;\n//            return MP_STREAM_ERROR;\n//        }\n        check_for_exceptions();\n    }\n\n    *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;\n    return MP_STREAM_ERROR;\n}\n\nmp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in,\n        struct sockaddr *from, socklen_t *from_len) {\n    size_t len = mp_obj_get_int(len_in);\n    vstr_t vstr;\n    vstr_init_len(&vstr, len);\n\n    int errcode;\n    mp_uint_t ret = _socket_read_data(self_in, vstr.buf, len, from, from_len, &errcode);\n    if (ret == MP_STREAM_ERROR) {\n        exception_from_errno(errcode);\n    }\n\n    vstr.len = ret;\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\n\nSTATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {\n    return _socket_recvfrom(self_in, len_in, NULL, NULL);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);\n\nSTATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {\n    struct sockaddr from;\n    socklen_t fromlen = sizeof(from);\n\n    mp_obj_t tuple[2];\n    tuple[0] = _socket_recvfrom(self_in, len_in, &from, &fromlen);\n\n    uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&from)->sin_addr;\n    mp_uint_t port = ntohs(((struct sockaddr_in*)&from)->sin_port);\n    tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);\n\n    return mp_obj_new_tuple(2, tuple);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);\n\nSTATIC int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) {\n    int sentlen = 0;\n    for (int i = 0; i <= sock->retries && sentlen < datalen; i++) {\n        MP_THREAD_GIL_EXIT();\n        int r = send(sock->fd, data + sentlen, datalen - sentlen, 0);\n        MP_THREAD_GIL_ENTER();\n        if (r < 0 && errno != EWOULDBLOCK) exception_from_errno(errno);\n        if (r > 0) sentlen += r;\n        check_for_exceptions();\n    }\n    if (sentlen == 0) mp_raise_OSError(MP_ETIMEDOUT);\n    return sentlen;\n}\n\nSTATIC mp_obj_t socket_send(const mp_obj_t arg0, const mp_obj_t arg1) {\n    socket_obj_t *sock = MP_OBJ_TO_PTR(arg0);\n    mp_uint_t datalen;\n    const char *data = mp_obj_str_get_data(arg1, &datalen);\n    int r = _socket_send(sock, data, datalen);\n    return mp_obj_new_int(r);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);\n\nSTATIC mp_obj_t socket_sendall(const mp_obj_t arg0, const mp_obj_t arg1) {\n    // XXX behaviour when nonblocking (see extmod/modlwip.c)\n    // XXX also timeout behaviour.\n    socket_obj_t *sock = MP_OBJ_TO_PTR(arg0);\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(arg1, &bufinfo, MP_BUFFER_READ);\n    int r = _socket_send(sock, bufinfo.buf, bufinfo.len);\n    if (r < bufinfo.len) mp_raise_OSError(MP_ETIMEDOUT);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_sendall_obj, socket_sendall);\n\nSTATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {\n    socket_obj_t *self = MP_OBJ_TO_PTR(self_in);\n\n    // get the buffer to send\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);\n\n    // create the destination address\n    struct sockaddr_in to;\n    to.sin_len = sizeof(to);\n    to.sin_family = AF_INET;\n    to.sin_port = htons(netutils_parse_inet_addr(addr_in, (uint8_t*)&to.sin_addr, NETUTILS_BIG));\n\n    // send the data\n    for (int i=0; i<=self->retries; i++) {\n        MP_THREAD_GIL_EXIT();\n        int ret = sendto(self->fd, bufinfo.buf, bufinfo.len, 0, (struct sockaddr*)&to, sizeof(to));\n        MP_THREAD_GIL_ENTER();\n        if (ret > 0) return mp_obj_new_int_from_uint(ret);\n        if (ret == -1 && errno != EWOULDBLOCK) {\n            exception_from_errno(errno);\n        }\n        check_for_exceptions();\n    }\n    mp_raise_OSError(MP_ETIMEDOUT);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto);\n\nSTATIC mp_obj_t socket_fileno(const mp_obj_t arg0) {\n    socket_obj_t *self = MP_OBJ_TO_PTR(arg0);\n    return mp_obj_new_int(self->fd);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno);\n\nSTATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n    return args[0];\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile);\n\nSTATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {\n    return _socket_read_data(self_in, buf, size, NULL, NULL, errcode);\n}\n\nSTATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {\n    socket_obj_t *sock = self_in;\n    for (int i = 0; i <= sock->retries; i++) {\n        MP_THREAD_GIL_EXIT();\n        int r = send(sock->fd, buf, size, 0);\n        MP_THREAD_GIL_ENTER();\n        if (r > 0) return r;\n        if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; }\n        check_for_exceptions();\n    }\n    *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;\n    return MP_STREAM_ERROR;\n}\n\nSTATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    socket_obj_t * socket = self_in;\n    if (request == MP_STREAM_POLL) {\n\n        fd_set rfds; FD_ZERO(&rfds);\n        fd_set wfds; FD_ZERO(&wfds);\n        fd_set efds; FD_ZERO(&efds);\n        struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };\n        if (arg & MP_STREAM_POLL_RD) FD_SET(socket->fd, &rfds);\n        if (arg & MP_STREAM_POLL_WR) FD_SET(socket->fd, &wfds);\n        if (arg & MP_STREAM_POLL_HUP) FD_SET(socket->fd, &efds);\n\n        MP_THREAD_GIL_EXIT();\n        int r = select((socket->fd)+1, &rfds, &wfds, &efds, &timeout);\n        MP_THREAD_GIL_ENTER();\n        if (r < 0) {\n            *errcode = MP_EIO;\n            return MP_STREAM_ERROR;\n        }\n\n        mp_uint_t ret = 0;\n        if (FD_ISSET(socket->fd, &rfds)) ret |= MP_STREAM_POLL_RD;\n        if (FD_ISSET(socket->fd, &wfds)) ret |= MP_STREAM_POLL_WR;\n        if (FD_ISSET(socket->fd, &efds)) ret |= MP_STREAM_POLL_HUP;\n        return ret;\n    } else if (request == MP_STREAM_CLOSE) {\n        if (socket->fd >= 0) {\n            int ret = closesocket(socket->fd);\n            if (ret != 0) {\n                *errcode = errno;\n                return MP_STREAM_ERROR;\n            }\n            socket->fd = -1;\n        }\n        return 0;\n    }\n\n    *errcode = MP_EINVAL;\n    return MP_STREAM_ERROR;\n}\n\nSTATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },\n    { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },\n    { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },\n    { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },\n    { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) },\n    { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_sendall_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) },\n    { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) },\n    { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },\n    { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },\n    { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },\n    { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) },\n    { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&socket_fileno_obj) },\n\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);\n\nSTATIC const mp_stream_p_t socket_stream_p = {\n    .read = socket_stream_read,\n    .write = socket_stream_write,\n    .ioctl = socket_stream_ioctl\n};\n\nSTATIC const mp_obj_type_t socket_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_socket,\n    .protocol = &socket_stream_p,\n    .locals_dict = (mp_obj_t)&socket_locals_dict,\n};\n\nSTATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) {\n    socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t);\n    sock->base.type = &socket_type;\n    sock->domain = AF_INET;\n    sock->type = SOCK_STREAM;\n    sock->proto = 0;\n    sock->peer_closed = false;\n    if (n_args > 0) {\n        sock->domain = mp_obj_get_int(args[0]);\n        if (n_args > 1) {\n            sock->type = mp_obj_get_int(args[1]);\n            if (n_args > 2) {\n                sock->proto = mp_obj_get_int(args[2]);\n            }\n        }\n    }\n\n    sock->fd = socket(sock->domain, sock->type, sock->proto);\n    if (sock->fd < 0) {\n        exception_from_errno(errno);\n    }\n    _socket_settimeout(sock, UINT64_MAX);\n\n    return MP_OBJ_FROM_PTR(sock);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket);\n\n/******************************************************************************/\n// usocket module\n// function usocket.getaddrinfo(host, port)\nSTATIC mp_obj_t mod_usocket_getaddrinfo(uint n_args, const mp_obj_t *arg) {\n    // TODO support additional args beyond the first two\n    size_t hlen;\n    int ret;\n    const char *host = mp_obj_str_get_data(arg[0], &hlen);\n    mp_int_t port = mp_obj_get_int(arg[1]);\n    struct addrinfo hint, *res = NULL;\n    memset(&hint, 0, sizeof(hint));\n\n    MP_THREAD_GIL_EXIT();\n    ret = getaddrinfo(host, NULL, &hint, &res);\n    MP_THREAD_GIL_ENTER();\n    if (ret != 0) {\n        mp_printf(&mp_plat_print, \"getaddrinfo err: %d '%s'\\n\", ret, host);\n        nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, \"no available netif\"));\n    }\n\n    mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);\n    tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);\n    tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);\n    tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);\n    tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);\n\n    mp_obj_t tuple_addr[2] = {\n            tuple_addr[0] = netutils_format_ipv4_addr((uint8_t *)((res->ai_addr->sa_data) + 2), NETUTILS_BIG),\n            tuple_addr[1] = mp_obj_new_int(port),\n    };\n\n    tuple->items[4] = mp_obj_new_tuple(2, tuple_addr);\n    freeaddrinfo(res);\n\n    return mp_obj_new_list(1, (mp_obj_t*) &tuple);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_usocket_getaddrinfo_obj, 2, 6, mod_usocket_getaddrinfo);\n\nSTATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) },\n\n    { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&get_socket_obj) },\n    { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_usocket_getaddrinfo_obj) },\n\n    { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) },\n    { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(AF_INET6) },\n    { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SOCK_STREAM) },\n    { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SOCK_DGRAM) },\n    { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(SOCK_RAW) },\n    { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IPPROTO_TCP) },\n    { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(IPPROTO_UDP) },\n    { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(IPPROTO_IP) },\n    { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(SOL_SOCKET) },\n    { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SO_REUSEADDR) },\n    { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table);\n\nconst mp_obj_module_t mp_module_usocket = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_socket_globals,\n};\n\n#endif  // MICROPY_PY_USOCKET\n"
  },
  {
    "path": "port/modules/modutils.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 SummerGift (SummerGift@qq.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n \n#include \"py/mpconfig.h\"\n\nstatic const uint32_t crc32_table[] =\n{\n    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,\n    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,\n    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,\n    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\n    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,\n    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,\n    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,\n    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,\n    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,\n    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,\n    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,\n    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,\n    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,\n    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,\n    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,\n    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,\n    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\n    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,\n    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,\n    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,\n    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,\n    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,\n    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,\n    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,\n    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,\n    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,\n    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,\n    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,\n    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d\n};\n\n/**\n * Calculate the CRC32 value of a memory buffer.\n *\n * @param crc accumulated CRC32 value, must be 0 on first call\n * @param buf buffer to calculate CRC32 value for\n * @param len bytes in buffer\n *\n * @return calculated CRC32 value\n */\nuint32_t mp_calc_crc32(uint32_t crc, const void *buf, size_t len)\n{\n    const uint8_t *p;\n\n    p = (const uint8_t *)buf;\n    crc = crc ^ ~0U;\n\n    while (len--) {\n        crc = crc32_table[(crc ^ *p++) & 0xFF] ^ (crc >> 8);\n    }\n\n    return crc ^ ~0U;\n}\n\nvoid mp_hex_to_str(char *pbDest, char *pbSrc, int nLen)\n{\n    char ddl,ddh;\n    int i;\n\n    for (i=0; i<nLen; i++)\n    {\n        ddh = 48 + pbSrc[i] / 16;\n        ddl = 48 + pbSrc[i] % 16;\n        if (ddh > 57) ddh = ddh + 7;\n        if (ddl > 57) ddl = ddl + 7;\n        pbDest[i*2] = ddh;\n        pbDest[i*2+1] = ddl;\n    }\n\n    pbDest[nLen*2] = '\\0';\n}\n"
  },
  {
    "path": "port/modules/modutime.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_PY_UTIME\n\n#include <rtthread.h>\n#include <sys/time.h>\n\n#include \"py/runtime.h\"\n#include \"py/smallint.h\"\n#include \"py/mphal.h\"\n#include \"extmod/utime_mphal.h\"\n#include \"lib/timeutils/timeutils.h\"\n#include <math.h>\n\nSTATIC mp_obj_t mod_time_time(void) {\n#if MICROPY_PY_BUILTINS_FLOAT\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n    mp_float_t val = tv.tv_sec + (mp_float_t)tv.tv_usec / 1000000;\n    return mp_obj_new_float(val);\n#else\n    return mp_obj_new_int((mp_int_t)time(NULL));\n#endif\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time);\n\nSTATIC mp_obj_t mod_time_localtime(size_t n_args, const mp_obj_t *args) {\n    time_t t;\n    if (n_args == 0) {\n        t = time(NULL);\n    } else {\n        #if MICROPY_PY_BUILTINS_FLOAT\n        mp_float_t val = mp_obj_get_float(args[0]);\n        t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val);\n        #else\n        t = mp_obj_get_int(args[0]);\n        #endif\n    }\n    struct tm *tm = localtime(&t);\n\n    mp_obj_t ret = mp_obj_new_tuple(9, NULL);\n\n    mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(ret);\n    tuple->items[0] = MP_OBJ_NEW_SMALL_INT(tm->tm_year + 1900);\n    tuple->items[1] = MP_OBJ_NEW_SMALL_INT(tm->tm_mon + 1);\n    tuple->items[2] = MP_OBJ_NEW_SMALL_INT(tm->tm_mday);\n    tuple->items[3] = MP_OBJ_NEW_SMALL_INT(tm->tm_hour);\n    tuple->items[4] = MP_OBJ_NEW_SMALL_INT(tm->tm_min);\n    tuple->items[5] = MP_OBJ_NEW_SMALL_INT(tm->tm_sec);\n    int wday = tm->tm_wday - 1;\n    if (wday < 0) {\n        wday = 6;\n    }\n    tuple->items[6] = MP_OBJ_NEW_SMALL_INT(wday);\n    tuple->items[7] = MP_OBJ_NEW_SMALL_INT(tm->tm_yday + 1);\n    tuple->items[8] = MP_OBJ_NEW_SMALL_INT(tm->tm_isdst);\n\n    return ret;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_localtime_obj, 0, 1, mod_time_localtime);\n\n/// \\function mktime()\n/// This is inverse function of localtime. It's argument is a full 8-tuple\n/// which expresses a time as per localtime. It returns an integer which is\n/// the number of seconds since Jan 1, 2000.\nSTATIC mp_obj_t time_mktime(mp_obj_t tuple) {\n\n    size_t len;\n    mp_obj_t *elem;\n\n    mp_obj_get_array(tuple, &len, &elem);\n\n    // localtime generates a tuple of len 8. CPython uses 9, so we accept both.\n    if (len < 8 || len > 9) {\n        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, \"mktime needs a tuple of length 8 or 9 (%d given)\", len));\n    }\n\n    return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),\n            mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),\n            mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));\n}\nMP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);\n\nSTATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },\n    { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },\n    { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mod_time_time_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },\n    { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&mod_time_localtime_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table);\n\nconst mp_obj_module_t mp_module_time = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_time_globals,\n};\n\n#endif // MICROPY_PY_UTIME\n"
  },
  {
    "path": "port/modules/user/moduserfunc.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 SummerGift <summergift2019@gmail.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/runtime.h\"\n\nSTATIC mp_obj_t add(\n        mp_obj_t arg_1_obj,\n        mp_obj_t arg_2_obj) {\n    mp_int_t arg_1 = mp_obj_get_int(arg_1_obj);\n    mp_int_t arg_2 = mp_obj_get_int(arg_2_obj);\n    mp_int_t ret_val;\n\n    /* Your code start! */\n\n    ret_val = arg_1 + arg_2;\n\n    /* Your code end! */\n\n    return mp_obj_new_int(ret_val);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(add_obj, add);\n\nSTATIC const mp_rom_map_elem_t mp_module_userfunc_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_userfunc) },\n    { MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&add_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_userfunc_globals, mp_module_userfunc_globals_table);\n\nconst mp_obj_module_t mp_module_userfunc = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t*)&mp_module_userfunc_globals,\n};\n\n"
  },
  {
    "path": "port/mpconfigport.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <rthw.h>\n#include <rtthread.h>\n#include <stdint.h>\n#include <stdio.h>\n\n// options to control how MicroPython is built\n\n// You can disable the built-in MicroPython compiler by setting the following\n// config option to 0.  If you do this then you won't get a REPL prompt, but you\n// will still be able to execute pre-compiled scripts, compiled with mpy-cross.\n#define MICROPY_ENABLE_COMPILER     (1)\n\n#if defined(PKG_MICROPYTHON_HEAP_SIZE)\n#define MICROPY_HEAP_SIZE PKG_MICROPYTHON_HEAP_SIZE\n#else\n#define MICROPY_HEAP_SIZE (8 * 1024)\n#endif\n\n#define MP_ENDIANNESS_LITTLE        (1)\n#define MICROPY_STACK_CHECK         (1)\n#define MICROPY_PY_MICROPYTHON_STACK_USE (1)\n#define MICROPY_QSTR_BYTES_IN_HASH  (1)\n#define MICROPY_QSTR_EXTRA_POOL     mp_qstr_frozen_const_pool\n#define MICROPY_ALLOC_PATH_MAX      (256)\n#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16)\n#define MICROPY_EMIT_X64            (0)\n#define MICROPY_EMIT_THUMB          (0)\n#define MICROPY_EMIT_INLINE_THUMB   (0)\n#define MICROPY_COMP_MODULE_CONST   (0)\n#define MICROPY_COMP_CONST          (0)\n#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)\n#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)\n#define MICROPY_MEM_STATS           (0)\n#define MICROPY_DEBUG_PRINTERS      (0)\n#define MICROPY_ENABLE_GC           (1)\n#define MICROPY_ENABLE_FINALISER    (1)\n#define MICROPY_GC_ALLOC_THRESHOLD  (0)\n#define MICROPY_REPL_EVENT_DRIVEN   (0)\n#define MICROPY_REPL_AUTO_INDENT    (1)\n#define MICROPY_KBD_EXCEPTION       (1)\n#define MICROPY_HELPER_REPL         (1)\n#define MICROPY_HELPER_LEXER_UNIX   (0)\n#define MICROPY_ENABLE_SOURCE_LINE  (1)\n#define MICROPY_ENABLE_DOC_STRING   (0)\n#define MICROPY_ENABLE_SCHEDULER    (1)\n#define MICROPY_ERROR_REPORTING     (MICROPY_ERROR_REPORTING_TERSE)\n#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)\n#define MICROPY_PY_ASYNC_AWAIT      (0)\n// control over Python builtins\n#define MICROPY_PY_FUNCTION_ATTRS   (1)\n#define MICROPY_PY_BUILTINS_STR_UNICODE (1)\n#define MICROPY_PY_BUILTINS_STR_CENTER (1)\n#define MICROPY_PY_BUILTINS_STR_PARTITION (1)\n#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)\n#define MICROPY_PY_BUILTINS_BYTEARRAY (1)\n#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)\n#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)\n#define MICROPY_PY_ALL_SPECIAL_METHODS (1)\n#define MICROPY_PY_BUILTINS_INPUT (1)\n#define MICROPY_PY_BUILTINS_POW3 (1)\n#define MICROPY_PY_BUILTINS_ENUMERATE (1)\n#define MICROPY_PY_BUILTINS_FILTER  (1)\n#define MICROPY_PY_BUILTINS_FROZENSET (1)\n#define MICROPY_PY_BUILTINS_REVERSED (1)\n#define MICROPY_PY_BUILTINS_SET     (1)\n#define MICROPY_PY_BUILTINS_HELP    (1)\n#define MICROPY_PY_BUILTINS_HELP_TEXT rtthread_help_text\n#define MICROPY_PY_BUILTINS_HELP_MODULES (1)\n#define MICROPY_PY_BUILTINS_SLICE   (1)\n#define MICROPY_PY_BUILTINS_PROPERTY (1)\n#define MICROPY_PY_BUILTINS_MIN_MAX (1)\n#define MICROPY_PY___FILE__         (1)\n#define MICROPY_PY_GC               (1)\n#define MICROPY_PY_ARRAY            (1)\n#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)\n#define MICROPY_PY_ATTRTUPLE        (1)\n#define MICROPY_PY_COLLECTIONS      (1)\n#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)\n#define MICROPY_PY_MATH             (1)\n#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)\n#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)\n#define MICROPY_STREAMS_NON_BLOCK   (1)\n#define MICROPY_MODULE_WEAK_LINKS   (1)\n#define MICROPY_CAN_OVERRIDE_BUILTINS (1)\n#define MICROPY_USE_INTERNAL_ERRNO  (1)\n#define MICROPY_USE_INTERNAL_PRINTF (0)\n#define MICROPY_PY_STRUCT           (1)\n#define MICROPY_PY_SYS              (1)\n#define MICROPY_MODULE_FROZEN_MPY   (1)\n#define MICROPY_MODULE_FROZEN_STR   (0)\n#define MICROPY_CPYTHON_COMPAT      (1)\n#define MICROPY_LONGINT_IMPL        (MICROPY_LONGINT_IMPL_MPZ)\n#ifdef MICROPYTHON_USING_FLOAT_IMPL_FLOAT\n#define MICROPY_FLOAT_IMPL          (MICROPY_FLOAT_IMPL_FLOAT)\n#else\n#define MICROPY_FLOAT_IMPL          (MICROPY_FLOAT_IMPL_DOUBLE)\n#endif\n#define MICROPY_READER_VFS          (0)\n#define MICROPY_PY_PIN              (1)\n#define MICROPY_PY_OS_DUPTERM       (1)\n#define MICROPY_VFS                 (0)\n#define MICROPY_VFS_FAT             (0)\n#define MICROPY_PY_UTIME            (1)\n#define MICROPY_PY_MACHINE          (1)\n#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new\n#define MICROPY_PY_UTIME_MP_HAL     (1)\n#define MICROPY_PY_UTIMEQ           (1)\n#define MICROPY_PY_RTTHREAD         (1)\n\n/*****************************************************************************/\n/* Hardware Module                                                           */\n\n#ifdef MICROPYTHON_USING_MACHINE_I2C\n#define MICROPY_PY_MACHINE_I2C      (1)\n#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new\n#endif\n\n#ifdef MICROPYTHON_USING_MACHINE_SPI\n#define MICROPY_PY_MACHINE_SPI      (1)\n#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hard_spi_make_new\n#endif\n\n#ifdef MICROPYTHON_USING_MACHINE_UART\n#define MICROPY_PY_MACHINE_UART      (1)\n#endif\n\n#ifdef MICROPYTHON_USING_MACHINE_ADC\n#define MICROPY_PY_MACHINE_ADC       (1)\n#endif\n\n#ifdef MICROPYTHON_USING_MACHINE_PWM\n#define MICROPY_PY_MACHINE_PWM       (1)\n#endif\n\n#ifdef MICROPYTHON_USING_MACHINE_LCD\n#define MICROPY_PY_MACHINE_LCD       (1)\n#endif\n\n#ifdef MICROPYTHON_USING_MACHINE_RTC\n#define MICROPY_PY_MACHINE_RTC       (1)\n#endif\n\n#ifdef MICROPYTHON_USING_MACHINE_WDT\n#define MICROPY_PY_MACHINE_WDT       (1)\n#endif\n\n#ifdef MICROPYTHON_USING_MACHINE_TIMER\n#define MICROPY_PY_MACHINE_TIMER     (1)\n#endif\n\n/*****************************************************************************/\n/* System Module                                                             */\n\n#ifdef MICROPYTHON_USING_UOS\n#define MICROPY_PY_IO               (1)\n#define MICROPY_PY_IO_FILEIO        (1)\n#define MICROPY_PY_MODUOS           (1)\n#define MICROPY_PY_MODUOS_FILE      (1)\n#define MICROPY_PY_SYS_STDFILES     (1)\n#define MICROPY_READER_POSIX        (1)\n#define MICROPY_PY_BUILTINS_COMPILE (1)\n#define MICROPY_PY_BUILTINS_EXECFILE (1)\n#define MICROPY_PERSISTENT_CODE_LOAD (1)\n#else\n#define MICROPY_PY_IO               (0)\n#define MICROPY_PY_MODUOS           (0)\n#endif /* MICROPYTHON_USING_UOS */\n\n#ifdef MICROPYTHON_USING_THREAD\n#define MICROPY_PY_THREAD           (1)\n#define MICROPY_SCHEDULER_DEPTH     (8)\n#endif /* MICROPYTHON_USING_THREAD */\n\n#ifdef MICROPYTHON_USING_USELECT\n#define MICROPY_PY_USELECT          (1)\n#endif\n\n#ifdef MICROPYTHON_USING_UCTYPES\n#define MICROPY_PY_UCTYPES          (1)\n#endif\n\n#ifdef MICROPYTHON_USING_UERRNO\n#define MICROPY_PY_UERRNO           (1)\n#endif\n\n#ifdef MICROPYTHON_USING_FFI\n#define MICROPY_PY_FFI              (1)\n#endif\n\n/*****************************************************************************/\n/* Tools Module                                                              */\n\n#ifdef MICROPYTHON_USING_CMATH\n#define MICROPY_PY_CMATH            (1)\n#endif\n\n#ifdef MICROPYTHON_USING_UBINASCII\n#define MICROPY_PY_UBINASCII        (1)\n#endif\n\n#ifdef MICROPYTHON_USING_UHASHLIB\n#define MICROPY_PY_UHASHLIB         (1)\n#endif\n\n#ifdef MICROPYTHON_USING_UHEAPQ\n#define MICROPY_PY_UHEAPQ           (1)\n#endif\n\n#ifdef MICROPYTHON_USING_UJSON\n#define MICROPY_PY_UJSON            (1)\n#endif\n\n#ifdef MICROPYTHON_USING_URE\n#define MICROPY_PY_URE              (1)\n#endif\n\n#ifdef MICROPYTHON_USING_UZLIB\n#define MICROPY_PY_UZLIB            (1)\n#endif\n\n#ifdef MICROPYTHON_USING_URANDOM\n#define MICROPY_PY_URANDOM             (1)\n#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)\n#endif\n\n/*****************************************************************************/\n/* Network Module                                                            */\n\n#ifdef MICROPYTHON_USING_USOCKET\n#define MICROPY_PY_USOCKET          (1)\n#endif\n\n#ifdef MICROPYTHON_USING_USSL\n#define MICROPY_PY_USSL             (1)\n#define MICROPY_SSL_MBEDTLS         (1)\n#endif\n\n#ifdef MICROPYTHON_USING_NETWORK\n#define MICROPY_PY_NETWORK          (1)\n#endif\n\n#ifdef MICROPYTHON_USING_WLAN\n#define MICROPY_PY_WLAN             (1)\n#endif\n\n#if MICROPY_PY_THREAD\n#define MICROPY_EVENT_POLL_HOOK \\\n    do { \\\n        extern void mp_handle_pending(bool); \\\n        mp_handle_pending(true); \\\n        MP_THREAD_GIL_EXIT(); \\\n        MP_THREAD_GIL_ENTER(); \\\n    } while (0);\n#else\n#define MICROPY_EVENT_POLL_HOOK \\\n    do { \\\n        extern void mp_handle_pending(bool); \\\n        mp_handle_pending(true); \\\n        rt_thread_delay(1); \\\n    } while (0);\n#endif\n\n/*****************************************************************************/\n/* Modules define in your project\n   You must provide 'moddefs.user.extmods.h'\n   and 'qstrdefs.user.extmods.h'\n*/\n\n#ifdef MICROPYTHON_USING_USEREXTMODS\n#define MICROPY_USER_EXTMODS     (1)\n#include <moddefs.user.extmods.h>\n#else\n#define MICROPY_USER_EXTMODS     (0)\n#endif\n#ifndef MICROPY_USER_MODULES\n#define MICROPY_USER_MODULES\n#endif\n\n#if defined(__CC_ARM)\n#include <sys/types.h>\n#define MICROPY_NO_ALLOCA           1\n#if (RTTHREAD_VERSION < RT_VERSION_CHECK(5, 0, 0))\n#define MP_WEAK                     RT_WEAK\n#else\n#define MP_WEAK                     rt_weak\n#endif\n#define MP_NOINLINE\n#define MP_ALWAYSINLINE\n#define MP_LIKELY(x)               x\n#define MP_UNLIKELY(x)             x\n#undef __arm__\n#undef __thumb__\n#undef __thumb2__\n#elif defined(__ICCARM__)\n#include <libc/libc_errno.h>\n#include <sys/types.h>\n#define MICROPY_NO_ALLOCA           1\n#define NORETURN                    __noreturn\n#if (RTTHREAD_VERSION < RT_VERSION_CHECK(5, 0, 0))\n#define MP_WEAK                     RT_WEAK\n#else\n#define MP_WEAK                     rt_weak\n#endif\n#define MP_NOINLINE\n#define MP_ALWAYSINLINE\n#define MP_LIKELY(x)               x\n#define MP_UNLIKELY(x)             x\n#elif defined(__GNUC__)\n// We need to provide a declaration/definition of alloca()\n#include <alloca.h>\n#else\n    #error \"not supported compiler\"\n#endif /* defined(__CC_ARM) */\n\n// type definitions for the specific machine\n\n#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))\n\n// This port is intended to be 32-bit, but unfortunately, int32_t for\n// different targets may be defined in different ways - either as int\n// or as long. This requires different printf formatting specifiers\n// to print such value. So, we avoid int32_t and use int directly.\n#define UINT_FMT \"%u\"\n#define INT_FMT \"%d\"\ntypedef intptr_t mp_int_t; // must be pointer size\ntypedef uintptr_t mp_uint_t; // must be pointer size\n\ntypedef long mp_off_t;\n\n#define MP_PLAT_PRINT_STRN(str, len)   mp_hal_stdout_tx_strn_stream(str, len)\n\n#define MICROPY_PY_SYS_PLATFORM        \"rt-thread\"\n#define MICROPY_HW_BOARD_NAME          \"Universal python platform\"\n#define MICROPY_HW_MCU_NAME            \"RT-Thread\"\n#define MICROPY_PY_PATH_FIRST          \"/libs/mpy/\"\n#define MICROPY_PY_PATH_SECOND         \"/scripts/\"\n#define MICROPY_MAIN_PY_PATH           \"/main.py\"\n\n#define MICROPY_BEGIN_ATOMIC_SECTION()     rt_hw_interrupt_disable()\n#define MICROPY_END_ATOMIC_SECTION(state)  rt_hw_interrupt_enable(state)\n\n#ifdef __linux__\n#define MICROPY_MIN_USE_STDOUT (1)\n#endif\n\n#define MP_STATE_PORT                  MP_STATE_VM\n\n#define MICROPY_PORT_ROOT_POINTERS     const char *readline_hist[8];\n\nextern const struct _mp_obj_module_t pyb_module;\nextern const struct _mp_obj_module_t mp_module_rtthread;\nextern const struct _mp_obj_module_t mp_module_time;\nextern const struct _mp_obj_module_t mp_module_machine;\nextern const struct _mp_obj_module_t mp_module_uos;\nextern const struct _mp_obj_module_t mp_module_uselect;\nextern const struct _mp_obj_module_t mp_module_usocket;\nextern const struct _mp_obj_module_t mp_module_io;\nextern const struct _mp_obj_fun_builtin_fixed_t machine_soft_reset_obj;\nextern const struct _mp_obj_module_t mp_module_ffi;\nextern const struct _mp_obj_module_t mp_module_network;\nextern const struct _mp_obj_module_t mp_module_userfunc;\n\n#if MICROPY_PY_RTTHREAD\n#define RTTHREAD_PORT_BUILTIN_MODULES { MP_ROM_QSTR(MP_QSTR_rtthread), MP_ROM_PTR(&mp_module_rtthread) },\n#else\n#define RTTHREAD_PORT_BUILTIN_MODULES\n#endif /* MICROPY_PY_RTTHREAD */\n\n#if MICROPY_PY_MODUOS\n#define MODUOS_PORT_BUILTINS                     { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },\n#define MODUOS_PORT_BUILTIN_MODULES              { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) },\n#define MODUOS_PORT_BUILTIN_MODULE_WEAK_LINKS    { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&mp_module_uos) },\n#define mp_import_stat(x)                        mp_posix_import_stat(x)\n#else\n#define MODUOS_PORT_BUILTINS\n#define MODUOS_PORT_BUILTIN_MODULES\n#define MODUOS_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_MODUOS */\n\n#if MICROPY_PY_USOCKET\n#define SOCKET_PORT_BUILTIN_MODULES              { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) },\n#define SOCKET_PORT_BUILTIN_MODULE_WEAK_LINKS    { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) },\n#else\n#define SOCKET_PORT_BUILTIN_MODULES\n#define SOCKET_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_USOCKET */\n\n#ifdef MICROPYTHON_USING_UBINASCII\n#define MODUBINASCII_PORT_BUILTIN_MODULE_WEAK_LINKS        { MP_ROM_QSTR(MP_QSTR_binascii), MP_ROM_PTR(&mp_module_ubinascii) },\n#else\n#define MODUBINASCII_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_UBINASCII */\n\n#ifdef MICROPY_PY_COLLECTIONS\n#define MODUCOLLECTIONS_PORT_BUILTIN_MODULE_WEAK_LINKS     { MP_ROM_QSTR(MP_QSTR_collections), MP_ROM_PTR(&mp_module_collections ) },\n#else\n#define MODUCOLLECTIONS_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_COLLECTIONS */\n\n#ifdef MICROPYTHON_USING_UERRNO\n#define MODUERRNO_PORT_BUILTIN_MODULE_WEAK_LINKS           { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno ) },\n#else\n#define MODUERRNO_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_UERRNO */\n\n#ifdef MICROPYTHON_USING_UHASHLIB\n#define MODUHASHLIB_PORT_BUILTIN_MODULE_WEAK_LINKS         { MP_ROM_QSTR(MP_QSTR_hashlib), MP_ROM_PTR(&mp_module_uhashlib ) },\n#else\n#define MODUHASHLIB_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_UHASHLIB */\n\n#ifdef MICROPYTHON_USING_UHEAPQ\n#define MODUHEAPQ_PORT_BUILTIN_MODULE_WEAK_LINKS           { MP_ROM_QSTR(MP_QSTR_heapq), MP_ROM_PTR(&mp_module_uheapq ) },\n#else\n#define MODUHEAPQ_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_UHEAPQ */\n\n#if MICROPY_PY_IO\n#define MODUIO_PORT_BUILTIN_MODULE_WEAK_LINKS              { MP_ROM_QSTR(MP_QSTR_io), MP_ROM_PTR(&mp_module_io ) },\n#else\n#define MODUIO_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_UIO */\n\n#ifdef MICROPYTHON_USING_UJSON\n#define MODUJSON_PORT_BUILTIN_MODULE_WEAK_LINKS            { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson ) },\n#else\n#define MODUJSON_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_UJSON */\n\n#ifdef MICROPYTHON_USING_URANDOM\n#define MODURANDOM_PORT_BUILTIN_MODULE_WEAK_LINKS          { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mp_module_urandom ) },\n#else\n#define MODURANDOM_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_URANDOM */\n\n#ifdef MICROPYTHON_USING_URE\n#define MODURE_PORT_BUILTIN_MODULE_WEAK_LINKS              { MP_ROM_QSTR(MP_QSTR_re), MP_ROM_PTR(&mp_module_ure ) },\n#else\n#define MODURE_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_URE */\n\n#ifdef MICROPYTHON_USING_USELECT\n#define MODUSELECT_PORT_BUILTIN_MODULE_WEAK_LINKS          { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect ) },\n#else\n#define MODUSELECT_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_USELECT */\n\n#if MICROPY_PY_USSL\n#define MODUSSL_PORT_BUILTIN_MODULE_WEAK_LINKS             { MP_ROM_QSTR(MP_QSTR_ssl), MP_ROM_PTR(&mp_module_ussl ) },\n#else\n#define MODUSSL_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_USSL */\n\n#if MICROPY_PY_STRUCT\n#define MODUSTRUCT_PORT_BUILTIN_MODULE_WEAK_LINKS          { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct ) },\n#else\n#define MODUSTRUCT_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_USTRUCT */\n\n#ifdef MICROPY_PY_UTIME\n#define MODUTIME_PORT_BUILTIN_MODULES                      { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_time) },\n#define MODUTIME_PORT_BUILTIN_MODULE_WEAK_LINKS            { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_time ) },\n#else\n#define SOCKET_PORT_BUILTIN_MODULES    \n#define MODUTIME_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_UTIME */\n\n#ifdef MICROPYTHON_USING_UZLIB\n#define MODUZLIB_PORT_BUILTIN_MODULE_WEAK_LINKS            { MP_ROM_QSTR(MP_QSTR_zlib), MP_ROM_PTR(&mp_module_uzlib ) },\n#else\n#define MODUZLIB_PORT_BUILTIN_MODULE_WEAK_LINKS\n#endif /* MICROPY_PY_UZLIB */\n\n#if MICROPY_PY_FFI\n#define MODFFI_PORT_BUILTIN_MODULES                        { MP_ROM_QSTR(MP_QSTR_ffi), MP_ROM_PTR(&mp_module_ffi) },\n#else\n#define MODFFI_PORT_BUILTIN_MODULES\n#endif\n\n#if MICROPY_PY_NETWORK\n#define MODNETWORK_PORT_BUILTIN_MODULES                    { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) },\n#else\n#define MODNETWORK_PORT_BUILTIN_MODULES\n#endif\n\n#define USERFUNC_PORT_BUILTIN_MODULES { MP_ROM_QSTR(MP_QSTR_userfunc), MP_ROM_PTR(&mp_module_userfunc) },\n\n// extra built in names to add to the global namespace\n#define MICROPY_PORT_BUILTINS \\\n    { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&machine_soft_reset_obj) }, \\\n    { MP_ROM_QSTR(MP_QSTR_quit), MP_ROM_PTR(&machine_soft_reset_obj) }, \\\n    MODUOS_PORT_BUILTINS \\\n\n#define MICROPY_PORT_BUILTIN_MODULES \\\n    { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \\\n    { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \\\n    RTTHREAD_PORT_BUILTIN_MODULES \\\n    MODUOS_PORT_BUILTIN_MODULES \\\n    SOCKET_PORT_BUILTIN_MODULES \\\n    MODUTIME_PORT_BUILTIN_MODULES \\\n    MODFFI_PORT_BUILTIN_MODULES \\\n    MODNETWORK_PORT_BUILTIN_MODULES \\\n    USERFUNC_PORT_BUILTIN_MODULES \\\n    MICROPY_USER_MODULES \\\n\n#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUTIME_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUOS_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    SOCKET_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUBINASCII_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUCOLLECTIONS_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUERRNO_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUHASHLIB_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUHEAPQ_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUIO_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUJSON_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODURANDOM_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODURE_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUSELECT_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUSSL_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUSTRUCT_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUTIME_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUZLIB_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n    MODUSTRUCT_PORT_BUILTIN_MODULE_WEAK_LINKS \\\n\n#define MP_RTT_NOT_IMPL_PRINT mp_printf(&mp_plat_print, \"Not implement on %s:%ld, Please add for your board!\\n\", __FILE__, __LINE__)\n\n"
  },
  {
    "path": "port/mpgetcharport.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <rtthread.h>\n#include <rtdevice.h>\n#include <rthw.h>\n#include \"py/runtime.h\"\n#include \"lib/utils/interrupt_char.h\"\n#include \"mpgetcharport.h\"\n\n#define UART_FIFO_SIZE 256\n\nstatic struct rt_ringbuffer *rx_fifo = NULL;\nstatic rt_err_t (*odev_rx_ind)(rt_device_t dev, rt_size_t size) = NULL;\n\nstatic rt_err_t getchar_rx_ind(rt_device_t dev, rt_size_t size) {\n    uint8_t ch;\n    rt_size_t i;\n    rt_base_t int_lvl;\n\n    for (i = 0; i < size; i++) {\n        /* read a char */\n        if (rt_device_read(dev, 0, &ch, 1)) {\n            if (ch == mp_interrupt_char) {\n                mp_keyboard_interrupt();\n            } else {\n                int_lvl = rt_hw_interrupt_disable();\n                rt_ringbuffer_put_force(rx_fifo, &ch, 1);\n                rt_hw_interrupt_enable(int_lvl);\n            }\n        }\n    }\n    return RT_EOK;\n}\n\nvoid mp_getchar_init(void) {\n    rt_base_t int_lvl;\n    rt_device_t console;\n\n    /* create RX FIFO */\n    rx_fifo = rt_ringbuffer_create(UART_FIFO_SIZE);\n    /* created must success */\n    RT_ASSERT(rx_fifo);\n\n    int_lvl = rt_hw_interrupt_disable();\n    console = rt_console_get_device();\n    if (console) {\n        /* backup RX indicate */\n        odev_rx_ind = console->rx_indicate;\n        rt_device_set_rx_indicate(console, getchar_rx_ind);\n    }\n    rt_hw_interrupt_enable(int_lvl);\n\n}\n\nvoid mp_getchar_deinit(void) {\n    rt_base_t int_lvl;\n    rt_device_t console;\n\n    rt_ringbuffer_destroy(rx_fifo);\n\n    int_lvl = rt_hw_interrupt_disable();\n    console = rt_console_get_device();\n    if (console && odev_rx_ind) {\n        /* restore RX indicate */\n        rt_device_set_rx_indicate(console, odev_rx_ind);\n    }\n    rt_hw_interrupt_enable(int_lvl);\n}\n\nint mp_getchar(void) {\n    uint8_t ch;\n    rt_base_t int_lvl;\n\n    int_lvl = rt_hw_interrupt_disable();\n    if (!rt_ringbuffer_getchar(rx_fifo, &ch)) {\n        ch = 0xFF;\n    }\n    rt_hw_interrupt_enable(int_lvl);\n\n    return ch;\n\n}\n"
  },
  {
    "path": "port/mpgetcharport.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef _MPGETCHARPORT_H_\n#define _MPGETCHARPORT_H_\n\nvoid mp_getchar_init(void);\nvoid mp_getchar_deinit(void);\nint mp_getchar(void);\n\n#endif /* _MPGETCHARPORT_H_ */\n"
  },
  {
    "path": "port/mphalport.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include <rtthread.h>\n#include <py/mpconfig.h>\n#include <py/runtime.h>\n#include \"mphalport.h\"\n#include \"mpgetcharport.h\"\n#include \"mpputsnport.h\"\n\nconst char rtthread_help_text[] =\n\"Welcome to MicroPython on RT-Thread!\\n\"\n\"\\n\"\n\"Control commands:\\n\"\n\"  CTRL-A        -- on a blank line, enter raw REPL mode\\n\"\n\"  CTRL-B        -- on a blank line, enter normal REPL mode\\n\"\n\"  CTRL-C        -- interrupt a running program\\n\"\n\"  CTRL-D        -- on a blank line, do a soft reset of the board\\n\"\n\"  CTRL-E        -- on a blank line, enter paste mode\\n\"\n\"\\n\"\n\"For further help on a specific object, type help(obj)\\n\"\n;\n\nint mp_hal_stdin_rx_chr(void) {\n    char ch;\n    while (1) {\n        ch = mp_getchar();\n        if (ch != (char)0xFF) {\n            break;\n        }\n        MICROPY_EVENT_POLL_HOOK;\n        rt_thread_delay(1);\n    }\n    return ch;\n}\n\n// Send string of given length\nvoid mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {\n    mp_putsn(str, len);\n#ifdef PKG_USING_OPENMV_CP\n    extern void serial_dbg_send_strn(const char *str, int len);\n    serial_dbg_send_strn(str, len);\n#endif\n}\n\nvoid mp_hal_stdout_tx_strn_stream(const char *str, size_t len) {\n    mp_putsn_stream(str, len);\n#ifdef PKG_USING_OPENMV_CP\n    extern void serial_dbg_send_strn_cooked(const char *str, int len);\n    serial_dbg_send_strn_cooked(str, len);\n#endif\n}\n\nmp_uint_t mp_hal_ticks_us(void) {\n    return rt_tick_get() * 1000000UL / RT_TICK_PER_SECOND;\n}\n\nmp_uint_t mp_hal_ticks_ms(void) {\n    return rt_tick_get() * 1000 / RT_TICK_PER_SECOND;\n}\n\nmp_uint_t mp_hal_ticks_cpu(void) {\n    return rt_tick_get();\n}\n\nvoid mp_hal_delay_us(mp_uint_t us) {\n    rt_tick_t t0 = rt_tick_get(), t1, dt;\n    uint64_t dtick = us * RT_TICK_PER_SECOND / 1000000L;\n    while (1) {\n        t1 = rt_tick_get();\n        dt = t1 - t0;\n        if (dt >= dtick) {\n            break;\n        }\n        mp_handle_pending(true);\n    }\n}\n\nvoid mp_hal_delay_ms(mp_uint_t ms) {\n    rt_tick_t t0 = rt_tick_get(), t1, dt;\n    uint64_t dtick = ms * RT_TICK_PER_SECOND / 1000L;\n    while (1) {\n        t1 = rt_tick_get();\n        dt = t1 - t0;\n        if (dt >= dtick) {\n            break;\n        }\n        MICROPY_EVENT_POLL_HOOK;\n        rt_thread_delay(1);\n    }\n}\n"
  },
  {
    "path": "port/mphalport.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <rtthread.h>\n#include <rtdevice.h>\n\n#define MP_HAL_PIN_FMT                 \"%s\"\n\nextern void mp_hal_set_interrupt_char (int c);\nextern void mp_pin_od_write(void *machine_pin, int stat);\nextern void mp_hal_pin_open_set(void *machine_pin, int mode);\nextern char* mp_hal_pin_get_name(void *machine_pin);\nextern void mp_hal_stdout_tx_strn_stream(const char *str, size_t len);\n\n#define mp_hal_quiet_timing_enter()         MICROPY_BEGIN_ATOMIC_SECTION()\n#define mp_hal_quiet_timing_exit(irq_state) MICROPY_END_ATOMIC_SECTION(irq_state)\n\n// needed for machine.I2C\n#define mp_hal_delay_us_fast(us) mp_hal_delay_us(us)\n#define mp_hal_pin_od_low(pin)   mp_pin_od_write(pin, PIN_LOW)\n#define mp_hal_pin_od_high(pin)  mp_pin_od_write(pin, PIN_HIGH)\n#define mp_hal_pin_open_drain(p) mp_hal_pin_open_set(p, PIN_MODE_OUTPUT_OD)\n\n// needed for soft machine.SPI\n#define mp_hal_pin_output(p)     mp_hal_pin_open_set(p, PIN_MODE_OUTPUT)\n#define mp_hal_pin_input(p)      mp_hal_pin_open_set(p, PIN_MODE_INPUT)\n#define mp_hal_pin_name(p)       mp_hal_pin_get_name(p)\n#define mp_hal_pin_high(p)       mp_hal_pin_write(p, 1)\n\n"
  },
  {
    "path": "port/mpputsnport.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdio.h>\n#include <rtthread.h>\n#include <rtdevice.h>\n\nstatic rt_device_t console_dev = NULL;\nstatic struct rt_device dummy_console = { 0 };\nstatic rt_uint16_t console_open_flag;\n\nvoid mp_putsn(const char *str, size_t len) {\n    if (console_dev) {\n        rt_device_write(console_dev, 0, str, len);\n    }\n}\n\nvoid mp_putsn_stream(const char *str, size_t len) {\n    if (console_dev) {\n        rt_uint16_t old_flag = console_dev->open_flag;\n\n        console_dev->open_flag |= RT_DEVICE_FLAG_STREAM;\n        rt_device_write(console_dev, 0, str, len);\n        console_dev->open_flag = old_flag;\n    }\n}\n\nvoid mp_putsn_init(void) {\n    {/* register dummy console device */\n#ifdef RT_USING_DEVICE_OPS\n        static struct rt_device_ops _ops = {0};\n        dummy_console.ops = &_ops;\n#endif\n\n        dummy_console.type = RT_Device_Class_Char;\n\n        rt_device_register(&dummy_console, \"dummy\", RT_DEVICE_FLAG_RDWR);\n    }\n\n    /* backup the console device */\n    console_dev = rt_console_get_device();\n    console_open_flag = console_dev->open_flag;\n    console_dev->open_flag = 0;\n\n    /* set the new console device to dummy console */\n    rt_console_set_device(dummy_console.parent.name);\n    /* reopen the old console device for mp_putsn */\n    rt_device_open(console_dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);\n}\n\nvoid mp_putsn_deinit(void) {\n    /* close the old console, it's already in mp_putsn_init */\n    rt_device_close(console_dev);\n    /* restore the old console device */\n    rt_console_set_device(console_dev->parent.name);\n    console_dev->open_flag = console_open_flag;\n\n    rt_device_unregister(&dummy_console);\n}\n"
  },
  {
    "path": "port/mpputsnport.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef _MPPUTCHARPORT_H_\n#define _MPPUTCHARPORT_H_\n\nvoid mp_putsn_init(void);\nvoid mp_putsn_deinit(void);\nvoid mp_putsn(const char *str, size_t len);\nvoid mp_putsn_stream(const char *str, size_t len);\n\n#endif /* _MPPUTCHARPORT_H_ */\n"
  },
  {
    "path": "port/mpthreadport.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"stdio.h\"\n\n#include \"py/mpconfig.h\"\n#include \"py/mpstate.h\"\n#include \"py/gc.h\"\n#include \"py/mpthread.h\"\n#include \"mpthreadport.h\"\n\n#include <rthw.h>\n\n#if MICROPY_PY_THREAD\n\n#define MP_THREAD_MIN_STACK_SIZE                 (4 * 1024)\n#define MP_THREAD_DEFAULT_STACK_SIZE             (MP_THREAD_MIN_STACK_SIZE + 1024)\n\n#define MP_THREAD_STATUS_READY                   0\n#define MP_THREAD_STATUS_RUNNING                 1\n#define MP_THREAD_STATUS_FINISH                  2\n\ntypedef struct _thread_t {\n    rt_thread_t id;         // system id of thread\n    int status;              // whether the thread is ready, running and finish\n    void *arg;              // thread Python args, a GC root pointer\n    void *stack;            // pointer to the stack\n    size_t stack_len;       // number of words in the stack\n    struct _thread_t *next;\n} thread_t;\n\n// the mutex controls access to the linked list\nSTATIC mp_thread_mutex_t thread_mutex;\nSTATIC thread_t thread_root_node;\nSTATIC thread_t *thread_root; // root pointer, handled by mp_thread_gc_others\n\n/**\n * thread port initialization\n *\n * @param stack MicroPython main thread stack start address\n * @param stack_len number of words in the stack\n */\nvoid mp_thread_init(void *stack, uint32_t stack_len) {\n    mp_thread_set_state(&mp_state_ctx.thread);\n\n    thread_root = &thread_root_node;\n    thread_root->id = rt_thread_self();\n    thread_root->status = MP_THREAD_STATUS_RUNNING;\n    thread_root->arg = NULL;\n    thread_root->stack = stack;\n    thread_root->stack_len = stack_len;\n    thread_root->next = NULL;\n\n    mp_thread_mutex_init(&thread_mutex);\n}\n\nvoid mp_thread_gc_others(void) {\n\n    mp_thread_mutex_lock(&thread_mutex, 1);\n    for (thread_t *th = thread_root; th != NULL; th = th->next) {\n        // the root node not using the mpy heap\n        if (th != &thread_root_node) {\n            gc_collect_root((void**)&th, 1);\n            gc_collect_root(&th->arg, 1); // probably not needed\n        }\n\n        if (th->status == MP_THREAD_STATUS_READY) {\n            continue;\n        }\n\n        gc_collect_root((void**) &th->id, 1); // probably not needed\n        gc_collect_root(th->stack, th->stack_len); // probably not needed\n    }\n    mp_thread_mutex_unlock(&thread_mutex);\n}\n\nmp_state_thread_t *mp_thread_get_state(void) {\n    return (mp_state_thread_t *)(rt_thread_self()->user_data);\n}\n\nvoid mp_thread_set_state(mp_state_thread_t *state) {\n    rt_thread_self()->user_data = (rt_uint32_t)state;\n}\n\nvoid mp_thread_start(void) {\n    mp_thread_mutex_lock(&thread_mutex, 1);\n    for (thread_t *th = thread_root; th != NULL; th = th->next) {\n        if (th->id == rt_thread_self()) {\n            th->status = MP_THREAD_STATUS_RUNNING;\n            break;\n        }\n    }\n    mp_thread_mutex_unlock(&thread_mutex);\n}\n\nvoid mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, int priority, char *name) {\n    static uint8_t count = 0;\n\n    if (*stack_size == 0) {\n        *stack_size = MP_THREAD_DEFAULT_STACK_SIZE; // default stack size\n    } else if (*stack_size < MP_THREAD_MIN_STACK_SIZE) {\n        *stack_size = MP_THREAD_MIN_STACK_SIZE; // minimum stack size\n    }\n\n    // allocate the linked-list node, TCB and stack (must be outside thread_mutex lock)\n    thread_t *th = m_new_obj(thread_t);\n    if (th == NULL) {\n        nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, \"can't create thread obj\"));\n    }\n    else {\n        th->id = m_new_obj(struct rt_thread);\n        if (th->id == NULL) {\n            nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, \"can't create thread id\"));\n        }\n        th->stack = m_new(uint8_t, *stack_size);\n        if (th->stack == NULL) {\n            nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, \"can't create thread stack\"));\n        }\n    }\n\n    mp_thread_mutex_lock(&thread_mutex, 1);\n\n    // adjust the stack_size to provide room to recover from hitting the limit\n    *stack_size -= 1024;\n\n    // add thread to linked list of all threads\n    th->status = MP_THREAD_STATUS_READY;\n    th->arg = arg;\n    th->stack_len = *stack_size / 4;\n    th->next = thread_root;\n    thread_root = th;\n\n    rt_thread_init(th->id, name, (void (*)(void *))entry, arg, th->stack, *stack_size, priority, count++);\n    rt_thread_startup(th->id);\n\n    mp_thread_mutex_unlock(&thread_mutex);\n}\n\nvoid mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) {\n    static uint8_t count = 0;\n    int priority = rt_thread_self()->current_priority;\n    char name[RT_NAME_MAX];\n\n    if (priority > 0) {\n        priority --;\n    }\n\n    /* build name */\n    rt_snprintf(name, sizeof(name), \"mp%02d\", count++);\n\n    mp_thread_create_ex(entry, arg, stack_size, priority, name);\n}\n\nvoid mp_thread_finish(void) {\n    thread_t *prev = NULL;\n\n    mp_thread_mutex_lock(&thread_mutex, 1);\n    for (thread_t *th = thread_root; th != NULL;prev = th, th = th->next) {\n        // unlink the node from the list\n        if (th->id == rt_thread_self()) {\n\n            if (prev != NULL) {\n                prev->next = th->next;\n            } else {\n                // move the start pointer\n                thread_root = th->next;\n            }\n            th->status = MP_THREAD_STATUS_FINISH;\n            // explicitly release all its memory\n            m_del_obj(struct rt_thread, th->id);\n            m_del(uint8_t, th->stack, th->stack_len);\n            m_del_obj(thread_t, th);\n            break;\n        }\n    }\n    mp_thread_mutex_unlock(&thread_mutex);\n}\n\nvoid mp_thread_mutex_init(mp_thread_mutex_t *mutex) {\n    static uint8_t count = 0;\n    char name[RT_NAME_MAX];\n\n    if (!mutex->is_init) {\n        /* build name */\n        rt_snprintf(name, sizeof(name), \"mp%02d\", count++);\n        rt_mutex_init(&(mutex->mutex), name, RT_IPC_FLAG_FIFO);\n        mutex->is_init = 1;\n    }\n}\n\nint mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) {\n    return (RT_EOK == rt_mutex_take(&(mutex->mutex), wait ? RT_WAITING_FOREVER : 0));\n}\n\nvoid mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {\n    rt_mutex_release(&(mutex->mutex));\n}\n\nvoid mp_thread_deinit(void) {\n    // detach all ready and running mpy thread\n    for (thread_t *th = thread_root; th != NULL; th = th->next) {\n        if (th != &thread_root_node && th->status != MP_THREAD_STATUS_FINISH) {\n            rt_thread_detach(th->id);\n        }\n    }\n\n    // allow RT-Thread to clean-up the threads\n    rt_thread_delay(200);\n}\n\n#endif /* MICROPY_PY_THREAD */\n"
  },
  {
    "path": "port/mpthreadport.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef _MPTHREADPORT_H\n#define _MPTHREADPORT_H\n\n#include \"rtthread.h\"\n\ntypedef struct _mp_thread_mutex_t {\n    struct rt_mutex mutex;\n    int is_init;\n} mp_thread_mutex_t;\n\nvoid mp_thread_init(void *stack, uint32_t stack_len);\nvoid mp_thread_gc_others(void);\nvoid mp_thread_deinit(void);\n\n#endif // _MPTHREADPORT_H\n"
  },
  {
    "path": "port/mpy_main.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n#include <rtthread.h>\n#ifdef RT_USING_DFS\n#include <unistd.h>\n#include <fcntl.h>\n#include <dfs.h>\n#endif\n#include <py/compile.h>\n#include <py/runtime.h>\n#include <py/repl.h>\n#include <py/gc.h>\n#include <py/mperrno.h>\n#include <py/stackctrl.h>\n#include <py/frozenmod.h>\n#include <lib/mp-readline/readline.h>\n#include <lib/utils/pyexec.h>\n#include \"mpgetcharport.h\"\n#include \"mpputsnport.h\"\n\n#define THREAD_STACK_NO_SYNC   4096\n#define THREAD_STACK_WITH_SYNC 8192\n\n#if MICROPY_ENABLE_COMPILER\nvoid do_str(const char *src, mp_parse_input_kind_t input_kind) {\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);\n        qstr source_name = lex->source_name;\n        mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);\n        mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true);\n        mp_call_function_0(module_fun);\n        nlr_pop();\n    } else {\n        // uncaught exception\n        mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);\n    }\n}\n#endif\n\n#ifdef RT_USING_DFS\nstatic int mp_sys_resource_bak(struct dfs_fdtable **table_bak)\n{\n    struct dfs_fdtable *fd_table;\n    struct dfs_fdtable *fd_table_bak;\n    struct dfs_fd **fds;\n\n    fd_table = dfs_fdtable_get();\n    if (!fd_table) \n    {\n        return RT_FALSE;\n    }\n\n    fd_table_bak = (struct dfs_fdtable *)rt_malloc(sizeof(struct dfs_fdtable));\n    if (!fd_table_bak)\n    {\n        goto _exit_tab;\n    }\n\n    fds = (struct dfs_fd **)rt_malloc((int)fd_table->maxfd * sizeof(struct dfs_fd *));\n    if (!fds)\n    {\n        goto _exit_fds;\n    }\n    else\n    {\n        rt_memcpy(fds, fd_table->fds, (int)fd_table->maxfd * sizeof(struct dfs_fd *));\n        fd_table_bak->maxfd = (int)fd_table->maxfd;\n        fd_table_bak->fds = fds;\n    }\n\n    *table_bak = fd_table_bak;\n\n    return RT_TRUE;\n\n_exit_fds:\n    rt_free(fd_table_bak);\n    \n_exit_tab:\n    return RT_FALSE;\n}\n\nstatic void mp_sys_resource_gc(struct dfs_fdtable *fd_table_bak)\n{\n    struct dfs_fdtable *fd_table;\n    \n    if (!fd_table_bak) return;\n\n    fd_table = dfs_fdtable_get();\n\n    for(int i = 0; i < fd_table->maxfd; i++)\n    {\n        if (fd_table->fds[i] != RT_NULL)\n        {\n            if ((i < fd_table_bak->maxfd && fd_table_bak->fds[i] == RT_NULL) || (i >= fd_table_bak->maxfd))\n            {\n                close(i + DFS_FD_OFFSET);\n            }\n        }\n    }\n\n    rt_free(fd_table_bak->fds);\n    rt_free(fd_table_bak);\n}\n#endif\n\nstatic void *stack_top = RT_NULL;\nstatic char *heap = RT_NULL;\n\nvoid mpy_main(const char *filename) {\n    int stack_dummy;\n    int stack_size_check;\n    stack_top = (void *)&stack_dummy;\n    \n#ifdef RT_USING_DFS\n    struct dfs_fdtable *fd_table_bak = NULL;\n    mp_sys_resource_bak(&fd_table_bak);\n#endif\n\n    mp_getchar_init();\n    mp_putsn_init();\n\n#if defined(MICROPYTHON_USING_FILE_SYNC_VIA_IDE)\n    stack_size_check = THREAD_STACK_WITH_SYNC;\n#else\n    stack_size_check = THREAD_STACK_NO_SYNC;\n#endif\n\n    if (rt_thread_self()->stack_size < stack_size_check) \n    {\n        #if (RTTHREAD_VERSION < RT_VERSION_CHECK(5, 0, 1))\n        mp_printf(&mp_plat_print, \"The stack (%.*s) size for executing MicroPython must be >= %d\\n\", RT_NAME_MAX, rt_thread_self()->name, stack_size_check);\n        #else\n        mp_printf(&mp_plat_print, \"The stack (%.*s) size for executing MicroPython must be >= %d\\n\", RT_NAME_MAX, rt_thread_self()->parent.name, stack_size_check);\n        #endif\n    }\n\n#if MICROPY_PY_THREAD\n    mp_thread_init(rt_thread_self()->stack_addr, ((rt_uint32_t)stack_top - (rt_uint32_t)rt_thread_self()->stack_addr) / 4);\n#endif\n\n    mp_stack_set_top(stack_top);\n    // Make MicroPython's stack limit somewhat smaller than full stack available\n    mp_stack_set_limit(rt_thread_self()->stack_size - 1024);\n\n#if MICROPY_ENABLE_GC\n    heap = rt_malloc(MICROPY_HEAP_SIZE);\n    if (!heap) {\n        mp_printf(&mp_plat_print, \"No memory for MicroPython Heap!\\n\");\n        return;\n    }\n    gc_init(heap, heap + MICROPY_HEAP_SIZE);\n#endif\n\n    /* MicroPython initialization */\n    mp_init();\n\n    /* system path initialization */\n    mp_obj_list_init(mp_sys_path, 0);\n    mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)\n    mp_obj_list_append(mp_sys_path, mp_obj_new_str(MICROPY_PY_PATH_FIRST, strlen(MICROPY_PY_PATH_FIRST)));\n    mp_obj_list_append(mp_sys_path, mp_obj_new_str(MICROPY_PY_PATH_SECOND, strlen(MICROPY_PY_PATH_SECOND)));\n    mp_obj_list_init(mp_sys_argv, 0);\n    readline_init0();\n\n    if (filename) {\n#ifndef MICROPYTHON_USING_UOS\n        mp_printf(&mp_plat_print, \"Please enable uos module in sys module option first.\\n\");\n#else\n        pyexec_file(filename);\n#endif\n    } else {\n#ifdef MICROPYTHON_USING_UOS\n        // run boot-up scripts\n        void *frozen_data;\n        const char *_boot_file = \"_boot.py\", *boot_file = \"boot.py\", *main_file = MICROPY_MAIN_PY_PATH;\n        if (mp_find_frozen_module(_boot_file, strlen(_boot_file), &frozen_data) != MP_FROZEN_NONE) {\n            pyexec_frozen_module(_boot_file);\n        }\n        if (!access(boot_file, 0)) {\n            pyexec_file(boot_file);\n        }\n        // run main scripts\n        if (!access(main_file, 0)) {\n            if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {\n                pyexec_file(main_file);\n            }\n        }\n#endif /* MICROPYTHON_USING_UOS */\n\n        mp_printf(&mp_plat_print, \"\\n\");\n        for (;;) {\n            if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {\n                if (pyexec_raw_repl() != 0) {\n                    break;\n                }\n            } else {\n                if (pyexec_friendly_repl() != 0) {\n                    break;\n                }\n            }\n        }\n    }\n\n    gc_sweep_all();\n\n    mp_deinit();\n\n#if MICROPY_PY_THREAD\n    mp_thread_deinit();\n#endif\n\n    rt_free(heap);\n\n    mp_putsn_deinit();\n    mp_getchar_deinit();\n    \n#ifdef RT_USING_DFS\n    mp_sys_resource_gc(fd_table_bak);\n#endif\n}\n\n#if !MICROPY_PY_MODUOS_FILE\nmp_import_stat_t mp_import_stat(const char *path) {\n    return MP_IMPORT_STAT_NO_EXIST;\n}\n#endif\n\nNORETURN void nlr_jump_fail(void *val) {\n    mp_printf(MICROPY_ERROR_PRINTER, \"nlr_jump_fail\\n\");\n    while (1);\n}\n\n#ifndef NDEBUG\nNORETURN void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {\n    mp_printf(MICROPY_ERROR_PRINTER, \"Assertion '%s' failed, at file %s:%d\\n\", expr, file, line);\n    while (1);\n}\n#endif\n\n#include <stdarg.h>\n\nint DEBUG_printf(const char *format, ...)\n{\n    static char log_buf[512];\n    va_list args;\n\n    /* args point to the first variable parameter */\n    va_start(args, format);\n    /* must use vprintf to print */\n    rt_vsprintf(log_buf, format, args);\n    mp_printf(&mp_plat_print, \"%s\", log_buf);\n    va_end(args);\n\n    return 0;\n}\n\n#ifndef MICROPYTHON_USING_UOS\nmp_lexer_t *mp_lexer_new_from_file(const char *filename) {\n    mp_raise_OSError(MP_ENOENT);\n}\n#endif\n\n#if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)\n#include <finsh.h>\nstatic void python(uint8_t argc, char **argv) {\n    if (argc > 1) {\n        mpy_main(argv[1]);\n    } else {\n        mpy_main(NULL);\n    }\n}\nMSH_CMD_EXPORT(python, MicroPython: `python [file.py]` execute python script);\n#endif /* defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) */\n"
  },
  {
    "path": "port/mpy_project_cfg.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n/**\n * MicroPython Project compile configuration\n */\n#define NDEBUG                         0\n#define N_X64                          0\n#define N_X86                          0\n#define N_THUMB                        0\n#define N_ARM                          0\n#define N_XTENSA                       0\n"
  },
  {
    "path": "port/native/easyflash_module.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <rtthread.h>\n#include <py/runtime.h>\n\n#if defined(MICROPYTHON_USING_FFI) && defined(PKG_EASYFLASH_ENV)\n\n#include <easyflash.h>\n\nRTM_EXPORT(ef_set_env)\nRTM_EXPORT(ef_get_env)\nRTM_EXPORT(ef_del_env)\nRTM_EXPORT(ef_print_env)\n\n#endif /* defined(MICROPYTHON_USING_FFI) && defined(PKG_EASYFLASH_ENV) */\n"
  },
  {
    "path": "port/native/easyflash_module.py",
    "content": "import ffi\n\nprint = ffi.func(\"v\", \"ef_print_env\", \"v\")\nset = ffi.func(\"i\", \"ef_set_env\", \"ss\")\nget = ffi.func(\"s\", \"ef_get_env\", \"s\")\nremove = ffi.func(\"i\", \"ef_del_env\", \"s\")\n"
  },
  {
    "path": "port/native/native_module.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Armink (armink.ztl@gmail.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <rtthread.h>\n#include <py/runtime.h>\n\n#ifdef MICROPYTHON_USING_FFI\n\n/*\n * Native module implement by C function export.\n * The python module will using ffi to import all of functions.\n * You can call those functions by:\n *\n * STEP1:\n *     generate the python module from 'native_module.c' to 'native_module.py'\n *     run 'python native_gen.py native_module.c' command\n *\n * STEP2:\n *     push the 'native_module.py' file to '/libs/mpy/' folder on target\n *\n * STEP3:\n *     import native_modbule\n *\n * STEP4:\n *     native_module.show(\"Hello native module\")\n *     native_module.add(1, 2)\n */\n\nvoid native_module_show(const char *str) {\n    mp_printf(&mp_plat_print, \"Native module show: %s\\n\", str);\n}\nRTM_EXPORT(native_module_show)\n\nint native_module_add(int a, int b) {\n    return a + b;\n}\nRTM_EXPORT(native_module_add)\n\n#endif /* MICROPYTHON_USING_FFI */\n"
  },
  {
    "path": "port/native/native_module.py",
    "content": "import ffi\n\nshow = ffi.func(\"v\", \"native_module_show\", \"s\")\nadd = ffi.func(\"i\", \"native_module_add\", \"ii\")\n"
  },
  {
    "path": "port/qstrdefsport.h",
    "content": "// qstrs specific to this port\n"
  },
  {
    "path": "py/argcheck.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n\nvoid mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {\n    // TODO maybe take the function name as an argument so we can print nicer error messages\n\n    // The reverse of MP_OBJ_FUN_MAKE_SIG\n    bool takes_kw = sig & 1;\n    size_t n_args_min = sig >> 17;\n    size_t n_args_max = (sig >> 1) & 0xffff;\n\n    if (n_kw && !takes_kw) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_arg_error_terse_mismatch();\n        #else\n        mp_raise_TypeError(MP_ERROR_TEXT(\"function doesn't take keyword arguments\"));\n        #endif\n    }\n\n    if (n_args_min == n_args_max) {\n        if (n_args != n_args_min) {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_arg_error_terse_mismatch();\n            #else\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"function takes %d positional arguments but %d were given\"),\n                n_args_min, n_args);\n            #endif\n        }\n    } else {\n        if (n_args < n_args_min) {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_arg_error_terse_mismatch();\n            #else\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"function missing %d required positional arguments\"),\n                n_args_min - n_args);\n            #endif\n        } else if (n_args > n_args_max) {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_arg_error_terse_mismatch();\n            #else\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"function expected at most %d arguments, got %d\"),\n                n_args_max, n_args);\n            #endif\n        }\n    }\n}\n\nvoid 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) {\n    size_t pos_found = 0, kws_found = 0;\n    for (size_t i = 0; i < n_allowed; i++) {\n        mp_obj_t given_arg;\n        if (i < n_pos) {\n            if (allowed[i].flags & MP_ARG_KW_ONLY) {\n                goto extra_positional;\n            }\n            pos_found++;\n            given_arg = pos[i];\n        } else {\n            mp_map_elem_t *kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qst), MP_MAP_LOOKUP);\n            if (kw == NULL) {\n                if (allowed[i].flags & MP_ARG_REQUIRED) {\n                    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                    mp_arg_error_terse_mismatch();\n                    #else\n                    mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT(\"'%q' argument required\"), allowed[i].qst);\n                    #endif\n                }\n                out_vals[i] = allowed[i].defval;\n                continue;\n            } else {\n                kws_found++;\n                given_arg = kw->value;\n            }\n        }\n        if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_BOOL) {\n            out_vals[i].u_bool = mp_obj_is_true(given_arg);\n        } else if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_INT) {\n            out_vals[i].u_int = mp_obj_get_int(given_arg);\n        } else {\n            assert((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_OBJ);\n            out_vals[i].u_obj = given_arg;\n        }\n    }\n    if (pos_found < n_pos) {\n    extra_positional:\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_arg_error_terse_mismatch();\n        #else\n        // TODO better error message\n        mp_raise_TypeError(MP_ERROR_TEXT(\"extra positional arguments given\"));\n        #endif\n    }\n    if (kws_found < kws->used) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_arg_error_terse_mismatch();\n        #else\n        // TODO better error message\n        mp_raise_TypeError(MP_ERROR_TEXT(\"extra keyword arguments given\"));\n        #endif\n    }\n}\n\nvoid 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) {\n    mp_map_t kw_args;\n    mp_map_init_fixed_table(&kw_args, n_kw, args + n_pos);\n    mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals);\n}\n\nNORETURN void mp_arg_error_terse_mismatch(void) {\n    mp_raise_TypeError(MP_ERROR_TEXT(\"argument num/types mismatch\"));\n}\n\n#if MICROPY_CPYTHON_COMPAT\nNORETURN void mp_arg_error_unimpl_kw(void) {\n    mp_raise_NotImplementedError(MP_ERROR_TEXT(\"keyword argument(s) not yet implemented - use normal args instead\"));\n}\n#endif\n"
  },
  {
    "path": "py/asmarm.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Fabian Vogt\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <assert.h>\n#include <string.h>\n\n#include \"py/mpconfig.h\"\n\n// wrapper around everything in this file\n#if MICROPY_EMIT_ARM\n\n#include \"py/asmarm.h\"\n\n#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)\n\nvoid asm_arm_end_pass(asm_arm_t *as) {\n    if (as->base.pass == MP_ASM_PASS_EMIT) {\n        #if defined(__linux__) && defined(__GNUC__)\n        char *start = mp_asm_base_get_code(&as->base);\n        char *end = start + mp_asm_base_get_code_size(&as->base);\n        __builtin___clear_cache(start, end);\n        #elif defined(__arm__)\n        // flush I- and D-cache\n        asm volatile (\n            \"0:\"\n            \"mrc p15, 0, r15, c7, c10, 3\\n\"\n            \"bne 0b\\n\"\n            \"mov r0, #0\\n\"\n            \"mcr p15, 0, r0, c7, c7, 0\\n\"\n            : : : \"r0\", \"cc\");\n        #endif\n    }\n}\n\n// Insert word into instruction flow\nSTATIC void emit(asm_arm_t *as, uint op) {\n    uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);\n    if (c != NULL) {\n        *(uint32_t *)c = op;\n    }\n}\n\n// Insert word into instruction flow, add \"ALWAYS\" condition code\nSTATIC void emit_al(asm_arm_t *as, uint op) {\n    emit(as, op | ASM_ARM_CC_AL);\n}\n\n// Basic instructions without condition code\nSTATIC uint asm_arm_op_push(uint reglist) {\n    // stmfd sp!, {reglist}\n    return 0x92d0000 | (reglist & 0xFFFF);\n}\n\nSTATIC uint asm_arm_op_pop(uint reglist) {\n    // ldmfd sp!, {reglist}\n    return 0x8bd0000 | (reglist & 0xFFFF);\n}\n\nSTATIC uint asm_arm_op_mov_reg(uint rd, uint rn) {\n    // mov rd, rn\n    return 0x1a00000 | (rd << 12) | rn;\n}\n\nSTATIC uint asm_arm_op_mov_imm(uint rd, uint imm) {\n    // mov rd, #imm\n    return 0x3a00000 | (rd << 12) | imm;\n}\n\nSTATIC uint asm_arm_op_mvn_imm(uint rd, uint imm) {\n    // mvn rd, #imm\n    return 0x3e00000 | (rd << 12) | imm;\n}\n\nSTATIC uint asm_arm_op_add_imm(uint rd, uint rn, uint imm) {\n    // add rd, rn, #imm\n    return 0x2800000 | (rn << 16) | (rd << 12) | (imm & 0xFF);\n}\n\nSTATIC uint asm_arm_op_add_reg(uint rd, uint rn, uint rm) {\n    // add rd, rn, rm\n    return 0x0800000 | (rn << 16) | (rd << 12) | rm;\n}\n\nSTATIC uint asm_arm_op_sub_imm(uint rd, uint rn, uint imm) {\n    // sub rd, rn, #imm\n    return 0x2400000 | (rn << 16) | (rd << 12) | (imm & 0xFF);\n}\n\nSTATIC uint asm_arm_op_sub_reg(uint rd, uint rn, uint rm) {\n    // sub rd, rn, rm\n    return 0x0400000 | (rn << 16) | (rd << 12) | rm;\n}\n\nSTATIC uint asm_arm_op_mul_reg(uint rd, uint rm, uint rs) {\n    // mul rd, rm, rs\n    assert(rd != rm);\n    return 0x0000090 | (rd << 16) | (rs << 8) | rm;\n}\n\nSTATIC uint asm_arm_op_and_reg(uint rd, uint rn, uint rm) {\n    // and rd, rn, rm\n    return 0x0000000 | (rn << 16) | (rd << 12) | rm;\n}\n\nSTATIC uint asm_arm_op_eor_reg(uint rd, uint rn, uint rm) {\n    // eor rd, rn, rm\n    return 0x0200000 | (rn << 16) | (rd << 12) | rm;\n}\n\nSTATIC uint asm_arm_op_orr_reg(uint rd, uint rn, uint rm) {\n    // orr rd, rn, rm\n    return 0x1800000 | (rn << 16) | (rd << 12) | rm;\n}\n\nvoid asm_arm_bkpt(asm_arm_t *as) {\n    // bkpt #0\n    emit_al(as, 0x1200070);\n}\n\n// locals:\n//  - stored on the stack in ascending order\n//  - numbered 0 through num_locals-1\n//  - SP points to first local\n//\n//  | SP\n//  v\n//  l0  l1  l2  ...  l(n-1)\n//  ^                ^\n//  | low address    | high address in RAM\n\nvoid asm_arm_entry(asm_arm_t *as, int num_locals) {\n    assert(num_locals >= 0);\n\n    as->stack_adjust = 0;\n    as->push_reglist = 1 << ASM_ARM_REG_R1\n        | 1 << ASM_ARM_REG_R2\n        | 1 << ASM_ARM_REG_R3\n        | 1 << ASM_ARM_REG_R4\n        | 1 << ASM_ARM_REG_R5\n        | 1 << ASM_ARM_REG_R6\n        | 1 << ASM_ARM_REG_R7\n        | 1 << ASM_ARM_REG_R8;\n\n    // Only adjust the stack if there are more locals than usable registers\n    if (num_locals > 3) {\n        as->stack_adjust = num_locals * 4;\n        // Align stack to 8 bytes\n        if (num_locals & 1) {\n            as->stack_adjust += 4;\n        }\n    }\n\n    emit_al(as, asm_arm_op_push(as->push_reglist | 1 << ASM_ARM_REG_LR));\n    if (as->stack_adjust > 0) {\n        emit_al(as, asm_arm_op_sub_imm(ASM_ARM_REG_SP, ASM_ARM_REG_SP, as->stack_adjust));\n    }\n}\n\nvoid asm_arm_exit(asm_arm_t *as) {\n    if (as->stack_adjust > 0) {\n        emit_al(as, asm_arm_op_add_imm(ASM_ARM_REG_SP, ASM_ARM_REG_SP, as->stack_adjust));\n    }\n\n    emit_al(as, asm_arm_op_pop(as->push_reglist | (1 << ASM_ARM_REG_PC)));\n}\n\nvoid asm_arm_push(asm_arm_t *as, uint reglist) {\n    emit_al(as, asm_arm_op_push(reglist));\n}\n\nvoid asm_arm_pop(asm_arm_t *as, uint reglist) {\n    emit_al(as, asm_arm_op_pop(reglist));\n}\n\nvoid asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) {\n    emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src));\n}\n\nsize_t asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) {\n    // Insert immediate into code and jump over it\n    emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc]\n    emit_al(as, 0xa000000); // b pc\n    size_t loc = mp_asm_base_get_code_pos(&as->base);\n    emit(as, imm);\n    return loc;\n}\n\nvoid asm_arm_mov_reg_i32_optimised(asm_arm_t *as, uint rd, int imm) {\n    // TODO: There are more variants of immediate values\n    if ((imm & 0xFF) == imm) {\n        emit_al(as, asm_arm_op_mov_imm(rd, imm));\n    } else if (imm < 0 && imm >= -256) {\n        // mvn is \"move not\", not \"move negative\"\n        emit_al(as, asm_arm_op_mvn_imm(rd, ~imm));\n    } else {\n        asm_arm_mov_reg_i32(as, rd, imm);\n    }\n}\n\nvoid asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd) {\n    // str rd, [sp, #local_num*4]\n    emit_al(as, 0x58d0000 | (rd << 12) | (local_num << 2));\n}\n\nvoid asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num) {\n    // ldr rd, [sp, #local_num*4]\n    emit_al(as, 0x59d0000 | (rd << 12) | (local_num << 2));\n}\n\nvoid asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm) {\n    // cmp rd, #imm\n    emit_al(as, 0x3500000 | (rd << 16) | (imm & 0xFF));\n}\n\nvoid asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn) {\n    // cmp rd, rn\n    emit_al(as, 0x1500000 | (rd << 16) | rn);\n}\n\nvoid asm_arm_setcc_reg(asm_arm_t *as, uint rd, uint cond) {\n    emit(as, asm_arm_op_mov_imm(rd, 1) | cond); // movCOND rd, #1\n    emit(as, asm_arm_op_mov_imm(rd, 0) | (cond ^ (1 << 28))); // mov!COND rd, #0\n}\n\nvoid asm_arm_add_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {\n    // add rd, rn, rm\n    emit_al(as, asm_arm_op_add_reg(rd, rn, rm));\n}\n\nvoid asm_arm_sub_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {\n    // sub rd, rn, rm\n    emit_al(as, asm_arm_op_sub_reg(rd, rn, rm));\n}\n\nvoid asm_arm_mul_reg_reg_reg(asm_arm_t *as, uint rd, uint rs, uint rm) {\n    // rs and rm are swapped because of restriction rd!=rm\n    // mul rd, rm, rs\n    emit_al(as, asm_arm_op_mul_reg(rd, rm, rs));\n}\n\nvoid asm_arm_and_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {\n    // and rd, rn, rm\n    emit_al(as, asm_arm_op_and_reg(rd, rn, rm));\n}\n\nvoid asm_arm_eor_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {\n    // eor rd, rn, rm\n    emit_al(as, asm_arm_op_eor_reg(rd, rn, rm));\n}\n\nvoid asm_arm_orr_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {\n    // orr rd, rn, rm\n    emit_al(as, asm_arm_op_orr_reg(rd, rn, rm));\n}\n\nvoid asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num) {\n    // add rd, sp, #local_num*4\n    emit_al(as, asm_arm_op_add_imm(rd, ASM_ARM_REG_SP, local_num << 2));\n}\n\nvoid asm_arm_mov_reg_pcrel(asm_arm_t *as, uint reg_dest, uint label) {\n    assert(label < as->base.max_num_labels);\n    mp_uint_t dest = as->base.label_offsets[label];\n    mp_int_t rel = dest - as->base.code_offset;\n    rel -= 12 + 8; // adjust for load of rel, and then PC+8 prefetch of add_reg_reg_reg\n\n    // To load rel int reg_dest, insert immediate into code and jump over it\n    emit_al(as, 0x59f0000 | (reg_dest << 12)); // ldr rd, [pc]\n    emit_al(as, 0xa000000); // b pc\n    emit(as, rel);\n\n    // Do reg_dest += PC\n    asm_arm_add_reg_reg_reg(as, reg_dest, reg_dest, ASM_ARM_REG_PC);\n}\n\nvoid asm_arm_lsl_reg_reg(asm_arm_t *as, uint rd, uint rs) {\n    // mov rd, rd, lsl rs\n    emit_al(as, 0x1a00010 | (rd << 12) | (rs << 8) | rd);\n}\n\nvoid asm_arm_lsr_reg_reg(asm_arm_t *as, uint rd, uint rs) {\n    // mov rd, rd, lsr rs\n    emit_al(as, 0x1a00030 | (rd << 12) | (rs << 8) | rd);\n}\n\nvoid asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs) {\n    // mov rd, rd, asr rs\n    emit_al(as, 0x1a00050 | (rd << 12) | (rs << 8) | rd);\n}\n\nvoid asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn, uint byte_offset) {\n    // ldr rd, [rn, #off]\n    emit_al(as, 0x5900000 | (rn << 16) | (rd << 12) | byte_offset);\n}\n\nvoid asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn) {\n    // ldrh rd, [rn]\n    emit_al(as, 0x1d000b0 | (rn << 16) | (rd << 12));\n}\n\nvoid asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn) {\n    // ldrb rd, [rn]\n    emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12));\n}\n\nvoid asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm, uint byte_offset) {\n    // str rd, [rm, #off]\n    emit_al(as, 0x5800000 | (rm << 16) | (rd << 12) | byte_offset);\n}\n\nvoid asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm) {\n    // strh rd, [rm]\n    emit_al(as, 0x1c000b0 | (rm << 16) | (rd << 12));\n}\n\nvoid asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm) {\n    // strb rd, [rm]\n    emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12));\n}\n\nvoid asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {\n    // str rd, [rm, rn, lsl #2]\n    emit_al(as, 0x7800100 | (rm << 16) | (rd << 12) | rn);\n}\n\nvoid asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {\n    // strh doesn't support scaled register index\n    emit_al(as, 0x1a00080 | (ASM_ARM_REG_R8 << 12) | rn); // mov r8, rn, lsl #1\n    emit_al(as, 0x18000b0 | (rm << 16) | (rd << 12) | ASM_ARM_REG_R8); // strh rd, [rm, r8]\n}\n\nvoid asm_arm_strb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {\n    // strb rd, [rm, rn]\n    emit_al(as, 0x7c00000 | (rm << 16) | (rd << 12) | rn);\n}\n\nvoid asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) {\n    assert(label < as->base.max_num_labels);\n    mp_uint_t dest = as->base.label_offsets[label];\n    mp_int_t rel = dest - as->base.code_offset;\n    rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction\n    rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted\n\n    if (SIGNED_FIT24(rel)) {\n        emit(as, cond | 0xa000000 | (rel & 0xffffff));\n    } else {\n        printf(\"asm_arm_bcc: branch does not fit in 24 bits\\n\");\n    }\n}\n\nvoid asm_arm_b_label(asm_arm_t *as, uint label) {\n    asm_arm_bcc_label(as, ASM_ARM_CC_AL, label);\n}\n\nvoid asm_arm_bl_ind(asm_arm_t *as, uint fun_id, uint reg_temp) {\n    // The table offset should fit into the ldr instruction\n    assert(fun_id < (0x1000 / 4));\n    emit_al(as, asm_arm_op_mov_reg(ASM_ARM_REG_LR, ASM_ARM_REG_PC)); // mov lr, pc\n    emit_al(as, 0x597f000 | (fun_id << 2)); // ldr pc, [r7, #fun_id*4]\n}\n\nvoid asm_arm_bx_reg(asm_arm_t *as, uint reg_src) {\n    emit_al(as, 0x012fff10 | reg_src);\n}\n\n#endif // MICROPY_EMIT_ARM\n"
  },
  {
    "path": "py/asmarm.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Fabian Vogt\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_ASMARM_H\n#define MICROPY_INCLUDED_PY_ASMARM_H\n\n#include \"py/misc.h\"\n#include \"py/asmbase.h\"\n\n#define ASM_ARM_REG_R0  (0)\n#define ASM_ARM_REG_R1  (1)\n#define ASM_ARM_REG_R2  (2)\n#define ASM_ARM_REG_R3  (3)\n#define ASM_ARM_REG_R4  (4)\n#define ASM_ARM_REG_R5  (5)\n#define ASM_ARM_REG_R6  (6)\n#define ASM_ARM_REG_R7  (7)\n#define ASM_ARM_REG_R8  (8)\n#define ASM_ARM_REG_R9  (9)\n#define ASM_ARM_REG_R10 (10)\n#define ASM_ARM_REG_R11 (11)\n#define ASM_ARM_REG_R12 (12)\n#define ASM_ARM_REG_R13 (13)\n#define ASM_ARM_REG_R14 (14)\n#define ASM_ARM_REG_R15 (15)\n#define ASM_ARM_REG_SP  (ASM_ARM_REG_R13)\n#define ASM_ARM_REG_LR  (ASM_ARM_REG_R14)\n#define ASM_ARM_REG_PC  (ASM_ARM_REG_R15)\n\n#define ASM_ARM_CC_EQ (0x0 << 28)\n#define ASM_ARM_CC_NE (0x1 << 28)\n#define ASM_ARM_CC_CS (0x2 << 28)\n#define ASM_ARM_CC_CC (0x3 << 28)\n#define ASM_ARM_CC_MI (0x4 << 28)\n#define ASM_ARM_CC_PL (0x5 << 28)\n#define ASM_ARM_CC_VS (0x6 << 28)\n#define ASM_ARM_CC_VC (0x7 << 28)\n#define ASM_ARM_CC_HI (0x8 << 28)\n#define ASM_ARM_CC_LS (0x9 << 28)\n#define ASM_ARM_CC_GE (0xa << 28)\n#define ASM_ARM_CC_LT (0xb << 28)\n#define ASM_ARM_CC_GT (0xc << 28)\n#define ASM_ARM_CC_LE (0xd << 28)\n#define ASM_ARM_CC_AL (0xe << 28)\n\ntypedef struct _asm_arm_t {\n    mp_asm_base_t base;\n    uint push_reglist;\n    uint stack_adjust;\n} asm_arm_t;\n\nvoid asm_arm_end_pass(asm_arm_t *as);\n\nvoid asm_arm_entry(asm_arm_t *as, int num_locals);\nvoid asm_arm_exit(asm_arm_t *as);\n\nvoid asm_arm_bkpt(asm_arm_t *as);\n\n// mov\nvoid asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src);\nsize_t asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm);\nvoid asm_arm_mov_reg_i32_optimised(asm_arm_t *as, uint rd, int imm);\nvoid asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd);\nvoid asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num);\nvoid asm_arm_setcc_reg(asm_arm_t *as, uint rd, uint cond);\n\n// compare\nvoid asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm);\nvoid asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn);\n\n// arithmetic\nvoid asm_arm_add_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);\nvoid asm_arm_sub_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);\nvoid asm_arm_mul_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);\nvoid asm_arm_and_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);\nvoid asm_arm_eor_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);\nvoid asm_arm_orr_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);\nvoid asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num);\nvoid asm_arm_mov_reg_pcrel(asm_arm_t *as, uint reg_dest, uint label);\nvoid asm_arm_lsl_reg_reg(asm_arm_t *as, uint rd, uint rs);\nvoid asm_arm_lsr_reg_reg(asm_arm_t *as, uint rd, uint rs);\nvoid asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs);\n\n// memory\nvoid asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn, uint byte_offset);\nvoid asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn);\nvoid asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn);\nvoid asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm, uint byte_offset);\nvoid asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm);\nvoid asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm);\n// store to array\nvoid asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn);\nvoid asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn);\nvoid asm_arm_strb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn);\n\n// stack\nvoid asm_arm_push(asm_arm_t *as, uint reglist);\nvoid asm_arm_pop(asm_arm_t *as, uint reglist);\n\n// control flow\nvoid asm_arm_bcc_label(asm_arm_t *as, int cond, uint label);\nvoid asm_arm_b_label(asm_arm_t *as, uint label);\nvoid asm_arm_bl_ind(asm_arm_t *as, uint fun_id, uint reg_temp);\nvoid asm_arm_bx_reg(asm_arm_t *as, uint reg_src);\n\n// Holds a pointer to mp_fun_table\n#define ASM_ARM_REG_FUN_TABLE ASM_ARM_REG_R7\n\n#if GENERIC_ASM_API\n\n// The following macros provide a (mostly) arch-independent API to\n// generate native code, and are used by the native emitter.\n\n#define ASM_WORD_SIZE (4)\n\n#define REG_RET ASM_ARM_REG_R0\n#define REG_ARG_1 ASM_ARM_REG_R0\n#define REG_ARG_2 ASM_ARM_REG_R1\n#define REG_ARG_3 ASM_ARM_REG_R2\n#define REG_ARG_4 ASM_ARM_REG_R3\n\n#define REG_TEMP0 ASM_ARM_REG_R0\n#define REG_TEMP1 ASM_ARM_REG_R1\n#define REG_TEMP2 ASM_ARM_REG_R2\n\n#define REG_LOCAL_1 ASM_ARM_REG_R4\n#define REG_LOCAL_2 ASM_ARM_REG_R5\n#define REG_LOCAL_3 ASM_ARM_REG_R6\n#define REG_LOCAL_NUM (3)\n\n// Holds a pointer to mp_fun_table\n#define REG_FUN_TABLE ASM_ARM_REG_FUN_TABLE\n\n#define ASM_T               asm_arm_t\n#define ASM_END_PASS        asm_arm_end_pass\n#define ASM_ENTRY           asm_arm_entry\n#define ASM_EXIT            asm_arm_exit\n\n#define ASM_JUMP            asm_arm_b_label\n#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \\\n    do { \\\n        asm_arm_cmp_reg_i8(as, reg, 0); \\\n        asm_arm_bcc_label(as, ASM_ARM_CC_EQ, label); \\\n    } while (0)\n#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \\\n    do { \\\n        asm_arm_cmp_reg_i8(as, reg, 0); \\\n        asm_arm_bcc_label(as, ASM_ARM_CC_NE, label); \\\n    } while (0)\n#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \\\n    do { \\\n        asm_arm_cmp_reg_reg(as, reg1, reg2); \\\n        asm_arm_bcc_label(as, ASM_ARM_CC_EQ, label); \\\n    } while (0)\n#define ASM_JUMP_REG(as, reg) asm_arm_bx_reg((as), (reg))\n#define ASM_CALL_IND(as, idx) asm_arm_bl_ind(as, idx, ASM_ARM_REG_R3)\n\n#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_arm_mov_local_reg((as), (local_num), (reg_src))\n#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32_optimised((as), (reg_dest), (imm))\n#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm))\n#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm))\n#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_arm_mov_reg_local((as), (reg_dest), (local_num))\n#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_arm_mov_reg_reg((as), (reg_dest), (reg_src))\n#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_arm_mov_reg_local_addr((as), (reg_dest), (local_num))\n#define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_arm_mov_reg_pcrel((as), (reg_dest), (label))\n\n#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_arm_lsl_reg_reg((as), (reg_dest), (reg_shift))\n#define ASM_LSR_REG_REG(as, reg_dest, reg_shift) asm_arm_lsr_reg_reg((as), (reg_dest), (reg_shift))\n#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_arm_asr_reg_reg((as), (reg_dest), (reg_shift))\n#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_arm_orr_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_arm_eor_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_arm_and_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_arm_add_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_arm_sub_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_arm_mul_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))\n\n#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 0)\n#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))\n#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_arm_ldrb_reg_reg((as), (reg_dest), (reg_base))\n#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_arm_ldrh_reg_reg((as), (reg_dest), (reg_base))\n#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 0)\n\n#define ASM_STORE_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base), 0)\n#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))\n#define ASM_STORE8_REG_REG(as, reg_value, reg_base) asm_arm_strb_reg_reg((as), (reg_value), (reg_base))\n#define ASM_STORE16_REG_REG(as, reg_value, reg_base) asm_arm_strh_reg_reg((as), (reg_value), (reg_base))\n#define ASM_STORE32_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base), 0)\n\n#endif // GENERIC_ASM_API\n\n#endif // MICROPY_INCLUDED_PY_ASMARM_H\n"
  },
  {
    "path": "py/asmbase.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <string.h>\n\n#include \"py/obj.h\"\n#include \"py/misc.h\"\n#include \"py/asmbase.h\"\n\n#if MICROPY_EMIT_MACHINE_CODE\n\nvoid mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels) {\n    as->max_num_labels = max_num_labels;\n    as->label_offsets = m_new(size_t, max_num_labels);\n}\n\nvoid mp_asm_base_deinit(mp_asm_base_t *as, bool free_code) {\n    if (free_code) {\n        MP_PLAT_FREE_EXEC(as->code_base, as->code_size);\n    }\n    m_del(size_t, as->label_offsets, as->max_num_labels);\n}\n\nvoid mp_asm_base_start_pass(mp_asm_base_t *as, int pass) {\n    if (pass < MP_ASM_PASS_EMIT) {\n        // Reset labels so we can detect backwards jumps (and verify unique assignment)\n        memset(as->label_offsets, -1, as->max_num_labels * sizeof(size_t));\n    } else {\n        // allocating executable RAM is platform specific\n        MP_PLAT_ALLOC_EXEC(as->code_offset, (void **)&as->code_base, &as->code_size);\n        assert(as->code_base != NULL);\n    }\n    as->pass = pass;\n    as->code_offset = 0;\n}\n\n// all functions must go through this one to emit bytes\n// if as->pass < MP_ASM_PASS_EMIT, then this function just counts the number\n// of bytes needed and returns NULL, and callers should not store any data\nuint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write) {\n    uint8_t *c = NULL;\n    if (as->pass == MP_ASM_PASS_EMIT) {\n        assert(as->code_offset + num_bytes_to_write <= as->code_size);\n        c = as->code_base + as->code_offset;\n    }\n    as->code_offset += num_bytes_to_write;\n    return c;\n}\n\nvoid mp_asm_base_label_assign(mp_asm_base_t *as, size_t label) {\n    assert(label < as->max_num_labels);\n    if (as->pass < MP_ASM_PASS_EMIT) {\n        // assign label offset\n        assert(as->label_offsets[label] == (size_t)-1);\n        as->label_offsets[label] = as->code_offset;\n    } else {\n        // ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT\n        assert(as->label_offsets[label] == as->code_offset);\n    }\n}\n\n// align must be a multiple of 2\nvoid mp_asm_base_align(mp_asm_base_t *as, unsigned int align) {\n    as->code_offset = (as->code_offset + align - 1) & (~(align - 1));\n}\n\n// this function assumes a little endian machine\nvoid mp_asm_base_data(mp_asm_base_t *as, unsigned int bytesize, uintptr_t val) {\n    uint8_t *c = mp_asm_base_get_cur_to_write_bytes(as, bytesize);\n    if (c != NULL) {\n        for (unsigned int i = 0; i < bytesize; i++) {\n            *c++ = val;\n            val >>= 8;\n        }\n    }\n}\n\n#endif // MICROPY_EMIT_MACHINE_CODE\n"
  },
  {
    "path": "py/asmbase.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_ASMBASE_H\n#define MICROPY_INCLUDED_PY_ASMBASE_H\n\n#include <stdint.h>\n#include <stdbool.h>\n\n#define MP_ASM_PASS_COMPUTE (1)\n#define MP_ASM_PASS_EMIT    (2)\n\ntypedef struct _mp_asm_base_t {\n    int pass;\n    size_t code_offset;\n    size_t code_size;\n    uint8_t *code_base;\n\n    size_t max_num_labels;\n    size_t *label_offsets;\n} mp_asm_base_t;\n\nvoid mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels);\nvoid mp_asm_base_deinit(mp_asm_base_t *as, bool free_code);\nvoid mp_asm_base_start_pass(mp_asm_base_t *as, int pass);\nuint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write);\nvoid mp_asm_base_label_assign(mp_asm_base_t *as, size_t label);\nvoid mp_asm_base_align(mp_asm_base_t *as, unsigned int align);\nvoid mp_asm_base_data(mp_asm_base_t *as, unsigned int bytesize, uintptr_t val);\n\nstatic inline size_t mp_asm_base_get_code_pos(mp_asm_base_t *as) {\n    return as->code_offset;\n}\n\nstatic inline size_t mp_asm_base_get_code_size(mp_asm_base_t *as) {\n    return as->code_size;\n}\n\nstatic inline void *mp_asm_base_get_code(mp_asm_base_t *as) {\n    #if defined(MP_PLAT_COMMIT_EXEC)\n    return MP_PLAT_COMMIT_EXEC(as->code_base, as->code_size, NULL);\n    #else\n    return as->code_base;\n    #endif\n}\n\n#endif // MICROPY_INCLUDED_PY_ASMBASE_H\n"
  },
  {
    "path": "py/asmthumb.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <assert.h>\n#include <string.h>\n\n#include \"py/mpconfig.h\"\n\n// wrapper around everything in this file\n#if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB\n\n#include \"py/mpstate.h\"\n#include \"py/persistentcode.h\"\n#include \"py/mphal.h\"\n#include \"py/asmthumb.h\"\n\n#define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32)\n#define UNSIGNED_FIT7(x) ((uint32_t)(x) < 128)\n#define UNSIGNED_FIT8(x) (((x) & 0xffffff00) == 0)\n#define UNSIGNED_FIT16(x) (((x) & 0xffff0000) == 0)\n#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)\n#define SIGNED_FIT9(x) (((x) & 0xffffff00) == 0) || (((x) & 0xffffff00) == 0xffffff00)\n#define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)\n#define SIGNED_FIT23(x) (((x) & 0xffc00000) == 0) || (((x) & 0xffc00000) == 0xffc00000)\n\n// Note: these actually take an imm12 but the high-bit is not encoded here\n#define OP_ADD_W_RRI_HI(reg_src) (0xf200 | (reg_src))\n#define OP_ADD_W_RRI_LO(reg_dest, imm11) ((imm11 << 4 & 0x7000) | reg_dest << 8 | (imm11 & 0xff))\n#define OP_SUB_W_RRI_HI(reg_src) (0xf2a0 | (reg_src))\n#define OP_SUB_W_RRI_LO(reg_dest, imm11) ((imm11 << 4 & 0x7000) | reg_dest << 8 | (imm11 & 0xff))\n\n#define OP_LDR_W_HI(reg_base) (0xf8d0 | (reg_base))\n#define OP_LDR_W_LO(reg_dest, imm12) ((reg_dest) << 12 | (imm12))\n\nstatic inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) {\n    return mp_asm_base_get_cur_to_write_bytes(&as->base, n);\n}\n\nvoid asm_thumb_end_pass(asm_thumb_t *as) {\n    (void)as;\n    // could check labels are resolved...\n\n    #if __ICACHE_PRESENT == 1\n    if (as->base.pass == MP_ASM_PASS_EMIT) {\n        // flush D-cache, so the code emitted is stored in memory\n        MP_HAL_CLEAN_DCACHE(as->base.code_base, as->base.code_size);\n        // invalidate I-cache\n        SCB_InvalidateICache();\n    }\n    #endif\n}\n\n/*\nSTATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) {\n    byte *c = asm_thumb_get_cur_to_write_bytes(as, 1);\n    c[0] = b1;\n}\n*/\n\n/*\n#define IMM32_L0(x) ((x) & 0xff)\n#define IMM32_L1(x) (((x) >> 8) & 0xff)\n#define IMM32_L2(x) (((x) >> 16) & 0xff)\n#define IMM32_L3(x) (((x) >> 24) & 0xff)\n\nSTATIC void asm_thumb_write_word32(asm_thumb_t *as, int w32) {\n    byte *c = asm_thumb_get_cur_to_write_bytes(as, 4);\n    c[0] = IMM32_L0(w32);\n    c[1] = IMM32_L1(w32);\n    c[2] = IMM32_L2(w32);\n    c[3] = IMM32_L3(w32);\n}\n*/\n\n// rlolist is a bit map indicating desired lo-registers\n#define OP_PUSH_RLIST(rlolist)      (0xb400 | (rlolist))\n#define OP_PUSH_RLIST_LR(rlolist)   (0xb400 | 0x0100 | (rlolist))\n#define OP_POP_RLIST(rlolist)       (0xbc00 | (rlolist))\n#define OP_POP_RLIST_PC(rlolist)    (0xbc00 | 0x0100 | (rlolist))\n\n// The number of words must fit in 7 unsigned bits\n#define OP_ADD_SP(num_words) (0xb000 | (num_words))\n#define OP_SUB_SP(num_words) (0xb080 | (num_words))\n\n// locals:\n//  - stored on the stack in ascending order\n//  - numbered 0 through num_locals-1\n//  - SP points to first local\n//\n//  | SP\n//  v\n//  l0  l1  l2  ...  l(n-1)\n//  ^                ^\n//  | low address    | high address in RAM\n\nvoid asm_thumb_entry(asm_thumb_t *as, int num_locals) {\n    assert(num_locals >= 0);\n\n    // If this Thumb machine code is run from ARM state then add a prelude\n    // to switch to Thumb state for the duration of the function.\n    #if MICROPY_DYNAMIC_COMPILER || MICROPY_EMIT_ARM || (defined(__arm__) && !defined(__thumb2__))\n    #if MICROPY_DYNAMIC_COMPILER\n    if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_ARMV6)\n    #endif\n    {\n        asm_thumb_op32(as, 0x4010, 0xe92d); // push {r4, lr}\n        asm_thumb_op32(as, 0xe009, 0xe28f); // add lr, pc, 8 + 1\n        asm_thumb_op32(as, 0xff3e, 0xe12f); // blx lr\n        asm_thumb_op32(as, 0x4010, 0xe8bd); // pop {r4, lr}\n        asm_thumb_op32(as, 0xff1e, 0xe12f); // bx lr\n    }\n    #endif\n\n    // work out what to push and how many extra spaces to reserve on stack\n    // so that we have enough for all locals and it's aligned an 8-byte boundary\n    // we push extra regs (r1, r2, r3) to help do the stack adjustment\n    // we probably should just always subtract from sp, since this would be more efficient\n    // for push rlist, lowest numbered register at the lowest address\n    uint reglist;\n    uint stack_adjust;\n    // don't pop r0 because it's used for return value\n    switch (num_locals) {\n        case 0:\n            reglist = 0xf2;\n            stack_adjust = 0;\n            break;\n\n        case 1:\n            reglist = 0xf2;\n            stack_adjust = 0;\n            break;\n\n        case 2:\n            reglist = 0xfe;\n            stack_adjust = 0;\n            break;\n\n        case 3:\n            reglist = 0xfe;\n            stack_adjust = 0;\n            break;\n\n        default:\n            reglist = 0xfe;\n            stack_adjust = ((num_locals - 3) + 1) & (~1);\n            break;\n    }\n    asm_thumb_op16(as, OP_PUSH_RLIST_LR(reglist));\n    if (stack_adjust > 0) {\n        if (UNSIGNED_FIT7(stack_adjust)) {\n            asm_thumb_op16(as, OP_SUB_SP(stack_adjust));\n        } else {\n            asm_thumb_op32(as, OP_SUB_W_RRI_HI(ASM_THUMB_REG_SP), OP_SUB_W_RRI_LO(ASM_THUMB_REG_SP, stack_adjust * 4));\n        }\n    }\n    as->push_reglist = reglist;\n    as->stack_adjust = stack_adjust;\n}\n\nvoid asm_thumb_exit(asm_thumb_t *as) {\n    if (as->stack_adjust > 0) {\n        if (UNSIGNED_FIT7(as->stack_adjust)) {\n            asm_thumb_op16(as, OP_ADD_SP(as->stack_adjust));\n        } else {\n            asm_thumb_op32(as, OP_ADD_W_RRI_HI(ASM_THUMB_REG_SP), OP_ADD_W_RRI_LO(ASM_THUMB_REG_SP, as->stack_adjust * 4));\n        }\n    }\n    asm_thumb_op16(as, OP_POP_RLIST_PC(as->push_reglist));\n}\n\nSTATIC mp_uint_t get_label_dest(asm_thumb_t *as, uint label) {\n    assert(label < as->base.max_num_labels);\n    return as->base.label_offsets[label];\n}\n\nvoid asm_thumb_op16(asm_thumb_t *as, uint op) {\n    byte *c = asm_thumb_get_cur_to_write_bytes(as, 2);\n    if (c != NULL) {\n        // little endian\n        c[0] = op;\n        c[1] = op >> 8;\n    }\n}\n\nvoid asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2) {\n    byte *c = asm_thumb_get_cur_to_write_bytes(as, 4);\n    if (c != NULL) {\n        // little endian, op1 then op2\n        c[0] = op1;\n        c[1] = op1 >> 8;\n        c[2] = op2;\n        c[3] = op2 >> 8;\n    }\n}\n\n#define OP_FORMAT_4(op, rlo_dest, rlo_src) ((op) | ((rlo_src) << 3) | (rlo_dest))\n\nvoid asm_thumb_format_4(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src) {\n    assert(rlo_dest < ASM_THUMB_REG_R8);\n    assert(rlo_src < ASM_THUMB_REG_R8);\n    asm_thumb_op16(as, OP_FORMAT_4(op, rlo_dest, rlo_src));\n}\n\nvoid asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) {\n    uint op_lo;\n    if (reg_src < 8) {\n        op_lo = reg_src << 3;\n    } else {\n        op_lo = 0x40 | ((reg_src - 8) << 3);\n    }\n    if (reg_dest < 8) {\n        op_lo |= reg_dest;\n    } else {\n        op_lo |= 0x80 | (reg_dest - 8);\n    }\n    // mov reg_dest, reg_src\n    asm_thumb_op16(as, 0x4600 | op_lo);\n}\n\n// if loading lo half with movw, the i16 value will be zero extended into the r32 register!\nsize_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src) {\n    assert(reg_dest < ASM_THUMB_REG_R15);\n    size_t loc = mp_asm_base_get_code_pos(&as->base);\n    // mov[wt] reg_dest, #i16_src\n    asm_thumb_op32(as, mov_op | ((i16_src >> 1) & 0x0400) | ((i16_src >> 12) & 0xf), ((i16_src << 4) & 0x7000) | (reg_dest << 8) | (i16_src & 0xff));\n    return loc;\n}\n\n#define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff))\n\nbool asm_thumb_b_n_label(asm_thumb_t *as, uint label) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction\n    asm_thumb_op16(as, OP_B_N(rel));\n    return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT12(rel);\n}\n\n#define OP_BCC_N(cond, byte_offset) (0xd000 | ((cond) << 8) | (((byte_offset) >> 1) & 0x00ff))\n\n// all these bit arithmetics need coverage testing!\n#define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 14) & 0x003f))\n#define OP_BCC_W_LO(byte_offset) (0x8000 | ((byte_offset) & 0x2000) | (((byte_offset) >> 1) & 0x0fff))\n\nbool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction\n    if (!wide) {\n        asm_thumb_op16(as, OP_BCC_N(cond, rel));\n        return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT9(rel);\n    } else {\n        asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel));\n        return true;\n    }\n}\n\n#define OP_BL_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff))\n#define OP_BL_LO(byte_offset) (0xf800 | (((byte_offset) >> 1) & 0x07ff))\n\nbool asm_thumb_bl_label(asm_thumb_t *as, uint label) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction\n    asm_thumb_op32(as, OP_BL_HI(rel), OP_BL_LO(rel));\n    return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT23(rel);\n}\n\nsize_t asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) {\n    // movw, movt does it in 8 bytes\n    // ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw\n\n    size_t loc = mp_asm_base_get_code_pos(&as->base);\n\n    asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32);\n    asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVT, reg_dest, i32 >> 16);\n\n    return loc;\n}\n\nvoid asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) {\n    if (reg_dest < 8 && UNSIGNED_FIT8(i32)) {\n        asm_thumb_mov_rlo_i8(as, reg_dest, i32);\n    } else if (UNSIGNED_FIT16(i32)) {\n        asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32);\n    } else {\n        asm_thumb_mov_reg_i32(as, reg_dest, i32);\n    }\n}\n\n#define OP_STR_TO_SP_OFFSET(rlo_dest, word_offset) (0x9000 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))\n#define OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset) (0x9800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))\n\nvoid asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num, uint rlo_src) {\n    assert(rlo_src < ASM_THUMB_REG_R8);\n    int word_offset = local_num;\n    assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0);\n    asm_thumb_op16(as, OP_STR_TO_SP_OFFSET(rlo_src, word_offset));\n}\n\nvoid asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) {\n    assert(rlo_dest < ASM_THUMB_REG_R8);\n    int word_offset = local_num;\n    assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0);\n    asm_thumb_op16(as, OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset));\n}\n\n#define OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset) (0xa800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))\n\nvoid asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) {\n    assert(rlo_dest < ASM_THUMB_REG_R8);\n    int word_offset = local_num;\n    assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0);\n    asm_thumb_op16(as, OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset));\n}\n\nvoid asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    rel -= 4 + 4; // adjust for mov_reg_i16 and then PC+4 prefetch of add_reg_reg\n    rel |= 1; // to stay in Thumb state when jumping to this address\n    asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, rlo_dest, rel); // 4 bytes\n    asm_thumb_add_reg_reg(as, rlo_dest, ASM_THUMB_REG_R15); // 2 bytes\n}\n\nstatic inline void asm_thumb_ldr_reg_reg_i12(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) {\n    asm_thumb_op32(as, OP_LDR_W_HI(reg_base), OP_LDR_W_LO(reg_dest, word_offset * 4));\n}\n\nvoid asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) {\n    if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 && UNSIGNED_FIT5(word_offset)) {\n        asm_thumb_ldr_rlo_rlo_i5(as, reg_dest, reg_base, word_offset);\n    } else {\n        asm_thumb_ldr_reg_reg_i12(as, reg_dest, reg_base, word_offset);\n    }\n}\n\n// this could be wrong, because it should have a range of +/- 16MiB...\n#define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff))\n#define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff))\n\nvoid asm_thumb_b_label(asm_thumb_t *as, uint label) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction\n    if (dest != (mp_uint_t)-1 && rel <= -4) {\n        // is a backwards jump, so we know the size of the jump on the first pass\n        // calculate rel assuming 12 bit relative jump\n        if (SIGNED_FIT12(rel)) {\n            asm_thumb_op16(as, OP_B_N(rel));\n        } else {\n            goto large_jump;\n        }\n    } else {\n        // is a forwards jump, so need to assume it's large\n    large_jump:\n        asm_thumb_op32(as, OP_BW_HI(rel), OP_BW_LO(rel));\n    }\n}\n\nvoid asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction\n    if (dest != (mp_uint_t)-1 && rel <= -4) {\n        // is a backwards jump, so we know the size of the jump on the first pass\n        // calculate rel assuming 9 bit relative jump\n        if (SIGNED_FIT9(rel)) {\n            asm_thumb_op16(as, OP_BCC_N(cond, rel));\n        } else {\n            goto large_jump;\n        }\n    } else {\n        // is a forwards jump, so need to assume it's large\n    large_jump:\n        asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel));\n    }\n}\n\n#define OP_BLX(reg) (0x4780 | ((reg) << 3))\n#define OP_SVC(arg) (0xdf00 | (arg))\n\nvoid asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp) {\n    // Load ptr to function from table, indexed by fun_id, then call it\n    asm_thumb_ldr_reg_reg_i12_optimised(as, reg_temp, ASM_THUMB_REG_FUN_TABLE, fun_id);\n    asm_thumb_op16(as, OP_BLX(reg_temp));\n}\n\n#endif // MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB\n"
  },
  {
    "path": "py/asmthumb.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_ASMTHUMB_H\n#define MICROPY_INCLUDED_PY_ASMTHUMB_H\n\n#include <assert.h>\n#include \"py/misc.h\"\n#include \"py/asmbase.h\"\n\n#define ASM_THUMB_REG_R0  (0)\n#define ASM_THUMB_REG_R1  (1)\n#define ASM_THUMB_REG_R2  (2)\n#define ASM_THUMB_REG_R3  (3)\n#define ASM_THUMB_REG_R4  (4)\n#define ASM_THUMB_REG_R5  (5)\n#define ASM_THUMB_REG_R6  (6)\n#define ASM_THUMB_REG_R7  (7)\n#define ASM_THUMB_REG_R8  (8)\n#define ASM_THUMB_REG_R9  (9)\n#define ASM_THUMB_REG_R10 (10)\n#define ASM_THUMB_REG_R11 (11)\n#define ASM_THUMB_REG_R12 (12)\n#define ASM_THUMB_REG_R13 (13)\n#define ASM_THUMB_REG_R14 (14)\n#define ASM_THUMB_REG_R15 (15)\n#define ASM_THUMB_REG_SP  (ASM_THUMB_REG_R13)\n#define ASM_THUMB_REG_LR  (REG_R14)\n\n#define ASM_THUMB_CC_EQ (0x0)\n#define ASM_THUMB_CC_NE (0x1)\n#define ASM_THUMB_CC_CS (0x2)\n#define ASM_THUMB_CC_CC (0x3)\n#define ASM_THUMB_CC_MI (0x4)\n#define ASM_THUMB_CC_PL (0x5)\n#define ASM_THUMB_CC_VS (0x6)\n#define ASM_THUMB_CC_VC (0x7)\n#define ASM_THUMB_CC_HI (0x8)\n#define ASM_THUMB_CC_LS (0x9)\n#define ASM_THUMB_CC_GE (0xa)\n#define ASM_THUMB_CC_LT (0xb)\n#define ASM_THUMB_CC_GT (0xc)\n#define ASM_THUMB_CC_LE (0xd)\n\ntypedef struct _asm_thumb_t {\n    mp_asm_base_t base;\n    uint32_t push_reglist;\n    uint32_t stack_adjust;\n} asm_thumb_t;\n\nvoid asm_thumb_end_pass(asm_thumb_t *as);\n\nvoid asm_thumb_entry(asm_thumb_t *as, int num_locals);\nvoid asm_thumb_exit(asm_thumb_t *as);\n\n// argument order follows ARM, in general dest is first\n// note there is a difference between movw and mov.w, and many others!\n\n#define ASM_THUMB_OP_IT (0xbf00)\n#define ASM_THUMB_OP_ITE_EQ (0xbf0c)\n#define ASM_THUMB_OP_ITE_NE (0xbf14)\n#define ASM_THUMB_OP_ITE_CS (0xbf2c)\n#define ASM_THUMB_OP_ITE_CC (0xbf34)\n#define ASM_THUMB_OP_ITE_MI (0xbf4c)\n#define ASM_THUMB_OP_ITE_PL (0xbf54)\n#define ASM_THUMB_OP_ITE_VS (0xbf6c)\n#define ASM_THUMB_OP_ITE_VC (0xbf74)\n#define ASM_THUMB_OP_ITE_HI (0xbf8c)\n#define ASM_THUMB_OP_ITE_LS (0xbf94)\n#define ASM_THUMB_OP_ITE_GE (0xbfac)\n#define ASM_THUMB_OP_ITE_LT (0xbfb4)\n#define ASM_THUMB_OP_ITE_GT (0xbfcc)\n#define ASM_THUMB_OP_ITE_LE (0xbfd4)\n\n#define ASM_THUMB_OP_NOP        (0xbf00)\n#define ASM_THUMB_OP_WFI        (0xbf30)\n#define ASM_THUMB_OP_CPSID_I    (0xb672) // cpsid i, disable irq\n#define ASM_THUMB_OP_CPSIE_I    (0xb662) // cpsie i, enable irq\n\nvoid asm_thumb_op16(asm_thumb_t *as, uint op);\nvoid asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2);\n\nstatic inline void asm_thumb_it_cc(asm_thumb_t *as, uint cc, uint mask) {\n    asm_thumb_op16(as, ASM_THUMB_OP_IT | (cc << 4) | mask);\n}\n\n// FORMAT 1: move shifted register\n\n#define ASM_THUMB_FORMAT_1_LSL (0x0000)\n#define ASM_THUMB_FORMAT_1_LSR (0x0800)\n#define ASM_THUMB_FORMAT_1_ASR (0x1000)\n\n#define ASM_THUMB_FORMAT_1_ENCODE(op, rlo_dest, rlo_src, offset) \\\n    ((op) | ((offset) << 6) | ((rlo_src) << 3) | (rlo_dest))\n\nstatic inline void asm_thumb_format_1(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src, uint offset) {\n    assert(rlo_dest < ASM_THUMB_REG_R8);\n    assert(rlo_src < ASM_THUMB_REG_R8);\n    asm_thumb_op16(as, ASM_THUMB_FORMAT_1_ENCODE(op, rlo_dest, rlo_src, offset));\n}\n\n// FORMAT 2: add/subtract\n\n#define ASM_THUMB_FORMAT_2_ADD (0x1800)\n#define ASM_THUMB_FORMAT_2_SUB (0x1a00)\n#define ASM_THUMB_FORMAT_2_REG_OPERAND (0x0000)\n#define ASM_THUMB_FORMAT_2_IMM_OPERAND (0x0400)\n\n#define ASM_THUMB_FORMAT_2_ENCODE(op, rlo_dest, rlo_src, src_b) \\\n    ((op) | ((src_b) << 6) | ((rlo_src) << 3) | (rlo_dest))\n\nstatic inline void asm_thumb_format_2(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src, int src_b) {\n    assert(rlo_dest < ASM_THUMB_REG_R8);\n    assert(rlo_src < ASM_THUMB_REG_R8);\n    asm_thumb_op16(as, ASM_THUMB_FORMAT_2_ENCODE(op, rlo_dest, rlo_src, src_b));\n}\n\nstatic inline void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {\n    asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_ADD | ASM_THUMB_FORMAT_2_REG_OPERAND, rlo_dest, rlo_src_a, rlo_src_b);\n}\nstatic inline void asm_thumb_add_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, int i3_src) {\n    asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_ADD | ASM_THUMB_FORMAT_2_IMM_OPERAND, rlo_dest, rlo_src_a, i3_src);\n}\nstatic inline void asm_thumb_sub_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {\n    asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_SUB | ASM_THUMB_FORMAT_2_REG_OPERAND, rlo_dest, rlo_src_a, rlo_src_b);\n}\nstatic inline void asm_thumb_sub_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, int i3_src) {\n    asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_SUB | ASM_THUMB_FORMAT_2_IMM_OPERAND, rlo_dest, rlo_src_a, i3_src);\n}\n\n// FORMAT 3: move/compare/add/subtract immediate\n// These instructions all do zero extension of the i8 value\n\n#define ASM_THUMB_FORMAT_3_MOV (0x2000)\n#define ASM_THUMB_FORMAT_3_CMP (0x2800)\n#define ASM_THUMB_FORMAT_3_ADD (0x3000)\n#define ASM_THUMB_FORMAT_3_SUB (0x3800)\n\n#define ASM_THUMB_FORMAT_3_ENCODE(op, rlo, i8) ((op) | ((rlo) << 8) | (i8))\n\nstatic inline void asm_thumb_format_3(asm_thumb_t *as, uint op, uint rlo, int i8) {\n    assert(rlo < ASM_THUMB_REG_R8);\n    asm_thumb_op16(as, ASM_THUMB_FORMAT_3_ENCODE(op, rlo, i8));\n}\n\nstatic inline void asm_thumb_mov_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {\n    asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_MOV, rlo, i8);\n}\nstatic inline void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {\n    asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_CMP, rlo, i8);\n}\nstatic inline void asm_thumb_add_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {\n    asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_ADD, rlo, i8);\n}\nstatic inline void asm_thumb_sub_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {\n    asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_SUB, rlo, i8);\n}\n\n// FORMAT 4: ALU operations\n\n#define ASM_THUMB_FORMAT_4_AND (0x4000)\n#define ASM_THUMB_FORMAT_4_EOR (0x4040)\n#define ASM_THUMB_FORMAT_4_LSL (0x4080)\n#define ASM_THUMB_FORMAT_4_LSR (0x40c0)\n#define ASM_THUMB_FORMAT_4_ASR (0x4100)\n#define ASM_THUMB_FORMAT_4_ADC (0x4140)\n#define ASM_THUMB_FORMAT_4_SBC (0x4180)\n#define ASM_THUMB_FORMAT_4_ROR (0x41c0)\n#define ASM_THUMB_FORMAT_4_TST (0x4200)\n#define ASM_THUMB_FORMAT_4_NEG (0x4240)\n#define ASM_THUMB_FORMAT_4_CMP (0x4280)\n#define ASM_THUMB_FORMAT_4_CMN (0x42c0)\n#define ASM_THUMB_FORMAT_4_ORR (0x4300)\n#define ASM_THUMB_FORMAT_4_MUL (0x4340)\n#define ASM_THUMB_FORMAT_4_BIC (0x4380)\n#define ASM_THUMB_FORMAT_4_MVN (0x43c0)\n\nvoid asm_thumb_format_4(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src);\n\nstatic inline void asm_thumb_cmp_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src) {\n    asm_thumb_format_4(as, ASM_THUMB_FORMAT_4_CMP, rlo_dest, rlo_src);\n}\n\n// FORMAT 5: hi register operations (add, cmp, mov, bx)\n// For add/cmp/mov, at least one of the args must be a high register\n\n#define ASM_THUMB_FORMAT_5_ADD (0x4400)\n#define ASM_THUMB_FORMAT_5_BX (0x4700)\n\n#define ASM_THUMB_FORMAT_5_ENCODE(op, r_dest, r_src) \\\n    ((op) | ((r_dest) << 4 & 0x0080) | ((r_src) << 3) | ((r_dest) & 0x0007))\n\nstatic inline void asm_thumb_format_5(asm_thumb_t *as, uint op, uint r_dest, uint r_src) {\n    asm_thumb_op16(as, ASM_THUMB_FORMAT_5_ENCODE(op, r_dest, r_src));\n}\n\nstatic inline void asm_thumb_add_reg_reg(asm_thumb_t *as, uint r_dest, uint r_src) {\n    asm_thumb_format_5(as, ASM_THUMB_FORMAT_5_ADD, r_dest, r_src);\n}\nstatic inline void asm_thumb_bx_reg(asm_thumb_t *as, uint r_src) {\n    asm_thumb_format_5(as, ASM_THUMB_FORMAT_5_BX, 0, r_src);\n}\n\n// FORMAT 9: load/store with immediate offset\n// For word transfers the offset must be aligned, and >>2\n\n// FORMAT 10: load/store halfword\n// The offset must be aligned, and >>1\n// The load is zero extended into the register\n\n#define ASM_THUMB_FORMAT_9_STR (0x6000)\n#define ASM_THUMB_FORMAT_9_LDR (0x6800)\n#define ASM_THUMB_FORMAT_9_WORD_TRANSFER (0x0000)\n#define ASM_THUMB_FORMAT_9_BYTE_TRANSFER (0x1000)\n\n#define ASM_THUMB_FORMAT_10_STRH (0x8000)\n#define ASM_THUMB_FORMAT_10_LDRH (0x8800)\n\n#define ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset) \\\n    ((op) | (((offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))\n\nstatic inline void asm_thumb_format_9_10(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_base, uint offset) {\n    asm_thumb_op16(as, ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset));\n}\n\nstatic inline void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset) {\n    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_src, rlo_base, word_offset);\n}\nstatic inline void asm_thumb_strb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) {\n    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_src, rlo_base, byte_offset);\n}\nstatic inline void asm_thumb_strh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) {\n    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_STRH, rlo_src, rlo_base, byte_offset);\n}\nstatic inline void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset) {\n    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_dest, rlo_base, word_offset);\n}\nstatic inline void asm_thumb_ldrb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) {\n    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_dest, rlo_base, byte_offset);\n}\nstatic inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) {\n    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_LDRH, rlo_dest, rlo_base, byte_offset);\n}\n\n// TODO convert these to above format style\n\n#define ASM_THUMB_OP_MOVW (0xf240)\n#define ASM_THUMB_OP_MOVT (0xf2c0)\n\nvoid asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src);\nsize_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src);\n\n// these return true if the destination is in range, false otherwise\nbool asm_thumb_b_n_label(asm_thumb_t *as, uint label);\nbool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide);\nbool asm_thumb_bl_label(asm_thumb_t *as, uint label);\n\nsize_t asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience\nvoid asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience\nvoid asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); // convenience\nvoid asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience\nvoid asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience\nvoid asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label);\n\nvoid asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint byte_offset); // convenience\n\nvoid asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience: picks narrow or wide branch\nvoid asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch\nvoid asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp); // convenience\n\n// Holds a pointer to mp_fun_table\n#define ASM_THUMB_REG_FUN_TABLE ASM_THUMB_REG_R7\n\n#if GENERIC_ASM_API\n\n// The following macros provide a (mostly) arch-independent API to\n// generate native code, and are used by the native emitter.\n\n#define ASM_WORD_SIZE (4)\n\n#define REG_RET ASM_THUMB_REG_R0\n#define REG_ARG_1 ASM_THUMB_REG_R0\n#define REG_ARG_2 ASM_THUMB_REG_R1\n#define REG_ARG_3 ASM_THUMB_REG_R2\n#define REG_ARG_4 ASM_THUMB_REG_R3\n// rest of args go on stack\n\n#define REG_TEMP0 ASM_THUMB_REG_R0\n#define REG_TEMP1 ASM_THUMB_REG_R1\n#define REG_TEMP2 ASM_THUMB_REG_R2\n\n#define REG_LOCAL_1 ASM_THUMB_REG_R4\n#define REG_LOCAL_2 ASM_THUMB_REG_R5\n#define REG_LOCAL_3 ASM_THUMB_REG_R6\n#define REG_LOCAL_NUM (3)\n\n#define REG_FUN_TABLE ASM_THUMB_REG_FUN_TABLE\n\n#define ASM_T               asm_thumb_t\n#define ASM_END_PASS        asm_thumb_end_pass\n#define ASM_ENTRY           asm_thumb_entry\n#define ASM_EXIT            asm_thumb_exit\n\n#define ASM_JUMP            asm_thumb_b_label\n#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \\\n    do { \\\n        asm_thumb_cmp_rlo_i8(as, reg, 0); \\\n        asm_thumb_bcc_label(as, ASM_THUMB_CC_EQ, label); \\\n    } while (0)\n#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \\\n    do { \\\n        asm_thumb_cmp_rlo_i8(as, reg, 0); \\\n        asm_thumb_bcc_label(as, ASM_THUMB_CC_NE, label); \\\n    } while (0)\n#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \\\n    do { \\\n        asm_thumb_cmp_rlo_rlo(as, reg1, reg2); \\\n        asm_thumb_bcc_label(as, ASM_THUMB_CC_EQ, label); \\\n    } while (0)\n#define ASM_JUMP_REG(as, reg) asm_thumb_bx_reg((as), (reg))\n#define ASM_CALL_IND(as, idx) asm_thumb_bl_ind(as, idx, ASM_THUMB_REG_R3)\n\n#define ASM_MOV_LOCAL_REG(as, local_num, reg) asm_thumb_mov_local_reg((as), (local_num), (reg))\n#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_optimised((as), (reg_dest), (imm))\n#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_thumb_mov_reg_i16((as), ASM_THUMB_OP_MOVW, (reg_dest), (imm))\n#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_thumb_mov_reg_i32((as), (reg_dest), (imm))\n#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_thumb_mov_reg_local((as), (reg_dest), (local_num))\n#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src))\n#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_thumb_mov_reg_local_addr((as), (reg_dest), (local_num))\n#define ASM_MOV_REG_PCREL(as, rlo_dest, label) asm_thumb_mov_reg_pcrel((as), (rlo_dest), (label))\n\n#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSL, (reg_dest), (reg_shift))\n#define ASM_LSR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSR, (reg_dest), (reg_shift))\n#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ASR, (reg_dest), (reg_shift))\n#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ORR, (reg_dest), (reg_src))\n#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_EOR, (reg_dest), (reg_src))\n#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_AND, (reg_dest), (reg_src))\n#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_thumb_add_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_thumb_sub_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_MUL, (reg_dest), (reg_src))\n\n#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), 0)\n#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_thumb_ldr_reg_reg_i12_optimised((as), (reg_dest), (reg_base), (word_offset))\n#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrb_rlo_rlo_i5((as), (reg_dest), (reg_base), 0)\n#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrh_rlo_rlo_i5((as), (reg_dest), (reg_base), 0)\n#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), 0)\n\n#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0)\n#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))\n#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_thumb_strb_rlo_rlo_i5((as), (reg_src), (reg_base), 0)\n#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_thumb_strh_rlo_rlo_i5((as), (reg_src), (reg_base), 0)\n#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0)\n\n#endif // GENERIC_ASM_API\n\n#endif // MICROPY_INCLUDED_PY_ASMTHUMB_H\n"
  },
  {
    "path": "py/asmx64.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <assert.h>\n#include <string.h>\n\n#include \"py/mpconfig.h\"\n\n// wrapper around everything in this file\n#if MICROPY_EMIT_X64\n\n#include \"py/asmx64.h\"\n\n/* all offsets are measured in multiples of 8 bytes */\n#define WORD_SIZE                (8)\n\n#define OPCODE_NOP               (0x90)\n#define OPCODE_PUSH_R64          (0x50) /* +rq */\n#define OPCODE_PUSH_I64          (0x68)\n#define OPCODE_PUSH_M64          (0xff) /* /6 */\n#define OPCODE_POP_R64           (0x58) /* +rq */\n#define OPCODE_RET               (0xc3)\n#define OPCODE_MOV_I8_TO_R8      (0xb0) /* +rb */\n#define OPCODE_MOV_I64_TO_R64    (0xb8) /* +rq */\n#define OPCODE_MOV_I32_TO_RM32   (0xc7)\n#define OPCODE_MOV_R8_TO_RM8     (0x88) /* /r */\n#define OPCODE_MOV_R64_TO_RM64   (0x89) /* /r */\n#define OPCODE_MOV_RM64_TO_R64   (0x8b) /* /r */\n#define OPCODE_MOVZX_RM8_TO_R64  (0xb6) /* 0x0f 0xb6/r */\n#define OPCODE_MOVZX_RM16_TO_R64 (0xb7) /* 0x0f 0xb7/r */\n#define OPCODE_LEA_MEM_TO_R64    (0x8d) /* /r */\n#define OPCODE_AND_R64_TO_RM64   (0x21) /* /r */\n#define OPCODE_OR_R64_TO_RM64    (0x09) /* /r */\n#define OPCODE_XOR_R64_TO_RM64   (0x31) /* /r */\n#define OPCODE_ADD_R64_TO_RM64   (0x01) /* /r */\n#define OPCODE_ADD_I32_TO_RM32   (0x81) /* /0 */\n#define OPCODE_ADD_I8_TO_RM32    (0x83) /* /0 */\n#define OPCODE_SUB_R64_FROM_RM64 (0x29)\n#define OPCODE_SUB_I32_FROM_RM64 (0x81) /* /5 */\n#define OPCODE_SUB_I8_FROM_RM64  (0x83) /* /5 */\n// #define OPCODE_SHL_RM32_BY_I8    (0xc1) /* /4 */\n// #define OPCODE_SHR_RM32_BY_I8    (0xc1) /* /5 */\n// #define OPCODE_SAR_RM32_BY_I8    (0xc1) /* /7 */\n#define OPCODE_SHL_RM64_CL       (0xd3) /* /4 */\n#define OPCODE_SHR_RM64_CL       (0xd3) /* /5 */\n#define OPCODE_SAR_RM64_CL       (0xd3) /* /7 */\n// #define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */\n// #define OPCODE_CMP_I8_WITH_RM32  (0x83) /* /7 */\n#define OPCODE_CMP_R64_WITH_RM64 (0x39) /* /r */\n// #define OPCODE_CMP_RM32_WITH_R32 (0x3b)\n#define OPCODE_TEST_R8_WITH_RM8  (0x84) /* /r */\n#define OPCODE_TEST_R64_WITH_RM64 (0x85) /* /r */\n#define OPCODE_JMP_REL8          (0xeb)\n#define OPCODE_JMP_REL32         (0xe9)\n#define OPCODE_JMP_RM64          (0xff) /* /4 */\n#define OPCODE_JCC_REL8          (0x70) /* | jcc type */\n#define OPCODE_JCC_REL32_A       (0x0f)\n#define OPCODE_JCC_REL32_B       (0x80) /* | jcc type */\n#define OPCODE_SETCC_RM8_A       (0x0f)\n#define OPCODE_SETCC_RM8_B       (0x90) /* | jcc type, /0 */\n#define OPCODE_CALL_REL32        (0xe8)\n#define OPCODE_CALL_RM32         (0xff) /* /2 */\n#define OPCODE_LEAVE             (0xc9)\n\n#define MODRM_R64(x)    (((x) & 0x7) << 3)\n#define MODRM_RM_DISP0  (0x00)\n#define MODRM_RM_DISP8  (0x40)\n#define MODRM_RM_DISP32 (0x80)\n#define MODRM_RM_REG    (0xc0)\n#define MODRM_RM_R64(x) ((x) & 0x7)\n\n#define OP_SIZE_PREFIX (0x66)\n\n#define REX_PREFIX  (0x40)\n#define REX_W       (0x08)  // width\n#define REX_R       (0x04)  // register\n#define REX_X       (0x02)  // index\n#define REX_B       (0x01)  // base\n#define REX_W_FROM_R64(r64) ((r64) >> 0 & 0x08)\n#define REX_R_FROM_R64(r64) ((r64) >> 1 & 0x04)\n#define REX_X_FROM_R64(r64) ((r64) >> 2 & 0x02)\n#define REX_B_FROM_R64(r64) ((r64) >> 3 & 0x01)\n\n#define IMM32_L0(x) ((x) & 0xff)\n#define IMM32_L1(x) (((x) >> 8) & 0xff)\n#define IMM32_L2(x) (((x) >> 16) & 0xff)\n#define IMM32_L3(x) (((x) >> 24) & 0xff)\n#define IMM64_L4(x) (((x) >> 32) & 0xff)\n#define IMM64_L5(x) (((x) >> 40) & 0xff)\n#define IMM64_L6(x) (((x) >> 48) & 0xff)\n#define IMM64_L7(x) (((x) >> 56) & 0xff)\n\n#define UNSIGNED_FIT8(x) (((x) & 0xffffffffffffff00) == 0)\n#define UNSIGNED_FIT32(x) (((x) & 0xffffffff00000000) == 0)\n#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)\n\nstatic inline byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int n) {\n    return mp_asm_base_get_cur_to_write_bytes(&as->base, n);\n}\n\nSTATIC void asm_x64_write_byte_1(asm_x64_t *as, byte b1) {\n    byte *c = asm_x64_get_cur_to_write_bytes(as, 1);\n    if (c != NULL) {\n        c[0] = b1;\n    }\n}\n\nSTATIC void asm_x64_write_byte_2(asm_x64_t *as, byte b1, byte b2) {\n    byte *c = asm_x64_get_cur_to_write_bytes(as, 2);\n    if (c != NULL) {\n        c[0] = b1;\n        c[1] = b2;\n    }\n}\n\nSTATIC void asm_x64_write_byte_3(asm_x64_t *as, byte b1, byte b2, byte b3) {\n    byte *c = asm_x64_get_cur_to_write_bytes(as, 3);\n    if (c != NULL) {\n        c[0] = b1;\n        c[1] = b2;\n        c[2] = b3;\n    }\n}\n\nSTATIC void asm_x64_write_word32(asm_x64_t *as, int w32) {\n    byte *c = asm_x64_get_cur_to_write_bytes(as, 4);\n    if (c != NULL) {\n        c[0] = IMM32_L0(w32);\n        c[1] = IMM32_L1(w32);\n        c[2] = IMM32_L2(w32);\n        c[3] = IMM32_L3(w32);\n    }\n}\n\nSTATIC void asm_x64_write_word64(asm_x64_t *as, int64_t w64) {\n    byte *c = asm_x64_get_cur_to_write_bytes(as, 8);\n    if (c != NULL) {\n        c[0] = IMM32_L0(w64);\n        c[1] = IMM32_L1(w64);\n        c[2] = IMM32_L2(w64);\n        c[3] = IMM32_L3(w64);\n        c[4] = IMM64_L4(w64);\n        c[5] = IMM64_L5(w64);\n        c[6] = IMM64_L6(w64);\n        c[7] = IMM64_L7(w64);\n    }\n}\n\n/* unused\nSTATIC void asm_x64_write_word32_to(asm_x64_t *as, int offset, int w32) {\n    byte* c;\n    assert(offset + 4 <= as->code_size);\n    c = as->code_base + offset;\n    c[0] = IMM32_L0(w32);\n    c[1] = IMM32_L1(w32);\n    c[2] = IMM32_L2(w32);\n    c[3] = IMM32_L3(w32);\n}\n*/\n\nSTATIC void asm_x64_write_r64_disp(asm_x64_t *as, int r64, int disp_r64, int disp_offset) {\n    uint8_t rm_disp;\n    if (disp_offset == 0 && (disp_r64 & 7) != ASM_X64_REG_RBP) {\n        rm_disp = MODRM_RM_DISP0;\n    } else if (SIGNED_FIT8(disp_offset)) {\n        rm_disp = MODRM_RM_DISP8;\n    } else {\n        rm_disp = MODRM_RM_DISP32;\n    }\n    asm_x64_write_byte_1(as, MODRM_R64(r64) | rm_disp | MODRM_RM_R64(disp_r64));\n    if ((disp_r64 & 7) == ASM_X64_REG_RSP) {\n        // Special case for rsp and r12, they need a SIB byte\n        asm_x64_write_byte_1(as, 0x24);\n    }\n    if (rm_disp == MODRM_RM_DISP8) {\n        asm_x64_write_byte_1(as, IMM32_L0(disp_offset));\n    } else if (rm_disp == MODRM_RM_DISP32) {\n        asm_x64_write_word32(as, disp_offset);\n    }\n}\n\nSTATIC void asm_x64_generic_r64_r64(asm_x64_t *as, int dest_r64, int src_r64, int op) {\n    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));\n}\n\nvoid asm_x64_nop(asm_x64_t *as) {\n    asm_x64_write_byte_1(as, OPCODE_NOP);\n}\n\nvoid asm_x64_push_r64(asm_x64_t *as, int src_r64) {\n    if (src_r64 < 8) {\n        asm_x64_write_byte_1(as, OPCODE_PUSH_R64 | src_r64);\n    } else {\n        asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_PUSH_R64 | (src_r64 & 7));\n    }\n}\n\n/*\nvoid asm_x64_push_i32(asm_x64_t *as, int src_i32) {\n    asm_x64_write_byte_1(as, OPCODE_PUSH_I64);\n    asm_x64_write_word32(as, src_i32); // will be sign extended to 64 bits\n}\n*/\n\n/*\nvoid asm_x64_push_disp(asm_x64_t *as, int src_r64, int src_offset) {\n    assert(src_r64 < 8);\n    asm_x64_write_byte_1(as, OPCODE_PUSH_M64);\n    asm_x64_write_r64_disp(as, 6, src_r64, src_offset);\n}\n*/\n\nvoid asm_x64_pop_r64(asm_x64_t *as, int dest_r64) {\n    if (dest_r64 < 8) {\n        asm_x64_write_byte_1(as, OPCODE_POP_R64 | dest_r64);\n    } else {\n        asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_POP_R64 | (dest_r64 & 7));\n    }\n}\n\nSTATIC void asm_x64_ret(asm_x64_t *as) {\n    asm_x64_write_byte_1(as, OPCODE_RET);\n}\n\nvoid asm_x64_mov_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {\n    asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_MOV_R64_TO_RM64);\n}\n\nvoid asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {\n    if (src_r64 < 8 && dest_r64 < 8) {\n        asm_x64_write_byte_1(as, OPCODE_MOV_R8_TO_RM8);\n    } else {\n        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);\n    }\n    asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);\n}\n\nvoid asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {\n    if (src_r64 < 8 && dest_r64 < 8) {\n        asm_x64_write_byte_2(as, OP_SIZE_PREFIX, OPCODE_MOV_R64_TO_RM64);\n    } else {\n        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);\n    }\n    asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);\n}\n\nvoid asm_x64_mov_r32_to_mem32(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {\n    if (src_r64 < 8 && dest_r64 < 8) {\n        asm_x64_write_byte_1(as, OPCODE_MOV_R64_TO_RM64);\n    } else {\n        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);\n    }\n    asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);\n}\n\nvoid asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {\n    // use REX prefix for 64 bit operation\n    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);\n    asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);\n}\n\nvoid asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {\n    assert(src_r64 < 8);\n    if (dest_r64 < 8) {\n        asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R64);\n    } else {\n        asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM8_TO_R64);\n    }\n    asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);\n}\n\nvoid asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {\n    assert(src_r64 < 8);\n    if (dest_r64 < 8) {\n        asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R64);\n    } else {\n        asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM16_TO_R64);\n    }\n    asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);\n}\n\nvoid asm_x64_mov_mem32_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {\n    assert(src_r64 < 8);\n    if (dest_r64 < 8) {\n        asm_x64_write_byte_1(as, OPCODE_MOV_RM64_TO_R64);\n    } else {\n        asm_x64_write_byte_2(as, REX_PREFIX | REX_R, OPCODE_MOV_RM64_TO_R64);\n    }\n    asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);\n}\n\nvoid asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {\n    // use REX prefix for 64 bit operation\n    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);\n    asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);\n}\n\nSTATIC void asm_x64_lea_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {\n    // use REX prefix for 64 bit operation\n    assert(src_r64 < 8);\n    assert(dest_r64 < 8);\n    asm_x64_write_byte_2(as, REX_PREFIX | REX_W, OPCODE_LEA_MEM_TO_R64);\n    asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);\n}\n\n/*\nvoid asm_x64_mov_i8_to_r8(asm_x64_t *as, int src_i8, int dest_r64) {\n    assert(dest_r64 < 8);\n    asm_x64_write_byte_2(as, OPCODE_MOV_I8_TO_R8 | dest_r64, src_i8);\n}\n*/\n\nsize_t asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) {\n    // cpu defaults to i32 to r64, with zero extension\n    if (dest_r64 < 8) {\n        asm_x64_write_byte_1(as, OPCODE_MOV_I64_TO_R64 | dest_r64);\n    } else {\n        asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7));\n    }\n    size_t loc = mp_asm_base_get_code_pos(&as->base);\n    asm_x64_write_word32(as, src_i32);\n    return loc;\n}\n\nvoid asm_x64_mov_i64_to_r64(asm_x64_t *as, int64_t src_i64, int dest_r64) {\n    // cpu defaults to i32 to r64\n    // to mov i64 to r64 need to use REX prefix\n    asm_x64_write_byte_2(as,\n        REX_PREFIX | REX_W | (dest_r64 < 8 ? 0 : REX_B),\n        OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7));\n    asm_x64_write_word64(as, src_i64);\n}\n\nvoid asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64) {\n    // TODO use movzx, movsx if possible\n    if (UNSIGNED_FIT32(src_i64)) {\n        // 5 bytes\n        asm_x64_mov_i32_to_r64(as, src_i64 & 0xffffffff, dest_r64);\n    } else {\n        // 10 bytes\n        asm_x64_mov_i64_to_r64(as, src_i64, dest_r64);\n    }\n}\n\nvoid asm_x64_and_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {\n    asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_AND_R64_TO_RM64);\n}\n\nvoid asm_x64_or_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {\n    asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_OR_R64_TO_RM64);\n}\n\nvoid asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {\n    asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_XOR_R64_TO_RM64);\n}\n\nvoid asm_x64_shl_r64_cl(asm_x64_t *as, int dest_r64) {\n    asm_x64_generic_r64_r64(as, dest_r64, 4, OPCODE_SHL_RM64_CL);\n}\n\nvoid asm_x64_shr_r64_cl(asm_x64_t *as, int dest_r64) {\n    asm_x64_generic_r64_r64(as, dest_r64, 5, OPCODE_SHR_RM64_CL);\n}\n\nvoid asm_x64_sar_r64_cl(asm_x64_t *as, int dest_r64) {\n    asm_x64_generic_r64_r64(as, dest_r64, 7, OPCODE_SAR_RM64_CL);\n}\n\nvoid asm_x64_add_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {\n    asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_ADD_R64_TO_RM64);\n}\n\nvoid asm_x64_sub_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {\n    asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_SUB_R64_FROM_RM64);\n}\n\nvoid asm_x64_mul_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {\n    // imul reg64, reg/mem64 -- 0x0f 0xaf /r\n    asm_x64_write_byte_1(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64));\n    asm_x64_write_byte_3(as, 0x0f, 0xaf, MODRM_R64(dest_r64) | MODRM_RM_REG | MODRM_RM_R64(src_r64));\n}\n\n/*\nvoid asm_x64_sub_i32_from_r32(asm_x64_t *as, int src_i32, int dest_r32) {\n    if (SIGNED_FIT8(src_i32)) {\n        // defaults to 32 bit operation\n        asm_x64_write_byte_2(as, OPCODE_SUB_I8_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r32));\n        asm_x64_write_byte_1(as, src_i32 & 0xff);\n    } else {\n        // defaults to 32 bit operation\n        asm_x64_write_byte_2(as, OPCODE_SUB_I32_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r32));\n        asm_x64_write_word32(as, src_i32);\n    }\n}\n*/\n\nSTATIC void asm_x64_sub_r64_i32(asm_x64_t *as, int dest_r64, int src_i32) {\n    assert(dest_r64 < 8);\n    if (SIGNED_FIT8(src_i32)) {\n        // use REX prefix for 64 bit operation\n        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));\n        asm_x64_write_byte_1(as, src_i32 & 0xff);\n    } else {\n        // use REX prefix for 64 bit operation\n        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));\n        asm_x64_write_word32(as, src_i32);\n    }\n}\n\n/*\nvoid asm_x64_shl_r32_by_imm(asm_x64_t *as, int r32, int imm) {\n    asm_x64_write_byte_2(as, OPCODE_SHL_RM32_BY_I8, MODRM_R64(4) | MODRM_RM_REG | MODRM_RM_R64(r32));\n    asm_x64_write_byte_1(as, imm);\n}\n\nvoid asm_x64_shr_r32_by_imm(asm_x64_t *as, int r32, int imm) {\n    asm_x64_write_byte_2(as, OPCODE_SHR_RM32_BY_I8, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(r32));\n    asm_x64_write_byte_1(as, imm);\n}\n\nvoid asm_x64_sar_r32_by_imm(asm_x64_t *as, int r32, int imm) {\n    asm_x64_write_byte_2(as, OPCODE_SAR_RM32_BY_I8, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(r32));\n    asm_x64_write_byte_1(as, imm);\n}\n*/\n\nvoid asm_x64_cmp_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b) {\n    asm_x64_generic_r64_r64(as, src_r64_b, src_r64_a, OPCODE_CMP_R64_WITH_RM64);\n}\n\n/*\nvoid asm_x64_cmp_i32_with_r32(asm_x64_t *as, int src_i32, int src_r32) {\n    if (SIGNED_FIT8(src_i32)) {\n        asm_x64_write_byte_2(as, OPCODE_CMP_I8_WITH_RM32, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(src_r32));\n        asm_x64_write_byte_1(as, src_i32 & 0xff);\n    } else {\n        asm_x64_write_byte_2(as, OPCODE_CMP_I32_WITH_RM32, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(src_r32));\n        asm_x64_write_word32(as, src_i32);\n    }\n}\n*/\n\nvoid asm_x64_test_r8_with_r8(asm_x64_t *as, int src_r64_a, int src_r64_b) {\n    assert(src_r64_a < 8);\n    assert(src_r64_b < 8);\n    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));\n}\n\nvoid asm_x64_test_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b) {\n    asm_x64_generic_r64_r64(as, src_r64_b, src_r64_a, OPCODE_TEST_R64_WITH_RM64);\n}\n\nvoid asm_x64_setcc_r8(asm_x64_t *as, int jcc_type, int dest_r8) {\n    assert(dest_r8 < 8);\n    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));\n}\n\nvoid asm_x64_jmp_reg(asm_x64_t *as, int src_r64) {\n    assert(src_r64 < 8);\n    asm_x64_write_byte_2(as, OPCODE_JMP_RM64, MODRM_R64(4) | MODRM_RM_REG | MODRM_RM_R64(src_r64));\n}\n\nSTATIC mp_uint_t get_label_dest(asm_x64_t *as, mp_uint_t label) {\n    assert(label < as->base.max_num_labels);\n    return as->base.label_offsets[label];\n}\n\nvoid asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    if (dest != (mp_uint_t)-1 && rel < 0) {\n        // is a backwards jump, so we know the size of the jump on the first pass\n        // calculate rel assuming 8 bit relative jump\n        rel -= 2;\n        if (SIGNED_FIT8(rel)) {\n            asm_x64_write_byte_2(as, OPCODE_JMP_REL8, rel & 0xff);\n        } else {\n            rel += 2;\n            goto large_jump;\n        }\n    } else {\n        // is a forwards jump, so need to assume it's large\n    large_jump:\n        rel -= 5;\n        asm_x64_write_byte_1(as, OPCODE_JMP_REL32);\n        asm_x64_write_word32(as, rel);\n    }\n}\n\nvoid asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    if (dest != (mp_uint_t)-1 && rel < 0) {\n        // is a backwards jump, so we know the size of the jump on the first pass\n        // calculate rel assuming 8 bit relative jump\n        rel -= 2;\n        if (SIGNED_FIT8(rel)) {\n            asm_x64_write_byte_2(as, OPCODE_JCC_REL8 | jcc_type, rel & 0xff);\n        } else {\n            rel += 2;\n            goto large_jump;\n        }\n    } else {\n        // is a forwards jump, so need to assume it's large\n    large_jump:\n        rel -= 6;\n        asm_x64_write_byte_2(as, OPCODE_JCC_REL32_A, OPCODE_JCC_REL32_B | jcc_type);\n        asm_x64_write_word32(as, rel);\n    }\n}\n\nvoid asm_x64_entry(asm_x64_t *as, int num_locals) {\n    assert(num_locals >= 0);\n    asm_x64_push_r64(as, ASM_X64_REG_RBP);\n    asm_x64_push_r64(as, ASM_X64_REG_RBX);\n    asm_x64_push_r64(as, ASM_X64_REG_R12);\n    asm_x64_push_r64(as, ASM_X64_REG_R13);\n    num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary\n    asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, num_locals * WORD_SIZE);\n    as->num_locals = num_locals;\n}\n\nvoid asm_x64_exit(asm_x64_t *as) {\n    asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, -as->num_locals * WORD_SIZE);\n    asm_x64_pop_r64(as, ASM_X64_REG_R13);\n    asm_x64_pop_r64(as, ASM_X64_REG_R12);\n    asm_x64_pop_r64(as, ASM_X64_REG_RBX);\n    asm_x64_pop_r64(as, ASM_X64_REG_RBP);\n    asm_x64_ret(as);\n}\n\n// locals:\n//  - stored on the stack in ascending order\n//  - numbered 0 through as->num_locals-1\n//  - RSP points to the first local\n//\n//  | RSP\n//  v\n//  l0  l1  l2  ...  l(n-1)\n//  ^                ^\n//  | low address    | high address in RAM\n//\nSTATIC int asm_x64_local_offset_from_rsp(asm_x64_t *as, int local_num) {\n    (void)as;\n    // Stack is full descending, RSP points to local0\n    return local_num * WORD_SIZE;\n}\n\nvoid asm_x64_mov_local_to_r64(asm_x64_t *as, int src_local_num, int dest_r64) {\n    asm_x64_mov_mem64_to_r64(as, ASM_X64_REG_RSP, asm_x64_local_offset_from_rsp(as, src_local_num), dest_r64);\n}\n\nvoid asm_x64_mov_r64_to_local(asm_x64_t *as, int src_r64, int dest_local_num) {\n    asm_x64_mov_r64_to_mem64(as, src_r64, ASM_X64_REG_RSP, asm_x64_local_offset_from_rsp(as, dest_local_num));\n}\n\nvoid asm_x64_mov_local_addr_to_r64(asm_x64_t *as, int local_num, int dest_r64) {\n    int offset = asm_x64_local_offset_from_rsp(as, local_num);\n    if (offset == 0) {\n        asm_x64_mov_r64_r64(as, dest_r64, ASM_X64_REG_RSP);\n    } else {\n        asm_x64_lea_disp_to_r64(as, ASM_X64_REG_RSP, offset, dest_r64);\n    }\n}\n\nvoid asm_x64_mov_reg_pcrel(asm_x64_t *as, int dest_r64, mp_uint_t label) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - (as->base.code_offset + 7);\n    asm_x64_write_byte_3(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64), OPCODE_LEA_MEM_TO_R64, MODRM_R64(dest_r64) | MODRM_RM_R64(5));\n    asm_x64_write_word32(as, rel);\n}\n\n/*\nvoid asm_x64_push_local(asm_x64_t *as, int local_num) {\n    asm_x64_push_disp(as, ASM_X64_REG_RSP, asm_x64_local_offset_from_rsp(as, local_num));\n}\n\nvoid asm_x64_push_local_addr(asm_x64_t *as, int local_num, int temp_r64) {\n    asm_x64_mov_r64_r64(as, temp_r64, ASM_X64_REG_RSP);\n    asm_x64_add_i32_to_r32(as, asm_x64_local_offset_from_rsp(as, local_num), temp_r64);\n    asm_x64_push_r64(as, temp_r64);\n}\n*/\n\n/*\n   can't use these because code might be relocated when resized\n\nvoid asm_x64_call(asm_x64_t *as, void* func) {\n    asm_x64_sub_i32_from_r32(as, 8, ASM_X64_REG_RSP);\n    asm_x64_write_byte_1(as, OPCODE_CALL_REL32);\n    asm_x64_write_word32(as, func - (void*)(as->code_cur + 4));\n    asm_x64_mov_r64_r64(as, ASM_X64_REG_RSP, ASM_X64_REG_RBP);\n}\n\nvoid asm_x64_call_i1(asm_x64_t *as, void* func, int i1) {\n    asm_x64_sub_i32_from_r32(as, 8, ASM_X64_REG_RSP);\n    asm_x64_sub_i32_from_r32(as, 12, ASM_X64_REG_RSP);\n    asm_x64_push_i32(as, i1);\n    asm_x64_write_byte_1(as, OPCODE_CALL_REL32);\n    asm_x64_write_word32(as, func - (void*)(as->code_cur + 4));\n    asm_x64_add_i32_to_r32(as, 16, ASM_X64_REG_RSP);\n    asm_x64_mov_r64_r64(as, ASM_X64_REG_RSP, ASM_X64_REG_RBP);\n}\n*/\n\nvoid asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r64) {\n    assert(temp_r64 < 8);\n    asm_x64_mov_mem64_to_r64(as, ASM_X64_REG_FUN_TABLE, fun_id * WORD_SIZE, temp_r64);\n    asm_x64_write_byte_2(as, OPCODE_CALL_RM32, MODRM_R64(2) | MODRM_RM_REG | MODRM_RM_R64(temp_r64));\n}\n\n#endif // MICROPY_EMIT_X64\n"
  },
  {
    "path": "py/asmx64.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_ASMX64_H\n#define MICROPY_INCLUDED_PY_ASMX64_H\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n#include \"py/asmbase.h\"\n\n// AMD64 calling convention is:\n//  - args pass in: RDI, RSI, RDX, RCX, R08, R09\n//  - return value in RAX\n//  - stack must be aligned on a 16-byte boundary before all calls\n//  - RAX, RCX, RDX, RSI, RDI, R08, R09, R10, R11 are caller-save\n//  - RBX, RBP, R12, R13, R14, R15 are callee-save\n\n// In the functions below, argument order follows x86 docs and generally\n// the destination is the first argument.\n// NOTE: this is a change from the old convention used in this file and\n// some functions still use the old (reverse) convention.\n\n#define ASM_X64_REG_RAX (0)\n#define ASM_X64_REG_RCX (1)\n#define ASM_X64_REG_RDX (2)\n#define ASM_X64_REG_RBX (3)\n#define ASM_X64_REG_RSP (4)\n#define ASM_X64_REG_RBP (5)\n#define ASM_X64_REG_RSI (6)\n#define ASM_X64_REG_RDI (7)\n#define ASM_X64_REG_R08 (8)\n#define ASM_X64_REG_R09 (9)\n#define ASM_X64_REG_R10 (10)\n#define ASM_X64_REG_R11 (11)\n#define ASM_X64_REG_R12 (12)\n#define ASM_X64_REG_R13 (13)\n#define ASM_X64_REG_R14 (14)\n#define ASM_X64_REG_R15 (15)\n\n// condition codes, used for jcc and setcc (despite their j-name!)\n#define ASM_X64_CC_JB  (0x2) // below, unsigned\n#define ASM_X64_CC_JAE (0x3) // above or equal, unsigned\n#define ASM_X64_CC_JZ  (0x4)\n#define ASM_X64_CC_JE  (0x4)\n#define ASM_X64_CC_JNZ (0x5)\n#define ASM_X64_CC_JNE (0x5)\n#define ASM_X64_CC_JBE (0x6) // below or equal, unsigned\n#define ASM_X64_CC_JA  (0x7) // above, unsigned\n#define ASM_X64_CC_JL  (0xc) // less, signed\n#define ASM_X64_CC_JGE (0xd) // greater or equal, signed\n#define ASM_X64_CC_JLE (0xe) // less or equal, signed\n#define ASM_X64_CC_JG  (0xf) // greater, signed\n\ntypedef struct _asm_x64_t {\n    mp_asm_base_t base;\n    int num_locals;\n} asm_x64_t;\n\nstatic inline void asm_x64_end_pass(asm_x64_t *as) {\n    (void)as;\n}\n\nvoid asm_x64_nop(asm_x64_t *as);\nvoid asm_x64_push_r64(asm_x64_t *as, int src_r64);\nvoid asm_x64_pop_r64(asm_x64_t *as, int dest_r64);\nvoid asm_x64_mov_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);\nsize_t asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64);\nvoid asm_x64_mov_i64_to_r64(asm_x64_t *as, int64_t src_i64, int dest_r64);\nvoid asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64);\nvoid asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);\nvoid asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);\nvoid asm_x64_mov_r32_to_mem32(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);\nvoid asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);\nvoid asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64);\nvoid asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64);\nvoid asm_x64_mov_mem32_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64);\nvoid asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64);\nvoid asm_x64_and_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);\nvoid asm_x64_or_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);\nvoid asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);\nvoid asm_x64_shl_r64_cl(asm_x64_t *as, int dest_r64);\nvoid asm_x64_shr_r64_cl(asm_x64_t *as, int dest_r64);\nvoid asm_x64_sar_r64_cl(asm_x64_t *as, int dest_r64);\nvoid asm_x64_add_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);\nvoid asm_x64_sub_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);\nvoid asm_x64_mul_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);\nvoid asm_x64_cmp_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b);\nvoid asm_x64_test_r8_with_r8(asm_x64_t *as, int src_r64_a, int src_r64_b);\nvoid asm_x64_test_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b);\nvoid asm_x64_setcc_r8(asm_x64_t *as, int jcc_type, int dest_r8);\nvoid asm_x64_jmp_reg(asm_x64_t *as, int src_r64);\nvoid asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label);\nvoid asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label);\nvoid asm_x64_entry(asm_x64_t *as, int num_locals);\nvoid asm_x64_exit(asm_x64_t *as);\nvoid asm_x64_mov_local_to_r64(asm_x64_t *as, int src_local_num, int dest_r64);\nvoid asm_x64_mov_r64_to_local(asm_x64_t *as, int src_r64, int dest_local_num);\nvoid asm_x64_mov_local_addr_to_r64(asm_x64_t *as, int local_num, int dest_r64);\nvoid asm_x64_mov_reg_pcrel(asm_x64_t *as, int dest_r64, mp_uint_t label);\nvoid asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r32);\n\n// Holds a pointer to mp_fun_table\n#define ASM_X64_REG_FUN_TABLE ASM_X64_REG_RBP\n\n#if GENERIC_ASM_API\n\n// The following macros provide a (mostly) arch-independent API to\n// generate native code, and are used by the native emitter.\n\n#define ASM_WORD_SIZE (8)\n\n#define REG_RET ASM_X64_REG_RAX\n#define REG_ARG_1 ASM_X64_REG_RDI\n#define REG_ARG_2 ASM_X64_REG_RSI\n#define REG_ARG_3 ASM_X64_REG_RDX\n#define REG_ARG_4 ASM_X64_REG_RCX\n#define REG_ARG_5 ASM_X64_REG_R08\n\n// caller-save\n#define REG_TEMP0 ASM_X64_REG_RAX\n#define REG_TEMP1 ASM_X64_REG_RDI\n#define REG_TEMP2 ASM_X64_REG_RSI\n\n// callee-save\n#define REG_LOCAL_1 ASM_X64_REG_RBX\n#define REG_LOCAL_2 ASM_X64_REG_R12\n#define REG_LOCAL_3 ASM_X64_REG_R13\n#define REG_LOCAL_NUM (3)\n\n// Holds a pointer to mp_fun_table\n#define REG_FUN_TABLE ASM_X64_REG_FUN_TABLE\n\n#define ASM_T               asm_x64_t\n#define ASM_END_PASS        asm_x64_end_pass\n#define ASM_ENTRY           asm_x64_entry\n#define ASM_EXIT            asm_x64_exit\n\n#define ASM_JUMP            asm_x64_jmp_label\n#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \\\n    do { \\\n        if (bool_test) { \\\n            asm_x64_test_r8_with_r8((as), (reg), (reg)); \\\n        } else { \\\n            asm_x64_test_r64_with_r64((as), (reg), (reg)); \\\n        } \\\n        asm_x64_jcc_label(as, ASM_X64_CC_JZ, label); \\\n    } while (0)\n#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \\\n    do { \\\n        if (bool_test) { \\\n            asm_x64_test_r8_with_r8((as), (reg), (reg)); \\\n        } else { \\\n            asm_x64_test_r64_with_r64((as), (reg), (reg)); \\\n        } \\\n        asm_x64_jcc_label(as, ASM_X64_CC_JNZ, label); \\\n    } while (0)\n#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \\\n    do { \\\n        asm_x64_cmp_r64_with_r64(as, reg1, reg2); \\\n        asm_x64_jcc_label(as, ASM_X64_CC_JE, label); \\\n    } while (0)\n#define ASM_JUMP_REG(as, reg) asm_x64_jmp_reg((as), (reg))\n#define ASM_CALL_IND(as, idx) asm_x64_call_ind(as, idx, ASM_X64_REG_RAX)\n\n#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x64_mov_r64_to_local((as), (reg_src), (local_num))\n#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x64_mov_i64_to_r64_optimised((as), (imm), (reg_dest))\n#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_x64_mov_i32_to_r64((as), (imm), (reg_dest))\n#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_x64_mov_i32_to_r64((as), (imm), (reg_dest))\n#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x64_mov_local_to_r64((as), (local_num), (reg_dest))\n#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x64_mov_r64_r64((as), (reg_dest), (reg_src))\n#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x64_mov_local_addr_to_r64((as), (local_num), (reg_dest))\n#define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_x64_mov_reg_pcrel((as), (reg_dest), (label))\n\n#define ASM_LSL_REG(as, reg) asm_x64_shl_r64_cl((as), (reg))\n#define ASM_LSR_REG(as, reg) asm_x64_shr_r64_cl((as), (reg))\n#define ASM_ASR_REG(as, reg) asm_x64_sar_r64_cl((as), (reg))\n#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_x64_or_r64_r64((as), (reg_dest), (reg_src))\n#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_x64_xor_r64_r64((as), (reg_dest), (reg_src))\n#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_x64_and_r64_r64((as), (reg_dest), (reg_src))\n#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_x64_add_r64_r64((as), (reg_dest), (reg_src))\n#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x64_sub_r64_r64((as), (reg_dest), (reg_src))\n#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_x64_mul_r64_r64((as), (reg_dest), (reg_src))\n\n#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem64_to_r64((as), (reg_base), 0, (reg_dest))\n#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))\n#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem8_to_r64zx((as), (reg_base), 0, (reg_dest))\n#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 0, (reg_dest))\n#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem32_to_r64zx((as), (reg_base), 0, (reg_dest))\n\n#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 0)\n#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))\n#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x64_mov_r8_to_mem8((as), (reg_src), (reg_base), 0)\n#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x64_mov_r16_to_mem16((as), (reg_src), (reg_base), 0)\n#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x64_mov_r32_to_mem32((as), (reg_src), (reg_base), 0)\n\n#endif // GENERIC_ASM_API\n\n#endif // MICROPY_INCLUDED_PY_ASMX64_H\n"
  },
  {
    "path": "py/asmx86.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <assert.h>\n#include <string.h>\n\n#include \"py/mpconfig.h\"\n\n// wrapper around everything in this file\n#if MICROPY_EMIT_X86\n\n#include \"py/asmx86.h\"\n\n/* all offsets are measured in multiples of 4 bytes */\n#define WORD_SIZE                (4)\n\n#define OPCODE_NOP               (0x90)\n#define OPCODE_PUSH_R32          (0x50)\n// #define OPCODE_PUSH_I32          (0x68)\n// #define OPCODE_PUSH_M32          (0xff) /* /6 */\n#define OPCODE_POP_R32           (0x58)\n#define OPCODE_RET               (0xc3)\n// #define OPCODE_MOV_I8_TO_R8      (0xb0) /* +rb */\n#define OPCODE_MOV_I32_TO_R32    (0xb8)\n// #define OPCODE_MOV_I32_TO_RM32   (0xc7)\n#define OPCODE_MOV_R8_TO_RM8     (0x88) /* /r */\n#define OPCODE_MOV_R32_TO_RM32   (0x89) /* /r */\n#define OPCODE_MOV_RM32_TO_R32   (0x8b) /* /r */\n#define OPCODE_MOVZX_RM8_TO_R32  (0xb6) /* 0x0f 0xb6/r */\n#define OPCODE_MOVZX_RM16_TO_R32 (0xb7) /* 0x0f 0xb7/r */\n#define OPCODE_LEA_MEM_TO_R32    (0x8d) /* /r */\n#define OPCODE_AND_R32_TO_RM32   (0x21) /* /r */\n#define OPCODE_OR_R32_TO_RM32    (0x09) /* /r */\n#define OPCODE_XOR_R32_TO_RM32   (0x31) /* /r */\n#define OPCODE_ADD_R32_TO_RM32   (0x01)\n#define OPCODE_ADD_I32_TO_RM32   (0x81) /* /0 */\n#define OPCODE_ADD_I8_TO_RM32    (0x83) /* /0 */\n#define OPCODE_SUB_R32_FROM_RM32 (0x29)\n#define OPCODE_SUB_I32_FROM_RM32 (0x81) /* /5 */\n#define OPCODE_SUB_I8_FROM_RM32  (0x83) /* /5 */\n// #define OPCODE_SHL_RM32_BY_I8    (0xc1) /* /4 */\n// #define OPCODE_SHR_RM32_BY_I8    (0xc1) /* /5 */\n// #define OPCODE_SAR_RM32_BY_I8    (0xc1) /* /7 */\n#define OPCODE_SHL_RM32_CL       (0xd3) /* /4 */\n#define OPCODE_SHR_RM32_CL       (0xd3) /* /5 */\n#define OPCODE_SAR_RM32_CL       (0xd3) /* /7 */\n// #define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */\n// #define OPCODE_CMP_I8_WITH_RM32  (0x83) /* /7 */\n#define OPCODE_CMP_R32_WITH_RM32 (0x39)\n// #define OPCODE_CMP_RM32_WITH_R32 (0x3b)\n#define OPCODE_TEST_R8_WITH_RM8  (0x84) /* /r */\n#define OPCODE_TEST_R32_WITH_RM32 (0x85) /* /r */\n#define OPCODE_JMP_REL8          (0xeb)\n#define OPCODE_JMP_REL32         (0xe9)\n#define OPCODE_JMP_RM32          (0xff) /* /4 */\n#define OPCODE_JCC_REL8          (0x70) /* | jcc type */\n#define OPCODE_JCC_REL32_A       (0x0f)\n#define OPCODE_JCC_REL32_B       (0x80) /* | jcc type */\n#define OPCODE_SETCC_RM8_A       (0x0f)\n#define OPCODE_SETCC_RM8_B       (0x90) /* | jcc type, /0 */\n#define OPCODE_CALL_REL32        (0xe8)\n#define OPCODE_CALL_RM32         (0xff) /* /2 */\n#define OPCODE_LEAVE             (0xc9)\n\n#define MODRM_R32(x)    ((x) << 3)\n#define MODRM_RM_DISP0  (0x00)\n#define MODRM_RM_DISP8  (0x40)\n#define MODRM_RM_DISP32 (0x80)\n#define MODRM_RM_REG    (0xc0)\n#define MODRM_RM_R32(x) (x)\n\n#define OP_SIZE_PREFIX (0x66)\n\n#define IMM32_L0(x) ((x) & 0xff)\n#define IMM32_L1(x) (((x) >> 8) & 0xff)\n#define IMM32_L2(x) (((x) >> 16) & 0xff)\n#define IMM32_L3(x) (((x) >> 24) & 0xff)\n\n#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)\n\nSTATIC void asm_x86_write_byte_1(asm_x86_t *as, byte b1) {\n    byte *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 1);\n    if (c != NULL) {\n        c[0] = b1;\n    }\n}\n\nSTATIC void asm_x86_write_byte_2(asm_x86_t *as, byte b1, byte b2) {\n    byte *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 2);\n    if (c != NULL) {\n        c[0] = b1;\n        c[1] = b2;\n    }\n}\n\nSTATIC void asm_x86_write_byte_3(asm_x86_t *as, byte b1, byte b2, byte b3) {\n    byte *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 3);\n    if (c != NULL) {\n        c[0] = b1;\n        c[1] = b2;\n        c[2] = b3;\n    }\n}\n\nSTATIC void asm_x86_write_word32(asm_x86_t *as, int w32) {\n    byte *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);\n    if (c != NULL) {\n        c[0] = IMM32_L0(w32);\n        c[1] = IMM32_L1(w32);\n        c[2] = IMM32_L2(w32);\n        c[3] = IMM32_L3(w32);\n    }\n}\n\nSTATIC void asm_x86_write_r32_disp(asm_x86_t *as, int r32, int disp_r32, int disp_offset) {\n    uint8_t rm_disp;\n    if (disp_offset == 0 && disp_r32 != ASM_X86_REG_EBP) {\n        rm_disp = MODRM_RM_DISP0;\n    } else if (SIGNED_FIT8(disp_offset)) {\n        rm_disp = MODRM_RM_DISP8;\n    } else {\n        rm_disp = MODRM_RM_DISP32;\n    }\n    asm_x86_write_byte_1(as, MODRM_R32(r32) | rm_disp | MODRM_RM_R32(disp_r32));\n    if (disp_r32 == ASM_X86_REG_ESP) {\n        // Special case for esp, it needs a SIB byte\n        asm_x86_write_byte_1(as, 0x24);\n    }\n    if (rm_disp == MODRM_RM_DISP8) {\n        asm_x86_write_byte_1(as, IMM32_L0(disp_offset));\n    } else if (rm_disp == MODRM_RM_DISP32) {\n        asm_x86_write_word32(as, disp_offset);\n    }\n}\n\nSTATIC void asm_x86_generic_r32_r32(asm_x86_t *as, int dest_r32, int src_r32, int op) {\n    asm_x86_write_byte_2(as, op, MODRM_R32(src_r32) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));\n}\n\n#if 0\nSTATIC void asm_x86_nop(asm_x86_t *as) {\n    asm_x86_write_byte_1(as, OPCODE_NOP);\n}\n#endif\n\nSTATIC void asm_x86_push_r32(asm_x86_t *as, int src_r32) {\n    asm_x86_write_byte_1(as, OPCODE_PUSH_R32 | src_r32);\n}\n\n#if 0\nvoid asm_x86_push_i32(asm_x86_t *as, int src_i32) {\n    asm_x86_write_byte_1(as, OPCODE_PUSH_I32);\n    asm_x86_write_word32(as, src_i32);\n}\n\nvoid asm_x86_push_disp(asm_x86_t *as, int src_r32, int src_offset) {\n    asm_x86_write_byte_1(as, OPCODE_PUSH_M32);\n    asm_x86_write_r32_disp(as, 6, src_r32, src_offset);\n}\n#endif\n\nSTATIC void asm_x86_pop_r32(asm_x86_t *as, int dest_r32) {\n    asm_x86_write_byte_1(as, OPCODE_POP_R32 | dest_r32);\n}\n\nSTATIC void asm_x86_ret(asm_x86_t *as) {\n    asm_x86_write_byte_1(as, OPCODE_RET);\n}\n\nvoid asm_x86_mov_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {\n    asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_MOV_R32_TO_RM32);\n}\n\nvoid asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {\n    asm_x86_write_byte_1(as, OPCODE_MOV_R8_TO_RM8);\n    asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp);\n}\n\nvoid asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {\n    asm_x86_write_byte_2(as, OP_SIZE_PREFIX, OPCODE_MOV_R32_TO_RM32);\n    asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp);\n}\n\nvoid asm_x86_mov_r32_to_mem32(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {\n    asm_x86_write_byte_1(as, OPCODE_MOV_R32_TO_RM32);\n    asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp);\n}\n\nvoid asm_x86_mov_mem8_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {\n    asm_x86_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R32);\n    asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);\n}\n\nvoid asm_x86_mov_mem16_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {\n    asm_x86_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R32);\n    asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);\n}\n\nvoid asm_x86_mov_mem32_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {\n    asm_x86_write_byte_1(as, OPCODE_MOV_RM32_TO_R32);\n    asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);\n}\n\nSTATIC void asm_x86_lea_disp_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {\n    asm_x86_write_byte_1(as, OPCODE_LEA_MEM_TO_R32);\n    asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);\n}\n\n#if 0\nvoid asm_x86_mov_i8_to_r8(asm_x86_t *as, int src_i8, int dest_r32) {\n    asm_x86_write_byte_2(as, OPCODE_MOV_I8_TO_R8 | dest_r32, src_i8);\n}\n#endif\n\nsize_t asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32) {\n    asm_x86_write_byte_1(as, OPCODE_MOV_I32_TO_R32 | dest_r32);\n    size_t loc = mp_asm_base_get_code_pos(&as->base);\n    asm_x86_write_word32(as, src_i32);\n    return loc;\n}\n\nvoid asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {\n    asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_AND_R32_TO_RM32);\n}\n\nvoid asm_x86_or_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {\n    asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_OR_R32_TO_RM32);\n}\n\nvoid asm_x86_xor_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {\n    asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_XOR_R32_TO_RM32);\n}\n\nvoid asm_x86_shl_r32_cl(asm_x86_t *as, int dest_r32) {\n    asm_x86_generic_r32_r32(as, dest_r32, 4, OPCODE_SHL_RM32_CL);\n}\n\nvoid asm_x86_shr_r32_cl(asm_x86_t *as, int dest_r32) {\n    asm_x86_generic_r32_r32(as, dest_r32, 5, OPCODE_SHR_RM32_CL);\n}\n\nvoid asm_x86_sar_r32_cl(asm_x86_t *as, int dest_r32) {\n    asm_x86_generic_r32_r32(as, dest_r32, 7, OPCODE_SAR_RM32_CL);\n}\n\nvoid asm_x86_add_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {\n    asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_ADD_R32_TO_RM32);\n}\n\nSTATIC void asm_x86_add_i32_to_r32(asm_x86_t *as, int src_i32, int dest_r32) {\n    if (SIGNED_FIT8(src_i32)) {\n        asm_x86_write_byte_2(as, OPCODE_ADD_I8_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));\n        asm_x86_write_byte_1(as, src_i32 & 0xff);\n    } else {\n        asm_x86_write_byte_2(as, OPCODE_ADD_I32_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));\n        asm_x86_write_word32(as, src_i32);\n    }\n}\n\nvoid asm_x86_sub_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {\n    asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_SUB_R32_FROM_RM32);\n}\n\nSTATIC void asm_x86_sub_r32_i32(asm_x86_t *as, int dest_r32, int src_i32) {\n    if (SIGNED_FIT8(src_i32)) {\n        // defaults to 32 bit operation\n        asm_x86_write_byte_2(as, OPCODE_SUB_I8_FROM_RM32, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));\n        asm_x86_write_byte_1(as, src_i32 & 0xff);\n    } else {\n        // defaults to 32 bit operation\n        asm_x86_write_byte_2(as, OPCODE_SUB_I32_FROM_RM32, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));\n        asm_x86_write_word32(as, src_i32);\n    }\n}\n\nvoid asm_x86_mul_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {\n    // imul reg32, reg/mem32 -- 0x0f 0xaf /r\n    asm_x86_write_byte_3(as, 0x0f, 0xaf, MODRM_R32(dest_r32) | MODRM_RM_REG | MODRM_RM_R32(src_r32));\n}\n\n#if 0\n/* shifts not tested */\nvoid asm_x86_shl_r32_by_imm(asm_x86_t *as, int r32, int imm) {\n    asm_x86_write_byte_2(as, OPCODE_SHL_RM32_BY_I8, MODRM_R32(4) | MODRM_RM_REG | MODRM_RM_R32(r32));\n    asm_x86_write_byte_1(as, imm);\n}\n\nvoid asm_x86_shr_r32_by_imm(asm_x86_t *as, int r32, int imm) {\n    asm_x86_write_byte_2(as, OPCODE_SHR_RM32_BY_I8, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(r32));\n    asm_x86_write_byte_1(as, imm);\n}\n\nvoid asm_x86_sar_r32_by_imm(asm_x86_t *as, int r32, int imm) {\n    asm_x86_write_byte_2(as, OPCODE_SAR_RM32_BY_I8, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(r32));\n    asm_x86_write_byte_1(as, imm);\n}\n#endif\n\nvoid asm_x86_cmp_r32_with_r32(asm_x86_t *as, int src_r32_a, int src_r32_b) {\n    asm_x86_generic_r32_r32(as, src_r32_b, src_r32_a, OPCODE_CMP_R32_WITH_RM32);\n}\n\n#if 0\nvoid asm_x86_cmp_i32_with_r32(asm_x86_t *as, int src_i32, int src_r32) {\n    if (SIGNED_FIT8(src_i32)) {\n        asm_x86_write_byte_2(as, OPCODE_CMP_I8_WITH_RM32, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(src_r32));\n        asm_x86_write_byte_1(as, src_i32 & 0xff);\n    } else {\n        asm_x86_write_byte_2(as, OPCODE_CMP_I32_WITH_RM32, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(src_r32));\n        asm_x86_write_word32(as, src_i32);\n    }\n}\n#endif\n\nvoid asm_x86_test_r8_with_r8(asm_x86_t *as, int src_r32_a, int src_r32_b) {\n    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));\n}\n\nvoid asm_x86_test_r32_with_r32(asm_x86_t *as, int src_r32_a, int src_r32_b) {\n    asm_x86_generic_r32_r32(as, src_r32_b, src_r32_a, OPCODE_TEST_R32_WITH_RM32);\n}\n\nvoid asm_x86_setcc_r8(asm_x86_t *as, mp_uint_t jcc_type, int dest_r8) {\n    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));\n}\n\nvoid asm_x86_jmp_reg(asm_x86_t *as, int src_r32) {\n    asm_x86_write_byte_2(as, OPCODE_JMP_RM32, MODRM_R32(4) | MODRM_RM_REG | MODRM_RM_R32(src_r32));\n}\n\nSTATIC mp_uint_t get_label_dest(asm_x86_t *as, mp_uint_t label) {\n    assert(label < as->base.max_num_labels);\n    return as->base.label_offsets[label];\n}\n\nvoid asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    if (dest != (mp_uint_t)-1 && rel < 0) {\n        // is a backwards jump, so we know the size of the jump on the first pass\n        // calculate rel assuming 8 bit relative jump\n        rel -= 2;\n        if (SIGNED_FIT8(rel)) {\n            asm_x86_write_byte_2(as, OPCODE_JMP_REL8, rel & 0xff);\n        } else {\n            rel += 2;\n            goto large_jump;\n        }\n    } else {\n        // is a forwards jump, so need to assume it's large\n    large_jump:\n        rel -= 5;\n        asm_x86_write_byte_1(as, OPCODE_JMP_REL32);\n        asm_x86_write_word32(as, rel);\n    }\n}\n\nvoid asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label) {\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    if (dest != (mp_uint_t)-1 && rel < 0) {\n        // is a backwards jump, so we know the size of the jump on the first pass\n        // calculate rel assuming 8 bit relative jump\n        rel -= 2;\n        if (SIGNED_FIT8(rel)) {\n            asm_x86_write_byte_2(as, OPCODE_JCC_REL8 | jcc_type, rel & 0xff);\n        } else {\n            rel += 2;\n            goto large_jump;\n        }\n    } else {\n        // is a forwards jump, so need to assume it's large\n    large_jump:\n        rel -= 6;\n        asm_x86_write_byte_2(as, OPCODE_JCC_REL32_A, OPCODE_JCC_REL32_B | jcc_type);\n        asm_x86_write_word32(as, rel);\n    }\n}\n\nvoid asm_x86_entry(asm_x86_t *as, int num_locals) {\n    assert(num_locals >= 0);\n    asm_x86_push_r32(as, ASM_X86_REG_EBP);\n    asm_x86_push_r32(as, ASM_X86_REG_EBX);\n    asm_x86_push_r32(as, ASM_X86_REG_ESI);\n    asm_x86_push_r32(as, ASM_X86_REG_EDI);\n    num_locals |= 3; // make it odd so stack is aligned on 16 byte boundary\n    asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, num_locals * WORD_SIZE);\n    as->num_locals = num_locals;\n}\n\nvoid asm_x86_exit(asm_x86_t *as) {\n    asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, -as->num_locals * WORD_SIZE);\n    asm_x86_pop_r32(as, ASM_X86_REG_EDI);\n    asm_x86_pop_r32(as, ASM_X86_REG_ESI);\n    asm_x86_pop_r32(as, ASM_X86_REG_EBX);\n    asm_x86_pop_r32(as, ASM_X86_REG_EBP);\n    asm_x86_ret(as);\n}\n\nSTATIC int asm_x86_arg_offset_from_esp(asm_x86_t *as, size_t arg_num) {\n    // Above esp are: locals, 4 saved registers, return eip, arguments\n    return (as->num_locals + 4 + 1 + arg_num) * WORD_SIZE;\n}\n\n#if 0\nvoid asm_x86_push_arg(asm_x86_t *as, int src_arg_num) {\n    asm_x86_push_disp(as, ASM_X86_REG_ESP, asm_x86_arg_offset_from_esp(as, src_arg_num));\n}\n#endif\n\nvoid asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32) {\n    asm_x86_mov_mem32_to_r32(as, ASM_X86_REG_ESP, asm_x86_arg_offset_from_esp(as, src_arg_num), dest_r32);\n}\n\n#if 0\nvoid asm_x86_mov_r32_to_arg(asm_x86_t *as, int src_r32, int dest_arg_num) {\n    asm_x86_mov_r32_to_mem32(as, src_r32, ASM_X86_REG_ESP, asm_x86_arg_offset_from_esp(as, dest_arg_num));\n}\n#endif\n\n// locals:\n//  - stored on the stack in ascending order\n//  - numbered 0 through as->num_locals-1\n//  - ESP points to the first local\n//\n//  | ESP\n//  v\n//  l0  l1  l2  ...  l(n-1)\n//  ^                ^\n//  | low address    | high address in RAM\n//\nSTATIC int asm_x86_local_offset_from_esp(asm_x86_t *as, int local_num) {\n    (void)as;\n    // Stack is full descending, ESP points to local0\n    return local_num * WORD_SIZE;\n}\n\nvoid asm_x86_mov_local_to_r32(asm_x86_t *as, int src_local_num, int dest_r32) {\n    asm_x86_mov_mem32_to_r32(as, ASM_X86_REG_ESP, asm_x86_local_offset_from_esp(as, src_local_num), dest_r32);\n}\n\nvoid asm_x86_mov_r32_to_local(asm_x86_t *as, int src_r32, int dest_local_num) {\n    asm_x86_mov_r32_to_mem32(as, src_r32, ASM_X86_REG_ESP, asm_x86_local_offset_from_esp(as, dest_local_num));\n}\n\nvoid asm_x86_mov_local_addr_to_r32(asm_x86_t *as, int local_num, int dest_r32) {\n    int offset = asm_x86_local_offset_from_esp(as, local_num);\n    if (offset == 0) {\n        asm_x86_mov_r32_r32(as, dest_r32, ASM_X86_REG_ESP);\n    } else {\n        asm_x86_lea_disp_to_r32(as, ASM_X86_REG_ESP, offset, dest_r32);\n    }\n}\n\nvoid asm_x86_mov_reg_pcrel(asm_x86_t *as, int dest_r32, mp_uint_t label) {\n    asm_x86_write_byte_1(as, OPCODE_CALL_REL32);\n    asm_x86_write_word32(as, 0);\n    mp_uint_t dest = get_label_dest(as, label);\n    mp_int_t rel = dest - as->base.code_offset;\n    asm_x86_pop_r32(as, dest_r32);\n    // PC rel is usually a forward reference, so need to assume it's large\n    asm_x86_write_byte_2(as, OPCODE_ADD_I32_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));\n    asm_x86_write_word32(as, rel);\n}\n\n#if 0\nvoid asm_x86_push_local(asm_x86_t *as, int local_num) {\n    asm_x86_push_disp(as, ASM_X86_REG_ESP, asm_x86_local_offset_from_esp(as, local_num));\n}\n\nvoid asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32) {\n    asm_x86_mov_r32_r32(as, temp_r32, ASM_X86_REG_ESP);\n    asm_x86_add_i32_to_r32(as, asm_x86_local_offset_from_esp(as, local_num), temp_r32);\n    asm_x86_push_r32(as, temp_r32);\n}\n#endif\n\nvoid asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r32) {\n    assert(n_args <= 4);\n\n    // Align stack on 16-byte boundary during the call\n    unsigned int align = ((n_args + 3) & ~3) - n_args;\n    if (align) {\n        asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, align * WORD_SIZE);\n    }\n\n    if (n_args > 3) {\n        asm_x86_push_r32(as, ASM_X86_REG_ARG_4);\n    }\n    if (n_args > 2) {\n        asm_x86_push_r32(as, ASM_X86_REG_ARG_3);\n    }\n    if (n_args > 1) {\n        asm_x86_push_r32(as, ASM_X86_REG_ARG_2);\n    }\n    if (n_args > 0) {\n        asm_x86_push_r32(as, ASM_X86_REG_ARG_1);\n    }\n\n    // Load the pointer to the function and make the call\n    asm_x86_mov_mem32_to_r32(as, ASM_X86_REG_FUN_TABLE, fun_id * WORD_SIZE, temp_r32);\n    asm_x86_write_byte_2(as, OPCODE_CALL_RM32, MODRM_R32(2) | MODRM_RM_REG | MODRM_RM_R32(temp_r32));\n\n    // the caller must clean up the stack\n    if (n_args > 0) {\n        asm_x86_add_i32_to_r32(as, (n_args + align) * WORD_SIZE, ASM_X86_REG_ESP);\n    }\n}\n\n#endif // MICROPY_EMIT_X86\n"
  },
  {
    "path": "py/asmx86.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_ASMX86_H\n#define MICROPY_INCLUDED_PY_ASMX86_H\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n#include \"py/asmbase.h\"\n\n// x86 cdecl calling convention is:\n//  - args passed on the stack in reverse order\n//  - return value in EAX\n//  - caller cleans up the stack after a call\n//  - stack must be aligned to 16-byte boundary before all calls\n//  - EAX, ECX, EDX are caller-save\n//  - EBX, ESI, EDI, EBP, ESP, EIP are callee-save\n\n// In the functions below, argument order follows x86 docs and generally\n// the destination is the first argument.\n// NOTE: this is a change from the old convention used in this file and\n// some functions still use the old (reverse) convention.\n\n#define ASM_X86_REG_EAX (0)\n#define ASM_X86_REG_ECX (1)\n#define ASM_X86_REG_EDX (2)\n#define ASM_X86_REG_EBX (3)\n#define ASM_X86_REG_ESP (4)\n#define ASM_X86_REG_EBP (5)\n#define ASM_X86_REG_ESI (6)\n#define ASM_X86_REG_EDI (7)\n\n// x86 passes values on the stack, but the emitter is register based, so we need\n// to define registers that can temporarily hold the function arguments.  They\n// need to be defined here so that asm_x86_call_ind can push them onto the stack\n// before the call.\n#define ASM_X86_REG_ARG_1 ASM_X86_REG_EAX\n#define ASM_X86_REG_ARG_2 ASM_X86_REG_ECX\n#define ASM_X86_REG_ARG_3 ASM_X86_REG_EDX\n#define ASM_X86_REG_ARG_4 ASM_X86_REG_EBX\n\n// condition codes, used for jcc and setcc (despite their j-name!)\n#define ASM_X86_CC_JB  (0x2) // below, unsigned\n#define ASM_X86_CC_JAE (0x3) // above or equal, unsigned\n#define ASM_X86_CC_JZ  (0x4)\n#define ASM_X86_CC_JE  (0x4)\n#define ASM_X86_CC_JNZ (0x5)\n#define ASM_X86_CC_JNE (0x5)\n#define ASM_X86_CC_JBE (0x6) // below or equal, unsigned\n#define ASM_X86_CC_JA  (0x7) // above, unsigned\n#define ASM_X86_CC_JL  (0xc) // less, signed\n#define ASM_X86_CC_JGE (0xd) // greater or equal, signed\n#define ASM_X86_CC_JLE (0xe) // less or equal, signed\n#define ASM_X86_CC_JG  (0xf) // greater, signed\n\ntypedef struct _asm_x86_t {\n    mp_asm_base_t base;\n    int num_locals;\n} asm_x86_t;\n\nstatic inline void asm_x86_end_pass(asm_x86_t *as) {\n    (void)as;\n}\n\nvoid asm_x86_mov_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);\nsize_t asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32);\nvoid asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);\nvoid asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);\nvoid asm_x86_mov_r32_to_mem32(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);\nvoid asm_x86_mov_mem8_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32);\nvoid asm_x86_mov_mem16_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32);\nvoid asm_x86_mov_mem32_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32);\nvoid asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);\nvoid asm_x86_or_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);\nvoid asm_x86_xor_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);\nvoid asm_x86_shl_r32_cl(asm_x86_t *as, int dest_r32);\nvoid asm_x86_shr_r32_cl(asm_x86_t *as, int dest_r32);\nvoid asm_x86_sar_r32_cl(asm_x86_t *as, int dest_r32);\nvoid asm_x86_add_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);\nvoid asm_x86_sub_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);\nvoid asm_x86_mul_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);\nvoid asm_x86_cmp_r32_with_r32(asm_x86_t *as, int src_r32_a, int src_r32_b);\nvoid asm_x86_test_r8_with_r8(asm_x86_t *as, int src_r32_a, int src_r32_b);\nvoid asm_x86_test_r32_with_r32(asm_x86_t *as, int src_r32_a, int src_r32_b);\nvoid asm_x86_setcc_r8(asm_x86_t *as, mp_uint_t jcc_type, int dest_r8);\nvoid asm_x86_jmp_reg(asm_x86_t *as, int src_r86);\nvoid asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label);\nvoid asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label);\nvoid asm_x86_entry(asm_x86_t *as, int num_locals);\nvoid asm_x86_exit(asm_x86_t *as);\nvoid asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32);\nvoid asm_x86_mov_local_to_r32(asm_x86_t *as, int src_local_num, int dest_r32);\nvoid asm_x86_mov_r32_to_local(asm_x86_t *as, int src_r32, int dest_local_num);\nvoid asm_x86_mov_local_addr_to_r32(asm_x86_t *as, int local_num, int dest_r32);\nvoid asm_x86_mov_reg_pcrel(asm_x86_t *as, int dest_r64, mp_uint_t label);\nvoid asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r32);\n\n// Holds a pointer to mp_fun_table\n#define ASM_X86_REG_FUN_TABLE ASM_X86_REG_EBP\n\n#if GENERIC_ASM_API\n\n// The following macros provide a (mostly) arch-independent API to\n// generate native code, and are used by the native emitter.\n\n#define ASM_WORD_SIZE (4)\n\n#define REG_RET ASM_X86_REG_EAX\n#define REG_ARG_1 ASM_X86_REG_ARG_1\n#define REG_ARG_2 ASM_X86_REG_ARG_2\n#define REG_ARG_3 ASM_X86_REG_ARG_3\n#define REG_ARG_4 ASM_X86_REG_ARG_4\n\n// caller-save, so can be used as temporaries\n#define REG_TEMP0 ASM_X86_REG_EAX\n#define REG_TEMP1 ASM_X86_REG_ECX\n#define REG_TEMP2 ASM_X86_REG_EDX\n\n// callee-save, so can be used as locals\n#define REG_LOCAL_1 ASM_X86_REG_EBX\n#define REG_LOCAL_2 ASM_X86_REG_ESI\n#define REG_LOCAL_3 ASM_X86_REG_EDI\n#define REG_LOCAL_NUM (3)\n\n// Holds a pointer to mp_fun_table\n#define REG_FUN_TABLE ASM_X86_REG_FUN_TABLE\n\n#define ASM_T               asm_x86_t\n#define ASM_END_PASS        asm_x86_end_pass\n#define ASM_ENTRY           asm_x86_entry\n#define ASM_EXIT            asm_x86_exit\n\n#define ASM_JUMP            asm_x86_jmp_label\n#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \\\n    do { \\\n        if (bool_test) { \\\n            asm_x86_test_r8_with_r8(as, reg, reg); \\\n        } else { \\\n            asm_x86_test_r32_with_r32(as, reg, reg); \\\n        } \\\n        asm_x86_jcc_label(as, ASM_X86_CC_JZ, label); \\\n    } while (0)\n#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \\\n    do { \\\n        if (bool_test) { \\\n            asm_x86_test_r8_with_r8(as, reg, reg); \\\n        } else { \\\n            asm_x86_test_r32_with_r32(as, reg, reg); \\\n        } \\\n        asm_x86_jcc_label(as, ASM_X86_CC_JNZ, label); \\\n    } while (0)\n#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \\\n    do { \\\n        asm_x86_cmp_r32_with_r32(as, reg1, reg2); \\\n        asm_x86_jcc_label(as, ASM_X86_CC_JE, label); \\\n    } while (0)\n#define ASM_JUMP_REG(as, reg) asm_x86_jmp_reg((as), (reg))\n#define ASM_CALL_IND(as, idx) asm_x86_call_ind(as, idx, mp_f_n_args[idx], ASM_X86_REG_EAX)\n\n#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x86_mov_r32_to_local((as), (reg_src), (local_num))\n#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest))\n#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest))\n#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest))\n#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x86_mov_local_to_r32((as), (local_num), (reg_dest))\n#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x86_mov_r32_r32((as), (reg_dest), (reg_src))\n#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x86_mov_local_addr_to_r32((as), (local_num), (reg_dest))\n#define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_x86_mov_reg_pcrel((as), (reg_dest), (label))\n\n#define ASM_LSL_REG(as, reg) asm_x86_shl_r32_cl((as), (reg))\n#define ASM_LSR_REG(as, reg) asm_x86_shr_r32_cl((as), (reg))\n#define ASM_ASR_REG(as, reg) asm_x86_sar_r32_cl((as), (reg))\n#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_x86_or_r32_r32((as), (reg_dest), (reg_src))\n#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_x86_xor_r32_r32((as), (reg_dest), (reg_src))\n#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_x86_and_r32_r32((as), (reg_dest), (reg_src))\n#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_x86_add_r32_r32((as), (reg_dest), (reg_src))\n#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x86_sub_r32_r32((as), (reg_dest), (reg_src))\n#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_x86_mul_r32_r32((as), (reg_dest), (reg_src))\n\n#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest))\n#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))\n#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem8_to_r32zx((as), (reg_base), 0, (reg_dest))\n#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 0, (reg_dest))\n#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest))\n\n#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0)\n#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))\n#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x86_mov_r8_to_mem8((as), (reg_src), (reg_base), 0)\n#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x86_mov_r16_to_mem16((as), (reg_src), (reg_base), 0)\n#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0)\n\n#endif // GENERIC_ASM_API\n\n#endif // MICROPY_INCLUDED_PY_ASMX86_H\n"
  },
  {
    "path": "py/asmxtensa.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <assert.h>\n\n#include \"py/mpconfig.h\"\n\n// wrapper around everything in this file\n#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN\n\n#include \"py/asmxtensa.h\"\n\n#define WORD_SIZE (4)\n#define SIGNED_FIT8(x) ((((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80))\n#define SIGNED_FIT12(x) ((((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800))\n\nvoid asm_xtensa_end_pass(asm_xtensa_t *as) {\n    as->num_const = as->cur_const;\n    as->cur_const = 0;\n\n    #if 0\n    // make a hex dump of the machine code\n    if (as->base.pass == MP_ASM_PASS_EMIT) {\n        uint8_t *d = as->base.code_base;\n        printf(\"XTENSA ASM:\");\n        for (int i = 0; i < ((as->base.code_size + 15) & ~15); ++i) {\n            if (i % 16 == 0) {\n                printf(\"\\n%08x:\", (uint32_t)&d[i]);\n            }\n            if (i % 2 == 0) {\n                printf(\" \");\n            }\n            printf(\"%02x\", d[i]);\n        }\n        printf(\"\\n\");\n    }\n    #endif\n}\n\nvoid asm_xtensa_entry(asm_xtensa_t *as, int num_locals) {\n    // jump over the constants\n    asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4);\n    mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte\n    as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4);\n\n    // adjust the stack-pointer to store a0, a12, a13, a14, a15 and locals, 16-byte aligned\n    as->stack_adjust = (((ASM_XTENSA_NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15;\n    if (SIGNED_FIT8(-as->stack_adjust)) {\n        asm_xtensa_op_addi(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, -as->stack_adjust);\n    } else {\n        asm_xtensa_op_movi(as, ASM_XTENSA_REG_A9, as->stack_adjust);\n        asm_xtensa_op_sub(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A9);\n    }\n\n    // save return value (a0) and callee-save registers (a12, a13, a14, a15)\n    asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0);\n    for (int i = 1; i < ASM_XTENSA_NUM_REGS_SAVED; ++i) {\n        asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A11 + i, ASM_XTENSA_REG_A1, i);\n    }\n}\n\nvoid asm_xtensa_exit(asm_xtensa_t *as) {\n    // restore registers\n    for (int i = ASM_XTENSA_NUM_REGS_SAVED - 1; i >= 1; --i) {\n        asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A11 + i, ASM_XTENSA_REG_A1, i);\n    }\n    asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0);\n\n    // restore stack-pointer and return\n    if (SIGNED_FIT8(as->stack_adjust)) {\n        asm_xtensa_op_addi(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, as->stack_adjust);\n    } else {\n        asm_xtensa_op_movi(as, ASM_XTENSA_REG_A9, as->stack_adjust);\n        asm_xtensa_op_add_n(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A9);\n    }\n\n    asm_xtensa_op_ret_n(as);\n}\n\nvoid asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals) {\n    // jump over the constants\n    asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4);\n    mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte\n    as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4);\n\n    as->stack_adjust = 32 + ((((ASM_XTENSA_NUM_REGS_SAVED_WIN + num_locals) * WORD_SIZE) + 15) & ~15);\n    asm_xtensa_op_entry(as, ASM_XTENSA_REG_A1, as->stack_adjust);\n    asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0);\n}\n\nvoid asm_xtensa_exit_win(asm_xtensa_t *as) {\n    asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0);\n    asm_xtensa_op_retw_n(as);\n}\n\nSTATIC uint32_t get_label_dest(asm_xtensa_t *as, uint label) {\n    assert(label < as->base.max_num_labels);\n    return as->base.label_offsets[label];\n}\n\nvoid asm_xtensa_op16(asm_xtensa_t *as, uint16_t op) {\n    uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 2);\n    if (c != NULL) {\n        c[0] = op;\n        c[1] = op >> 8;\n    }\n}\n\nvoid asm_xtensa_op24(asm_xtensa_t *as, uint32_t op) {\n    uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 3);\n    if (c != NULL) {\n        c[0] = op;\n        c[1] = op >> 8;\n        c[2] = op >> 16;\n    }\n}\n\nvoid asm_xtensa_j_label(asm_xtensa_t *as, uint label) {\n    uint32_t dest = get_label_dest(as, label);\n    int32_t rel = dest - as->base.code_offset - 4;\n    // we assume rel, as a signed int, fits in 18-bits\n    asm_xtensa_op_j(as, rel);\n}\n\nvoid asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label) {\n    uint32_t dest = get_label_dest(as, label);\n    int32_t rel = dest - as->base.code_offset - 4;\n    if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT12(rel)) {\n        printf(\"ERROR: xtensa bccz out of range\\n\");\n    }\n    asm_xtensa_op_bccz(as, cond, reg, rel);\n}\n\nvoid asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label) {\n    uint32_t dest = get_label_dest(as, label);\n    int32_t rel = dest - as->base.code_offset - 4;\n    if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT8(rel)) {\n        printf(\"ERROR: xtensa bcc out of range\\n\");\n    }\n    asm_xtensa_op_bcc(as, cond, reg1, reg2, rel);\n}\n\n// convenience function; reg_dest must be different from reg_src[12]\nvoid asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, uint reg_src1, uint reg_src2) {\n    asm_xtensa_op_movi_n(as, reg_dest, 1);\n    asm_xtensa_op_bcc(as, cond, reg_src1, reg_src2, 1);\n    asm_xtensa_op_movi_n(as, reg_dest, 0);\n}\n\nsize_t asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) {\n    // load the constant\n    uint32_t const_table_offset = (uint8_t *)as->const_table - as->base.code_base;\n    size_t loc = const_table_offset + as->cur_const * WORD_SIZE;\n    asm_xtensa_op_l32r(as, reg_dest, as->base.code_offset, loc);\n    // store the constant in the table\n    if (as->const_table != NULL) {\n        as->const_table[as->cur_const] = i32;\n    }\n    ++as->cur_const;\n    return loc;\n}\n\nvoid asm_xtensa_mov_reg_i32_optimised(asm_xtensa_t *as, uint reg_dest, uint32_t i32) {\n    if (SIGNED_FIT12(i32)) {\n        asm_xtensa_op_movi(as, reg_dest, i32);\n    } else {\n        asm_xtensa_mov_reg_i32(as, reg_dest, i32);\n    }\n}\n\nvoid asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src) {\n    asm_xtensa_op_s32i(as, reg_src, ASM_XTENSA_REG_A1, local_num);\n}\n\nvoid asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num) {\n    asm_xtensa_op_l32i(as, reg_dest, ASM_XTENSA_REG_A1, local_num);\n}\n\nvoid asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num) {\n    uint off = local_num * WORD_SIZE;\n    if (SIGNED_FIT8(off)) {\n        asm_xtensa_op_addi(as, reg_dest, ASM_XTENSA_REG_A1, off);\n    } else {\n        asm_xtensa_op_movi(as, reg_dest, off);\n        asm_xtensa_op_add_n(as, reg_dest, reg_dest, ASM_XTENSA_REG_A1);\n    }\n}\n\nvoid asm_xtensa_mov_reg_pcrel(asm_xtensa_t *as, uint reg_dest, uint label) {\n    // Get relative offset from PC\n    uint32_t dest = get_label_dest(as, label);\n    int32_t rel = dest - as->base.code_offset;\n    rel -= 3 + 3; // account for 3 bytes of movi instruction, 3 bytes call0 adjustment\n    asm_xtensa_op_movi(as, reg_dest, rel); // imm has 12-bit range\n\n    // Use call0 to get PC+3 into a0\n    // call0 destination must be aligned on 4 bytes:\n    //  - code_offset&3=0: off=0, pad=1\n    //  - code_offset&3=1: off=0, pad=0\n    //  - code_offset&3=2: off=1, pad=3\n    //  - code_offset&3=3: off=1, pad=2\n    uint32_t off = as->base.code_offset >> 1 & 1;\n    uint32_t pad = (5 - as->base.code_offset) & 3;\n    asm_xtensa_op_call0(as, off);\n    mp_asm_base_get_cur_to_write_bytes(&as->base, pad);\n\n    // Add PC to relative offset\n    asm_xtensa_op_add_n(as, reg_dest, reg_dest, ASM_XTENSA_REG_A0);\n}\n\nvoid asm_xtensa_call_ind(asm_xtensa_t *as, uint idx) {\n    if (idx < 16) {\n        asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_FUN_TABLE, idx);\n    } else {\n        asm_xtensa_op_l32i(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_FUN_TABLE, idx);\n    }\n    asm_xtensa_op_callx0(as, ASM_XTENSA_REG_A0);\n}\n\nvoid asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx) {\n    if (idx < 16) {\n        asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A8, ASM_XTENSA_REG_FUN_TABLE_WIN, idx);\n    } else {\n        asm_xtensa_op_l32i(as, ASM_XTENSA_REG_A8, ASM_XTENSA_REG_FUN_TABLE_WIN, idx);\n    }\n    asm_xtensa_op_callx8(as, ASM_XTENSA_REG_A8);\n}\n\n#endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN\n"
  },
  {
    "path": "py/asmxtensa.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_ASMXTENSA_H\n#define MICROPY_INCLUDED_PY_ASMXTENSA_H\n\n#include \"py/misc.h\"\n#include \"py/asmbase.h\"\n\n// calling conventions:\n// up to 6 args in a2-a7\n// return value in a2\n// PC stored in a0\n// stack pointer is a1, stack full descending, is aligned to 16 bytes\n// callee save: a1, a12, a13, a14, a15\n// caller save: a3\n\n// With windowed registers, size 8:\n// - a0: return PC\n// - a1: stack pointer, full descending, aligned to 16 bytes\n// - a2-a7: incoming args, and essentially callee save\n// - a2: return value\n// - a8-a15: caller save temporaries\n// - a10-a15: input args to called function\n// - a10: return value of called function\n// note: a0-a7 are saved automatically via window shift of called function\n\n#define ASM_XTENSA_REG_A0  (0)\n#define ASM_XTENSA_REG_A1  (1)\n#define ASM_XTENSA_REG_A2  (2)\n#define ASM_XTENSA_REG_A3  (3)\n#define ASM_XTENSA_REG_A4  (4)\n#define ASM_XTENSA_REG_A5  (5)\n#define ASM_XTENSA_REG_A6  (6)\n#define ASM_XTENSA_REG_A7  (7)\n#define ASM_XTENSA_REG_A8  (8)\n#define ASM_XTENSA_REG_A9  (9)\n#define ASM_XTENSA_REG_A10 (10)\n#define ASM_XTENSA_REG_A11 (11)\n#define ASM_XTENSA_REG_A12 (12)\n#define ASM_XTENSA_REG_A13 (13)\n#define ASM_XTENSA_REG_A14 (14)\n#define ASM_XTENSA_REG_A15 (15)\n\n// for bccz\n#define ASM_XTENSA_CCZ_EQ (0)\n#define ASM_XTENSA_CCZ_NE (1)\n\n// for bcc and setcc\n#define ASM_XTENSA_CC_NONE  (0)\n#define ASM_XTENSA_CC_EQ    (1)\n#define ASM_XTENSA_CC_LT    (2)\n#define ASM_XTENSA_CC_LTU   (3)\n#define ASM_XTENSA_CC_ALL   (4)\n#define ASM_XTENSA_CC_BC    (5)\n#define ASM_XTENSA_CC_ANY   (8)\n#define ASM_XTENSA_CC_NE    (9)\n#define ASM_XTENSA_CC_GE    (10)\n#define ASM_XTENSA_CC_GEU   (11)\n#define ASM_XTENSA_CC_NALL  (12)\n#define ASM_XTENSA_CC_BS    (13)\n\n// macros for encoding instructions (little endian versions)\n#define ASM_XTENSA_ENCODE_RRR(op0, op1, op2, r, s, t) \\\n    ((((uint32_t)op2) << 20) | (((uint32_t)op1) << 16) | ((r) << 12) | ((s) << 8) | ((t) << 4) | (op0))\n#define ASM_XTENSA_ENCODE_RRI4(op0, op1, r, s, t, imm4) \\\n    (((imm4) << 20) | ((op1) << 16) | ((r) << 12) | ((s) << 8) | ((t) << 4) | (op0))\n#define ASM_XTENSA_ENCODE_RRI8(op0, r, s, t, imm8) \\\n    ((((uint32_t)imm8) << 16) | ((r) << 12) | ((s) << 8) | ((t) << 4) | (op0))\n#define ASM_XTENSA_ENCODE_RI16(op0, t, imm16) \\\n    (((imm16) << 8) | ((t) << 4) | (op0))\n#define ASM_XTENSA_ENCODE_RSR(op0, op1, op2, rs, t) \\\n    (((op2) << 20) | ((op1) << 16) | ((rs) << 8) | ((t) << 4) | (op0))\n#define ASM_XTENSA_ENCODE_CALL(op0, n, offset) \\\n    (((offset) << 6) | ((n) << 4) | (op0))\n#define ASM_XTENSA_ENCODE_CALLX(op0, op1, op2, r, s, m, n) \\\n    ((((uint32_t)op2) << 20) | (((uint32_t)op1) << 16) | ((r) << 12) | ((s) << 8) | ((m) << 6) | ((n) << 4) | (op0))\n#define ASM_XTENSA_ENCODE_BRI8(op0, r, s, m, n, imm8) \\\n    (((imm8) << 16) | ((r) << 12) | ((s) << 8) | ((m) << 6) | ((n) << 4) | (op0))\n#define ASM_XTENSA_ENCODE_BRI12(op0, s, m, n, imm12) \\\n    (((imm12) << 12) | ((s) << 8) | ((m) << 6) | ((n) << 4) | (op0))\n#define ASM_XTENSA_ENCODE_RRRN(op0, r, s, t) \\\n    (((r) << 12) | ((s) << 8) | ((t) << 4) | (op0))\n#define ASM_XTENSA_ENCODE_RI7(op0, s, imm7) \\\n    ((((imm7) & 0xf) << 12) | ((s) << 8) | ((imm7) & 0x70) | (op0))\n\n// Number of registers saved on the stack upon entry to function\n#define ASM_XTENSA_NUM_REGS_SAVED (5)\n#define ASM_XTENSA_NUM_REGS_SAVED_WIN (1)\n\ntypedef struct _asm_xtensa_t {\n    mp_asm_base_t base;\n    uint32_t cur_const;\n    uint32_t num_const;\n    uint32_t *const_table;\n    uint32_t stack_adjust;\n} asm_xtensa_t;\n\nvoid asm_xtensa_end_pass(asm_xtensa_t *as);\n\nvoid asm_xtensa_entry(asm_xtensa_t *as, int num_locals);\nvoid asm_xtensa_exit(asm_xtensa_t *as);\n\nvoid asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals);\nvoid asm_xtensa_exit_win(asm_xtensa_t *as);\n\nvoid asm_xtensa_op16(asm_xtensa_t *as, uint16_t op);\nvoid asm_xtensa_op24(asm_xtensa_t *as, uint32_t op);\n\n// raw instructions\n\nstatic inline void asm_xtensa_op_entry(asm_xtensa_t *as, uint reg_src, int32_t num_bytes) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_BRI12(6, reg_src, 0, 3, (num_bytes / 8) & 0xfff));\n}\n\nstatic inline void asm_xtensa_op_add_n(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) {\n    asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(10, reg_dest, reg_src_a, reg_src_b));\n}\n\nstatic inline void asm_xtensa_op_addi(asm_xtensa_t *as, uint reg_dest, uint reg_src, int imm8) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 12, reg_src, reg_dest, imm8 & 0xff));\n}\n\nstatic inline void asm_xtensa_op_and(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 1, reg_dest, reg_src_a, reg_src_b));\n}\n\nstatic inline void asm_xtensa_op_bcc(asm_xtensa_t *as, uint cond, uint reg_src1, uint reg_src2, int32_t rel8) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(7, cond, reg_src1, reg_src2, rel8 & 0xff));\n}\n\nstatic inline void asm_xtensa_op_bccz(asm_xtensa_t *as, uint cond, uint reg_src, int32_t rel12) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_BRI12(6, reg_src, cond, 1, rel12 & 0xfff));\n}\n\nstatic inline void asm_xtensa_op_call0(asm_xtensa_t *as, int32_t rel18) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALL(5, 0, rel18 & 0x3ffff));\n}\n\nstatic inline void asm_xtensa_op_callx0(asm_xtensa_t *as, uint reg) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 3, 0));\n}\n\nstatic inline void asm_xtensa_op_callx8(asm_xtensa_t *as, uint reg) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 3, 2));\n}\n\nstatic inline void asm_xtensa_op_j(asm_xtensa_t *as, int32_t rel18) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALL(6, 0, rel18 & 0x3ffff));\n}\n\nstatic inline void asm_xtensa_op_jx(asm_xtensa_t *as, uint reg) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 2, 2));\n}\n\nstatic inline void asm_xtensa_op_l8ui(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint byte_offset) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 0, reg_base, reg_dest, byte_offset & 0xff));\n}\n\nstatic inline void asm_xtensa_op_l16ui(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint half_word_offset) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 1, reg_base, reg_dest, half_word_offset & 0xff));\n}\n\nstatic inline void asm_xtensa_op_l32i(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint word_offset) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 2, reg_base, reg_dest, word_offset & 0xff));\n}\n\nstatic inline void asm_xtensa_op_l32i_n(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint word_offset) {\n    asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(8, word_offset & 0xf, reg_base, reg_dest));\n}\n\nstatic inline void asm_xtensa_op_l32r(asm_xtensa_t *as, uint reg_dest, uint32_t op_off, uint32_t dest_off) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RI16(1, reg_dest, ((dest_off - ((op_off + 3) & ~3)) >> 2) & 0xffff));\n}\n\nstatic inline void asm_xtensa_op_mov_n(asm_xtensa_t *as, uint reg_dest, uint reg_src) {\n    asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 0, reg_src, reg_dest));\n}\n\nstatic inline void asm_xtensa_op_movi(asm_xtensa_t *as, uint reg_dest, int32_t imm12) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 10, (imm12 >> 8) & 0xf, reg_dest, imm12 & 0xff));\n}\n\nstatic inline void asm_xtensa_op_movi_n(asm_xtensa_t *as, uint reg_dest, int imm4) {\n    asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RI7(12, reg_dest, imm4));\n}\n\nstatic inline void asm_xtensa_op_mull(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 2, 8, reg_dest, reg_src_a, reg_src_b));\n}\n\nstatic inline void asm_xtensa_op_or(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 2, reg_dest, reg_src_a, reg_src_b));\n}\n\nstatic inline void asm_xtensa_op_ret_n(asm_xtensa_t *as) {\n    asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 15, 0, 0));\n}\n\nstatic inline void asm_xtensa_op_retw_n(asm_xtensa_t *as) {\n    asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 15, 0, 1));\n}\n\nstatic inline void asm_xtensa_op_s8i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint byte_offset) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 4, reg_base, reg_src, byte_offset & 0xff));\n}\n\nstatic inline void asm_xtensa_op_s16i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint half_word_offset) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 5, reg_base, reg_src, half_word_offset & 0xff));\n}\n\nstatic inline void asm_xtensa_op_s32i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 6, reg_base, reg_src, word_offset & 0xff));\n}\n\nstatic inline void asm_xtensa_op_s32i_n(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset) {\n    asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(9, word_offset & 0xf, reg_base, reg_src));\n}\n\nstatic inline void asm_xtensa_op_sll(asm_xtensa_t *as, uint reg_dest, uint reg_src) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 1, 10, reg_dest, reg_src, 0));\n}\n\nstatic inline void asm_xtensa_op_srl(asm_xtensa_t *as, uint reg_dest, uint reg_src) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 1, 9, reg_dest, 0, reg_src));\n}\n\nstatic inline void asm_xtensa_op_sra(asm_xtensa_t *as, uint reg_dest, uint reg_src) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 1, 11, reg_dest, 0, reg_src));\n}\n\nstatic inline void asm_xtensa_op_ssl(asm_xtensa_t *as, uint reg_src) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 1, reg_src, 0));\n}\n\nstatic inline void asm_xtensa_op_ssr(asm_xtensa_t *as, uint reg_src) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 0, reg_src, 0));\n}\n\nstatic inline void asm_xtensa_op_sub(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 12, reg_dest, reg_src_a, reg_src_b));\n}\n\nstatic inline void asm_xtensa_op_xor(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) {\n    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 3, reg_dest, reg_src_a, reg_src_b));\n}\n\n// convenience functions\nvoid asm_xtensa_j_label(asm_xtensa_t *as, uint label);\nvoid asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label);\nvoid asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label);\nvoid asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, uint reg_src1, uint reg_src2);\nsize_t asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32);\nvoid asm_xtensa_mov_reg_i32_optimised(asm_xtensa_t *as, uint reg_dest, uint32_t i32);\nvoid asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src);\nvoid asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num);\nvoid asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num);\nvoid asm_xtensa_mov_reg_pcrel(asm_xtensa_t *as, uint reg_dest, uint label);\nvoid asm_xtensa_call_ind(asm_xtensa_t *as, uint idx);\nvoid asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx);\n\n// Holds a pointer to mp_fun_table\n#define ASM_XTENSA_REG_FUN_TABLE ASM_XTENSA_REG_A15\n#define ASM_XTENSA_REG_FUN_TABLE_WIN ASM_XTENSA_REG_A7\n\n#if GENERIC_ASM_API\n\n// The following macros provide a (mostly) arch-independent API to\n// generate native code, and are used by the native emitter.\n\n#define ASM_WORD_SIZE (4)\n\n#if !GENERIC_ASM_API_WIN\n// Configuration for non-windowed calls\n\n#define REG_RET ASM_XTENSA_REG_A2\n#define REG_ARG_1 ASM_XTENSA_REG_A2\n#define REG_ARG_2 ASM_XTENSA_REG_A3\n#define REG_ARG_3 ASM_XTENSA_REG_A4\n#define REG_ARG_4 ASM_XTENSA_REG_A5\n#define REG_ARG_5 ASM_XTENSA_REG_A6\n\n#define REG_TEMP0 ASM_XTENSA_REG_A2\n#define REG_TEMP1 ASM_XTENSA_REG_A3\n#define REG_TEMP2 ASM_XTENSA_REG_A4\n\n#define REG_LOCAL_1 ASM_XTENSA_REG_A12\n#define REG_LOCAL_2 ASM_XTENSA_REG_A13\n#define REG_LOCAL_3 ASM_XTENSA_REG_A14\n#define REG_LOCAL_NUM (3)\n\n#define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED\n#define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE\n\n#define ASM_ENTRY(as, nlocal)   asm_xtensa_entry((as), (nlocal))\n#define ASM_EXIT(as)            asm_xtensa_exit((as))\n#define ASM_CALL_IND(as, idx)   asm_xtensa_call_ind((as), (idx))\n\n#else\n// Configuration for windowed calls with window size 8\n\n#define REG_PARENT_RET ASM_XTENSA_REG_A2\n#define REG_PARENT_ARG_1 ASM_XTENSA_REG_A2\n#define REG_PARENT_ARG_2 ASM_XTENSA_REG_A3\n#define REG_PARENT_ARG_3 ASM_XTENSA_REG_A4\n#define REG_PARENT_ARG_4 ASM_XTENSA_REG_A5\n#define REG_RET ASM_XTENSA_REG_A10\n#define REG_ARG_1 ASM_XTENSA_REG_A10\n#define REG_ARG_2 ASM_XTENSA_REG_A11\n#define REG_ARG_3 ASM_XTENSA_REG_A12\n#define REG_ARG_4 ASM_XTENSA_REG_A13\n\n#define REG_TEMP0 ASM_XTENSA_REG_A10\n#define REG_TEMP1 ASM_XTENSA_REG_A11\n#define REG_TEMP2 ASM_XTENSA_REG_A12\n\n#define REG_LOCAL_1 ASM_XTENSA_REG_A4\n#define REG_LOCAL_2 ASM_XTENSA_REG_A5\n#define REG_LOCAL_3 ASM_XTENSA_REG_A6\n#define REG_LOCAL_NUM (3)\n\n#define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED_WIN\n#define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE_WIN\n\n#define ASM_ENTRY(as, nlocal)   asm_xtensa_entry_win((as), (nlocal))\n#define ASM_EXIT(as)            asm_xtensa_exit_win((as))\n#define ASM_CALL_IND(as, idx)   asm_xtensa_call_ind_win((as), (idx))\n\n#endif\n\n#define ASM_T               asm_xtensa_t\n#define ASM_END_PASS        asm_xtensa_end_pass\n\n#define ASM_JUMP            asm_xtensa_j_label\n#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \\\n    asm_xtensa_bccz_reg_label(as, ASM_XTENSA_CCZ_EQ, reg, label)\n#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \\\n    asm_xtensa_bccz_reg_label(as, ASM_XTENSA_CCZ_NE, reg, label)\n#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \\\n    asm_xtensa_bcc_reg_reg_label(as, ASM_XTENSA_CC_EQ, reg1, reg2, label)\n#define ASM_JUMP_REG(as, reg) asm_xtensa_op_jx((as), (reg))\n\n#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), ASM_NUM_REGS_SAVED + (local_num), (reg_src))\n#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32_optimised((as), (reg_dest), (imm))\n#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm))\n#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm))\n#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), ASM_NUM_REGS_SAVED + (local_num))\n#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mov_n((as), (reg_dest), (reg_src))\n#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), ASM_NUM_REGS_SAVED + (local_num))\n#define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_xtensa_mov_reg_pcrel((as), (reg_dest), (label))\n\n#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) \\\n    do { \\\n        asm_xtensa_op_ssl((as), (reg_shift)); \\\n        asm_xtensa_op_sll((as), (reg_dest), (reg_dest)); \\\n    } while (0)\n#define ASM_LSR_REG_REG(as, reg_dest, reg_shift) \\\n    do { \\\n        asm_xtensa_op_ssr((as), (reg_shift)); \\\n        asm_xtensa_op_srl((as), (reg_dest), (reg_dest)); \\\n    } while (0)\n#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) \\\n    do { \\\n        asm_xtensa_op_ssr((as), (reg_shift)); \\\n        asm_xtensa_op_sra((as), (reg_dest), (reg_dest)); \\\n    } while (0)\n#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_or((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_xor((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_and((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_add_n((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_sub((as), (reg_dest), (reg_dest), (reg_src))\n#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mull((as), (reg_dest), (reg_dest), (reg_src))\n\n#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))\n#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l8ui((as), (reg_dest), (reg_base), 0)\n#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), 0)\n#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l32i_n((as), (reg_dest), (reg_base), 0)\n\n#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))\n#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s8i((as), (reg_src), (reg_base), 0)\n#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s16i((as), (reg_src), (reg_base), 0)\n#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s32i_n((as), (reg_src), (reg_base), 0)\n\n#endif // GENERIC_ASM_API\n\n#endif // MICROPY_INCLUDED_PY_ASMXTENSA_H\n"
  },
  {
    "path": "py/bc.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdbool.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n#include \"py/bc0.h\"\n#include \"py/bc.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_PRINT (1)\n#else // don't print debugging info\n#define DEBUG_PRINT (0)\n#define DEBUG_printf(...) (void)0\n#endif\n\n#if !MICROPY_PERSISTENT_CODE\n\nmp_uint_t mp_decode_uint(const byte **ptr) {\n    mp_uint_t unum = 0;\n    byte val;\n    const byte *p = *ptr;\n    do {\n        val = *p++;\n        unum = (unum << 7) | (val & 0x7f);\n    } while ((val & 0x80) != 0);\n    *ptr = p;\n    return unum;\n}\n\n// This function is used to help reduce stack usage at the caller, for the case when\n// the caller doesn't need to increase the ptr argument.  If ptr is a local variable\n// and the caller uses mp_decode_uint(&ptr) instead of this function, then the compiler\n// must allocate a slot on the stack for ptr, and this slot cannot be reused for\n// anything else in the function because the pointer may have been stored in a global\n// and reused later in the function.\nmp_uint_t mp_decode_uint_value(const byte *ptr) {\n    return mp_decode_uint(&ptr);\n}\n\n// This function is used to help reduce stack usage at the caller, for the case when\n// the caller doesn't need the actual value and just wants to skip over it.\nconst byte *mp_decode_uint_skip(const byte *ptr) {\n    while ((*ptr++) & 0x80) {\n    }\n    return ptr;\n}\n\n#endif\n\nSTATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    // generic message, used also for other argument issues\n    (void)f;\n    (void)expected;\n    (void)given;\n    mp_arg_error_terse_mismatch();\n    #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL\n    (void)f;\n    mp_raise_msg_varg(&mp_type_TypeError,\n        MP_ERROR_TEXT(\"function takes %d positional arguments but %d were given\"), expected, given);\n    #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED\n    mp_raise_msg_varg(&mp_type_TypeError,\n        MP_ERROR_TEXT(\"%q() takes %d positional arguments but %d were given\"),\n        mp_obj_fun_get_name(MP_OBJ_FROM_PTR(f)), expected, given);\n    #endif\n}\n\n#if DEBUG_PRINT\nSTATIC void dump_args(const mp_obj_t *a, size_t sz) {\n    DEBUG_printf(\"%p: \", a);\n    for (size_t i = 0; i < sz; i++) {\n        DEBUG_printf(\"%p \", a[i]);\n    }\n    DEBUG_printf(\"\\n\");\n}\n#else\n#define dump_args(...) (void)0\n#endif\n\n// On entry code_state should be allocated somewhere (stack/heap) and\n// contain the following valid entries:\n//    - code_state->fun_bc should contain a pointer to the function object\n//    - code_state->ip should contain the offset in bytes from the pointer\n//      code_state->fun_bc->bytecode to the entry n_state (0 for bytecode, non-zero for native)\nvoid mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    // This function is pretty complicated.  It's main aim is to be efficient in speed and RAM\n    // usage for the common case of positional only args.\n\n    // get the function object that we want to set up (could be bytecode or native code)\n    mp_obj_fun_bc_t *self = code_state->fun_bc;\n\n    // ip comes in as an offset into bytecode, so turn it into a true pointer\n    code_state->ip = self->bytecode + (size_t)code_state->ip;\n\n    #if MICROPY_STACKLESS\n    code_state->prev = NULL;\n    #endif\n\n    #if MICROPY_PY_SYS_SETTRACE\n    code_state->prev_state = NULL;\n    code_state->frame = NULL;\n    #endif\n\n    // Get cached n_state (rather than decode it again)\n    size_t n_state = code_state->n_state;\n\n    // Decode prelude\n    size_t n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args;\n    MP_BC_PRELUDE_SIG_DECODE_INTO(code_state->ip, n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args);\n    (void)n_state_unused;\n    (void)n_exc_stack_unused;\n\n    code_state->sp = &code_state->state[0] - 1;\n    code_state->exc_sp_idx = 0;\n\n    // zero out the local stack to begin with\n    memset(code_state->state, 0, n_state * sizeof(*code_state->state));\n\n    const mp_obj_t *kwargs = args + n_args;\n\n    // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed)\n    mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - n_pos_args - n_kwonly_args];\n\n    // check positional arguments\n\n    if (n_args > n_pos_args) {\n        // given more than enough arguments\n        if ((scope_flags & MP_SCOPE_FLAG_VARARGS) == 0) {\n            fun_pos_args_mismatch(self, n_pos_args, n_args);\n        }\n        // put extra arguments in varargs tuple\n        *var_pos_kw_args-- = mp_obj_new_tuple(n_args - n_pos_args, args + n_pos_args);\n        n_args = n_pos_args;\n    } else {\n        if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {\n            DEBUG_printf(\"passing empty tuple as *args\\n\");\n            *var_pos_kw_args-- = mp_const_empty_tuple;\n        }\n        // Apply processing and check below only if we don't have kwargs,\n        // otherwise, kw handling code below has own extensive checks.\n        if (n_kw == 0 && (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) == 0) {\n            if (n_args >= (size_t)(n_pos_args - n_def_pos_args)) {\n                // given enough arguments, but may need to use some default arguments\n                for (size_t i = n_args; i < n_pos_args; i++) {\n                    code_state->state[n_state - 1 - i] = self->extra_args[i - (n_pos_args - n_def_pos_args)];\n                }\n            } else {\n                fun_pos_args_mismatch(self, n_pos_args - n_def_pos_args, n_args);\n            }\n        }\n    }\n\n    // copy positional args into state\n    for (size_t i = 0; i < n_args; i++) {\n        code_state->state[n_state - 1 - i] = args[i];\n    }\n\n    // check keyword arguments\n\n    if (n_kw != 0 || (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {\n        DEBUG_printf(\"Initial args: \");\n        dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);\n\n        mp_obj_t dict = MP_OBJ_NULL;\n        if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {\n            dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?\n            *var_pos_kw_args = dict;\n        }\n\n        // get pointer to arg_names array\n        const mp_obj_t *arg_names = (const mp_obj_t *)self->const_table;\n\n        for (size_t i = 0; i < n_kw; i++) {\n            // the keys in kwargs are expected to be qstr objects\n            mp_obj_t wanted_arg_name = kwargs[2 * i];\n            for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) {\n                if (wanted_arg_name == arg_names[j]) {\n                    if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {\n                        mp_raise_msg_varg(&mp_type_TypeError,\n                            MP_ERROR_TEXT(\"function got multiple values for argument '%q'\"), MP_OBJ_QSTR_VALUE(wanted_arg_name));\n                    }\n                    code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];\n                    goto continue2;\n                }\n            }\n            // Didn't find name match with positional args\n            if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) {\n                #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                mp_raise_TypeError(MP_ERROR_TEXT(\"unexpected keyword argument\"));\n                #else\n                mp_raise_msg_varg(&mp_type_TypeError,\n                    MP_ERROR_TEXT(\"unexpected keyword argument '%q'\"), MP_OBJ_QSTR_VALUE(wanted_arg_name));\n                #endif\n            }\n            mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);\n        continue2:;\n        }\n\n        DEBUG_printf(\"Args with kws flattened: \");\n        dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);\n\n        // fill in defaults for positional args\n        mp_obj_t *d = &code_state->state[n_state - n_pos_args];\n        mp_obj_t *s = &self->extra_args[n_def_pos_args - 1];\n        for (size_t i = n_def_pos_args; i > 0; i--, d++, s--) {\n            if (*d == MP_OBJ_NULL) {\n                *d = *s;\n            }\n        }\n\n        DEBUG_printf(\"Args after filling default positional: \");\n        dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);\n\n        // Check that all mandatory positional args are specified\n        while (d < &code_state->state[n_state]) {\n            if (*d++ == MP_OBJ_NULL) {\n                mp_raise_msg_varg(&mp_type_TypeError,\n                    MP_ERROR_TEXT(\"function missing required positional argument #%d\"), &code_state->state[n_state] - d);\n            }\n        }\n\n        // Check that all mandatory keyword args are specified\n        // Fill in default kw args if we have them\n        for (size_t i = 0; i < n_kwonly_args; i++) {\n            if (code_state->state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) {\n                mp_map_elem_t *elem = NULL;\n                if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {\n                    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);\n                }\n                if (elem != NULL) {\n                    code_state->state[n_state - 1 - n_pos_args - i] = elem->value;\n                } else {\n                    mp_raise_msg_varg(&mp_type_TypeError,\n                        MP_ERROR_TEXT(\"function missing required keyword argument '%q'\"), MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i]));\n                }\n            }\n        }\n\n    } else {\n        // no keyword arguments given\n        if (n_kwonly_args != 0) {\n            mp_raise_TypeError(MP_ERROR_TEXT(\"function missing keyword-only argument\"));\n        }\n        if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {\n            *var_pos_kw_args = mp_obj_new_dict(0);\n        }\n    }\n\n    // read the size part of the prelude\n    const byte *ip = code_state->ip;\n    MP_BC_PRELUDE_SIZE_DECODE(ip);\n\n    // jump over code info (source file and line-number mapping)\n    ip += n_info;\n\n    // bytecode prelude: initialise closed over variables\n    for (; n_cell; --n_cell) {\n        size_t local_num = *ip++;\n        code_state->state[n_state - 1 - local_num] =\n            mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);\n    }\n\n    #if !MICROPY_PERSISTENT_CODE\n    // so bytecode is aligned\n    ip = MP_ALIGN(ip, sizeof(mp_uint_t));\n    #endif\n\n    // now that we skipped over the prelude, set the ip for the VM\n    code_state->ip = ip;\n\n    DEBUG_printf(\"Calling: n_pos_args=%d, n_kwonly_args=%d\\n\", n_pos_args, n_kwonly_args);\n    dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);\n    dump_args(code_state->state, n_state);\n}\n\n#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE\n\n// The following table encodes the number of bytes that a specific opcode\n// takes up.  Some opcodes have an extra byte, defined by MP_BC_MASK_EXTRA_BYTE.\n// There are 4 special opcodes that have an extra byte only when\n// MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE is enabled (and they take a qstr):\n//     MP_BC_LOAD_NAME\n//     MP_BC_LOAD_GLOBAL\n//     MP_BC_LOAD_ATTR\n//     MP_BC_STORE_ATTR\nuint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) {\n    uint f = MP_BC_FORMAT(*ip);\n    const byte *ip_start = ip;\n    if (f == MP_BC_FORMAT_QSTR) {\n        if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {\n            if (*ip == MP_BC_LOAD_NAME\n                || *ip == MP_BC_LOAD_GLOBAL\n                || *ip == MP_BC_LOAD_ATTR\n                || *ip == MP_BC_STORE_ATTR) {\n                ip += 1;\n            }\n        }\n        ip += 3;\n    } else {\n        int extra_byte = (*ip & MP_BC_MASK_EXTRA_BYTE) == 0;\n        ip += 1;\n        if (f == MP_BC_FORMAT_VAR_UINT) {\n            if (count_var_uint) {\n                while ((*ip++ & 0x80) != 0) {\n                }\n            }\n        } else if (f == MP_BC_FORMAT_OFFSET) {\n            ip += 2;\n        }\n        ip += extra_byte;\n    }\n    *opcode_size = ip - ip_start;\n    return f;\n}\n\n#endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE\n"
  },
  {
    "path": "py/bc.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_BC_H\n#define MICROPY_INCLUDED_PY_BC_H\n\n#include \"py/runtime.h\"\n#include \"py/objfun.h\"\n\n// bytecode layout:\n//\n//  func signature  : var uint\n//      contains six values interleaved bit-wise as: xSSSSEAA [xFSSKAED repeated]\n//          x = extension           another byte follows\n//          S = n_state - 1         number of entries in Python value stack\n//          E = n_exc_stack         number of entries in exception stack\n//          F = scope_flags         four bits of flags, MP_SCOPE_FLAG_xxx\n//          A = n_pos_args          number of arguments this function takes\n//          K = n_kwonly_args       number of keyword-only arguments this function takes\n//          D = n_def_pos_args      number of default positional arguments\n//\n//  prelude size    : var uint\n//      contains two values interleaved bit-wise as: xIIIIIIC repeated\n//          x = extension           another byte follows\n//          I = n_info              number of bytes in source info section\n//          C = n_cells             number of bytes/cells in closure section\n//\n//  source info section:\n//      simple_name : var qstr\n//      source_file : var qstr\n//      <line number info>\n//\n//  closure section:\n//      local_num0  : byte\n//      ...         : byte\n//      local_numN  : byte          N = n_cells-1\n//\n//  <word alignment padding>        only needed if bytecode contains pointers\n//\n//  <bytecode>\n//\n//\n// constant table layout:\n//\n//  argname0        : obj (qstr)\n//  ...             : obj (qstr)\n//  argnameN        : obj (qstr)    N = num_pos_args + num_kwonly_args\n//  const0          : obj\n//  constN          : obj\n\n#define MP_BC_PRELUDE_SIG_ENCODE(S, E, scope, out_byte, out_env) \\\n    do {                                                            \\\n        /*// Get values to store in prelude */                      \\\n        size_t F = scope->scope_flags & MP_SCOPE_FLAG_ALL_SIG;      \\\n        size_t A = scope->num_pos_args;                             \\\n        size_t K = scope->num_kwonly_args;                          \\\n        size_t D = scope->num_def_pos_args;                         \\\n                                                                \\\n        /* Adjust S to shrink range, to compress better */          \\\n        S -= 1;                                                     \\\n                                                                \\\n        /* Encode prelude */                                        \\\n        /* xSSSSEAA */                                              \\\n        uint8_t z = (S & 0xf) << 3 | (E & 1) << 2 | (A & 3);        \\\n        S >>= 4;                                                    \\\n        E >>= 1;                                                    \\\n        A >>= 2;                                                    \\\n        while (S | E | F | A | K | D) {                             \\\n            out_byte(out_env, 0x80 | z);                            \\\n            /* xFSSKAED */                                          \\\n            z = (F & 1) << 6 | (S & 3) << 4 | (K & 1) << 3          \\\n                | (A & 1) << 2 | (E & 1) << 1 | (D & 1);            \\\n            S >>= 2;                                                \\\n            E >>= 1;                                                \\\n            F >>= 1;                                                \\\n            A >>= 1;                                                \\\n            K >>= 1;                                                \\\n            D >>= 1;                                                \\\n        }                                                           \\\n        out_byte(out_env, z);                                       \\\n    } while (0)\n\n#define MP_BC_PRELUDE_SIG_DECODE_INTO(ip, S, E, F, A, K, D)     \\\n    do {                                                            \\\n        uint8_t z = *(ip)++;                                        \\\n        /* xSSSSEAA */                                              \\\n        S = (z >> 3) & 0xf;                                         \\\n        E = (z >> 2) & 0x1;                                         \\\n        F = 0;                                                      \\\n        A = z & 0x3;                                                \\\n        K = 0;                                                      \\\n        D = 0;                                                      \\\n        for (unsigned n = 0; z & 0x80; ++n) {                       \\\n            z = *(ip)++;                                            \\\n            /* xFSSKAED */                                          \\\n            S |= (z & 0x30) << (2 * n);                             \\\n            E |= (z & 0x02) << n;                                   \\\n            F |= ((z & 0x40) >> 6) << n;                            \\\n            A |= (z & 0x4) << n;                                    \\\n            K |= ((z & 0x08) >> 3) << n;                            \\\n            D |= (z & 0x1) << n;                                    \\\n        }                                                           \\\n        S += 1;                                                     \\\n    } while (0)\n\n#define MP_BC_PRELUDE_SIG_DECODE(ip) \\\n    size_t n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args; \\\n    MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args)\n\n#define MP_BC_PRELUDE_SIZE_ENCODE(I, C, out_byte, out_env)      \\\n    do {                                                            \\\n        /* Encode bit-wise as: xIIIIIIC */                          \\\n        uint8_t z = 0;                                              \\\n        do {                                                        \\\n            z = (I & 0x3f) << 1 | (C & 1);                          \\\n            C >>= 1;                                                \\\n            I >>= 6;                                                \\\n            if (C | I) {                                            \\\n                z |= 0x80;                                          \\\n            }                                                       \\\n            out_byte(out_env, z);                                   \\\n        } while (C | I);                                            \\\n    } while (0)\n\n#define MP_BC_PRELUDE_SIZE_DECODE_INTO(ip, I, C)                \\\n    do {                                                            \\\n        uint8_t z;                                                  \\\n        C = 0;                                                      \\\n        I = 0;                                                      \\\n        for (unsigned n = 0;; ++n) {                                \\\n            z = *(ip)++;                                            \\\n            /* xIIIIIIC */                                          \\\n            C |= (z & 1) << n;                                      \\\n            I |= ((z & 0x7e) >> 1) << (6 * n);                      \\\n            if (!(z & 0x80)) {                                      \\\n                break;                                              \\\n            }                                                       \\\n        }                                                           \\\n    } while (0)\n\n#define MP_BC_PRELUDE_SIZE_DECODE(ip) \\\n    size_t n_info, n_cell; \\\n    MP_BC_PRELUDE_SIZE_DECODE_INTO(ip, n_info, n_cell)\n\n// Sentinel value for mp_code_state_t.exc_sp_idx\n#define MP_CODE_STATE_EXC_SP_IDX_SENTINEL ((uint16_t)-1)\n\n// To convert mp_code_state_t.exc_sp_idx to/from a pointer to mp_exc_stack_t\n#define MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp) ((exc_sp) + 1 - (exc_stack))\n#define MP_CODE_STATE_EXC_SP_IDX_TO_PTR(exc_stack, exc_sp_idx) ((exc_stack) + (exc_sp_idx) - 1)\n\ntypedef struct _mp_bytecode_prelude_t {\n    uint n_state;\n    uint n_exc_stack;\n    uint scope_flags;\n    uint n_pos_args;\n    uint n_kwonly_args;\n    uint n_def_pos_args;\n    qstr qstr_block_name;\n    qstr qstr_source_file;\n    const byte *line_info;\n    const byte *opcodes;\n} mp_bytecode_prelude_t;\n\n// Exception stack entry\ntypedef struct _mp_exc_stack_t {\n    const byte *handler;\n    // bit 0 is currently unused\n    // bit 1 is whether the opcode was SETUP_WITH or SETUP_FINALLY\n    mp_obj_t *val_sp;\n    // Saved exception\n    mp_obj_base_t *prev_exc;\n} mp_exc_stack_t;\n\ntypedef struct _mp_code_state_t {\n    // The fun_bc entry points to the underlying function object that is being executed.\n    // It is needed to access the start of bytecode and the const_table.\n    // It is also needed to prevent the GC from reclaiming the bytecode during execution,\n    // because the ip pointer below will always point to the interior of the bytecode.\n    mp_obj_fun_bc_t *fun_bc;\n    const byte *ip;\n    mp_obj_t *sp;\n    uint16_t n_state;\n    uint16_t exc_sp_idx;\n    mp_obj_dict_t *old_globals;\n    #if MICROPY_STACKLESS\n    struct _mp_code_state_t *prev;\n    #endif\n    #if MICROPY_PY_SYS_SETTRACE\n    struct _mp_code_state_t *prev_state;\n    struct _mp_obj_frame_t *frame;\n    #endif\n    // Variable-length\n    mp_obj_t state[0];\n    // Variable-length, never accessed by name, only as (void*)(state + n_state)\n    // mp_exc_stack_t exc_state[0];\n} mp_code_state_t;\n\nmp_uint_t mp_decode_uint(const byte **ptr);\nmp_uint_t mp_decode_uint_value(const byte *ptr);\nconst byte *mp_decode_uint_skip(const byte *ptr);\n\nmp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc);\nmp_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);\nvoid mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args);\nvoid mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table);\nvoid mp_bytecode_print2(const mp_print_t *print, const byte *code, size_t len, const mp_uint_t *const_table);\nconst byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip);\n#define mp_bytecode_print_inst(print, code, const_table) mp_bytecode_print2(print, code, 1, const_table)\n\n// Helper macros to access pointer with least significant bits holding flags\n#define MP_TAGPTR_PTR(x) ((void *)((uintptr_t)(x) & ~((uintptr_t)3)))\n#define MP_TAGPTR_TAG0(x) ((uintptr_t)(x) & 1)\n#define MP_TAGPTR_TAG1(x) ((uintptr_t)(x) & 2)\n#define MP_TAGPTR_MAKE(ptr, tag) ((void *)((uintptr_t)(ptr) | (tag)))\n\n#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE\n\nuint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint);\n\n#endif\n\nstatic inline size_t mp_bytecode_get_source_line(const byte *line_info, size_t bc_offset) {\n    size_t source_line = 1;\n    size_t c;\n    while ((c = *line_info)) {\n        size_t b, l;\n        if ((c & 0x80) == 0) {\n            // 0b0LLBBBBB encoding\n            b = c & 0x1f;\n            l = c >> 5;\n            line_info += 1;\n        } else {\n            // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte)\n            b = c & 0xf;\n            l = ((c << 4) & 0x700) | line_info[1];\n            line_info += 2;\n        }\n        if (bc_offset >= b) {\n            bc_offset -= b;\n            source_line += l;\n        } else {\n            // found source line corresponding to bytecode offset\n            break;\n        }\n    }\n    return source_line;\n}\n\n#endif // MICROPY_INCLUDED_PY_BC_H\n"
  },
  {
    "path": "py/bc0.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_BC0_H\n#define MICROPY_INCLUDED_PY_BC0_H\n\n// MicroPython bytecode opcodes, grouped based on the format of the opcode\n\n#define MP_BC_MASK_FORMAT                   (0xf0)\n#define MP_BC_MASK_EXTRA_BYTE               (0x9e)\n\n#define MP_BC_FORMAT_BYTE                   (0)\n#define MP_BC_FORMAT_QSTR                   (1)\n#define MP_BC_FORMAT_VAR_UINT               (2)\n#define MP_BC_FORMAT_OFFSET                 (3)\n\n// Nibbles in magic number are: BB BB BB BB BB BO VV QU\n#define MP_BC_FORMAT(op) ((0x000003a4 >> (2 * ((op) >> 4))) & 3)\n\n// Load, Store, Delete, Import, Make, Build, Unpack, Call, Jump, Exception, For, sTack, Return, Yield, Op\n#define MP_BC_BASE_RESERVED                 (0x00) // ----------------\n#define MP_BC_BASE_QSTR_O                   (0x10) // LLLLLLSSSDDII---\n#define MP_BC_BASE_VINT_E                   (0x20) // MMLLLLSSDDBBBBBB\n#define MP_BC_BASE_VINT_O                   (0x30) // UUMMCCCC--------\n#define MP_BC_BASE_JUMP_E                   (0x40) // J-JJJJJEEEEF----\n#define MP_BC_BASE_BYTE_O                   (0x50) // LLLLSSDTTTTTEEFF\n#define MP_BC_BASE_BYTE_E                   (0x60) // --BREEEYYI------\n#define MP_BC_LOAD_CONST_SMALL_INT_MULTI    (0x70) // LLLLLLLLLLLLLLLL\n//                                          (0x80) // LLLLLLLLLLLLLLLL\n//                                          (0x90) // LLLLLLLLLLLLLLLL\n//                                          (0xa0) // LLLLLLLLLLLLLLLL\n#define MP_BC_LOAD_FAST_MULTI               (0xb0) // LLLLLLLLLLLLLLLL\n#define MP_BC_STORE_FAST_MULTI              (0xc0) // SSSSSSSSSSSSSSSS\n#define MP_BC_UNARY_OP_MULTI                (0xd0) // OOOOOOO\n#define MP_BC_BINARY_OP_MULTI               (0xd7) //        OOOOOOOOO\n//                                          (0xe0) // OOOOOOOOOOOOOOOO\n//                                          (0xf0) // OOOOOOOOOO------\n\n#define MP_BC_LOAD_CONST_SMALL_INT_MULTI_NUM (64)\n#define MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS (16)\n#define MP_BC_LOAD_FAST_MULTI_NUM           (16)\n#define MP_BC_STORE_FAST_MULTI_NUM          (16)\n#define MP_BC_UNARY_OP_MULTI_NUM            (MP_UNARY_OP_NUM_BYTECODE)\n#define MP_BC_BINARY_OP_MULTI_NUM           (MP_BINARY_OP_NUM_BYTECODE)\n\n#define MP_BC_LOAD_CONST_FALSE              (MP_BC_BASE_BYTE_O + 0x00)\n#define MP_BC_LOAD_CONST_NONE               (MP_BC_BASE_BYTE_O + 0x01)\n#define MP_BC_LOAD_CONST_TRUE               (MP_BC_BASE_BYTE_O + 0x02)\n#define MP_BC_LOAD_CONST_SMALL_INT          (MP_BC_BASE_VINT_E + 0x02) // signed var-int\n#define MP_BC_LOAD_CONST_STRING             (MP_BC_BASE_QSTR_O + 0x00) // qstr\n#define MP_BC_LOAD_CONST_OBJ                (MP_BC_BASE_VINT_E + 0x03) // ptr\n#define MP_BC_LOAD_NULL                     (MP_BC_BASE_BYTE_O + 0x03)\n\n#define MP_BC_LOAD_FAST_N                   (MP_BC_BASE_VINT_E + 0x04) // uint\n#define MP_BC_LOAD_DEREF                    (MP_BC_BASE_VINT_E + 0x05) // uint\n#define MP_BC_LOAD_NAME                     (MP_BC_BASE_QSTR_O + 0x01) // qstr\n#define MP_BC_LOAD_GLOBAL                   (MP_BC_BASE_QSTR_O + 0x02) // qstr\n#define MP_BC_LOAD_ATTR                     (MP_BC_BASE_QSTR_O + 0x03) // qstr\n#define MP_BC_LOAD_METHOD                   (MP_BC_BASE_QSTR_O + 0x04) // qstr\n#define MP_BC_LOAD_SUPER_METHOD             (MP_BC_BASE_QSTR_O + 0x05) // qstr\n#define MP_BC_LOAD_BUILD_CLASS              (MP_BC_BASE_BYTE_O + 0x04)\n#define MP_BC_LOAD_SUBSCR                   (MP_BC_BASE_BYTE_O + 0x05)\n\n#define MP_BC_STORE_FAST_N                  (MP_BC_BASE_VINT_E + 0x06) // uint\n#define MP_BC_STORE_DEREF                   (MP_BC_BASE_VINT_E + 0x07) // uint\n#define MP_BC_STORE_NAME                    (MP_BC_BASE_QSTR_O + 0x06) // qstr\n#define MP_BC_STORE_GLOBAL                  (MP_BC_BASE_QSTR_O + 0x07) // qstr\n#define MP_BC_STORE_ATTR                    (MP_BC_BASE_QSTR_O + 0x08) // qstr\n#define MP_BC_STORE_SUBSCR                  (MP_BC_BASE_BYTE_O + 0x06)\n\n#define MP_BC_DELETE_FAST                   (MP_BC_BASE_VINT_E + 0x08) // uint\n#define MP_BC_DELETE_DEREF                  (MP_BC_BASE_VINT_E + 0x09) // uint\n#define MP_BC_DELETE_NAME                   (MP_BC_BASE_QSTR_O + 0x09) // qstr\n#define MP_BC_DELETE_GLOBAL                 (MP_BC_BASE_QSTR_O + 0x0a) // qstr\n\n#define MP_BC_DUP_TOP                       (MP_BC_BASE_BYTE_O + 0x07)\n#define MP_BC_DUP_TOP_TWO                   (MP_BC_BASE_BYTE_O + 0x08)\n#define MP_BC_POP_TOP                       (MP_BC_BASE_BYTE_O + 0x09)\n#define MP_BC_ROT_TWO                       (MP_BC_BASE_BYTE_O + 0x0a)\n#define MP_BC_ROT_THREE                     (MP_BC_BASE_BYTE_O + 0x0b)\n\n#define MP_BC_JUMP                          (MP_BC_BASE_JUMP_E + 0x02) // rel byte code offset, 16-bit signed, in excess\n#define MP_BC_POP_JUMP_IF_TRUE              (MP_BC_BASE_JUMP_E + 0x03) // rel byte code offset, 16-bit signed, in excess\n#define MP_BC_POP_JUMP_IF_FALSE             (MP_BC_BASE_JUMP_E + 0x04) // rel byte code offset, 16-bit signed, in excess\n#define MP_BC_JUMP_IF_TRUE_OR_POP           (MP_BC_BASE_JUMP_E + 0x05) // rel byte code offset, 16-bit signed, in excess\n#define MP_BC_JUMP_IF_FALSE_OR_POP          (MP_BC_BASE_JUMP_E + 0x06) // rel byte code offset, 16-bit signed, in excess\n#define MP_BC_UNWIND_JUMP                   (MP_BC_BASE_JUMP_E + 0x00) // rel byte code offset, 16-bit signed, in excess; then a byte\n#define MP_BC_SETUP_WITH                    (MP_BC_BASE_JUMP_E + 0x07) // rel byte code offset, 16-bit unsigned\n#define MP_BC_SETUP_EXCEPT                  (MP_BC_BASE_JUMP_E + 0x08) // rel byte code offset, 16-bit unsigned\n#define MP_BC_SETUP_FINALLY                 (MP_BC_BASE_JUMP_E + 0x09) // rel byte code offset, 16-bit unsigned\n#define MP_BC_POP_EXCEPT_JUMP               (MP_BC_BASE_JUMP_E + 0x0a) // rel byte code offset, 16-bit unsigned\n#define MP_BC_FOR_ITER                      (MP_BC_BASE_JUMP_E + 0x0b) // rel byte code offset, 16-bit unsigned\n#define MP_BC_WITH_CLEANUP                  (MP_BC_BASE_BYTE_O + 0x0c)\n#define MP_BC_END_FINALLY                   (MP_BC_BASE_BYTE_O + 0x0d)\n#define MP_BC_GET_ITER                      (MP_BC_BASE_BYTE_O + 0x0e)\n#define MP_BC_GET_ITER_STACK                (MP_BC_BASE_BYTE_O + 0x0f)\n\n#define MP_BC_BUILD_TUPLE                   (MP_BC_BASE_VINT_E + 0x0a) // uint\n#define MP_BC_BUILD_LIST                    (MP_BC_BASE_VINT_E + 0x0b) // uint\n#define MP_BC_BUILD_MAP                     (MP_BC_BASE_VINT_E + 0x0c) // uint\n#define MP_BC_STORE_MAP                     (MP_BC_BASE_BYTE_E + 0x02)\n#define MP_BC_BUILD_SET                     (MP_BC_BASE_VINT_E + 0x0d) // uint\n#define MP_BC_BUILD_SLICE                   (MP_BC_BASE_VINT_E + 0x0e) // uint\n#define MP_BC_STORE_COMP                    (MP_BC_BASE_VINT_E + 0x0f) // uint\n#define MP_BC_UNPACK_SEQUENCE               (MP_BC_BASE_VINT_O + 0x00) // uint\n#define MP_BC_UNPACK_EX                     (MP_BC_BASE_VINT_O + 0x01) // uint\n\n#define MP_BC_RETURN_VALUE                  (MP_BC_BASE_BYTE_E + 0x03)\n#define MP_BC_RAISE_LAST                    (MP_BC_BASE_BYTE_E + 0x04)\n#define MP_BC_RAISE_OBJ                     (MP_BC_BASE_BYTE_E + 0x05)\n#define MP_BC_RAISE_FROM                    (MP_BC_BASE_BYTE_E + 0x06)\n#define MP_BC_YIELD_VALUE                   (MP_BC_BASE_BYTE_E + 0x07)\n#define MP_BC_YIELD_FROM                    (MP_BC_BASE_BYTE_E + 0x08)\n\n#define MP_BC_MAKE_FUNCTION                 (MP_BC_BASE_VINT_O + 0x02) // uint\n#define MP_BC_MAKE_FUNCTION_DEFARGS         (MP_BC_BASE_VINT_O + 0x03) // uint\n#define MP_BC_MAKE_CLOSURE                  (MP_BC_BASE_VINT_E + 0x00) // uint; extra byte\n#define MP_BC_MAKE_CLOSURE_DEFARGS          (MP_BC_BASE_VINT_E + 0x01) // uint; extra byte\n#define MP_BC_CALL_FUNCTION                 (MP_BC_BASE_VINT_O + 0x04) // uint\n#define MP_BC_CALL_FUNCTION_VAR_KW          (MP_BC_BASE_VINT_O + 0x05) // uint\n#define MP_BC_CALL_METHOD                   (MP_BC_BASE_VINT_O + 0x06) // uint\n#define MP_BC_CALL_METHOD_VAR_KW            (MP_BC_BASE_VINT_O + 0x07) // uint\n\n#define MP_BC_IMPORT_NAME                   (MP_BC_BASE_QSTR_O + 0x0b) // qstr\n#define MP_BC_IMPORT_FROM                   (MP_BC_BASE_QSTR_O + 0x0c) // qstr\n#define MP_BC_IMPORT_STAR                   (MP_BC_BASE_BYTE_E + 0x09)\n\n#endif // MICROPY_INCLUDED_PY_BC0_H\n"
  },
  {
    "path": "py/binary.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2017 Paul Sokolovsky\n * Copyright (c) 2014-2019 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/binary.h\"\n#include \"py/smallint.h\"\n#include \"py/objint.h\"\n#include \"py/runtime.h\"\n\n// Helpers to work with binary-encoded data\n\n#ifndef alignof\n#define alignof(type) offsetof(struct { char c; type t; }, t)\n#endif\n\nsize_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) {\n    size_t size = 0;\n    int align = 1;\n    switch (struct_type) {\n        case '<':\n        case '>':\n            switch (val_type) {\n                case 'b':\n                case 'B':\n                    size = 1;\n                    break;\n                case 'h':\n                case 'H':\n                    size = 2;\n                    break;\n                case 'i':\n                case 'I':\n                    size = 4;\n                    break;\n                case 'l':\n                case 'L':\n                    size = 4;\n                    break;\n                case 'q':\n                case 'Q':\n                    size = 8;\n                    break;\n                case 'P':\n                case 'O':\n                case 'S':\n                    size = sizeof(void *);\n                    break;\n                case 'f':\n                    size = sizeof(float);\n                    break;\n                case 'd':\n                    size = sizeof(double);\n                    break;\n            }\n            break;\n        case '@': {\n            // TODO:\n            // The simplest heuristic for alignment is to align by value\n            // size, but that doesn't work for \"bigger than int\" types,\n            // for example, long long may very well have long alignment\n            // So, we introduce separate alignment handling, but having\n            // formal support for that is different from actually supporting\n            // particular (or any) ABI.\n            switch (val_type) {\n                case BYTEARRAY_TYPECODE:\n                case 'b':\n                case 'B':\n                    align = size = 1;\n                    break;\n                case 'h':\n                case 'H':\n                    align = alignof(short);\n                    size = sizeof(short);\n                    break;\n                case 'i':\n                case 'I':\n                    align = alignof(int);\n                    size = sizeof(int);\n                    break;\n                case 'l':\n                case 'L':\n                    align = alignof(long);\n                    size = sizeof(long);\n                    break;\n                case 'q':\n                case 'Q':\n                    align = alignof(long long);\n                    size = sizeof(long long);\n                    break;\n                case 'P':\n                case 'O':\n                case 'S':\n                    align = alignof(void *);\n                    size = sizeof(void *);\n                    break;\n                case 'f':\n                    align = alignof(float);\n                    size = sizeof(float);\n                    break;\n                case 'd':\n                    align = alignof(double);\n                    size = sizeof(double);\n                    break;\n            }\n        }\n    }\n\n    if (size == 0) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"bad typecode\"));\n    }\n\n    if (palign != NULL) {\n        *palign = align;\n    }\n    return size;\n}\n\nmp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) {\n    mp_int_t val = 0;\n    switch (typecode) {\n        case 'b':\n            val = ((signed char *)p)[index];\n            break;\n        case BYTEARRAY_TYPECODE:\n        case 'B':\n            val = ((unsigned char *)p)[index];\n            break;\n        case 'h':\n            val = ((short *)p)[index];\n            break;\n        case 'H':\n            val = ((unsigned short *)p)[index];\n            break;\n        case 'i':\n            return mp_obj_new_int(((int *)p)[index]);\n        case 'I':\n            return mp_obj_new_int_from_uint(((unsigned int *)p)[index]);\n        case 'l':\n            return mp_obj_new_int(((long *)p)[index]);\n        case 'L':\n            return mp_obj_new_int_from_uint(((unsigned long *)p)[index]);\n        #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE\n        case 'q':\n            return mp_obj_new_int_from_ll(((long long *)p)[index]);\n        case 'Q':\n            return mp_obj_new_int_from_ull(((unsigned long long *)p)[index]);\n        #endif\n        #if MICROPY_PY_BUILTINS_FLOAT\n        case 'f':\n            return mp_obj_new_float_from_f(((float *)p)[index]);\n        case 'd':\n            return mp_obj_new_float_from_d(((double *)p)[index]);\n        #endif\n        // Extension to CPython: array of objects\n        case 'O':\n            return ((mp_obj_t *)p)[index];\n        // Extension to CPython: array of pointers\n        case 'P':\n            return mp_obj_new_int((mp_int_t)(uintptr_t)((void **)p)[index]);\n    }\n    return MP_OBJ_NEW_SMALL_INT(val);\n}\n\n// The long long type is guaranteed to hold at least 64 bits, and size is at\n// most 8 (for q and Q), so we will always be able to parse the given data\n// and fit it into a long long.\nlong long mp_binary_get_int(size_t size, bool is_signed, bool big_endian, const byte *src) {\n    int delta;\n    if (!big_endian) {\n        delta = -1;\n        src += size - 1;\n    } else {\n        delta = 1;\n    }\n\n    long long val = 0;\n    if (is_signed && *src & 0x80) {\n        val = -1;\n    }\n    for (uint i = 0; i < size; i++) {\n        val <<= 8;\n        val |= *src;\n        src += delta;\n    }\n\n    return val;\n}\n\n#define is_signed(typecode) (typecode > 'Z')\nmp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr) {\n    byte *p = *ptr;\n    size_t align;\n\n    size_t size = mp_binary_get_size(struct_type, val_type, &align);\n    if (struct_type == '@') {\n        // Align p relative to p_base\n        p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align);\n        #if MP_ENDIANNESS_LITTLE\n        struct_type = '<';\n        #else\n        struct_type = '>';\n        #endif\n    }\n    *ptr = p + size;\n\n    long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);\n\n    if (val_type == 'O') {\n        return (mp_obj_t)(mp_uint_t)val;\n    } else if (val_type == 'S') {\n        const char *s_val = (const char *)(uintptr_t)(mp_uint_t)val;\n        return mp_obj_new_str(s_val, strlen(s_val));\n    #if MICROPY_PY_BUILTINS_FLOAT\n    } else if (val_type == 'f') {\n        union { uint32_t i;\n                float f;\n        } fpu = {val};\n        return mp_obj_new_float_from_f(fpu.f);\n    } else if (val_type == 'd') {\n        union { uint64_t i;\n                double f;\n        } fpu = {val};\n        return mp_obj_new_float_from_d(fpu.f);\n    #endif\n    } else if (is_signed(val_type)) {\n        if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) {\n            return mp_obj_new_int((mp_int_t)val);\n        } else {\n            return mp_obj_new_int_from_ll(val);\n        }\n    } else {\n        if ((unsigned long long)val <= (unsigned long long)MP_SMALL_INT_MAX) {\n            return mp_obj_new_int_from_uint((mp_uint_t)val);\n        } else {\n            return mp_obj_new_int_from_ull(val);\n        }\n    }\n}\n\nvoid mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val) {\n    if (MP_ENDIANNESS_LITTLE && !big_endian) {\n        memcpy(dest, &val, val_sz);\n    } else if (MP_ENDIANNESS_BIG && big_endian) {\n        // only copy the least-significant val_sz bytes\n        memcpy(dest, (byte *)&val + sizeof(mp_uint_t) - val_sz, val_sz);\n    } else {\n        const byte *src;\n        if (MP_ENDIANNESS_LITTLE) {\n            src = (const byte *)&val + val_sz;\n        } else {\n            src = (const byte *)&val + sizeof(mp_uint_t);\n        }\n        while (val_sz--) {\n            *dest++ = *--src;\n        }\n    }\n}\n\nvoid mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr) {\n    byte *p = *ptr;\n    size_t align;\n\n    size_t size = mp_binary_get_size(struct_type, val_type, &align);\n    if (struct_type == '@') {\n        // Align p relative to p_base\n        p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align);\n        if (MP_ENDIANNESS_LITTLE) {\n            struct_type = '<';\n        } else {\n            struct_type = '>';\n        }\n    }\n    *ptr = p + size;\n\n    mp_uint_t val;\n    switch (val_type) {\n        case 'O':\n            val = (mp_uint_t)val_in;\n            break;\n        #if MICROPY_PY_BUILTINS_FLOAT\n        case 'f': {\n            union { uint32_t i;\n                    float f;\n            } fp_sp;\n            fp_sp.f = mp_obj_get_float_to_f(val_in);\n            val = fp_sp.i;\n            break;\n        }\n        case 'd': {\n            union { uint64_t i64;\n                    uint32_t i32[2];\n                    double f;\n            } fp_dp;\n            fp_dp.f = mp_obj_get_float_to_d(val_in);\n            if (BYTES_PER_WORD == 8) {\n                val = fp_dp.i64;\n            } else {\n                int be = struct_type == '>';\n                mp_binary_set_int(sizeof(uint32_t), be, p, fp_dp.i32[MP_ENDIANNESS_BIG ^ be]);\n                p += sizeof(uint32_t);\n                val = fp_dp.i32[MP_ENDIANNESS_LITTLE ^ be];\n            }\n            break;\n        }\n        #endif\n        default:\n            #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE\n            if (mp_obj_is_type(val_in, &mp_type_int)) {\n                mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p);\n                return;\n            }\n            #endif\n\n            val = mp_obj_get_int(val_in);\n            // zero/sign extend if needed\n            if (BYTES_PER_WORD < 8 && size > sizeof(val)) {\n                int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00;\n                memset(p, c, size);\n                if (struct_type == '>') {\n                    p += size - sizeof(val);\n                }\n            }\n            break;\n    }\n\n    mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val);\n}\n\nvoid mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in) {\n    switch (typecode) {\n        #if MICROPY_PY_BUILTINS_FLOAT\n        case 'f':\n            ((float *)p)[index] = mp_obj_get_float_to_f(val_in);\n            break;\n        case 'd':\n            ((double *)p)[index] = mp_obj_get_float_to_d(val_in);\n            break;\n        #endif\n        // Extension to CPython: array of objects\n        case 'O':\n            ((mp_obj_t *)p)[index] = val_in;\n            break;\n        default:\n            #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE\n            if (mp_obj_is_type(val_in, &mp_type_int)) {\n                size_t size = mp_binary_get_size('@', typecode, NULL);\n                mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG,\n                    size, (uint8_t *)p + index * size);\n                return;\n            }\n            #endif\n            mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));\n    }\n}\n\nvoid mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val) {\n    switch (typecode) {\n        case 'b':\n            ((signed char *)p)[index] = val;\n            break;\n        case BYTEARRAY_TYPECODE:\n        case 'B':\n            ((unsigned char *)p)[index] = val;\n            break;\n        case 'h':\n            ((short *)p)[index] = val;\n            break;\n        case 'H':\n            ((unsigned short *)p)[index] = val;\n            break;\n        case 'i':\n            ((int *)p)[index] = val;\n            break;\n        case 'I':\n            ((unsigned int *)p)[index] = val;\n            break;\n        case 'l':\n            ((long *)p)[index] = val;\n            break;\n        case 'L':\n            ((unsigned long *)p)[index] = val;\n            break;\n        #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE\n        case 'q':\n            ((long long *)p)[index] = val;\n            break;\n        case 'Q':\n            ((unsigned long long *)p)[index] = val;\n            break;\n        #endif\n        #if MICROPY_PY_BUILTINS_FLOAT\n        case 'f':\n            ((float *)p)[index] = (float)val;\n            break;\n        case 'd':\n            ((double *)p)[index] = (double)val;\n            break;\n        #endif\n        // Extension to CPython: array of pointers\n        case 'P':\n            ((void **)p)[index] = (void *)(uintptr_t)val;\n            break;\n    }\n}\n"
  },
  {
    "path": "py/binary.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Paul Sokolovsky\n * Copyright (c) 2014-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_BINARY_H\n#define MICROPY_INCLUDED_PY_BINARY_H\n\n#include \"py/obj.h\"\n\n// Use special typecode to differentiate repr() of bytearray vs array.array('B')\n// (underlyingly they're same).  Can't use 0 here because that's used to detect\n// type-specification errors due to end-of-string.\n#define BYTEARRAY_TYPECODE 1\n\nsize_t mp_binary_get_size(char struct_type, char val_type, size_t *palign);\nmp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index);\nvoid mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in);\nvoid mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val);\nmp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr);\nvoid mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr);\nlong long mp_binary_get_int(size_t size, bool is_signed, bool big_endian, const byte *src);\nvoid mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val);\n\n#endif // MICROPY_INCLUDED_PY_BINARY_H\n"
  },
  {
    "path": "py/builtin.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_BUILTIN_H\n#define MICROPY_INCLUDED_PY_BUILTIN_H\n\n#include \"py/obj.h\"\n\nmp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args);\nmp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);\nmp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args);\n\nMP_DECLARE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_abs_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_all_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_any_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_bin_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_callable_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_chr_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_execfile_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj);\nMP_DECLARE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_globals_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_hash_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_hex_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_id_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_iter_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_len_obj);\nMP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_locals_obj);\nMP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_max_obj);\nMP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_min_obj);\n#if MICROPY_PY_BUILTINS_NEXT2\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_next_obj);\n#else\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_next_obj);\n#endif\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_oct_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_ord_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj);\nMP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_print_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_repr_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj);\nMP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj);\n// Defined by a port, but declared here for simplicity\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_input_obj);\nMP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj);\n\nMP_DECLARE_CONST_FUN_OBJ_2(mp_namedtuple_obj);\n\nMP_DECLARE_CONST_FUN_OBJ_2(mp_op_contains_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_op_getitem_obj);\nMP_DECLARE_CONST_FUN_OBJ_3(mp_op_setitem_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_op_delitem_obj);\n\nextern const mp_obj_module_t mp_module___main__;\nextern const mp_obj_module_t mp_module_builtins;\nextern const mp_obj_module_t mp_module_uarray;\nextern const mp_obj_module_t mp_module_collections;\nextern const mp_obj_module_t mp_module_io;\nextern const mp_obj_module_t mp_module_math;\nextern const mp_obj_module_t mp_module_cmath;\nextern const mp_obj_module_t mp_module_micropython;\nextern const mp_obj_module_t mp_module_ustruct;\nextern const mp_obj_module_t mp_module_sys;\nextern const mp_obj_module_t mp_module_gc;\nextern const mp_obj_module_t mp_module_thread;\n\nextern const mp_obj_dict_t mp_module_builtins_globals;\n\n// extmod modules\nextern const mp_obj_module_t mp_module_uasyncio;\nextern const mp_obj_module_t mp_module_uerrno;\nextern const mp_obj_module_t mp_module_uctypes;\nextern const mp_obj_module_t mp_module_uzlib;\nextern const mp_obj_module_t mp_module_ujson;\nextern const mp_obj_module_t mp_module_ure;\nextern const mp_obj_module_t mp_module_uheapq;\nextern const mp_obj_module_t mp_module_uhashlib;\nextern const mp_obj_module_t mp_module_ucryptolib;\nextern const mp_obj_module_t mp_module_ubinascii;\nextern const mp_obj_module_t mp_module_urandom;\nextern const mp_obj_module_t mp_module_uselect;\nextern const mp_obj_module_t mp_module_ussl;\nextern const mp_obj_module_t mp_module_utimeq;\nextern const mp_obj_module_t mp_module_machine;\nextern const mp_obj_module_t mp_module_lwip;\nextern const mp_obj_module_t mp_module_uwebsocket;\nextern const mp_obj_module_t mp_module_webrepl;\nextern const mp_obj_module_t mp_module_framebuf;\nextern const mp_obj_module_t mp_module_btree;\nextern const mp_obj_module_t mp_module_ubluetooth;\n\nextern const char MICROPY_PY_BUILTINS_HELP_TEXT[];\n\n#endif // MICROPY_INCLUDED_PY_BUILTIN_H\n"
  },
  {
    "path": "py/builtinevex.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n\n#include \"py/objfun.h\"\n#include \"py/compile.h\"\n#include \"py/runtime.h\"\n#include \"py/builtin.h\"\n\n#if MICROPY_PY_BUILTINS_COMPILE\n\ntypedef struct _mp_obj_code_t {\n    mp_obj_base_t base;\n    mp_obj_t module_fun;\n} mp_obj_code_t;\n\nSTATIC const mp_obj_type_t mp_type_code = {\n    { &mp_type_type },\n    .name = MP_QSTR_code,\n};\n\nSTATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj_dict_t *locals) {\n    // save context and set new context\n    mp_obj_dict_t *old_globals = mp_globals_get();\n    mp_obj_dict_t *old_locals = mp_locals_get();\n    mp_globals_set(globals);\n    mp_locals_set(locals);\n\n    // a bit of a hack: fun_bc will re-set globals, so need to make sure it's\n    // the correct one\n    if (mp_obj_is_type(self->module_fun, &mp_type_fun_bc)) {\n        mp_obj_fun_bc_t *fun_bc = MP_OBJ_TO_PTR(self->module_fun);\n        fun_bc->globals = globals;\n    }\n\n    // execute code\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        mp_obj_t ret = mp_call_function_0(self->module_fun);\n        nlr_pop();\n        mp_globals_set(old_globals);\n        mp_locals_set(old_locals);\n        return ret;\n    } else {\n        // exception; restore context and re-raise same exception\n        mp_globals_set(old_globals);\n        mp_locals_set(old_locals);\n        nlr_jump(nlr.ret_val);\n    }\n}\n\nSTATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n\n    // get the source\n    size_t str_len;\n    const char *str = mp_obj_str_get_data(args[0], &str_len);\n\n    // get the filename\n    qstr filename = mp_obj_str_get_qstr(args[1]);\n\n    // create the lexer\n    mp_lexer_t *lex = mp_lexer_new_from_str_len(filename, str, str_len, 0);\n\n    // get the compile mode\n    qstr mode = mp_obj_str_get_qstr(args[2]);\n    mp_parse_input_kind_t parse_input_kind;\n    switch (mode) {\n        case MP_QSTR_single:\n            parse_input_kind = MP_PARSE_SINGLE_INPUT;\n            break;\n        case MP_QSTR_exec:\n            parse_input_kind = MP_PARSE_FILE_INPUT;\n            break;\n        case MP_QSTR_eval:\n            parse_input_kind = MP_PARSE_EVAL_INPUT;\n            break;\n        default:\n            mp_raise_ValueError(MP_ERROR_TEXT(\"bad compile mode\"));\n    }\n\n    mp_obj_code_t *code = m_new_obj(mp_obj_code_t);\n    code->base.type = &mp_type_code;\n    code->module_fun = mp_parse_compile_execute(lex, parse_input_kind, NULL, NULL);\n    return MP_OBJ_FROM_PTR(code);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj, 3, 6, mp_builtin_compile);\n\n#endif // MICROPY_PY_BUILTINS_COMPILE\n\n#if MICROPY_PY_BUILTINS_EVAL_EXEC\n\nSTATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_input_kind_t parse_input_kind) {\n    // work out the context\n    mp_obj_dict_t *globals = mp_globals_get();\n    mp_obj_dict_t *locals = mp_locals_get();\n    for (size_t i = 1; i < 3 && i < n_args; ++i) {\n        if (args[i] != mp_const_none) {\n            if (!mp_obj_is_type(args[i], &mp_type_dict)) {\n                mp_raise_TypeError(NULL);\n            }\n            locals = MP_OBJ_TO_PTR(args[i]);\n            if (i == 1) {\n                globals = locals;\n            }\n        }\n    }\n\n    #if MICROPY_PY_BUILTINS_COMPILE\n    if (mp_obj_is_type(args[0], &mp_type_code)) {\n        return code_execute(MP_OBJ_TO_PTR(args[0]), globals, locals);\n    }\n    #endif\n\n    // Extract the source code.\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);\n\n    // create the lexer\n    // MP_PARSE_SINGLE_INPUT is used to indicate a file input\n    mp_lexer_t *lex;\n    if (MICROPY_PY_BUILTINS_EXECFILE && parse_input_kind == MP_PARSE_SINGLE_INPUT) {\n        lex = mp_lexer_new_from_file(bufinfo.buf);\n        parse_input_kind = MP_PARSE_FILE_INPUT;\n    } else {\n        lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, bufinfo.buf, bufinfo.len, 0);\n    }\n\n    return mp_parse_compile_execute(lex, parse_input_kind, globals, locals);\n}\n\nSTATIC mp_obj_t mp_builtin_eval(size_t n_args, const mp_obj_t *args) {\n    return eval_exec_helper(n_args, args, MP_PARSE_EVAL_INPUT);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj, 1, 3, mp_builtin_eval);\n\nSTATIC mp_obj_t mp_builtin_exec(size_t n_args, const mp_obj_t *args) {\n    return eval_exec_helper(n_args, args, MP_PARSE_FILE_INPUT);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj, 1, 3, mp_builtin_exec);\n\n#endif // MICROPY_PY_BUILTINS_EVAL_EXEC\n\n#if MICROPY_PY_BUILTINS_EXECFILE\nSTATIC mp_obj_t mp_builtin_execfile(size_t n_args, const mp_obj_t *args) {\n    // MP_PARSE_SINGLE_INPUT is used to indicate a file input\n    return eval_exec_helper(n_args, args, MP_PARSE_SINGLE_INPUT);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_execfile_obj, 1, 3, mp_builtin_execfile);\n#endif\n"
  },
  {
    "path": "py/builtinhelp.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/builtin.h\"\n#include \"py/objmodule.h\"\n\n#if MICROPY_PY_BUILTINS_HELP\n\nconst char mp_help_default_text[] =\n    \"Welcome to MicroPython!\\n\"\n    \"\\n\"\n    \"For online docs please visit http://docs.micropython.org/\\n\"\n    \"\\n\"\n    \"Control commands:\\n\"\n    \"  CTRL-A        -- on a blank line, enter raw REPL mode\\n\"\n    \"  CTRL-B        -- on a blank line, enter normal REPL mode\\n\"\n    \"  CTRL-C        -- interrupt a running program\\n\"\n    \"  CTRL-D        -- on a blank line, exit or do a soft reset\\n\"\n    \"  CTRL-E        -- on a blank line, enter paste mode\\n\"\n    \"\\n\"\n    \"For further help on a specific object, type help(obj)\\n\"\n;\n\nSTATIC void mp_help_print_info_about_object(mp_obj_t name_o, mp_obj_t value) {\n    mp_print_str(MP_PYTHON_PRINTER, \"  \");\n    mp_obj_print(name_o, PRINT_STR);\n    mp_print_str(MP_PYTHON_PRINTER, \" -- \");\n    mp_obj_print(value, PRINT_STR);\n    mp_print_str(MP_PYTHON_PRINTER, \"\\n\");\n}\n\n#if MICROPY_PY_BUILTINS_HELP_MODULES\nSTATIC void mp_help_add_from_map(mp_obj_t list, const mp_map_t *map) {\n    for (size_t i = 0; i < map->alloc; i++) {\n        if (mp_map_slot_is_filled(map, i)) {\n            mp_obj_list_append(list, map->table[i].key);\n        }\n    }\n}\n\n#if MICROPY_MODULE_FROZEN\nSTATIC void mp_help_add_from_names(mp_obj_t list, const char *name) {\n    while (*name) {\n        size_t l = strlen(name);\n        // name should end in '.py' and we strip it off\n        mp_obj_list_append(list, mp_obj_new_str(name, l - 3));\n        name += l + 1;\n    }\n}\n#endif\n\nSTATIC void mp_help_print_modules(void) {\n    mp_obj_t list = mp_obj_new_list(0, NULL);\n\n    mp_help_add_from_map(list, &mp_builtin_module_map);\n\n    #if MICROPY_MODULE_FROZEN_STR\n    extern const char mp_frozen_str_names[];\n    mp_help_add_from_names(list, mp_frozen_str_names);\n    #endif\n\n    #if MICROPY_MODULE_FROZEN_MPY\n    extern const char mp_frozen_mpy_names[];\n    mp_help_add_from_names(list, mp_frozen_mpy_names);\n    #endif\n\n    // sort the list so it's printed in alphabetical order\n    mp_obj_list_sort(1, &list, (mp_map_t *)&mp_const_empty_map);\n\n    // print the list of modules in a column-first order\n    #define NUM_COLUMNS (4)\n    #define COLUMN_WIDTH (18)\n    size_t len;\n    mp_obj_t *items;\n    mp_obj_list_get(list, &len, &items);\n    unsigned int num_rows = (len + NUM_COLUMNS - 1) / NUM_COLUMNS;\n    for (unsigned int i = 0; i < num_rows; ++i) {\n        unsigned int j = i;\n        for (;;) {\n            int l = mp_print_str(MP_PYTHON_PRINTER, mp_obj_str_get_str(items[j]));\n            j += num_rows;\n            if (j >= len) {\n                break;\n            }\n            int gap = COLUMN_WIDTH - l;\n            while (gap < 1) {\n                gap += COLUMN_WIDTH;\n            }\n            while (gap--) {\n                mp_print_str(MP_PYTHON_PRINTER, \" \");\n            }\n        }\n        mp_print_str(MP_PYTHON_PRINTER, \"\\n\");\n    }\n\n    #if MICROPY_ENABLE_EXTERNAL_IMPORT\n    // let the user know there may be other modules available from the filesystem\n    mp_print_str(MP_PYTHON_PRINTER, \"Plus any modules on the filesystem\\n\");\n    #endif\n}\n#endif\n\nSTATIC void mp_help_print_obj(const mp_obj_t obj) {\n    #if MICROPY_PY_BUILTINS_HELP_MODULES\n    if (obj == MP_OBJ_NEW_QSTR(MP_QSTR_modules)) {\n        mp_help_print_modules();\n        return;\n    }\n    #endif\n\n    const mp_obj_type_t *type = mp_obj_get_type(obj);\n\n    // try to print something sensible about the given object\n    mp_print_str(MP_PYTHON_PRINTER, \"object \");\n    mp_obj_print(obj, PRINT_STR);\n    mp_printf(MP_PYTHON_PRINTER, \" is of type %q\\n\", type->name);\n\n    mp_map_t *map = NULL;\n    if (type == &mp_type_module) {\n        map = &mp_obj_module_get_globals(obj)->map;\n    } else {\n        if (type == &mp_type_type) {\n            type = MP_OBJ_TO_PTR(obj);\n        }\n        if (type->locals_dict != NULL) {\n            map = &type->locals_dict->map;\n        }\n    }\n    if (map != NULL) {\n        for (uint i = 0; i < map->alloc; i++) {\n            if (map->table[i].key != MP_OBJ_NULL) {\n                mp_help_print_info_about_object(map->table[i].key, map->table[i].value);\n            }\n        }\n    }\n}\n\nSTATIC mp_obj_t mp_builtin_help(size_t n_args, const mp_obj_t *args) {\n    if (n_args == 0) {\n        // print a general help message\n        mp_print_str(MP_PYTHON_PRINTER, MICROPY_PY_BUILTINS_HELP_TEXT);\n    } else {\n        // try to print something sensible about the given object\n        mp_help_print_obj(args[0]);\n    }\n\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj, 0, 1, mp_builtin_help);\n\n#endif // MICROPY_PY_BUILTINS_HELP\n"
  },
  {
    "path": "py/builtinimport.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2019 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/compile.h\"\n#include \"py/objmodule.h\"\n#include \"py/persistentcode.h\"\n#include \"py/runtime.h\"\n#include \"py/builtin.h\"\n#include \"py/frozenmod.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_PRINT (1)\n#define DEBUG_printf DEBUG_printf\n#else // don't print debugging info\n#define DEBUG_PRINT (0)\n#define DEBUG_printf(...) (void)0\n#endif\n\n#if MICROPY_ENABLE_EXTERNAL_IMPORT\n\n#define PATH_SEP_CHAR '/'\n\nbool mp_obj_is_package(mp_obj_t module) {\n    mp_obj_t dest[2];\n    mp_load_method_maybe(module, MP_QSTR___path__, dest);\n    return dest[0] != MP_OBJ_NULL;\n}\n\n// Stat either frozen or normal module by a given path\n// (whatever is available, if at all).\nSTATIC mp_import_stat_t mp_import_stat_any(const char *path) {\n    #if MICROPY_MODULE_FROZEN\n    mp_import_stat_t st = mp_frozen_stat(path);\n    if (st != MP_IMPORT_STAT_NO_EXIST) {\n        return st;\n    }\n    #endif\n    return mp_import_stat(path);\n}\n\nSTATIC mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) {\n    mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path));\n    if (stat == MP_IMPORT_STAT_FILE) {\n        return stat;\n    }\n\n    #if MICROPY_PERSISTENT_CODE_LOAD\n    vstr_ins_byte(path, path->len - 2, 'm');\n    stat = mp_import_stat_any(vstr_null_terminated_str(path));\n    if (stat == MP_IMPORT_STAT_FILE) {\n        return stat;\n    }\n    #endif\n\n    return MP_IMPORT_STAT_NO_EXIST;\n}\n\nSTATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {\n    mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path));\n    DEBUG_printf(\"stat %s: %d\\n\", vstr_str(path), stat);\n    if (stat == MP_IMPORT_STAT_DIR) {\n        return stat;\n    }\n\n    // not a directory, add .py and try as a file\n    vstr_add_str(path, \".py\");\n    return stat_file_py_or_mpy(path);\n}\n\nSTATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {\n    #if MICROPY_PY_SYS\n    // extract the list of paths\n    size_t path_num;\n    mp_obj_t *path_items;\n    mp_obj_list_get(mp_sys_path, &path_num, &path_items);\n\n    if (path_num != 0) {\n        // go through each path looking for a directory or file\n        for (size_t i = 0; i < path_num; i++) {\n            vstr_reset(dest);\n            size_t p_len;\n            const char *p = mp_obj_str_get_data(path_items[i], &p_len);\n            if (p_len > 0) {\n                vstr_add_strn(dest, p, p_len);\n                vstr_add_char(dest, PATH_SEP_CHAR);\n            }\n            vstr_add_strn(dest, file_str, file_len);\n            mp_import_stat_t stat = stat_dir_or_file(dest);\n            if (stat != MP_IMPORT_STAT_NO_EXIST) {\n                return stat;\n            }\n        }\n\n        // could not find a directory or file\n        return MP_IMPORT_STAT_NO_EXIST;\n    }\n    #endif\n\n    // mp_sys_path is empty, so just use the given file name\n    vstr_add_strn(dest, file_str, file_len);\n    return stat_dir_or_file(dest);\n}\n\n#if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER\nSTATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) {\n    #if MICROPY_PY___FILE__\n    qstr source_name = lex->source_name;\n    mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));\n    #endif\n\n    // parse, compile and execute the module in its context\n    mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj);\n    mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals);\n}\n#endif\n\n#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_MODULE_FROZEN_MPY\nSTATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, const char *source_name) {\n    (void)source_name;\n\n    #if MICROPY_PY___FILE__\n    mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(qstr_from_str(source_name)));\n    #endif\n\n    // execute the module in its context\n    mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj);\n\n    // save context\n    mp_obj_dict_t *volatile old_globals = mp_globals_get();\n    mp_obj_dict_t *volatile old_locals = mp_locals_get();\n\n    // set new context\n    mp_globals_set(mod_globals);\n    mp_locals_set(mod_globals);\n\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        mp_obj_t module_fun = mp_make_function_from_raw_code(raw_code, MP_OBJ_NULL, MP_OBJ_NULL);\n        mp_call_function_0(module_fun);\n\n        // finish nlr block, restore context\n        nlr_pop();\n        mp_globals_set(old_globals);\n        mp_locals_set(old_locals);\n    } else {\n        // exception; restore context and re-raise same exception\n        mp_globals_set(old_globals);\n        mp_locals_set(old_locals);\n        nlr_jump(nlr.ret_val);\n    }\n}\n#endif\n\nSTATIC void do_load(mp_obj_t module_obj, vstr_t *file) {\n    #if MICROPY_MODULE_FROZEN || MICROPY_ENABLE_COMPILER || (MICROPY_PERSISTENT_CODE_LOAD && MICROPY_HAS_FILE_READER)\n    char *file_str = vstr_null_terminated_str(file);\n    #endif\n\n    // If we support frozen modules (either as str or mpy) then try to find the\n    // requested filename in the list of frozen module filenames.\n    #if MICROPY_MODULE_FROZEN\n    void *modref;\n    int frozen_type = mp_find_frozen_module(file_str, file->len, &modref);\n    #endif\n\n    // If we support frozen str modules and the compiler is enabled, and we\n    // found the filename in the list of frozen files, then load and execute it.\n    #if MICROPY_MODULE_FROZEN_STR\n    if (frozen_type == MP_FROZEN_STR) {\n        do_load_from_lexer(module_obj, modref);\n        return;\n    }\n    #endif\n\n    // If we support frozen mpy modules and we found a corresponding file (and\n    // its data) in the list of frozen files, execute it.\n    #if MICROPY_MODULE_FROZEN_MPY\n    if (frozen_type == MP_FROZEN_MPY) {\n        do_execute_raw_code(module_obj, modref, file_str);\n        return;\n    }\n    #endif\n\n    // If we support loading .mpy files then check if the file extension is of\n    // the correct format and, if so, load and execute the file.\n    #if MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD\n    if (file_str[file->len - 3] == 'm') {\n        mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str);\n        do_execute_raw_code(module_obj, raw_code, file_str);\n        return;\n    }\n    #endif\n\n    // If we can compile scripts then load the file and compile and execute it.\n    #if MICROPY_ENABLE_COMPILER\n    {\n        mp_lexer_t *lex = mp_lexer_new_from_file(file_str);\n        do_load_from_lexer(module_obj, lex);\n        return;\n    }\n    #else\n    // If we get here then the file was not frozen and we can't compile scripts.\n    mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT(\"script compilation not supported\"));\n    #endif\n}\n\nSTATIC void chop_component(const char *start, const char **end) {\n    const char *p = *end;\n    while (p > start) {\n        if (*--p == '.') {\n            *end = p;\n            return;\n        }\n    }\n    *end = p;\n}\n\nmp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {\n    #if DEBUG_PRINT\n    DEBUG_printf(\"__import__:\\n\");\n    for (size_t i = 0; i < n_args; i++) {\n        DEBUG_printf(\"  \");\n        mp_obj_print(args[i], PRINT_REPR);\n        DEBUG_printf(\"\\n\");\n    }\n    #endif\n\n    mp_obj_t module_name = args[0];\n    mp_obj_t fromtuple = mp_const_none;\n    mp_int_t level = 0;\n    if (n_args >= 4) {\n        fromtuple = args[3];\n        if (n_args >= 5) {\n            level = MP_OBJ_SMALL_INT_VALUE(args[4]);\n            if (level < 0) {\n                mp_raise_ValueError(NULL);\n            }\n        }\n    }\n\n    size_t mod_len;\n    const char *mod_str = mp_obj_str_get_data(module_name, &mod_len);\n\n    if (level != 0) {\n        // What we want to do here is to take name of current module,\n        // chop <level> trailing components, and concatenate with passed-in\n        // module name, thus resolving relative import name into absolute.\n        // This even appears to be correct per\n        // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name\n        // \"Relative imports use a module's __name__ attribute to determine that\n        // module's position in the package hierarchy.\"\n        level--;\n        mp_obj_t this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__));\n        assert(this_name_q != MP_OBJ_NULL);\n        #if MICROPY_CPYTHON_COMPAT\n        if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) {\n            // This is a module run by -m command-line switch, get its real name from backup attribute\n            this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__));\n        }\n        #endif\n        mp_map_t *globals_map = &mp_globals_get()->map;\n        mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP);\n        bool is_pkg = (elem != NULL);\n\n        #if DEBUG_PRINT\n        DEBUG_printf(\"Current module/package: \");\n        mp_obj_print(this_name_q, PRINT_REPR);\n        DEBUG_printf(\", is_package: %d\", is_pkg);\n        DEBUG_printf(\"\\n\");\n        #endif\n\n        size_t this_name_l;\n        const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l);\n\n        const char *p = this_name + this_name_l;\n        if (!is_pkg) {\n            // We have module, but relative imports are anchored at package, so\n            // go there.\n            chop_component(this_name, &p);\n        }\n\n        while (level--) {\n            chop_component(this_name, &p);\n        }\n\n        // We must have some component left over to import from\n        if (p == this_name) {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"can't perform relative import\"));\n        }\n\n        uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);\n        char *new_mod = mp_local_alloc(new_mod_l);\n        memcpy(new_mod, this_name, p - this_name);\n        if (mod_len != 0) {\n            new_mod[p - this_name] = '.';\n            memcpy(new_mod + (p - this_name) + 1, mod_str, mod_len);\n        }\n\n        qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l);\n        mp_local_free(new_mod);\n        DEBUG_printf(\"Resolved base name for relative import: '%s'\\n\", qstr_str(new_mod_q));\n        module_name = MP_OBJ_NEW_QSTR(new_mod_q);\n        mod_str = qstr_str(new_mod_q);\n        mod_len = new_mod_l;\n    }\n\n    if (mod_len == 0) {\n        mp_raise_ValueError(NULL);\n    }\n\n    // check if module already exists\n    qstr module_name_qstr = mp_obj_str_get_qstr(module_name);\n    mp_obj_t module_obj = mp_module_get(module_name_qstr);\n    if (module_obj != MP_OBJ_NULL) {\n        DEBUG_printf(\"Module already loaded\\n\");\n        // If it's not a package, return module right away\n        char *p = strchr(mod_str, '.');\n        if (p == NULL) {\n            return module_obj;\n        }\n        // If fromlist is not empty, return leaf module\n        if (fromtuple != mp_const_none) {\n            return module_obj;\n        }\n        // Otherwise, we need to return top-level package\n        qstr pkg_name = qstr_from_strn(mod_str, p - mod_str);\n        return mp_module_get(pkg_name);\n    }\n    DEBUG_printf(\"Module not yet loaded\\n\");\n\n    uint last = 0;\n    VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)\n    module_obj = MP_OBJ_NULL;\n    mp_obj_t top_module_obj = MP_OBJ_NULL;\n    mp_obj_t outer_module_obj = MP_OBJ_NULL;\n    uint i;\n    for (i = 1; i <= mod_len; i++) {\n        if (i == mod_len || mod_str[i] == '.') {\n            // create a qstr for the module name up to this depth\n            qstr mod_name = qstr_from_strn(mod_str, i);\n            DEBUG_printf(\"Processing module: %s\\n\", qstr_str(mod_name));\n            DEBUG_printf(\"Previous path: =%.*s=\\n\", vstr_len(&path), vstr_str(&path));\n\n            // find the file corresponding to the module name\n            mp_import_stat_t stat;\n            if (vstr_len(&path) == 0) {\n                // first module in the dotted-name; search for a directory or file\n                stat = find_file(mod_str, i, &path);\n            } else {\n                // latter module in the dotted-name; append to path\n                vstr_add_char(&path, PATH_SEP_CHAR);\n                vstr_add_strn(&path, mod_str + last, i - last);\n                stat = stat_dir_or_file(&path);\n            }\n            DEBUG_printf(\"Current path: %.*s\\n\", vstr_len(&path), vstr_str(&path));\n\n            if (stat == MP_IMPORT_STAT_NO_EXIST) {\n                module_obj = MP_OBJ_NULL;\n                #if MICROPY_MODULE_WEAK_LINKS\n                // check if there is a weak link to this module\n                if (i == mod_len) {\n                    module_obj = mp_module_search_umodule(mod_str);\n                    if (module_obj != MP_OBJ_NULL) {\n                        // found weak linked module\n                        mp_module_call_init(mod_name, module_obj);\n                    }\n                }\n                #endif\n                if (module_obj == MP_OBJ_NULL) {\n                    // couldn't find the file, so fail\n                    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                    mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT(\"module not found\"));\n                    #else\n                    mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT(\"no module named '%q'\"), mod_name);\n                    #endif\n                }\n            } else {\n                // found the file, so get the module\n                module_obj = mp_module_get(mod_name);\n            }\n\n            if (module_obj == MP_OBJ_NULL) {\n                // module not already loaded, so load it!\n\n                module_obj = mp_obj_new_module(mod_name);\n\n                // if args[3] (fromtuple) has magic value False, set up\n                // this module for command-line \"-m\" option (set module's\n                // name to __main__ instead of real name). Do this only\n                // for *modules* however - packages never have their names\n                // replaced, instead they're -m'ed using a special __main__\n                // submodule in them. (This all apparently is done to not\n                // touch package name itself, which is important for future\n                // imports).\n                if (i == mod_len && fromtuple == mp_const_false && stat != MP_IMPORT_STAT_DIR) {\n                    mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj);\n                    mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));\n                    #if MICROPY_CPYTHON_COMPAT\n                    // Store module as \"__main__\" in the dictionary of loaded modules (returned by sys.modules).\n                    mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj);\n                    // Store real name in \"__main__\" attribute. Chosen semi-randonly, to reuse existing qstr's.\n                    mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(mod_name));\n                    #endif\n                }\n\n                if (stat == MP_IMPORT_STAT_DIR) {\n                    DEBUG_printf(\"%.*s is dir\\n\", vstr_len(&path), vstr_str(&path));\n                    // https://docs.python.org/3/reference/import.html\n                    // \"Specifically, any module that contains a __path__ attribute is considered a package.\"\n                    mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path)));\n                    size_t orig_path_len = path.len;\n                    vstr_add_char(&path, PATH_SEP_CHAR);\n                    vstr_add_str(&path, \"__init__.py\");\n                    if (stat_file_py_or_mpy(&path) != MP_IMPORT_STAT_FILE) {\n                        // mp_warning(\"%s is imported as namespace package\", vstr_str(&path));\n                    } else {\n                        do_load(module_obj, &path);\n                    }\n                    path.len = orig_path_len;\n                } else { // MP_IMPORT_STAT_FILE\n                    do_load(module_obj, &path);\n                    // This should be the last component in the import path.  If there are\n                    // remaining components then it's an ImportError because the current path\n                    // (the module that was just loaded) is not a package.  This will be caught\n                    // on the next iteration because the file will not exist.\n                }\n            }\n            if (outer_module_obj != MP_OBJ_NULL) {\n                qstr s = qstr_from_strn(mod_str + last, i - last);\n                mp_store_attr(outer_module_obj, s, module_obj);\n            }\n            outer_module_obj = module_obj;\n            if (top_module_obj == MP_OBJ_NULL) {\n                top_module_obj = module_obj;\n            }\n            last = i + 1;\n        }\n    }\n\n    // If fromlist is not empty, return leaf module\n    if (fromtuple != mp_const_none) {\n        return module_obj;\n    }\n    // Otherwise, we need to return top-level package\n    return top_module_obj;\n}\n\n#else // MICROPY_ENABLE_EXTERNAL_IMPORT\n\nmp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {\n    // Check that it's not a relative import\n    if (n_args >= 5 && MP_OBJ_SMALL_INT_VALUE(args[4]) != 0) {\n        mp_raise_NotImplementedError(MP_ERROR_TEXT(\"relative import\"));\n    }\n\n    // Check if module already exists, and return it if it does\n    qstr module_name_qstr = mp_obj_str_get_qstr(args[0]);\n    mp_obj_t module_obj = mp_module_get(module_name_qstr);\n    if (module_obj != MP_OBJ_NULL) {\n        return module_obj;\n    }\n\n    #if MICROPY_MODULE_WEAK_LINKS\n    // Check if there is a weak link to this module\n    module_obj = mp_module_search_umodule(qstr_str(module_name_qstr));\n    if (module_obj != MP_OBJ_NULL) {\n        // Found weak-linked module\n        mp_module_call_init(module_name_qstr, module_obj);\n        return module_obj;\n    }\n    #endif\n\n    // Couldn't find the module, so fail\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT(\"module not found\"));\n    #else\n    mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT(\"no module named '%q'\"), module_name_qstr);\n    #endif\n}\n\n#endif // MICROPY_ENABLE_EXTERNAL_IMPORT\n\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj, 1, 5, mp_builtin___import__);\n"
  },
  {
    "path": "py/compile.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2020 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/scope.h\"\n#include \"py/emit.h\"\n#include \"py/compile.h\"\n#include \"py/runtime.h\"\n#include \"py/asmbase.h\"\n#include \"py/persistentcode.h\"\n\n#if MICROPY_ENABLE_COMPILER\n\n// TODO need to mangle __attr names\n\n#define INVALID_LABEL (0xffff)\n\ntypedef enum {\n// define rules with a compile function\n#define DEF_RULE(rule, comp, kind, ...) PN_##rule,\n#define DEF_RULE_NC(rule, kind, ...)\n    #include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n    PN_const_object, // special node for a constant, generic Python object\n// define rules without a compile function\n#define DEF_RULE(rule, comp, kind, ...)\n#define DEF_RULE_NC(rule, kind, ...) PN_##rule,\n    #include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n} pn_kind_t;\n\n#define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE\n\n#if NEED_METHOD_TABLE\n\n// we need a method table to do the lookup for the emitter functions\n#define EMIT(fun) (comp->emit_method_table->fun(comp->emit))\n#define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__))\n#define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST))\n#define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL))\n\n#else\n\n// if we only have the bytecode emitter enabled then we can do a direct call to the functions\n#define EMIT(fun) (mp_emit_bc_##fun(comp->emit))\n#define EMIT_ARG(fun, ...) (mp_emit_bc_##fun(comp->emit, __VA_ARGS__))\n#define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST))\n#define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL))\n\n#endif\n\n#if MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER\n\n#define NATIVE_EMITTER(f) emit_native_table[mp_dynamic_compiler.native_arch]->emit_##f\n#define NATIVE_EMITTER_TABLE emit_native_table[mp_dynamic_compiler.native_arch]\n\nSTATIC const emit_method_table_t *emit_native_table[] = {\n    NULL,\n    &emit_native_x86_method_table,\n    &emit_native_x64_method_table,\n    &emit_native_arm_method_table,\n    &emit_native_thumb_method_table,\n    &emit_native_thumb_method_table,\n    &emit_native_thumb_method_table,\n    &emit_native_thumb_method_table,\n    &emit_native_thumb_method_table,\n    &emit_native_xtensa_method_table,\n    &emit_native_xtensawin_method_table,\n};\n\n#elif MICROPY_EMIT_NATIVE\n// define a macro to access external native emitter\n#if MICROPY_EMIT_X64\n#define NATIVE_EMITTER(f) emit_native_x64_##f\n#elif MICROPY_EMIT_X86\n#define NATIVE_EMITTER(f) emit_native_x86_##f\n#elif MICROPY_EMIT_THUMB\n#define NATIVE_EMITTER(f) emit_native_thumb_##f\n#elif MICROPY_EMIT_ARM\n#define NATIVE_EMITTER(f) emit_native_arm_##f\n#elif MICROPY_EMIT_XTENSA\n#define NATIVE_EMITTER(f) emit_native_xtensa_##f\n#elif MICROPY_EMIT_XTENSAWIN\n#define NATIVE_EMITTER(f) emit_native_xtensawin_##f\n#else\n#error \"unknown native emitter\"\n#endif\n#define NATIVE_EMITTER_TABLE &NATIVE_EMITTER(method_table)\n#endif\n\n#if MICROPY_EMIT_INLINE_ASM && MICROPY_DYNAMIC_COMPILER\n\n#define ASM_EMITTER(f) emit_asm_table[mp_dynamic_compiler.native_arch]->asm_##f\n#define ASM_EMITTER_TABLE emit_asm_table[mp_dynamic_compiler.native_arch]\n\nSTATIC const emit_inline_asm_method_table_t *emit_asm_table[] = {\n    NULL,\n    NULL,\n    NULL,\n    &emit_inline_thumb_method_table,\n    &emit_inline_thumb_method_table,\n    &emit_inline_thumb_method_table,\n    &emit_inline_thumb_method_table,\n    &emit_inline_thumb_method_table,\n    &emit_inline_thumb_method_table,\n    &emit_inline_xtensa_method_table,\n    NULL,\n};\n\n#elif MICROPY_EMIT_INLINE_ASM\n// define macros for inline assembler\n#if MICROPY_EMIT_INLINE_THUMB\n#define ASM_DECORATOR_QSTR MP_QSTR_asm_thumb\n#define ASM_EMITTER(f) emit_inline_thumb_##f\n#elif MICROPY_EMIT_INLINE_XTENSA\n#define ASM_DECORATOR_QSTR MP_QSTR_asm_xtensa\n#define ASM_EMITTER(f) emit_inline_xtensa_##f\n#else\n#error \"unknown asm emitter\"\n#endif\n#define ASM_EMITTER_TABLE &ASM_EMITTER(method_table)\n#endif\n\n#define EMIT_INLINE_ASM(fun) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm))\n#define EMIT_INLINE_ASM_ARG(fun, ...) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm, __VA_ARGS__))\n\n// elements in this struct are ordered to make it compact\ntypedef struct _compiler_t {\n    qstr source_file;\n\n    uint8_t is_repl;\n    uint8_t pass; // holds enum type pass_kind_t\n    uint8_t have_star;\n\n    // try to keep compiler clean from nlr\n    mp_obj_t compile_error; // set to an exception object if there's an error\n    size_t compile_error_line; // set to best guess of line of error\n\n    uint next_label;\n\n    uint16_t num_dict_params;\n    uint16_t num_default_params;\n\n    uint16_t break_label; // highest bit set indicates we are breaking out of a for loop\n    uint16_t continue_label;\n    uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT\n    uint16_t break_continue_except_level;\n\n    scope_t *scope_head;\n    scope_t *scope_cur;\n\n    emit_t *emit;                                   // current emitter\n    #if NEED_METHOD_TABLE\n    const emit_method_table_t *emit_method_table;   // current emit method table\n    #endif\n\n    #if MICROPY_EMIT_INLINE_ASM\n    emit_inline_asm_t *emit_inline_asm;                                   // current emitter for inline asm\n    const emit_inline_asm_method_table_t *emit_inline_asm_method_table;   // current emit method table for inline asm\n    #endif\n} compiler_t;\n\nSTATIC void compile_error_set_line(compiler_t *comp, mp_parse_node_t pn) {\n    // if the line of the error is unknown then try to update it from the pn\n    if (comp->compile_error_line == 0 && MP_PARSE_NODE_IS_STRUCT(pn)) {\n        comp->compile_error_line = ((mp_parse_node_struct_t *)pn)->source_line;\n    }\n}\n\nSTATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, mp_rom_error_text_t msg) {\n    // only register the error if there has been no other error\n    if (comp->compile_error == MP_OBJ_NULL) {\n        comp->compile_error = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);\n        compile_error_set_line(comp, pn);\n    }\n}\n\nSTATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);\nSTATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);\nSTATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *pns, bool create_map);\nSTATIC void compile_node(compiler_t *comp, mp_parse_node_t pn);\n\nSTATIC uint comp_next_label(compiler_t *comp) {\n    return comp->next_label++;\n}\n\n#if MICROPY_EMIT_NATIVE\nSTATIC void reserve_labels_for_native(compiler_t *comp, int n) {\n    if (comp->scope_cur->emit_options != MP_EMIT_OPT_BYTECODE) {\n        comp->next_label += n;\n    }\n}\n#else\n#define reserve_labels_for_native(comp, n)\n#endif\n\nSTATIC void compile_increase_except_level(compiler_t *comp, uint label, int kind) {\n    EMIT_ARG(setup_block, label, kind);\n    comp->cur_except_level += 1;\n    if (comp->cur_except_level > comp->scope_cur->exc_stack_size) {\n        comp->scope_cur->exc_stack_size = comp->cur_except_level;\n    }\n}\n\nSTATIC void compile_decrease_except_level(compiler_t *comp) {\n    assert(comp->cur_except_level > 0);\n    comp->cur_except_level -= 1;\n    EMIT(end_finally);\n    reserve_labels_for_native(comp, 1);\n}\n\nSTATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) {\n    scope_t *scope = scope_new(kind, pn, comp->source_file, emit_options);\n    scope->parent = comp->scope_cur;\n    scope->next = NULL;\n    if (comp->scope_head == NULL) {\n        comp->scope_head = scope;\n    } else {\n        scope_t *s = comp->scope_head;\n        while (s->next != NULL) {\n            s = s->next;\n        }\n        s->next = scope;\n    }\n    return scope;\n}\n\ntypedef void (*apply_list_fun_t)(compiler_t *comp, mp_parse_node_t pn);\n\nSTATIC 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) {\n    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, pn_list_kind)) {\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n        int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n        for (int i = 0; i < num_nodes; i++) {\n            f(comp, pns->nodes[i]);\n        }\n    } else if (!MP_PARSE_NODE_IS_NULL(pn)) {\n        f(comp, pn);\n    }\n}\n\nSTATIC void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n    for (int i = 0; i < num_nodes; i++) {\n        compile_node(comp, pns->nodes[i]);\n        if (comp->compile_error != MP_OBJ_NULL) {\n            // add line info for the error in case it didn't have a line number\n            compile_error_set_line(comp, pns->nodes[i]);\n            return;\n        }\n    }\n}\n\nSTATIC void compile_load_id(compiler_t *comp, qstr qst) {\n    if (comp->pass == MP_PASS_SCOPE) {\n        mp_emit_common_get_id_for_load(comp->scope_cur, qst);\n    } else {\n        #if NEED_METHOD_TABLE\n        mp_emit_common_id_op(comp->emit, &comp->emit_method_table->load_id, comp->scope_cur, qst);\n        #else\n        mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_load_id_ops, comp->scope_cur, qst);\n        #endif\n    }\n}\n\nSTATIC void compile_store_id(compiler_t *comp, qstr qst) {\n    if (comp->pass == MP_PASS_SCOPE) {\n        mp_emit_common_get_id_for_modification(comp->scope_cur, qst);\n    } else {\n        #if NEED_METHOD_TABLE\n        mp_emit_common_id_op(comp->emit, &comp->emit_method_table->store_id, comp->scope_cur, qst);\n        #else\n        mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_store_id_ops, comp->scope_cur, qst);\n        #endif\n    }\n}\n\nSTATIC void compile_delete_id(compiler_t *comp, qstr qst) {\n    if (comp->pass == MP_PASS_SCOPE) {\n        mp_emit_common_get_id_for_modification(comp->scope_cur, qst);\n    } else {\n        #if NEED_METHOD_TABLE\n        mp_emit_common_id_op(comp->emit, &comp->emit_method_table->delete_id, comp->scope_cur, qst);\n        #else\n        mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_delete_id_ops, comp->scope_cur, qst);\n        #endif\n    }\n}\n\nSTATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {\n    int total = 0;\n    if (!MP_PARSE_NODE_IS_NULL(pn)) {\n        compile_node(comp, pn);\n        total += 1;\n    }\n    if (pns_list != NULL) {\n        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);\n        for (int i = 0; i < n; i++) {\n            compile_node(comp, pns_list->nodes[i]);\n        }\n        total += n;\n    }\n    EMIT_ARG(build, total, MP_EMIT_BUILD_TUPLE);\n}\n\nSTATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // a simple tuple expression\n    c_tuple(comp, MP_PARSE_NODE_NULL, pns);\n}\n\nSTATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {\n    if (mp_parse_node_is_const_false(pn)) {\n        if (jump_if == false) {\n            EMIT_ARG(jump, label);\n        }\n        return;\n    } else if (mp_parse_node_is_const_true(pn)) {\n        if (jump_if == true) {\n            EMIT_ARG(jump, label);\n        }\n        return;\n    } else if (MP_PARSE_NODE_IS_STRUCT(pn)) {\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n        if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test) {\n            if (jump_if == false) {\n            and_or_logic1:;\n                uint label2 = comp_next_label(comp);\n                for (int i = 0; i < n - 1; i++) {\n                    c_if_cond(comp, pns->nodes[i], !jump_if, label2);\n                }\n                c_if_cond(comp, pns->nodes[n - 1], jump_if, label);\n                EMIT_ARG(label_assign, label2);\n            } else {\n            and_or_logic2:\n                for (int i = 0; i < n; i++) {\n                    c_if_cond(comp, pns->nodes[i], jump_if, label);\n                }\n            }\n            return;\n        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {\n            if (jump_if == false) {\n                goto and_or_logic2;\n            } else {\n                goto and_or_logic1;\n            }\n        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {\n            c_if_cond(comp, pns->nodes[0], !jump_if, label);\n            return;\n        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_atom_paren) {\n            // cond is something in parenthesis\n            if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n                // empty tuple, acts as false for the condition\n                if (jump_if == false) {\n                    EMIT_ARG(jump, label);\n                }\n            } else {\n                assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));\n                // non-empty tuple, acts as true for the condition\n                if (jump_if == true) {\n                    EMIT_ARG(jump, label);\n                }\n            }\n            return;\n        }\n    }\n\n    // nothing special, fall back to default compiling for node and jump\n    compile_node(comp, pn);\n    EMIT_ARG(pop_jump_if, jump_if, label);\n}\n\ntypedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t;\nSTATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind);\n\nSTATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {\n    if (assign_kind != ASSIGN_AUG_STORE) {\n        compile_node(comp, pns->nodes[0]);\n    }\n\n    if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {\n        mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1];\n        if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) {\n            int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);\n            if (assign_kind != ASSIGN_AUG_STORE) {\n                for (int i = 0; i < n - 1; i++) {\n                    compile_node(comp, pns1->nodes[i]);\n                }\n            }\n            assert(MP_PARSE_NODE_IS_STRUCT(pns1->nodes[n - 1]));\n            pns1 = (mp_parse_node_struct_t *)pns1->nodes[n - 1];\n        }\n        if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {\n            if (assign_kind == ASSIGN_AUG_STORE) {\n                EMIT(rot_three);\n                EMIT_ARG(subscr, MP_EMIT_SUBSCR_STORE);\n            } else {\n                compile_node(comp, pns1->nodes[0]);\n                if (assign_kind == ASSIGN_AUG_LOAD) {\n                    EMIT(dup_top_two);\n                    EMIT_ARG(subscr, MP_EMIT_SUBSCR_LOAD);\n                } else {\n                    EMIT_ARG(subscr, MP_EMIT_SUBSCR_STORE);\n                }\n            }\n            return;\n        } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) {\n            assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));\n            if (assign_kind == ASSIGN_AUG_LOAD) {\n                EMIT(dup_top);\n                EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_LOAD);\n            } else {\n                if (assign_kind == ASSIGN_AUG_STORE) {\n                    EMIT(rot_two);\n                }\n                EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_STORE);\n            }\n            return;\n        }\n    }\n\n    compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"can't assign to expression\"));\n}\n\n// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail)\nSTATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {\n    uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;\n\n    // look for star expression\n    uint have_star_index = -1;\n    if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) {\n        EMIT_ARG(unpack_ex, 0, num_tail);\n        have_star_index = 0;\n    }\n    for (uint i = 0; i < num_tail; i++) {\n        if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) {\n            if (have_star_index == (uint)-1) {\n                EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1);\n                have_star_index = num_head + i;\n            } else {\n                compile_syntax_error(comp, nodes_tail[i], MP_ERROR_TEXT(\"multiple *x in assignment\"));\n                return;\n            }\n        }\n    }\n    if (have_star_index == (uint)-1) {\n        EMIT_ARG(unpack_sequence, num_head + num_tail);\n    }\n    if (num_head != 0) {\n        if (0 == have_star_index) {\n            c_assign(comp, ((mp_parse_node_struct_t *)node_head)->nodes[0], ASSIGN_STORE);\n        } else {\n            c_assign(comp, node_head, ASSIGN_STORE);\n        }\n    }\n    for (uint i = 0; i < num_tail; i++) {\n        if (num_head + i == have_star_index) {\n            c_assign(comp, ((mp_parse_node_struct_t *)nodes_tail[i])->nodes[0], ASSIGN_STORE);\n        } else {\n            c_assign(comp, nodes_tail[i], ASSIGN_STORE);\n        }\n    }\n}\n\n// assigns top of stack to pn\nSTATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {\n    assert(!MP_PARSE_NODE_IS_NULL(pn));\n    if (MP_PARSE_NODE_IS_LEAF(pn)) {\n        if (MP_PARSE_NODE_IS_ID(pn)) {\n            qstr arg = MP_PARSE_NODE_LEAF_ARG(pn);\n            switch (assign_kind) {\n                case ASSIGN_STORE:\n                case ASSIGN_AUG_STORE:\n                    compile_store_id(comp, arg);\n                    break;\n                case ASSIGN_AUG_LOAD:\n                default:\n                    compile_load_id(comp, arg);\n                    break;\n            }\n        } else {\n            goto cannot_assign;\n        }\n    } else {\n        // pn must be a struct\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {\n            case PN_atom_expr_normal:\n                // lhs is an index or attribute\n                c_assign_atom_expr(comp, pns, assign_kind);\n                break;\n\n            case PN_testlist_star_expr:\n            case PN_exprlist:\n                // lhs is a tuple\n                if (assign_kind != ASSIGN_STORE) {\n                    goto cannot_assign;\n                }\n                c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);\n                break;\n\n            case PN_atom_paren:\n                // lhs is something in parenthesis\n                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n                    // empty tuple\n                    goto cannot_assign;\n                } else {\n                    assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));\n                    if (assign_kind != ASSIGN_STORE) {\n                        goto cannot_assign;\n                    }\n                    pns = (mp_parse_node_struct_t *)pns->nodes[0];\n                    goto testlist_comp;\n                }\n                break;\n\n            case PN_atom_bracket:\n                // lhs is something in brackets\n                if (assign_kind != ASSIGN_STORE) {\n                    goto cannot_assign;\n                }\n                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n                    // empty list, assignment allowed\n                    c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL);\n                } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {\n                    pns = (mp_parse_node_struct_t *)pns->nodes[0];\n                    goto testlist_comp;\n                } else {\n                    // brackets around 1 item\n                    c_assign_tuple(comp, pns->nodes[0], 0, NULL);\n                }\n                break;\n\n            default:\n                goto cannot_assign;\n        }\n        return;\n\n    testlist_comp:\n        // lhs is a sequence\n        if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {\n            mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1];\n            if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) {\n                // sequence of one item, with trailing comma\n                assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));\n                c_assign_tuple(comp, pns->nodes[0], 0, NULL);\n            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {\n                // sequence of many items\n                uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);\n                c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes);\n            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) {\n                goto cannot_assign;\n            } else {\n                // sequence with 2 items\n                goto sequence_with_2_items;\n            }\n        } else {\n            // sequence with 2 items\n        sequence_with_2_items:\n            c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes);\n        }\n        return;\n    }\n    return;\n\ncannot_assign:\n    compile_syntax_error(comp, pn, MP_ERROR_TEXT(\"can't assign to expression\"));\n}\n\n// stuff for lambda and comprehensions and generators:\n//  if n_pos_defaults > 0 then there is a tuple on the stack with the positional defaults\n//  if n_kw_defaults > 0 then there is a dictionary on the stack with the keyword defaults\n//  if both exist, the tuple is above the dictionary (ie the first pop gets the tuple)\nSTATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) {\n    assert(n_pos_defaults >= 0);\n    assert(n_kw_defaults >= 0);\n\n    // set flags\n    if (n_kw_defaults > 0) {\n        this_scope->scope_flags |= MP_SCOPE_FLAG_DEFKWARGS;\n    }\n    this_scope->num_def_pos_args = n_pos_defaults;\n\n    #if MICROPY_EMIT_NATIVE\n    // When creating a function/closure it will take a reference to the current globals\n    comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_REFGLOBALS | MP_SCOPE_FLAG_HASCONSTS;\n    #endif\n\n    // make closed over variables, if any\n    // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython)\n    int nfree = 0;\n    if (comp->scope_cur->kind != SCOPE_MODULE) {\n        for (int i = 0; i < comp->scope_cur->id_info_len; i++) {\n            id_info_t *id = &comp->scope_cur->id_info[i];\n            if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {\n                for (int j = 0; j < this_scope->id_info_len; j++) {\n                    id_info_t *id2 = &this_scope->id_info[j];\n                    if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) {\n                        // in MicroPython we load closures using LOAD_FAST\n                        EMIT_LOAD_FAST(id->qst, id->local_num);\n                        nfree += 1;\n                    }\n                }\n            }\n        }\n    }\n\n    // make the function/closure\n    if (nfree == 0) {\n        EMIT_ARG(make_function, this_scope, n_pos_defaults, n_kw_defaults);\n    } else {\n        EMIT_ARG(make_closure, this_scope, nfree, n_pos_defaults, n_kw_defaults);\n    }\n}\n\nSTATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn) {\n    // For efficiency of the code below we extract the parse-node kind here\n    int pn_kind;\n    if (MP_PARSE_NODE_IS_ID(pn)) {\n        pn_kind = -1;\n    } else {\n        assert(MP_PARSE_NODE_IS_STRUCT(pn));\n        pn_kind = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t *)pn);\n    }\n\n    if (pn_kind == PN_typedargslist_star || pn_kind == PN_varargslist_star) {\n        comp->have_star = true;\n        /* don't need to distinguish bare from named star\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;\n        if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n            // bare star\n        } else {\n            // named star\n        }\n        */\n\n    } else if (pn_kind == PN_typedargslist_dbl_star || pn_kind == PN_varargslist_dbl_star) {\n        // named double star\n        // TODO do we need to do anything with this?\n\n    } else {\n        mp_parse_node_t pn_id;\n        mp_parse_node_t pn_equal;\n        if (pn_kind == -1) {\n            // this parameter is just an id\n\n            pn_id = pn;\n            pn_equal = MP_PARSE_NODE_NULL;\n\n        } else if (pn_kind == PN_typedargslist_name) {\n            // this parameter has a colon and/or equal specifier\n\n            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n            pn_id = pns->nodes[0];\n            // pn_colon = pns->nodes[1]; // unused\n            pn_equal = pns->nodes[2];\n\n        } else {\n            assert(pn_kind == PN_varargslist_name); // should be\n            // this parameter has an equal specifier\n\n            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n            pn_id = pns->nodes[0];\n            pn_equal = pns->nodes[1];\n        }\n\n        if (MP_PARSE_NODE_IS_NULL(pn_equal)) {\n            // this parameter does not have a default value\n\n            // check for non-default parameters given after default parameters (allowed by parser, but not syntactically valid)\n            if (!comp->have_star && comp->num_default_params != 0) {\n                compile_syntax_error(comp, pn, MP_ERROR_TEXT(\"non-default argument follows default argument\"));\n                return;\n            }\n\n        } else {\n            // this parameter has a default value\n            // in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why\n\n            if (comp->have_star) {\n                comp->num_dict_params += 1;\n                // in MicroPython we put the default dict parameters into a dictionary using the bytecode\n                if (comp->num_dict_params == 1) {\n                    // in MicroPython we put the default positional parameters into a tuple using the bytecode\n                    // we need to do this here before we start building the map for the default keywords\n                    if (comp->num_default_params > 0) {\n                        EMIT_ARG(build, comp->num_default_params, MP_EMIT_BUILD_TUPLE);\n                    } else {\n                        EMIT(load_null); // sentinel indicating empty default positional args\n                    }\n                    // first default dict param, so make the map\n                    EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP);\n                }\n\n                // compile value then key, then store it to the dict\n                compile_node(comp, pn_equal);\n                EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id));\n                EMIT(store_map);\n            } else {\n                comp->num_default_params += 1;\n                compile_node(comp, pn_equal);\n            }\n        }\n    }\n}\n\nSTATIC void compile_funcdef_lambdef(compiler_t *comp, scope_t *scope, mp_parse_node_t pn_params, pn_kind_t pn_list_kind) {\n    // When we call compile_funcdef_lambdef_param below it can compile an arbitrary\n    // expression for default arguments, which may contain a lambda.  The lambda will\n    // call here in a nested way, so we must save and restore the relevant state.\n    bool orig_have_star = comp->have_star;\n    uint16_t orig_num_dict_params = comp->num_dict_params;\n    uint16_t orig_num_default_params = comp->num_default_params;\n\n    // compile default parameters\n    comp->have_star = false;\n    comp->num_dict_params = 0;\n    comp->num_default_params = 0;\n    apply_to_single_or_list(comp, pn_params, pn_list_kind, compile_funcdef_lambdef_param);\n\n    if (comp->compile_error != MP_OBJ_NULL) {\n        return;\n    }\n\n    // in MicroPython we put the default positional parameters into a tuple using the bytecode\n    // the default keywords args may have already made the tuple; if not, do it now\n    if (comp->num_default_params > 0 && comp->num_dict_params == 0) {\n        EMIT_ARG(build, comp->num_default_params, MP_EMIT_BUILD_TUPLE);\n        EMIT(load_null); // sentinel indicating empty default keyword args\n    }\n\n    // make the function\n    close_over_variables_etc(comp, scope, comp->num_default_params, comp->num_dict_params);\n\n    // restore state\n    comp->have_star = orig_have_star;\n    comp->num_dict_params = orig_num_dict_params;\n    comp->num_default_params = orig_num_default_params;\n}\n\n// leaves function object on stack\n// returns function name\nSTATIC qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {\n    if (comp->pass == MP_PASS_SCOPE) {\n        // create a new scope for this function\n        scope_t *s = scope_new_and_link(comp, SCOPE_FUNCTION, (mp_parse_node_t)pns, emit_options);\n        // store the function scope so the compiling function can use it at each pass\n        pns->nodes[4] = (mp_parse_node_t)s;\n    }\n\n    // get the scope for this function\n    scope_t *fscope = (scope_t *)pns->nodes[4];\n\n    // compile the function definition\n    compile_funcdef_lambdef(comp, fscope, pns->nodes[1], PN_typedargslist);\n\n    // return its name (the 'f' in \"def f(...):\")\n    return fscope->simple_name;\n}\n\n// leaves class object on stack\n// returns class name\nSTATIC qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {\n    if (comp->pass == MP_PASS_SCOPE) {\n        // create a new scope for this class\n        scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (mp_parse_node_t)pns, emit_options);\n        // store the class scope so the compiling function can use it at each pass\n        pns->nodes[3] = (mp_parse_node_t)s;\n    }\n\n    EMIT(load_build_class);\n\n    // scope for this class\n    scope_t *cscope = (scope_t *)pns->nodes[3];\n\n    // compile the class\n    close_over_variables_etc(comp, cscope, 0, 0);\n\n    // get its name\n    EMIT_ARG(load_const_str, cscope->simple_name);\n\n    // nodes[1] has parent classes, if any\n    // empty parenthesis (eg class C():) gets here as an empty PN_classdef_2 and needs special handling\n    mp_parse_node_t parents = pns->nodes[1];\n    if (MP_PARSE_NODE_IS_STRUCT_KIND(parents, PN_classdef_2)) {\n        parents = MP_PARSE_NODE_NULL;\n    }\n    compile_trailer_paren_helper(comp, parents, false, 2);\n\n    // return its name (the 'C' in class C(...):\")\n    return cscope->simple_name;\n}\n\n// returns true if it was a built-in decorator (even if the built-in had an error)\nSTATIC bool compile_built_in_decorator(compiler_t *comp, size_t name_len, mp_parse_node_t *name_nodes, uint *emit_options) {\n    if (MP_PARSE_NODE_LEAF_ARG(name_nodes[0]) != MP_QSTR_micropython) {\n        return false;\n    }\n\n    if (name_len != 2) {\n        compile_syntax_error(comp, name_nodes[0], MP_ERROR_TEXT(\"invalid micropython decorator\"));\n        return true;\n    }\n\n    qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]);\n    if (attr == MP_QSTR_bytecode) {\n        *emit_options = MP_EMIT_OPT_BYTECODE;\n    #if MICROPY_EMIT_NATIVE\n    } else if (attr == MP_QSTR_native) {\n        *emit_options = MP_EMIT_OPT_NATIVE_PYTHON;\n    } else if (attr == MP_QSTR_viper) {\n        *emit_options = MP_EMIT_OPT_VIPER;\n    #endif\n        #if MICROPY_EMIT_INLINE_ASM\n    #if MICROPY_DYNAMIC_COMPILER\n    } else if (attr == MP_QSTR_asm_thumb) {\n        *emit_options = MP_EMIT_OPT_ASM;\n    } else if (attr == MP_QSTR_asm_xtensa) {\n        *emit_options = MP_EMIT_OPT_ASM;\n    #else\n    } else if (attr == ASM_DECORATOR_QSTR) {\n        *emit_options = MP_EMIT_OPT_ASM;\n    #endif\n        #endif\n    } else {\n        compile_syntax_error(comp, name_nodes[1], MP_ERROR_TEXT(\"invalid micropython decorator\"));\n    }\n\n    #if MICROPY_DYNAMIC_COMPILER\n    if (*emit_options == MP_EMIT_OPT_NATIVE_PYTHON || *emit_options == MP_EMIT_OPT_VIPER) {\n        if (emit_native_table[mp_dynamic_compiler.native_arch] == NULL) {\n            compile_syntax_error(comp, name_nodes[1], MP_ERROR_TEXT(\"invalid arch\"));\n        }\n    } else if (*emit_options == MP_EMIT_OPT_ASM) {\n        if (emit_asm_table[mp_dynamic_compiler.native_arch] == NULL) {\n            compile_syntax_error(comp, name_nodes[1], MP_ERROR_TEXT(\"invalid arch\"));\n        }\n    }\n    #endif\n\n    return true;\n}\n\nSTATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // get the list of decorators\n    mp_parse_node_t *nodes;\n    size_t n = mp_parse_node_extract_list(&pns->nodes[0], PN_decorators, &nodes);\n\n    // inherit emit options for this function/class definition\n    uint emit_options = comp->scope_cur->emit_options;\n\n    // compile each decorator\n    size_t num_built_in_decorators = 0;\n    for (size_t i = 0; i < n; i++) {\n        assert(MP_PARSE_NODE_IS_STRUCT_KIND(nodes[i], PN_decorator)); // should be\n        mp_parse_node_struct_t *pns_decorator = (mp_parse_node_struct_t *)nodes[i];\n\n        // nodes[0] contains the decorator function, which is a dotted name\n        mp_parse_node_t *name_nodes;\n        size_t name_len = mp_parse_node_extract_list(&pns_decorator->nodes[0], PN_dotted_name, &name_nodes);\n\n        // check for built-in decorators\n        if (compile_built_in_decorator(comp, name_len, name_nodes, &emit_options)) {\n            // this was a built-in\n            num_built_in_decorators += 1;\n\n        } else {\n            // not a built-in, compile normally\n\n            // compile the decorator function\n            compile_node(comp, name_nodes[0]);\n            for (size_t j = 1; j < name_len; j++) {\n                assert(MP_PARSE_NODE_IS_ID(name_nodes[j])); // should be\n                EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j]), MP_EMIT_ATTR_LOAD);\n            }\n\n            // nodes[1] contains arguments to the decorator function, if any\n            if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) {\n                // call the decorator function with the arguments in nodes[1]\n                compile_node(comp, pns_decorator->nodes[1]);\n            }\n        }\n    }\n\n    // compile the body (funcdef, async funcdef or classdef) and get its name\n    mp_parse_node_struct_t *pns_body = (mp_parse_node_struct_t *)pns->nodes[1];\n    qstr body_name = 0;\n    if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) {\n        body_name = compile_funcdef_helper(comp, pns_body, emit_options);\n    #if MICROPY_PY_ASYNC_AWAIT\n    } else if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_async_funcdef) {\n        assert(MP_PARSE_NODE_IS_STRUCT(pns_body->nodes[0]));\n        mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t *)pns_body->nodes[0];\n        body_name = compile_funcdef_helper(comp, pns0, emit_options);\n        scope_t *fscope = (scope_t *)pns0->nodes[4];\n        fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;\n    #endif\n    } else {\n        assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be\n        body_name = compile_classdef_helper(comp, pns_body, emit_options);\n    }\n\n    // call each decorator\n    for (size_t i = 0; i < n - num_built_in_decorators; i++) {\n        EMIT_ARG(call_function, 1, 0, 0);\n    }\n\n    // store func/class object into name\n    compile_store_id(comp, body_name);\n}\n\nSTATIC void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    qstr fname = compile_funcdef_helper(comp, pns, comp->scope_cur->emit_options);\n    // store function object into function name\n    compile_store_id(comp, fname);\n}\n\nSTATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {\n    if (MP_PARSE_NODE_IS_ID(pn)) {\n        compile_delete_id(comp, MP_PARSE_NODE_LEAF_ARG(pn));\n    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_expr_normal)) {\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n\n        compile_node(comp, pns->nodes[0]); // base of the atom_expr_normal node\n\n        if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {\n            mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1];\n            if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) {\n                int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);\n                for (int i = 0; i < n - 1; i++) {\n                    compile_node(comp, pns1->nodes[i]);\n                }\n                assert(MP_PARSE_NODE_IS_STRUCT(pns1->nodes[n - 1]));\n                pns1 = (mp_parse_node_struct_t *)pns1->nodes[n - 1];\n            }\n            if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {\n                compile_node(comp, pns1->nodes[0]);\n                EMIT_ARG(subscr, MP_EMIT_SUBSCR_DELETE);\n            } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) {\n                assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));\n                EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_DELETE);\n            } else {\n                goto cannot_delete;\n            }\n        } else {\n            goto cannot_delete;\n        }\n\n    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) {\n        pn = ((mp_parse_node_struct_t *)pn)->nodes[0];\n        if (MP_PARSE_NODE_IS_NULL(pn)) {\n            goto cannot_delete;\n        } else {\n            assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp));\n            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n            // TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp\n\n            if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {\n                mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1];\n                if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3b) {\n                    // sequence of one item, with trailing comma\n                    assert(MP_PARSE_NODE_IS_NULL(pns1->nodes[0]));\n                    c_del_stmt(comp, pns->nodes[0]);\n                } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3c) {\n                    // sequence of many items\n                    int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);\n                    c_del_stmt(comp, pns->nodes[0]);\n                    for (int i = 0; i < n; i++) {\n                        c_del_stmt(comp, pns1->nodes[i]);\n                    }\n                } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for) {\n                    goto cannot_delete;\n                } else {\n                    // sequence with 2 items\n                    goto sequence_with_2_items;\n                }\n            } else {\n                // sequence with 2 items\n            sequence_with_2_items:\n                c_del_stmt(comp, pns->nodes[0]);\n                c_del_stmt(comp, pns->nodes[1]);\n            }\n        }\n    } else {\n        // some arbitrary statement that we can't delete (eg del 1)\n        goto cannot_delete;\n    }\n\n    return;\n\ncannot_delete:\n    compile_syntax_error(comp, (mp_parse_node_t)pn, MP_ERROR_TEXT(\"can't delete expression\"));\n}\n\nSTATIC void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    apply_to_single_or_list(comp, pns->nodes[0], PN_exprlist, c_del_stmt);\n}\n\nSTATIC void compile_break_cont_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    uint16_t label;\n    if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_break_stmt) {\n        label = comp->break_label;\n    } else {\n        label = comp->continue_label;\n    }\n    if (label == INVALID_LABEL) {\n        compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"'break'/'continue' outside loop\"));\n    }\n    assert(comp->cur_except_level >= comp->break_continue_except_level);\n    EMIT_ARG(unwind_jump, label, comp->cur_except_level - comp->break_continue_except_level);\n}\n\nSTATIC void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    #if MICROPY_CPYTHON_COMPAT\n    if (comp->scope_cur->kind != SCOPE_FUNCTION) {\n        compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"'return' outside function\"));\n        return;\n    }\n    #endif\n    if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n        // no argument to 'return', so return None\n        EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n    } else if (MICROPY_COMP_RETURN_IF_EXPR\n               && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_test_if_expr)) {\n        // special case when returning an if-expression; to match CPython optimisation\n        mp_parse_node_struct_t *pns_test_if_expr = (mp_parse_node_struct_t *)pns->nodes[0];\n        mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t *)pns_test_if_expr->nodes[1];\n\n        uint l_fail = comp_next_label(comp);\n        c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition\n        compile_node(comp, pns_test_if_expr->nodes[0]); // success value\n        EMIT(return_value);\n        EMIT_ARG(label_assign, l_fail);\n        compile_node(comp, pns_test_if_else->nodes[1]); // failure value\n    } else {\n        compile_node(comp, pns->nodes[0]);\n    }\n    EMIT(return_value);\n}\n\nSTATIC void compile_yield_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    compile_node(comp, pns->nodes[0]);\n    EMIT(pop_top);\n}\n\nSTATIC void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n        // raise\n        EMIT_ARG(raise_varargs, 0);\n    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_raise_stmt_arg)) {\n        // raise x from y\n        pns = (mp_parse_node_struct_t *)pns->nodes[0];\n        compile_node(comp, pns->nodes[0]);\n        compile_node(comp, pns->nodes[1]);\n        EMIT_ARG(raise_varargs, 2);\n    } else {\n        // raise x\n        compile_node(comp, pns->nodes[0]);\n        EMIT_ARG(raise_varargs, 1);\n    }\n}\n\n// q_base holds the base of the name\n// eg   a -> q_base=a\n//      a.b.c -> q_base=a\nSTATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {\n    bool is_as = false;\n    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_as_name)) {\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n        // a name of the form x as y; unwrap it\n        *q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);\n        pn = pns->nodes[0];\n        is_as = true;\n    }\n    if (MP_PARSE_NODE_IS_NULL(pn)) {\n        // empty name (eg, from . import x)\n        *q_base = MP_QSTR_;\n        EMIT_ARG(import, MP_QSTR_, MP_EMIT_IMPORT_NAME); // import the empty string\n    } else if (MP_PARSE_NODE_IS_ID(pn)) {\n        // just a simple name\n        qstr q_full = MP_PARSE_NODE_LEAF_ARG(pn);\n        if (!is_as) {\n            *q_base = q_full;\n        }\n        EMIT_ARG(import, q_full, MP_EMIT_IMPORT_NAME);\n    } else {\n        assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_name)); // should be\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n        {\n            // a name of the form a.b.c\n            if (!is_as) {\n                *q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);\n            }\n            int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n            int len = n - 1;\n            for (int i = 0; i < n; i++) {\n                len += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));\n            }\n            char *q_ptr = mp_local_alloc(len);\n            char *str_dest = q_ptr;\n            for (int i = 0; i < n; i++) {\n                if (i > 0) {\n                    *str_dest++ = '.';\n                }\n                size_t str_src_len;\n                const byte *str_src = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &str_src_len);\n                memcpy(str_dest, str_src, str_src_len);\n                str_dest += str_src_len;\n            }\n            qstr q_full = qstr_from_strn(q_ptr, len);\n            mp_local_free(q_ptr);\n            EMIT_ARG(import, q_full, MP_EMIT_IMPORT_NAME);\n            if (is_as) {\n                for (int i = 1; i < n; i++) {\n                    EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), MP_EMIT_ATTR_LOAD);\n                }\n            }\n        }\n    }\n}\n\nSTATIC void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) {\n    EMIT_ARG(load_const_small_int, 0); // level 0 import\n    EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // not importing from anything\n    qstr q_base;\n    do_import_name(comp, pn, &q_base);\n    compile_store_id(comp, q_base);\n}\n\nSTATIC void compile_import_name(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    apply_to_single_or_list(comp, pns->nodes[0], PN_dotted_as_names, compile_dotted_as_name);\n}\n\nSTATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    mp_parse_node_t pn_import_source = pns->nodes[0];\n\n    // extract the preceding .'s (if any) for a relative import, to compute the import level\n    uint import_level = 0;\n    do {\n        mp_parse_node_t pn_rel;\n        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)) {\n            // This covers relative imports with dots only like \"from .. import\"\n            pn_rel = pn_import_source;\n            pn_import_source = MP_PARSE_NODE_NULL;\n        } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_import_from_2b)) {\n            // This covers relative imports starting with dot(s) like \"from .foo import\"\n            mp_parse_node_struct_t *pns_2b = (mp_parse_node_struct_t *)pn_import_source;\n            pn_rel = pns_2b->nodes[0];\n            pn_import_source = pns_2b->nodes[1];\n            assert(!MP_PARSE_NODE_IS_NULL(pn_import_source)); // should not be\n        } else {\n            // Not a relative import\n            break;\n        }\n\n        // get the list of . and/or ...'s\n        mp_parse_node_t *nodes;\n        size_t n = mp_parse_node_extract_list(&pn_rel, PN_one_or_more_period_or_ellipsis, &nodes);\n\n        // count the total number of .'s\n        for (size_t i = 0; i < n; i++) {\n            if (MP_PARSE_NODE_IS_TOKEN_KIND(nodes[i], MP_TOKEN_DEL_PERIOD)) {\n                import_level++;\n            } else {\n                // should be an MP_TOKEN_ELLIPSIS\n                import_level += 3;\n            }\n        }\n    } while (0);\n\n    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {\n        #if MICROPY_CPYTHON_COMPAT\n        if (comp->scope_cur->kind != SCOPE_MODULE) {\n            compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"import * not at module level\"));\n            return;\n        }\n        #endif\n\n        EMIT_ARG(load_const_small_int, import_level);\n\n        // build the \"fromlist\" tuple\n        EMIT_ARG(load_const_str, MP_QSTR__star_);\n        EMIT_ARG(build, 1, MP_EMIT_BUILD_TUPLE);\n\n        // do the import\n        qstr dummy_q;\n        do_import_name(comp, pn_import_source, &dummy_q);\n        EMIT_ARG(import, MP_QSTRnull, MP_EMIT_IMPORT_STAR);\n\n    } else {\n        EMIT_ARG(load_const_small_int, import_level);\n\n        // build the \"fromlist\" tuple\n        mp_parse_node_t *pn_nodes;\n        size_t n = mp_parse_node_extract_list(&pns->nodes[1], PN_import_as_names, &pn_nodes);\n        for (size_t i = 0; i < n; i++) {\n            assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name));\n            mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t *)pn_nodes[i];\n            qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id\n            EMIT_ARG(load_const_str, id2);\n        }\n        EMIT_ARG(build, n, MP_EMIT_BUILD_TUPLE);\n\n        // do the import\n        qstr dummy_q;\n        do_import_name(comp, pn_import_source, &dummy_q);\n        for (size_t i = 0; i < n; i++) {\n            assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name));\n            mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t *)pn_nodes[i];\n            qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id\n            EMIT_ARG(import, id2, MP_EMIT_IMPORT_FROM);\n            if (MP_PARSE_NODE_IS_NULL(pns3->nodes[1])) {\n                compile_store_id(comp, id2);\n            } else {\n                compile_store_id(comp, MP_PARSE_NODE_LEAF_ARG(pns3->nodes[1]));\n            }\n        }\n        EMIT(pop_top);\n    }\n}\n\nSTATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, id_info_t *id_info) {\n    if (id_info->kind != ID_INFO_KIND_UNDECIDED && id_info->kind != ID_INFO_KIND_GLOBAL_EXPLICIT) {\n        compile_syntax_error(comp, pn, MP_ERROR_TEXT(\"identifier redefined as global\"));\n        return;\n    }\n    id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;\n\n    // if the id exists in the global scope, set its kind to EXPLICIT_GLOBAL\n    id_info = scope_find_global(comp->scope_cur, id_info->qst);\n    if (id_info != NULL) {\n        id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;\n    }\n}\n\nSTATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, id_info_t *id_info) {\n    if (id_info->kind == ID_INFO_KIND_UNDECIDED) {\n        id_info->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;\n        scope_check_to_close_over(comp->scope_cur, id_info);\n        if (id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {\n            compile_syntax_error(comp, pn, MP_ERROR_TEXT(\"no binding for nonlocal found\"));\n        }\n    } else if (id_info->kind != ID_INFO_KIND_FREE) {\n        compile_syntax_error(comp, pn, MP_ERROR_TEXT(\"identifier redefined as nonlocal\"));\n    }\n}\n\nSTATIC void compile_global_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    if (comp->pass == MP_PASS_SCOPE) {\n        bool is_global = MP_PARSE_NODE_STRUCT_KIND(pns) == PN_global_stmt;\n\n        if (!is_global && comp->scope_cur->kind == SCOPE_MODULE) {\n            compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"can't declare nonlocal in outer code\"));\n            return;\n        }\n\n        mp_parse_node_t *nodes;\n        size_t n = mp_parse_node_extract_list(&pns->nodes[0], PN_name_list, &nodes);\n        for (size_t i = 0; i < n; i++) {\n            qstr qst = MP_PARSE_NODE_LEAF_ARG(nodes[i]);\n            id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, ID_INFO_KIND_UNDECIDED);\n            if (is_global) {\n                compile_declare_global(comp, (mp_parse_node_t)pns, id_info);\n            } else {\n                compile_declare_nonlocal(comp, (mp_parse_node_t)pns, id_info);\n            }\n        }\n    }\n}\n\nSTATIC void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // with optimisations enabled we don't compile assertions\n    if (MP_STATE_VM(mp_optimise_value) != 0) {\n        return;\n    }\n\n    uint l_end = comp_next_label(comp);\n    c_if_cond(comp, pns->nodes[0], true, l_end);\n    EMIT_LOAD_GLOBAL(MP_QSTR_AssertionError); // we load_global instead of load_id, to be consistent with CPython\n    if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {\n        // assertion message\n        compile_node(comp, pns->nodes[1]);\n        EMIT_ARG(call_function, 1, 0, 0);\n    }\n    EMIT_ARG(raise_varargs, 1);\n    EMIT_ARG(label_assign, l_end);\n}\n\nSTATIC void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    uint l_end = comp_next_label(comp);\n\n    // optimisation: don't emit anything when \"if False\"\n    if (!mp_parse_node_is_const_false(pns->nodes[0])) {\n        uint l_fail = comp_next_label(comp);\n        c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition\n\n        compile_node(comp, pns->nodes[1]); // if block\n\n        // optimisation: skip everything else when \"if True\"\n        if (mp_parse_node_is_const_true(pns->nodes[0])) {\n            goto done;\n        }\n\n        if (\n            // optimisation: don't jump over non-existent elif/else blocks\n            !(MP_PARSE_NODE_IS_NULL(pns->nodes[2]) && MP_PARSE_NODE_IS_NULL(pns->nodes[3]))\n            // optimisation: don't jump if last instruction was return\n            && !EMIT(last_emit_was_return_value)\n            ) {\n            // jump over elif/else blocks\n            EMIT_ARG(jump, l_end);\n        }\n\n        EMIT_ARG(label_assign, l_fail);\n    }\n\n    // compile elif blocks (if any)\n    mp_parse_node_t *pn_elif;\n    size_t n_elif = mp_parse_node_extract_list(&pns->nodes[2], PN_if_stmt_elif_list, &pn_elif);\n    for (size_t i = 0; i < n_elif; i++) {\n        assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_elif[i], PN_if_stmt_elif)); // should be\n        mp_parse_node_struct_t *pns_elif = (mp_parse_node_struct_t *)pn_elif[i];\n\n        // optimisation: don't emit anything when \"if False\"\n        if (!mp_parse_node_is_const_false(pns_elif->nodes[0])) {\n            uint l_fail = comp_next_label(comp);\n            c_if_cond(comp, pns_elif->nodes[0], false, l_fail); // elif condition\n\n            compile_node(comp, pns_elif->nodes[1]); // elif block\n\n            // optimisation: skip everything else when \"elif True\"\n            if (mp_parse_node_is_const_true(pns_elif->nodes[0])) {\n                goto done;\n            }\n\n            // optimisation: don't jump if last instruction was return\n            if (!EMIT(last_emit_was_return_value)) {\n                EMIT_ARG(jump, l_end);\n            }\n            EMIT_ARG(label_assign, l_fail);\n        }\n    }\n\n    // compile else block\n    compile_node(comp, pns->nodes[3]); // can be null\n\ndone:\n    EMIT_ARG(label_assign, l_end);\n}\n\n#define START_BREAK_CONTINUE_BLOCK \\\n    uint16_t old_break_label = comp->break_label; \\\n    uint16_t old_continue_label = comp->continue_label; \\\n    uint16_t old_break_continue_except_level = comp->break_continue_except_level; \\\n    uint break_label = comp_next_label(comp); \\\n    uint continue_label = comp_next_label(comp); \\\n    comp->break_label = break_label; \\\n    comp->continue_label = continue_label; \\\n    comp->break_continue_except_level = comp->cur_except_level;\n\n#define END_BREAK_CONTINUE_BLOCK \\\n    comp->break_label = old_break_label; \\\n    comp->continue_label = old_continue_label; \\\n    comp->break_continue_except_level = old_break_continue_except_level;\n\nSTATIC void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    START_BREAK_CONTINUE_BLOCK\n\n    if (!mp_parse_node_is_const_false(pns->nodes[0])) { // optimisation: don't emit anything for \"while False\"\n        uint top_label = comp_next_label(comp);\n        if (!mp_parse_node_is_const_true(pns->nodes[0])) { // optimisation: don't jump to cond for \"while True\"\n            EMIT_ARG(jump, continue_label);\n        }\n        EMIT_ARG(label_assign, top_label);\n        compile_node(comp, pns->nodes[1]); // body\n        EMIT_ARG(label_assign, continue_label);\n        c_if_cond(comp, pns->nodes[0], true, top_label); // condition\n    }\n\n    // break/continue apply to outer loop (if any) in the else block\n    END_BREAK_CONTINUE_BLOCK\n\n    compile_node(comp, pns->nodes[2]); // else\n\n    EMIT_ARG(label_assign, break_label);\n}\n\n// This function compiles an optimised for-loop of the form:\n//      for <var> in range(<start>, <end>, <step>):\n//          <body>\n//      else:\n//          <else>\n// <var> must be an identifier and <step> must be a small-int.\n//\n// Semantics of for-loop require:\n//  - final failing value should not be stored in the loop variable\n//  - if the loop never runs, the loop variable should never be assigned\n//  - assignments to <var>, <end> or <step> in the body do not alter the loop\n//    (<step> is a constant for us, so no need to worry about it changing)\n//\n// If <end> is a small-int, then the stack during the for-loop contains just\n// the current value of <var>.  Otherwise, the stack contains <end> then the\n// current value of <var>.\nSTATIC 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) {\n    START_BREAK_CONTINUE_BLOCK\n\n    uint top_label = comp_next_label(comp);\n    uint entry_label = comp_next_label(comp);\n\n    // put the end value on the stack if it's not a small-int constant\n    bool end_on_stack = !MP_PARSE_NODE_IS_SMALL_INT(pn_end);\n    if (end_on_stack) {\n        compile_node(comp, pn_end);\n    }\n\n    // compile: start\n    compile_node(comp, pn_start);\n\n    EMIT_ARG(jump, entry_label);\n    EMIT_ARG(label_assign, top_label);\n\n    // duplicate next value and store it to var\n    EMIT(dup_top);\n    c_assign(comp, pn_var, ASSIGN_STORE);\n\n    // compile body\n    compile_node(comp, pn_body);\n\n    EMIT_ARG(label_assign, continue_label);\n\n    // compile: var + step\n    compile_node(comp, pn_step);\n    EMIT_ARG(binary_op, MP_BINARY_OP_INPLACE_ADD);\n\n    EMIT_ARG(label_assign, entry_label);\n\n    // compile: if var <cond> end: goto top\n    if (end_on_stack) {\n        EMIT(dup_top_two);\n        EMIT(rot_two);\n    } else {\n        EMIT(dup_top);\n        compile_node(comp, pn_end);\n    }\n    assert(MP_PARSE_NODE_IS_SMALL_INT(pn_step));\n    if (MP_PARSE_NODE_LEAF_SMALL_INT(pn_step) >= 0) {\n        EMIT_ARG(binary_op, MP_BINARY_OP_LESS);\n    } else {\n        EMIT_ARG(binary_op, MP_BINARY_OP_MORE);\n    }\n    EMIT_ARG(pop_jump_if, true, top_label);\n\n    // break/continue apply to outer loop (if any) in the else block\n    END_BREAK_CONTINUE_BLOCK\n\n    // Compile the else block.  We must pop the iterator variables before\n    // executing the else code because it may contain break/continue statements.\n    uint end_label = 0;\n    if (!MP_PARSE_NODE_IS_NULL(pn_else)) {\n        // discard final value of \"var\", and possible \"end\" value\n        EMIT(pop_top);\n        if (end_on_stack) {\n            EMIT(pop_top);\n        }\n        compile_node(comp, pn_else);\n        end_label = comp_next_label(comp);\n        EMIT_ARG(jump, end_label);\n        EMIT_ARG(adjust_stack_size, 1 + end_on_stack);\n    }\n\n    EMIT_ARG(label_assign, break_label);\n\n    // discard final value of var that failed the loop condition\n    EMIT(pop_top);\n\n    // discard <end> value if it's on the stack\n    if (end_on_stack) {\n        EMIT(pop_top);\n    }\n\n    if (!MP_PARSE_NODE_IS_NULL(pn_else)) {\n        EMIT_ARG(label_assign, end_label);\n    }\n}\n\nSTATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // this bit optimises: for <x> in range(...), turning it into an explicitly incremented variable\n    // this is actually slower, but uses no heap memory\n    // for viper it will be much, much faster\n    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)) {\n        mp_parse_node_struct_t *pns_it = (mp_parse_node_struct_t *)pns->nodes[1];\n        if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0])\n            && MP_PARSE_NODE_LEAF_ARG(pns_it->nodes[0]) == MP_QSTR_range\n            && MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t *)pns_it->nodes[1]) == PN_trailer_paren) {\n            mp_parse_node_t pn_range_args = ((mp_parse_node_struct_t *)pns_it->nodes[1])->nodes[0];\n            mp_parse_node_t *args;\n            size_t n_args = mp_parse_node_extract_list(&pn_range_args, PN_arglist, &args);\n            mp_parse_node_t pn_range_start;\n            mp_parse_node_t pn_range_end;\n            mp_parse_node_t pn_range_step;\n            bool optimize = false;\n            if (1 <= n_args && n_args <= 3) {\n                optimize = true;\n                if (n_args == 1) {\n                    pn_range_start = mp_parse_node_new_small_int(0);\n                    pn_range_end = args[0];\n                    pn_range_step = mp_parse_node_new_small_int(1);\n                } else if (n_args == 2) {\n                    pn_range_start = args[0];\n                    pn_range_end = args[1];\n                    pn_range_step = mp_parse_node_new_small_int(1);\n                } else {\n                    pn_range_start = args[0];\n                    pn_range_end = args[1];\n                    pn_range_step = args[2];\n                    // the step must be a non-zero constant integer to do the optimisation\n                    if (!MP_PARSE_NODE_IS_SMALL_INT(pn_range_step)\n                        || MP_PARSE_NODE_LEAF_SMALL_INT(pn_range_step) == 0) {\n                        optimize = false;\n                    }\n                }\n                // arguments must be able to be compiled as standard expressions\n                if (optimize && MP_PARSE_NODE_IS_STRUCT(pn_range_start)) {\n                    int k = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t *)pn_range_start);\n                    if (k == PN_arglist_star || k == PN_arglist_dbl_star || k == PN_argument) {\n                        optimize = false;\n                    }\n                }\n                if (optimize && MP_PARSE_NODE_IS_STRUCT(pn_range_end)) {\n                    int k = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t *)pn_range_end);\n                    if (k == PN_arglist_star || k == PN_arglist_dbl_star || k == PN_argument) {\n                        optimize = false;\n                    }\n                }\n            }\n            if (optimize) {\n                compile_for_stmt_optimised_range(comp, pns->nodes[0], pn_range_start, pn_range_end, pn_range_step, pns->nodes[2], pns->nodes[3]);\n                return;\n            }\n        }\n    }\n\n    START_BREAK_CONTINUE_BLOCK\n    comp->break_label |= MP_EMIT_BREAK_FROM_FOR;\n\n    uint pop_label = comp_next_label(comp);\n\n    compile_node(comp, pns->nodes[1]); // iterator\n    EMIT_ARG(get_iter, true);\n    EMIT_ARG(label_assign, continue_label);\n    EMIT_ARG(for_iter, pop_label);\n    c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable\n    compile_node(comp, pns->nodes[2]); // body\n    if (!EMIT(last_emit_was_return_value)) {\n        EMIT_ARG(jump, continue_label);\n    }\n    EMIT_ARG(label_assign, pop_label);\n    EMIT(for_iter_end);\n\n    // break/continue apply to outer loop (if any) in the else block\n    END_BREAK_CONTINUE_BLOCK\n\n    compile_node(comp, pns->nodes[3]); // else (may be empty)\n\n    EMIT_ARG(label_assign, break_label);\n}\n\nSTATIC 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) {\n    // setup code\n    uint l1 = comp_next_label(comp);\n    uint success_label = comp_next_label(comp);\n\n    compile_increase_except_level(comp, l1, MP_EMIT_SETUP_BLOCK_EXCEPT);\n\n    compile_node(comp, pn_body); // body\n    EMIT_ARG(pop_except_jump, success_label, false); // jump over exception handler\n\n    EMIT_ARG(label_assign, l1); // start of exception handler\n    EMIT(start_except_handler);\n\n    // at this point the top of the stack contains the exception instance that was raised\n\n    uint l2 = comp_next_label(comp);\n\n    for (int i = 0; i < n_except; i++) {\n        assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_excepts[i], PN_try_stmt_except)); // should be\n        mp_parse_node_struct_t *pns_except = (mp_parse_node_struct_t *)pn_excepts[i];\n\n        qstr qstr_exception_local = 0;\n        uint end_finally_label = comp_next_label(comp);\n        #if MICROPY_PY_SYS_SETTRACE\n        EMIT_ARG(set_source_line, pns_except->source_line);\n        #endif\n\n        if (MP_PARSE_NODE_IS_NULL(pns_except->nodes[0])) {\n            // this is a catch all exception handler\n            if (i + 1 != n_except) {\n                compile_syntax_error(comp, pn_excepts[i], MP_ERROR_TEXT(\"default 'except' must be last\"));\n                compile_decrease_except_level(comp);\n                return;\n            }\n        } else {\n            // this exception handler requires a match to a certain type of exception\n            mp_parse_node_t pns_exception_expr = pns_except->nodes[0];\n            if (MP_PARSE_NODE_IS_STRUCT(pns_exception_expr)) {\n                mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t *)pns_exception_expr;\n                if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_try_stmt_as_name) {\n                    // handler binds the exception to a local\n                    pns_exception_expr = pns3->nodes[0];\n                    qstr_exception_local = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[1]);\n                }\n            }\n            EMIT(dup_top);\n            compile_node(comp, pns_exception_expr);\n            EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH);\n            EMIT_ARG(pop_jump_if, false, end_finally_label);\n        }\n\n        // either discard or store the exception instance\n        if (qstr_exception_local == 0) {\n            EMIT(pop_top);\n        } else {\n            compile_store_id(comp, qstr_exception_local);\n        }\n\n        // If the exception is bound to a variable <e> then the <body> of the\n        // exception handler is wrapped in a try-finally so that the name <e> can\n        // be deleted (per Python semantics) even if the <body> has an exception.\n        // In such a case the generated code for the exception handler is:\n        //      try:\n        //          <body>\n        //      finally:\n        //          <e> = None\n        //          del <e>\n        uint l3 = 0;\n        if (qstr_exception_local != 0) {\n            l3 = comp_next_label(comp);\n            compile_increase_except_level(comp, l3, MP_EMIT_SETUP_BLOCK_FINALLY);\n        }\n        compile_node(comp, pns_except->nodes[1]); // the <body>\n        if (qstr_exception_local != 0) {\n            EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n            EMIT_ARG(label_assign, l3);\n            EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n            compile_store_id(comp, qstr_exception_local);\n            compile_delete_id(comp, qstr_exception_local);\n            compile_decrease_except_level(comp);\n        }\n\n        EMIT_ARG(pop_except_jump, l2, true);\n        EMIT_ARG(label_assign, end_finally_label);\n        EMIT_ARG(adjust_stack_size, 1); // stack adjust for the exception instance\n    }\n\n    compile_decrease_except_level(comp);\n    EMIT(end_except_handler);\n\n    EMIT_ARG(label_assign, success_label);\n    compile_node(comp, pn_else); // else block, can be null\n    EMIT_ARG(label_assign, l2);\n}\n\nSTATIC 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) {\n    uint l_finally_block = comp_next_label(comp);\n\n    compile_increase_except_level(comp, l_finally_block, MP_EMIT_SETUP_BLOCK_FINALLY);\n\n    if (n_except == 0) {\n        assert(MP_PARSE_NODE_IS_NULL(pn_else));\n        EMIT_ARG(adjust_stack_size, 3); // stack adjust for possible UNWIND_JUMP state\n        compile_node(comp, pn_body);\n        EMIT_ARG(adjust_stack_size, -3);\n    } else {\n        compile_try_except(comp, pn_body, n_except, pn_except, pn_else);\n    }\n    EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n    EMIT_ARG(label_assign, l_finally_block);\n    compile_node(comp, pn_finally);\n\n    compile_decrease_except_level(comp);\n}\n\nSTATIC void compile_try_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should be\n    {\n        mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1];\n        if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_try_stmt_finally) {\n            // just try-finally\n            compile_try_finally(comp, pns->nodes[0], 0, NULL, MP_PARSE_NODE_NULL, pns2->nodes[0]);\n        } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_try_stmt_except_and_more) {\n            // try-except and possibly else and/or finally\n            mp_parse_node_t *pn_excepts;\n            size_t n_except = mp_parse_node_extract_list(&pns2->nodes[0], PN_try_stmt_except_list, &pn_excepts);\n            if (MP_PARSE_NODE_IS_NULL(pns2->nodes[2])) {\n                // no finally\n                compile_try_except(comp, pns->nodes[0], n_except, pn_excepts, pns2->nodes[1]);\n            } else {\n                // have finally\n                compile_try_finally(comp, pns->nodes[0], n_except, pn_excepts, pns2->nodes[1], ((mp_parse_node_struct_t *)pns2->nodes[2])->nodes[0]);\n            }\n        } else {\n            // just try-except\n            mp_parse_node_t *pn_excepts;\n            size_t n_except = mp_parse_node_extract_list(&pns->nodes[1], PN_try_stmt_except_list, &pn_excepts);\n            compile_try_except(comp, pns->nodes[0], n_except, pn_excepts, MP_PARSE_NODE_NULL);\n        }\n    }\n}\n\nSTATIC void compile_with_stmt_helper(compiler_t *comp, size_t n, mp_parse_node_t *nodes, mp_parse_node_t body) {\n    if (n == 0) {\n        // no more pre-bits, compile the body of the with\n        compile_node(comp, body);\n    } else {\n        uint l_end = comp_next_label(comp);\n        if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) {\n            // this pre-bit is of the form \"a as b\"\n            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)nodes[0];\n            compile_node(comp, pns->nodes[0]);\n            compile_increase_except_level(comp, l_end, MP_EMIT_SETUP_BLOCK_WITH);\n            c_assign(comp, pns->nodes[1], ASSIGN_STORE);\n        } else {\n            // this pre-bit is just an expression\n            compile_node(comp, nodes[0]);\n            compile_increase_except_level(comp, l_end, MP_EMIT_SETUP_BLOCK_WITH);\n            EMIT(pop_top);\n        }\n        // compile additional pre-bits and the body\n        compile_with_stmt_helper(comp, n - 1, nodes + 1, body);\n        // finish this with block\n        EMIT_ARG(with_cleanup, l_end);\n        reserve_labels_for_native(comp, 3); // used by native's with_cleanup\n        compile_decrease_except_level(comp);\n    }\n}\n\nSTATIC void compile_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // get the nodes for the pre-bit of the with (the a as b, c as d, ... bit)\n    mp_parse_node_t *nodes;\n    size_t n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes);\n    assert(n > 0);\n\n    // compile in a nested fashion\n    compile_with_stmt_helper(comp, n, nodes, pns->nodes[1]);\n}\n\nSTATIC void compile_yield_from(compiler_t *comp) {\n    EMIT_ARG(get_iter, false);\n    EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n    EMIT_ARG(yield, MP_EMIT_YIELD_FROM);\n    reserve_labels_for_native(comp, 3);\n}\n\n#if MICROPY_PY_ASYNC_AWAIT\nSTATIC void compile_await_object_method(compiler_t *comp, qstr method) {\n    EMIT_ARG(load_method, method, false);\n    EMIT_ARG(call_method, 0, 0, 0);\n    compile_yield_from(comp);\n}\n\nSTATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // comp->break_label |= MP_EMIT_BREAK_FROM_FOR;\n\n    qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);\n    uint while_else_label = comp_next_label(comp);\n    uint try_exception_label = comp_next_label(comp);\n    uint try_else_label = comp_next_label(comp);\n    uint try_finally_label = comp_next_label(comp);\n\n    compile_node(comp, pns->nodes[1]); // iterator\n    EMIT_ARG(load_method, MP_QSTR___aiter__, false);\n    EMIT_ARG(call_method, 0, 0, 0);\n    compile_store_id(comp, context);\n\n    START_BREAK_CONTINUE_BLOCK\n\n    EMIT_ARG(label_assign, continue_label);\n\n    compile_increase_except_level(comp, try_exception_label, MP_EMIT_SETUP_BLOCK_EXCEPT);\n\n    compile_load_id(comp, context);\n    compile_await_object_method(comp, MP_QSTR___anext__);\n    c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable\n    EMIT_ARG(pop_except_jump, try_else_label, false);\n\n    EMIT_ARG(label_assign, try_exception_label);\n    EMIT(start_except_handler);\n    EMIT(dup_top);\n    EMIT_LOAD_GLOBAL(MP_QSTR_StopAsyncIteration);\n    EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH);\n    EMIT_ARG(pop_jump_if, false, try_finally_label);\n    EMIT(pop_top); // pop exception instance\n    EMIT_ARG(pop_except_jump, while_else_label, true);\n\n    EMIT_ARG(label_assign, try_finally_label);\n    EMIT_ARG(adjust_stack_size, 1); // if we jump here, the exc is on the stack\n    compile_decrease_except_level(comp);\n    EMIT(end_except_handler);\n\n    EMIT_ARG(label_assign, try_else_label);\n    compile_node(comp, pns->nodes[2]); // body\n\n    EMIT_ARG(jump, continue_label);\n    // break/continue apply to outer loop (if any) in the else block\n    END_BREAK_CONTINUE_BLOCK\n\n    EMIT_ARG(label_assign, while_else_label);\n    compile_node(comp, pns->nodes[3]); // else\n\n    EMIT_ARG(label_assign, break_label);\n}\n\nSTATIC void compile_async_with_stmt_helper(compiler_t *comp, size_t n, mp_parse_node_t *nodes, mp_parse_node_t body) {\n    if (n == 0) {\n        // no more pre-bits, compile the body of the with\n        compile_node(comp, body);\n    } else {\n        uint l_finally_block = comp_next_label(comp);\n        uint l_aexit_no_exc = comp_next_label(comp);\n        uint l_ret_unwind_jump = comp_next_label(comp);\n        uint l_end = comp_next_label(comp);\n\n        if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) {\n            // this pre-bit is of the form \"a as b\"\n            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)nodes[0];\n            compile_node(comp, pns->nodes[0]);\n            EMIT(dup_top);\n            compile_await_object_method(comp, MP_QSTR___aenter__);\n            c_assign(comp, pns->nodes[1], ASSIGN_STORE);\n        } else {\n            // this pre-bit is just an expression\n            compile_node(comp, nodes[0]);\n            EMIT(dup_top);\n            compile_await_object_method(comp, MP_QSTR___aenter__);\n            EMIT(pop_top);\n        }\n\n        // To keep the Python stack size down, and because we can't access values on\n        // this stack further down than 3 elements (via rot_three), we don't preload\n        // __aexit__ (as per normal with) but rather wait until we need it below.\n\n        // Start the try-finally statement\n        compile_increase_except_level(comp, l_finally_block, MP_EMIT_SETUP_BLOCK_FINALLY);\n\n        // Compile any additional pre-bits of the \"async with\", and also the body\n        EMIT_ARG(adjust_stack_size, 3); // stack adjust for possible UNWIND_JUMP state\n        compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body);\n        EMIT_ARG(adjust_stack_size, -3);\n\n        // We have now finished the \"try\" block and fall through to the \"finally\"\n\n        // At this point, after the with body has executed, we have 3 cases:\n        // 1. no exception, we just fall through to this point; stack: (..., ctx_mgr)\n        // 2. exception propagating out, we get to the finally block; stack: (..., ctx_mgr, exc)\n        // 3. return or unwind jump, we get to the finally block; stack: (..., ctx_mgr, X, INT)\n\n        // Handle case 1: call __aexit__\n        // Stack: (..., ctx_mgr)\n        EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // to tell end_finally there's no exception\n        EMIT(rot_two);\n        EMIT_ARG(jump, l_aexit_no_exc); // jump to code below to call __aexit__\n\n        // Start of \"finally\" block\n        // At this point we have case 2 or 3, we detect which one by the TOS being an exception or not\n        EMIT_ARG(label_assign, l_finally_block);\n\n        // Detect if TOS an exception or not\n        EMIT(dup_top);\n        EMIT_LOAD_GLOBAL(MP_QSTR_BaseException);\n        EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH);\n        EMIT_ARG(pop_jump_if, false, l_ret_unwind_jump); // if not an exception then we have case 3\n\n        // Handle case 2: call __aexit__ and either swallow or re-raise the exception\n        // Stack: (..., ctx_mgr, exc)\n        EMIT(dup_top);\n        EMIT(rot_three);\n        EMIT(rot_two);\n        EMIT_ARG(load_method, MP_QSTR___aexit__, false);\n        EMIT(rot_three);\n        EMIT(rot_three);\n        EMIT(dup_top);\n        #if MICROPY_CPYTHON_COMPAT\n        EMIT_ARG(attr, MP_QSTR___class__, MP_EMIT_ATTR_LOAD); // get type(exc)\n        #else\n        compile_load_id(comp, MP_QSTR_type);\n        EMIT(rot_two);\n        EMIT_ARG(call_function, 1, 0, 0); // get type(exc)\n        #endif\n        EMIT(rot_two);\n        EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // dummy traceback value\n        // Stack: (..., exc, __aexit__, ctx_mgr, type(exc), exc, None)\n        EMIT_ARG(call_method, 3, 0, 0);\n        compile_yield_from(comp);\n        EMIT_ARG(pop_jump_if, false, l_end);\n        EMIT(pop_top); // pop exception\n        EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // replace with None to swallow exception\n        EMIT_ARG(jump, l_end);\n        EMIT_ARG(adjust_stack_size, 2);\n\n        // Handle case 3: call __aexit__\n        // Stack: (..., ctx_mgr, X, INT)\n        EMIT_ARG(label_assign, l_ret_unwind_jump);\n        EMIT(rot_three);\n        EMIT(rot_three);\n        EMIT_ARG(label_assign, l_aexit_no_exc);\n        EMIT_ARG(load_method, MP_QSTR___aexit__, false);\n        EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n        EMIT(dup_top);\n        EMIT(dup_top);\n        EMIT_ARG(call_method, 3, 0, 0);\n        compile_yield_from(comp);\n        EMIT(pop_top);\n        EMIT_ARG(adjust_stack_size, -1);\n\n        // End of \"finally\" block\n        // Stack can have one of three configurations:\n        // a. (..., None) - from either case 1, or case 2 with swallowed exception\n        // b. (..., exc) - from case 2 with re-raised exception\n        // c. (..., X, INT) - from case 3\n        EMIT_ARG(label_assign, l_end);\n        compile_decrease_except_level(comp);\n    }\n}\n\nSTATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // get the nodes for the pre-bit of the with (the a as b, c as d, ... bit)\n    mp_parse_node_t *nodes;\n    size_t n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes);\n    assert(n > 0);\n\n    // compile in a nested fashion\n    compile_async_with_stmt_helper(comp, n, nodes, pns->nodes[1]);\n}\n\nSTATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[0]));\n    mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t *)pns->nodes[0];\n    if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_funcdef) {\n        // async def\n        compile_funcdef(comp, pns0);\n        scope_t *fscope = (scope_t *)pns0->nodes[4];\n        fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;\n    } else if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) {\n        // async for\n        compile_async_for_stmt(comp, pns0);\n    } else {\n        // async with\n        assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt);\n        compile_async_with_stmt(comp, pns0);\n    }\n}\n#endif\n\nSTATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    mp_parse_node_t pn_rhs = pns->nodes[1];\n    if (MP_PARSE_NODE_IS_NULL(pn_rhs)) {\n        if (comp->is_repl && comp->scope_cur->kind == SCOPE_MODULE) {\n            // for REPL, evaluate then print the expression\n            compile_load_id(comp, MP_QSTR___repl_print__);\n            compile_node(comp, pns->nodes[0]);\n            EMIT_ARG(call_function, 1, 0, 0);\n            EMIT(pop_top);\n\n        } else {\n            // for non-REPL, evaluate then discard the expression\n            if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0]))\n                || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_const_object)) {\n                // do nothing with a lonely constant\n            } else {\n                compile_node(comp, pns->nodes[0]); // just an expression\n                EMIT(pop_top); // discard last result since this is a statement and leaves nothing on the stack\n            }\n        }\n    } else if (MP_PARSE_NODE_IS_STRUCT(pn_rhs)) {\n        mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pn_rhs;\n        int kind = MP_PARSE_NODE_STRUCT_KIND(pns1);\n        if (kind == PN_annassign) {\n            // the annotation is in pns1->nodes[0] and is ignored\n            if (MP_PARSE_NODE_IS_NULL(pns1->nodes[1])) {\n                // an annotation of the form \"x: y\"\n                // inside a function this declares \"x\" as a local\n                if (comp->scope_cur->kind == SCOPE_FUNCTION) {\n                    if (MP_PARSE_NODE_IS_ID(pns->nodes[0])) {\n                        qstr lhs = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);\n                        scope_find_or_add_id(comp->scope_cur, lhs, ID_INFO_KIND_LOCAL);\n                    }\n                }\n            } else {\n                // an assigned annotation of the form \"x: y = z\"\n                pn_rhs = pns1->nodes[1];\n                goto plain_assign;\n            }\n        } else if (kind == PN_expr_stmt_augassign) {\n            c_assign(comp, pns->nodes[0], ASSIGN_AUG_LOAD); // lhs load for aug assign\n            compile_node(comp, pns1->nodes[1]); // rhs\n            assert(MP_PARSE_NODE_IS_TOKEN(pns1->nodes[0]));\n            mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]);\n            mp_binary_op_t op = MP_BINARY_OP_INPLACE_OR + (tok - MP_TOKEN_DEL_PIPE_EQUAL);\n            EMIT_ARG(binary_op, op);\n            c_assign(comp, pns->nodes[0], ASSIGN_AUG_STORE); // lhs store for aug assign\n        } else if (kind == PN_expr_stmt_assign_list) {\n            int rhs = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1) - 1;\n            compile_node(comp, pns1->nodes[rhs]); // rhs\n            // following CPython, we store left-most first\n            if (rhs > 0) {\n                EMIT(dup_top);\n            }\n            c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store\n            for (int i = 0; i < rhs; i++) {\n                if (i + 1 < rhs) {\n                    EMIT(dup_top);\n                }\n                c_assign(comp, pns1->nodes[i], ASSIGN_STORE); // middle store\n            }\n        } else {\n        plain_assign:\n            #if MICROPY_COMP_DOUBLE_TUPLE_ASSIGN\n            if (MP_PARSE_NODE_IS_STRUCT_KIND(pn_rhs, PN_testlist_star_expr)\n                && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)) {\n                mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t *)pns->nodes[0];\n                pns1 = (mp_parse_node_struct_t *)pn_rhs;\n                uint32_t n_pns0 = MP_PARSE_NODE_STRUCT_NUM_NODES(pns0);\n                // Can only optimise a tuple-to-tuple assignment when all of the following hold:\n                //  - equal number of items in LHS and RHS tuples\n                //  - 2 or 3 items in the tuples\n                //  - there are no star expressions in the LHS tuple\n                if (n_pns0 == MP_PARSE_NODE_STRUCT_NUM_NODES(pns1)\n                    && (n_pns0 == 2\n                        #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN\n                        || n_pns0 == 3\n                        #endif\n                        )\n                    && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr)\n                    && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr)\n                    #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN\n                    && (n_pns0 == 2 || !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr))\n                    #endif\n                    ) {\n                    // Optimisation for a, b = c, d or a, b, c = d, e, f\n                    compile_node(comp, pns1->nodes[0]); // rhs\n                    compile_node(comp, pns1->nodes[1]); // rhs\n                    #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN\n                    if (n_pns0 == 3) {\n                        compile_node(comp, pns1->nodes[2]); // rhs\n                        EMIT(rot_three);\n                    }\n                    #endif\n                    EMIT(rot_two);\n                    c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store\n                    c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store\n                    #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN\n                    if (n_pns0 == 3) {\n                        c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store\n                    }\n                    #endif\n                    return;\n                }\n            }\n            #endif\n\n            compile_node(comp, pn_rhs); // rhs\n            c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store\n        }\n    } else {\n        goto plain_assign;\n    }\n}\n\nSTATIC void compile_test_if_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_test_if_else));\n    mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t *)pns->nodes[1];\n\n    uint l_fail = comp_next_label(comp);\n    uint l_end = comp_next_label(comp);\n    c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition\n    compile_node(comp, pns->nodes[0]); // success value\n    EMIT_ARG(jump, l_end);\n    EMIT_ARG(label_assign, l_fail);\n    EMIT_ARG(adjust_stack_size, -1); // adjust stack size\n    compile_node(comp, pns_test_if_else->nodes[1]); // failure value\n    EMIT_ARG(label_assign, l_end);\n}\n\nSTATIC void compile_lambdef(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    if (comp->pass == MP_PASS_SCOPE) {\n        // create a new scope for this lambda\n        scope_t *s = scope_new_and_link(comp, SCOPE_LAMBDA, (mp_parse_node_t)pns, comp->scope_cur->emit_options);\n        // store the lambda scope so the compiling function (this one) can use it at each pass\n        pns->nodes[2] = (mp_parse_node_t)s;\n    }\n\n    // get the scope for this lambda\n    scope_t *this_scope = (scope_t *)pns->nodes[2];\n\n    // compile the lambda definition\n    compile_funcdef_lambdef(comp, this_scope, pns->nodes[0], PN_varargslist);\n}\n\n#if MICROPY_PY_ASSIGN_EXPR\nSTATIC void compile_namedexpr_helper(compiler_t *comp, mp_parse_node_t pn_name, mp_parse_node_t pn_expr) {\n    if (!MP_PARSE_NODE_IS_ID(pn_name)) {\n        compile_syntax_error(comp, (mp_parse_node_t)pn_name, MP_ERROR_TEXT(\"can't assign to expression\"));\n    }\n    compile_node(comp, pn_expr);\n    EMIT(dup_top);\n    scope_t *old_scope = comp->scope_cur;\n    if (SCOPE_IS_COMP_LIKE(comp->scope_cur->kind)) {\n        // Use parent's scope for assigned value so it can \"escape\"\n        comp->scope_cur = comp->scope_cur->parent;\n    }\n    compile_store_id(comp, MP_PARSE_NODE_LEAF_ARG(pn_name));\n    comp->scope_cur = old_scope;\n}\n\nSTATIC void compile_namedexpr(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    compile_namedexpr_helper(comp, pns->nodes[0], pns->nodes[1]);\n}\n#endif\n\nSTATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    bool cond = MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test;\n    uint l_end = comp_next_label(comp);\n    int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n    for (int i = 0; i < n; i += 1) {\n        compile_node(comp, pns->nodes[i]);\n        if (i + 1 < n) {\n            EMIT_ARG(jump_if_or_pop, cond, l_end);\n        }\n    }\n    EMIT_ARG(label_assign, l_end);\n}\n\nSTATIC void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    compile_node(comp, pns->nodes[0]);\n    EMIT_ARG(unary_op, MP_UNARY_OP_NOT);\n}\n\nSTATIC void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n    compile_node(comp, pns->nodes[0]);\n    bool multi = (num_nodes > 3);\n    uint l_fail = 0;\n    if (multi) {\n        l_fail = comp_next_label(comp);\n    }\n    for (int i = 1; i + 1 < num_nodes; i += 2) {\n        compile_node(comp, pns->nodes[i + 1]);\n        if (i + 2 < num_nodes) {\n            EMIT(dup_top);\n            EMIT(rot_three);\n        }\n        if (MP_PARSE_NODE_IS_TOKEN(pns->nodes[i])) {\n            mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]);\n            mp_binary_op_t op;\n            if (tok == MP_TOKEN_KW_IN) {\n                op = MP_BINARY_OP_IN;\n            } else {\n                op = MP_BINARY_OP_LESS + (tok - MP_TOKEN_OP_LESS);\n            }\n            EMIT_ARG(binary_op, op);\n        } else {\n            assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[i])); // should be\n            mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[i];\n            int kind = MP_PARSE_NODE_STRUCT_KIND(pns2);\n            if (kind == PN_comp_op_not_in) {\n                EMIT_ARG(binary_op, MP_BINARY_OP_NOT_IN);\n            } else {\n                assert(kind == PN_comp_op_is); // should be\n                if (MP_PARSE_NODE_IS_NULL(pns2->nodes[0])) {\n                    EMIT_ARG(binary_op, MP_BINARY_OP_IS);\n                } else {\n                    EMIT_ARG(binary_op, MP_BINARY_OP_IS_NOT);\n                }\n            }\n        }\n        if (i + 2 < num_nodes) {\n            EMIT_ARG(jump_if_or_pop, false, l_fail);\n        }\n    }\n    if (multi) {\n        uint l_end = comp_next_label(comp);\n        EMIT_ARG(jump, l_end);\n        EMIT_ARG(label_assign, l_fail);\n        EMIT_ARG(adjust_stack_size, 1);\n        EMIT(rot_two);\n        EMIT(pop_top);\n        EMIT_ARG(label_assign, l_end);\n    }\n}\n\nSTATIC void compile_star_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"*x must be assignment target\"));\n}\n\nSTATIC void compile_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    MP_STATIC_ASSERT(MP_BINARY_OP_OR + PN_xor_expr - PN_expr == MP_BINARY_OP_XOR);\n    MP_STATIC_ASSERT(MP_BINARY_OP_OR + PN_and_expr - PN_expr == MP_BINARY_OP_AND);\n    mp_binary_op_t binary_op = MP_BINARY_OP_OR + MP_PARSE_NODE_STRUCT_KIND(pns) - PN_expr;\n    int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n    compile_node(comp, pns->nodes[0]);\n    for (int i = 1; i < num_nodes; ++i) {\n        compile_node(comp, pns->nodes[i]);\n        EMIT_ARG(binary_op, binary_op);\n    }\n}\n\nSTATIC void compile_term(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n    compile_node(comp, pns->nodes[0]);\n    for (int i = 1; i + 1 < num_nodes; i += 2) {\n        compile_node(comp, pns->nodes[i + 1]);\n        mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]);\n        mp_binary_op_t op = MP_BINARY_OP_LSHIFT + (tok - MP_TOKEN_OP_DBL_LESS);\n        EMIT_ARG(binary_op, op);\n    }\n}\n\nSTATIC void compile_factor_2(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    compile_node(comp, pns->nodes[1]);\n    mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);\n    mp_unary_op_t op;\n    if (tok == MP_TOKEN_OP_TILDE) {\n        op = MP_UNARY_OP_INVERT;\n    } else {\n        assert(tok == MP_TOKEN_OP_PLUS || tok == MP_TOKEN_OP_MINUS);\n        op = MP_UNARY_OP_POSITIVE + (tok - MP_TOKEN_OP_PLUS);\n    }\n    EMIT_ARG(unary_op, op);\n}\n\nSTATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // compile the subject of the expression\n    compile_node(comp, pns->nodes[0]);\n\n    // compile_atom_expr_await may call us with a NULL node\n    if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {\n        return;\n    }\n\n    // get the array of trailers (known to be an array of PARSE_NODE_STRUCT)\n    size_t num_trail = 1;\n    mp_parse_node_struct_t **pns_trail = (mp_parse_node_struct_t **)&pns->nodes[1];\n    if (MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_atom_expr_trailers) {\n        num_trail = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_trail[0]);\n        pns_trail = (mp_parse_node_struct_t **)&pns_trail[0]->nodes[0];\n    }\n\n    // the current index into the array of trailers\n    size_t i = 0;\n\n    // handle special super() call\n    if (comp->scope_cur->kind == SCOPE_FUNCTION\n        && MP_PARSE_NODE_IS_ID(pns->nodes[0])\n        && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super\n        && MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren\n        && MP_PARSE_NODE_IS_NULL(pns_trail[0]->nodes[0])) {\n        // at this point we have matched \"super()\" within a function\n\n        // load the class for super to search for a parent\n        compile_load_id(comp, MP_QSTR___class__);\n\n        // look for first argument to function (assumes it's \"self\")\n        bool found = false;\n        id_info_t *id = &comp->scope_cur->id_info[0];\n        for (size_t n = comp->scope_cur->id_info_len; n > 0; --n, ++id) {\n            if (id->flags & ID_FLAG_IS_PARAM) {\n                // first argument found; load it\n                compile_load_id(comp, id->qst);\n                found = true;\n                break;\n            }\n        }\n        if (!found) {\n            compile_syntax_error(comp, (mp_parse_node_t)pns_trail[0],\n                MP_ERROR_TEXT(\"super() can't find self\")); // really a TypeError\n            return;\n        }\n\n        if (num_trail >= 3\n            && MP_PARSE_NODE_STRUCT_KIND(pns_trail[1]) == PN_trailer_period\n            && MP_PARSE_NODE_STRUCT_KIND(pns_trail[2]) == PN_trailer_paren) {\n            // optimisation for method calls super().f(...), to eliminate heap allocation\n            mp_parse_node_struct_t *pns_period = pns_trail[1];\n            mp_parse_node_struct_t *pns_paren = pns_trail[2];\n            EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]), true);\n            compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0);\n            i = 3;\n        } else {\n            // a super() call\n            EMIT_ARG(call_function, 2, 0, 0);\n            i = 1;\n        }\n\n        #if MICROPY_COMP_CONST_LITERAL && MICROPY_PY_COLLECTIONS_ORDEREDDICT\n        // handle special OrderedDict constructor\n    } else if (MP_PARSE_NODE_IS_ID(pns->nodes[0])\n               && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_OrderedDict\n               && MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren\n               && MP_PARSE_NODE_IS_STRUCT_KIND(pns_trail[0]->nodes[0], PN_atom_brace)) {\n        // at this point we have matched \"OrderedDict({...})\"\n\n        EMIT_ARG(call_function, 0, 0, 0);\n        mp_parse_node_struct_t *pns_dict = (mp_parse_node_struct_t *)pns_trail[0]->nodes[0];\n        compile_atom_brace_helper(comp, pns_dict, false);\n        i = 1;\n        #endif\n    }\n\n    // compile the remaining trailers\n    for (; i < num_trail; i++) {\n        if (i + 1 < num_trail\n            && MP_PARSE_NODE_STRUCT_KIND(pns_trail[i]) == PN_trailer_period\n            && MP_PARSE_NODE_STRUCT_KIND(pns_trail[i + 1]) == PN_trailer_paren) {\n            // optimisation for method calls a.f(...), following PyPy\n            mp_parse_node_struct_t *pns_period = pns_trail[i];\n            mp_parse_node_struct_t *pns_paren = pns_trail[i + 1];\n            EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]), false);\n            compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0);\n            i += 1;\n        } else {\n            // node is one of: trailer_paren, trailer_bracket, trailer_period\n            compile_node(comp, (mp_parse_node_t)pns_trail[i]);\n        }\n    }\n}\n\nSTATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    compile_generic_all_nodes(comp, pns); // 2 nodes, arguments of power\n    EMIT_ARG(binary_op, MP_BINARY_OP_POWER);\n}\n\nSTATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) {\n    // function to call is on top of stack\n\n    // get the list of arguments\n    mp_parse_node_t *args;\n    size_t n_args = mp_parse_node_extract_list(&pn_arglist, PN_arglist, &args);\n\n    // compile the arguments\n    // Rather than calling compile_node on the list, we go through the list of args\n    // explicitly here so that we can count the number of arguments and give sensible\n    // error messages.\n    int n_positional = n_positional_extra;\n    uint n_keyword = 0;\n    uint star_flags = 0;\n    mp_parse_node_struct_t *star_args_node = NULL, *dblstar_args_node = NULL;\n    for (size_t i = 0; i < n_args; i++) {\n        if (MP_PARSE_NODE_IS_STRUCT(args[i])) {\n            mp_parse_node_struct_t *pns_arg = (mp_parse_node_struct_t *)args[i];\n            if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_arglist_star) {\n                if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) {\n                    compile_syntax_error(comp, (mp_parse_node_t)pns_arg, MP_ERROR_TEXT(\"can't have multiple *x\"));\n                    return;\n                }\n                star_flags |= MP_EMIT_STAR_FLAG_SINGLE;\n                star_args_node = pns_arg;\n            } else if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_arglist_dbl_star) {\n                if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) {\n                    compile_syntax_error(comp, (mp_parse_node_t)pns_arg, MP_ERROR_TEXT(\"can't have multiple **x\"));\n                    return;\n                }\n                star_flags |= MP_EMIT_STAR_FLAG_DOUBLE;\n                dblstar_args_node = pns_arg;\n            } else if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_argument) {\n                #if MICROPY_PY_ASSIGN_EXPR\n                if (MP_PARSE_NODE_IS_STRUCT_KIND(pns_arg->nodes[1], PN_argument_3)) {\n                    compile_namedexpr_helper(comp, pns_arg->nodes[0], ((mp_parse_node_struct_t *)pns_arg->nodes[1])->nodes[0]);\n                    n_positional++;\n                } else\n                #endif\n                if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns_arg->nodes[1], PN_comp_for)) {\n                    if (!MP_PARSE_NODE_IS_ID(pns_arg->nodes[0])) {\n                        compile_syntax_error(comp, (mp_parse_node_t)pns_arg, MP_ERROR_TEXT(\"LHS of keyword arg must be an id\"));\n                        return;\n                    }\n                    EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pns_arg->nodes[0]));\n                    compile_node(comp, pns_arg->nodes[1]);\n                    n_keyword += 1;\n                } else {\n                    compile_comprehension(comp, pns_arg, SCOPE_GEN_EXPR);\n                    n_positional++;\n                }\n            } else {\n                goto normal_argument;\n            }\n        } else {\n        normal_argument:\n            if (star_flags) {\n                compile_syntax_error(comp, args[i], MP_ERROR_TEXT(\"non-keyword arg after */**\"));\n                return;\n            }\n            if (n_keyword > 0) {\n                compile_syntax_error(comp, args[i], MP_ERROR_TEXT(\"non-keyword arg after keyword arg\"));\n                return;\n            }\n            compile_node(comp, args[i]);\n            n_positional++;\n        }\n    }\n\n    // compile the star/double-star arguments if we had them\n    // if we had one but not the other then we load \"null\" as a place holder\n    if (star_flags != 0) {\n        if (star_args_node == NULL) {\n            EMIT(load_null);\n        } else {\n            compile_node(comp, star_args_node->nodes[0]);\n        }\n        if (dblstar_args_node == NULL) {\n            EMIT(load_null);\n        } else {\n            compile_node(comp, dblstar_args_node->nodes[0]);\n        }\n    }\n\n    // emit the function/method call\n    if (is_method_call) {\n        EMIT_ARG(call_method, n_positional, n_keyword, star_flags);\n    } else {\n        EMIT_ARG(call_function, n_positional, n_keyword, star_flags);\n    }\n}\n\n// pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node\nSTATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) {\n    assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2);\n    assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for));\n    mp_parse_node_struct_t *pns_comp_for = (mp_parse_node_struct_t *)pns->nodes[1];\n\n    if (comp->pass == MP_PASS_SCOPE) {\n        // create a new scope for this comprehension\n        scope_t *s = scope_new_and_link(comp, kind, (mp_parse_node_t)pns, comp->scope_cur->emit_options);\n        // store the comprehension scope so the compiling function (this one) can use it at each pass\n        pns_comp_for->nodes[3] = (mp_parse_node_t)s;\n    }\n\n    // get the scope for this comprehension\n    scope_t *this_scope = (scope_t *)pns_comp_for->nodes[3];\n\n    // compile the comprehension\n    close_over_variables_etc(comp, this_scope, 0, 0);\n\n    compile_node(comp, pns_comp_for->nodes[1]); // source of the iterator\n    if (kind == SCOPE_GEN_EXPR) {\n        EMIT_ARG(get_iter, false);\n    }\n    EMIT_ARG(call_function, 1, 0, 0);\n}\n\nSTATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n        // an empty tuple\n        c_tuple(comp, MP_PARSE_NODE_NULL, NULL);\n    } else {\n        assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));\n        pns = (mp_parse_node_struct_t *)pns->nodes[0];\n        assert(!MP_PARSE_NODE_IS_NULL(pns->nodes[1]));\n        if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {\n            mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1];\n            if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) {\n                // tuple of one item, with trailing comma\n                assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));\n                c_tuple(comp, pns->nodes[0], NULL);\n            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {\n                // tuple of many items\n                c_tuple(comp, pns->nodes[0], pns2);\n            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) {\n                // generator expression\n                compile_comprehension(comp, pns, SCOPE_GEN_EXPR);\n            } else {\n                // tuple with 2 items\n                goto tuple_with_2_items;\n            }\n        } else {\n            // tuple with 2 items\n        tuple_with_2_items:\n            c_tuple(comp, MP_PARSE_NODE_NULL, pns);\n        }\n    }\n}\n\nSTATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n        // empty list\n        EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST);\n    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {\n        mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[0];\n        if (MP_PARSE_NODE_IS_STRUCT(pns2->nodes[1])) {\n            mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t *)pns2->nodes[1];\n            if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3b) {\n                // list of one item, with trailing comma\n                assert(MP_PARSE_NODE_IS_NULL(pns3->nodes[0]));\n                compile_node(comp, pns2->nodes[0]);\n                EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST);\n            } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3c) {\n                // list of many items\n                compile_node(comp, pns2->nodes[0]);\n                compile_generic_all_nodes(comp, pns3);\n                EMIT_ARG(build, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3), MP_EMIT_BUILD_LIST);\n            } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_comp_for) {\n                // list comprehension\n                compile_comprehension(comp, pns2, SCOPE_LIST_COMP);\n            } else {\n                // list with 2 items\n                goto list_with_2_items;\n            }\n        } else {\n            // list with 2 items\n        list_with_2_items:\n            compile_node(comp, pns2->nodes[0]);\n            compile_node(comp, pns2->nodes[1]);\n            EMIT_ARG(build, 2, MP_EMIT_BUILD_LIST);\n        }\n    } else {\n        // list with 1 item\n        compile_node(comp, pns->nodes[0]);\n        EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST);\n    }\n}\n\nSTATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *pns, bool create_map) {\n    mp_parse_node_t pn = pns->nodes[0];\n    if (MP_PARSE_NODE_IS_NULL(pn)) {\n        // empty dict\n        if (create_map) {\n            EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP);\n        }\n    } else if (MP_PARSE_NODE_IS_STRUCT(pn)) {\n        pns = (mp_parse_node_struct_t *)pn;\n        if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker_item) {\n            // dict with one element\n            if (create_map) {\n                EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP);\n            }\n            compile_node(comp, pn);\n            EMIT(store_map);\n        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) {\n            assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should succeed\n            mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1];\n            if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_dictorsetmaker_list) {\n                // dict/set with multiple elements\n\n                // get tail elements (2nd, 3rd, ...)\n                mp_parse_node_t *nodes;\n                size_t n = mp_parse_node_extract_list(&pns1->nodes[0], PN_dictorsetmaker_list2, &nodes);\n\n                // first element sets whether it's a dict or set\n                bool is_dict;\n                if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) {\n                    // a dictionary\n                    if (create_map) {\n                        EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP);\n                    }\n                    compile_node(comp, pns->nodes[0]);\n                    EMIT(store_map);\n                    is_dict = true;\n                } else {\n                    // a set\n                    compile_node(comp, pns->nodes[0]); // 1st value of set\n                    is_dict = false;\n                }\n\n                // process rest of elements\n                for (size_t i = 0; i < n; i++) {\n                    mp_parse_node_t pn_i = nodes[i];\n                    bool is_key_value = MP_PARSE_NODE_IS_STRUCT_KIND(pn_i, PN_dictorsetmaker_item);\n                    compile_node(comp, pn_i);\n                    if (is_dict) {\n                        if (!is_key_value) {\n                            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                            compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"invalid syntax\"));\n                            #else\n                            compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"expecting key:value for dict\"));\n                            #endif\n                            return;\n                        }\n                        EMIT(store_map);\n                    } else {\n                        if (is_key_value) {\n                            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                            compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"invalid syntax\"));\n                            #else\n                            compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"expecting just a value for set\"));\n                            #endif\n                            return;\n                        }\n                    }\n                }\n\n                #if MICROPY_PY_BUILTINS_SET\n                // if it's a set, build it\n                if (!is_dict) {\n                    EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_SET);\n                }\n                #endif\n            } else {\n                assert(MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for); // should be\n                // dict/set comprehension\n                if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) {\n                    // a dictionary comprehension\n                    compile_comprehension(comp, pns, SCOPE_DICT_COMP);\n                } else {\n                    // a set comprehension\n                    compile_comprehension(comp, pns, SCOPE_SET_COMP);\n                }\n            }\n        } else {\n            // set with one element\n            goto set_with_one_element;\n        }\n    } else {\n        // set with one element\n    set_with_one_element:\n        #if MICROPY_PY_BUILTINS_SET\n        compile_node(comp, pn);\n        EMIT_ARG(build, 1, MP_EMIT_BUILD_SET);\n        #else\n        assert(0);\n        #endif\n    }\n}\n\nSTATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    compile_atom_brace_helper(comp, pns, true);\n}\n\nSTATIC void compile_trailer_paren(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    compile_trailer_paren_helper(comp, pns->nodes[0], false, 0);\n}\n\nSTATIC void compile_trailer_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // object who's index we want is on top of stack\n    compile_node(comp, pns->nodes[0]); // the index\n    EMIT_ARG(subscr, MP_EMIT_SUBSCR_LOAD);\n}\n\nSTATIC void compile_trailer_period(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // object who's attribute we want is on top of stack\n    EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]), MP_EMIT_ATTR_LOAD); // attribute to get\n}\n\n#if MICROPY_PY_BUILTINS_SLICE\nSTATIC void compile_subscript(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_2) {\n        compile_node(comp, pns->nodes[0]); // start of slice\n        assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be\n        pns = (mp_parse_node_struct_t *)pns->nodes[1];\n    } else {\n        // pns is a PN_subscript_3, load None for start of slice\n        EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n    }\n\n    assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3); // should always be\n    mp_parse_node_t pn = pns->nodes[0];\n    if (MP_PARSE_NODE_IS_NULL(pn)) {\n        // [?:]\n        EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n        EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE);\n    } else if (MP_PARSE_NODE_IS_STRUCT(pn)) {\n        pns = (mp_parse_node_struct_t *)pn;\n        if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3c) {\n            EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n            pn = pns->nodes[0];\n            if (MP_PARSE_NODE_IS_NULL(pn)) {\n                // [?::]\n                EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE);\n            } else {\n                // [?::x]\n                compile_node(comp, pn);\n                EMIT_ARG(build, 3, MP_EMIT_BUILD_SLICE);\n            }\n        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3d) {\n            compile_node(comp, pns->nodes[0]);\n            assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be\n            pns = (mp_parse_node_struct_t *)pns->nodes[1];\n            assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_sliceop); // should always be\n            if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n                // [?:x:]\n                EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE);\n            } else {\n                // [?:x:x]\n                compile_node(comp, pns->nodes[0]);\n                EMIT_ARG(build, 3, MP_EMIT_BUILD_SLICE);\n            }\n        } else {\n            // [?:x]\n            compile_node(comp, pn);\n            EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE);\n        }\n    } else {\n        // [?:x]\n        compile_node(comp, pn);\n        EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE);\n    }\n}\n#endif // MICROPY_PY_BUILTINS_SLICE\n\nSTATIC void compile_dictorsetmaker_item(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    // if this is called then we are compiling a dict key:value pair\n    compile_node(comp, pns->nodes[1]); // value\n    compile_node(comp, pns->nodes[0]); // key\n}\n\nSTATIC void compile_classdef(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    qstr cname = compile_classdef_helper(comp, pns, comp->scope_cur->emit_options);\n    // store class object into class name\n    compile_store_id(comp, cname);\n}\n\nSTATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) {\n        compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"'yield' outside function\"));\n        return;\n    }\n    if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n        EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n        EMIT_ARG(yield, MP_EMIT_YIELD_VALUE);\n        reserve_labels_for_native(comp, 1);\n    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) {\n        pns = (mp_parse_node_struct_t *)pns->nodes[0];\n        compile_node(comp, pns->nodes[0]);\n        compile_yield_from(comp);\n    } else {\n        compile_node(comp, pns->nodes[0]);\n        EMIT_ARG(yield, MP_EMIT_YIELD_VALUE);\n        reserve_labels_for_native(comp, 1);\n    }\n}\n\n#if MICROPY_PY_ASYNC_AWAIT\nSTATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) {\n        compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT(\"'await' outside function\"));\n        return;\n    }\n    compile_atom_expr_normal(comp, pns);\n    compile_yield_from(comp);\n}\n#endif\n\nSTATIC mp_obj_t get_const_object(mp_parse_node_struct_t *pns) {\n    #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D\n    // nodes are 32-bit pointers, but need to extract 64-bit object\n    return (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32);\n    #else\n    return (mp_obj_t)pns->nodes[0];\n    #endif\n}\n\nSTATIC void compile_const_object(compiler_t *comp, mp_parse_node_struct_t *pns) {\n    EMIT_ARG(load_const_obj, get_const_object(pns));\n}\n\ntypedef void (*compile_function_t)(compiler_t *, mp_parse_node_struct_t *);\nSTATIC const compile_function_t compile_function[] = {\n// only define rules with a compile function\n#define c(f) compile_##f\n#define DEF_RULE(rule, comp, kind, ...) comp,\n#define DEF_RULE_NC(rule, kind, ...)\n    #include \"py/grammar.h\"\n#undef c\n#undef DEF_RULE\n#undef DEF_RULE_NC\n    compile_const_object,\n};\n\nSTATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {\n    if (MP_PARSE_NODE_IS_NULL(pn)) {\n        // pass\n    } else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {\n        mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);\n        #if MICROPY_DYNAMIC_COMPILER\n        mp_uint_t sign_mask = -((mp_uint_t)1 << (mp_dynamic_compiler.small_int_bits - 1));\n        if ((arg & sign_mask) == 0 || (arg & sign_mask) == sign_mask) {\n            // integer fits in target runtime's small-int\n            EMIT_ARG(load_const_small_int, arg);\n        } else {\n            // integer doesn't fit, so create a multi-precision int object\n            // (but only create the actual object on the last pass)\n            if (comp->pass != MP_PASS_EMIT) {\n                EMIT_ARG(load_const_obj, mp_const_none);\n            } else {\n                EMIT_ARG(load_const_obj, mp_obj_new_int_from_ll(arg));\n            }\n        }\n        #else\n        EMIT_ARG(load_const_small_int, arg);\n        #endif\n    } else if (MP_PARSE_NODE_IS_LEAF(pn)) {\n        uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn);\n        switch (MP_PARSE_NODE_LEAF_KIND(pn)) {\n            case MP_PARSE_NODE_ID:\n                compile_load_id(comp, arg);\n                break;\n            case MP_PARSE_NODE_STRING:\n                EMIT_ARG(load_const_str, arg);\n                break;\n            case MP_PARSE_NODE_BYTES:\n                // only create and load the actual bytes object on the last pass\n                if (comp->pass != MP_PASS_EMIT) {\n                    EMIT_ARG(load_const_obj, mp_const_none);\n                } else {\n                    size_t len;\n                    const byte *data = qstr_data(arg, &len);\n                    EMIT_ARG(load_const_obj, mp_obj_new_bytes(data, len));\n                }\n                break;\n            case MP_PARSE_NODE_TOKEN:\n            default:\n                if (arg == MP_TOKEN_NEWLINE) {\n                    // this can occur when file_input lets through a NEWLINE (eg if file starts with a newline)\n                    // or when single_input lets through a NEWLINE (user enters a blank line)\n                    // do nothing\n                } else {\n                    EMIT_ARG(load_const_tok, arg);\n                }\n                break;\n        }\n    } else {\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n        EMIT_ARG(set_source_line, pns->source_line);\n        assert(MP_PARSE_NODE_STRUCT_KIND(pns) <= PN_const_object);\n        compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];\n        f(comp, pns);\n    }\n}\n\n#if MICROPY_EMIT_NATIVE\nSTATIC int compile_viper_type_annotation(compiler_t *comp, mp_parse_node_t pn_annotation) {\n    int native_type = MP_NATIVE_TYPE_OBJ;\n    if (MP_PARSE_NODE_IS_NULL(pn_annotation)) {\n        // No annotation, type defaults to object\n    } else if (MP_PARSE_NODE_IS_ID(pn_annotation)) {\n        qstr type_name = MP_PARSE_NODE_LEAF_ARG(pn_annotation);\n        native_type = mp_native_type_from_qstr(type_name);\n        if (native_type < 0) {\n            comp->compile_error = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, MP_ERROR_TEXT(\"unknown type '%q'\"), type_name);\n            native_type = 0;\n        }\n    } else {\n        compile_syntax_error(comp, pn_annotation, MP_ERROR_TEXT(\"annotation must be an identifier\"));\n    }\n    return native_type;\n}\n#endif\n\nSTATIC 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) {\n    (void)pn_dbl_star;\n\n    // check that **kw is last\n    if ((comp->scope_cur->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {\n        compile_syntax_error(comp, pn, MP_ERROR_TEXT(\"invalid syntax\"));\n        return;\n    }\n\n    qstr param_name = MP_QSTRnull;\n    uint param_flag = ID_FLAG_IS_PARAM;\n    mp_parse_node_struct_t *pns = NULL;\n    if (MP_PARSE_NODE_IS_ID(pn)) {\n        param_name = MP_PARSE_NODE_LEAF_ARG(pn);\n        if (comp->have_star) {\n            // comes after a star, so counts as a keyword-only parameter\n            comp->scope_cur->num_kwonly_args += 1;\n        } else {\n            // comes before a star, so counts as a positional parameter\n            comp->scope_cur->num_pos_args += 1;\n        }\n    } else {\n        assert(MP_PARSE_NODE_IS_STRUCT(pn));\n        pns = (mp_parse_node_struct_t *)pn;\n        if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_name) {\n            // named parameter with possible annotation\n            param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);\n            if (comp->have_star) {\n                // comes after a star, so counts as a keyword-only parameter\n                comp->scope_cur->num_kwonly_args += 1;\n            } else {\n                // comes before a star, so counts as a positional parameter\n                comp->scope_cur->num_pos_args += 1;\n            }\n        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_star) {\n            if (comp->have_star) {\n                // more than one star\n                compile_syntax_error(comp, pn, MP_ERROR_TEXT(\"invalid syntax\"));\n                return;\n            }\n            comp->have_star = true;\n            param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_STAR_PARAM;\n            if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {\n                // bare star\n                // TODO see http://www.python.org/dev/peps/pep-3102/\n                // assert(comp->scope_cur->num_dict_params == 0);\n                pns = NULL;\n            } else if (MP_PARSE_NODE_IS_ID(pns->nodes[0])) {\n                // named star\n                comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;\n                param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);\n                pns = NULL;\n            } else {\n                assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)); // should be\n                // named star with possible annotation\n                comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;\n                pns = (mp_parse_node_struct_t *)pns->nodes[0];\n                param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);\n            }\n        } else {\n            // double star with possible annotation\n            assert(MP_PARSE_NODE_STRUCT_KIND(pns) == pn_dbl_star); // should be\n            param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);\n            param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_DBL_STAR_PARAM;\n            comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARKEYWORDS;\n        }\n    }\n\n    if (param_name != MP_QSTRnull) {\n        id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, param_name, ID_INFO_KIND_UNDECIDED);\n        if (id_info->kind != ID_INFO_KIND_UNDECIDED) {\n            compile_syntax_error(comp, pn, MP_ERROR_TEXT(\"argument name reused\"));\n            return;\n        }\n        id_info->kind = ID_INFO_KIND_LOCAL;\n        id_info->flags = param_flag;\n\n        #if MICROPY_EMIT_NATIVE\n        if (comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER && pn_name == PN_typedargslist_name && pns != NULL) {\n            id_info->flags |= compile_viper_type_annotation(comp, pns->nodes[1]) << ID_FLAG_VIPER_TYPE_POS;\n        }\n        #else\n        (void)pns;\n        #endif\n    }\n}\n\nSTATIC void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) {\n    compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star);\n}\n\nSTATIC void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) {\n    compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star);\n}\n\nSTATIC 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) {\n    uint l_top = comp_next_label(comp);\n    uint l_end = comp_next_label(comp);\n    EMIT_ARG(label_assign, l_top);\n    EMIT_ARG(for_iter, l_end);\n    c_assign(comp, pns_comp_for->nodes[0], ASSIGN_STORE);\n    mp_parse_node_t pn_iter = pns_comp_for->nodes[2];\n\ntail_recursion:\n    if (MP_PARSE_NODE_IS_NULL(pn_iter)) {\n        // no more nested if/for; compile inner expression\n        compile_node(comp, pn_inner_expr);\n        if (comp->scope_cur->kind == SCOPE_GEN_EXPR) {\n            EMIT_ARG(yield, MP_EMIT_YIELD_VALUE);\n            reserve_labels_for_native(comp, 1);\n            EMIT(pop_top);\n        } else {\n            EMIT_ARG(store_comp, comp->scope_cur->kind, 4 * for_depth + 5);\n        }\n    } else if (MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t *)pn_iter) == PN_comp_if) {\n        // if condition\n        mp_parse_node_struct_t *pns_comp_if = (mp_parse_node_struct_t *)pn_iter;\n        c_if_cond(comp, pns_comp_if->nodes[0], false, l_top);\n        pn_iter = pns_comp_if->nodes[1];\n        goto tail_recursion;\n    } else {\n        assert(MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t *)pn_iter) == PN_comp_for); // should be\n        // for loop\n        mp_parse_node_struct_t *pns_comp_for2 = (mp_parse_node_struct_t *)pn_iter;\n        compile_node(comp, pns_comp_for2->nodes[1]);\n        EMIT_ARG(get_iter, true);\n        compile_scope_comp_iter(comp, pns_comp_for2, pn_inner_expr, for_depth + 1);\n    }\n\n    EMIT_ARG(jump, l_top);\n    EMIT_ARG(label_assign, l_end);\n    EMIT(for_iter_end);\n}\n\nSTATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) {\n    #if MICROPY_ENABLE_DOC_STRING\n    // see http://www.python.org/dev/peps/pep-0257/\n\n    // look for the first statement\n    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) {\n        // a statement; fall through\n    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_file_input_2)) {\n        // file input; find the first non-newline node\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n        int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n        for (int i = 0; i < num_nodes; i++) {\n            pn = pns->nodes[i];\n            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)) {\n                // not a newline, so this is the first statement; finish search\n                break;\n            }\n        }\n        // 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\n    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_suite_block_stmts)) {\n        // a list of statements; get the first one\n        pn = ((mp_parse_node_struct_t *)pn)->nodes[0];\n    } else {\n        return;\n    }\n\n    // check the first statement for a doc string\n    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) {\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n        if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0])\n             && MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]) == MP_PARSE_NODE_STRING)\n            || (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_const_object)\n                && mp_obj_is_str(get_const_object((mp_parse_node_struct_t *)pns->nodes[0])))) {\n            // compile the doc string\n            compile_node(comp, pns->nodes[0]);\n            // store the doc string\n            compile_store_id(comp, MP_QSTR___doc__);\n        }\n    }\n    #else\n    (void)comp;\n    (void)pn;\n    #endif\n}\n\nSTATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {\n    comp->pass = pass;\n    comp->scope_cur = scope;\n    comp->next_label = 0;\n    EMIT_ARG(start_pass, pass, scope);\n    reserve_labels_for_native(comp, 6); // used by native's start_pass\n\n    if (comp->pass == MP_PASS_SCOPE) {\n        // reset maximum stack sizes in scope\n        // they will be computed in this first pass\n        scope->stack_size = 0;\n        scope->exc_stack_size = 0;\n    }\n\n    // compile\n    if (MP_PARSE_NODE_IS_STRUCT_KIND(scope->pn, PN_eval_input)) {\n        assert(scope->kind == SCOPE_MODULE);\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)scope->pn;\n        compile_node(comp, pns->nodes[0]); // compile the expression\n        EMIT(return_value);\n    } else if (scope->kind == SCOPE_MODULE) {\n        if (!comp->is_repl) {\n            check_for_doc_string(comp, scope->pn);\n        }\n        compile_node(comp, scope->pn);\n        EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n        EMIT(return_value);\n    } else if (scope->kind == SCOPE_FUNCTION) {\n        assert(MP_PARSE_NODE_IS_STRUCT(scope->pn));\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)scope->pn;\n        assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_funcdef);\n\n        // work out number of parameters, keywords and default parameters, and add them to the id_info array\n        // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc)\n        if (comp->pass == MP_PASS_SCOPE) {\n            comp->have_star = false;\n            apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_param);\n\n            #if MICROPY_EMIT_NATIVE\n            if (scope->emit_options == MP_EMIT_OPT_VIPER) {\n                // Compile return type; pns->nodes[2] is return/whole function annotation\n                scope->scope_flags |= compile_viper_type_annotation(comp, pns->nodes[2]) << MP_SCOPE_FLAG_VIPERRET_POS;\n            }\n            #endif // MICROPY_EMIT_NATIVE\n        }\n\n        compile_node(comp, pns->nodes[3]); // 3 is function body\n        // emit return if it wasn't the last opcode\n        if (!EMIT(last_emit_was_return_value)) {\n            EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n            EMIT(return_value);\n        }\n    } else if (scope->kind == SCOPE_LAMBDA) {\n        assert(MP_PARSE_NODE_IS_STRUCT(scope->pn));\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)scope->pn;\n        assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 3);\n\n        // Set the source line number for the start of the lambda\n        EMIT_ARG(set_source_line, pns->source_line);\n\n        // work out number of parameters, keywords and default parameters, and add them to the id_info array\n        // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc)\n        if (comp->pass == MP_PASS_SCOPE) {\n            comp->have_star = false;\n            apply_to_single_or_list(comp, pns->nodes[0], PN_varargslist, compile_scope_lambda_param);\n        }\n\n        compile_node(comp, pns->nodes[1]); // 1 is lambda body\n\n        // if the lambda is a generator, then we return None, not the result of the expression of the lambda\n        if (scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {\n            EMIT(pop_top);\n            EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n        }\n        EMIT(return_value);\n    } else if (SCOPE_IS_COMP_LIKE(scope->kind)) {\n        // a bit of a hack at the moment\n\n        assert(MP_PARSE_NODE_IS_STRUCT(scope->pn));\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)scope->pn;\n        assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2);\n        assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for));\n        mp_parse_node_struct_t *pns_comp_for = (mp_parse_node_struct_t *)pns->nodes[1];\n\n        // We need a unique name for the comprehension argument (the iterator).\n        // CPython uses .0, but we should be able to use anything that won't\n        // clash with a user defined variable.  Best to use an existing qstr,\n        // so we use the blank qstr.\n        qstr qstr_arg = MP_QSTR_;\n        if (comp->pass == MP_PASS_SCOPE) {\n            scope_find_or_add_id(comp->scope_cur, qstr_arg, ID_INFO_KIND_LOCAL);\n            scope->num_pos_args = 1;\n        }\n\n        // Set the source line number for the start of the comprehension\n        EMIT_ARG(set_source_line, pns->source_line);\n\n        if (scope->kind == SCOPE_LIST_COMP) {\n            EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST);\n        } else if (scope->kind == SCOPE_DICT_COMP) {\n            EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP);\n        #if MICROPY_PY_BUILTINS_SET\n        } else if (scope->kind == SCOPE_SET_COMP) {\n            EMIT_ARG(build, 0, MP_EMIT_BUILD_SET);\n        #endif\n        }\n\n        // There are 4 slots on the stack for the iterator, and the first one is\n        // NULL to indicate that the second one points to the iterator object.\n        if (scope->kind == SCOPE_GEN_EXPR) {\n            MP_STATIC_ASSERT(MP_OBJ_ITER_BUF_NSLOTS == 4);\n            EMIT(load_null);\n            compile_load_id(comp, qstr_arg);\n            EMIT(load_null);\n            EMIT(load_null);\n        } else {\n            compile_load_id(comp, qstr_arg);\n            EMIT_ARG(get_iter, true);\n        }\n\n        compile_scope_comp_iter(comp, pns_comp_for, pns->nodes[0], 0);\n\n        if (scope->kind == SCOPE_GEN_EXPR) {\n            EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n        }\n        EMIT(return_value);\n    } else {\n        assert(scope->kind == SCOPE_CLASS);\n        assert(MP_PARSE_NODE_IS_STRUCT(scope->pn));\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)scope->pn;\n        assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_classdef);\n\n        if (comp->pass == MP_PASS_SCOPE) {\n            scope_find_or_add_id(scope, MP_QSTR___class__, ID_INFO_KIND_LOCAL);\n        }\n\n        #if MICROPY_PY_SYS_SETTRACE\n        EMIT_ARG(set_source_line, pns->source_line);\n        #endif\n        compile_load_id(comp, MP_QSTR___name__);\n        compile_store_id(comp, MP_QSTR___module__);\n        EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); // 0 is class name\n        compile_store_id(comp, MP_QSTR___qualname__);\n\n        check_for_doc_string(comp, pns->nodes[2]);\n        compile_node(comp, pns->nodes[2]); // 2 is class body\n\n        id_info_t *id = scope_find(scope, MP_QSTR___class__);\n        assert(id != NULL);\n        if (id->kind == ID_INFO_KIND_LOCAL) {\n            EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);\n        } else {\n            EMIT_LOAD_FAST(MP_QSTR___class__, id->local_num);\n        }\n        EMIT(return_value);\n    }\n\n    EMIT(end_pass);\n\n    // make sure we match all the exception levels\n    assert(comp->cur_except_level == 0);\n}\n\n#if MICROPY_EMIT_INLINE_ASM\n// requires 3 passes: SCOPE, CODE_SIZE, EMIT\nSTATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass) {\n    comp->pass = pass;\n    comp->scope_cur = scope;\n    comp->next_label = 0;\n\n    if (scope->kind != SCOPE_FUNCTION) {\n        compile_syntax_error(comp, MP_PARSE_NODE_NULL, MP_ERROR_TEXT(\"inline assembler must be a function\"));\n        return;\n    }\n\n    if (comp->pass > MP_PASS_SCOPE) {\n        EMIT_INLINE_ASM_ARG(start_pass, comp->pass, &comp->compile_error);\n    }\n\n    // get the function definition parse node\n    assert(MP_PARSE_NODE_IS_STRUCT(scope->pn));\n    mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)scope->pn;\n    assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_funcdef);\n\n    // qstr f_id = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); // function name\n\n    // parameters are in pns->nodes[1]\n    if (comp->pass == MP_PASS_CODE_SIZE) {\n        mp_parse_node_t *pn_params;\n        size_t n_params = mp_parse_node_extract_list(&pns->nodes[1], PN_typedargslist, &pn_params);\n        scope->num_pos_args = EMIT_INLINE_ASM_ARG(count_params, n_params, pn_params);\n        if (comp->compile_error != MP_OBJ_NULL) {\n            goto inline_asm_error;\n        }\n    }\n\n    // pns->nodes[2] is function return annotation\n    mp_uint_t type_sig = MP_NATIVE_TYPE_INT;\n    mp_parse_node_t pn_annotation = pns->nodes[2];\n    if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {\n        // nodes[2] can be null or a test-expr\n        if (MP_PARSE_NODE_IS_ID(pn_annotation)) {\n            qstr ret_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation);\n            switch (ret_type) {\n                case MP_QSTR_object:\n                    type_sig = MP_NATIVE_TYPE_OBJ;\n                    break;\n                case MP_QSTR_bool:\n                    type_sig = MP_NATIVE_TYPE_BOOL;\n                    break;\n                case MP_QSTR_int:\n                    type_sig = MP_NATIVE_TYPE_INT;\n                    break;\n                case MP_QSTR_uint:\n                    type_sig = MP_NATIVE_TYPE_UINT;\n                    break;\n                default:\n                    compile_syntax_error(comp, pn_annotation, MP_ERROR_TEXT(\"unknown type\"));\n                    return;\n            }\n        } else {\n            compile_syntax_error(comp, pn_annotation, MP_ERROR_TEXT(\"return annotation must be an identifier\"));\n        }\n    }\n\n    mp_parse_node_t pn_body = pns->nodes[3]; // body\n    mp_parse_node_t *nodes;\n    size_t num = mp_parse_node_extract_list(&pn_body, PN_suite_block_stmts, &nodes);\n\n    for (size_t i = 0; i < num; i++) {\n        assert(MP_PARSE_NODE_IS_STRUCT(nodes[i]));\n        mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)nodes[i];\n        if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_pass_stmt) {\n            // no instructions\n            continue;\n        } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_expr_stmt) {\n            // not an instruction; error\n        not_an_instruction:\n            compile_syntax_error(comp, nodes[i], MP_ERROR_TEXT(\"expecting an assembler instruction\"));\n            return;\n        }\n\n        // check structure of parse node\n        assert(MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0]));\n        if (!MP_PARSE_NODE_IS_NULL(pns2->nodes[1])) {\n            goto not_an_instruction;\n        }\n        pns2 = (mp_parse_node_struct_t *)pns2->nodes[0];\n        if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_atom_expr_normal) {\n            goto not_an_instruction;\n        }\n        if (!MP_PARSE_NODE_IS_ID(pns2->nodes[0])) {\n            goto not_an_instruction;\n        }\n        if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns2->nodes[1], PN_trailer_paren)) {\n            goto not_an_instruction;\n        }\n\n        // parse node looks like an instruction\n        // get instruction name and args\n        qstr op = MP_PARSE_NODE_LEAF_ARG(pns2->nodes[0]);\n        pns2 = (mp_parse_node_struct_t *)pns2->nodes[1]; // PN_trailer_paren\n        mp_parse_node_t *pn_arg;\n        size_t n_args = mp_parse_node_extract_list(&pns2->nodes[0], PN_arglist, &pn_arg);\n\n        // emit instructions\n        if (op == MP_QSTR_label) {\n            if (!(n_args == 1 && MP_PARSE_NODE_IS_ID(pn_arg[0]))) {\n                compile_syntax_error(comp, nodes[i], MP_ERROR_TEXT(\"'label' requires 1 argument\"));\n                return;\n            }\n            uint lab = comp_next_label(comp);\n            if (pass > MP_PASS_SCOPE) {\n                if (!EMIT_INLINE_ASM_ARG(label, lab, MP_PARSE_NODE_LEAF_ARG(pn_arg[0]))) {\n                    compile_syntax_error(comp, nodes[i], MP_ERROR_TEXT(\"label redefined\"));\n                    return;\n                }\n            }\n        } else if (op == MP_QSTR_align) {\n            if (!(n_args == 1 && MP_PARSE_NODE_IS_SMALL_INT(pn_arg[0]))) {\n                compile_syntax_error(comp, nodes[i], MP_ERROR_TEXT(\"'align' requires 1 argument\"));\n                return;\n            }\n            if (pass > MP_PASS_SCOPE) {\n                mp_asm_base_align((mp_asm_base_t *)comp->emit_inline_asm,\n                    MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]));\n            }\n        } else if (op == MP_QSTR_data) {\n            if (!(n_args >= 2 && MP_PARSE_NODE_IS_SMALL_INT(pn_arg[0]))) {\n                compile_syntax_error(comp, nodes[i], MP_ERROR_TEXT(\"'data' requires at least 2 arguments\"));\n                return;\n            }\n            if (pass > MP_PASS_SCOPE) {\n                mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);\n                for (uint j = 1; j < n_args; j++) {\n                    if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[j])) {\n                        compile_syntax_error(comp, nodes[i], MP_ERROR_TEXT(\"'data' requires integer arguments\"));\n                        return;\n                    }\n                    mp_asm_base_data((mp_asm_base_t *)comp->emit_inline_asm,\n                        bytesize, MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[j]));\n                }\n            }\n        } else {\n            if (pass > MP_PASS_SCOPE) {\n                EMIT_INLINE_ASM_ARG(op, op, n_args, pn_arg);\n            }\n        }\n\n        if (comp->compile_error != MP_OBJ_NULL) {\n            pns = pns2; // this is the parse node that had the error\n            goto inline_asm_error;\n        }\n    }\n\n    if (comp->pass > MP_PASS_SCOPE) {\n        EMIT_INLINE_ASM_ARG(end_pass, type_sig);\n\n        if (comp->pass == MP_PASS_EMIT) {\n            void *f = mp_asm_base_get_code((mp_asm_base_t *)comp->emit_inline_asm);\n            mp_emit_glue_assign_native(comp->scope_cur->raw_code, MP_CODE_NATIVE_ASM,\n                f, mp_asm_base_get_code_size((mp_asm_base_t *)comp->emit_inline_asm),\n                NULL,\n                #if MICROPY_PERSISTENT_CODE_SAVE\n                0, 0, 0, 0, NULL,\n                #endif\n                comp->scope_cur->num_pos_args, 0, type_sig);\n        }\n    }\n\n    if (comp->compile_error != MP_OBJ_NULL) {\n        // inline assembler had an error; set line for its exception\n    inline_asm_error:\n        comp->compile_error_line = pns->source_line;\n    }\n}\n#endif\n\nSTATIC void scope_compute_things(scope_t *scope) {\n    // in MicroPython we put the *x parameter after all other parameters (except **y)\n    if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {\n        id_info_t *id_param = NULL;\n        for (int i = scope->id_info_len - 1; i >= 0; i--) {\n            id_info_t *id = &scope->id_info[i];\n            if (id->flags & ID_FLAG_IS_STAR_PARAM) {\n                if (id_param != NULL) {\n                    // swap star param with last param\n                    id_info_t temp = *id_param;\n                    *id_param = *id;\n                    *id = temp;\n                }\n                break;\n            } else if (id_param == NULL && id->flags == ID_FLAG_IS_PARAM) {\n                id_param = id;\n            }\n        }\n    }\n\n    // in functions, turn implicit globals into explicit globals\n    // compute the index of each local\n    scope->num_locals = 0;\n    for (int i = 0; i < scope->id_info_len; i++) {\n        id_info_t *id = &scope->id_info[i];\n        if (scope->kind == SCOPE_CLASS && id->qst == MP_QSTR___class__) {\n            // __class__ is not counted as a local; if it's used then it becomes a ID_INFO_KIND_CELL\n            continue;\n        }\n        if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {\n            id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;\n        }\n        #if MICROPY_EMIT_NATIVE\n        if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {\n            // This function makes a reference to a global variable\n            if (scope->emit_options == MP_EMIT_OPT_VIPER\n                && mp_native_type_from_qstr(id->qst) >= MP_NATIVE_TYPE_INT) {\n                // A casting operator in viper mode, not a real global reference\n            } else {\n                scope->scope_flags |= MP_SCOPE_FLAG_REFGLOBALS;\n            }\n        }\n        #endif\n        // params always count for 1 local, even if they are a cell\n        if (id->kind == ID_INFO_KIND_LOCAL || (id->flags & ID_FLAG_IS_PARAM)) {\n            id->local_num = scope->num_locals++;\n        }\n    }\n\n    // compute the index of cell vars\n    for (int i = 0; i < scope->id_info_len; i++) {\n        id_info_t *id = &scope->id_info[i];\n        // in MicroPython the cells come right after the fast locals\n        // parameters are not counted here, since they remain at the start\n        // of the locals, even if they are cell vars\n        if (id->kind == ID_INFO_KIND_CELL && !(id->flags & ID_FLAG_IS_PARAM)) {\n            id->local_num = scope->num_locals;\n            scope->num_locals += 1;\n        }\n    }\n\n    // compute the index of free vars\n    // make sure they are in the order of the parent scope\n    if (scope->parent != NULL) {\n        int num_free = 0;\n        for (int i = 0; i < scope->parent->id_info_len; i++) {\n            id_info_t *id = &scope->parent->id_info[i];\n            if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {\n                for (int j = 0; j < scope->id_info_len; j++) {\n                    id_info_t *id2 = &scope->id_info[j];\n                    if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) {\n                        assert(!(id2->flags & ID_FLAG_IS_PARAM)); // free vars should not be params\n                        // in MicroPython the frees come first, before the params\n                        id2->local_num = num_free;\n                        num_free += 1;\n                    }\n                }\n            }\n        }\n        // in MicroPython shift all other locals after the free locals\n        if (num_free > 0) {\n            for (int i = 0; i < scope->id_info_len; i++) {\n                id_info_t *id = &scope->id_info[i];\n                if (id->kind != ID_INFO_KIND_FREE || (id->flags & ID_FLAG_IS_PARAM)) {\n                    id->local_num += num_free;\n                }\n            }\n            scope->num_pos_args += num_free; // free vars are counted as params for passing them into the function\n            scope->num_locals += num_free;\n        }\n    }\n}\n\n#if !MICROPY_PERSISTENT_CODE_SAVE\nSTATIC\n#endif\nmp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) {\n    // put compiler state on the stack, it's relatively small\n    compiler_t comp_state = {0};\n    compiler_t *comp = &comp_state;\n\n    comp->source_file = source_file;\n    comp->is_repl = is_repl;\n    comp->break_label = INVALID_LABEL;\n    comp->continue_label = INVALID_LABEL;\n\n    // create the module scope\n    #if MICROPY_EMIT_NATIVE\n    const uint emit_opt = MP_STATE_VM(default_emit_opt);\n    #else\n    const uint emit_opt = MP_EMIT_OPT_NONE;\n    #endif\n    scope_t *module_scope = scope_new_and_link(comp, SCOPE_MODULE, parse_tree->root, emit_opt);\n\n    // create standard emitter; it's used at least for MP_PASS_SCOPE\n    emit_t *emit_bc = emit_bc_new();\n\n    // compile pass 1\n    comp->emit = emit_bc;\n    #if MICROPY_EMIT_NATIVE\n    comp->emit_method_table = &emit_bc_method_table;\n    #endif\n    uint max_num_labels = 0;\n    for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {\n        #if MICROPY_EMIT_INLINE_ASM\n        if (s->emit_options == MP_EMIT_OPT_ASM) {\n            compile_scope_inline_asm(comp, s, MP_PASS_SCOPE);\n        } else\n        #endif\n        {\n            compile_scope(comp, s, MP_PASS_SCOPE);\n\n            // Check if any implicitly declared variables should be closed over\n            for (size_t i = 0; i < s->id_info_len; ++i) {\n                id_info_t *id = &s->id_info[i];\n                if (id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {\n                    scope_check_to_close_over(s, id);\n                }\n            }\n        }\n\n        // update maximim number of labels needed\n        if (comp->next_label > max_num_labels) {\n            max_num_labels = comp->next_label;\n        }\n    }\n\n    // compute some things related to scope and identifiers\n    for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {\n        scope_compute_things(s);\n    }\n\n    // set max number of labels now that it's calculated\n    emit_bc_set_max_num_labels(emit_bc, max_num_labels);\n\n    // compile pass 2 and 3\n    #if MICROPY_EMIT_NATIVE\n    emit_t *emit_native = NULL;\n    #endif\n    for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {\n        #if MICROPY_EMIT_INLINE_ASM\n        if (s->emit_options == MP_EMIT_OPT_ASM) {\n            // inline assembly\n            if (comp->emit_inline_asm == NULL) {\n                comp->emit_inline_asm = ASM_EMITTER(new)(max_num_labels);\n            }\n            comp->emit = NULL;\n            comp->emit_inline_asm_method_table = ASM_EMITTER_TABLE;\n            compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE);\n            #if MICROPY_EMIT_INLINE_XTENSA\n            // Xtensa requires an extra pass to compute size of l32r const table\n            // TODO this can be improved by calculating it during SCOPE pass\n            // but that requires some other structural changes to the asm emitters\n            #if MICROPY_DYNAMIC_COMPILER\n            if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSA)\n            #endif\n            {\n                compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE);\n            }\n            #endif\n            if (comp->compile_error == MP_OBJ_NULL) {\n                compile_scope_inline_asm(comp, s, MP_PASS_EMIT);\n            }\n        } else\n        #endif\n        {\n\n            // choose the emit type\n\n            switch (s->emit_options) {\n\n                #if MICROPY_EMIT_NATIVE\n                case MP_EMIT_OPT_NATIVE_PYTHON:\n                case MP_EMIT_OPT_VIPER:\n                    if (emit_native == NULL) {\n                        emit_native = NATIVE_EMITTER(new)(&comp->compile_error, &comp->next_label, max_num_labels);\n                    }\n                    comp->emit_method_table = NATIVE_EMITTER_TABLE;\n                    comp->emit = emit_native;\n                    break;\n                #endif // MICROPY_EMIT_NATIVE\n\n                default:\n                    comp->emit = emit_bc;\n                    #if MICROPY_EMIT_NATIVE\n                    comp->emit_method_table = &emit_bc_method_table;\n                    #endif\n                    break;\n            }\n\n            // need a pass to compute stack size\n            compile_scope(comp, s, MP_PASS_STACK_SIZE);\n\n            // second last pass: compute code size\n            if (comp->compile_error == MP_OBJ_NULL) {\n                compile_scope(comp, s, MP_PASS_CODE_SIZE);\n            }\n\n            // final pass: emit code\n            if (comp->compile_error == MP_OBJ_NULL) {\n                compile_scope(comp, s, MP_PASS_EMIT);\n            }\n        }\n    }\n\n    if (comp->compile_error != MP_OBJ_NULL) {\n        // if there is no line number for the error then use the line\n        // number for the start of this scope\n        compile_error_set_line(comp, comp->scope_cur->pn);\n        // add a traceback to the exception using relevant source info\n        mp_obj_exception_add_traceback(comp->compile_error, comp->source_file,\n            comp->compile_error_line, comp->scope_cur->simple_name);\n    }\n\n    // free the emitters\n\n    emit_bc_free(emit_bc);\n    #if MICROPY_EMIT_NATIVE\n    if (emit_native != NULL) {\n        NATIVE_EMITTER(free)(emit_native);\n    }\n    #endif\n    #if MICROPY_EMIT_INLINE_ASM\n    if (comp->emit_inline_asm != NULL) {\n        ASM_EMITTER(free)(comp->emit_inline_asm);\n    }\n    #endif\n\n    // free the parse tree\n    mp_parse_tree_clear(parse_tree);\n\n    // free the scopes\n    mp_raw_code_t *outer_raw_code = module_scope->raw_code;\n    for (scope_t *s = module_scope; s;) {\n        scope_t *next = s->next;\n        scope_free(s);\n        s = next;\n    }\n\n    if (comp->compile_error != MP_OBJ_NULL) {\n        nlr_raise(comp->compile_error);\n    } else {\n        return outer_raw_code;\n    }\n}\n\nmp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) {\n    mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, is_repl);\n    // return function that executes the outer module\n    return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL);\n}\n\n#endif // MICROPY_ENABLE_COMPILER\n"
  },
  {
    "path": "py/compile.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_COMPILE_H\n#define MICROPY_INCLUDED_PY_COMPILE_H\n\n#include \"py/lexer.h\"\n#include \"py/parse.h\"\n#include \"py/emitglue.h\"\n\n// the compiler will raise an exception if an error occurred\n// the compiler will clear the parse tree before it returns\nmp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl);\n\n#if MICROPY_PERSISTENT_CODE_SAVE\n// this has the same semantics as mp_compile\nmp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl);\n#endif\n\n// this is implemented in runtime.c\nmp_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);\n\n#endif // MICROPY_INCLUDED_PY_COMPILE_H\n"
  },
  {
    "path": "py/dynruntime.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_DYNRUNTIME_H\n#define MICROPY_INCLUDED_PY_DYNRUNTIME_H\n\n// This header file contains definitions to dynamically implement the static\n// MicroPython runtime API defined in py/obj.h and py/runtime.h.\n\n#include \"py/nativeglue.h\"\n#include \"py/objstr.h\"\n#include \"py/objtype.h\"\n\n#if !MICROPY_ENABLE_DYNRUNTIME\n#error \"dynruntime.h included in non-dynamic-module build.\"\n#endif\n\n#undef MP_ROM_QSTR\n#undef MP_OBJ_QSTR_VALUE\n#undef MP_OBJ_NEW_QSTR\n#undef mp_const_none\n#undef mp_const_false\n#undef mp_const_true\n#undef mp_const_empty_tuple\n#undef nlr_raise\n\n/******************************************************************************/\n// Memory allocation\n\n#define m_malloc(n)                     (m_malloc_dyn((n)))\n#define m_free(ptr)                     (m_free_dyn((ptr)))\n#define m_realloc(ptr, new_num_bytes)   (m_realloc_dyn((ptr), (new_num_bytes)))\n\nstatic inline void *m_malloc_dyn(size_t n) {\n    // TODO won't raise on OOM\n    return mp_fun_table.realloc_(NULL, n, false);\n}\n\nstatic inline void m_free_dyn(void *ptr) {\n    mp_fun_table.realloc_(ptr, 0, false);\n}\n\nstatic inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {\n    // TODO won't raise on OOM\n    return mp_fun_table.realloc_(ptr, new_num_bytes, true);\n}\n\n/******************************************************************************/\n// Printing\n\n#define mp_plat_print               (*mp_fun_table.plat_print)\n#define mp_printf(p, ...)           (mp_fun_table.printf_((p), __VA_ARGS__))\n#define mp_vprintf(p, fmt, args)    (mp_fun_table.vprintf_((p), (fmt), (args)))\n\n/******************************************************************************/\n// Types and objects\n\n#define MP_OBJ_NEW_QSTR(x) MP_OBJ_NEW_QSTR_##x\n\n#define mp_type_type                        (*mp_fun_table.type_type)\n#define mp_type_str                         (*mp_fun_table.type_str)\n#define mp_type_list                        (*mp_fun_table.type_list)\n#define mp_type_EOFError                    (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_EOFError)))\n#define mp_type_IndexError                  (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_IndexError)))\n#define mp_type_KeyError                    (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_KeyError)))\n#define mp_type_NotImplementedError         (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_NotImplementedError)))\n#define mp_type_RuntimeError                (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_RuntimeError)))\n#define mp_type_TypeError                   (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_TypeError)))\n#define mp_type_ValueError                  (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_ValueError)))\n\n#define mp_stream_read_obj                  (*mp_fun_table.stream_read_obj)\n#define mp_stream_readinto_obj              (*mp_fun_table.stream_readinto_obj)\n#define mp_stream_unbuffered_readline_obj   (*mp_fun_table.stream_unbuffered_readline_obj)\n#define mp_stream_write_obj                 (*mp_fun_table.stream_write_obj)\n\n#define mp_const_none                       ((mp_obj_t)mp_fun_table.const_none)\n#define mp_const_false                      ((mp_obj_t)mp_fun_table.const_false)\n#define mp_const_true                       ((mp_obj_t)mp_fun_table.const_true)\n#define mp_const_empty_tuple                (mp_fun_table.new_tuple(0, NULL))\n\n#define mp_obj_new_bool(b)                  ((b) ? (mp_obj_t)mp_fun_table.const_true : (mp_obj_t)mp_fun_table.const_false)\n#define mp_obj_new_int(i)                   (mp_fun_table.native_to_obj(i, MP_NATIVE_TYPE_INT))\n#define mp_obj_new_int_from_uint(i)         (mp_fun_table.native_to_obj(i, MP_NATIVE_TYPE_UINT))\n#define mp_obj_new_str(data, len)           (mp_fun_table.obj_new_str((data), (len)))\n#define mp_obj_new_str_of_type(t, d, l)     (mp_obj_new_str_of_type_dyn((t), (d), (l)))\n#define mp_obj_new_bytes(data, len)         (mp_fun_table.obj_new_bytes((data), (len)))\n#define mp_obj_new_bytearray_by_ref(n, i)   (mp_fun_table.obj_new_bytearray_by_ref((n), (i)))\n#define mp_obj_new_tuple(n, items)          (mp_fun_table.new_tuple((n), (items)))\n#define mp_obj_new_list(n, items)           (mp_fun_table.new_list((n), (items)))\n\n#define mp_obj_get_type(o)                  (mp_fun_table.obj_get_type((o)))\n#define mp_obj_cast_to_native_base(o, t)    (mp_obj_cast_to_native_base_dyn((o), (t)))\n#define mp_obj_get_int(o)                   (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_INT))\n#define mp_obj_get_int_truncated(o)         (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_UINT))\n#define mp_obj_str_get_str(s)               (mp_obj_str_get_data_dyn((s), NULL))\n#define mp_obj_str_get_data(o, len)         (mp_obj_str_get_data_dyn((o), (len)))\n#define mp_get_buffer_raise(o, bufinfo, fl) (mp_fun_table.get_buffer_raise((o), (bufinfo), (fl)))\n#define mp_get_stream_raise(s, flags)       (mp_fun_table.get_stream_raise((s), (flags)))\n\n#define mp_obj_len(o)                       (mp_obj_len_dyn(o))\n#define mp_obj_subscr(base, index, val)     (mp_fun_table.obj_subscr((base), (index), (val)))\n#define mp_obj_list_append(list, item)      (mp_fun_table.list_append((list), (item)))\n\nstatic inline mp_obj_t mp_obj_new_str_of_type_dyn(const mp_obj_type_t *type, const byte *data, size_t len) {\n    if (type == &mp_type_str) {\n        return mp_obj_new_str((const char *)data, len);\n    } else {\n        return mp_obj_new_bytes(data, len);\n    }\n}\n\nstatic inline mp_obj_t mp_obj_cast_to_native_base_dyn(mp_obj_t self_in, mp_const_obj_t native_type) {\n    const mp_obj_type_t *self_type = mp_obj_get_type(self_in);\n\n    if (MP_OBJ_FROM_PTR(self_type) == native_type) {\n        return self_in;\n    } else if (self_type->parent != native_type) {\n        // The self_in object is not a direct descendant of native_type, so fail the cast.\n        // This is a very simple version of mp_obj_is_subclass_fast that could be improved.\n        return MP_OBJ_NULL;\n    } else {\n        mp_obj_instance_t *self = (mp_obj_instance_t *)MP_OBJ_TO_PTR(self_in);\n        return self->subobj[0];\n    }\n}\n\nstatic inline void *mp_obj_str_get_data_dyn(mp_obj_t o, size_t *l) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(o, &bufinfo, MP_BUFFER_READ);\n    if (l != NULL) {\n        *l = bufinfo.len;\n    }\n    return bufinfo.buf;\n}\n\nstatic inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {\n    // If bytes implemented MP_UNARY_OP_LEN could use: mp_unary_op(MP_UNARY_OP_LEN, o)\n    return mp_fun_table.call_function_n_kw(mp_fun_table.load_name(MP_QSTR_len), 1, &o);\n}\n\n/******************************************************************************/\n// General runtime functions\n\n#define mp_load_name(qst)                 (mp_fun_table.load_name((qst)))\n#define mp_load_global(qst)               (mp_fun_table.load_global((qst)))\n#define mp_load_attr(base, attr)          (mp_fun_table.load_attr((base), (attr)))\n#define mp_load_method(base, attr, dest)  (mp_fun_table.load_method((base), (attr), (dest)))\n#define mp_load_super_method(attr, dest)  (mp_fun_table.load_super_method((attr), (dest)))\n#define mp_store_name(qst, obj)           (mp_fun_table.store_name((qst), (obj)))\n#define mp_store_global(qst, obj)         (mp_fun_table.store_global((qst), (obj)))\n#define mp_store_attr(base, attr, val)    (mp_fun_table.store_attr((base), (attr), (val)))\n\n#define mp_unary_op(op, obj)        (mp_fun_table.unary_op((op), (obj)))\n#define mp_binary_op(op, lhs, rhs)  (mp_fun_table.binary_op((op), (lhs), (rhs)))\n\n#define mp_make_function_from_raw_code(rc, def_args, def_kw_args) \\\n    (mp_fun_table.make_function_from_raw_code((rc), (def_args), (def_kw_args)))\n\n#define mp_call_function_n_kw(fun, n_args, n_kw, args) \\\n    (mp_fun_table.call_function_n_kw((fun), (n_args) | ((n_kw) << 8), args))\n\n#define mp_arg_check_num(n_args, n_kw, n_args_min, n_args_max, takes_kw) \\\n    (mp_fun_table.arg_check_num_sig((n_args), (n_kw), MP_OBJ_FUN_MAKE_SIG((n_args_min), (n_args_max), (takes_kw))))\n\n#define MP_DYNRUNTIME_INIT_ENTRY \\\n    mp_obj_t old_globals = mp_fun_table.swap_globals(self->globals); \\\n    mp_raw_code_t rc; \\\n    rc.kind = MP_CODE_NATIVE_VIPER; \\\n    rc.scope_flags = 0; \\\n    rc.const_table = (void *)self->const_table; \\\n    (void)rc;\n\n#define MP_DYNRUNTIME_INIT_EXIT \\\n    mp_fun_table.swap_globals(old_globals); \\\n    return mp_const_none;\n\n#define MP_DYNRUNTIME_MAKE_FUNCTION(f) \\\n    (mp_make_function_from_raw_code((rc.fun_data = (f), &rc), MP_OBJ_NULL, MP_OBJ_NULL))\n\n#define mp_import_name(name, fromlist, level) \\\n    (mp_fun_table.import_name((name), (fromlist), (level)))\n#define mp_import_from(module, name) \\\n    (mp_fun_table.import_from((module), (name)))\n#define mp_import_all(module) \\\n    (mp_fun_table.import_all((module))\n\n/******************************************************************************/\n// Exceptions\n\n#define mp_obj_new_exception(o)                 ((mp_obj_t)(o)) // Assumes returned object will be raised, will create instance then\n#define mp_obj_new_exception_arg1(e_type, arg)  (mp_obj_new_exception_arg1_dyn((e_type), (arg)))\n\n#define nlr_raise(o)                            (mp_raise_dyn(o))\n#define mp_raise_msg(type, msg)                 (mp_fun_table.raise_msg((type), (msg)))\n#define mp_raise_OSError(er)                    (mp_raise_OSError_dyn(er))\n#define mp_raise_NotImplementedError(msg)       (mp_raise_msg(&mp_type_NotImplementedError, (msg)))\n#define mp_raise_TypeError(msg)                 (mp_raise_msg(&mp_type_TypeError, (msg)))\n#define mp_raise_ValueError(msg)                (mp_raise_msg(&mp_type_ValueError, (msg)))\n\nstatic inline mp_obj_t mp_obj_new_exception_arg1_dyn(const mp_obj_type_t *exc_type, mp_obj_t arg) {\n    mp_obj_t args[1] = { arg };\n    return mp_call_function_n_kw(MP_OBJ_FROM_PTR(exc_type), 1, 0, &args[0]);\n}\n\nstatic NORETURN inline void mp_raise_dyn(mp_obj_t o) {\n    mp_fun_table.raise(o);\n    for (;;) {\n    }\n}\n\nstatic inline void mp_raise_OSError_dyn(int er) {\n    mp_obj_t args[1] = { MP_OBJ_NEW_SMALL_INT(er) };\n    nlr_raise(mp_call_function_n_kw(mp_load_global(MP_QSTR_OSError), 1, 0, &args[0]));\n}\n\n/******************************************************************************/\n// Floating point\n\n#define mp_obj_new_float_from_f(f)  (mp_fun_table.obj_new_float_from_f((f)))\n#define mp_obj_new_float_from_d(d)  (mp_fun_table.obj_new_float_from_d((d)))\n#define mp_obj_get_float_to_f(o)    (mp_fun_table.obj_get_float_to_f((o)))\n#define mp_obj_get_float_to_d(o)    (mp_fun_table.obj_get_float_to_d((o)))\n\n#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n#define mp_obj_new_float(f)         (mp_obj_new_float_from_f((f)))\n#define mp_obj_get_float(o)         (mp_obj_get_float_to_f((o)))\n#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE\n#define mp_obj_new_float(f)         (mp_obj_new_float_from_d((f)))\n#define mp_obj_get_float(o)         (mp_obj_get_float_to_d((o)))\n#endif\n\n#endif // MICROPY_INCLUDED_PY_DYNRUNTIME_H\n"
  },
  {
    "path": "py/dynruntime.mk",
    "content": "# Makefile fragment for generating native .mpy files from C source\n# MPY_DIR must be set to the top of the MicroPython source tree\n\nBUILD ?= build\n\nECHO = @echo\nRM = /bin/rm\nMKDIR = /bin/mkdir\nPYTHON = python3\nMPY_CROSS = $(MPY_DIR)/mpy-cross/mpy-cross\nMPY_TOOL = $(PYTHON) $(MPY_DIR)/tools/mpy-tool.py\nMPY_LD = $(PYTHON) $(MPY_DIR)/tools/mpy_ld.py\n\nQ = @\nifeq (\"$(origin V)\", \"command line\")\nifeq ($(V),1)\nQ =\nMPY_LD += '-vvv'\nendif\nendif\n\nARCH_UPPER = $(shell echo $(ARCH) | tr '[:lower:]' '[:upper:]')\nCONFIG_H = $(BUILD)/$(MOD).config.h\n\nCFLAGS += -I. -I$(MPY_DIR)\nCFLAGS += -std=c99\nCFLAGS += -Os\nCFLAGS += -Wall -Werror -DNDEBUG\nCFLAGS += -DNO_QSTR\nCFLAGS += -DMICROPY_ENABLE_DYNRUNTIME\nCFLAGS += -DMP_CONFIGFILE='<$(CONFIG_H)>'\nCFLAGS += -fpic -fno-common\nCFLAGS += -U _FORTIFY_SOURCE # prevent use of __*_chk libc functions\n#CFLAGS += -fdata-sections -ffunction-sections\n\nMPY_CROSS_FLAGS += -march=$(ARCH)\n\nSRC_O += $(addprefix $(BUILD)/, $(patsubst %.c,%.o,$(filter %.c,$(SRC))))\nSRC_MPY += $(addprefix $(BUILD)/, $(patsubst %.py,%.mpy,$(filter %.py,$(SRC))))\n\n################################################################################\n# Architecture configuration\n\nifeq ($(ARCH),x86)\n\n# x86\nCROSS =\nCFLAGS += -m32 -fno-stack-protector\nMPY_CROSS_FLAGS += -mcache-lookup-bc\nMICROPY_FLOAT_IMPL ?= double\n\nelse ifeq ($(ARCH),x64)\n\n# x64\nCROSS =\nCFLAGS += -fno-stack-protector\nMPY_CROSS_FLAGS += -mcache-lookup-bc\nMICROPY_FLOAT_IMPL ?= double\n\nelse ifeq ($(ARCH),armv7m)\n\n# thumb\nCROSS = arm-none-eabi-\nCFLAGS += -mthumb -mcpu=cortex-m3\nMICROPY_FLOAT_IMPL ?= none\n\nelse ifeq ($(ARCH),armv7emsp)\n\n# thumb\nCROSS = arm-none-eabi-\nCFLAGS += -mthumb -mcpu=cortex-m4\nCFLAGS += -mfpu=fpv4-sp-d16 -mfloat-abi=hard\nMICROPY_FLOAT_IMPL ?= float\n\nelse ifeq ($(ARCH),armv7emdp)\n\n# thumb\nCROSS = arm-none-eabi-\nCFLAGS += -mthumb -mcpu=cortex-m7\nCFLAGS += -mfpu=fpv5-d16 -mfloat-abi=hard\nMICROPY_FLOAT_IMPL ?= double\n\nelse ifeq ($(ARCH),xtensa)\n\n# xtensa\nCROSS = xtensa-lx106-elf-\nCFLAGS += -mforce-l32\nMICROPY_FLOAT_IMPL ?= none\n\nelse ifeq ($(ARCH),xtensawin)\n\n# xtensawin\nCROSS = xtensa-esp32-elf-\nCFLAGS +=\nMICROPY_FLOAT_IMPL ?= float\n\nelse\n$(error architecture '$(ARCH)' not supported)\nendif\n\nMICROPY_FLOAT_IMPL_UPPER = $(shell echo $(MICROPY_FLOAT_IMPL) | tr '[:lower:]' '[:upper:]')\nCFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_$(MICROPY_FLOAT_IMPL_UPPER)\n\nCFLAGS += $(CFLAGS_EXTRA)\n\n################################################################################\n# Build rules\n\n.PHONY: all clean\n\nall: $(MOD).mpy\n\nclean:\n\t$(RM) -rf $(BUILD) $(CLEAN_EXTRA)\n\n# Create build destination directories first\nBUILD_DIRS = $(sort $(dir $(CONFIG_H) $(SRC_O) $(SRC_MPY)))\n$(CONFIG_H) $(SRC_O) $(SRC_MPY): | $(BUILD_DIRS)\n$(BUILD_DIRS):\n\t$(Q)$(MKDIR) -p $@\n\n# Preprocess all source files to generate $(CONFIG_H)\n$(CONFIG_H): $(SRC)\n\t$(ECHO) \"GEN $@\"\n\t$(Q)$(MPY_LD) --arch $(ARCH) --preprocess -o $@ $^\n\n# Build .o from .c source files\n$(BUILD)/%.o: %.c $(CONFIG_H) Makefile\n\t$(ECHO) \"CC $<\"\n\t$(Q)$(CROSS)gcc $(CFLAGS) -o $@ -c $<\n\n# Build .mpy from .py source files\n$(BUILD)/%.mpy: %.py\n\t$(ECHO) \"MPY $<\"\n\t$(Q)$(MPY_CROSS) $(MPY_CROSS_FLAGS) -o $@ $<\n\n# Build native .mpy from object files\n$(BUILD)/$(MOD).native.mpy: $(SRC_O)\n\t$(ECHO) \"LINK $<\"\n\t$(Q)$(MPY_LD) --arch $(ARCH) --qstrs $(CONFIG_H) -o $@ $^\n\n# Build final .mpy from all intermediate .mpy files\n$(MOD).mpy: $(BUILD)/$(MOD).native.mpy $(SRC_MPY)\n\t$(ECHO) \"GEN $@\"\n\t$(Q)$(MPY_TOOL) --merge -o $@ $^\n"
  },
  {
    "path": "py/emit.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_EMIT_H\n#define MICROPY_INCLUDED_PY_EMIT_H\n\n#include \"py/lexer.h\"\n#include \"py/scope.h\"\n\n/* Notes on passes:\n * We don't know exactly the opcodes in pass 1 because they depend on the\n * closing over of variables (LOAD_CLOSURE, BUILD_TUPLE, MAKE_CLOSURE), which\n * depends on determining the scope of variables in each function, and this\n * is not known until the end of pass 1.\n * As a consequence, we don't know the maximum stack size until the end of pass 2.\n * This is problematic for some emitters (x64) since they need to know the maximum\n * stack size to compile the entry to the function, and this affects code size.\n */\n\ntypedef enum {\n    MP_PASS_SCOPE = 1,      // work out id's and their kind, and number of labels\n    MP_PASS_STACK_SIZE = 2, // work out maximum stack size\n    MP_PASS_CODE_SIZE = 3,  // work out code size and label offsets\n    MP_PASS_EMIT = 4,       // emit code\n} pass_kind_t;\n\n#define MP_EMIT_STAR_FLAG_SINGLE (0x01)\n#define MP_EMIT_STAR_FLAG_DOUBLE (0x02)\n\n#define MP_EMIT_BREAK_FROM_FOR (0x8000)\n\n// Kind for emit_id_ops->local()\n#define MP_EMIT_IDOP_LOCAL_FAST (0)\n#define MP_EMIT_IDOP_LOCAL_DEREF (1)\n\n// Kind for emit_id_ops->global()\n#define MP_EMIT_IDOP_GLOBAL_NAME (0)\n#define MP_EMIT_IDOP_GLOBAL_GLOBAL (1)\n\n// Kind for emit->import()\n#define MP_EMIT_IMPORT_NAME (0)\n#define MP_EMIT_IMPORT_FROM (1)\n#define MP_EMIT_IMPORT_STAR (2)\n\n// Kind for emit->subscr()\n#define MP_EMIT_SUBSCR_LOAD (0)\n#define MP_EMIT_SUBSCR_STORE (1)\n#define MP_EMIT_SUBSCR_DELETE (2)\n\n// Kind for emit->attr()\n#define MP_EMIT_ATTR_LOAD (0)\n#define MP_EMIT_ATTR_STORE (1)\n#define MP_EMIT_ATTR_DELETE (2)\n\n// Kind for emit->setup_block()\n#define MP_EMIT_SETUP_BLOCK_WITH (0)\n#define MP_EMIT_SETUP_BLOCK_EXCEPT (1)\n#define MP_EMIT_SETUP_BLOCK_FINALLY (2)\n\n// Kind for emit->build()\n#define MP_EMIT_BUILD_TUPLE (0)\n#define MP_EMIT_BUILD_LIST (1)\n#define MP_EMIT_BUILD_MAP (2)\n#define MP_EMIT_BUILD_SET (3)\n#define MP_EMIT_BUILD_SLICE (4)\n\n// Kind for emit->yield()\n#define MP_EMIT_YIELD_VALUE (0)\n#define MP_EMIT_YIELD_FROM (1)\n\ntypedef struct _emit_t emit_t;\n\ntypedef struct _mp_emit_method_table_id_ops_t {\n    void (*local)(emit_t *emit, qstr qst, mp_uint_t local_num, int kind);\n    void (*global)(emit_t *emit, qstr qst, int kind);\n} mp_emit_method_table_id_ops_t;\n\ntypedef struct _emit_method_table_t {\n    #if MICROPY_DYNAMIC_COMPILER\n    emit_t *(*emit_new)(mp_obj_t * error_slot, uint *label_slot, mp_uint_t max_num_labels);\n    void (*emit_free)(emit_t *emit);\n    #endif\n\n    void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope);\n    void (*end_pass)(emit_t *emit);\n    bool (*last_emit_was_return_value)(emit_t *emit);\n    void (*adjust_stack_size)(emit_t *emit, mp_int_t delta);\n    void (*set_source_line)(emit_t *emit, mp_uint_t line);\n\n    mp_emit_method_table_id_ops_t load_id;\n    mp_emit_method_table_id_ops_t store_id;\n    mp_emit_method_table_id_ops_t delete_id;\n\n    void (*label_assign)(emit_t *emit, mp_uint_t l);\n    void (*import)(emit_t *emit, qstr qst, int kind);\n    void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok);\n    void (*load_const_small_int)(emit_t *emit, mp_int_t arg);\n    void (*load_const_str)(emit_t *emit, qstr qst);\n    void (*load_const_obj)(emit_t *emit, mp_obj_t obj);\n    void (*load_null)(emit_t *emit);\n    void (*load_method)(emit_t *emit, qstr qst, bool is_super);\n    void (*load_build_class)(emit_t *emit);\n    void (*subscr)(emit_t *emit, int kind);\n    void (*attr)(emit_t *emit, qstr qst, int kind);\n    void (*dup_top)(emit_t *emit);\n    void (*dup_top_two)(emit_t *emit);\n    void (*pop_top)(emit_t *emit);\n    void (*rot_two)(emit_t *emit);\n    void (*rot_three)(emit_t *emit);\n    void (*jump)(emit_t *emit, mp_uint_t label);\n    void (*pop_jump_if)(emit_t *emit, bool cond, mp_uint_t label);\n    void (*jump_if_or_pop)(emit_t *emit, bool cond, mp_uint_t label);\n    void (*unwind_jump)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth);\n    void (*setup_block)(emit_t *emit, mp_uint_t label, int kind);\n    void (*with_cleanup)(emit_t *emit, mp_uint_t label);\n    void (*end_finally)(emit_t *emit);\n    void (*get_iter)(emit_t *emit, bool use_stack);\n    void (*for_iter)(emit_t *emit, mp_uint_t label);\n    void (*for_iter_end)(emit_t *emit);\n    void (*pop_except_jump)(emit_t *emit, mp_uint_t label, bool within_exc_handler);\n    void (*unary_op)(emit_t *emit, mp_unary_op_t op);\n    void (*binary_op)(emit_t *emit, mp_binary_op_t op);\n    void (*build)(emit_t *emit, mp_uint_t n_args, int kind);\n    void (*store_map)(emit_t *emit);\n    void (*store_comp)(emit_t *emit, scope_kind_t kind, mp_uint_t set_stack_index);\n    void (*unpack_sequence)(emit_t *emit, mp_uint_t n_args);\n    void (*unpack_ex)(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right);\n    void (*make_function)(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults);\n    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);\n    void (*call_function)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags);\n    void (*call_method)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags);\n    void (*return_value)(emit_t *emit);\n    void (*raise_varargs)(emit_t *emit, mp_uint_t n_args);\n    void (*yield)(emit_t *emit, int kind);\n\n    // these methods are used to control entry to/exit from an exception handler\n    // they may or may not emit code\n    void (*start_except_handler)(emit_t *emit);\n    void (*end_except_handler)(emit_t *emit);\n} emit_method_table_t;\n\nstatic inline void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) {\n    scope_find_or_add_id(scope, qst, ID_INFO_KIND_GLOBAL_IMPLICIT);\n}\n\nvoid mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst);\nvoid mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emit_method_table, scope_t *scope, qstr qst);\n\nextern const emit_method_table_t emit_bc_method_table;\nextern const emit_method_table_t emit_native_x64_method_table;\nextern const emit_method_table_t emit_native_x86_method_table;\nextern const emit_method_table_t emit_native_thumb_method_table;\nextern const emit_method_table_t emit_native_arm_method_table;\nextern const emit_method_table_t emit_native_xtensa_method_table;\nextern const emit_method_table_t emit_native_xtensawin_method_table;\n\nextern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops;\nextern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops;\nextern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops;\n\nemit_t *emit_bc_new(void);\nemit_t *emit_native_x64_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);\nemit_t *emit_native_x86_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);\nemit_t *emit_native_thumb_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);\nemit_t *emit_native_arm_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);\nemit_t *emit_native_xtensa_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);\nemit_t *emit_native_xtensawin_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);\n\nvoid emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels);\n\nvoid emit_bc_free(emit_t *emit);\nvoid emit_native_x64_free(emit_t *emit);\nvoid emit_native_x86_free(emit_t *emit);\nvoid emit_native_thumb_free(emit_t *emit);\nvoid emit_native_arm_free(emit_t *emit);\nvoid emit_native_xtensa_free(emit_t *emit);\nvoid emit_native_xtensawin_free(emit_t *emit);\n\nvoid mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope);\nvoid mp_emit_bc_end_pass(emit_t *emit);\nbool mp_emit_bc_last_emit_was_return_value(emit_t *emit);\nvoid mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta);\nvoid mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t line);\n\nvoid mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind);\nvoid mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind);\nvoid mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind);\nvoid mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind);\nvoid mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind);\nvoid mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind);\n\nvoid mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l);\nvoid mp_emit_bc_import(emit_t *emit, qstr qst, int kind);\nvoid mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok);\nvoid mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg);\nvoid mp_emit_bc_load_const_str(emit_t *emit, qstr qst);\nvoid mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj);\nvoid mp_emit_bc_load_null(emit_t *emit);\nvoid mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super);\nvoid mp_emit_bc_load_build_class(emit_t *emit);\nvoid mp_emit_bc_subscr(emit_t *emit, int kind);\nvoid mp_emit_bc_attr(emit_t *emit, qstr qst, int kind);\nvoid mp_emit_bc_dup_top(emit_t *emit);\nvoid mp_emit_bc_dup_top_two(emit_t *emit);\nvoid mp_emit_bc_pop_top(emit_t *emit);\nvoid mp_emit_bc_rot_two(emit_t *emit);\nvoid mp_emit_bc_rot_three(emit_t *emit);\nvoid mp_emit_bc_jump(emit_t *emit, mp_uint_t label);\nvoid mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label);\nvoid mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label);\nvoid mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth);\nvoid mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind);\nvoid mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label);\nvoid mp_emit_bc_end_finally(emit_t *emit);\nvoid mp_emit_bc_get_iter(emit_t *emit, bool use_stack);\nvoid mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label);\nvoid mp_emit_bc_for_iter_end(emit_t *emit);\nvoid mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler);\nvoid mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op);\nvoid mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op);\nvoid mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind);\nvoid mp_emit_bc_store_map(emit_t *emit);\nvoid mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t list_stack_index);\nvoid mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args);\nvoid mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right);\nvoid mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults);\nvoid 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);\nvoid mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags);\nvoid mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags);\nvoid mp_emit_bc_return_value(emit_t *emit);\nvoid mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args);\nvoid mp_emit_bc_yield(emit_t *emit, int kind);\nvoid mp_emit_bc_start_except_handler(emit_t *emit);\nvoid mp_emit_bc_end_except_handler(emit_t *emit);\n\ntypedef struct _emit_inline_asm_t emit_inline_asm_t;\n\ntypedef struct _emit_inline_asm_method_table_t {\n    #if MICROPY_DYNAMIC_COMPILER\n    emit_inline_asm_t *(*asm_new)(mp_uint_t max_num_labels);\n    void (*asm_free)(emit_inline_asm_t *emit);\n    #endif\n\n    void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot);\n    void (*end_pass)(emit_inline_asm_t *emit, mp_uint_t type_sig);\n    mp_uint_t (*count_params)(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params);\n    bool (*label)(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id);\n    void (*op)(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args);\n} emit_inline_asm_method_table_t;\n\nextern const emit_inline_asm_method_table_t emit_inline_thumb_method_table;\nextern const emit_inline_asm_method_table_t emit_inline_xtensa_method_table;\n\nemit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels);\nemit_inline_asm_t *emit_inline_xtensa_new(mp_uint_t max_num_labels);\n\nvoid emit_inline_thumb_free(emit_inline_asm_t *emit);\nvoid emit_inline_xtensa_free(emit_inline_asm_t *emit);\n\n#if MICROPY_WARNINGS\nvoid mp_emitter_warning(pass_kind_t pass, const char *msg);\n#else\n#define mp_emitter_warning(pass, msg)\n#endif\n\n#endif // MICROPY_INCLUDED_PY_EMIT_H\n"
  },
  {
    "path": "py/emitbc.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2019 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/mpstate.h\"\n#include \"py/emit.h\"\n#include \"py/bc0.h\"\n\n#if MICROPY_ENABLE_COMPILER\n\n#define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7)\n#define DUMMY_DATA_SIZE (BYTES_FOR_INT)\n\nstruct _emit_t {\n    // Accessed as mp_obj_t, so must be aligned as such, and we rely on the\n    // memory allocator returning a suitably aligned pointer.\n    // Should work for cases when mp_obj_t is 64-bit on a 32-bit machine.\n    byte dummy_data[DUMMY_DATA_SIZE];\n\n    pass_kind_t pass : 8;\n    mp_uint_t last_emit_was_return_value : 8;\n\n    int stack_size;\n\n    scope_t *scope;\n\n    mp_uint_t last_source_line_offset;\n    mp_uint_t last_source_line;\n\n    mp_uint_t max_num_labels;\n    mp_uint_t *label_offsets;\n\n    size_t code_info_offset;\n    size_t code_info_size;\n    size_t bytecode_offset;\n    size_t bytecode_size;\n    byte *code_base; // stores both byte code and code info\n\n    size_t n_info;\n    size_t n_cell;\n\n    #if MICROPY_PERSISTENT_CODE\n    uint16_t ct_cur_obj;\n    uint16_t ct_num_obj;\n    uint16_t ct_cur_raw_code;\n    #endif\n    mp_uint_t *const_table;\n};\n\nemit_t *emit_bc_new(void) {\n    emit_t *emit = m_new0(emit_t, 1);\n    return emit;\n}\n\nvoid emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels) {\n    emit->max_num_labels = max_num_labels;\n    emit->label_offsets = m_new(mp_uint_t, emit->max_num_labels);\n}\n\nvoid emit_bc_free(emit_t *emit) {\n    m_del(mp_uint_t, emit->label_offsets, emit->max_num_labels);\n    m_del_obj(emit_t, emit);\n}\n\ntypedef byte *(*emit_allocator_t)(emit_t *emit, int nbytes);\n\nSTATIC void emit_write_uint(emit_t *emit, emit_allocator_t allocator, mp_uint_t val) {\n    // We store each 7 bits in a separate byte, and that's how many bytes needed\n    byte buf[BYTES_FOR_INT];\n    byte *p = buf + sizeof(buf);\n    // We encode in little-ending order, but store in big-endian, to help decoding\n    do {\n        *--p = val & 0x7f;\n        val >>= 7;\n    } while (val != 0);\n    byte *c = allocator(emit, buf + sizeof(buf) - p);\n    while (p != buf + sizeof(buf) - 1) {\n        *c++ = *p++ | 0x80;\n    }\n    *c = *p;\n}\n\n// all functions must go through this one to emit code info\nSTATIC byte *emit_get_cur_to_write_code_info(emit_t *emit, int num_bytes_to_write) {\n    if (emit->pass < MP_PASS_EMIT) {\n        emit->code_info_offset += num_bytes_to_write;\n        return emit->dummy_data;\n    } else {\n        assert(emit->code_info_offset + num_bytes_to_write <= emit->code_info_size);\n        byte *c = emit->code_base + emit->code_info_offset;\n        emit->code_info_offset += num_bytes_to_write;\n        return c;\n    }\n}\n\nSTATIC void emit_write_code_info_byte(emit_t *emit, byte val) {\n    *emit_get_cur_to_write_code_info(emit, 1) = val;\n}\n\nSTATIC void emit_write_code_info_qstr(emit_t *emit, qstr qst) {\n    #if MICROPY_PERSISTENT_CODE\n    assert((qst >> 16) == 0);\n    byte *c = emit_get_cur_to_write_code_info(emit, 2);\n    c[0] = qst;\n    c[1] = qst >> 8;\n    #else\n    emit_write_uint(emit, emit_get_cur_to_write_code_info, qst);\n    #endif\n}\n\n#if MICROPY_ENABLE_SOURCE_LINE\nSTATIC void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_skip, mp_uint_t lines_to_skip) {\n    assert(bytes_to_skip > 0 || lines_to_skip > 0);\n    while (bytes_to_skip > 0 || lines_to_skip > 0) {\n        mp_uint_t b, l;\n        if (lines_to_skip <= 6 || bytes_to_skip > 0xf) {\n            // use 0b0LLBBBBB encoding\n            b = MIN(bytes_to_skip, 0x1f);\n            if (b < bytes_to_skip) {\n                // we can't skip any lines until we skip all the bytes\n                l = 0;\n            } else {\n                l = MIN(lines_to_skip, 0x3);\n            }\n            *emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);\n        } else {\n            // use 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte)\n            b = MIN(bytes_to_skip, 0xf);\n            l = MIN(lines_to_skip, 0x7ff);\n            byte *ci = emit_get_cur_to_write_code_info(emit, 2);\n            ci[0] = 0x80 | b | ((l >> 4) & 0x70);\n            ci[1] = l;\n        }\n        bytes_to_skip -= b;\n        lines_to_skip -= l;\n    }\n}\n#endif\n\n// all functions must go through this one to emit byte code\nSTATIC byte *emit_get_cur_to_write_bytecode(emit_t *emit, int num_bytes_to_write) {\n    if (emit->pass < MP_PASS_EMIT) {\n        emit->bytecode_offset += num_bytes_to_write;\n        return emit->dummy_data;\n    } else {\n        assert(emit->bytecode_offset + num_bytes_to_write <= emit->bytecode_size);\n        byte *c = emit->code_base + emit->code_info_size + emit->bytecode_offset;\n        emit->bytecode_offset += num_bytes_to_write;\n        return c;\n    }\n}\n\nSTATIC void emit_write_bytecode_raw_byte(emit_t *emit, byte b1) {\n    byte *c = emit_get_cur_to_write_bytecode(emit, 1);\n    c[0] = b1;\n}\n\nSTATIC void emit_write_bytecode_byte(emit_t *emit, int stack_adj, byte b1) {\n    mp_emit_bc_adjust_stack_size(emit, stack_adj);\n    byte *c = emit_get_cur_to_write_bytecode(emit, 1);\n    c[0] = b1;\n}\n\n// Similar to emit_write_bytecode_uint(), just some extra handling to encode sign\nSTATIC void emit_write_bytecode_byte_int(emit_t *emit, int stack_adj, byte b1, mp_int_t num) {\n    emit_write_bytecode_byte(emit, stack_adj, b1);\n\n    // We store each 7 bits in a separate byte, and that's how many bytes needed\n    byte buf[BYTES_FOR_INT];\n    byte *p = buf + sizeof(buf);\n    // We encode in little-ending order, but store in big-endian, to help decoding\n    do {\n        *--p = num & 0x7f;\n        num >>= 7;\n    } while (num != 0 && num != -1);\n    // Make sure that highest bit we stored (mask 0x40) matches sign\n    // of the number. If not, store extra byte just to encode sign\n    if (num == -1 && (*p & 0x40) == 0) {\n        *--p = 0x7f;\n    } else if (num == 0 && (*p & 0x40) != 0) {\n        *--p = 0;\n    }\n\n    byte *c = emit_get_cur_to_write_bytecode(emit, buf + sizeof(buf) - p);\n    while (p != buf + sizeof(buf) - 1) {\n        *c++ = *p++ | 0x80;\n    }\n    *c = *p;\n}\n\nSTATIC void emit_write_bytecode_byte_uint(emit_t *emit, int stack_adj, byte b, mp_uint_t val) {\n    emit_write_bytecode_byte(emit, stack_adj, b);\n    emit_write_uint(emit, emit_get_cur_to_write_bytecode, val);\n}\n\n#if MICROPY_PERSISTENT_CODE\nSTATIC void emit_write_bytecode_byte_const(emit_t *emit, int stack_adj, byte b, mp_uint_t n, mp_uint_t c) {\n    if (emit->pass == MP_PASS_EMIT) {\n        emit->const_table[n] = c;\n    }\n    emit_write_bytecode_byte_uint(emit, stack_adj, b, n);\n}\n#endif\n\nSTATIC void emit_write_bytecode_byte_qstr(emit_t *emit, int stack_adj, byte b, qstr qst) {\n    #if MICROPY_PERSISTENT_CODE\n    assert((qst >> 16) == 0);\n    mp_emit_bc_adjust_stack_size(emit, stack_adj);\n    byte *c = emit_get_cur_to_write_bytecode(emit, 3);\n    c[0] = b;\n    c[1] = qst;\n    c[2] = qst >> 8;\n    #else\n    emit_write_bytecode_byte_uint(emit, stack_adj, b, qst);\n    #endif\n}\n\nSTATIC void emit_write_bytecode_byte_obj(emit_t *emit, int stack_adj, byte b, mp_obj_t obj) {\n    #if MICROPY_PERSISTENT_CODE\n    emit_write_bytecode_byte_const(emit, stack_adj, b,\n        emit->scope->num_pos_args + emit->scope->num_kwonly_args\n        + emit->ct_cur_obj++, (mp_uint_t)obj);\n    #else\n    // aligns the pointer so it is friendly to GC\n    emit_write_bytecode_byte(emit, stack_adj, b);\n    emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(mp_obj_t));\n    mp_obj_t *c = (mp_obj_t *)emit_get_cur_to_write_bytecode(emit, sizeof(mp_obj_t));\n    // Verify thar c is already uint-aligned\n    assert(c == MP_ALIGN(c, sizeof(mp_obj_t)));\n    *c = obj;\n    #endif\n}\n\nSTATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, int stack_adj, byte b, mp_raw_code_t *rc) {\n    #if MICROPY_PERSISTENT_CODE\n    emit_write_bytecode_byte_const(emit, stack_adj, b,\n        emit->scope->num_pos_args + emit->scope->num_kwonly_args\n        + emit->ct_num_obj + emit->ct_cur_raw_code++, (mp_uint_t)(uintptr_t)rc);\n    #else\n    // aligns the pointer so it is friendly to GC\n    emit_write_bytecode_byte(emit, stack_adj, b);\n    emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(void *));\n    void **c = (void **)emit_get_cur_to_write_bytecode(emit, sizeof(void *));\n    // Verify thar c is already uint-aligned\n    assert(c == MP_ALIGN(c, sizeof(void *)));\n    *c = rc;\n    #endif\n    #if MICROPY_PY_SYS_SETTRACE\n    rc->line_of_definition = emit->last_source_line;\n    #endif\n}\n\n// unsigned labels are relative to ip following this instruction, stored as 16 bits\nSTATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, int stack_adj, byte b1, mp_uint_t label) {\n    mp_emit_bc_adjust_stack_size(emit, stack_adj);\n    mp_uint_t bytecode_offset;\n    if (emit->pass < MP_PASS_EMIT) {\n        bytecode_offset = 0;\n    } else {\n        bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3;\n    }\n    byte *c = emit_get_cur_to_write_bytecode(emit, 3);\n    c[0] = b1;\n    c[1] = bytecode_offset;\n    c[2] = bytecode_offset >> 8;\n}\n\n// signed labels are relative to ip following this instruction, stored as 16 bits, in excess\nSTATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, int stack_adj, byte b1, mp_uint_t label) {\n    mp_emit_bc_adjust_stack_size(emit, stack_adj);\n    int bytecode_offset;\n    if (emit->pass < MP_PASS_EMIT) {\n        bytecode_offset = 0;\n    } else {\n        bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3 + 0x8000;\n    }\n    byte *c = emit_get_cur_to_write_bytecode(emit, 3);\n    c[0] = b1;\n    c[1] = bytecode_offset;\n    c[2] = bytecode_offset >> 8;\n}\n\nvoid mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {\n    emit->pass = pass;\n    emit->stack_size = 0;\n    emit->last_emit_was_return_value = false;\n    emit->scope = scope;\n    emit->last_source_line_offset = 0;\n    emit->last_source_line = 1;\n    #ifndef NDEBUG\n    // With debugging enabled labels are checked for unique assignment\n    if (pass < MP_PASS_EMIT && emit->label_offsets != NULL) {\n        memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t));\n    }\n    #endif\n    emit->bytecode_offset = 0;\n    emit->code_info_offset = 0;\n\n    // Write local state size, exception stack size, scope flags and number of arguments\n    {\n        mp_uint_t n_state = scope->num_locals + scope->stack_size;\n        if (n_state == 0) {\n            // Need at least 1 entry in the state, in the case an exception is\n            // propagated through this function, the exception is returned in\n            // the highest slot in the state (fastn[0], see vm.c).\n            n_state = 1;\n        }\n        #if MICROPY_DEBUG_VM_STACK_OVERFLOW\n        // An extra slot in the stack is needed to detect VM stack overflow\n        n_state += 1;\n        #endif\n\n        size_t n_exc_stack = scope->exc_stack_size;\n        MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, scope, emit_write_code_info_byte, emit);\n    }\n\n    // Write number of cells and size of the source code info\n    if (pass >= MP_PASS_CODE_SIZE) {\n        MP_BC_PRELUDE_SIZE_ENCODE(emit->n_info, emit->n_cell, emit_write_code_info_byte, emit);\n    }\n\n    emit->n_info = emit->code_info_offset;\n\n    // Write the name and source file of this function.\n    emit_write_code_info_qstr(emit, scope->simple_name);\n    emit_write_code_info_qstr(emit, scope->source_file);\n\n    #if MICROPY_PERSISTENT_CODE\n    emit->ct_cur_obj = 0;\n    emit->ct_cur_raw_code = 0;\n    #endif\n\n    if (pass == MP_PASS_EMIT) {\n        // Write argument names (needed to resolve positional args passed as\n        // keywords).  We store them as full word-sized objects for efficient access\n        // in mp_setup_code_state this is the start of the prelude and is guaranteed\n        // to be aligned on a word boundary.\n\n        // For a given argument position (indexed by i) we need to find the\n        // corresponding id_info which is a parameter, as it has the correct\n        // qstr name to use as the argument name.  Note that it's not a simple\n        // 1-1 mapping (ie i!=j in general) because of possible closed-over\n        // variables.  In the case that the argument i has no corresponding\n        // parameter we use \"*\" as its name (since no argument can ever be named\n        // \"*\").  We could use a blank qstr but \"*\" is better for debugging.\n        // Note: there is some wasted RAM here for the case of storing a qstr\n        // for each closed-over variable, and maybe there is a better way to do\n        // it, but that would require changes to mp_setup_code_state.\n        for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) {\n            qstr qst = MP_QSTR__star_;\n            for (int j = 0; j < scope->id_info_len; ++j) {\n                id_info_t *id = &scope->id_info[j];\n                if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) {\n                    qst = id->qst;\n                    break;\n                }\n            }\n            emit->const_table[i] = (mp_uint_t)MP_OBJ_NEW_QSTR(qst);\n        }\n    }\n}\n\nvoid mp_emit_bc_end_pass(emit_t *emit) {\n    if (emit->pass == MP_PASS_SCOPE) {\n        return;\n    }\n\n    // check stack is back to zero size\n    assert(emit->stack_size == 0);\n\n    emit_write_code_info_byte(emit, 0); // end of line number info\n\n    // Calculate size of source code info section\n    emit->n_info = emit->code_info_offset - emit->n_info;\n\n    // Emit closure section of prelude\n    emit->n_cell = 0;\n    for (size_t i = 0; i < emit->scope->id_info_len; ++i) {\n        id_info_t *id = &emit->scope->id_info[i];\n        if (id->kind == ID_INFO_KIND_CELL) {\n            assert(id->local_num <= 255);\n            emit_write_code_info_byte(emit, id->local_num); // write the local which should be converted to a cell\n            ++emit->n_cell;\n        }\n    }\n\n    #if MICROPY_PERSISTENT_CODE\n    assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->ct_num_obj == emit->ct_cur_obj));\n    emit->ct_num_obj = emit->ct_cur_obj;\n    #endif\n\n    if (emit->pass == MP_PASS_CODE_SIZE) {\n        #if !MICROPY_PERSISTENT_CODE\n        // so bytecode is aligned\n        emit->code_info_offset = (size_t)MP_ALIGN(emit->code_info_offset, sizeof(mp_uint_t));\n        #endif\n\n        // calculate size of total code-info + bytecode, in bytes\n        emit->code_info_size = emit->code_info_offset;\n        emit->bytecode_size = emit->bytecode_offset;\n        emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size);\n\n        #if MICROPY_PERSISTENT_CODE\n        emit->const_table = m_new0(mp_uint_t,\n            emit->scope->num_pos_args + emit->scope->num_kwonly_args\n            + emit->ct_cur_obj + emit->ct_cur_raw_code);\n        #else\n        emit->const_table = m_new0(mp_uint_t,\n            emit->scope->num_pos_args + emit->scope->num_kwonly_args);\n        #endif\n\n    } else if (emit->pass == MP_PASS_EMIT) {\n        mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base,\n            #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS\n            emit->code_info_size + emit->bytecode_size,\n            #endif\n            emit->const_table,\n            #if MICROPY_PERSISTENT_CODE_SAVE\n            emit->ct_cur_obj, emit->ct_cur_raw_code,\n            #endif\n            emit->scope->scope_flags);\n    }\n}\n\nbool mp_emit_bc_last_emit_was_return_value(emit_t *emit) {\n    return emit->last_emit_was_return_value;\n}\n\nvoid mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) {\n    if (emit->pass == MP_PASS_SCOPE) {\n        return;\n    }\n    assert((mp_int_t)emit->stack_size + delta >= 0);\n    emit->stack_size += delta;\n    if (emit->stack_size > emit->scope->stack_size) {\n        emit->scope->stack_size = emit->stack_size;\n    }\n    emit->last_emit_was_return_value = false;\n}\n\nvoid mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) {\n    #if MICROPY_ENABLE_SOURCE_LINE\n    if (MP_STATE_VM(mp_optimise_value) >= 3) {\n        // If we compile with -O3, don't store line numbers.\n        return;\n    }\n    if (source_line > emit->last_source_line) {\n        mp_uint_t bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset;\n        mp_uint_t lines_to_skip = source_line - emit->last_source_line;\n        emit_write_code_info_bytes_lines(emit, bytes_to_skip, lines_to_skip);\n        emit->last_source_line_offset = emit->bytecode_offset;\n        emit->last_source_line = source_line;\n    }\n    #else\n    (void)emit;\n    (void)source_line;\n    #endif\n}\n\nvoid mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) {\n    mp_emit_bc_adjust_stack_size(emit, 0);\n    if (emit->pass == MP_PASS_SCOPE) {\n        return;\n    }\n    assert(l < emit->max_num_labels);\n    if (emit->pass < MP_PASS_EMIT) {\n        // assign label offset\n        assert(emit->label_offsets[l] == (mp_uint_t)-1);\n        emit->label_offsets[l] = emit->bytecode_offset;\n    } else {\n        // ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT\n        assert(emit->label_offsets[l] == emit->bytecode_offset);\n    }\n}\n\nvoid mp_emit_bc_import(emit_t *emit, qstr qst, int kind) {\n    MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_NAME == MP_BC_IMPORT_NAME);\n    MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_FROM == MP_BC_IMPORT_FROM);\n    int stack_adj = kind == MP_EMIT_IMPORT_FROM ? 1 : -1;\n    if (kind == MP_EMIT_IMPORT_STAR) {\n        emit_write_bytecode_byte(emit, stack_adj, MP_BC_IMPORT_STAR);\n    } else {\n        emit_write_bytecode_byte_qstr(emit, stack_adj, MP_BC_IMPORT_NAME + kind, qst);\n    }\n}\n\nvoid mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {\n    MP_STATIC_ASSERT(MP_BC_LOAD_CONST_FALSE + (MP_TOKEN_KW_NONE - MP_TOKEN_KW_FALSE) == MP_BC_LOAD_CONST_NONE);\n    MP_STATIC_ASSERT(MP_BC_LOAD_CONST_FALSE + (MP_TOKEN_KW_TRUE - MP_TOKEN_KW_FALSE) == MP_BC_LOAD_CONST_TRUE);\n    if (tok == MP_TOKEN_ELLIPSIS) {\n        emit_write_bytecode_byte_obj(emit, 1, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj));\n    } else {\n        emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_CONST_FALSE + (tok - MP_TOKEN_KW_FALSE));\n    }\n}\n\nvoid mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) {\n    if (-MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS <= arg\n        && arg < MP_BC_LOAD_CONST_SMALL_INT_MULTI_NUM - MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS) {\n        emit_write_bytecode_byte(emit, 1,\n            MP_BC_LOAD_CONST_SMALL_INT_MULTI + MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS + arg);\n    } else {\n        emit_write_bytecode_byte_int(emit, 1, MP_BC_LOAD_CONST_SMALL_INT, arg);\n    }\n}\n\nvoid mp_emit_bc_load_const_str(emit_t *emit, qstr qst) {\n    emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_CONST_STRING, qst);\n}\n\nvoid mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj) {\n    emit_write_bytecode_byte_obj(emit, 1, MP_BC_LOAD_CONST_OBJ, obj);\n}\n\nvoid mp_emit_bc_load_null(emit_t *emit) {\n    emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_NULL);\n}\n\nvoid mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {\n    MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_LOAD_FAST_N);\n    MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_LOAD_DEREF);\n    (void)qst;\n    if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) {\n        emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_FAST_MULTI + local_num);\n    } else {\n        emit_write_bytecode_byte_uint(emit, 1, MP_BC_LOAD_FAST_N + kind, local_num);\n    }\n}\n\nvoid mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) {\n    MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_LOAD_NAME);\n    MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL);\n    (void)qst;\n    emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_NAME + kind, qst);\n    if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {\n        emit_write_bytecode_raw_byte(emit, 0);\n    }\n}\n\nvoid mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) {\n    int stack_adj = 1 - 2 * is_super;\n    emit_write_bytecode_byte_qstr(emit, stack_adj, is_super ? MP_BC_LOAD_SUPER_METHOD : MP_BC_LOAD_METHOD, qst);\n}\n\nvoid mp_emit_bc_load_build_class(emit_t *emit) {\n    emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_BUILD_CLASS);\n}\n\nvoid mp_emit_bc_subscr(emit_t *emit, int kind) {\n    if (kind == MP_EMIT_SUBSCR_LOAD) {\n        emit_write_bytecode_byte(emit, -1, MP_BC_LOAD_SUBSCR);\n    } else {\n        if (kind == MP_EMIT_SUBSCR_DELETE) {\n            mp_emit_bc_load_null(emit);\n            mp_emit_bc_rot_three(emit);\n        }\n        emit_write_bytecode_byte(emit, -3, MP_BC_STORE_SUBSCR);\n    }\n}\n\nvoid mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) {\n    if (kind == MP_EMIT_ATTR_LOAD) {\n        emit_write_bytecode_byte_qstr(emit, 0, MP_BC_LOAD_ATTR, qst);\n    } else {\n        if (kind == MP_EMIT_ATTR_DELETE) {\n            mp_emit_bc_load_null(emit);\n            mp_emit_bc_rot_two(emit);\n        }\n        emit_write_bytecode_byte_qstr(emit, -2, MP_BC_STORE_ATTR, qst);\n    }\n    if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {\n        emit_write_bytecode_raw_byte(emit, 0);\n    }\n}\n\nvoid mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {\n    MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_STORE_FAST_N);\n    MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_STORE_DEREF);\n    (void)qst;\n    if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) {\n        emit_write_bytecode_byte(emit, -1, MP_BC_STORE_FAST_MULTI + local_num);\n    } else {\n        emit_write_bytecode_byte_uint(emit, -1, MP_BC_STORE_FAST_N + kind, local_num);\n    }\n}\n\nvoid mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind) {\n    MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_STORE_NAME);\n    MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_STORE_GLOBAL);\n    emit_write_bytecode_byte_qstr(emit, -1, MP_BC_STORE_NAME + kind, qst);\n}\n\nvoid mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {\n    MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_DELETE_FAST);\n    MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_DELETE_DEREF);\n    (void)qst;\n    emit_write_bytecode_byte_uint(emit, 0, MP_BC_DELETE_FAST + kind, local_num);\n}\n\nvoid mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind) {\n    MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_DELETE_NAME);\n    MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_DELETE_GLOBAL);\n    emit_write_bytecode_byte_qstr(emit, 0, MP_BC_DELETE_NAME + kind, qst);\n}\n\nvoid mp_emit_bc_dup_top(emit_t *emit) {\n    emit_write_bytecode_byte(emit, 1, MP_BC_DUP_TOP);\n}\n\nvoid mp_emit_bc_dup_top_two(emit_t *emit) {\n    emit_write_bytecode_byte(emit, 2, MP_BC_DUP_TOP_TWO);\n}\n\nvoid mp_emit_bc_pop_top(emit_t *emit) {\n    emit_write_bytecode_byte(emit, -1, MP_BC_POP_TOP);\n}\n\nvoid mp_emit_bc_rot_two(emit_t *emit) {\n    emit_write_bytecode_byte(emit, 0, MP_BC_ROT_TWO);\n}\n\nvoid mp_emit_bc_rot_three(emit_t *emit) {\n    emit_write_bytecode_byte(emit, 0, MP_BC_ROT_THREE);\n}\n\nvoid mp_emit_bc_jump(emit_t *emit, mp_uint_t label) {\n    emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_JUMP, label);\n}\n\nvoid mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) {\n    if (cond) {\n        emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_POP_JUMP_IF_TRUE, label);\n    } else {\n        emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_POP_JUMP_IF_FALSE, label);\n    }\n}\n\nvoid mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) {\n    if (cond) {\n        emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_JUMP_IF_TRUE_OR_POP, label);\n    } else {\n        emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_JUMP_IF_FALSE_OR_POP, label);\n    }\n}\n\nvoid mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {\n    if (except_depth == 0) {\n        if (label & MP_EMIT_BREAK_FROM_FOR) {\n            // need to pop the iterator if we are breaking out of a for loop\n            emit_write_bytecode_raw_byte(emit, MP_BC_POP_TOP);\n            // also pop the iter_buf\n            for (size_t i = 0; i < MP_OBJ_ITER_BUF_NSLOTS - 1; ++i) {\n                emit_write_bytecode_raw_byte(emit, MP_BC_POP_TOP);\n            }\n        }\n        emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);\n    } else {\n        emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);\n        emit_write_bytecode_raw_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth);\n    }\n}\n\nvoid mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind) {\n    MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_WITH == MP_BC_SETUP_WITH);\n    MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_EXCEPT == MP_BC_SETUP_EXCEPT);\n    MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_FINALLY == MP_BC_SETUP_FINALLY);\n    // The SETUP_WITH opcode pops ctx_mgr from the top of the stack\n    // and then pushes 3 entries: __exit__, ctx_mgr, as_value.\n    int stack_adj = kind == MP_EMIT_SETUP_BLOCK_WITH ? 2 : 0;\n    emit_write_bytecode_byte_unsigned_label(emit, stack_adj, MP_BC_SETUP_WITH + kind, label);\n}\n\nvoid mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) {\n    mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE);\n    mp_emit_bc_label_assign(emit, label);\n    // The +2 is to ensure we have enough stack space to call the __exit__ method\n    emit_write_bytecode_byte(emit, 2, MP_BC_WITH_CLEANUP);\n    // Cancel the +2 above, plus the +2 from mp_emit_bc_setup_block(MP_EMIT_SETUP_BLOCK_WITH)\n    mp_emit_bc_adjust_stack_size(emit, -4);\n}\n\nvoid mp_emit_bc_end_finally(emit_t *emit) {\n    emit_write_bytecode_byte(emit, -1, MP_BC_END_FINALLY);\n}\n\nvoid mp_emit_bc_get_iter(emit_t *emit, bool use_stack) {\n    int stack_adj = use_stack ? MP_OBJ_ITER_BUF_NSLOTS - 1 : 0;\n    emit_write_bytecode_byte(emit, stack_adj, use_stack ? MP_BC_GET_ITER_STACK : MP_BC_GET_ITER);\n}\n\nvoid mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label) {\n    emit_write_bytecode_byte_unsigned_label(emit, 1, MP_BC_FOR_ITER, label);\n}\n\nvoid mp_emit_bc_for_iter_end(emit_t *emit) {\n    mp_emit_bc_adjust_stack_size(emit, -MP_OBJ_ITER_BUF_NSLOTS);\n}\n\nvoid mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) {\n    (void)within_exc_handler;\n    emit_write_bytecode_byte_unsigned_label(emit, 0, MP_BC_POP_EXCEPT_JUMP, label);\n}\n\nvoid mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) {\n    emit_write_bytecode_byte(emit, 0, MP_BC_UNARY_OP_MULTI + op);\n}\n\nvoid mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) {\n    bool invert = false;\n    if (op == MP_BINARY_OP_NOT_IN) {\n        invert = true;\n        op = MP_BINARY_OP_IN;\n    } else if (op == MP_BINARY_OP_IS_NOT) {\n        invert = true;\n        op = MP_BINARY_OP_IS;\n    }\n    emit_write_bytecode_byte(emit, -1, MP_BC_BINARY_OP_MULTI + op);\n    if (invert) {\n        emit_write_bytecode_byte(emit, 0, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NOT);\n    }\n}\n\nvoid mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind) {\n    MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_BC_BUILD_TUPLE);\n    MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_BC_BUILD_LIST);\n    MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_BC_BUILD_MAP);\n    MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_BC_BUILD_SET);\n    MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SLICE == MP_BC_BUILD_SLICE);\n    int stack_adj = kind == MP_EMIT_BUILD_MAP ? 1 : 1 - n_args;\n    emit_write_bytecode_byte_uint(emit, stack_adj, MP_BC_BUILD_TUPLE + kind, n_args);\n}\n\nvoid mp_emit_bc_store_map(emit_t *emit) {\n    emit_write_bytecode_byte(emit, -2, MP_BC_STORE_MAP);\n}\n\nvoid mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_stack_index) {\n    int t;\n    int n;\n    if (kind == SCOPE_LIST_COMP) {\n        n = 0;\n        t = 0;\n    } else if (!MICROPY_PY_BUILTINS_SET || kind == SCOPE_DICT_COMP) {\n        n = 1;\n        t = 1;\n    } else if (MICROPY_PY_BUILTINS_SET) {\n        n = 0;\n        t = 2;\n    }\n    // the lower 2 bits of the opcode argument indicate the collection type\n    emit_write_bytecode_byte_uint(emit, -1 - n, MP_BC_STORE_COMP, ((collection_stack_index + n) << 2) | t);\n}\n\nvoid mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args) {\n    emit_write_bytecode_byte_uint(emit, -1 + n_args, MP_BC_UNPACK_SEQUENCE, n_args);\n}\n\nvoid mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) {\n    emit_write_bytecode_byte_uint(emit, -1 + n_left + n_right + 1, MP_BC_UNPACK_EX, n_left | (n_right << 8));\n}\n\nvoid mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {\n    if (n_pos_defaults == 0 && n_kw_defaults == 0) {\n        emit_write_bytecode_byte_raw_code(emit, 1, MP_BC_MAKE_FUNCTION, scope->raw_code);\n    } else {\n        emit_write_bytecode_byte_raw_code(emit, -1, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code);\n    }\n}\n\nvoid 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) {\n    if (n_pos_defaults == 0 && n_kw_defaults == 0) {\n        int stack_adj = -n_closed_over + 1;\n        emit_write_bytecode_byte_raw_code(emit, stack_adj, MP_BC_MAKE_CLOSURE, scope->raw_code);\n        emit_write_bytecode_raw_byte(emit, n_closed_over);\n    } else {\n        assert(n_closed_over <= 255);\n        int stack_adj = -2 - (mp_int_t)n_closed_over + 1;\n        emit_write_bytecode_byte_raw_code(emit, stack_adj, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code);\n        emit_write_bytecode_raw_byte(emit, n_closed_over);\n    }\n}\n\nSTATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, mp_uint_t bytecode_base, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {\n    if (star_flags) {\n        stack_adj -= (int)n_positional + 2 * (int)n_keyword + 2;\n        emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints?\n    } else {\n        stack_adj -= (int)n_positional + 2 * (int)n_keyword;\n        emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints?\n    }\n}\n\nvoid mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {\n    emit_bc_call_function_method_helper(emit, 0, MP_BC_CALL_FUNCTION, n_positional, n_keyword, star_flags);\n}\n\nvoid mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {\n    emit_bc_call_function_method_helper(emit, -1, MP_BC_CALL_METHOD, n_positional, n_keyword, star_flags);\n}\n\nvoid mp_emit_bc_return_value(emit_t *emit) {\n    emit_write_bytecode_byte(emit, -1, MP_BC_RETURN_VALUE);\n    emit->last_emit_was_return_value = true;\n}\n\nvoid mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) {\n    MP_STATIC_ASSERT(MP_BC_RAISE_LAST + 1 == MP_BC_RAISE_OBJ);\n    MP_STATIC_ASSERT(MP_BC_RAISE_LAST + 2 == MP_BC_RAISE_FROM);\n    assert(n_args <= 2);\n    emit_write_bytecode_byte(emit, -n_args, MP_BC_RAISE_LAST + n_args);\n}\n\nvoid mp_emit_bc_yield(emit_t *emit, int kind) {\n    MP_STATIC_ASSERT(MP_BC_YIELD_VALUE + 1 == MP_BC_YIELD_FROM);\n    emit_write_bytecode_byte(emit, -kind, MP_BC_YIELD_VALUE + kind);\n    emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;\n}\n\nvoid mp_emit_bc_start_except_handler(emit_t *emit) {\n    mp_emit_bc_adjust_stack_size(emit, 4); // stack adjust for the exception instance, +3 for possible UNWIND_JUMP state\n}\n\nvoid mp_emit_bc_end_except_handler(emit_t *emit) {\n    mp_emit_bc_adjust_stack_size(emit, -3); // stack adjust\n}\n\n#if MICROPY_EMIT_NATIVE\nconst emit_method_table_t emit_bc_method_table = {\n    #if MICROPY_DYNAMIC_COMPILER\n    NULL,\n    NULL,\n    #endif\n\n    mp_emit_bc_start_pass,\n    mp_emit_bc_end_pass,\n    mp_emit_bc_last_emit_was_return_value,\n    mp_emit_bc_adjust_stack_size,\n    mp_emit_bc_set_source_line,\n\n    {\n        mp_emit_bc_load_local,\n        mp_emit_bc_load_global,\n    },\n    {\n        mp_emit_bc_store_local,\n        mp_emit_bc_store_global,\n    },\n    {\n        mp_emit_bc_delete_local,\n        mp_emit_bc_delete_global,\n    },\n\n    mp_emit_bc_label_assign,\n    mp_emit_bc_import,\n    mp_emit_bc_load_const_tok,\n    mp_emit_bc_load_const_small_int,\n    mp_emit_bc_load_const_str,\n    mp_emit_bc_load_const_obj,\n    mp_emit_bc_load_null,\n    mp_emit_bc_load_method,\n    mp_emit_bc_load_build_class,\n    mp_emit_bc_subscr,\n    mp_emit_bc_attr,\n    mp_emit_bc_dup_top,\n    mp_emit_bc_dup_top_two,\n    mp_emit_bc_pop_top,\n    mp_emit_bc_rot_two,\n    mp_emit_bc_rot_three,\n    mp_emit_bc_jump,\n    mp_emit_bc_pop_jump_if,\n    mp_emit_bc_jump_if_or_pop,\n    mp_emit_bc_unwind_jump,\n    mp_emit_bc_setup_block,\n    mp_emit_bc_with_cleanup,\n    mp_emit_bc_end_finally,\n    mp_emit_bc_get_iter,\n    mp_emit_bc_for_iter,\n    mp_emit_bc_for_iter_end,\n    mp_emit_bc_pop_except_jump,\n    mp_emit_bc_unary_op,\n    mp_emit_bc_binary_op,\n    mp_emit_bc_build,\n    mp_emit_bc_store_map,\n    mp_emit_bc_store_comp,\n    mp_emit_bc_unpack_sequence,\n    mp_emit_bc_unpack_ex,\n    mp_emit_bc_make_function,\n    mp_emit_bc_make_closure,\n    mp_emit_bc_call_function,\n    mp_emit_bc_call_method,\n    mp_emit_bc_return_value,\n    mp_emit_bc_raise_varargs,\n    mp_emit_bc_yield,\n\n    mp_emit_bc_start_except_handler,\n    mp_emit_bc_end_except_handler,\n};\n#else\nconst mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops = {\n    mp_emit_bc_load_local,\n    mp_emit_bc_load_global,\n};\n\nconst mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops = {\n    mp_emit_bc_store_local,\n    mp_emit_bc_store_global,\n};\n\nconst mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = {\n    mp_emit_bc_delete_local,\n    mp_emit_bc_delete_global,\n};\n#endif\n\n#endif // MICROPY_ENABLE_COMPILER\n"
  },
  {
    "path": "py/emitcommon.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n\n#include \"py/emit.h\"\n\n#if MICROPY_ENABLE_COMPILER\n\nvoid mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst) {\n    // name adding/lookup\n    id_info_t *id = scope_find_or_add_id(scope, qst, ID_INFO_KIND_GLOBAL_IMPLICIT);\n    if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {\n        // rebind as a local variable\n        id->kind = ID_INFO_KIND_LOCAL;\n    }\n}\n\nvoid mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emit_method_table, scope_t *scope, qstr qst) {\n    // assumes pass is greater than 1, ie that all identifiers are defined in the scope\n\n    id_info_t *id = scope_find(scope, qst);\n    assert(id != NULL);\n\n    // call the emit backend with the correct code\n    if (id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {\n        emit_method_table->global(emit, qst, MP_EMIT_IDOP_GLOBAL_NAME);\n    } else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {\n        emit_method_table->global(emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL);\n    } else if (id->kind == ID_INFO_KIND_LOCAL) {\n        emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_FAST);\n    } else {\n        assert(id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE);\n        emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_DEREF);\n    }\n}\n\n#endif // MICROPY_ENABLE_COMPILER\n"
  },
  {
    "path": "py/emitglue.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n// This code glues the code emitters to the runtime.\n\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/emitglue.h\"\n#include \"py/runtime0.h\"\n#include \"py/bc.h\"\n#include \"py/profile.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_PRINT (1)\n#define WRITE_CODE (1)\n#define DEBUG_printf DEBUG_printf\n#define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__)\n#else // don't print debugging info\n#define DEBUG_printf(...) (void)0\n#define DEBUG_OP_printf(...) (void)0\n#endif\n\n#if MICROPY_DEBUG_PRINTERS\nmp_uint_t mp_verbose_flag = 0;\n#endif\n\nmp_raw_code_t *mp_emit_glue_new_raw_code(void) {\n    mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1);\n    rc->kind = MP_CODE_RESERVED;\n    #if MICROPY_PY_SYS_SETTRACE\n    rc->line_of_definition = 0;\n    #endif\n    return rc;\n}\n\nvoid mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,\n    #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS\n    size_t len,\n    #endif\n    const mp_uint_t *const_table,\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    uint16_t n_obj, uint16_t n_raw_code,\n    #endif\n    mp_uint_t scope_flags) {\n\n    rc->kind = MP_CODE_BYTECODE;\n    rc->scope_flags = scope_flags;\n    rc->fun_data = code;\n    rc->const_table = const_table;\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    rc->fun_data_len = len;\n    rc->n_obj = n_obj;\n    rc->n_raw_code = n_raw_code;\n    #endif\n\n    #if MICROPY_PY_SYS_SETTRACE\n    mp_bytecode_prelude_t *prelude = &rc->prelude;\n    mp_prof_extract_prelude(code, prelude);\n    #endif\n\n    #ifdef DEBUG_PRINT\n    #if !MICROPY_DEBUG_PRINTERS\n    const size_t len = 0;\n    #endif\n    DEBUG_printf(\"assign byte code: code=%p len=\" UINT_FMT \" flags=%x\\n\", code, len, (uint)scope_flags);\n    #endif\n    #if MICROPY_DEBUG_PRINTERS\n    if (mp_verbose_flag >= 2) {\n        mp_bytecode_print(&mp_plat_print, rc, code, len, const_table);\n    }\n    #endif\n}\n\n#if MICROPY_EMIT_MACHINE_CODE\nvoid 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,\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    uint16_t prelude_offset,\n    uint16_t n_obj, uint16_t n_raw_code,\n    uint16_t n_qstr, mp_qstr_link_entry_t *qstr_link,\n    #endif\n    mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig) {\n\n    assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);\n\n    rc->kind = kind;\n    rc->scope_flags = scope_flags;\n    rc->n_pos_args = n_pos_args;\n    rc->fun_data = fun_data;\n    rc->const_table = const_table;\n    rc->type_sig = type_sig;\n\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    rc->fun_data_len = fun_len;\n    rc->prelude_offset = prelude_offset;\n    rc->n_obj = n_obj;\n    rc->n_raw_code = n_raw_code;\n    rc->n_qstr = n_qstr;\n    rc->qstr_link = qstr_link;\n    #endif\n\n    #ifdef DEBUG_PRINT\n    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);\n    for (mp_uint_t i = 0; i < fun_len; i++) {\n        if (i > 0 && i % 16 == 0) {\n            DEBUG_printf(\"\\n\");\n        }\n        DEBUG_printf(\" %02x\", ((byte *)fun_data)[i]);\n    }\n    DEBUG_printf(\"\\n\");\n\n    #ifdef WRITE_CODE\n    FILE *fp_write_code = fopen(\"out-code\", \"wb\");\n    fwrite(fun_data, fun_len, 1, fp_write_code);\n    fclose(fp_write_code);\n    #endif\n    #else\n    (void)fun_len;\n    #endif\n}\n#endif\n\nmp_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) {\n    DEBUG_OP_printf(\"make_function_from_raw_code %p\\n\", rc);\n    assert(rc != NULL);\n\n    // def_args must be MP_OBJ_NULL or a tuple\n    assert(def_args == MP_OBJ_NULL || mp_obj_is_type(def_args, &mp_type_tuple));\n\n    // def_kw_args must be MP_OBJ_NULL or a dict\n    assert(def_kw_args == MP_OBJ_NULL || mp_obj_is_type(def_kw_args, &mp_type_dict));\n\n    // make the function, depending on the raw code kind\n    mp_obj_t fun;\n    switch (rc->kind) {\n        #if MICROPY_EMIT_NATIVE\n        case MP_CODE_NATIVE_PY:\n        case MP_CODE_NATIVE_VIPER:\n            fun = mp_obj_new_fun_native(def_args, def_kw_args, rc->fun_data, rc->const_table);\n            // Check for a generator function, and if so change the type of the object\n            if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {\n                ((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_native_gen_wrap;\n            }\n            break;\n        #endif\n        #if MICROPY_EMIT_INLINE_ASM\n        case MP_CODE_NATIVE_ASM:\n            fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->fun_data, rc->type_sig);\n            break;\n        #endif\n        default:\n            // rc->kind should always be set and BYTECODE is the only remaining case\n            assert(rc->kind == MP_CODE_BYTECODE);\n            fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->fun_data, rc->const_table);\n            // check for generator functions and if so change the type of the object\n            if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {\n                ((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap;\n            }\n\n            #if MICROPY_PY_SYS_SETTRACE\n            mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t *)MP_OBJ_TO_PTR(fun);\n            self_fun->rc = rc;\n            #endif\n\n            break;\n    }\n\n    return fun;\n}\n\nmp_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) {\n    DEBUG_OP_printf(\"make_closure_from_raw_code %p \" UINT_FMT \" %p\\n\", rc, n_closed_over, args);\n    // make function object\n    mp_obj_t ffun;\n    if (n_closed_over & 0x100) {\n        // default positional and keyword args given\n        ffun = mp_make_function_from_raw_code(rc, args[0], args[1]);\n    } else {\n        // default positional and keyword args not given\n        ffun = mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL);\n    }\n    // wrap function in closure object\n    return mp_obj_new_closure(ffun, n_closed_over & 0xff, args + ((n_closed_over >> 7) & 2));\n}\n"
  },
  {
    "path": "py/emitglue.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_EMITGLUE_H\n#define MICROPY_INCLUDED_PY_EMITGLUE_H\n\n#include \"py/obj.h\"\n#include \"py/bc.h\"\n\n// These variables and functions glue the code emitters to the runtime.\n\n// These must fit in 8 bits; see scope.h\nenum {\n    MP_EMIT_OPT_NONE,\n    MP_EMIT_OPT_BYTECODE,\n    MP_EMIT_OPT_NATIVE_PYTHON,\n    MP_EMIT_OPT_VIPER,\n    MP_EMIT_OPT_ASM,\n};\n\ntypedef enum {\n    MP_CODE_UNUSED,\n    MP_CODE_RESERVED,\n    MP_CODE_BYTECODE,\n    MP_CODE_NATIVE_PY,\n    MP_CODE_NATIVE_VIPER,\n    MP_CODE_NATIVE_ASM,\n} mp_raw_code_kind_t;\n\ntypedef struct _mp_qstr_link_entry_t {\n    uint16_t off;\n    uint16_t qst;\n} mp_qstr_link_entry_t;\n\ntypedef struct _mp_raw_code_t {\n    mp_uint_t kind : 3; // of type mp_raw_code_kind_t\n    mp_uint_t scope_flags : 7;\n    mp_uint_t n_pos_args : 11;\n    const void *fun_data;\n    const mp_uint_t *const_table;\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    size_t fun_data_len;\n    uint16_t n_obj;\n    uint16_t n_raw_code;\n    #if MICROPY_PY_SYS_SETTRACE\n    mp_bytecode_prelude_t prelude;\n    // line_of_definition is a Python source line where the raw_code was\n    // created e.g. MP_BC_MAKE_FUNCTION. This is different from lineno info\n    // stored in prelude, which provides line number for first statement of\n    // a function. Required to properly implement \"call\" trace event.\n    mp_uint_t line_of_definition;\n    #endif\n    #if MICROPY_EMIT_MACHINE_CODE\n    uint16_t prelude_offset;\n    uint16_t n_qstr;\n    mp_qstr_link_entry_t *qstr_link;\n    #endif\n    #endif\n    #if MICROPY_EMIT_MACHINE_CODE\n    mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc\n    #endif\n} mp_raw_code_t;\n\nmp_raw_code_t *mp_emit_glue_new_raw_code(void);\n\nvoid mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,\n    #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS\n    size_t len,\n    #endif\n    const mp_uint_t *const_table,\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    uint16_t n_obj, uint16_t n_raw_code,\n    #endif\n    mp_uint_t scope_flags);\n\nvoid mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len,\n    const mp_uint_t *const_table,\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    uint16_t prelude_offset,\n    uint16_t n_obj, uint16_t n_raw_code,\n    uint16_t n_qstr, mp_qstr_link_entry_t *qstr_link,\n    #endif\n    mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig);\n\nmp_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);\nmp_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);\n\n#endif // MICROPY_INCLUDED_PY_EMITGLUE_H\n"
  },
  {
    "path": "py/emitinlinethumb.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n#include <stdarg.h>\n#include <assert.h>\n\n#include \"py/emit.h\"\n#include \"py/asmthumb.h\"\n\n#if MICROPY_EMIT_INLINE_THUMB\n\ntypedef enum {\n// define rules with a compile function\n#define DEF_RULE(rule, comp, kind, ...) PN_##rule,\n#define DEF_RULE_NC(rule, kind, ...)\n    #include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n    PN_const_object, // special node for a constant, generic Python object\n// define rules without a compile function\n#define DEF_RULE(rule, comp, kind, ...)\n#define DEF_RULE_NC(rule, kind, ...) PN_##rule,\n    #include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n} pn_kind_t;\n\nstruct _emit_inline_asm_t {\n    asm_thumb_t as;\n    uint16_t pass;\n    mp_obj_t *error_slot;\n    mp_uint_t max_num_labels;\n    qstr *label_lookup;\n};\n\nSTATIC void emit_inline_thumb_error_msg(emit_inline_asm_t *emit, mp_rom_error_text_t msg) {\n    *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);\n}\n\nSTATIC void emit_inline_thumb_error_exc(emit_inline_asm_t *emit, mp_obj_t exc) {\n    *emit->error_slot = exc;\n}\n\nemit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels) {\n    emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t);\n    memset(&emit->as, 0, sizeof(emit->as));\n    mp_asm_base_init(&emit->as.base, max_num_labels);\n    emit->max_num_labels = max_num_labels;\n    emit->label_lookup = m_new(qstr, max_num_labels);\n    return emit;\n}\n\nvoid emit_inline_thumb_free(emit_inline_asm_t *emit) {\n    m_del(qstr, emit->label_lookup, emit->max_num_labels);\n    mp_asm_base_deinit(&emit->as.base, false);\n    m_del_obj(emit_inline_asm_t, emit);\n}\n\nSTATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot) {\n    emit->pass = pass;\n    emit->error_slot = error_slot;\n    if (emit->pass == MP_PASS_CODE_SIZE) {\n        memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr));\n    }\n    mp_asm_base_start_pass(&emit->as.base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE);\n    asm_thumb_entry(&emit->as, 0);\n}\n\nSTATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) {\n    asm_thumb_exit(&emit->as);\n    asm_thumb_end_pass(&emit->as);\n}\n\nSTATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) {\n    if (n_params > 4) {\n        emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT(\"can only have up to 4 parameters to Thumb assembly\"));\n        return 0;\n    }\n    for (mp_uint_t i = 0; i < n_params; i++) {\n        if (!MP_PARSE_NODE_IS_ID(pn_params[i])) {\n            emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT(\"parameters must be registers in sequence r0 to r3\"));\n            return 0;\n        }\n        const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));\n        if (!(strlen(p) == 2 && p[0] == 'r' && (mp_uint_t)p[1] == '0' + i)) {\n            emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT(\"parameters must be registers in sequence r0 to r3\"));\n            return 0;\n        }\n    }\n    return n_params;\n}\n\nSTATIC bool emit_inline_thumb_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) {\n    assert(label_num < emit->max_num_labels);\n    if (emit->pass == MP_PASS_CODE_SIZE) {\n        // check for duplicate label on first pass\n        for (uint i = 0; i < emit->max_num_labels; i++) {\n            if (emit->label_lookup[i] == label_id) {\n                return false;\n            }\n        }\n    }\n    emit->label_lookup[label_num] = label_id;\n    mp_asm_base_label_assign(&emit->as.base, label_num);\n    return true;\n}\n\ntypedef struct _reg_name_t { byte reg;\n                             byte name[3];\n} reg_name_t;\nSTATIC const reg_name_t reg_name_table[] = {\n    {0, \"r0\\0\"},\n    {1, \"r1\\0\"},\n    {2, \"r2\\0\"},\n    {3, \"r3\\0\"},\n    {4, \"r4\\0\"},\n    {5, \"r5\\0\"},\n    {6, \"r6\\0\"},\n    {7, \"r7\\0\"},\n    {8, \"r8\\0\"},\n    {9, \"r9\\0\"},\n    {10, \"r10\"},\n    {11, \"r11\"},\n    {12, \"r12\"},\n    {13, \"r13\"},\n    {14, \"r14\"},\n    {15, \"r15\"},\n    {10, \"sl\\0\"},\n    {11, \"fp\\0\"},\n    {13, \"sp\\0\"},\n    {14, \"lr\\0\"},\n    {15, \"pc\\0\"},\n};\n\n#define MAX_SPECIAL_REGISTER_NAME_LENGTH 7\ntypedef struct _special_reg_name_t { byte reg;\n                                     char name[MAX_SPECIAL_REGISTER_NAME_LENGTH + 1];\n} special_reg_name_t;\nSTATIC const special_reg_name_t special_reg_name_table[] = {\n    {5, \"IPSR\"},\n    {17, \"BASEPRI\"},\n};\n\n// return empty string in case of error, so we can attempt to parse the string\n// without a special check if it was in fact a string\nSTATIC const char *get_arg_str(mp_parse_node_t pn) {\n    if (MP_PARSE_NODE_IS_ID(pn)) {\n        qstr qst = MP_PARSE_NODE_LEAF_ARG(pn);\n        return qstr_str(qst);\n    } else {\n        return \"\";\n    }\n}\n\nSTATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, mp_uint_t max_reg) {\n    const char *reg_str = get_arg_str(pn);\n    for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) {\n        const reg_name_t *r = &reg_name_table[i];\n        if (reg_str[0] == r->name[0]\n            && reg_str[1] == r->name[1]\n            && reg_str[2] == r->name[2]\n            && (reg_str[2] == '\\0' || reg_str[3] == '\\0')) {\n            if (r->reg > max_reg) {\n                emit_inline_thumb_error_exc(emit,\n                    mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,\n                        MP_ERROR_TEXT(\"'%s' expects at most r%d\"), op, max_reg));\n                return 0;\n            } else {\n                return r->reg;\n            }\n        }\n    }\n    emit_inline_thumb_error_exc(emit,\n        mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,\n            MP_ERROR_TEXT(\"'%s' expects a register\"), op));\n    return 0;\n}\n\nSTATIC mp_uint_t get_arg_special_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {\n    const char *reg_str = get_arg_str(pn);\n    for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(special_reg_name_table); i++) {\n        const special_reg_name_t *r = &special_reg_name_table[i];\n        if (strcmp(r->name, reg_str) == 0) {\n            return r->reg;\n        }\n    }\n    emit_inline_thumb_error_exc(emit,\n        mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,\n            MP_ERROR_TEXT(\"'%s' expects a special register\"), op));\n    return 0;\n}\n\n#if MICROPY_EMIT_INLINE_THUMB_FLOAT\nSTATIC mp_uint_t get_arg_vfpreg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {\n    const char *reg_str = get_arg_str(pn);\n    if (reg_str[0] == 's' && reg_str[1] != '\\0') {\n        mp_uint_t regno = 0;\n        for (++reg_str; *reg_str; ++reg_str) {\n            mp_uint_t v = *reg_str;\n            if (!('0' <= v && v <= '9')) {\n                goto malformed;\n            }\n            regno = 10 * regno + v - '0';\n        }\n        if (regno > 31) {\n            emit_inline_thumb_error_exc(emit,\n                mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,\n                    MP_ERROR_TEXT(\"'%s' expects at most r%d\"), op, 31));\n            return 0;\n        } else {\n            return regno;\n        }\n    }\nmalformed:\n    emit_inline_thumb_error_exc(emit,\n        mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,\n            MP_ERROR_TEXT(\"'%s' expects an FPU register\"), op));\n    return 0;\n}\n#endif\n\nSTATIC mp_uint_t get_arg_reglist(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {\n    // a register list looks like {r0, r1, r2} and is parsed as a Python set\n\n    if (!MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_brace)) {\n        goto bad_arg;\n    }\n\n    mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n    assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 1); // should always be\n    pn = pns->nodes[0];\n\n    mp_uint_t reglist = 0;\n\n    if (MP_PARSE_NODE_IS_ID(pn)) {\n        // set with one element\n        reglist |= 1 << get_arg_reg(emit, op, pn, 15);\n    } else if (MP_PARSE_NODE_IS_STRUCT(pn)) {\n        pns = (mp_parse_node_struct_t *)pn;\n        if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) {\n            assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should succeed\n            mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1];\n            if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_dictorsetmaker_list) {\n                // set with multiple elements\n\n                // get first element of set (we rely on get_arg_reg to catch syntax errors)\n                reglist |= 1 << get_arg_reg(emit, op, pns->nodes[0], 15);\n\n                // get tail elements (2nd, 3rd, ...)\n                mp_parse_node_t *nodes;\n                int n = mp_parse_node_extract_list(&pns1->nodes[0], PN_dictorsetmaker_list2, &nodes);\n\n                // process rest of elements\n                for (int i = 0; i < n; i++) {\n                    reglist |= 1 << get_arg_reg(emit, op, nodes[i], 15);\n                }\n            } else {\n                goto bad_arg;\n            }\n        } else {\n            goto bad_arg;\n        }\n    } else {\n        goto bad_arg;\n    }\n\n    return reglist;\n\nbad_arg:\n    emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"'%s' expects {r0, r1, ...}\"), op));\n    return 0;\n}\n\nSTATIC uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, uint32_t fit_mask) {\n    mp_obj_t o;\n    if (!mp_parse_node_get_int_maybe(pn, &o)) {\n        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"'%s' expects an integer\"), op));\n        return 0;\n    }\n    uint32_t i = mp_obj_get_int_truncated(o);\n    if ((i & (~fit_mask)) != 0) {\n        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"'%s' integer 0x%x doesn't fit in mask 0x%x\"), op, i, fit_mask));\n        return 0;\n    }\n    return i;\n}\n\nSTATIC 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) {\n    if (!MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_bracket)) {\n        goto bad_arg;\n    }\n    mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n    if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {\n        goto bad_arg;\n    }\n    pns = (mp_parse_node_struct_t *)pns->nodes[0];\n    if (MP_PARSE_NODE_STRUCT_NUM_NODES(pns) != 2) {\n        goto bad_arg;\n    }\n\n    *pn_base = pns->nodes[0];\n    *pn_offset = pns->nodes[1];\n    return true;\n\nbad_arg:\n    emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"'%s' expects an address of the form [a, b]\"), op));\n    return false;\n}\n\nSTATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {\n    if (!MP_PARSE_NODE_IS_ID(pn)) {\n        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"'%s' expects a label\"), op));\n        return 0;\n    }\n    qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn);\n    for (uint i = 0; i < emit->max_num_labels; i++) {\n        if (emit->label_lookup[i] == label_qstr) {\n            return i;\n        }\n    }\n    // only need to have the labels on the last pass\n    if (emit->pass == MP_PASS_EMIT) {\n        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"label '%q' not defined\"), label_qstr));\n    }\n    return 0;\n}\n\ntypedef struct _cc_name_t { byte cc;\n                            byte name[2];\n} cc_name_t;\nSTATIC const cc_name_t cc_name_table[] = {\n    { ASM_THUMB_CC_EQ, \"eq\" },\n    { ASM_THUMB_CC_NE, \"ne\" },\n    { ASM_THUMB_CC_CS, \"cs\" },\n    { ASM_THUMB_CC_CC, \"cc\" },\n    { ASM_THUMB_CC_MI, \"mi\" },\n    { ASM_THUMB_CC_PL, \"pl\" },\n    { ASM_THUMB_CC_VS, \"vs\" },\n    { ASM_THUMB_CC_VC, \"vc\" },\n    { ASM_THUMB_CC_HI, \"hi\" },\n    { ASM_THUMB_CC_LS, \"ls\" },\n    { ASM_THUMB_CC_GE, \"ge\" },\n    { ASM_THUMB_CC_LT, \"lt\" },\n    { ASM_THUMB_CC_GT, \"gt\" },\n    { ASM_THUMB_CC_LE, \"le\" },\n};\n\ntypedef struct _format_4_op_t { byte op;\n                                char name[3];\n} format_4_op_t;\n#define X(x) (((x) >> 4) & 0xff) // only need 1 byte to distinguish these ops\nSTATIC const format_4_op_t format_4_op_table[] = {\n    { X(ASM_THUMB_FORMAT_4_EOR), \"eor\" },\n    { X(ASM_THUMB_FORMAT_4_LSL), \"lsl\" },\n    { X(ASM_THUMB_FORMAT_4_LSR), \"lsr\" },\n    { X(ASM_THUMB_FORMAT_4_ASR), \"asr\" },\n    { X(ASM_THUMB_FORMAT_4_ADC), \"adc\" },\n    { X(ASM_THUMB_FORMAT_4_SBC), \"sbc\" },\n    { X(ASM_THUMB_FORMAT_4_ROR), \"ror\" },\n    { X(ASM_THUMB_FORMAT_4_TST), \"tst\" },\n    { X(ASM_THUMB_FORMAT_4_NEG), \"neg\" },\n    { X(ASM_THUMB_FORMAT_4_CMP), \"cmp\" },\n    { X(ASM_THUMB_FORMAT_4_CMN), \"cmn\" },\n    { X(ASM_THUMB_FORMAT_4_ORR), \"orr\" },\n    { X(ASM_THUMB_FORMAT_4_MUL), \"mul\" },\n    { X(ASM_THUMB_FORMAT_4_BIC), \"bic\" },\n    { X(ASM_THUMB_FORMAT_4_MVN), \"mvn\" },\n};\n#undef X\n\n// name is actually a qstr, which should fit in 16 bits\ntypedef struct _format_9_10_op_t { uint16_t op;\n                                   uint16_t name;\n} format_9_10_op_t;\n#define X(x) (x)\nSTATIC const format_9_10_op_t format_9_10_op_table[] = {\n    { X(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER), MP_QSTR_ldr },\n    { X(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER), MP_QSTR_ldrb },\n    { X(ASM_THUMB_FORMAT_10_LDRH), MP_QSTR_ldrh },\n    { X(ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER), MP_QSTR_str },\n    { X(ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER), MP_QSTR_strb },\n    { X(ASM_THUMB_FORMAT_10_STRH), MP_QSTR_strh },\n};\n#undef X\n\n#if MICROPY_EMIT_INLINE_THUMB_FLOAT\n// actual opcodes are: 0xee00 | op.hi_nibble, 0x0a00 | op.lo_nibble\ntypedef struct _format_vfp_op_t { byte op;\n                                  char name[3];\n} format_vfp_op_t;\nSTATIC const format_vfp_op_t format_vfp_op_table[] = {\n    { 0x30, \"add\" },\n    { 0x34, \"sub\" },\n    { 0x20, \"mul\" },\n    { 0x80, \"div\" },\n};\n#endif\n\n// shorthand alias for whether we allow ARMv7-M instructions\n#define ARMV7M MICROPY_EMIT_INLINE_THUMB_ARMV7M\n\nSTATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) {\n    // TODO perhaps make two tables:\n    // one_args =\n    // \"b\", LAB, asm_thumb_b_n,\n    // \"bgt\", LAB, asm_thumb_bgt_n,\n    // two_args =\n    // \"movs\", RLO, I8, asm_thumb_movs_reg_i8\n    // \"movw\", REG, REG, asm_thumb_movw_reg_i16\n    // three_args =\n    // \"subs\", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3\n\n    size_t op_len;\n    const char *op_str = (const char *)qstr_data(op, &op_len);\n\n    #if MICROPY_EMIT_INLINE_THUMB_FLOAT\n    if (op_str[0] == 'v') {\n        // floating point operations\n        if (n_args == 2) {\n            mp_uint_t op_code = 0x0ac0, op_code_hi;\n            if (op == MP_QSTR_vcmp) {\n                op_code_hi = 0xeeb4;\n            op_vfp_twoargs:;\n                mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]);\n                mp_uint_t vm = get_arg_vfpreg(emit, op_str, pn_args[1]);\n                asm_thumb_op32(&emit->as,\n                    op_code_hi | ((vd & 1) << 6),\n                    op_code | ((vd & 0x1e) << 11) | ((vm & 1) << 5) | (vm & 0x1e) >> 1);\n            } else if (op == MP_QSTR_vsqrt) {\n                op_code_hi = 0xeeb1;\n                goto op_vfp_twoargs;\n            } else if (op == MP_QSTR_vneg) {\n                op_code_hi = 0xeeb1;\n                op_code = 0x0a40;\n                goto op_vfp_twoargs;\n            } else if (op == MP_QSTR_vcvt_f32_s32) {\n                op_code_hi = 0xeeb8; // int to float\n                goto op_vfp_twoargs;\n            } else if (op == MP_QSTR_vcvt_s32_f32) {\n                op_code_hi = 0xeebd; // float to int\n                goto op_vfp_twoargs;\n            } else if (op == MP_QSTR_vmrs) {\n                mp_uint_t reg_dest;\n                const char *reg_str0 = get_arg_str(pn_args[0]);\n                if (strcmp(reg_str0, \"APSR_nzcv\") == 0) {\n                    reg_dest = 15;\n                } else {\n                    reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);\n                }\n                const char *reg_str1 = get_arg_str(pn_args[1]);\n                if (strcmp(reg_str1, \"FPSCR\") == 0) {\n                    // FP status to ARM reg\n                    asm_thumb_op32(&emit->as, 0xeef1, 0x0a10 | (reg_dest << 12));\n                } else {\n                    goto unknown_op;\n                }\n            } else if (op == MP_QSTR_vmov) {\n                op_code_hi = 0xee00;\n                mp_uint_t r_arm, vm;\n                const char *reg_str = get_arg_str(pn_args[0]);\n                if (reg_str[0] == 'r') {\n                    r_arm = get_arg_reg(emit, op_str, pn_args[0], 15);\n                    vm = get_arg_vfpreg(emit, op_str, pn_args[1]);\n                    op_code_hi |= 0x10;\n                } else {\n                    vm = get_arg_vfpreg(emit, op_str, pn_args[0]);\n                    r_arm = get_arg_reg(emit, op_str, pn_args[1], 15);\n                }\n                asm_thumb_op32(&emit->as,\n                    op_code_hi | ((vm & 0x1e) >> 1),\n                    0x0a10 | (r_arm << 12) | ((vm & 1) << 7));\n            } else if (op == MP_QSTR_vldr) {\n                op_code_hi = 0xed90;\n            op_vldr_vstr:;\n                mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]);\n                mp_parse_node_t pn_base, pn_offset;\n                if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) {\n                    mp_uint_t rlo_base = get_arg_reg(emit, op_str, pn_base, 7);\n                    mp_uint_t i8;\n                    i8 = get_arg_i(emit, op_str, pn_offset, 0x3fc) >> 2;\n                    asm_thumb_op32(&emit->as,\n                        op_code_hi | rlo_base | ((vd & 1) << 6),\n                        0x0a00 | ((vd & 0x1e) << 11) | i8);\n                }\n            } else if (op == MP_QSTR_vstr) {\n                op_code_hi = 0xed80;\n                goto op_vldr_vstr;\n            } else {\n                goto unknown_op;\n            }\n        } else if (n_args == 3) {\n            // search table for arith ops\n            for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_vfp_op_table); i++) {\n                if (strncmp(op_str + 1, format_vfp_op_table[i].name, 3) == 0 && op_str[4] == '\\0') {\n                    mp_uint_t op_code_hi = 0xee00 | (format_vfp_op_table[i].op & 0xf0);\n                    mp_uint_t op_code = 0x0a00 | ((format_vfp_op_table[i].op & 0x0f) << 4);\n                    mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]);\n                    mp_uint_t vn = get_arg_vfpreg(emit, op_str, pn_args[1]);\n                    mp_uint_t vm = get_arg_vfpreg(emit, op_str, pn_args[2]);\n                    asm_thumb_op32(&emit->as,\n                        op_code_hi | ((vd & 1) << 6) | (vn >> 1),\n                        op_code | (vm >> 1) | ((vm & 1) << 5) | ((vd & 0x1e) << 11) | ((vn & 1) << 7));\n                    return;\n                }\n            }\n            goto unknown_op;\n        } else {\n            goto unknown_op;\n        }\n        return;\n    }\n    #endif\n\n    if (n_args == 0) {\n        if (op == MP_QSTR_nop) {\n            asm_thumb_op16(&emit->as, ASM_THUMB_OP_NOP);\n        } else if (op == MP_QSTR_wfi) {\n            asm_thumb_op16(&emit->as, ASM_THUMB_OP_WFI);\n        } else {\n            goto unknown_op;\n        }\n\n    } else if (n_args == 1) {\n        if (op == MP_QSTR_b) {\n            int label_num = get_arg_label(emit, op_str, pn_args[0]);\n            if (!asm_thumb_b_n_label(&emit->as, label_num)) {\n                goto branch_not_in_range;\n            }\n        } else if (op == MP_QSTR_bl) {\n            int label_num = get_arg_label(emit, op_str, pn_args[0]);\n            if (!asm_thumb_bl_label(&emit->as, label_num)) {\n                goto branch_not_in_range;\n            }\n        } else if (op == MP_QSTR_bx) {\n            mp_uint_t r = get_arg_reg(emit, op_str, pn_args[0], 15);\n            asm_thumb_op16(&emit->as, 0x4700 | (r << 3));\n        } else if (op_str[0] == 'b' && (op_len == 3\n                                        || (op_len == 5 && op_str[3] == '_'\n                                            && (op_str[4] == 'n' || (ARMV7M && op_str[4] == 'w'))))) {\n            mp_uint_t cc = -1;\n            for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) {\n                if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) {\n                    cc = cc_name_table[i].cc;\n                }\n            }\n            if (cc == (mp_uint_t)-1) {\n                goto unknown_op;\n            }\n            int label_num = get_arg_label(emit, op_str, pn_args[0]);\n            if (!asm_thumb_bcc_nw_label(&emit->as, cc, label_num, op_len == 5 && op_str[4] == 'w')) {\n                goto branch_not_in_range;\n            }\n        } else if (ARMV7M && op_str[0] == 'i' && op_str[1] == 't') {\n            const char *arg_str = get_arg_str(pn_args[0]);\n            mp_uint_t cc = -1;\n            for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) {\n                if (arg_str[0] == cc_name_table[i].name[0]\n                    && arg_str[1] == cc_name_table[i].name[1]\n                    && arg_str[2] == '\\0') {\n                    cc = cc_name_table[i].cc;\n                    break;\n                }\n            }\n            if (cc == (mp_uint_t)-1) {\n                goto unknown_op;\n            }\n            const char *os = op_str + 2;\n            while (*os != '\\0') {\n                os++;\n            }\n            if (os > op_str + 5) {\n                goto unknown_op;\n            }\n            mp_uint_t it_mask = 8;\n            while (--os >= op_str + 2) {\n                it_mask >>= 1;\n                if (*os == 't') {\n                    it_mask |= (cc & 1) << 3;\n                } else if (*os == 'e') {\n                    it_mask |= ((~cc) & 1) << 3;\n                } else {\n                    goto unknown_op;\n                }\n            }\n            asm_thumb_it_cc(&emit->as, cc, it_mask);\n        } else if (op == MP_QSTR_cpsid) {\n            // TODO check pn_args[0] == i\n            asm_thumb_op16(&emit->as, ASM_THUMB_OP_CPSID_I);\n        } else if (op == MP_QSTR_cpsie) {\n            // TODO check pn_args[0] == i\n            asm_thumb_op16(&emit->as, ASM_THUMB_OP_CPSIE_I);\n        } else if (op == MP_QSTR_push) {\n            mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]);\n            if ((reglist & 0xff00) == 0) {\n                asm_thumb_op16(&emit->as, 0xb400 | reglist);\n            } else {\n                if (!ARMV7M) {\n                    goto unknown_op;\n                }\n                asm_thumb_op32(&emit->as, 0xe92d, reglist);\n            }\n        } else if (op == MP_QSTR_pop) {\n            mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]);\n            if ((reglist & 0xff00) == 0) {\n                asm_thumb_op16(&emit->as, 0xbc00 | reglist);\n            } else {\n                if (!ARMV7M) {\n                    goto unknown_op;\n                }\n                asm_thumb_op32(&emit->as, 0xe8bd, reglist);\n            }\n        } else {\n            goto unknown_op;\n        }\n\n    } else if (n_args == 2) {\n        if (MP_PARSE_NODE_IS_ID(pn_args[1])) {\n            // second arg is a register (or should be)\n            mp_uint_t op_code, op_code_hi;\n            if (op == MP_QSTR_mov) {\n                mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);\n                mp_uint_t reg_src = get_arg_reg(emit, op_str, pn_args[1], 15);\n                asm_thumb_mov_reg_reg(&emit->as, reg_dest, reg_src);\n            } else if (ARMV7M && op == MP_QSTR_clz) {\n                op_code_hi = 0xfab0;\n                op_code = 0xf080;\n                mp_uint_t rd, rm;\n            op_clz_rbit:\n                rd = get_arg_reg(emit, op_str, pn_args[0], 15);\n                rm = get_arg_reg(emit, op_str, pn_args[1], 15);\n                asm_thumb_op32(&emit->as, op_code_hi | rm, op_code | (rd << 8) | rm);\n            } else if (ARMV7M && op == MP_QSTR_rbit) {\n                op_code_hi = 0xfa90;\n                op_code = 0xf0a0;\n                goto op_clz_rbit;\n            } else if (ARMV7M && op == MP_QSTR_mrs) {\n                mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 12);\n                mp_uint_t reg_src = get_arg_special_reg(emit, op_str, pn_args[1]);\n                asm_thumb_op32(&emit->as, 0xf3ef, 0x8000 | (reg_dest << 8) | reg_src);\n            } else {\n                if (op == MP_QSTR_and_) {\n                    op_code = ASM_THUMB_FORMAT_4_AND;\n                    mp_uint_t reg_dest, reg_src;\n                op_format_4:\n                    reg_dest = get_arg_reg(emit, op_str, pn_args[0], 7);\n                    reg_src = get_arg_reg(emit, op_str, pn_args[1], 7);\n                    asm_thumb_format_4(&emit->as, op_code, reg_dest, reg_src);\n                    return;\n                }\n                // search table for ALU ops\n                for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_4_op_table); i++) {\n                    if (strncmp(op_str, format_4_op_table[i].name, 3) == 0 && op_str[3] == '\\0') {\n                        op_code = 0x4000 | (format_4_op_table[i].op << 4);\n                        goto op_format_4;\n                    }\n                }\n                goto unknown_op;\n            }\n        } else {\n            // second arg is not a register\n            mp_uint_t op_code;\n            if (op == MP_QSTR_mov) {\n                op_code = ASM_THUMB_FORMAT_3_MOV;\n                mp_uint_t rlo_dest, i8_src;\n            op_format_3:\n                rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);\n                i8_src = get_arg_i(emit, op_str, pn_args[1], 0xff);\n                asm_thumb_format_3(&emit->as, op_code, rlo_dest, i8_src);\n            } else if (op == MP_QSTR_cmp) {\n                op_code = ASM_THUMB_FORMAT_3_CMP;\n                goto op_format_3;\n            } else if (op == MP_QSTR_add) {\n                op_code = ASM_THUMB_FORMAT_3_ADD;\n                goto op_format_3;\n            } else if (op == MP_QSTR_sub) {\n                op_code = ASM_THUMB_FORMAT_3_SUB;\n                goto op_format_3;\n            } else if (ARMV7M && op == MP_QSTR_movw) {\n                op_code = ASM_THUMB_OP_MOVW;\n                mp_uint_t reg_dest;\n            op_movw_movt:\n                reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);\n                int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff);\n                asm_thumb_mov_reg_i16(&emit->as, op_code, reg_dest, i_src);\n            } else if (ARMV7M && op == MP_QSTR_movt) {\n                op_code = ASM_THUMB_OP_MOVT;\n                goto op_movw_movt;\n            } else if (ARMV7M && op == MP_QSTR_movwt) {\n                // this is a convenience instruction\n                mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);\n                uint32_t i_src = get_arg_i(emit, op_str, pn_args[1], 0xffffffff);\n                asm_thumb_mov_reg_i16(&emit->as, ASM_THUMB_OP_MOVW, reg_dest, i_src & 0xffff);\n                asm_thumb_mov_reg_i16(&emit->as, ASM_THUMB_OP_MOVT, reg_dest, (i_src >> 16) & 0xffff);\n            } else if (ARMV7M && op == MP_QSTR_ldrex) {\n                mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15);\n                mp_parse_node_t pn_base, pn_offset;\n                if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) {\n                    mp_uint_t r_base = get_arg_reg(emit, op_str, pn_base, 15);\n                    mp_uint_t i8 = get_arg_i(emit, op_str, pn_offset, 0xff) >> 2;\n                    asm_thumb_op32(&emit->as, 0xe850 | r_base, 0x0f00 | (r_dest << 12) | i8);\n                }\n            } else {\n                // search table for ldr/str instructions\n                for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_9_10_op_table); i++) {\n                    if (op == format_9_10_op_table[i].name) {\n                        op_code = format_9_10_op_table[i].op;\n                        mp_parse_node_t pn_base, pn_offset;\n                        mp_uint_t rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);\n                        if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) {\n                            mp_uint_t rlo_base = get_arg_reg(emit, op_str, pn_base, 7);\n                            mp_uint_t i5;\n                            if (op_code & ASM_THUMB_FORMAT_9_BYTE_TRANSFER) {\n                                i5 = get_arg_i(emit, op_str, pn_offset, 0x1f);\n                            } else if (op_code & ASM_THUMB_FORMAT_10_STRH) { // also catches LDRH\n                                i5 = get_arg_i(emit, op_str, pn_offset, 0x3e) >> 1;\n                            } else {\n                                i5 = get_arg_i(emit, op_str, pn_offset, 0x7c) >> 2;\n                            }\n                            asm_thumb_format_9_10(&emit->as, op_code, rlo_dest, rlo_base, i5);\n                            return;\n                        }\n                        break;\n                    }\n                }\n                goto unknown_op;\n            }\n        }\n\n    } else if (n_args == 3) {\n        mp_uint_t op_code;\n        if (op == MP_QSTR_lsl) {\n            op_code = ASM_THUMB_FORMAT_1_LSL;\n            mp_uint_t rlo_dest, rlo_src, i5;\n        op_format_1:\n            rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);\n            rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7);\n            i5 = get_arg_i(emit, op_str, pn_args[2], 0x1f);\n            asm_thumb_format_1(&emit->as, op_code, rlo_dest, rlo_src, i5);\n        } else if (op == MP_QSTR_lsr) {\n            op_code = ASM_THUMB_FORMAT_1_LSR;\n            goto op_format_1;\n        } else if (op == MP_QSTR_asr) {\n            op_code = ASM_THUMB_FORMAT_1_ASR;\n            goto op_format_1;\n        } else if (op == MP_QSTR_add) {\n            op_code = ASM_THUMB_FORMAT_2_ADD;\n            mp_uint_t rlo_dest, rlo_src;\n        op_format_2:\n            rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);\n            rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7);\n            int src_b;\n            if (MP_PARSE_NODE_IS_ID(pn_args[2])) {\n                op_code |= ASM_THUMB_FORMAT_2_REG_OPERAND;\n                src_b = get_arg_reg(emit, op_str, pn_args[2], 7);\n            } else {\n                op_code |= ASM_THUMB_FORMAT_2_IMM_OPERAND;\n                src_b = get_arg_i(emit, op_str, pn_args[2], 0x7);\n            }\n            asm_thumb_format_2(&emit->as, op_code, rlo_dest, rlo_src, src_b);\n        } else if (ARMV7M && op == MP_QSTR_sdiv) {\n            op_code = 0xfb90; // sdiv high part\n            mp_uint_t rd, rn, rm;\n        op_sdiv_udiv:\n            rd = get_arg_reg(emit, op_str, pn_args[0], 15);\n            rn = get_arg_reg(emit, op_str, pn_args[1], 15);\n            rm = get_arg_reg(emit, op_str, pn_args[2], 15);\n            asm_thumb_op32(&emit->as, op_code | rn, 0xf0f0 | (rd << 8) | rm);\n        } else if (ARMV7M && op == MP_QSTR_udiv) {\n            op_code = 0xfbb0; // udiv high part\n            goto op_sdiv_udiv;\n        } else if (op == MP_QSTR_sub) {\n            op_code = ASM_THUMB_FORMAT_2_SUB;\n            goto op_format_2;\n        } else if (ARMV7M && op == MP_QSTR_strex) {\n            mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15);\n            mp_uint_t r_src = get_arg_reg(emit, op_str, pn_args[1], 15);\n            mp_parse_node_t pn_base, pn_offset;\n            if (get_arg_addr(emit, op_str, pn_args[2], &pn_base, &pn_offset)) {\n                mp_uint_t r_base = get_arg_reg(emit, op_str, pn_base, 15);\n                mp_uint_t i8 = get_arg_i(emit, op_str, pn_offset, 0xff) >> 2;\n                asm_thumb_op32(&emit->as, 0xe840 | r_base, (r_src << 12) | (r_dest << 8) | i8);\n            }\n        } else {\n            goto unknown_op;\n        }\n\n    } else {\n        goto unknown_op;\n    }\n\n    return;\n\nunknown_op:\n    emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"unsupported Thumb instruction '%s' with %d arguments\"), op_str, n_args));\n    return;\n\nbranch_not_in_range:\n    emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT(\"branch not in range\"));\n    return;\n}\n\nconst emit_inline_asm_method_table_t emit_inline_thumb_method_table = {\n    #if MICROPY_DYNAMIC_COMPILER\n    emit_inline_thumb_new,\n    emit_inline_thumb_free,\n    #endif\n\n    emit_inline_thumb_start_pass,\n    emit_inline_thumb_end_pass,\n    emit_inline_thumb_count_params,\n    emit_inline_thumb_label,\n    emit_inline_thumb_op,\n};\n\n#endif // MICROPY_EMIT_INLINE_THUMB\n"
  },
  {
    "path": "py/emitinlinextensa.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n#include <stdarg.h>\n#include <assert.h>\n\n#include \"py/emit.h\"\n#include \"py/asmxtensa.h\"\n\n#if MICROPY_EMIT_INLINE_XTENSA\n\nstruct _emit_inline_asm_t {\n    asm_xtensa_t as;\n    uint16_t pass;\n    mp_obj_t *error_slot;\n    mp_uint_t max_num_labels;\n    qstr *label_lookup;\n};\n\nSTATIC void emit_inline_xtensa_error_msg(emit_inline_asm_t *emit, mp_rom_error_text_t msg) {\n    *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);\n}\n\nSTATIC void emit_inline_xtensa_error_exc(emit_inline_asm_t *emit, mp_obj_t exc) {\n    *emit->error_slot = exc;\n}\n\nemit_inline_asm_t *emit_inline_xtensa_new(mp_uint_t max_num_labels) {\n    emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t);\n    memset(&emit->as, 0, sizeof(emit->as));\n    mp_asm_base_init(&emit->as.base, max_num_labels);\n    emit->max_num_labels = max_num_labels;\n    emit->label_lookup = m_new(qstr, max_num_labels);\n    return emit;\n}\n\nvoid emit_inline_xtensa_free(emit_inline_asm_t *emit) {\n    m_del(qstr, emit->label_lookup, emit->max_num_labels);\n    mp_asm_base_deinit(&emit->as.base, false);\n    m_del_obj(emit_inline_asm_t, emit);\n}\n\nSTATIC void emit_inline_xtensa_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot) {\n    emit->pass = pass;\n    emit->error_slot = error_slot;\n    if (emit->pass == MP_PASS_CODE_SIZE) {\n        memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr));\n    }\n    mp_asm_base_start_pass(&emit->as.base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE);\n    asm_xtensa_entry(&emit->as, 0);\n}\n\nSTATIC void emit_inline_xtensa_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) {\n    asm_xtensa_exit(&emit->as);\n    asm_xtensa_end_pass(&emit->as);\n}\n\nSTATIC mp_uint_t emit_inline_xtensa_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) {\n    if (n_params > 4) {\n        emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT(\"can only have up to 4 parameters to Xtensa assembly\"));\n        return 0;\n    }\n    for (mp_uint_t i = 0; i < n_params; i++) {\n        if (!MP_PARSE_NODE_IS_ID(pn_params[i])) {\n            emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT(\"parameters must be registers in sequence a2 to a5\"));\n            return 0;\n        }\n        const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));\n        if (!(strlen(p) == 2 && p[0] == 'a' && (mp_uint_t)p[1] == '2' + i)) {\n            emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT(\"parameters must be registers in sequence a2 to a5\"));\n            return 0;\n        }\n    }\n    return n_params;\n}\n\nSTATIC bool emit_inline_xtensa_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) {\n    assert(label_num < emit->max_num_labels);\n    if (emit->pass == MP_PASS_CODE_SIZE) {\n        // check for duplicate label on first pass\n        for (uint i = 0; i < emit->max_num_labels; i++) {\n            if (emit->label_lookup[i] == label_id) {\n                return false;\n            }\n        }\n    }\n    emit->label_lookup[label_num] = label_id;\n    mp_asm_base_label_assign(&emit->as.base, label_num);\n    return true;\n}\n\ntypedef struct _reg_name_t { byte reg;\n                             byte name[3];\n} reg_name_t;\nSTATIC const reg_name_t reg_name_table[] = {\n    {0, \"a0\\0\"},\n    {1, \"a1\\0\"},\n    {2, \"a2\\0\"},\n    {3, \"a3\\0\"},\n    {4, \"a4\\0\"},\n    {5, \"a5\\0\"},\n    {6, \"a6\\0\"},\n    {7, \"a7\\0\"},\n    {8, \"a8\\0\"},\n    {9, \"a9\\0\"},\n    {10, \"a10\"},\n    {11, \"a11\"},\n    {12, \"a12\"},\n    {13, \"a13\"},\n    {14, \"a14\"},\n    {15, \"a15\"},\n};\n\n// return empty string in case of error, so we can attempt to parse the string\n// without a special check if it was in fact a string\nSTATIC const char *get_arg_str(mp_parse_node_t pn) {\n    if (MP_PARSE_NODE_IS_ID(pn)) {\n        qstr qst = MP_PARSE_NODE_LEAF_ARG(pn);\n        return qstr_str(qst);\n    } else {\n        return \"\";\n    }\n}\n\nSTATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {\n    const char *reg_str = get_arg_str(pn);\n    for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) {\n        const reg_name_t *r = &reg_name_table[i];\n        if (reg_str[0] == r->name[0]\n            && reg_str[1] == r->name[1]\n            && reg_str[2] == r->name[2]\n            && (reg_str[2] == '\\0' || reg_str[3] == '\\0')) {\n            return r->reg;\n        }\n    }\n    emit_inline_xtensa_error_exc(emit,\n        mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,\n            MP_ERROR_TEXT(\"'%s' expects a register\"), op));\n    return 0;\n}\n\nSTATIC uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, int min, int max) {\n    mp_obj_t o;\n    if (!mp_parse_node_get_int_maybe(pn, &o)) {\n        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"'%s' expects an integer\"), op));\n        return 0;\n    }\n    uint32_t i = mp_obj_get_int_truncated(o);\n    if (min != max && ((int)i < min || (int)i > max)) {\n        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"'%s' integer %d isn't within range %d..%d\"), op, i, min, max));\n        return 0;\n    }\n    return i;\n}\n\nSTATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {\n    if (!MP_PARSE_NODE_IS_ID(pn)) {\n        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"'%s' expects a label\"), op));\n        return 0;\n    }\n    qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn);\n    for (uint i = 0; i < emit->max_num_labels; i++) {\n        if (emit->label_lookup[i] == label_qstr) {\n            return i;\n        }\n    }\n    // only need to have the labels on the last pass\n    if (emit->pass == MP_PASS_EMIT) {\n        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"label '%q' not defined\"), label_qstr));\n    }\n    return 0;\n}\n\n#define RRR (0)\n#define RRI8 (1)\n#define RRI8_B (2)\n\ntypedef struct _opcode_table_3arg_t {\n    uint16_t name; // actually a qstr, which should fit in 16 bits\n    uint8_t type;\n    uint8_t a0 : 4;\n    uint8_t a1 : 4;\n} opcode_table_3arg_t;\n\nSTATIC const opcode_table_3arg_t opcode_table_3arg[] = {\n    // arithmetic opcodes: reg, reg, reg\n    {MP_QSTR_and_, RRR, 0, 1},\n    {MP_QSTR_or_, RRR, 0, 2},\n    {MP_QSTR_xor, RRR, 0, 3},\n    {MP_QSTR_add, RRR, 0, 8},\n    {MP_QSTR_sub, RRR, 0, 12},\n    {MP_QSTR_mull, RRR, 2, 8},\n\n    // load/store/addi opcodes: reg, reg, imm\n    // upper nibble of type encodes the range of the immediate arg\n    {MP_QSTR_l8ui, RRI8 | 0x10, 2, 0},\n    {MP_QSTR_l16ui, RRI8 | 0x30, 2, 1},\n    {MP_QSTR_l32i, RRI8 | 0x50, 2, 2},\n    {MP_QSTR_s8i, RRI8 | 0x10, 2, 4},\n    {MP_QSTR_s16i, RRI8 | 0x30, 2, 5},\n    {MP_QSTR_s32i, RRI8 | 0x50, 2, 6},\n    {MP_QSTR_l16si, RRI8 | 0x30, 2, 9},\n    {MP_QSTR_addi, RRI8 | 0x00, 2, 12},\n\n    // branch opcodes: reg, reg, label\n    {MP_QSTR_ball, RRI8_B, ASM_XTENSA_CC_ALL, 0},\n    {MP_QSTR_bany, RRI8_B, ASM_XTENSA_CC_ANY, 0},\n    {MP_QSTR_bbc, RRI8_B, ASM_XTENSA_CC_BC, 0},\n    {MP_QSTR_bbs, RRI8_B, ASM_XTENSA_CC_BS, 0},\n    {MP_QSTR_beq, RRI8_B, ASM_XTENSA_CC_EQ, 0},\n    {MP_QSTR_bge, RRI8_B, ASM_XTENSA_CC_GE, 0},\n    {MP_QSTR_bgeu, RRI8_B, ASM_XTENSA_CC_GEU, 0},\n    {MP_QSTR_blt, RRI8_B, ASM_XTENSA_CC_LT, 0},\n    {MP_QSTR_bnall, RRI8_B, ASM_XTENSA_CC_NALL, 0},\n    {MP_QSTR_bne, RRI8_B, ASM_XTENSA_CC_NE, 0},\n    {MP_QSTR_bnone, RRI8_B, ASM_XTENSA_CC_NONE, 0},\n};\n\nSTATIC void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) {\n    size_t op_len;\n    const char *op_str = (const char *)qstr_data(op, &op_len);\n\n    if (n_args == 0) {\n        if (op == MP_QSTR_ret_n) {\n            asm_xtensa_op_ret_n(&emit->as);\n        } else {\n            goto unknown_op;\n        }\n\n    } else if (n_args == 1) {\n        if (op == MP_QSTR_callx0) {\n            uint r0 = get_arg_reg(emit, op_str, pn_args[0]);\n            asm_xtensa_op_callx0(&emit->as, r0);\n        } else if (op == MP_QSTR_j) {\n            int label = get_arg_label(emit, op_str, pn_args[0]);\n            asm_xtensa_j_label(&emit->as, label);\n        } else if (op == MP_QSTR_jx) {\n            uint r0 = get_arg_reg(emit, op_str, pn_args[0]);\n            asm_xtensa_op_jx(&emit->as, r0);\n        } else {\n            goto unknown_op;\n        }\n\n    } else if (n_args == 2) {\n        uint r0 = get_arg_reg(emit, op_str, pn_args[0]);\n        if (op == MP_QSTR_beqz) {\n            int label = get_arg_label(emit, op_str, pn_args[1]);\n            asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_EQ, r0, label);\n        } else if (op == MP_QSTR_bnez) {\n            int label = get_arg_label(emit, op_str, pn_args[1]);\n            asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_NE, r0, label);\n        } else if (op == MP_QSTR_mov || op == MP_QSTR_mov_n) {\n            // we emit mov.n for both \"mov\" and \"mov_n\" opcodes\n            uint r1 = get_arg_reg(emit, op_str, pn_args[1]);\n            asm_xtensa_op_mov_n(&emit->as, r0, r1);\n        } else if (op == MP_QSTR_movi) {\n            // for convenience we emit l32r if the integer doesn't fit in movi\n            uint32_t imm = get_arg_i(emit, op_str, pn_args[1], 0, 0);\n            asm_xtensa_mov_reg_i32(&emit->as, r0, imm);\n        } else {\n            goto unknown_op;\n        }\n\n    } else if (n_args == 3) {\n        // search table for 3 arg instructions\n        for (uint i = 0; i < MP_ARRAY_SIZE(opcode_table_3arg); i++) {\n            const opcode_table_3arg_t *o = &opcode_table_3arg[i];\n            if (op == o->name) {\n                uint r0 = get_arg_reg(emit, op_str, pn_args[0]);\n                uint r1 = get_arg_reg(emit, op_str, pn_args[1]);\n                if (o->type == RRR) {\n                    uint r2 = get_arg_reg(emit, op_str, pn_args[2]);\n                    asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, o->a0, o->a1, r0, r1, r2));\n                } else if (o->type == RRI8_B) {\n                    int label = get_arg_label(emit, op_str, pn_args[2]);\n                    asm_xtensa_bcc_reg_reg_label(&emit->as, o->a0, r0, r1, label);\n                } else {\n                    int shift, min, max;\n                    if ((o->type & 0xf0) == 0) {\n                        shift = 0;\n                        min = -128;\n                        max = 127;\n                    } else {\n                        shift = (o->type & 0xf0) >> 5;\n                        min = 0;\n                        max = 0xff << shift;\n                    }\n                    uint32_t imm = get_arg_i(emit, op_str, pn_args[2], min, max);\n                    asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(o->a0, o->a1, r1, r0, (imm >> shift) & 0xff));\n                }\n                return;\n            }\n        }\n        goto unknown_op;\n\n    } else {\n        goto unknown_op;\n    }\n\n    return;\n\nunknown_op:\n    emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT(\"unsupported Xtensa instruction '%s' with %d arguments\"), op_str, n_args));\n    return;\n\n    /*\nbranch_not_in_range:\n    emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT(\"branch not in range\"));\n    return;\n    */\n}\n\nconst emit_inline_asm_method_table_t emit_inline_xtensa_method_table = {\n    #if MICROPY_DYNAMIC_COMPILER\n    emit_inline_xtensa_new,\n    emit_inline_xtensa_free,\n    #endif\n\n    emit_inline_xtensa_start_pass,\n    emit_inline_xtensa_end_pass,\n    emit_inline_xtensa_count_params,\n    emit_inline_xtensa_label,\n    emit_inline_xtensa_op,\n};\n\n#endif // MICROPY_EMIT_INLINE_XTENSA\n"
  },
  {
    "path": "py/emitnarm.c",
    "content": "// ARM specific stuff\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_EMIT_ARM\n\n// This is defined so that the assembler exports generic assembler API macros\n#define GENERIC_ASM_API (1)\n#include \"py/asmarm.h\"\n\n// Word indices of REG_LOCAL_x in nlr_buf_t\n#define NLR_BUF_IDX_LOCAL_1 (3) // r4\n#define NLR_BUF_IDX_LOCAL_2 (4) // r5\n#define NLR_BUF_IDX_LOCAL_3 (5) // r6\n\n#define N_ARM (1)\n#define EXPORT_FUN(name) emit_native_arm_##name\n#include \"py/emitnative.c\"\n\n#endif\n"
  },
  {
    "path": "py/emitnative.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n// Essentially normal Python has 1 type: Python objects\n// Viper has more than 1 type, and is just a more complicated (a superset of) Python.\n// If you declare everything in Viper as a Python object (ie omit type decls) then\n// it should in principle be exactly the same as Python native.\n// Having types means having more opcodes, like binary_op_nat_nat, binary_op_nat_obj etc.\n// In practice we won't have a VM but rather do this in asm which is actually very minimal.\n\n// Because it breaks strict Python equivalence it should be a completely separate\n// decorator.  It breaks equivalence because overflow on integers wraps around.\n// It shouldn't break equivalence if you don't use the new types, but since the\n// type decls might be used in normal Python for other reasons, it's probably safest,\n// cleanest and clearest to make it a separate decorator.\n\n// Actually, it does break equivalence because integers default to native integers,\n// not Python objects.\n\n// for x in l[0:8]: can be compiled into a native loop if l has pointer type\n\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/emit.h\"\n#include \"py/nativeglue.h\"\n#include \"py/objstr.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_PRINT (1)\n#define DEBUG_printf DEBUG_printf\n#else // don't print debugging info\n#define DEBUG_printf(...) (void)0\n#endif\n\n// wrapper around everything in this file\n#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA || N_XTENSAWIN\n\n// C stack layout for native functions:\n//  0:                          nlr_buf_t [optional]\n//  emit->code_state_start:     mp_code_state_t\n//  emit->stack_start:          Python object stack             | emit->n_state\n//                              locals (reversed, L0 at end)    |\n//\n// C stack layout for native generator functions:\n//  0=emit->stack_start:        nlr_buf_t\n//\n//  Then REG_GENERATOR_STATE points to:\n//  0=emit->code_state_start:   mp_code_state_t\n//  emit->stack_start:          Python object stack             | emit->n_state\n//                              locals (reversed, L0 at end)    |\n//\n// C stack layout for viper functions:\n//  0:                          nlr_buf_t [optional]\n//  emit->code_state_start:     fun_obj, old_globals [optional]\n//  emit->stack_start:          Python object stack             | emit->n_state\n//                              locals (reversed, L0 at end)    |\n//                              (L0-L2 may be in regs instead)\n\n// Native emitter needs to know the following sizes and offsets of C structs (on the target):\n#if MICROPY_DYNAMIC_COMPILER\n#define SIZEOF_NLR_BUF (2 + mp_dynamic_compiler.nlr_buf_num_regs + 1) // the +1 is conservative in case MICROPY_ENABLE_PYSTACK enabled\n#else\n#define SIZEOF_NLR_BUF (sizeof(nlr_buf_t) / sizeof(uintptr_t))\n#endif\n#define SIZEOF_CODE_STATE (sizeof(mp_code_state_t) / sizeof(uintptr_t))\n#define OFFSETOF_CODE_STATE_STATE (offsetof(mp_code_state_t, state) / sizeof(uintptr_t))\n#define OFFSETOF_CODE_STATE_FUN_BC (offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t))\n#define OFFSETOF_CODE_STATE_IP (offsetof(mp_code_state_t, ip) / sizeof(uintptr_t))\n#define OFFSETOF_CODE_STATE_SP (offsetof(mp_code_state_t, sp) / sizeof(uintptr_t))\n#define OFFSETOF_OBJ_FUN_BC_GLOBALS (offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t))\n#define OFFSETOF_OBJ_FUN_BC_BYTECODE (offsetof(mp_obj_fun_bc_t, bytecode) / sizeof(uintptr_t))\n#define OFFSETOF_OBJ_FUN_BC_CONST_TABLE (offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t))\n\n// If not already defined, set parent args to same as child call registers\n#ifndef REG_PARENT_RET\n#define REG_PARENT_RET REG_RET\n#define REG_PARENT_ARG_1 REG_ARG_1\n#define REG_PARENT_ARG_2 REG_ARG_2\n#define REG_PARENT_ARG_3 REG_ARG_3\n#define REG_PARENT_ARG_4 REG_ARG_4\n#endif\n\n// Word index of nlr_buf_t.ret_val\n#define NLR_BUF_IDX_RET_VAL (1)\n\n// Whether the viper function needs access to fun_obj\n#define NEED_FUN_OBJ(emit) ((emit)->scope->exc_stack_size > 0 \\\n    || ((emit)->scope->scope_flags & (MP_SCOPE_FLAG_REFGLOBALS | MP_SCOPE_FLAG_HASCONSTS)))\n\n// Whether the native/viper function needs to be wrapped in an exception handler\n#define NEED_GLOBAL_EXC_HANDLER(emit) ((emit)->scope->exc_stack_size > 0 \\\n    || ((emit)->scope->scope_flags & (MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_REFGLOBALS)))\n\n// Whether registers can be used to store locals (only true if there are no\n// exception handlers, because otherwise an nlr_jump will restore registers to\n// their state at the start of the function and updates to locals will be lost)\n#define CAN_USE_REGS_FOR_LOCALS(emit) ((emit)->scope->exc_stack_size == 0 && !(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR))\n\n// Indices within the local C stack for various variables\n#define LOCAL_IDX_EXC_VAL(emit) (NLR_BUF_IDX_RET_VAL)\n#define LOCAL_IDX_EXC_HANDLER_PC(emit) (NLR_BUF_IDX_LOCAL_1)\n#define LOCAL_IDX_EXC_HANDLER_UNWIND(emit) (NLR_BUF_IDX_LOCAL_2)\n#define LOCAL_IDX_RET_VAL(emit) (NLR_BUF_IDX_LOCAL_3)\n#define LOCAL_IDX_FUN_OBJ(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_FUN_BC)\n#define LOCAL_IDX_OLD_GLOBALS(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_IP)\n#define LOCAL_IDX_GEN_PC(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_IP)\n#define LOCAL_IDX_LOCAL_VAR(emit, local_num) ((emit)->stack_start + (emit)->n_state - 1 - (local_num))\n\n#define REG_GENERATOR_STATE (REG_LOCAL_3)\n\n#define EMIT_NATIVE_VIPER_TYPE_ERROR(emit, ...) do { \\\n        *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \\\n} while (0)\n\ntypedef enum {\n    STACK_VALUE,\n    STACK_REG,\n    STACK_IMM,\n} stack_info_kind_t;\n\n// these enums must be distinct and the bottom 4 bits\n// must correspond to the correct MP_NATIVE_TYPE_xxx value\ntypedef enum {\n    VTYPE_PYOBJ = 0x00 | MP_NATIVE_TYPE_OBJ,\n    VTYPE_BOOL = 0x00 | MP_NATIVE_TYPE_BOOL,\n    VTYPE_INT = 0x00 | MP_NATIVE_TYPE_INT,\n    VTYPE_UINT = 0x00 | MP_NATIVE_TYPE_UINT,\n    VTYPE_PTR = 0x00 | MP_NATIVE_TYPE_PTR,\n    VTYPE_PTR8 = 0x00 | MP_NATIVE_TYPE_PTR8,\n    VTYPE_PTR16 = 0x00 | MP_NATIVE_TYPE_PTR16,\n    VTYPE_PTR32 = 0x00 | MP_NATIVE_TYPE_PTR32,\n\n    VTYPE_PTR_NONE = 0x50 | MP_NATIVE_TYPE_PTR,\n\n    VTYPE_UNBOUND = 0x60 | MP_NATIVE_TYPE_OBJ,\n    VTYPE_BUILTIN_CAST = 0x70 | MP_NATIVE_TYPE_OBJ,\n} vtype_kind_t;\n\nSTATIC qstr vtype_to_qstr(vtype_kind_t vtype) {\n    switch (vtype) {\n        case VTYPE_PYOBJ:\n            return MP_QSTR_object;\n        case VTYPE_BOOL:\n            return MP_QSTR_bool;\n        case VTYPE_INT:\n            return MP_QSTR_int;\n        case VTYPE_UINT:\n            return MP_QSTR_uint;\n        case VTYPE_PTR:\n            return MP_QSTR_ptr;\n        case VTYPE_PTR8:\n            return MP_QSTR_ptr8;\n        case VTYPE_PTR16:\n            return MP_QSTR_ptr16;\n        case VTYPE_PTR32:\n            return MP_QSTR_ptr32;\n        case VTYPE_PTR_NONE:\n        default:\n            return MP_QSTR_None;\n    }\n}\n\ntypedef struct _stack_info_t {\n    vtype_kind_t vtype;\n    stack_info_kind_t kind;\n    union {\n        int u_reg;\n        mp_int_t u_imm;\n    } data;\n} stack_info_t;\n\n#define UNWIND_LABEL_UNUSED (0x7fff)\n#define UNWIND_LABEL_DO_FINAL_UNWIND (0x7ffe)\n\ntypedef struct _exc_stack_entry_t {\n    uint16_t label : 15;\n    uint16_t is_finally : 1;\n    uint16_t unwind_label : 15;\n    uint16_t is_active : 1;\n} exc_stack_entry_t;\n\nstruct _emit_t {\n    mp_obj_t *error_slot;\n    uint *label_slot;\n    uint exit_label;\n    int pass;\n\n    bool do_viper_types;\n\n    mp_uint_t local_vtype_alloc;\n    vtype_kind_t *local_vtype;\n\n    mp_uint_t stack_info_alloc;\n    stack_info_t *stack_info;\n    vtype_kind_t saved_stack_vtype;\n\n    size_t exc_stack_alloc;\n    size_t exc_stack_size;\n    exc_stack_entry_t *exc_stack;\n\n    int prelude_offset;\n    int start_offset;\n    int n_state;\n    uint16_t code_state_start;\n    uint16_t stack_start;\n    int stack_size;\n    uint16_t n_cell;\n\n    uint16_t const_table_cur_obj;\n    uint16_t const_table_num_obj;\n    uint16_t const_table_cur_raw_code;\n    mp_uint_t *const_table;\n\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    uint16_t qstr_link_cur;\n    mp_qstr_link_entry_t *qstr_link;\n    #endif\n\n    bool last_emit_was_return_value;\n\n    scope_t *scope;\n\n    ASM_T *as;\n};\n\nSTATIC const uint8_t reg_local_table[REG_LOCAL_NUM] = {REG_LOCAL_1, REG_LOCAL_2, REG_LOCAL_3};\n\nSTATIC void emit_native_global_exc_entry(emit_t *emit);\nSTATIC void emit_native_global_exc_exit(emit_t *emit);\nSTATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj);\n\nemit_t *EXPORT_FUN(new)(mp_obj_t * error_slot, uint *label_slot, mp_uint_t max_num_labels) {\n    emit_t *emit = m_new0(emit_t, 1);\n    emit->error_slot = error_slot;\n    emit->label_slot = label_slot;\n    emit->stack_info_alloc = 8;\n    emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc);\n    emit->exc_stack_alloc = 8;\n    emit->exc_stack = m_new(exc_stack_entry_t, emit->exc_stack_alloc);\n    emit->as = m_new0(ASM_T, 1);\n    mp_asm_base_init(&emit->as->base, max_num_labels);\n    return emit;\n}\n\nvoid EXPORT_FUN(free)(emit_t * emit) {\n    mp_asm_base_deinit(&emit->as->base, false);\n    m_del_obj(ASM_T, emit->as);\n    m_del(exc_stack_entry_t, emit->exc_stack, emit->exc_stack_alloc);\n    m_del(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc);\n    m_del(stack_info_t, emit->stack_info, emit->stack_info_alloc);\n    m_del_obj(emit_t, emit);\n}\n\nSTATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg);\n\nSTATIC void emit_native_mov_reg_const(emit_t *emit, int reg_dest, int const_val) {\n    ASM_LOAD_REG_REG_OFFSET(emit->as, reg_dest, REG_FUN_TABLE, const_val);\n}\n\nSTATIC void emit_native_mov_state_reg(emit_t *emit, int local_num, int reg_src) {\n    if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {\n        ASM_STORE_REG_REG_OFFSET(emit->as, reg_src, REG_GENERATOR_STATE, local_num);\n    } else {\n        ASM_MOV_LOCAL_REG(emit->as, local_num, reg_src);\n    }\n}\n\nSTATIC void emit_native_mov_reg_state(emit_t *emit, int reg_dest, int local_num) {\n    if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {\n        ASM_LOAD_REG_REG_OFFSET(emit->as, reg_dest, REG_GENERATOR_STATE, local_num);\n    } else {\n        ASM_MOV_REG_LOCAL(emit->as, reg_dest, local_num);\n    }\n}\n\nSTATIC void emit_native_mov_reg_state_addr(emit_t *emit, int reg_dest, int local_num) {\n    if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {\n        ASM_MOV_REG_IMM(emit->as, reg_dest, local_num * ASM_WORD_SIZE);\n        ASM_ADD_REG_REG(emit->as, reg_dest, REG_GENERATOR_STATE);\n    } else {\n        ASM_MOV_REG_LOCAL_ADDR(emit->as, reg_dest, local_num);\n    }\n}\n\nSTATIC void emit_native_mov_reg_qstr(emit_t *emit, int arg_reg, qstr qst) {\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    size_t loc = ASM_MOV_REG_IMM_FIX_U16(emit->as, arg_reg, qst);\n    size_t link_idx = emit->qstr_link_cur++;\n    if (emit->pass == MP_PASS_EMIT) {\n        emit->qstr_link[link_idx].off = loc << 2 | 1;\n        emit->qstr_link[link_idx].qst = qst;\n    }\n    #else\n    ASM_MOV_REG_IMM(emit->as, arg_reg, qst);\n    #endif\n}\n\nSTATIC void emit_native_mov_reg_qstr_obj(emit_t *emit, int reg_dest, qstr qst) {\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    size_t loc = ASM_MOV_REG_IMM_FIX_WORD(emit->as, reg_dest, (mp_uint_t)MP_OBJ_NEW_QSTR(qst));\n    size_t link_idx = emit->qstr_link_cur++;\n    if (emit->pass == MP_PASS_EMIT) {\n        emit->qstr_link[link_idx].off = loc << 2 | 2;\n        emit->qstr_link[link_idx].qst = qst;\n    }\n    #else\n    ASM_MOV_REG_IMM(emit->as, reg_dest, (mp_uint_t)MP_OBJ_NEW_QSTR(qst));\n    #endif\n}\n\n#define emit_native_mov_state_imm_via(emit, local_num, imm, reg_temp) \\\n    do { \\\n        ASM_MOV_REG_IMM((emit)->as, (reg_temp), (imm)); \\\n        emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \\\n    } while (false)\n\nSTATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {\n    DEBUG_printf(\"start_pass(pass=%u, scope=%p)\\n\", pass, scope);\n\n    emit->pass = pass;\n    emit->do_viper_types = scope->emit_options == MP_EMIT_OPT_VIPER;\n    emit->stack_size = 0;\n    #if N_PRELUDE_AS_BYTES_OBJ\n    emit->const_table_cur_obj = emit->do_viper_types ? 0 : 1; // reserve first obj for prelude bytes obj\n    #else\n    emit->const_table_cur_obj = 0;\n    #endif\n    emit->const_table_cur_raw_code = 0;\n    #if MICROPY_PERSISTENT_CODE_SAVE\n    emit->qstr_link_cur = 0;\n    #endif\n    emit->last_emit_was_return_value = false;\n    emit->scope = scope;\n\n    // allocate memory for keeping track of the types of locals\n    if (emit->local_vtype_alloc < scope->num_locals) {\n        emit->local_vtype = m_renew(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc, scope->num_locals);\n        emit->local_vtype_alloc = scope->num_locals;\n    }\n\n    // set default type for arguments\n    mp_uint_t num_args = emit->scope->num_pos_args + emit->scope->num_kwonly_args;\n    if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {\n        num_args += 1;\n    }\n    if (scope->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) {\n        num_args += 1;\n    }\n    for (mp_uint_t i = 0; i < num_args; i++) {\n        emit->local_vtype[i] = VTYPE_PYOBJ;\n    }\n\n    // Set viper type for arguments\n    if (emit->do_viper_types) {\n        for (int i = 0; i < emit->scope->id_info_len; ++i) {\n            id_info_t *id = &emit->scope->id_info[i];\n            if (id->flags & ID_FLAG_IS_PARAM) {\n                assert(id->local_num < emit->local_vtype_alloc);\n                emit->local_vtype[id->local_num] = id->flags >> ID_FLAG_VIPER_TYPE_POS;\n            }\n        }\n    }\n\n    // local variables begin unbound, and have unknown type\n    for (mp_uint_t i = num_args; i < emit->local_vtype_alloc; i++) {\n        emit->local_vtype[i] = VTYPE_UNBOUND;\n    }\n\n    // values on stack begin unbound\n    for (mp_uint_t i = 0; i < emit->stack_info_alloc; i++) {\n        emit->stack_info[i].kind = STACK_VALUE;\n        emit->stack_info[i].vtype = VTYPE_UNBOUND;\n    }\n\n    mp_asm_base_start_pass(&emit->as->base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE);\n\n    // generate code for entry to function\n\n    // Work out start of code state (mp_code_state_t or reduced version for viper)\n    emit->code_state_start = 0;\n    if (NEED_GLOBAL_EXC_HANDLER(emit)) {\n        emit->code_state_start = SIZEOF_NLR_BUF;\n    }\n\n    if (emit->do_viper_types) {\n        // Work out size of state (locals plus stack)\n        // n_state counts all stack and locals, even those in registers\n        emit->n_state = scope->num_locals + scope->stack_size;\n        int num_locals_in_regs = 0;\n        if (CAN_USE_REGS_FOR_LOCALS(emit)) {\n            num_locals_in_regs = scope->num_locals;\n            if (num_locals_in_regs > REG_LOCAL_NUM) {\n                num_locals_in_regs = REG_LOCAL_NUM;\n            }\n            // Need a spot for REG_LOCAL_3 if 4 or more args (see below)\n            if (scope->num_pos_args >= 4) {\n                --num_locals_in_regs;\n            }\n        }\n\n        // Work out where the locals and Python stack start within the C stack\n        if (NEED_GLOBAL_EXC_HANDLER(emit)) {\n            // Reserve 2 words for function object and old globals\n            emit->stack_start = emit->code_state_start + 2;\n        } else if (scope->scope_flags & MP_SCOPE_FLAG_HASCONSTS) {\n            // Reserve 1 word for function object, to access const table\n            emit->stack_start = emit->code_state_start + 1;\n        } else {\n            emit->stack_start = emit->code_state_start + 0;\n        }\n\n        // Entry to function\n        ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs);\n\n        #if N_X86\n        asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1);\n        #endif\n\n        // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table\n        ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);\n        ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, 0);\n\n        // Store function object (passed as first arg) to stack if needed\n        if (NEED_FUN_OBJ(emit)) {\n            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);\n        }\n\n        // Put n_args in REG_ARG_1, n_kw in REG_ARG_2, args array in REG_LOCAL_3\n        #if N_X86\n        asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_1);\n        asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_2);\n        asm_x86_mov_arg_to_r32(emit->as, 3, REG_LOCAL_3);\n        #else\n        ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_PARENT_ARG_2);\n        ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_3);\n        ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_4);\n        #endif\n\n        // Check number of args matches this function, and call mp_arg_check_num_sig if not\n        ASM_JUMP_IF_REG_NONZERO(emit->as, REG_ARG_2, *emit->label_slot + 4, true);\n        ASM_MOV_REG_IMM(emit->as, REG_ARG_3, scope->num_pos_args);\n        ASM_JUMP_IF_REG_EQ(emit->as, REG_ARG_1, REG_ARG_3, *emit->label_slot + 5);\n        mp_asm_base_label_assign(&emit->as->base, *emit->label_slot + 4);\n        ASM_MOV_REG_IMM(emit->as, REG_ARG_3, MP_OBJ_FUN_MAKE_SIG(scope->num_pos_args, scope->num_pos_args, false));\n        ASM_CALL_IND(emit->as, MP_F_ARG_CHECK_NUM_SIG);\n        mp_asm_base_label_assign(&emit->as->base, *emit->label_slot + 5);\n\n        // Store arguments into locals (reg or stack), converting to native if needed\n        for (int i = 0; i < emit->scope->num_pos_args; i++) {\n            int r = REG_ARG_1;\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_LOCAL_3, i);\n            if (emit->local_vtype[i] != VTYPE_PYOBJ) {\n                emit_call_with_imm_arg(emit, MP_F_CONVERT_OBJ_TO_NATIVE, emit->local_vtype[i], REG_ARG_2);\n                r = REG_RET;\n            }\n            // REG_LOCAL_3 points to the args array so be sure not to overwrite it if it's still needed\n            if (i < REG_LOCAL_NUM && CAN_USE_REGS_FOR_LOCALS(emit) && (i != 2 || emit->scope->num_pos_args == 3)) {\n                ASM_MOV_REG_REG(emit->as, reg_local_table[i], r);\n            } else {\n                emit_native_mov_state_reg(emit, LOCAL_IDX_LOCAL_VAR(emit, i), r);\n            }\n        }\n        // Get 3rd local from the stack back into REG_LOCAL_3 if this reg couldn't be written to above\n        if (emit->scope->num_pos_args >= 4 && CAN_USE_REGS_FOR_LOCALS(emit)) {\n            ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_3, LOCAL_IDX_LOCAL_VAR(emit, 2));\n        }\n\n        emit_native_global_exc_entry(emit);\n\n    } else {\n        // work out size of state (locals plus stack)\n        emit->n_state = scope->num_locals + scope->stack_size;\n\n        if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {\n            emit->code_state_start = 0;\n            emit->stack_start = SIZEOF_CODE_STATE;\n            #if N_PRELUDE_AS_BYTES_OBJ\n            // Load index of prelude bytes object in const_table\n            mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)(emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1));\n            #else\n            mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->prelude_offset);\n            #endif\n            mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->start_offset);\n            ASM_ENTRY(emit->as, SIZEOF_NLR_BUF);\n\n            // Put address of code_state into REG_GENERATOR_STATE\n            #if N_X86\n            asm_x86_mov_arg_to_r32(emit->as, 0, REG_GENERATOR_STATE);\n            #else\n            ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_PARENT_ARG_1);\n            #endif\n\n            // Put throw value into LOCAL_IDX_EXC_VAL slot, for yield/yield-from\n            #if N_X86\n            asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2);\n            #endif\n            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_PARENT_ARG_2);\n\n            // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, LOCAL_IDX_FUN_OBJ(emit));\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_TEMP0, emit->scope->num_pos_args + emit->scope->num_kwonly_args);\n        } else {\n            // The locals and stack start after the code_state structure\n            emit->stack_start = emit->code_state_start + SIZEOF_CODE_STATE;\n\n            // Allocate space on C-stack for code_state structure, which includes state\n            ASM_ENTRY(emit->as, emit->stack_start + emit->n_state);\n\n            // Prepare incoming arguments for call to mp_setup_code_state\n\n            #if N_X86\n            asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1);\n            asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2);\n            asm_x86_mov_arg_to_r32(emit->as, 2, REG_PARENT_ARG_3);\n            asm_x86_mov_arg_to_r32(emit->as, 3, REG_PARENT_ARG_4);\n            #endif\n\n            // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args);\n\n            // Set code_state.fun_bc\n            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);\n\n            // Set code_state.ip (offset from start of this function to prelude info)\n            #if N_PRELUDE_AS_BYTES_OBJ\n            // Prelude is a bytes object in const_table; store ip = prelude->data - fun_bc->bytecode\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1);\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, offsetof(mp_obj_str_t, data) / sizeof(uintptr_t));\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_PARENT_ARG_1, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_BYTECODE);\n            ASM_SUB_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1);\n            emit_native_mov_state_reg(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, REG_LOCAL_3);\n            #else\n            // TODO this encoding may change size in the final pass, need to make it fixed\n            emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_PARENT_ARG_1);\n            #endif\n\n            // Set code_state.n_state (only works on little endian targets due to n_state being uint16_t)\n            emit_native_mov_state_imm_via(emit, emit->code_state_start + offsetof(mp_code_state_t, n_state) / sizeof(uintptr_t), emit->n_state, REG_ARG_1);\n\n            // Put address of code_state into first arg\n            ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, emit->code_state_start);\n\n            // Copy next 3 args if needed\n            #if REG_ARG_2 != REG_PARENT_ARG_2\n            ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_2);\n            #endif\n            #if REG_ARG_3 != REG_PARENT_ARG_3\n            ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_PARENT_ARG_3);\n            #endif\n            #if REG_ARG_4 != REG_PARENT_ARG_4\n            ASM_MOV_REG_REG(emit->as, REG_ARG_4, REG_PARENT_ARG_4);\n            #endif\n\n            // Call mp_setup_code_state to prepare code_state structure\n            #if N_THUMB\n            asm_thumb_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4);\n            #elif N_ARM\n            asm_arm_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_ARM_REG_R4);\n            #else\n            ASM_CALL_IND(emit->as, MP_F_SETUP_CODE_STATE);\n            #endif\n        }\n\n        emit_native_global_exc_entry(emit);\n\n        // cache some locals in registers, but only if no exception handlers\n        if (CAN_USE_REGS_FOR_LOCALS(emit)) {\n            for (int i = 0; i < REG_LOCAL_NUM && i < scope->num_locals; ++i) {\n                ASM_MOV_REG_LOCAL(emit->as, reg_local_table[i], LOCAL_IDX_LOCAL_VAR(emit, i));\n            }\n        }\n\n        // set the type of closed over variables\n        for (mp_uint_t i = 0; i < scope->id_info_len; i++) {\n            id_info_t *id = &scope->id_info[i];\n            if (id->kind == ID_INFO_KIND_CELL) {\n                emit->local_vtype[id->local_num] = VTYPE_PYOBJ;\n            }\n        }\n\n        if (pass == MP_PASS_EMIT) {\n            // write argument names as qstr objects\n            // see comment in corresponding part of emitbc.c about the logic here\n            for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) {\n                qstr qst = MP_QSTR__star_;\n                for (int j = 0; j < scope->id_info_len; ++j) {\n                    id_info_t *id = &scope->id_info[j];\n                    if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) {\n                        qst = id->qst;\n                        break;\n                    }\n                }\n                emit->const_table[i] = (mp_uint_t)MP_OBJ_NEW_QSTR(qst);\n            }\n        }\n    }\n\n}\n\nstatic inline void emit_native_write_code_info_byte(emit_t *emit, byte val) {\n    mp_asm_base_data(&emit->as->base, 1, val);\n}\n\nSTATIC void emit_native_end_pass(emit_t *emit) {\n    emit_native_global_exc_exit(emit);\n\n    if (!emit->do_viper_types) {\n        emit->prelude_offset = mp_asm_base_get_code_pos(&emit->as->base);\n\n        size_t n_state = emit->n_state;\n        size_t n_exc_stack = 0; // exc-stack not needed for native code\n        MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, emit->scope, emit_native_write_code_info_byte, emit);\n\n        #if MICROPY_PERSISTENT_CODE\n        size_t n_info = 4;\n        #else\n        size_t n_info = 1;\n        #endif\n        MP_BC_PRELUDE_SIZE_ENCODE(n_info, emit->n_cell, emit_native_write_code_info_byte, emit);\n\n        #if MICROPY_PERSISTENT_CODE\n        mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name);\n        mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name >> 8);\n        mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file);\n        mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file >> 8);\n        #else\n        mp_asm_base_data(&emit->as->base, 1, 1);\n        #endif\n\n        // bytecode prelude: initialise closed over variables\n        size_t cell_start = mp_asm_base_get_code_pos(&emit->as->base);\n        for (int i = 0; i < emit->scope->id_info_len; i++) {\n            id_info_t *id = &emit->scope->id_info[i];\n            if (id->kind == ID_INFO_KIND_CELL) {\n                assert(id->local_num <= 255);\n                mp_asm_base_data(&emit->as->base, 1, id->local_num); // write the local which should be converted to a cell\n            }\n        }\n        emit->n_cell = mp_asm_base_get_code_pos(&emit->as->base) - cell_start;\n\n        #if N_PRELUDE_AS_BYTES_OBJ\n        // Prelude bytes object is after qstr arg names and mp_fun_table\n        size_t table_off = emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1;\n        if (emit->pass == MP_PASS_EMIT) {\n            void *buf = emit->as->base.code_base + emit->prelude_offset;\n            size_t n = emit->as->base.code_offset - emit->prelude_offset;\n            emit->const_table[table_off] = (uintptr_t)mp_obj_new_bytes(buf, n);\n        }\n        #endif\n    }\n\n    ASM_END_PASS(emit->as);\n\n    // check stack is back to zero size\n    assert(emit->stack_size == 0);\n    assert(emit->exc_stack_size == 0);\n\n    // Deal with const table accounting\n    assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->const_table_num_obj == emit->const_table_cur_obj));\n    emit->const_table_num_obj = emit->const_table_cur_obj;\n    if (emit->pass == MP_PASS_CODE_SIZE) {\n        size_t const_table_alloc = 1 + emit->const_table_num_obj + emit->const_table_cur_raw_code;\n        size_t nqstr = 0;\n        if (!emit->do_viper_types) {\n            // Add room for qstr names of arguments\n            nqstr = emit->scope->num_pos_args + emit->scope->num_kwonly_args;\n            const_table_alloc += nqstr;\n        }\n        emit->const_table = m_new(mp_uint_t, const_table_alloc);\n        #if !MICROPY_DYNAMIC_COMPILER\n        // Store mp_fun_table pointer just after qstrs\n        // (but in dynamic-compiler mode eliminate dependency on mp_fun_table)\n        emit->const_table[nqstr] = (mp_uint_t)(uintptr_t)&mp_fun_table;\n        #endif\n\n        #if MICROPY_PERSISTENT_CODE_SAVE\n        size_t qstr_link_alloc = emit->qstr_link_cur;\n        if (qstr_link_alloc > 0) {\n            emit->qstr_link = m_new(mp_qstr_link_entry_t, qstr_link_alloc);\n        }\n        #endif\n    }\n\n    if (emit->pass == MP_PASS_EMIT) {\n        void *f = mp_asm_base_get_code(&emit->as->base);\n        mp_uint_t f_len = mp_asm_base_get_code_size(&emit->as->base);\n\n        mp_emit_glue_assign_native(emit->scope->raw_code,\n            emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY,\n            f, f_len, emit->const_table,\n            #if MICROPY_PERSISTENT_CODE_SAVE\n            emit->prelude_offset,\n            emit->const_table_cur_obj, emit->const_table_cur_raw_code,\n            emit->qstr_link_cur, emit->qstr_link,\n            #endif\n            emit->scope->num_pos_args, emit->scope->scope_flags, 0);\n    }\n}\n\nSTATIC bool emit_native_last_emit_was_return_value(emit_t *emit) {\n    return emit->last_emit_was_return_value;\n}\n\nSTATIC void ensure_extra_stack(emit_t *emit, size_t delta) {\n    if (emit->stack_size + delta > emit->stack_info_alloc) {\n        size_t new_alloc = (emit->stack_size + delta + 8) & ~3;\n        emit->stack_info = m_renew(stack_info_t, emit->stack_info, emit->stack_info_alloc, new_alloc);\n        emit->stack_info_alloc = new_alloc;\n    }\n}\n\nSTATIC void adjust_stack(emit_t *emit, mp_int_t stack_size_delta) {\n    assert((mp_int_t)emit->stack_size + stack_size_delta >= 0);\n    assert((mp_int_t)emit->stack_size + stack_size_delta <= (mp_int_t)emit->stack_info_alloc);\n    emit->stack_size += stack_size_delta;\n    if (emit->pass > MP_PASS_SCOPE && emit->stack_size > emit->scope->stack_size) {\n        emit->scope->stack_size = emit->stack_size;\n    }\n    #ifdef DEBUG_PRINT\n    DEBUG_printf(\"  adjust_stack; stack_size=%d+%d; stack now:\", emit->stack_size - stack_size_delta, stack_size_delta);\n    for (int i = 0; i < emit->stack_size; i++) {\n        stack_info_t *si = &emit->stack_info[i];\n        DEBUG_printf(\" (v=%d k=%d %d)\", si->vtype, si->kind, si->data.u_reg);\n    }\n    DEBUG_printf(\"\\n\");\n    #endif\n}\n\nSTATIC void emit_native_adjust_stack_size(emit_t *emit, mp_int_t delta) {\n    DEBUG_printf(\"adjust_stack_size(\" INT_FMT \")\\n\", delta);\n    if (delta > 0) {\n        ensure_extra_stack(emit, delta);\n    }\n    // If we are adjusting the stack in a positive direction (pushing) then we\n    // need to fill in values for the stack kind and vtype of the newly-pushed\n    // entries.  These should be set to \"value\" (ie not reg or imm) because we\n    // should only need to adjust the stack due to a jump to this part in the\n    // code (and hence we have settled the stack before the jump).\n    for (mp_int_t i = 0; i < delta; i++) {\n        stack_info_t *si = &emit->stack_info[emit->stack_size + i];\n        si->kind = STACK_VALUE;\n        // TODO we don't know the vtype to use here.  At the moment this is a\n        // hack to get the case of multi comparison working.\n        if (delta == 1) {\n            si->vtype = emit->saved_stack_vtype;\n        } else {\n            si->vtype = VTYPE_PYOBJ;\n        }\n    }\n    adjust_stack(emit, delta);\n}\n\nSTATIC void emit_native_set_source_line(emit_t *emit, mp_uint_t source_line) {\n    (void)emit;\n    (void)source_line;\n}\n\n// this must be called at start of emit functions\nSTATIC void emit_native_pre(emit_t *emit) {\n    emit->last_emit_was_return_value = false;\n}\n\n// depth==0 is top, depth==1 is before top, etc\nSTATIC stack_info_t *peek_stack(emit_t *emit, mp_uint_t depth) {\n    return &emit->stack_info[emit->stack_size - 1 - depth];\n}\n\n// depth==0 is top, depth==1 is before top, etc\nSTATIC vtype_kind_t peek_vtype(emit_t *emit, mp_uint_t depth) {\n    if (emit->do_viper_types) {\n        return peek_stack(emit, depth)->vtype;\n    } else {\n        // Type is always PYOBJ even if the intermediate stored value is not\n        return VTYPE_PYOBJ;\n    }\n}\n\n// pos=1 is TOS, pos=2 is next, etc\n// use pos=0 for no skipping\nSTATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) {\n    skip_stack_pos = emit->stack_size - skip_stack_pos;\n    for (int i = 0; i < emit->stack_size; i++) {\n        if (i != skip_stack_pos) {\n            stack_info_t *si = &emit->stack_info[i];\n            if (si->kind == STACK_REG && si->data.u_reg == reg_needed) {\n                si->kind = STACK_VALUE;\n                emit_native_mov_state_reg(emit, emit->stack_start + i, si->data.u_reg);\n            }\n        }\n    }\n}\n\nSTATIC void need_reg_all(emit_t *emit) {\n    for (int i = 0; i < emit->stack_size; i++) {\n        stack_info_t *si = &emit->stack_info[i];\n        if (si->kind == STACK_REG) {\n            si->kind = STACK_VALUE;\n            emit_native_mov_state_reg(emit, emit->stack_start + i, si->data.u_reg);\n        }\n    }\n}\n\nSTATIC vtype_kind_t load_reg_stack_imm(emit_t *emit, int reg_dest, const stack_info_t *si, bool convert_to_pyobj) {\n    if (!convert_to_pyobj && emit->do_viper_types) {\n        ASM_MOV_REG_IMM(emit->as, reg_dest, si->data.u_imm);\n        return si->vtype;\n    } else {\n        if (si->vtype == VTYPE_PYOBJ) {\n            ASM_MOV_REG_IMM(emit->as, reg_dest, si->data.u_imm);\n        } else if (si->vtype == VTYPE_BOOL) {\n            emit_native_mov_reg_const(emit, reg_dest, MP_F_CONST_FALSE_OBJ + si->data.u_imm);\n        } else if (si->vtype == VTYPE_INT || si->vtype == VTYPE_UINT) {\n            ASM_MOV_REG_IMM(emit->as, reg_dest, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm));\n        } else if (si->vtype == VTYPE_PTR_NONE) {\n            emit_native_mov_reg_const(emit, reg_dest, MP_F_CONST_NONE_OBJ);\n        } else {\n            mp_raise_NotImplementedError(MP_ERROR_TEXT(\"conversion to object\"));\n        }\n        return VTYPE_PYOBJ;\n    }\n}\n\nSTATIC void need_stack_settled(emit_t *emit) {\n    DEBUG_printf(\"  need_stack_settled; stack_size=%d\\n\", emit->stack_size);\n    for (int i = 0; i < emit->stack_size; i++) {\n        stack_info_t *si = &emit->stack_info[i];\n        if (si->kind == STACK_REG) {\n            DEBUG_printf(\"    reg(%u) to local(%u)\\n\", si->data.u_reg, emit->stack_start + i);\n            si->kind = STACK_VALUE;\n            emit_native_mov_state_reg(emit, emit->stack_start + i, si->data.u_reg);\n        }\n    }\n    for (int i = 0; i < emit->stack_size; i++) {\n        stack_info_t *si = &emit->stack_info[i];\n        if (si->kind == STACK_IMM) {\n            DEBUG_printf(\"    imm(\" INT_FMT \") to local(%u)\\n\", si->data.u_imm, emit->stack_start + i);\n            si->kind = STACK_VALUE;\n            si->vtype = load_reg_stack_imm(emit, REG_TEMP0, si, false);\n            emit_native_mov_state_reg(emit, emit->stack_start + i, REG_TEMP0);\n        }\n    }\n}\n\n// pos=1 is TOS, pos=2 is next, etc\nSTATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int reg_dest) {\n    need_reg_single(emit, reg_dest, pos);\n    stack_info_t *si = &emit->stack_info[emit->stack_size - pos];\n    *vtype = si->vtype;\n    switch (si->kind) {\n        case STACK_VALUE:\n            emit_native_mov_reg_state(emit, reg_dest, emit->stack_start + emit->stack_size - pos);\n            break;\n\n        case STACK_REG:\n            if (si->data.u_reg != reg_dest) {\n                ASM_MOV_REG_REG(emit->as, reg_dest, si->data.u_reg);\n            }\n            break;\n\n        case STACK_IMM:\n            *vtype = load_reg_stack_imm(emit, reg_dest, si, false);\n            break;\n    }\n}\n\n// does an efficient X=pop(); discard(); push(X)\n// needs a (non-temp) register in case the poped element was stored in the stack\nSTATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) {\n    stack_info_t *si = &emit->stack_info[emit->stack_size - 2];\n    si[0] = si[1];\n    if (si->kind == STACK_VALUE) {\n        // if folded element was on the stack we need to put it in a register\n        emit_native_mov_reg_state(emit, reg_dest, emit->stack_start + emit->stack_size - 1);\n        si->kind = STACK_REG;\n        si->data.u_reg = reg_dest;\n    }\n    adjust_stack(emit, -1);\n}\n\n// If stacked value is in a register and the register is not r1 or r2, then\n// *reg_dest is set to that register.  Otherwise the value is put in *reg_dest.\nSTATIC void emit_pre_pop_reg_flexible(emit_t *emit, vtype_kind_t *vtype, int *reg_dest, int not_r1, int not_r2) {\n    emit->last_emit_was_return_value = false;\n    stack_info_t *si = peek_stack(emit, 0);\n    if (si->kind == STACK_REG && si->data.u_reg != not_r1 && si->data.u_reg != not_r2) {\n        *vtype = si->vtype;\n        *reg_dest = si->data.u_reg;\n        need_reg_single(emit, *reg_dest, 1);\n    } else {\n        emit_access_stack(emit, 1, vtype, *reg_dest);\n    }\n    adjust_stack(emit, -1);\n}\n\nSTATIC void emit_pre_pop_discard(emit_t *emit) {\n    emit->last_emit_was_return_value = false;\n    adjust_stack(emit, -1);\n}\n\nSTATIC void emit_pre_pop_reg(emit_t *emit, vtype_kind_t *vtype, int reg_dest) {\n    emit->last_emit_was_return_value = false;\n    emit_access_stack(emit, 1, vtype, reg_dest);\n    adjust_stack(emit, -1);\n}\n\nSTATIC void emit_pre_pop_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int rega, vtype_kind_t *vtypeb, int regb) {\n    emit_pre_pop_reg(emit, vtypea, rega);\n    emit_pre_pop_reg(emit, vtypeb, regb);\n}\n\nSTATIC 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) {\n    emit_pre_pop_reg(emit, vtypea, rega);\n    emit_pre_pop_reg(emit, vtypeb, regb);\n    emit_pre_pop_reg(emit, vtypec, regc);\n}\n\nSTATIC void emit_post(emit_t *emit) {\n    (void)emit;\n}\n\nSTATIC void emit_post_top_set_vtype(emit_t *emit, vtype_kind_t new_vtype) {\n    stack_info_t *si = &emit->stack_info[emit->stack_size - 1];\n    si->vtype = new_vtype;\n}\n\nSTATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg) {\n    ensure_extra_stack(emit, 1);\n    stack_info_t *si = &emit->stack_info[emit->stack_size];\n    si->vtype = vtype;\n    si->kind = STACK_REG;\n    si->data.u_reg = reg;\n    adjust_stack(emit, 1);\n}\n\nSTATIC void emit_post_push_imm(emit_t *emit, vtype_kind_t vtype, mp_int_t imm) {\n    ensure_extra_stack(emit, 1);\n    stack_info_t *si = &emit->stack_info[emit->stack_size];\n    si->vtype = vtype;\n    si->kind = STACK_IMM;\n    si->data.u_imm = imm;\n    adjust_stack(emit, 1);\n}\n\nSTATIC void emit_post_push_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb) {\n    emit_post_push_reg(emit, vtypea, rega);\n    emit_post_push_reg(emit, vtypeb, regb);\n}\n\nSTATIC 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) {\n    emit_post_push_reg(emit, vtypea, rega);\n    emit_post_push_reg(emit, vtypeb, regb);\n    emit_post_push_reg(emit, vtypec, regc);\n}\n\nSTATIC 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) {\n    emit_post_push_reg(emit, vtypea, rega);\n    emit_post_push_reg(emit, vtypeb, regb);\n    emit_post_push_reg(emit, vtypec, regc);\n    emit_post_push_reg(emit, vtyped, regd);\n}\n\nSTATIC void emit_call(emit_t *emit, mp_fun_kind_t fun_kind) {\n    need_reg_all(emit);\n    ASM_CALL_IND(emit->as, fun_kind);\n}\n\nSTATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) {\n    need_reg_all(emit);\n    ASM_MOV_REG_IMM(emit->as, arg_reg, arg_val);\n    ASM_CALL_IND(emit->as, fun_kind);\n}\n\nSTATIC 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) {\n    need_reg_all(emit);\n    ASM_MOV_REG_IMM(emit->as, arg_reg1, arg_val1);\n    ASM_MOV_REG_IMM(emit->as, arg_reg2, arg_val2);\n    ASM_CALL_IND(emit->as, fun_kind);\n}\n\nSTATIC void emit_call_with_qstr_arg(emit_t *emit, mp_fun_kind_t fun_kind, qstr qst, int arg_reg) {\n    need_reg_all(emit);\n    emit_native_mov_reg_qstr(emit, arg_reg, qst);\n    ASM_CALL_IND(emit->as, fun_kind);\n}\n\n// vtype of all n_pop objects is VTYPE_PYOBJ\n// Will convert any items that are not VTYPE_PYOBJ to this type and put them back on the stack.\n// If any conversions of non-immediate values are needed, then it uses REG_ARG_1, REG_ARG_2 and REG_RET.\n// Otherwise, it does not use any temporary registers (but may use reg_dest before loading it with stack pointer).\nSTATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_pop) {\n    need_reg_all(emit);\n\n    // First, store any immediate values to their respective place on the stack.\n    for (mp_uint_t i = 0; i < n_pop; i++) {\n        stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i];\n        // must push any imm's to stack\n        // must convert them to VTYPE_PYOBJ for viper code\n        if (si->kind == STACK_IMM) {\n            si->kind = STACK_VALUE;\n            si->vtype = load_reg_stack_imm(emit, reg_dest, si, true);\n            emit_native_mov_state_reg(emit, emit->stack_start + emit->stack_size - 1 - i, reg_dest);\n        }\n\n        // verify that this value is on the stack\n        assert(si->kind == STACK_VALUE);\n    }\n\n    // Second, convert any non-VTYPE_PYOBJ to that type.\n    for (mp_uint_t i = 0; i < n_pop; i++) {\n        stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i];\n        if (si->vtype != VTYPE_PYOBJ) {\n            mp_uint_t local_num = emit->stack_start + emit->stack_size - 1 - i;\n            emit_native_mov_reg_state(emit, REG_ARG_1, local_num);\n            emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, si->vtype, REG_ARG_2); // arg2 = type\n            emit_native_mov_state_reg(emit, local_num, REG_RET);\n            si->vtype = VTYPE_PYOBJ;\n            DEBUG_printf(\"  convert_native_to_obj(local_num=\" UINT_FMT \")\\n\", local_num);\n        }\n    }\n\n    // Adujust the stack for a pop of n_pop items, and load the stack pointer into reg_dest.\n    adjust_stack(emit, -n_pop);\n    emit_native_mov_reg_state_addr(emit, reg_dest, emit->stack_start + emit->stack_size);\n}\n\n// vtype of all n_push objects is VTYPE_PYOBJ\nSTATIC void emit_get_stack_pointer_to_reg_for_push(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_push) {\n    need_reg_all(emit);\n    ensure_extra_stack(emit, n_push);\n    for (mp_uint_t i = 0; i < n_push; i++) {\n        emit->stack_info[emit->stack_size + i].kind = STACK_VALUE;\n        emit->stack_info[emit->stack_size + i].vtype = VTYPE_PYOBJ;\n    }\n    emit_native_mov_reg_state_addr(emit, reg_dest, emit->stack_start + emit->stack_size);\n    adjust_stack(emit, n_push);\n}\n\nSTATIC void emit_native_push_exc_stack(emit_t *emit, uint label, bool is_finally) {\n    if (emit->exc_stack_size + 1 > emit->exc_stack_alloc) {\n        size_t new_alloc = emit->exc_stack_alloc + 4;\n        emit->exc_stack = m_renew(exc_stack_entry_t, emit->exc_stack, emit->exc_stack_alloc, new_alloc);\n        emit->exc_stack_alloc = new_alloc;\n    }\n\n    exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size++];\n    e->label = label;\n    e->is_finally = is_finally;\n    e->unwind_label = UNWIND_LABEL_UNUSED;\n    e->is_active = true;\n\n    ASM_MOV_REG_PCREL(emit->as, REG_RET, label);\n    ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET);\n}\n\nSTATIC void emit_native_leave_exc_stack(emit_t *emit, bool start_of_handler) {\n    assert(emit->exc_stack_size > 0);\n\n    // Get current exception handler and deactivate it\n    exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1];\n    e->is_active = false;\n\n    // Find next innermost active exception handler, to restore as current handler\n    for (--e; e >= emit->exc_stack && !e->is_active; --e) {\n    }\n\n    // Update the PC of the new exception handler\n    if (e < emit->exc_stack) {\n        // No active handler, clear handler PC to zero\n        if (start_of_handler) {\n            // Optimisation: PC is already cleared by global exc handler\n            return;\n        }\n        ASM_XOR_REG_REG(emit->as, REG_RET, REG_RET);\n    } else {\n        // Found new active handler, get its PC\n        ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label);\n    }\n    ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET);\n}\n\nSTATIC exc_stack_entry_t *emit_native_pop_exc_stack(emit_t *emit) {\n    assert(emit->exc_stack_size > 0);\n    exc_stack_entry_t *e = &emit->exc_stack[--emit->exc_stack_size];\n    assert(e->is_active == false);\n    return e;\n}\n\nSTATIC void emit_load_reg_with_ptr(emit_t *emit, int reg, mp_uint_t ptr, size_t table_off) {\n    if (!emit->do_viper_types) {\n        // Skip qstr names of arguments\n        table_off += emit->scope->num_pos_args + emit->scope->num_kwonly_args;\n    }\n    if (emit->pass == MP_PASS_EMIT) {\n        emit->const_table[table_off] = ptr;\n    }\n    emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_FUN_OBJ(emit));\n    ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);\n    ASM_LOAD_REG_REG_OFFSET(emit->as, reg, REG_TEMP0, table_off);\n}\n\nSTATIC void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj) {\n    // First entry is for mp_fun_table\n    size_t table_off = 1 + emit->const_table_cur_obj++;\n    emit_load_reg_with_ptr(emit, reg, (mp_uint_t)obj, table_off);\n}\n\nSTATIC void emit_load_reg_with_raw_code(emit_t *emit, int reg, mp_raw_code_t *rc) {\n    // First entry is for mp_fun_table, then constant objects\n    size_t table_off = 1 + emit->const_table_num_obj + emit->const_table_cur_raw_code++;\n    emit_load_reg_with_ptr(emit, reg, (mp_uint_t)rc, table_off);\n}\n\nSTATIC void emit_native_label_assign(emit_t *emit, mp_uint_t l) {\n    DEBUG_printf(\"label_assign(\" UINT_FMT \")\\n\", l);\n\n    bool is_finally = false;\n    if (emit->exc_stack_size > 0) {\n        exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1];\n        is_finally = e->is_finally && e->label == l;\n    }\n\n    if (is_finally) {\n        // Label is at start of finally handler: store TOS into exception slot\n        vtype_kind_t vtype;\n        emit_pre_pop_reg(emit, &vtype, REG_TEMP0);\n        ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0);\n    }\n\n    emit_native_pre(emit);\n    // need to commit stack because we can jump here from elsewhere\n    need_stack_settled(emit);\n    mp_asm_base_label_assign(&emit->as->base, l);\n    emit_post(emit);\n\n    if (is_finally) {\n        // Label is at start of finally handler: pop exception stack\n        emit_native_leave_exc_stack(emit, false);\n    }\n}\n\nSTATIC void emit_native_global_exc_entry(emit_t *emit) {\n    // Note: 4 labels are reserved for this function, starting at *emit->label_slot\n\n    emit->exit_label = *emit->label_slot;\n\n    if (NEED_GLOBAL_EXC_HANDLER(emit)) {\n        mp_uint_t nlr_label = *emit->label_slot + 1;\n        mp_uint_t start_label = *emit->label_slot + 2;\n        mp_uint_t global_except_label = *emit->label_slot + 3;\n\n        if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {\n            // Set new globals\n            emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_FUN_OBJ(emit));\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, OFFSETOF_OBJ_FUN_BC_GLOBALS);\n            emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);\n\n            // Save old globals (or NULL if globals didn't change)\n            emit_native_mov_state_reg(emit, LOCAL_IDX_OLD_GLOBALS(emit), REG_RET);\n        }\n\n        if (emit->scope->exc_stack_size == 0) {\n            if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {\n                // Optimisation: if globals didn't change don't push the nlr context\n                ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, false);\n            }\n\n            // Wrap everything in an nlr context\n            ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0);\n            emit_call(emit, MP_F_NLR_PUSH);\n            #if N_NLR_SETJMP\n            ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 2);\n            emit_call(emit, MP_F_SETJMP);\n            #endif\n            ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, true);\n        } else {\n            // Clear the unwind state\n            ASM_XOR_REG_REG(emit->as, REG_TEMP0, REG_TEMP0);\n            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_TEMP0);\n\n            // Put PC of start code block into REG_LOCAL_1\n            ASM_MOV_REG_PCREL(emit->as, REG_LOCAL_1, start_label);\n\n            // Wrap everything in an nlr context\n            emit_native_label_assign(emit, nlr_label);\n            ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_2, LOCAL_IDX_EXC_HANDLER_UNWIND(emit));\n            ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0);\n            emit_call(emit, MP_F_NLR_PUSH);\n            #if N_NLR_SETJMP\n            ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 2);\n            emit_call(emit, MP_F_SETJMP);\n            #endif\n            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_LOCAL_2);\n            ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, global_except_label, true);\n\n            // Clear PC of current code block, and jump there to resume execution\n            ASM_XOR_REG_REG(emit->as, REG_TEMP0, REG_TEMP0);\n            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_TEMP0);\n            ASM_JUMP_REG(emit->as, REG_LOCAL_1);\n\n            // Global exception handler: check for valid exception handler\n            emit_native_label_assign(emit, global_except_label);\n            #if N_NLR_SETJMP\n            // Reload REG_FUN_TABLE, since it may be clobbered by longjmp\n            emit_native_mov_reg_state(emit, REG_LOCAL_1, LOCAL_IDX_FUN_OBJ(emit));\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_1, REG_LOCAL_1, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t));\n            ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_1, emit->scope->num_pos_args + emit->scope->num_kwonly_args);\n            #endif\n            ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_1, LOCAL_IDX_EXC_HANDLER_PC(emit));\n            ASM_JUMP_IF_REG_NONZERO(emit->as, REG_LOCAL_1, nlr_label, false);\n        }\n\n        if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {\n            // Restore old globals\n            emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit));\n            emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);\n        }\n\n        if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {\n            // Store return value in state[0]\n            ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, LOCAL_IDX_EXC_VAL(emit));\n            ASM_STORE_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, OFFSETOF_CODE_STATE_STATE);\n\n            // Load return kind\n            ASM_MOV_REG_IMM(emit->as, REG_PARENT_RET, MP_VM_RETURN_EXCEPTION);\n\n            ASM_EXIT(emit->as);\n        } else {\n            // Re-raise exception out to caller\n            ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit));\n            emit_call(emit, MP_F_NATIVE_RAISE);\n        }\n\n        // Label for start of function\n        emit_native_label_assign(emit, start_label);\n\n        if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {\n            emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_GEN_PC(emit));\n            ASM_JUMP_REG(emit->as, REG_TEMP0);\n            emit->start_offset = mp_asm_base_get_code_pos(&emit->as->base);\n\n            // This is the first entry of the generator\n\n            // Check LOCAL_IDX_EXC_VAL for any injected value\n            ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit));\n            emit_call(emit, MP_F_NATIVE_RAISE);\n        }\n    }\n}\n\nSTATIC void emit_native_global_exc_exit(emit_t *emit) {\n    // Label for end of function\n    emit_native_label_assign(emit, emit->exit_label);\n\n    if (NEED_GLOBAL_EXC_HANDLER(emit)) {\n        // Get old globals\n        if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {\n            emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit));\n\n            if (emit->scope->exc_stack_size == 0) {\n                // Optimisation: if globals didn't change then don't restore them and don't do nlr_pop\n                ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, emit->exit_label + 1, false);\n            }\n\n            // Restore old globals\n            emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);\n        }\n\n        // Pop the nlr context\n        emit_call(emit, MP_F_NLR_POP);\n\n        if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {\n            if (emit->scope->exc_stack_size == 0) {\n                // Destination label for above optimisation\n                emit_native_label_assign(emit, emit->exit_label + 1);\n            }\n        }\n\n        // Load return value\n        ASM_MOV_REG_LOCAL(emit->as, REG_PARENT_RET, LOCAL_IDX_RET_VAL(emit));\n    }\n\n    ASM_EXIT(emit->as);\n}\n\nSTATIC void emit_native_import_name(emit_t *emit, qstr qst) {\n    DEBUG_printf(\"import_name %s\\n\", qstr_str(qst));\n\n    // get arguments from stack: arg2 = fromlist, arg3 = level\n    // If using viper types these arguments must be converted to proper objects, and\n    // to accomplish this viper types are turned off for the emit_pre_pop_reg_reg call.\n    bool orig_do_viper_types = emit->do_viper_types;\n    emit->do_viper_types = false;\n    vtype_kind_t vtype_fromlist;\n    vtype_kind_t vtype_level;\n    emit_pre_pop_reg_reg(emit, &vtype_fromlist, REG_ARG_2, &vtype_level, REG_ARG_3);\n    assert(vtype_fromlist == VTYPE_PYOBJ);\n    assert(vtype_level == VTYPE_PYOBJ);\n    emit->do_viper_types = orig_do_viper_types;\n\n    emit_call_with_qstr_arg(emit, MP_F_IMPORT_NAME, qst, REG_ARG_1); // arg1 = import name\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n\nSTATIC void emit_native_import_from(emit_t *emit, qstr qst) {\n    DEBUG_printf(\"import_from %s\\n\", qstr_str(qst));\n    emit_native_pre(emit);\n    vtype_kind_t vtype_module;\n    emit_access_stack(emit, 1, &vtype_module, REG_ARG_1); // arg1 = module\n    assert(vtype_module == VTYPE_PYOBJ);\n    emit_call_with_qstr_arg(emit, MP_F_IMPORT_FROM, qst, REG_ARG_2); // arg2 = import name\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n\nSTATIC void emit_native_import_star(emit_t *emit) {\n    DEBUG_printf(\"import_star\\n\");\n    vtype_kind_t vtype_module;\n    emit_pre_pop_reg(emit, &vtype_module, REG_ARG_1); // arg1 = module\n    assert(vtype_module == VTYPE_PYOBJ);\n    emit_call(emit, MP_F_IMPORT_ALL);\n    emit_post(emit);\n}\n\nSTATIC void emit_native_import(emit_t *emit, qstr qst, int kind) {\n    if (kind == MP_EMIT_IMPORT_NAME) {\n        emit_native_import_name(emit, qst);\n    } else if (kind == MP_EMIT_IMPORT_FROM) {\n        emit_native_import_from(emit, qst);\n    } else {\n        emit_native_import_star(emit);\n    }\n}\n\nSTATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {\n    DEBUG_printf(\"load_const_tok(tok=%u)\\n\", tok);\n    if (tok == MP_TOKEN_ELLIPSIS) {\n        #if MICROPY_PERSISTENT_CODE_SAVE\n        emit_native_load_const_obj(emit, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj));\n        #else\n        emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj));\n        #endif\n    } else {\n        emit_native_pre(emit);\n        if (tok == MP_TOKEN_KW_NONE) {\n            emit_post_push_imm(emit, VTYPE_PTR_NONE, 0);\n        } else {\n            emit_post_push_imm(emit, VTYPE_BOOL, tok == MP_TOKEN_KW_FALSE ? 0 : 1);\n        }\n    }\n}\n\nSTATIC void emit_native_load_const_small_int(emit_t *emit, mp_int_t arg) {\n    DEBUG_printf(\"load_const_small_int(int=\" INT_FMT \")\\n\", arg);\n    emit_native_pre(emit);\n    emit_post_push_imm(emit, VTYPE_INT, arg);\n}\n\nSTATIC void emit_native_load_const_str(emit_t *emit, qstr qst) {\n    emit_native_pre(emit);\n    // TODO: Eventually we want to be able to work with raw pointers in viper to\n    // do native array access.  For now we just load them as any other object.\n    /*\n    if (emit->do_viper_types) {\n        // load a pointer to the asciiz string?\n        emit_post_push_imm(emit, VTYPE_PTR, (mp_uint_t)qstr_str(qst));\n    } else\n    */\n    {\n        need_reg_single(emit, REG_TEMP0, 0);\n        emit_native_mov_reg_qstr_obj(emit, REG_TEMP0, qst);\n        emit_post_push_reg(emit, VTYPE_PYOBJ, REG_TEMP0);\n    }\n}\n\nSTATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj) {\n    emit->scope->scope_flags |= MP_SCOPE_FLAG_HASCONSTS;\n    emit_native_pre(emit);\n    need_reg_single(emit, REG_RET, 0);\n    emit_load_reg_with_object(emit, REG_RET, obj);\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n\nSTATIC void emit_native_load_null(emit_t *emit) {\n    emit_native_pre(emit);\n    emit_post_push_imm(emit, VTYPE_PYOBJ, 0);\n}\n\nSTATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {\n    DEBUG_printf(\"load_fast(%s, \" UINT_FMT \")\\n\", qstr_str(qst), local_num);\n    vtype_kind_t vtype = emit->local_vtype[local_num];\n    if (vtype == VTYPE_UNBOUND) {\n        EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT(\"local '%q' used before type known\"), qst);\n    }\n    emit_native_pre(emit);\n    if (local_num < REG_LOCAL_NUM && CAN_USE_REGS_FOR_LOCALS(emit)) {\n        emit_post_push_reg(emit, vtype, reg_local_table[local_num]);\n    } else {\n        need_reg_single(emit, REG_TEMP0, 0);\n        emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_LOCAL_VAR(emit, local_num));\n        emit_post_push_reg(emit, vtype, REG_TEMP0);\n    }\n}\n\nSTATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {\n    DEBUG_printf(\"load_deref(%s, \" UINT_FMT \")\\n\", qstr_str(qst), local_num);\n    need_reg_single(emit, REG_RET, 0);\n    emit_native_load_fast(emit, qst, local_num);\n    vtype_kind_t vtype;\n    int reg_base = REG_RET;\n    emit_pre_pop_reg_flexible(emit, &vtype, &reg_base, -1, -1);\n    ASM_LOAD_REG_REG_OFFSET(emit->as, REG_RET, reg_base, 1);\n    // closed over vars are always Python objects\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n\nSTATIC void emit_native_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {\n    if (kind == MP_EMIT_IDOP_LOCAL_FAST) {\n        emit_native_load_fast(emit, qst, local_num);\n    } else {\n        emit_native_load_deref(emit, qst, local_num);\n    }\n}\n\nSTATIC void emit_native_load_global(emit_t *emit, qstr qst, int kind) {\n    MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_LOAD_NAME);\n    MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_LOAD_GLOBAL);\n    emit_native_pre(emit);\n    if (kind == MP_EMIT_IDOP_GLOBAL_NAME) {\n        DEBUG_printf(\"load_name(%s)\\n\", qstr_str(qst));\n    } else {\n        DEBUG_printf(\"load_global(%s)\\n\", qstr_str(qst));\n        if (emit->do_viper_types) {\n            // check for builtin casting operators\n            int native_type = mp_native_type_from_qstr(qst);\n            if (native_type >= MP_NATIVE_TYPE_BOOL) {\n                emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, native_type);\n                return;\n            }\n        }\n    }\n    emit_call_with_qstr_arg(emit, MP_F_LOAD_NAME + kind, qst, REG_ARG_1);\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n\nSTATIC void emit_native_load_attr(emit_t *emit, qstr qst) {\n    // depends on type of subject:\n    //  - integer, function, pointer to integers: error\n    //  - pointer to structure: get member, quite easy\n    //  - Python object: call mp_load_attr, and needs to be typed to convert result\n    vtype_kind_t vtype_base;\n    emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base\n    assert(vtype_base == VTYPE_PYOBJ);\n    emit_call_with_qstr_arg(emit, MP_F_LOAD_ATTR, qst, REG_ARG_2); // arg2 = attribute name\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n\nSTATIC void emit_native_load_method(emit_t *emit, qstr qst, bool is_super) {\n    if (is_super) {\n        emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, 3); // arg2 = dest ptr\n        emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, 2); // arg2 = dest ptr\n        emit_call_with_qstr_arg(emit, MP_F_LOAD_SUPER_METHOD, qst, REG_ARG_1); // arg1 = method name\n    } else {\n        vtype_kind_t vtype_base;\n        emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base\n        assert(vtype_base == VTYPE_PYOBJ);\n        emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr\n        emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name\n    }\n}\n\nSTATIC void emit_native_load_build_class(emit_t *emit) {\n    emit_native_pre(emit);\n    emit_call(emit, MP_F_LOAD_BUILD_CLASS);\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n\nSTATIC void emit_native_load_subscr(emit_t *emit) {\n    DEBUG_printf(\"load_subscr\\n\");\n    // need to compile: base[index]\n\n    // pop: index, base\n    // optimise case where index is an immediate\n    vtype_kind_t vtype_base = peek_vtype(emit, 1);\n\n    if (vtype_base == VTYPE_PYOBJ) {\n        // standard Python subscr\n        // TODO factor this implicit cast code with other uses of it\n        vtype_kind_t vtype_index = peek_vtype(emit, 0);\n        if (vtype_index == VTYPE_PYOBJ) {\n            emit_pre_pop_reg(emit, &vtype_index, REG_ARG_2);\n        } else {\n            emit_pre_pop_reg(emit, &vtype_index, REG_ARG_1);\n            emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype_index, REG_ARG_2); // arg2 = type\n            ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);\n        }\n        emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);\n        emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_SENTINEL, REG_ARG_3);\n        emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n    } else {\n        // viper load\n        // TODO The different machine architectures have very different\n        // capabilities and requirements for loads, so probably best to\n        // write a completely separate load-optimiser for each one.\n        stack_info_t *top = peek_stack(emit, 0);\n        if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {\n            // index is an immediate\n            mp_int_t index_value = top->data.u_imm;\n            emit_pre_pop_discard(emit); // discard index\n            int reg_base = REG_ARG_1;\n            int reg_index = REG_ARG_2;\n            emit_pre_pop_reg_flexible(emit, &vtype_base, &reg_base, reg_index, reg_index);\n            switch (vtype_base) {\n                case VTYPE_PTR8: {\n                    // pointer to 8-bit memory\n                    // TODO optimise to use thumb ldrb r1, [r2, r3]\n                    if (index_value != 0) {\n                        // index is non-zero\n                        #if N_THUMB\n                        if (index_value > 0 && index_value < 32) {\n                            asm_thumb_ldrb_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value);\n                            break;\n                        }\n                        #endif\n                        ASM_MOV_REG_IMM(emit->as, reg_index, index_value);\n                        ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base\n                        reg_base = reg_index;\n                    }\n                    ASM_LOAD8_REG_REG(emit->as, REG_RET, reg_base); // load from (base+index)\n                    break;\n                }\n                case VTYPE_PTR16: {\n                    // pointer to 16-bit memory\n                    if (index_value != 0) {\n                        // index is a non-zero immediate\n                        #if N_THUMB\n                        if (index_value > 0 && index_value < 32) {\n                            asm_thumb_ldrh_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value);\n                            break;\n                        }\n                        #endif\n                        ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1);\n                        ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base\n                        reg_base = reg_index;\n                    }\n                    ASM_LOAD16_REG_REG(emit->as, REG_RET, reg_base); // load from (base+2*index)\n                    break;\n                }\n                case VTYPE_PTR32: {\n                    // pointer to 32-bit memory\n                    if (index_value != 0) {\n                        // index is a non-zero immediate\n                        #if N_THUMB\n                        if (index_value > 0 && index_value < 32) {\n                            asm_thumb_ldr_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value);\n                            break;\n                        }\n                        #endif\n                        ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2);\n                        ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base\n                        reg_base = reg_index;\n                    }\n                    ASM_LOAD32_REG_REG(emit->as, REG_RET, reg_base); // load from (base+4*index)\n                    break;\n                }\n                default:\n                    EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                        MP_ERROR_TEXT(\"can't load from '%q'\"), vtype_to_qstr(vtype_base));\n            }\n        } else {\n            // index is not an immediate\n            vtype_kind_t vtype_index;\n            int reg_index = REG_ARG_2;\n            emit_pre_pop_reg_flexible(emit, &vtype_index, &reg_index, REG_ARG_1, REG_ARG_1);\n            emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);\n            if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) {\n                EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                    MP_ERROR_TEXT(\"can't load with '%q' index\"), vtype_to_qstr(vtype_index));\n            }\n            switch (vtype_base) {\n                case VTYPE_PTR8: {\n                    // pointer to 8-bit memory\n                    // TODO optimise to use thumb ldrb r1, [r2, r3]\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_LOAD8_REG_REG(emit->as, REG_RET, REG_ARG_1); // store value to (base+index)\n                    break;\n                }\n                case VTYPE_PTR16: {\n                    // pointer to 16-bit memory\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_LOAD16_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+2*index)\n                    break;\n                }\n                case VTYPE_PTR32: {\n                    // pointer to word-size memory\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_LOAD32_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+4*index)\n                    break;\n                }\n                default:\n                    EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                        MP_ERROR_TEXT(\"can't load from '%q'\"), vtype_to_qstr(vtype_base));\n            }\n        }\n        emit_post_push_reg(emit, VTYPE_INT, REG_RET);\n    }\n}\n\nSTATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {\n    vtype_kind_t vtype;\n    if (local_num < REG_LOCAL_NUM && CAN_USE_REGS_FOR_LOCALS(emit)) {\n        emit_pre_pop_reg(emit, &vtype, reg_local_table[local_num]);\n    } else {\n        emit_pre_pop_reg(emit, &vtype, REG_TEMP0);\n        emit_native_mov_state_reg(emit, LOCAL_IDX_LOCAL_VAR(emit, local_num), REG_TEMP0);\n    }\n    emit_post(emit);\n\n    // check types\n    if (emit->local_vtype[local_num] == VTYPE_UNBOUND) {\n        // first time this local is assigned, so give it a type of the object stored in it\n        emit->local_vtype[local_num] = vtype;\n    } else if (emit->local_vtype[local_num] != vtype) {\n        // type of local is not the same as object stored in it\n        EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n            MP_ERROR_TEXT(\"local '%q' has type '%q' but source is '%q'\"),\n            qst, vtype_to_qstr(emit->local_vtype[local_num]), vtype_to_qstr(vtype));\n    }\n}\n\nSTATIC void emit_native_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {\n    DEBUG_printf(\"store_deref(%s, \" UINT_FMT \")\\n\", qstr_str(qst), local_num);\n    need_reg_single(emit, REG_TEMP0, 0);\n    need_reg_single(emit, REG_TEMP1, 0);\n    emit_native_load_fast(emit, qst, local_num);\n    vtype_kind_t vtype;\n    int reg_base = REG_TEMP0;\n    emit_pre_pop_reg_flexible(emit, &vtype, &reg_base, -1, -1);\n    int reg_src = REG_TEMP1;\n    emit_pre_pop_reg_flexible(emit, &vtype, &reg_src, reg_base, reg_base);\n    ASM_STORE_REG_REG_OFFSET(emit->as, reg_src, reg_base, 1);\n    emit_post(emit);\n}\n\nSTATIC void emit_native_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {\n    if (kind == MP_EMIT_IDOP_LOCAL_FAST) {\n        emit_native_store_fast(emit, qst, local_num);\n    } else {\n        emit_native_store_deref(emit, qst, local_num);\n    }\n}\n\nSTATIC void emit_native_store_global(emit_t *emit, qstr qst, int kind) {\n    MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_STORE_NAME);\n    MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_STORE_GLOBAL);\n    if (kind == MP_EMIT_IDOP_GLOBAL_NAME) {\n        // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type))\n        vtype_kind_t vtype;\n        emit_pre_pop_reg(emit, &vtype, REG_ARG_2);\n        assert(vtype == VTYPE_PYOBJ);\n    } else {\n        vtype_kind_t vtype = peek_vtype(emit, 0);\n        if (vtype == VTYPE_PYOBJ) {\n            emit_pre_pop_reg(emit, &vtype, REG_ARG_2);\n        } else {\n            emit_pre_pop_reg(emit, &vtype, REG_ARG_1);\n            emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type\n            ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);\n        }\n    }\n    emit_call_with_qstr_arg(emit, MP_F_STORE_NAME + kind, qst, REG_ARG_1); // arg1 = name\n    emit_post(emit);\n}\n\nSTATIC void emit_native_store_attr(emit_t *emit, qstr qst) {\n    vtype_kind_t vtype_base, vtype_val;\n    emit_pre_pop_reg_reg(emit, &vtype_base, REG_ARG_1, &vtype_val, REG_ARG_3); // arg1 = base, arg3 = value\n    assert(vtype_base == VTYPE_PYOBJ);\n    assert(vtype_val == VTYPE_PYOBJ);\n    emit_call_with_qstr_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name\n    emit_post(emit);\n}\n\nSTATIC void emit_native_store_subscr(emit_t *emit) {\n    DEBUG_printf(\"store_subscr\\n\");\n    // need to compile: base[index] = value\n\n    // pop: index, base, value\n    // optimise case where index is an immediate\n    vtype_kind_t vtype_base = peek_vtype(emit, 1);\n\n    if (vtype_base == VTYPE_PYOBJ) {\n        // standard Python subscr\n        vtype_kind_t vtype_index = peek_vtype(emit, 0);\n        vtype_kind_t vtype_value = peek_vtype(emit, 2);\n        if (vtype_index != VTYPE_PYOBJ || vtype_value != VTYPE_PYOBJ) {\n            // need to implicitly convert non-objects to objects\n            // TODO do this properly\n            emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, 3);\n            adjust_stack(emit, 3);\n        }\n        emit_pre_pop_reg_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1, &vtype_value, REG_ARG_3);\n        emit_call(emit, MP_F_OBJ_SUBSCR);\n    } else {\n        // viper store\n        // TODO The different machine architectures have very different\n        // capabilities and requirements for stores, so probably best to\n        // write a completely separate store-optimiser for each one.\n        stack_info_t *top = peek_stack(emit, 0);\n        if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {\n            // index is an immediate\n            mp_int_t index_value = top->data.u_imm;\n            emit_pre_pop_discard(emit); // discard index\n            vtype_kind_t vtype_value;\n            int reg_base = REG_ARG_1;\n            int reg_index = REG_ARG_2;\n            int reg_value = REG_ARG_3;\n            emit_pre_pop_reg_flexible(emit, &vtype_base, &reg_base, reg_index, reg_value);\n            #if N_X86\n            // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)\n            emit_pre_pop_reg(emit, &vtype_value, reg_value);\n            #else\n            emit_pre_pop_reg_flexible(emit, &vtype_value, &reg_value, reg_base, reg_index);\n            #endif\n            if (vtype_value != VTYPE_BOOL && vtype_value != VTYPE_INT && vtype_value != VTYPE_UINT) {\n                EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                    MP_ERROR_TEXT(\"can't store '%q'\"), vtype_to_qstr(vtype_value));\n            }\n            switch (vtype_base) {\n                case VTYPE_PTR8: {\n                    // pointer to 8-bit memory\n                    // TODO optimise to use thumb strb r1, [r2, r3]\n                    if (index_value != 0) {\n                        // index is non-zero\n                        #if N_THUMB\n                        if (index_value > 0 && index_value < 32) {\n                            asm_thumb_strb_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value);\n                            break;\n                        }\n                        #endif\n                        ASM_MOV_REG_IMM(emit->as, reg_index, index_value);\n                        #if N_ARM\n                        asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);\n                        return;\n                        #endif\n                        ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base\n                        reg_base = reg_index;\n                    }\n                    ASM_STORE8_REG_REG(emit->as, reg_value, reg_base); // store value to (base+index)\n                    break;\n                }\n                case VTYPE_PTR16: {\n                    // pointer to 16-bit memory\n                    if (index_value != 0) {\n                        // index is a non-zero immediate\n                        #if N_THUMB\n                        if (index_value > 0 && index_value < 32) {\n                            asm_thumb_strh_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value);\n                            break;\n                        }\n                        #endif\n                        ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1);\n                        ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base\n                        reg_base = reg_index;\n                    }\n                    ASM_STORE16_REG_REG(emit->as, reg_value, reg_base); // store value to (base+2*index)\n                    break;\n                }\n                case VTYPE_PTR32: {\n                    // pointer to 32-bit memory\n                    if (index_value != 0) {\n                        // index is a non-zero immediate\n                        #if N_THUMB\n                        if (index_value > 0 && index_value < 32) {\n                            asm_thumb_str_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value);\n                            break;\n                        }\n                        #endif\n                        #if N_ARM\n                        ASM_MOV_REG_IMM(emit->as, reg_index, index_value);\n                        asm_arm_str_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);\n                        return;\n                        #endif\n                        ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2);\n                        ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base\n                        reg_base = reg_index;\n                    }\n                    ASM_STORE32_REG_REG(emit->as, reg_value, reg_base); // store value to (base+4*index)\n                    break;\n                }\n                default:\n                    EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                        MP_ERROR_TEXT(\"can't store to '%q'\"), vtype_to_qstr(vtype_base));\n            }\n        } else {\n            // index is not an immediate\n            vtype_kind_t vtype_index, vtype_value;\n            int reg_index = REG_ARG_2;\n            int reg_value = REG_ARG_3;\n            emit_pre_pop_reg_flexible(emit, &vtype_index, &reg_index, REG_ARG_1, reg_value);\n            emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);\n            if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) {\n                EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                    MP_ERROR_TEXT(\"can't store with '%q' index\"), vtype_to_qstr(vtype_index));\n            }\n            #if N_X86\n            // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)\n            emit_pre_pop_reg(emit, &vtype_value, reg_value);\n            #else\n            emit_pre_pop_reg_flexible(emit, &vtype_value, &reg_value, REG_ARG_1, reg_index);\n            #endif\n            if (vtype_value != VTYPE_BOOL && vtype_value != VTYPE_INT && vtype_value != VTYPE_UINT) {\n                EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                    MP_ERROR_TEXT(\"can't store '%q'\"), vtype_to_qstr(vtype_value));\n            }\n            switch (vtype_base) {\n                case VTYPE_PTR8: {\n                    // pointer to 8-bit memory\n                    // TODO optimise to use thumb strb r1, [r2, r3]\n                    #if N_ARM\n                    asm_arm_strb_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);\n                    break;\n                    #endif\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_STORE8_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+index)\n                    break;\n                }\n                case VTYPE_PTR16: {\n                    // pointer to 16-bit memory\n                    #if N_ARM\n                    asm_arm_strh_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);\n                    break;\n                    #endif\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_STORE16_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+2*index)\n                    break;\n                }\n                case VTYPE_PTR32: {\n                    // pointer to 32-bit memory\n                    #if N_ARM\n                    asm_arm_str_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);\n                    break;\n                    #endif\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base\n                    ASM_STORE32_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+4*index)\n                    break;\n                }\n                default:\n                    EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                        MP_ERROR_TEXT(\"can't store to '%q'\"), vtype_to_qstr(vtype_base));\n            }\n        }\n\n    }\n}\n\nSTATIC void emit_native_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {\n    if (kind == MP_EMIT_IDOP_LOCAL_FAST) {\n        // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL\n        // to mark deleted vars but then every var would need to be checked on\n        // each access. Very inefficient, so just set value to None to enable GC.\n        emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE);\n        emit_native_store_fast(emit, qst, local_num);\n    } else {\n        // TODO implement me!\n    }\n}\n\nSTATIC void emit_native_delete_global(emit_t *emit, qstr qst, int kind) {\n    MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_DELETE_NAME);\n    MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_DELETE_GLOBAL);\n    emit_native_pre(emit);\n    emit_call_with_qstr_arg(emit, MP_F_DELETE_NAME + kind, qst, REG_ARG_1);\n    emit_post(emit);\n}\n\nSTATIC void emit_native_delete_attr(emit_t *emit, qstr qst) {\n    vtype_kind_t vtype_base;\n    emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base\n    assert(vtype_base == VTYPE_PYOBJ);\n    ASM_XOR_REG_REG(emit->as, REG_ARG_3, REG_ARG_3); // arg3 = value (null for delete)\n    emit_call_with_qstr_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name\n    emit_post(emit);\n}\n\nSTATIC void emit_native_delete_subscr(emit_t *emit) {\n    vtype_kind_t vtype_index, vtype_base;\n    emit_pre_pop_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1); // index, base\n    assert(vtype_index == VTYPE_PYOBJ);\n    assert(vtype_base == VTYPE_PYOBJ);\n    emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3);\n}\n\nSTATIC void emit_native_subscr(emit_t *emit, int kind) {\n    if (kind == MP_EMIT_SUBSCR_LOAD) {\n        emit_native_load_subscr(emit);\n    } else if (kind == MP_EMIT_SUBSCR_STORE) {\n        emit_native_store_subscr(emit);\n    } else {\n        emit_native_delete_subscr(emit);\n    }\n}\n\nSTATIC void emit_native_attr(emit_t *emit, qstr qst, int kind) {\n    if (kind == MP_EMIT_ATTR_LOAD) {\n        emit_native_load_attr(emit, qst);\n    } else if (kind == MP_EMIT_ATTR_STORE) {\n        emit_native_store_attr(emit, qst);\n    } else {\n        emit_native_delete_attr(emit, qst);\n    }\n}\n\nSTATIC void emit_native_dup_top(emit_t *emit) {\n    DEBUG_printf(\"dup_top\\n\");\n    vtype_kind_t vtype;\n    int reg = REG_TEMP0;\n    emit_pre_pop_reg_flexible(emit, &vtype, &reg, -1, -1);\n    emit_post_push_reg_reg(emit, vtype, reg, vtype, reg);\n}\n\nSTATIC void emit_native_dup_top_two(emit_t *emit) {\n    vtype_kind_t vtype0, vtype1;\n    emit_pre_pop_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1);\n    emit_post_push_reg_reg_reg_reg(emit, vtype1, REG_TEMP1, vtype0, REG_TEMP0, vtype1, REG_TEMP1, vtype0, REG_TEMP0);\n}\n\nSTATIC void emit_native_pop_top(emit_t *emit) {\n    DEBUG_printf(\"pop_top\\n\");\n    emit_pre_pop_discard(emit);\n    emit_post(emit);\n}\n\nSTATIC void emit_native_rot_two(emit_t *emit) {\n    DEBUG_printf(\"rot_two\\n\");\n    vtype_kind_t vtype0, vtype1;\n    emit_pre_pop_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1);\n    emit_post_push_reg_reg(emit, vtype0, REG_TEMP0, vtype1, REG_TEMP1);\n}\n\nSTATIC void emit_native_rot_three(emit_t *emit) {\n    DEBUG_printf(\"rot_three\\n\");\n    vtype_kind_t vtype0, vtype1, vtype2;\n    emit_pre_pop_reg_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1, &vtype2, REG_TEMP2);\n    emit_post_push_reg_reg_reg(emit, vtype0, REG_TEMP0, vtype2, REG_TEMP2, vtype1, REG_TEMP1);\n}\n\nSTATIC void emit_native_jump(emit_t *emit, mp_uint_t label) {\n    DEBUG_printf(\"jump(label=\" UINT_FMT \")\\n\", label);\n    emit_native_pre(emit);\n    // need to commit stack because we are jumping elsewhere\n    need_stack_settled(emit);\n    ASM_JUMP(emit->as, label);\n    emit_post(emit);\n}\n\nSTATIC void emit_native_jump_helper(emit_t *emit, bool cond, mp_uint_t label, bool pop) {\n    vtype_kind_t vtype = peek_vtype(emit, 0);\n    if (vtype == VTYPE_PYOBJ) {\n        emit_pre_pop_reg(emit, &vtype, REG_ARG_1);\n        if (!pop) {\n            adjust_stack(emit, 1);\n        }\n        emit_call(emit, MP_F_OBJ_IS_TRUE);\n    } else {\n        emit_pre_pop_reg(emit, &vtype, REG_RET);\n        if (!pop) {\n            adjust_stack(emit, 1);\n        }\n        if (!(vtype == VTYPE_BOOL || vtype == VTYPE_INT || vtype == VTYPE_UINT)) {\n            EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                MP_ERROR_TEXT(\"can't implicitly convert '%q' to 'bool'\"), vtype_to_qstr(vtype));\n        }\n    }\n    // For non-pop need to save the vtype so that emit_native_adjust_stack_size\n    // can use it.  This is a bit of a hack.\n    if (!pop) {\n        emit->saved_stack_vtype = vtype;\n    }\n    // need to commit stack because we may jump elsewhere\n    need_stack_settled(emit);\n    // Emit the jump\n    if (cond) {\n        ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label, vtype == VTYPE_PYOBJ);\n    } else {\n        ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label, vtype == VTYPE_PYOBJ);\n    }\n    if (!pop) {\n        adjust_stack(emit, -1);\n    }\n    emit_post(emit);\n}\n\nSTATIC void emit_native_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) {\n    DEBUG_printf(\"pop_jump_if(cond=%u, label=\" UINT_FMT \")\\n\", cond, label);\n    emit_native_jump_helper(emit, cond, label, true);\n}\n\nSTATIC void emit_native_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) {\n    DEBUG_printf(\"jump_if_or_pop(cond=%u, label=\" UINT_FMT \")\\n\", cond, label);\n    emit_native_jump_helper(emit, cond, label, false);\n}\n\nSTATIC void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {\n    if (except_depth > 0) {\n        exc_stack_entry_t *first_finally = NULL;\n        exc_stack_entry_t *prev_finally = NULL;\n        exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1];\n        for (; except_depth > 0; --except_depth, --e) {\n            if (e->is_finally && e->is_active) {\n                // Found an active finally handler\n                if (first_finally == NULL) {\n                    first_finally = e;\n                }\n                if (prev_finally != NULL) {\n                    // Mark prev finally as needed to unwind a jump\n                    prev_finally->unwind_label = e->label;\n                }\n                prev_finally = e;\n            }\n        }\n        if (prev_finally == NULL) {\n            // No finally, handle the jump ourselves\n            // First, restore the exception handler address for the jump\n            if (e < emit->exc_stack) {\n                ASM_XOR_REG_REG(emit->as, REG_RET, REG_RET);\n            } else {\n                ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label);\n            }\n            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET);\n        } else {\n            // Last finally should do our jump for us\n            // Mark finally as needing to decide the type of jump\n            prev_finally->unwind_label = UNWIND_LABEL_DO_FINAL_UNWIND;\n            ASM_MOV_REG_PCREL(emit->as, REG_RET, label & ~MP_EMIT_BREAK_FROM_FOR);\n            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_RET);\n            // Cancel any active exception (see also emit_native_pop_except_jump)\n            ASM_MOV_REG_IMM(emit->as, REG_RET, (mp_uint_t)MP_OBJ_NULL);\n            ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_RET);\n            // Jump to the innermost active finally\n            label = first_finally->label;\n        }\n    }\n    emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR);\n}\n\nSTATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) {\n    // the context manager is on the top of the stack\n    // stack: (..., ctx_mgr)\n\n    // get __exit__ method\n    vtype_kind_t vtype;\n    emit_access_stack(emit, 1, &vtype, REG_ARG_1); // arg1 = ctx_mgr\n    assert(vtype == VTYPE_PYOBJ);\n    emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr\n    emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___exit__, REG_ARG_2);\n    // stack: (..., ctx_mgr, __exit__, self)\n\n    emit_pre_pop_reg(emit, &vtype, REG_ARG_3); // self\n    emit_pre_pop_reg(emit, &vtype, REG_ARG_2); // __exit__\n    emit_pre_pop_reg(emit, &vtype, REG_ARG_1); // ctx_mgr\n    emit_post_push_reg(emit, vtype, REG_ARG_2); // __exit__\n    emit_post_push_reg(emit, vtype, REG_ARG_3); // self\n    // stack: (..., __exit__, self)\n    // REG_ARG_1=ctx_mgr\n\n    // get __enter__ method\n    emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr\n    emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___enter__, REG_ARG_2); // arg2 = method name\n    // stack: (..., __exit__, self, __enter__, self)\n\n    // call __enter__ method\n    emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2); // pointer to items, including meth and self\n    emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 0, REG_ARG_1, 0, REG_ARG_2);\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // push return value of __enter__\n    // stack: (..., __exit__, self, as_value)\n\n    // need to commit stack because we may jump elsewhere\n    need_stack_settled(emit);\n    emit_native_push_exc_stack(emit, label, true);\n\n    emit_native_dup_top(emit);\n    // stack: (..., __exit__, self, as_value, as_value)\n}\n\nSTATIC void emit_native_setup_block(emit_t *emit, mp_uint_t label, int kind) {\n    if (kind == MP_EMIT_SETUP_BLOCK_WITH) {\n        emit_native_setup_with(emit, label);\n    } else {\n        // Set up except and finally\n        emit_native_pre(emit);\n        need_stack_settled(emit);\n        emit_native_push_exc_stack(emit, label, kind == MP_EMIT_SETUP_BLOCK_FINALLY);\n        emit_post(emit);\n    }\n}\n\nSTATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) {\n    // Note: 3 labels are reserved for this function, starting at *emit->label_slot\n\n    // stack: (..., __exit__, self, as_value)\n    emit_native_pre(emit);\n    emit_native_leave_exc_stack(emit, false);\n    adjust_stack(emit, -1);\n    // stack: (..., __exit__, self)\n\n    // Label for case where __exit__ is called from an unwind jump\n    emit_native_label_assign(emit, *emit->label_slot + 2);\n\n    // call __exit__\n    emit_post_push_imm(emit, VTYPE_PTR_NONE, 0);\n    emit_post_push_imm(emit, VTYPE_PTR_NONE, 0);\n    emit_post_push_imm(emit, VTYPE_PTR_NONE, 0);\n    emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 5);\n    emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 3, REG_ARG_1, 0, REG_ARG_2);\n\n    // Replace exc with None and finish\n    emit_native_jump(emit, *emit->label_slot);\n\n    // nlr_catch\n    // Don't use emit_native_label_assign because this isn't a real finally label\n    mp_asm_base_label_assign(&emit->as->base, label);\n\n    // Leave with's exception handler\n    emit_native_leave_exc_stack(emit, true);\n\n    // Adjust stack counter for: __exit__, self (implicitly discard as_value which is above self)\n    emit_native_adjust_stack_size(emit, 2);\n    // stack: (..., __exit__, self)\n\n    ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); // get exc\n\n    // Check if exc is MP_OBJ_NULL (i.e. zero) and jump to non-exc handler if it is\n    ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, *emit->label_slot + 2, false);\n\n    ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_2, REG_ARG_1, 0); // get type(exc)\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_2); // push type(exc)\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_1); // push exc value\n    emit_post_push_imm(emit, VTYPE_PTR_NONE, 0); // traceback info\n    // Stack: (..., __exit__, self, type(exc), exc, traceback)\n\n    // call __exit__ method\n    emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 5);\n    emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 3, REG_ARG_1, 0, REG_ARG_2);\n    // Stack: (...)\n\n    // If REG_RET is true then we need to replace exception with None (swallow exception)\n    if (REG_ARG_1 != REG_RET) {\n        ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_RET);\n    }\n    emit_call(emit, MP_F_OBJ_IS_TRUE);\n    ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, *emit->label_slot + 1, true);\n\n    // Replace exception with MP_OBJ_NULL.\n    emit_native_label_assign(emit, *emit->label_slot);\n    ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL);\n    ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0);\n\n    // end of with cleanup nlr_catch block\n    emit_native_label_assign(emit, *emit->label_slot + 1);\n\n    // Exception is in nlr_buf.ret_val slot\n}\n\nSTATIC void emit_native_end_finally(emit_t *emit) {\n    // logic:\n    //   exc = pop_stack\n    //   if exc == None: pass\n    //   else: raise exc\n    // the check if exc is None is done in the MP_F_NATIVE_RAISE stub\n    emit_native_pre(emit);\n    ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit));\n    emit_call(emit, MP_F_NATIVE_RAISE);\n\n    // Get state for this finally and see if we need to unwind\n    exc_stack_entry_t *e = emit_native_pop_exc_stack(emit);\n    if (e->unwind_label != UNWIND_LABEL_UNUSED) {\n        ASM_MOV_REG_LOCAL(emit->as, REG_RET, LOCAL_IDX_EXC_HANDLER_UNWIND(emit));\n        ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, *emit->label_slot, false);\n        if (e->unwind_label == UNWIND_LABEL_DO_FINAL_UNWIND) {\n            ASM_JUMP_REG(emit->as, REG_RET);\n        } else {\n            emit_native_jump(emit, e->unwind_label);\n        }\n        emit_native_label_assign(emit, *emit->label_slot);\n    }\n\n    emit_post(emit);\n}\n\nSTATIC void emit_native_get_iter(emit_t *emit, bool use_stack) {\n    // perhaps the difficult one, as we want to rewrite for loops using native code\n    // in cases where we iterate over a Python object, can we use normal runtime calls?\n\n    vtype_kind_t vtype;\n    emit_pre_pop_reg(emit, &vtype, REG_ARG_1);\n    assert(vtype == VTYPE_PYOBJ);\n    if (use_stack) {\n        emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, MP_OBJ_ITER_BUF_NSLOTS);\n        emit_call(emit, MP_F_NATIVE_GETITER);\n    } else {\n        // mp_getiter will allocate the iter_buf on the heap\n        ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0);\n        emit_call(emit, MP_F_NATIVE_GETITER);\n        emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n    }\n}\n\nSTATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) {\n    emit_native_pre(emit);\n    emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, MP_OBJ_ITER_BUF_NSLOTS);\n    adjust_stack(emit, MP_OBJ_ITER_BUF_NSLOTS);\n    emit_call(emit, MP_F_NATIVE_ITERNEXT);\n    #if MICROPY_DEBUG_MP_OBJ_SENTINELS\n    ASM_MOV_REG_IMM(emit->as, REG_TEMP1, (mp_uint_t)MP_OBJ_STOP_ITERATION);\n    ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label);\n    #else\n    MP_STATIC_ASSERT(MP_OBJ_STOP_ITERATION == 0);\n    ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label, false);\n    #endif\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n\nSTATIC void emit_native_for_iter_end(emit_t *emit) {\n    // adjust stack counter (we get here from for_iter ending, which popped the value for us)\n    emit_native_pre(emit);\n    adjust_stack(emit, -MP_OBJ_ITER_BUF_NSLOTS);\n    emit_post(emit);\n}\n\nSTATIC void emit_native_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) {\n    if (within_exc_handler) {\n        // Cancel any active exception so subsequent handlers don't see it\n        ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL);\n        ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0);\n    } else {\n        emit_native_leave_exc_stack(emit, false);\n    }\n    emit_native_jump(emit, label);\n}\n\nSTATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) {\n    vtype_kind_t vtype;\n    emit_pre_pop_reg(emit, &vtype, REG_ARG_2);\n    if (vtype == VTYPE_PYOBJ) {\n        emit_call_with_imm_arg(emit, MP_F_UNARY_OP, op, REG_ARG_1);\n        emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n    } else {\n        adjust_stack(emit, 1);\n        EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n            MP_ERROR_TEXT(\"unary op %q not implemented\"), mp_unary_op_method_name[op]);\n    }\n}\n\nSTATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {\n    DEBUG_printf(\"binary_op(\" UINT_FMT \")\\n\", op);\n    vtype_kind_t vtype_lhs = peek_vtype(emit, 1);\n    vtype_kind_t vtype_rhs = peek_vtype(emit, 0);\n    if ((vtype_lhs == VTYPE_INT || vtype_lhs == VTYPE_UINT)\n        && (vtype_rhs == VTYPE_INT || vtype_rhs == VTYPE_UINT)) {\n        // for integers, inplace and normal ops are equivalent, so use just normal ops\n        if (MP_BINARY_OP_INPLACE_OR <= op && op <= MP_BINARY_OP_INPLACE_POWER) {\n            op += MP_BINARY_OP_OR - MP_BINARY_OP_INPLACE_OR;\n        }\n\n        #if N_X64 || N_X86\n        // special cases for x86 and shifting\n        if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_RSHIFT) {\n            #if N_X64\n            emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X64_REG_RCX, &vtype_lhs, REG_RET);\n            #else\n            emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X86_REG_ECX, &vtype_lhs, REG_RET);\n            #endif\n            if (op == MP_BINARY_OP_LSHIFT) {\n                ASM_LSL_REG(emit->as, REG_RET);\n            } else {\n                if (vtype_lhs == VTYPE_UINT) {\n                    ASM_LSR_REG(emit->as, REG_RET);\n                } else {\n                    ASM_ASR_REG(emit->as, REG_RET);\n                }\n            }\n            emit_post_push_reg(emit, vtype_lhs, REG_RET);\n            return;\n        }\n        #endif\n\n        // special cases for floor-divide and module because we dispatch to helper functions\n        if (op == MP_BINARY_OP_FLOOR_DIVIDE || op == MP_BINARY_OP_MODULO) {\n            emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_2, &vtype_lhs, REG_ARG_1);\n            if (vtype_lhs != VTYPE_INT) {\n                EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                    MP_ERROR_TEXT(\"div/mod not implemented for uint\"), mp_binary_op_method_name[op]);\n            }\n            if (op == MP_BINARY_OP_FLOOR_DIVIDE) {\n                emit_call(emit, MP_F_SMALL_INT_FLOOR_DIVIDE);\n            } else {\n                emit_call(emit, MP_F_SMALL_INT_MODULO);\n            }\n            emit_post_push_reg(emit, VTYPE_INT, REG_RET);\n            return;\n        }\n\n        int reg_rhs = REG_ARG_3;\n        emit_pre_pop_reg_flexible(emit, &vtype_rhs, &reg_rhs, REG_RET, REG_ARG_2);\n        emit_pre_pop_reg(emit, &vtype_lhs, REG_ARG_2);\n\n        #if !(N_X64 || N_X86)\n        if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_RSHIFT) {\n            if (op == MP_BINARY_OP_LSHIFT) {\n                ASM_LSL_REG_REG(emit->as, REG_ARG_2, reg_rhs);\n            } else {\n                if (vtype_lhs == VTYPE_UINT) {\n                    ASM_LSR_REG_REG(emit->as, REG_ARG_2, reg_rhs);\n                } else {\n                    ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs);\n                }\n            }\n            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);\n            return;\n        }\n        #endif\n\n        if (op == MP_BINARY_OP_OR) {\n            ASM_OR_REG_REG(emit->as, REG_ARG_2, reg_rhs);\n            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);\n        } else if (op == MP_BINARY_OP_XOR) {\n            ASM_XOR_REG_REG(emit->as, REG_ARG_2, reg_rhs);\n            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);\n        } else if (op == MP_BINARY_OP_AND) {\n            ASM_AND_REG_REG(emit->as, REG_ARG_2, reg_rhs);\n            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);\n        } else if (op == MP_BINARY_OP_ADD) {\n            ASM_ADD_REG_REG(emit->as, REG_ARG_2, reg_rhs);\n            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);\n        } else if (op == MP_BINARY_OP_SUBTRACT) {\n            ASM_SUB_REG_REG(emit->as, REG_ARG_2, reg_rhs);\n            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);\n        } else if (op == MP_BINARY_OP_MULTIPLY) {\n            ASM_MUL_REG_REG(emit->as, REG_ARG_2, reg_rhs);\n            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);\n        } else if (MP_BINARY_OP_LESS <= op && op <= MP_BINARY_OP_NOT_EQUAL) {\n            // comparison ops are (in enum order):\n            //  MP_BINARY_OP_LESS\n            //  MP_BINARY_OP_MORE\n            //  MP_BINARY_OP_EQUAL\n            //  MP_BINARY_OP_LESS_EQUAL\n            //  MP_BINARY_OP_MORE_EQUAL\n            //  MP_BINARY_OP_NOT_EQUAL\n\n            if (vtype_lhs != vtype_rhs) {\n                EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT(\"comparison of int and uint\"));\n            }\n\n            size_t op_idx = op - MP_BINARY_OP_LESS + (vtype_lhs == VTYPE_UINT ? 0 : 6);\n\n            need_reg_single(emit, REG_RET, 0);\n            #if N_X64\n            asm_x64_xor_r64_r64(emit->as, REG_RET, REG_RET);\n            asm_x64_cmp_r64_with_r64(emit->as, reg_rhs, REG_ARG_2);\n            static byte ops[6 + 6] = {\n                // unsigned\n                ASM_X64_CC_JB,\n                ASM_X64_CC_JA,\n                ASM_X64_CC_JE,\n                ASM_X64_CC_JBE,\n                ASM_X64_CC_JAE,\n                ASM_X64_CC_JNE,\n                // signed\n                ASM_X64_CC_JL,\n                ASM_X64_CC_JG,\n                ASM_X64_CC_JE,\n                ASM_X64_CC_JLE,\n                ASM_X64_CC_JGE,\n                ASM_X64_CC_JNE,\n            };\n            asm_x64_setcc_r8(emit->as, ops[op_idx], REG_RET);\n            #elif N_X86\n            asm_x86_xor_r32_r32(emit->as, REG_RET, REG_RET);\n            asm_x86_cmp_r32_with_r32(emit->as, reg_rhs, REG_ARG_2);\n            static byte ops[6 + 6] = {\n                // unsigned\n                ASM_X86_CC_JB,\n                ASM_X86_CC_JA,\n                ASM_X86_CC_JE,\n                ASM_X86_CC_JBE,\n                ASM_X86_CC_JAE,\n                ASM_X86_CC_JNE,\n                // signed\n                ASM_X86_CC_JL,\n                ASM_X86_CC_JG,\n                ASM_X86_CC_JE,\n                ASM_X86_CC_JLE,\n                ASM_X86_CC_JGE,\n                ASM_X86_CC_JNE,\n            };\n            asm_x86_setcc_r8(emit->as, ops[op_idx], REG_RET);\n            #elif N_THUMB\n            asm_thumb_cmp_rlo_rlo(emit->as, REG_ARG_2, reg_rhs);\n            static uint16_t ops[6 + 6] = {\n                // unsigned\n                ASM_THUMB_OP_ITE_CC,\n                ASM_THUMB_OP_ITE_HI,\n                ASM_THUMB_OP_ITE_EQ,\n                ASM_THUMB_OP_ITE_LS,\n                ASM_THUMB_OP_ITE_CS,\n                ASM_THUMB_OP_ITE_NE,\n                // signed\n                ASM_THUMB_OP_ITE_LT,\n                ASM_THUMB_OP_ITE_GT,\n                ASM_THUMB_OP_ITE_EQ,\n                ASM_THUMB_OP_ITE_LE,\n                ASM_THUMB_OP_ITE_GE,\n                ASM_THUMB_OP_ITE_NE,\n            };\n            asm_thumb_op16(emit->as, ops[op_idx]);\n            asm_thumb_mov_rlo_i8(emit->as, REG_RET, 1);\n            asm_thumb_mov_rlo_i8(emit->as, REG_RET, 0);\n            #elif N_ARM\n            asm_arm_cmp_reg_reg(emit->as, REG_ARG_2, reg_rhs);\n            static uint ccs[6 + 6] = {\n                // unsigned\n                ASM_ARM_CC_CC,\n                ASM_ARM_CC_HI,\n                ASM_ARM_CC_EQ,\n                ASM_ARM_CC_LS,\n                ASM_ARM_CC_CS,\n                ASM_ARM_CC_NE,\n                // signed\n                ASM_ARM_CC_LT,\n                ASM_ARM_CC_GT,\n                ASM_ARM_CC_EQ,\n                ASM_ARM_CC_LE,\n                ASM_ARM_CC_GE,\n                ASM_ARM_CC_NE,\n            };\n            asm_arm_setcc_reg(emit->as, REG_RET, ccs[op_idx]);\n            #elif N_XTENSA || N_XTENSAWIN\n            static uint8_t ccs[6 + 6] = {\n                // unsigned\n                ASM_XTENSA_CC_LTU,\n                0x80 | ASM_XTENSA_CC_LTU, // for GTU we'll swap args\n                ASM_XTENSA_CC_EQ,\n                0x80 | ASM_XTENSA_CC_GEU, // for LEU we'll swap args\n                ASM_XTENSA_CC_GEU,\n                ASM_XTENSA_CC_NE,\n                // signed\n                ASM_XTENSA_CC_LT,\n                0x80 | ASM_XTENSA_CC_LT, // for GT we'll swap args\n                ASM_XTENSA_CC_EQ,\n                0x80 | ASM_XTENSA_CC_GE, // for LE we'll swap args\n                ASM_XTENSA_CC_GE,\n                ASM_XTENSA_CC_NE,\n            };\n            uint8_t cc = ccs[op_idx];\n            if ((cc & 0x80) == 0) {\n                asm_xtensa_setcc_reg_reg_reg(emit->as, cc, REG_RET, REG_ARG_2, reg_rhs);\n            } else {\n                asm_xtensa_setcc_reg_reg_reg(emit->as, cc & ~0x80, REG_RET, reg_rhs, REG_ARG_2);\n            }\n            #else\n            #error not implemented\n            #endif\n            emit_post_push_reg(emit, VTYPE_BOOL, REG_RET);\n        } else {\n            // TODO other ops not yet implemented\n            adjust_stack(emit, 1);\n            EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                MP_ERROR_TEXT(\"binary op %q not implemented\"), mp_binary_op_method_name[op]);\n        }\n    } else if (vtype_lhs == VTYPE_PYOBJ && vtype_rhs == VTYPE_PYOBJ) {\n        emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_3, &vtype_lhs, REG_ARG_2);\n        bool invert = false;\n        if (op == MP_BINARY_OP_NOT_IN) {\n            invert = true;\n            op = MP_BINARY_OP_IN;\n        } else if (op == MP_BINARY_OP_IS_NOT) {\n            invert = true;\n            op = MP_BINARY_OP_IS;\n        }\n        emit_call_with_imm_arg(emit, MP_F_BINARY_OP, op, REG_ARG_1);\n        if (invert) {\n            ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);\n            emit_call_with_imm_arg(emit, MP_F_UNARY_OP, MP_UNARY_OP_NOT, REG_ARG_1);\n        }\n        emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n    } else {\n        adjust_stack(emit, -1);\n        EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n            MP_ERROR_TEXT(\"can't do binary op between '%q' and '%q'\"),\n            vtype_to_qstr(vtype_lhs), vtype_to_qstr(vtype_rhs));\n    }\n}\n\n#if MICROPY_PY_BUILTINS_SLICE\nSTATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args);\n#endif\n\nSTATIC void emit_native_build(emit_t *emit, mp_uint_t n_args, int kind) {\n    // for viper: call runtime, with types of args\n    //   if wrapped in byte_array, or something, allocates memory and fills it\n    MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_F_BUILD_TUPLE);\n    MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_F_BUILD_LIST);\n    MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_F_BUILD_MAP);\n    MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_F_BUILD_SET);\n    #if MICROPY_PY_BUILTINS_SLICE\n    if (kind == MP_EMIT_BUILD_SLICE) {\n        emit_native_build_slice(emit, n_args);\n        return;\n    }\n    #endif\n    emit_native_pre(emit);\n    if (kind == MP_EMIT_BUILD_TUPLE || kind == MP_EMIT_BUILD_LIST || kind == MP_EMIT_BUILD_SET) {\n        emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items\n    }\n    emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE + kind, n_args, REG_ARG_1);\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple/list/map/set\n}\n\nSTATIC void emit_native_store_map(emit_t *emit) {\n    vtype_kind_t vtype_key, vtype_value, vtype_map;\n    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\n    assert(vtype_key == VTYPE_PYOBJ);\n    assert(vtype_value == VTYPE_PYOBJ);\n    assert(vtype_map == VTYPE_PYOBJ);\n    emit_call(emit, MP_F_STORE_MAP);\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // map\n}\n\n#if MICROPY_PY_BUILTINS_SLICE\nSTATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args) {\n    DEBUG_printf(\"build_slice %d\\n\", n_args);\n    if (n_args == 2) {\n        vtype_kind_t vtype_start, vtype_stop;\n        emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop\n        assert(vtype_start == VTYPE_PYOBJ);\n        assert(vtype_stop == VTYPE_PYOBJ);\n        emit_native_mov_reg_const(emit, REG_ARG_3, MP_F_CONST_NONE_OBJ); // arg3 = step\n    } else {\n        assert(n_args == 3);\n        vtype_kind_t vtype_start, vtype_stop, vtype_step;\n        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\n        assert(vtype_start == VTYPE_PYOBJ);\n        assert(vtype_stop == VTYPE_PYOBJ);\n        assert(vtype_step == VTYPE_PYOBJ);\n    }\n    emit_call(emit, MP_F_NEW_SLICE);\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n#endif\n\nSTATIC void emit_native_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_index) {\n    mp_fun_kind_t f;\n    if (kind == SCOPE_LIST_COMP) {\n        vtype_kind_t vtype_item;\n        emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2);\n        assert(vtype_item == VTYPE_PYOBJ);\n        f = MP_F_LIST_APPEND;\n    #if MICROPY_PY_BUILTINS_SET\n    } else if (kind == SCOPE_SET_COMP) {\n        vtype_kind_t vtype_item;\n        emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2);\n        assert(vtype_item == VTYPE_PYOBJ);\n        f = MP_F_STORE_SET;\n    #endif\n    } else {\n        // SCOPE_DICT_COMP\n        vtype_kind_t vtype_key, vtype_value;\n        emit_pre_pop_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3);\n        assert(vtype_key == VTYPE_PYOBJ);\n        assert(vtype_value == VTYPE_PYOBJ);\n        f = MP_F_STORE_MAP;\n    }\n    vtype_kind_t vtype_collection;\n    emit_access_stack(emit, collection_index, &vtype_collection, REG_ARG_1);\n    assert(vtype_collection == VTYPE_PYOBJ);\n    emit_call(emit, f);\n    emit_post(emit);\n}\n\nSTATIC void emit_native_unpack_sequence(emit_t *emit, mp_uint_t n_args) {\n    DEBUG_printf(\"unpack_sequence %d\\n\", n_args);\n    vtype_kind_t vtype_base;\n    emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq\n    assert(vtype_base == VTYPE_PYOBJ);\n    emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_args); // arg3 = dest ptr\n    emit_call_with_imm_arg(emit, MP_F_UNPACK_SEQUENCE, n_args, REG_ARG_2); // arg2 = n_args\n}\n\nSTATIC void emit_native_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) {\n    DEBUG_printf(\"unpack_ex %d %d\\n\", n_left, n_right);\n    vtype_kind_t vtype_base;\n    emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq\n    assert(vtype_base == VTYPE_PYOBJ);\n    emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right + 1); // arg3 = dest ptr\n    emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, n_left | (n_right << 8), REG_ARG_2); // arg2 = n_left + n_right\n}\n\nSTATIC void emit_native_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {\n    // call runtime, with type info for args, or don't support dict/default params, or only support Python objects for them\n    emit_native_pre(emit);\n    if (n_pos_defaults == 0 && n_kw_defaults == 0) {\n        need_reg_all(emit);\n        ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL);\n        ASM_MOV_REG_IMM(emit->as, REG_ARG_3, (mp_uint_t)MP_OBJ_NULL);\n    } else {\n        vtype_kind_t vtype_def_tuple, vtype_def_dict;\n        emit_pre_pop_reg_reg(emit, &vtype_def_dict, REG_ARG_3, &vtype_def_tuple, REG_ARG_2);\n        assert(vtype_def_tuple == VTYPE_PYOBJ);\n        assert(vtype_def_dict == VTYPE_PYOBJ);\n        need_reg_all(emit);\n    }\n    emit_load_reg_with_raw_code(emit, REG_ARG_1, scope->raw_code);\n    ASM_CALL_IND(emit->as, MP_F_MAKE_FUNCTION_FROM_RAW_CODE);\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n\nSTATIC 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) {\n    emit_native_pre(emit);\n    if (n_pos_defaults == 0 && n_kw_defaults == 0) {\n        emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over);\n        ASM_MOV_REG_IMM(emit->as, REG_ARG_2, n_closed_over);\n    } else {\n        emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over + 2);\n        ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0x100 | n_closed_over);\n    }\n    emit_load_reg_with_raw_code(emit, REG_ARG_1, scope->raw_code);\n    ASM_CALL_IND(emit->as, MP_F_MAKE_CLOSURE_FROM_RAW_CODE);\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n}\n\nSTATIC void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {\n    DEBUG_printf(\"call_function(n_pos=\" UINT_FMT \", n_kw=\" UINT_FMT \", star_flags=\" UINT_FMT \")\\n\", n_positional, n_keyword, star_flags);\n\n    // TODO: in viper mode, call special runtime routine with type info for args,\n    // and wanted type info for return, to remove need for boxing/unboxing\n\n    emit_native_pre(emit);\n    vtype_kind_t vtype_fun = peek_vtype(emit, n_positional + 2 * n_keyword);\n    if (vtype_fun == VTYPE_BUILTIN_CAST) {\n        // casting operator\n        assert(n_positional == 1 && n_keyword == 0);\n        assert(!star_flags);\n        DEBUG_printf(\"  cast to %d\\n\", vtype_fun);\n        vtype_kind_t vtype_cast = peek_stack(emit, 1)->data.u_imm;\n        switch (peek_vtype(emit, 0)) {\n            case VTYPE_PYOBJ: {\n                vtype_kind_t vtype;\n                emit_pre_pop_reg(emit, &vtype, REG_ARG_1);\n                emit_pre_pop_discard(emit);\n                emit_call_with_imm_arg(emit, MP_F_CONVERT_OBJ_TO_NATIVE, vtype_cast, REG_ARG_2); // arg2 = type\n                emit_post_push_reg(emit, vtype_cast, REG_RET);\n                break;\n            }\n            case VTYPE_BOOL:\n            case VTYPE_INT:\n            case VTYPE_UINT:\n            case VTYPE_PTR:\n            case VTYPE_PTR8:\n            case VTYPE_PTR16:\n            case VTYPE_PTR32:\n            case VTYPE_PTR_NONE:\n                emit_fold_stack_top(emit, REG_ARG_1);\n                emit_post_top_set_vtype(emit, vtype_cast);\n                break;\n            default:\n                // this can happen when casting a cast: int(int)\n                mp_raise_NotImplementedError(MP_ERROR_TEXT(\"casting\"));\n        }\n    } else {\n        assert(vtype_fun == VTYPE_PYOBJ);\n        if (star_flags) {\n            emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 3); // pointer to args\n            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);\n            emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n        } else {\n            if (n_positional != 0 || n_keyword != 0) {\n                emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword); // pointer to args\n            }\n            emit_pre_pop_reg(emit, &vtype_fun, REG_ARG_1); // the function\n            emit_call_with_imm_arg(emit, MP_F_NATIVE_CALL_FUNCTION_N_KW, n_positional | (n_keyword << 8), REG_ARG_2);\n            emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n        }\n    }\n}\n\nSTATIC void emit_native_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {\n    if (star_flags) {\n        emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 4); // pointer to args\n        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);\n        emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n    } else {\n        emit_native_pre(emit);\n        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\n        emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, n_positional, REG_ARG_1, n_keyword, REG_ARG_2);\n        emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);\n    }\n}\n\nSTATIC void emit_native_return_value(emit_t *emit) {\n    DEBUG_printf(\"return_value\\n\");\n\n    if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {\n        // Save pointer to current stack position for caller to access return value\n        emit_get_stack_pointer_to_reg_for_pop(emit, REG_TEMP0, 1);\n        emit_native_mov_state_reg(emit, OFFSETOF_CODE_STATE_SP, REG_TEMP0);\n\n        // Put return type in return value slot\n        ASM_MOV_REG_IMM(emit->as, REG_TEMP0, MP_VM_RETURN_NORMAL);\n        ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_TEMP0);\n\n        // Do the unwinding jump to get to the return handler\n        emit_native_unwind_jump(emit, emit->exit_label, emit->exc_stack_size);\n        emit->last_emit_was_return_value = true;\n        return;\n    }\n\n    if (emit->do_viper_types) {\n        vtype_kind_t return_vtype = emit->scope->scope_flags >> MP_SCOPE_FLAG_VIPERRET_POS;\n        if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) {\n            emit_pre_pop_discard(emit);\n            if (return_vtype == VTYPE_PYOBJ) {\n                emit_native_mov_reg_const(emit, REG_PARENT_RET, MP_F_CONST_NONE_OBJ);\n            } else {\n                ASM_MOV_REG_IMM(emit->as, REG_ARG_1, 0);\n            }\n        } else {\n            vtype_kind_t vtype;\n            emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_PARENT_RET : REG_ARG_1);\n            if (vtype != return_vtype) {\n                EMIT_NATIVE_VIPER_TYPE_ERROR(emit,\n                    MP_ERROR_TEXT(\"return expected '%q' but got '%q'\"),\n                    vtype_to_qstr(return_vtype), vtype_to_qstr(vtype));\n            }\n        }\n        if (return_vtype != VTYPE_PYOBJ) {\n            emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, return_vtype, REG_ARG_2);\n            #if REG_RET != REG_PARENT_RET\n            ASM_MOV_REG_REG(emit->as, REG_PARENT_RET, REG_RET);\n            #endif\n        }\n    } else {\n        vtype_kind_t vtype;\n        emit_pre_pop_reg(emit, &vtype, REG_PARENT_RET);\n        assert(vtype == VTYPE_PYOBJ);\n    }\n    if (NEED_GLOBAL_EXC_HANDLER(emit)) {\n        // Save return value for the global exception handler to use\n        ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_PARENT_RET);\n    }\n    emit_native_unwind_jump(emit, emit->exit_label, emit->exc_stack_size);\n    emit->last_emit_was_return_value = true;\n}\n\nSTATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) {\n    (void)n_args;\n    assert(n_args == 1);\n    vtype_kind_t vtype_exc;\n    emit_pre_pop_reg(emit, &vtype_exc, REG_ARG_1); // arg1 = object to raise\n    if (vtype_exc != VTYPE_PYOBJ) {\n        EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT(\"must raise an object\"));\n    }\n    // TODO probably make this 1 call to the runtime (which could even call convert, native_raise(obj, type))\n    emit_call(emit, MP_F_NATIVE_RAISE);\n}\n\nSTATIC void emit_native_yield(emit_t *emit, int kind) {\n    // Note: 1 (yield) or 3 (yield from) labels are reserved for this function, starting at *emit->label_slot\n\n    if (emit->do_viper_types) {\n        mp_raise_NotImplementedError(MP_ERROR_TEXT(\"native yield\"));\n    }\n    emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;\n\n    need_stack_settled(emit);\n\n    if (kind == MP_EMIT_YIELD_FROM) {\n\n        // Top of yield-from loop, conceptually implementing:\n        //     for item in generator:\n        //         yield item\n\n        // Jump to start of loop\n        emit_native_jump(emit, *emit->label_slot + 2);\n\n        // Label for top of loop\n        emit_native_label_assign(emit, *emit->label_slot + 1);\n    }\n\n    // Save pointer to current stack position for caller to access yielded value\n    emit_get_stack_pointer_to_reg_for_pop(emit, REG_TEMP0, 1);\n    emit_native_mov_state_reg(emit, OFFSETOF_CODE_STATE_SP, REG_TEMP0);\n\n    // Put return type in return value slot\n    ASM_MOV_REG_IMM(emit->as, REG_TEMP0, MP_VM_RETURN_YIELD);\n    ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_TEMP0);\n\n    // Save re-entry PC\n    ASM_MOV_REG_PCREL(emit->as, REG_TEMP0, *emit->label_slot);\n    emit_native_mov_state_reg(emit, LOCAL_IDX_GEN_PC(emit), REG_TEMP0);\n\n    // Jump to exit handler\n    ASM_JUMP(emit->as, emit->exit_label);\n\n    // Label re-entry point\n    mp_asm_base_label_assign(&emit->as->base, *emit->label_slot);\n\n    // Re-open any active exception handler\n    if (emit->exc_stack_size > 0) {\n        // Find innermost active exception handler, to restore as current handler\n        exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1];\n        for (; e >= emit->exc_stack; --e) {\n            if (e->is_active) {\n                // Found active handler, get its PC\n                ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label);\n                ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET);\n                break;\n            }\n        }\n    }\n\n    emit_native_adjust_stack_size(emit, 1); // send_value\n\n    if (kind == MP_EMIT_YIELD_VALUE) {\n        // Check LOCAL_IDX_EXC_VAL for any injected value\n        ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit));\n        emit_call(emit, MP_F_NATIVE_RAISE);\n    } else {\n        // Label loop entry\n        emit_native_label_assign(emit, *emit->label_slot + 2);\n\n        // Get the next item from the delegate generator\n        vtype_kind_t vtype;\n        emit_pre_pop_reg(emit, &vtype, REG_ARG_2); // send_value\n        emit_access_stack(emit, 1, &vtype, REG_ARG_1); // generator\n        ASM_MOV_REG_LOCAL(emit->as, REG_ARG_3, LOCAL_IDX_EXC_VAL(emit)); // throw_value\n        emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_3);\n        emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 1); // ret_value\n        emit_call(emit, MP_F_NATIVE_YIELD_FROM);\n\n        // If returned non-zero then generator continues\n        ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, *emit->label_slot + 1, true);\n\n        // Pop exhausted gen, replace with ret_value\n        emit_native_adjust_stack_size(emit, 1); // ret_value\n        emit_fold_stack_top(emit, REG_ARG_1);\n    }\n}\n\nSTATIC void emit_native_start_except_handler(emit_t *emit) {\n    // Protected block has finished so leave the current exception handler\n    emit_native_leave_exc_stack(emit, true);\n\n    // Get and push nlr_buf.ret_val\n    ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, LOCAL_IDX_EXC_VAL(emit));\n    emit_post_push_reg(emit, VTYPE_PYOBJ, REG_TEMP0);\n}\n\nSTATIC void emit_native_end_except_handler(emit_t *emit) {\n    adjust_stack(emit, -1); // pop the exception (end_finally didn't use it)\n}\n\nconst emit_method_table_t EXPORT_FUN(method_table) = {\n    #if MICROPY_DYNAMIC_COMPILER\n    EXPORT_FUN(new),\n    EXPORT_FUN(free),\n    #endif\n\n    emit_native_start_pass,\n    emit_native_end_pass,\n    emit_native_last_emit_was_return_value,\n    emit_native_adjust_stack_size,\n    emit_native_set_source_line,\n\n    {\n        emit_native_load_local,\n        emit_native_load_global,\n    },\n    {\n        emit_native_store_local,\n        emit_native_store_global,\n    },\n    {\n        emit_native_delete_local,\n        emit_native_delete_global,\n    },\n\n    emit_native_label_assign,\n    emit_native_import,\n    emit_native_load_const_tok,\n    emit_native_load_const_small_int,\n    emit_native_load_const_str,\n    emit_native_load_const_obj,\n    emit_native_load_null,\n    emit_native_load_method,\n    emit_native_load_build_class,\n    emit_native_subscr,\n    emit_native_attr,\n    emit_native_dup_top,\n    emit_native_dup_top_two,\n    emit_native_pop_top,\n    emit_native_rot_two,\n    emit_native_rot_three,\n    emit_native_jump,\n    emit_native_pop_jump_if,\n    emit_native_jump_if_or_pop,\n    emit_native_unwind_jump,\n    emit_native_setup_block,\n    emit_native_with_cleanup,\n    emit_native_end_finally,\n    emit_native_get_iter,\n    emit_native_for_iter,\n    emit_native_for_iter_end,\n    emit_native_pop_except_jump,\n    emit_native_unary_op,\n    emit_native_binary_op,\n    emit_native_build,\n    emit_native_store_map,\n    emit_native_store_comp,\n    emit_native_unpack_sequence,\n    emit_native_unpack_ex,\n    emit_native_make_function,\n    emit_native_make_closure,\n    emit_native_call_function,\n    emit_native_call_method,\n    emit_native_return_value,\n    emit_native_raise_varargs,\n    emit_native_yield,\n\n    emit_native_start_except_handler,\n    emit_native_end_except_handler,\n};\n\n#endif\n"
  },
  {
    "path": "py/emitnthumb.c",
    "content": "// thumb specific stuff\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_EMIT_THUMB\n\n// this is defined so that the assembler exports generic assembler API macros\n#define GENERIC_ASM_API (1)\n#include \"py/asmthumb.h\"\n\n// Word indices of REG_LOCAL_x in nlr_buf_t\n#define NLR_BUF_IDX_LOCAL_1 (3) // r4\n#define NLR_BUF_IDX_LOCAL_2 (4) // r5\n#define NLR_BUF_IDX_LOCAL_3 (5) // r6\n\n#define N_THUMB (1)\n#define EXPORT_FUN(name) emit_native_thumb_##name\n#include \"py/emitnative.c\"\n\n#endif\n"
  },
  {
    "path": "py/emitnx64.c",
    "content": "// x64 specific stuff\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_EMIT_X64\n\n// This is defined so that the assembler exports generic assembler API macros\n#define GENERIC_ASM_API (1)\n#include \"py/asmx64.h\"\n\n// Word indices of REG_LOCAL_x in nlr_buf_t\n#define NLR_BUF_IDX_LOCAL_1 (5) // rbx\n#define NLR_BUF_IDX_LOCAL_2 (6) // r12\n#define NLR_BUF_IDX_LOCAL_3 (7) // r13\n\n#define N_X64 (1)\n#define EXPORT_FUN(name) emit_native_x64_##name\n#include \"py/emitnative.c\"\n\n#endif\n"
  },
  {
    "path": "py/emitnx86.c",
    "content": "// x86 specific stuff\n\n#include \"py/mpconfig.h\"\n#include \"py/nativeglue.h\"\n\n#if MICROPY_EMIT_X86\n\n// This is defined so that the assembler exports generic assembler API macros\n#define GENERIC_ASM_API (1)\n#include \"py/asmx86.h\"\n\n// Word indices of REG_LOCAL_x in nlr_buf_t\n#define NLR_BUF_IDX_LOCAL_1 (5) // ebx\n#define NLR_BUF_IDX_LOCAL_2 (7) // esi\n#define NLR_BUF_IDX_LOCAL_3 (6) // edi\n\n// x86 needs a table to know how many args a given function has\nSTATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {\n    [MP_F_CONVERT_OBJ_TO_NATIVE] = 2,\n    [MP_F_CONVERT_NATIVE_TO_OBJ] = 2,\n    [MP_F_NATIVE_SWAP_GLOBALS] = 1,\n    [MP_F_LOAD_NAME] = 1,\n    [MP_F_LOAD_GLOBAL] = 1,\n    [MP_F_LOAD_BUILD_CLASS] = 0,\n    [MP_F_LOAD_ATTR] = 2,\n    [MP_F_LOAD_METHOD] = 3,\n    [MP_F_LOAD_SUPER_METHOD] = 2,\n    [MP_F_STORE_NAME] = 2,\n    [MP_F_STORE_GLOBAL] = 2,\n    [MP_F_STORE_ATTR] = 3,\n    [MP_F_OBJ_SUBSCR] = 3,\n    [MP_F_OBJ_IS_TRUE] = 1,\n    [MP_F_UNARY_OP] = 2,\n    [MP_F_BINARY_OP] = 3,\n    [MP_F_BUILD_TUPLE] = 2,\n    [MP_F_BUILD_LIST] = 2,\n    [MP_F_BUILD_MAP] = 1,\n    [MP_F_BUILD_SET] = 2,\n    [MP_F_STORE_SET] = 2,\n    [MP_F_LIST_APPEND] = 2,\n    [MP_F_STORE_MAP] = 3,\n    [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3,\n    [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3,\n    [MP_F_CALL_METHOD_N_KW] = 3,\n    [MP_F_CALL_METHOD_N_KW_VAR] = 3,\n    [MP_F_NATIVE_GETITER] = 2,\n    [MP_F_NATIVE_ITERNEXT] = 1,\n    [MP_F_NLR_PUSH] = 1,\n    [MP_F_NLR_POP] = 0,\n    [MP_F_NATIVE_RAISE] = 1,\n    [MP_F_IMPORT_NAME] = 3,\n    [MP_F_IMPORT_FROM] = 2,\n    [MP_F_IMPORT_ALL] = 1,\n    [MP_F_NEW_SLICE] = 3,\n    [MP_F_UNPACK_SEQUENCE] = 3,\n    [MP_F_UNPACK_EX] = 3,\n    [MP_F_DELETE_NAME] = 1,\n    [MP_F_DELETE_GLOBAL] = 1,\n    [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3,\n    [MP_F_ARG_CHECK_NUM_SIG] = 3,\n    [MP_F_SETUP_CODE_STATE] = 4,\n    [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2,\n    [MP_F_SMALL_INT_MODULO] = 2,\n    [MP_F_NATIVE_YIELD_FROM] = 3,\n    [MP_F_SETJMP] = 1,\n};\n\n#define N_X86 (1)\n#define EXPORT_FUN(name) emit_native_x86_##name\n#include \"py/emitnative.c\"\n\n#endif\n"
  },
  {
    "path": "py/emitnxtensa.c",
    "content": "// Xtensa specific stuff\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_EMIT_XTENSA\n\n// this is defined so that the assembler exports generic assembler API macros\n#define GENERIC_ASM_API (1)\n#include \"py/asmxtensa.h\"\n\n// Word indices of REG_LOCAL_x in nlr_buf_t\n#define NLR_BUF_IDX_LOCAL_1 (8) // a12\n#define NLR_BUF_IDX_LOCAL_2 (9) // a13\n#define NLR_BUF_IDX_LOCAL_3 (10) // a14\n\n#define N_XTENSA (1)\n#define EXPORT_FUN(name) emit_native_xtensa_##name\n#include \"py/emitnative.c\"\n\n#endif\n"
  },
  {
    "path": "py/emitnxtensawin.c",
    "content": "// Xtensa-Windowed specific stuff\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_EMIT_XTENSAWIN\n\n// this is defined so that the assembler exports generic assembler API macros\n#define GENERIC_ASM_API (1)\n#define GENERIC_ASM_API_WIN (1)\n#include \"py/asmxtensa.h\"\n\n// Word indices of REG_LOCAL_x in nlr_buf_t\n#define NLR_BUF_IDX_LOCAL_1 (2 + 4) // a4\n#define NLR_BUF_IDX_LOCAL_2 (2 + 5) // a5\n#define NLR_BUF_IDX_LOCAL_3 (2 + 6) // a6\n\n#define N_NLR_SETJMP (1)\n#define N_PRELUDE_AS_BYTES_OBJ (1)\n#define N_XTENSAWIN (1)\n#define EXPORT_FUN(name) emit_native_xtensawin_##name\n#include \"py/emitnative.c\"\n\n#endif\n"
  },
  {
    "path": "py/formatfloat.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE\n\n#include <assert.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <math.h>\n#include \"py/formatfloat.h\"\n\n/***********************************************************************\n\n  Routine for converting a arbitrary floating\n  point number into a string.\n\n  The code in this funcion was inspired from Fred Bayer's pdouble.c.\n  Since pdouble.c was released as Public Domain, I'm releasing this\n  code as public domain as well.\n\n  The original code can be found in https://github.com/dhylands/format-float\n\n  Dave Hylands\n\n***********************************************************************/\n\n#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n// 1 sign bit, 8 exponent bits, and 23 mantissa bits.\n// exponent values 0 and 255 are reserved, exponent can be 1 to 254.\n// exponent is stored with a bias of 127.\n// The min and max floats are on the order of 1x10^37 and 1x10^-37\n\n#define FPTYPE float\n#define FPCONST(x) x##F\n#define FPROUND_TO_ONE 0.9999995F\n#define FPDECEXP 32\n#define FPMIN_BUF_SIZE 6 // +9e+99\n\n#define FLT_SIGN_MASK   0x80000000\n#define FLT_EXP_MASK    0x7F800000\n#define FLT_MAN_MASK    0x007FFFFF\n\nunion floatbits {\n    float f;\n    uint32_t u;\n};\nstatic inline int fp_signbit(float x) {\n    union floatbits fb = {x};\n    return fb.u & FLT_SIGN_MASK;\n}\n#define fp_isnan(x) isnan(x)\n#define fp_isinf(x) isinf(x)\nstatic inline int fp_iszero(float x) {\n    union floatbits fb = {x};\n    return fb.u == 0;\n}\nstatic inline int fp_isless1(float x) {\n    union floatbits fb = {x};\n    return fb.u < 0x3f800000;\n}\n\n#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE\n\n#define FPTYPE double\n#define FPCONST(x) x\n#define FPROUND_TO_ONE 0.999999999995\n#define FPDECEXP 256\n#define FPMIN_BUF_SIZE 7 // +9e+199\n#define fp_signbit(x) signbit(x)\n#define fp_isnan(x) isnan(x)\n#define fp_isinf(x) isinf(x)\n#define fp_iszero(x) (x == 0)\n#define fp_isless1(x) (x < 1.0)\n\n#endif\n\nstatic const FPTYPE g_pos_pow[] = {\n    #if FPDECEXP > 32\n    MICROPY_FLOAT_CONST(1e256), MICROPY_FLOAT_CONST(1e128), MICROPY_FLOAT_CONST(1e64),\n    #endif\n    MICROPY_FLOAT_CONST(1e32), MICROPY_FLOAT_CONST(1e16), MICROPY_FLOAT_CONST(1e8), MICROPY_FLOAT_CONST(1e4), MICROPY_FLOAT_CONST(1e2), MICROPY_FLOAT_CONST(1e1)\n};\nstatic const FPTYPE g_neg_pow[] = {\n    #if FPDECEXP > 32\n    MICROPY_FLOAT_CONST(1e-256), MICROPY_FLOAT_CONST(1e-128), MICROPY_FLOAT_CONST(1e-64),\n    #endif\n    MICROPY_FLOAT_CONST(1e-32), MICROPY_FLOAT_CONST(1e-16), MICROPY_FLOAT_CONST(1e-8), MICROPY_FLOAT_CONST(1e-4), MICROPY_FLOAT_CONST(1e-2), MICROPY_FLOAT_CONST(1e-1)\n};\n\nint mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) {\n\n    char *s = buf;\n\n    if (buf_size <= FPMIN_BUF_SIZE) {\n        // FPMIN_BUF_SIZE is the minimum size needed to store any FP number.\n        // If the buffer does not have enough room for this (plus null terminator)\n        // then don't try to format the float.\n\n        if (buf_size >= 2) {\n            *s++ = '?';\n        }\n        if (buf_size >= 1) {\n            *s = '\\0';\n        }\n        return buf_size >= 2;\n    }\n    if (fp_signbit(f) && !fp_isnan(f)) {\n        *s++ = '-';\n        f = -f;\n    } else {\n        if (sign) {\n            *s++ = sign;\n        }\n    }\n\n    // buf_remaining contains bytes available for digits and exponent.\n    // It is buf_size minus room for the sign and null byte.\n    int buf_remaining = buf_size - 1 - (s - buf);\n\n    {\n        char uc = fmt & 0x20;\n        if (fp_isinf(f)) {\n            *s++ = 'I' ^ uc;\n            *s++ = 'N' ^ uc;\n            *s++ = 'F' ^ uc;\n            goto ret;\n        } else if (fp_isnan(f)) {\n            *s++ = 'N' ^ uc;\n            *s++ = 'A' ^ uc;\n            *s++ = 'N' ^ uc;\n        ret:\n            *s = '\\0';\n            return s - buf;\n        }\n    }\n\n    if (prec < 0) {\n        prec = 6;\n    }\n    char e_char = 'E' | (fmt & 0x20);   // e_char will match case of fmt\n    fmt |= 0x20; // Force fmt to be lowercase\n    char org_fmt = fmt;\n    if (fmt == 'g' && prec == 0) {\n        prec = 1;\n    }\n    int e, e1;\n    int dec = 0;\n    char e_sign = '\\0';\n    int num_digits = 0;\n    const FPTYPE *pos_pow = g_pos_pow;\n    const FPTYPE *neg_pow = g_neg_pow;\n\n    if (fp_iszero(f)) {\n        e = 0;\n        if (fmt == 'f') {\n            // Truncate precision to prevent buffer overflow\n            if (prec + 2 > buf_remaining) {\n                prec = buf_remaining - 2;\n            }\n            num_digits = prec + 1;\n        } else {\n            // Truncate precision to prevent buffer overflow\n            if (prec + 6 > buf_remaining) {\n                prec = buf_remaining - 6;\n            }\n            if (fmt == 'e') {\n                e_sign = '+';\n            }\n        }\n    } else if (fp_isless1(f)) {\n        // We need to figure out what an integer digit will be used\n        // in case 'f' is used (or we revert other format to it below).\n        // As we just tested number to be <1, this is obviously 0,\n        // but we can round it up to 1 below.\n        char first_dig = '0';\n        if (f >= FPROUND_TO_ONE) {\n            first_dig = '1';\n        }\n\n        // Build negative exponent\n        for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) {\n            if (*neg_pow > f) {\n                e += e1;\n                f *= *pos_pow;\n            }\n        }\n        char e_sign_char = '-';\n        if (fp_isless1(f) && f >= FPROUND_TO_ONE) {\n            f = FPCONST(1.0);\n            if (e == 0) {\n                e_sign_char = '+';\n            }\n        } else if (fp_isless1(f)) {\n            e++;\n            f *= FPCONST(10.0);\n        }\n\n        // If the user specified 'g' format, and e is <= 4, then we'll switch\n        // to the fixed format ('f')\n\n        if (fmt == 'f' || (fmt == 'g' && e <= 4)) {\n            fmt = 'f';\n            dec = -1;\n            *s++ = first_dig;\n\n            if (org_fmt == 'g') {\n                prec += (e - 1);\n            }\n\n            // truncate precision to prevent buffer overflow\n            if (prec + 2 > buf_remaining) {\n                prec = buf_remaining - 2;\n            }\n\n            num_digits = prec;\n            if (num_digits) {\n                *s++ = '.';\n                while (--e && num_digits) {\n                    *s++ = '0';\n                    num_digits--;\n                }\n            }\n        } else {\n            // For e & g formats, we'll be printing the exponent, so set the\n            // sign.\n            e_sign = e_sign_char;\n            dec = 0;\n\n            if (prec > (buf_remaining - FPMIN_BUF_SIZE)) {\n                prec = buf_remaining - FPMIN_BUF_SIZE;\n                if (fmt == 'g') {\n                    prec++;\n                }\n            }\n        }\n    } else {\n        // Build positive exponent\n        for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) {\n            if (*pos_pow <= f) {\n                e += e1;\n                f *= *neg_pow;\n            }\n        }\n\n        // It can be that f was right on the edge of an entry in pos_pow needs to be reduced\n        if ((int)f >= 10) {\n            e += 1;\n            f *= FPCONST(0.1);\n        }\n\n        // If the user specified fixed format (fmt == 'f') and e makes the\n        // number too big to fit into the available buffer, then we'll\n        // switch to the 'e' format.\n\n        if (fmt == 'f') {\n            if (e >= buf_remaining) {\n                fmt = 'e';\n            } else if ((e + prec + 2) > buf_remaining) {\n                prec = buf_remaining - e - 2;\n                if (prec < 0) {\n                    // This means no decimal point, so we can add one back\n                    // for the decimal.\n                    prec++;\n                }\n            }\n        }\n        if (fmt == 'e' && prec > (buf_remaining - FPMIN_BUF_SIZE)) {\n            prec = buf_remaining - FPMIN_BUF_SIZE;\n        }\n        if (fmt == 'g') {\n            // Truncate precision to prevent buffer overflow\n            if (prec + (FPMIN_BUF_SIZE - 1) > buf_remaining) {\n                prec = buf_remaining - (FPMIN_BUF_SIZE - 1);\n            }\n        }\n        // If the user specified 'g' format, and e is < prec, then we'll switch\n        // to the fixed format.\n\n        if (fmt == 'g' && e < prec) {\n            fmt = 'f';\n            prec -= (e + 1);\n        }\n        if (fmt == 'f') {\n            dec = e;\n            num_digits = prec + e + 1;\n        } else {\n            e_sign = '+';\n        }\n    }\n    if (prec < 0) {\n        // This can happen when the prec is trimmed to prevent buffer overflow\n        prec = 0;\n    }\n\n    // We now have num.f as a floating point number between >= 1 and < 10\n    // (or equal to zero), and e contains the absolute value of the power of\n    // 10 exponent. and (dec + 1) == the number of dgits before the decimal.\n\n    // For e, prec is # digits after the decimal\n    // For f, prec is # digits after the decimal\n    // For g, prec is the max number of significant digits\n    //\n    // For e & g there will be a single digit before the decimal\n    // for f there will be e digits before the decimal\n\n    if (fmt == 'e') {\n        num_digits = prec + 1;\n    } else if (fmt == 'g') {\n        if (prec == 0) {\n            prec = 1;\n        }\n        num_digits = prec;\n    }\n\n    // Print the digits of the mantissa\n    for (int i = 0; i < num_digits; ++i, --dec) {\n        int32_t d = (int32_t)f;\n        if (d < 0) {\n            *s++ = '0';\n        } else {\n            *s++ = '0' + d;\n        }\n        if (dec == 0 && prec > 0) {\n            *s++ = '.';\n        }\n        f -= (FPTYPE)d;\n        f *= FPCONST(10.0);\n    }\n\n    // Round\n    // If we print non-exponential format (i.e. 'f'), but a digit we're going\n    // to round by (e) is too far away, then there's nothing to round.\n    if ((org_fmt != 'f' || e <= num_digits) && f >= FPCONST(5.0)) {\n        char *rs = s;\n        rs--;\n        while (1) {\n            if (*rs == '.') {\n                rs--;\n                continue;\n            }\n            if (*rs < '0' || *rs > '9') {\n                // + or -\n                rs++; // So we sit on the digit to the right of the sign\n                break;\n            }\n            if (*rs < '9') {\n                (*rs)++;\n                break;\n            }\n            *rs = '0';\n            if (rs == buf) {\n                break;\n            }\n            rs--;\n        }\n        if (*rs == '0') {\n            // We need to insert a 1\n            if (rs[1] == '.' && fmt != 'f') {\n                // We're going to round 9.99 to 10.00\n                // Move the decimal point\n                rs[0] = '.';\n                rs[1] = '0';\n                if (e_sign == '-') {\n                    e--;\n                    if (e == 0) {\n                        e_sign = '+';\n                    }\n                } else {\n                    e++;\n                }\n            } else {\n                // Need at extra digit at the end to make room for the leading '1'\n                s++;\n            }\n            char *ss = s;\n            while (ss > rs) {\n                *ss = ss[-1];\n                ss--;\n            }\n            *rs = '1';\n        }\n    }\n\n    // verify that we did not overrun the input buffer so far\n    assert((size_t)(s + 1 - buf) <= buf_size);\n\n    if (org_fmt == 'g' && prec > 0) {\n        // Remove trailing zeros and a trailing decimal point\n        while (s[-1] == '0') {\n            s--;\n        }\n        if (s[-1] == '.') {\n            s--;\n        }\n    }\n    // Append the exponent\n    if (e_sign) {\n        *s++ = e_char;\n        *s++ = e_sign;\n        if (FPMIN_BUF_SIZE == 7 && e >= 100) {\n            *s++ = '0' + (e / 100);\n        }\n        *s++ = '0' + ((e / 10) % 10);\n        *s++ = '0' + (e % 10);\n    }\n    *s = '\\0';\n\n    // verify that we did not overrun the input buffer\n    assert((size_t)(s + 1 - buf) <= buf_size);\n\n    return s - buf;\n}\n\n#endif // MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE\n"
  },
  {
    "path": "py/formatfloat.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_FORMATFLOAT_H\n#define MICROPY_INCLUDED_PY_FORMATFLOAT_H\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT\nint mp_format_float(mp_float_t f, char *buf, size_t bufSize, char fmt, int prec, char sign);\n#endif\n\n#endif // MICROPY_INCLUDED_PY_FORMATFLOAT_H\n"
  },
  {
    "path": "py/frozenmod.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 Paul Sokolovsky\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <stdint.h>\n\n#include \"py/lexer.h\"\n#include \"py/frozenmod.h\"\n\n#if MICROPY_MODULE_FROZEN_STR\n\n#ifndef MICROPY_MODULE_FROZEN_LEXER\n#define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str_len\n#else\nmp_lexer_t *MICROPY_MODULE_FROZEN_LEXER(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len);\n#endif\n\nextern const char mp_frozen_str_names[];\nextern const uint32_t mp_frozen_str_sizes[];\nextern const char mp_frozen_str_content[];\n\n// On input, *len contains size of name, on output - size of content\nconst char *mp_find_frozen_str(const char *str, size_t *len) {\n    const char *name = mp_frozen_str_names;\n\n    size_t offset = 0;\n    for (int i = 0; *name != 0; i++) {\n        size_t l = strlen(name);\n        if (l == *len && !memcmp(str, name, l)) {\n            *len = mp_frozen_str_sizes[i];\n            return mp_frozen_str_content + offset;\n        }\n        name += l + 1;\n        offset += mp_frozen_str_sizes[i] + 1;\n    }\n    return NULL;\n}\n\nSTATIC mp_lexer_t *mp_lexer_frozen_str(const char *str, size_t len) {\n    size_t name_len = len;\n    const char *content = mp_find_frozen_str(str, &len);\n\n    if (content == NULL) {\n        return NULL;\n    }\n\n    qstr source = qstr_from_strn(str, name_len);\n    mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, len, 0);\n    return lex;\n}\n\n#endif\n\n#if MICROPY_MODULE_FROZEN_MPY\n\n#include \"py/emitglue.h\"\n\nextern const char mp_frozen_mpy_names[];\nextern const mp_raw_code_t *const mp_frozen_mpy_content[];\n\nSTATIC const mp_raw_code_t *mp_find_frozen_mpy(const char *str, size_t len) {\n    const char *name = mp_frozen_mpy_names;\n    for (size_t i = 0; *name != 0; i++) {\n        size_t l = strlen(name);\n        if (l == len && !memcmp(str, name, l)) {\n            return mp_frozen_mpy_content[i];\n        }\n        name += l + 1;\n    }\n    return NULL;\n}\n\n#endif\n\n#if MICROPY_MODULE_FROZEN\n\nSTATIC mp_import_stat_t mp_frozen_stat_helper(const char *name, const char *str) {\n    size_t len = strlen(str);\n\n    for (int i = 0; *name != 0; i++) {\n        size_t l = strlen(name);\n        if (l >= len && !memcmp(str, name, len)) {\n            if (name[len] == 0) {\n                return MP_IMPORT_STAT_FILE;\n            } else if (name[len] == '/') {\n                return MP_IMPORT_STAT_DIR;\n            }\n        }\n        name += l + 1;\n    }\n    return MP_IMPORT_STAT_NO_EXIST;\n}\n\nmp_import_stat_t mp_frozen_stat(const char *str) {\n    mp_import_stat_t stat;\n\n    #if MICROPY_MODULE_FROZEN_STR\n    stat = mp_frozen_stat_helper(mp_frozen_str_names, str);\n    if (stat != MP_IMPORT_STAT_NO_EXIST) {\n        return stat;\n    }\n    #endif\n\n    #if MICROPY_MODULE_FROZEN_MPY\n    stat = mp_frozen_stat_helper(mp_frozen_mpy_names, str);\n    if (stat != MP_IMPORT_STAT_NO_EXIST) {\n        return stat;\n    }\n    #endif\n\n    return MP_IMPORT_STAT_NO_EXIST;\n}\n\nint mp_find_frozen_module(const char *str, size_t len, void **data) {\n    #if MICROPY_MODULE_FROZEN_STR\n    mp_lexer_t *lex = mp_lexer_frozen_str(str, len);\n    if (lex != NULL) {\n        *data = lex;\n        return MP_FROZEN_STR;\n    }\n    #endif\n    #if MICROPY_MODULE_FROZEN_MPY\n    const mp_raw_code_t *rc = mp_find_frozen_mpy(str, len);\n    if (rc != NULL) {\n        *data = (void *)rc;\n        return MP_FROZEN_MPY;\n    }\n    #endif\n    return MP_FROZEN_NONE;\n}\n\n#endif\n"
  },
  {
    "path": "py/frozenmod.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 Paul Sokolovsky\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_FROZENMOD_H\n#define MICROPY_INCLUDED_PY_FROZENMOD_H\n\n#include \"py/lexer.h\"\n\nenum {\n    MP_FROZEN_NONE,\n    MP_FROZEN_STR,\n    MP_FROZEN_MPY,\n};\n\nint mp_find_frozen_module(const char *str, size_t len, void **data);\nconst char *mp_find_frozen_str(const char *str, size_t *len);\nmp_import_stat_t mp_frozen_stat(const char *str);\n\n#endif // MICROPY_INCLUDED_PY_FROZENMOD_H\n"
  },
  {
    "path": "py/gc.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/gc.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_ENABLE_GC\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_PRINT (1)\n#define DEBUG_printf DEBUG_printf\n#else // don't print debugging info\n#define DEBUG_PRINT (0)\n#define DEBUG_printf(...) (void)0\n#endif\n\n// make this 1 to dump the heap each time it changes\n#define EXTENSIVE_HEAP_PROFILING (0)\n\n// make this 1 to zero out swept memory to more eagerly\n// detect untraced object still in use\n#define CLEAR_ON_SWEEP (0)\n\n#define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD)\n#define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK)\n\n// ATB = allocation table byte\n// 0b00 = FREE -- free block\n// 0b01 = HEAD -- head of a chain of blocks\n// 0b10 = TAIL -- in the tail of a chain of blocks\n// 0b11 = MARK -- marked head block\n\n#define AT_FREE (0)\n#define AT_HEAD (1)\n#define AT_TAIL (2)\n#define AT_MARK (3)\n\n#define BLOCKS_PER_ATB (4)\n#define ATB_MASK_0 (0x03)\n#define ATB_MASK_1 (0x0c)\n#define ATB_MASK_2 (0x30)\n#define ATB_MASK_3 (0xc0)\n\n#define ATB_0_IS_FREE(a) (((a) & ATB_MASK_0) == 0)\n#define ATB_1_IS_FREE(a) (((a) & ATB_MASK_1) == 0)\n#define ATB_2_IS_FREE(a) (((a) & ATB_MASK_2) == 0)\n#define ATB_3_IS_FREE(a) (((a) & ATB_MASK_3) == 0)\n\n#define BLOCK_SHIFT(block) (2 * ((block) & (BLOCKS_PER_ATB - 1)))\n#define ATB_GET_KIND(block) ((MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] >> BLOCK_SHIFT(block)) & 3)\n#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)\n#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)\n#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)\n#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)\n#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)\n\n#define BLOCK_FROM_PTR(ptr) (((byte *)(ptr) - MP_STATE_MEM(gc_pool_start)) / BYTES_PER_BLOCK)\n#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (uintptr_t)MP_STATE_MEM(gc_pool_start)))\n#define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB)\n\n#if MICROPY_ENABLE_FINALISER\n// FTB = finaliser table byte\n// if set, then the corresponding block may have a finaliser\n\n#define BLOCKS_PER_FTB (8)\n\n#define FTB_GET(block) ((MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] >> ((block) & 7)) & 1)\n#define FTB_SET(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] |= (1 << ((block) & 7)); } while (0)\n#define FTB_CLEAR(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0)\n#endif\n\n#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL\n#define GC_ENTER() mp_thread_mutex_lock(&MP_STATE_MEM(gc_mutex), 1)\n#define GC_EXIT() mp_thread_mutex_unlock(&MP_STATE_MEM(gc_mutex))\n#else\n#define GC_ENTER()\n#define GC_EXIT()\n#endif\n\n// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool\nvoid gc_init(void *start, void *end) {\n    // align end pointer on block boundary\n    end = (void *)((uintptr_t)end & (~(BYTES_PER_BLOCK - 1)));\n    DEBUG_printf(\"Initializing GC heap: %p..%p = \" UINT_FMT \" bytes\\n\", start, end, (byte *)end - (byte *)start);\n\n    // calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes):\n    // T = A + F + P\n    //     F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB\n    //     P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK\n    // => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK)\n    size_t total_byte_len = (byte *)end - (byte *)start;\n    #if MICROPY_ENABLE_FINALISER\n    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);\n    #else\n    MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);\n    #endif\n\n    MP_STATE_MEM(gc_alloc_table_start) = (byte *)start;\n\n    #if MICROPY_ENABLE_FINALISER\n    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;\n    MP_STATE_MEM(gc_finaliser_table_start) = MP_STATE_MEM(gc_alloc_table_start) + MP_STATE_MEM(gc_alloc_table_byte_len);\n    #endif\n\n    size_t gc_pool_block_len = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB;\n    MP_STATE_MEM(gc_pool_start) = (byte *)end - gc_pool_block_len * BYTES_PER_BLOCK;\n    MP_STATE_MEM(gc_pool_end) = end;\n\n    #if MICROPY_ENABLE_FINALISER\n    assert(MP_STATE_MEM(gc_pool_start) >= MP_STATE_MEM(gc_finaliser_table_start) + gc_finaliser_table_byte_len);\n    #endif\n\n    // clear ATBs\n    memset(MP_STATE_MEM(gc_alloc_table_start), 0, MP_STATE_MEM(gc_alloc_table_byte_len));\n\n    #if MICROPY_ENABLE_FINALISER\n    // clear FTBs\n    memset(MP_STATE_MEM(gc_finaliser_table_start), 0, gc_finaliser_table_byte_len);\n    #endif\n\n    // set last free ATB index to start of heap\n    MP_STATE_MEM(gc_last_free_atb_index) = 0;\n\n    // unlock the GC\n    MP_STATE_MEM(gc_lock_depth) = 0;\n\n    // allow auto collection\n    MP_STATE_MEM(gc_auto_collect_enabled) = 1;\n\n    #if MICROPY_GC_ALLOC_THRESHOLD\n    // by default, maxuint for gc threshold, effectively turning gc-by-threshold off\n    MP_STATE_MEM(gc_alloc_threshold) = (size_t)-1;\n    MP_STATE_MEM(gc_alloc_amount) = 0;\n    #endif\n\n    #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL\n    mp_thread_mutex_init(&MP_STATE_MEM(gc_mutex));\n    #endif\n\n    DEBUG_printf(\"GC layout:\\n\");\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);\n    #if MICROPY_ENABLE_FINALISER\n    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);\n    #endif\n    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);\n}\n\nvoid gc_lock(void) {\n    GC_ENTER();\n    MP_STATE_MEM(gc_lock_depth)++;\n    GC_EXIT();\n}\n\nvoid gc_unlock(void) {\n    GC_ENTER();\n    MP_STATE_MEM(gc_lock_depth)--;\n    GC_EXIT();\n}\n\nbool gc_is_locked(void) {\n    return MP_STATE_MEM(gc_lock_depth) != 0;\n}\n\n// ptr should be of type void*\n#define VERIFY_PTR(ptr) ( \\\n    ((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) == 0          /* must be aligned on a block */ \\\n    && ptr >= (void *)MP_STATE_MEM(gc_pool_start)        /* must be above start of pool */ \\\n    && ptr < (void *)MP_STATE_MEM(gc_pool_end)           /* must be below end of pool */ \\\n    )\n\n#ifndef TRACE_MARK\n#if DEBUG_PRINT\n#define TRACE_MARK(block, ptr) DEBUG_printf(\"gc_mark(%p)\\n\", ptr)\n#else\n#define TRACE_MARK(block, ptr)\n#endif\n#endif\n\n// Take the given block as the topmost block on the stack. Check all it's\n// children: mark the unmarked child blocks and put those newly marked\n// blocks on the stack. When all children have been checked, pop off the\n// topmost block on the stack and repeat with that one.\nSTATIC void gc_mark_subtree(size_t block) {\n    // Start with the block passed in the argument.\n    size_t sp = 0;\n    for (;;) {\n        // work out number of consecutive blocks in the chain starting with this one\n        size_t n_blocks = 0;\n        do {\n            n_blocks += 1;\n        } while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);\n\n        // check this block's children\n        void **ptrs = (void **)PTR_FROM_BLOCK(block);\n        for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void *); i > 0; i--, ptrs++) {\n            void *ptr = *ptrs;\n            if (VERIFY_PTR(ptr)) {\n                // Mark and push this pointer\n                size_t childblock = BLOCK_FROM_PTR(ptr);\n                if (ATB_GET_KIND(childblock) == AT_HEAD) {\n                    // an unmarked head, mark it, and push it on gc stack\n                    TRACE_MARK(childblock, ptr);\n                    ATB_HEAD_TO_MARK(childblock);\n                    if (sp < MICROPY_ALLOC_GC_STACK_SIZE) {\n                        MP_STATE_MEM(gc_stack)[sp++] = childblock;\n                    } else {\n                        MP_STATE_MEM(gc_stack_overflow) = 1;\n                    }\n                }\n            }\n        }\n\n        // Are there any blocks on the stack?\n        if (sp == 0) {\n            break; // No, stack is empty, we're done.\n        }\n\n        // pop the next block off the stack\n        block = MP_STATE_MEM(gc_stack)[--sp];\n    }\n}\n\nSTATIC void gc_deal_with_stack_overflow(void) {\n    while (MP_STATE_MEM(gc_stack_overflow)) {\n        MP_STATE_MEM(gc_stack_overflow) = 0;\n\n        // scan entire memory looking for blocks which have been marked but not their children\n        for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {\n            // trace (again) if mark bit set\n            if (ATB_GET_KIND(block) == AT_MARK) {\n                gc_mark_subtree(block);\n            }\n        }\n    }\n}\n\nSTATIC void gc_sweep(void) {\n    #if MICROPY_PY_GC_COLLECT_RETVAL\n    MP_STATE_MEM(gc_collected) = 0;\n    #endif\n    // free unmarked heads and their tails\n    int free_tail = 0;\n    for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {\n        switch (ATB_GET_KIND(block)) {\n            case AT_HEAD:\n                #if MICROPY_ENABLE_FINALISER\n                if (FTB_GET(block)) {\n                    mp_obj_base_t *obj = (mp_obj_base_t *)PTR_FROM_BLOCK(block);\n                    if (obj->type != NULL) {\n                        // if the object has a type then see if it has a __del__ method\n                        mp_obj_t dest[2];\n                        mp_load_method_maybe(MP_OBJ_FROM_PTR(obj), MP_QSTR___del__, dest);\n                        if (dest[0] != MP_OBJ_NULL) {\n                            // load_method returned a method, execute it in a protected environment\n                            #if MICROPY_ENABLE_SCHEDULER\n                            mp_sched_lock();\n                            #endif\n                            mp_call_function_1_protected(dest[0], dest[1]);\n                            #if MICROPY_ENABLE_SCHEDULER\n                            mp_sched_unlock();\n                            #endif\n                        }\n                    }\n                    // clear finaliser flag\n                    FTB_CLEAR(block);\n                }\n                #endif\n                free_tail = 1;\n                DEBUG_printf(\"gc_sweep(%p)\\n\", PTR_FROM_BLOCK(block));\n                #if MICROPY_PY_GC_COLLECT_RETVAL\n                MP_STATE_MEM(gc_collected)++;\n                #endif\n                // fall through to free the head\n                MP_FALLTHROUGH\n\n            case AT_TAIL:\n                if (free_tail) {\n                    ATB_ANY_TO_FREE(block);\n                    #if CLEAR_ON_SWEEP\n                    memset((void *)PTR_FROM_BLOCK(block), 0, BYTES_PER_BLOCK);\n                    #endif\n                }\n                break;\n\n            case AT_MARK:\n                ATB_MARK_TO_HEAD(block);\n                free_tail = 0;\n                break;\n        }\n    }\n}\n\nvoid gc_collect_start(void) {\n    GC_ENTER();\n    MP_STATE_MEM(gc_lock_depth)++;\n    #if MICROPY_GC_ALLOC_THRESHOLD\n    MP_STATE_MEM(gc_alloc_amount) = 0;\n    #endif\n    MP_STATE_MEM(gc_stack_overflow) = 0;\n\n    // Trace root pointers.  This relies on the root pointers being organised\n    // correctly in the mp_state_ctx structure.  We scan nlr_top, dict_locals,\n    // dict_globals, then the root pointer section of mp_state_vm.\n    void **ptrs = (void **)(void *)&mp_state_ctx;\n    size_t root_start = offsetof(mp_state_ctx_t, thread.dict_locals);\n    size_t root_end = offsetof(mp_state_ctx_t, vm.qstr_last_chunk);\n    gc_collect_root(ptrs + root_start / sizeof(void *), (root_end - root_start) / sizeof(void *));\n\n    #if MICROPY_ENABLE_PYSTACK\n    // Trace root pointers from the Python stack.\n    ptrs = (void **)(void *)MP_STATE_THREAD(pystack_start);\n    gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void *));\n    #endif\n}\n\nvoid gc_collect_root(void **ptrs, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        void *ptr = ptrs[i];\n        if (VERIFY_PTR(ptr)) {\n            size_t block = BLOCK_FROM_PTR(ptr);\n            if (ATB_GET_KIND(block) == AT_HEAD) {\n                // An unmarked head: mark it, and mark all its children\n                TRACE_MARK(block, ptr);\n                ATB_HEAD_TO_MARK(block);\n                gc_mark_subtree(block);\n            }\n        }\n    }\n}\n\nvoid gc_collect_end(void) {\n    gc_deal_with_stack_overflow();\n    gc_sweep();\n    MP_STATE_MEM(gc_last_free_atb_index) = 0;\n    MP_STATE_MEM(gc_lock_depth)--;\n    GC_EXIT();\n}\n\nvoid gc_sweep_all(void) {\n    GC_ENTER();\n    MP_STATE_MEM(gc_lock_depth)++;\n    MP_STATE_MEM(gc_stack_overflow) = 0;\n    gc_collect_end();\n}\n\nvoid gc_info(gc_info_t *info) {\n    GC_ENTER();\n    info->total = MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start);\n    info->used = 0;\n    info->free = 0;\n    info->max_free = 0;\n    info->num_1block = 0;\n    info->num_2block = 0;\n    info->max_block = 0;\n    bool finish = false;\n    for (size_t block = 0, len = 0, len_free = 0; !finish;) {\n        size_t kind = ATB_GET_KIND(block);\n        switch (kind) {\n            case AT_FREE:\n                info->free += 1;\n                len_free += 1;\n                len = 0;\n                break;\n\n            case AT_HEAD:\n                info->used += 1;\n                len = 1;\n                break;\n\n            case AT_TAIL:\n                info->used += 1;\n                len += 1;\n                break;\n\n            case AT_MARK:\n                // shouldn't happen\n                break;\n        }\n\n        block++;\n        finish = (block == MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB);\n        // Get next block type if possible\n        if (!finish) {\n            kind = ATB_GET_KIND(block);\n        }\n\n        if (finish || kind == AT_FREE || kind == AT_HEAD) {\n            if (len == 1) {\n                info->num_1block += 1;\n            } else if (len == 2) {\n                info->num_2block += 1;\n            }\n            if (len > info->max_block) {\n                info->max_block = len;\n            }\n            if (finish || kind == AT_HEAD) {\n                if (len_free > info->max_free) {\n                    info->max_free = len_free;\n                }\n                len_free = 0;\n            }\n        }\n    }\n\n    info->used *= BYTES_PER_BLOCK;\n    info->free *= BYTES_PER_BLOCK;\n    GC_EXIT();\n}\n\nvoid *gc_alloc(size_t n_bytes, unsigned int alloc_flags) {\n    bool has_finaliser = alloc_flags & GC_ALLOC_FLAG_HAS_FINALISER;\n    size_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;\n    DEBUG_printf(\"gc_alloc(\" UINT_FMT \" bytes -> \" UINT_FMT \" blocks)\\n\", n_bytes, n_blocks);\n\n    // check for 0 allocation\n    if (n_blocks == 0) {\n        return NULL;\n    }\n\n    GC_ENTER();\n\n    // check if GC is locked\n    if (MP_STATE_MEM(gc_lock_depth) > 0) {\n        GC_EXIT();\n        return NULL;\n    }\n\n    size_t i;\n    size_t end_block;\n    size_t start_block;\n    size_t n_free;\n    int collected = !MP_STATE_MEM(gc_auto_collect_enabled);\n\n    #if MICROPY_GC_ALLOC_THRESHOLD\n    if (!collected && MP_STATE_MEM(gc_alloc_amount) >= MP_STATE_MEM(gc_alloc_threshold)) {\n        GC_EXIT();\n        gc_collect();\n        collected = 1;\n        GC_ENTER();\n    }\n    #endif\n\n    for (;;) {\n\n        // look for a run of n_blocks available blocks\n        n_free = 0;\n        for (i = MP_STATE_MEM(gc_last_free_atb_index); i < MP_STATE_MEM(gc_alloc_table_byte_len); i++) {\n            byte a = MP_STATE_MEM(gc_alloc_table_start)[i];\n            // *FORMAT-OFF*\n            if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; }\n            if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; }\n            if (ATB_2_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 2; goto found; } } else { n_free = 0; }\n            if (ATB_3_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 3; goto found; } } else { n_free = 0; }\n            // *FORMAT-ON*\n        }\n\n        GC_EXIT();\n        // nothing found!\n        if (collected) {\n            return NULL;\n        }\n        DEBUG_printf(\"gc_alloc(\" UINT_FMT \"): no free mem, triggering GC\\n\", n_bytes);\n        gc_collect();\n        collected = 1;\n        GC_ENTER();\n    }\n\n    // found, ending at block i inclusive\nfound:\n    // get starting and end blocks, both inclusive\n    end_block = i;\n    start_block = i - n_free + 1;\n\n    // Set last free ATB index to block after last block we found, for start of\n    // next scan.  To reduce fragmentation, we only do this if we were looking\n    // for a single free block, which guarantees that there are no free blocks\n    // before this one.  Also, whenever we free or shink a block we must check\n    // if this index needs adjusting (see gc_realloc and gc_free).\n    if (n_free == 1) {\n        MP_STATE_MEM(gc_last_free_atb_index) = (i + 1) / BLOCKS_PER_ATB;\n    }\n\n    // mark first block as used head\n    ATB_FREE_TO_HEAD(start_block);\n\n    // mark rest of blocks as used tail\n    // TODO for a run of many blocks can make this more efficient\n    for (size_t bl = start_block + 1; bl <= end_block; bl++) {\n        ATB_FREE_TO_TAIL(bl);\n    }\n\n    // get pointer to first block\n    // we must create this pointer before unlocking the GC so a collection can find it\n    void *ret_ptr = (void *)(MP_STATE_MEM(gc_pool_start) + start_block * BYTES_PER_BLOCK);\n    DEBUG_printf(\"gc_alloc(%p)\\n\", ret_ptr);\n\n    #if MICROPY_GC_ALLOC_THRESHOLD\n    MP_STATE_MEM(gc_alloc_amount) += n_blocks;\n    #endif\n\n    GC_EXIT();\n\n    #if MICROPY_GC_CONSERVATIVE_CLEAR\n    // be conservative and zero out all the newly allocated blocks\n    memset((byte *)ret_ptr, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK);\n    #else\n    // zero out the additional bytes of the newly allocated blocks\n    // This is needed because the blocks may have previously held pointers\n    // to the heap and will not be set to something else if the caller\n    // doesn't actually use the entire block.  As such they will continue\n    // to point to the heap and may prevent other blocks from being reclaimed.\n    memset((byte *)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);\n    #endif\n\n    #if MICROPY_ENABLE_FINALISER\n    if (has_finaliser) {\n        // clear type pointer in case it is never set\n        ((mp_obj_base_t *)ret_ptr)->type = NULL;\n        // set mp_obj flag only if it has a finaliser\n        GC_ENTER();\n        FTB_SET(start_block);\n        GC_EXIT();\n    }\n    #else\n    (void)has_finaliser;\n    #endif\n\n    #if EXTENSIVE_HEAP_PROFILING\n    gc_dump_alloc_table();\n    #endif\n\n    return ret_ptr;\n}\n\n/*\nvoid *gc_alloc(mp_uint_t n_bytes) {\n    return _gc_alloc(n_bytes, false);\n}\n\nvoid *gc_alloc_with_finaliser(mp_uint_t n_bytes) {\n    return _gc_alloc(n_bytes, true);\n}\n*/\n\n// force the freeing of a piece of memory\n// TODO: freeing here does not call finaliser\nvoid gc_free(void *ptr) {\n    GC_ENTER();\n    if (MP_STATE_MEM(gc_lock_depth) > 0) {\n        // TODO how to deal with this error?\n        GC_EXIT();\n        return;\n    }\n\n    DEBUG_printf(\"gc_free(%p)\\n\", ptr);\n\n    if (ptr == NULL) {\n        GC_EXIT();\n    } else {\n        // get the GC block number corresponding to this pointer\n        assert(VERIFY_PTR(ptr));\n        size_t block = BLOCK_FROM_PTR(ptr);\n        assert(ATB_GET_KIND(block) == AT_HEAD);\n\n        #if MICROPY_ENABLE_FINALISER\n        FTB_CLEAR(block);\n        #endif\n\n        // set the last_free pointer to this block if it's earlier in the heap\n        if (block / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) {\n            MP_STATE_MEM(gc_last_free_atb_index) = block / BLOCKS_PER_ATB;\n        }\n\n        // free head and all of its tail blocks\n        do {\n            ATB_ANY_TO_FREE(block);\n            block += 1;\n        } while (ATB_GET_KIND(block) == AT_TAIL);\n\n        GC_EXIT();\n\n        #if EXTENSIVE_HEAP_PROFILING\n        gc_dump_alloc_table();\n        #endif\n    }\n}\n\nsize_t gc_nbytes(const void *ptr) {\n    GC_ENTER();\n    if (VERIFY_PTR(ptr)) {\n        size_t block = BLOCK_FROM_PTR(ptr);\n        if (ATB_GET_KIND(block) == AT_HEAD) {\n            // work out number of consecutive blocks in the chain starting with this on\n            size_t n_blocks = 0;\n            do {\n                n_blocks += 1;\n            } while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);\n            GC_EXIT();\n            return n_blocks * BYTES_PER_BLOCK;\n        }\n    }\n\n    // invalid pointer\n    GC_EXIT();\n    return 0;\n}\n\n#if 0\n// old, simple realloc that didn't expand memory in place\nvoid *gc_realloc(void *ptr, mp_uint_t n_bytes) {\n    mp_uint_t n_existing = gc_nbytes(ptr);\n    if (n_bytes <= n_existing) {\n        return ptr;\n    } else {\n        bool has_finaliser;\n        if (ptr == NULL) {\n            has_finaliser = false;\n        } else {\n            #if MICROPY_ENABLE_FINALISER\n            has_finaliser = FTB_GET(BLOCK_FROM_PTR((mp_uint_t)ptr));\n            #else\n            has_finaliser = false;\n            #endif\n        }\n        void *ptr2 = gc_alloc(n_bytes, has_finaliser);\n        if (ptr2 == NULL) {\n            return ptr2;\n        }\n        memcpy(ptr2, ptr, n_existing);\n        gc_free(ptr);\n        return ptr2;\n    }\n}\n\n#else // Alternative gc_realloc impl\n\nvoid *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {\n    // check for pure allocation\n    if (ptr_in == NULL) {\n        return gc_alloc(n_bytes, false);\n    }\n\n    // check for pure free\n    if (n_bytes == 0) {\n        gc_free(ptr_in);\n        return NULL;\n    }\n\n    void *ptr = ptr_in;\n\n    GC_ENTER();\n\n    if (MP_STATE_MEM(gc_lock_depth) > 0) {\n        GC_EXIT();\n        return NULL;\n    }\n\n    // get the GC block number corresponding to this pointer\n    assert(VERIFY_PTR(ptr));\n    size_t block = BLOCK_FROM_PTR(ptr);\n    assert(ATB_GET_KIND(block) == AT_HEAD);\n\n    // compute number of new blocks that are requested\n    size_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;\n\n    // Get the total number of consecutive blocks that are already allocated to\n    // this chunk of memory, and then count the number of free blocks following\n    // it.  Stop if we reach the end of the heap, or if we find enough extra\n    // free blocks to satisfy the realloc.  Note that we need to compute the\n    // total size of the existing memory chunk so we can correctly and\n    // efficiently shrink it (see below for shrinking code).\n    size_t n_free = 0;\n    size_t n_blocks = 1; // counting HEAD block\n    size_t max_block = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB;\n    for (size_t bl = block + n_blocks; bl < max_block; bl++) {\n        byte block_type = ATB_GET_KIND(bl);\n        if (block_type == AT_TAIL) {\n            n_blocks++;\n            continue;\n        }\n        if (block_type == AT_FREE) {\n            n_free++;\n            if (n_blocks + n_free >= new_blocks) {\n                // stop as soon as we find enough blocks for n_bytes\n                break;\n            }\n            continue;\n        }\n        break;\n    }\n\n    // return original ptr if it already has the requested number of blocks\n    if (new_blocks == n_blocks) {\n        GC_EXIT();\n        return ptr_in;\n    }\n\n    // check if we can shrink the allocated area\n    if (new_blocks < n_blocks) {\n        // free unneeded tail blocks\n        for (size_t bl = block + new_blocks, count = n_blocks - new_blocks; count > 0; bl++, count--) {\n            ATB_ANY_TO_FREE(bl);\n        }\n\n        // set the last_free pointer to end of this block if it's earlier in the heap\n        if ((block + new_blocks) / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) {\n            MP_STATE_MEM(gc_last_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB;\n        }\n\n        GC_EXIT();\n\n        #if EXTENSIVE_HEAP_PROFILING\n        gc_dump_alloc_table();\n        #endif\n\n        return ptr_in;\n    }\n\n    // check if we can expand in place\n    if (new_blocks <= n_blocks + n_free) {\n        // mark few more blocks as used tail\n        for (size_t bl = block + n_blocks; bl < block + new_blocks; bl++) {\n            assert(ATB_GET_KIND(bl) == AT_FREE);\n            ATB_FREE_TO_TAIL(bl);\n        }\n\n        GC_EXIT();\n\n        #if MICROPY_GC_CONSERVATIVE_CLEAR\n        // be conservative and zero out all the newly allocated blocks\n        memset((byte *)ptr_in + n_blocks * BYTES_PER_BLOCK, 0, (new_blocks - n_blocks) * BYTES_PER_BLOCK);\n        #else\n        // zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc)\n        memset((byte *)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);\n        #endif\n\n        #if EXTENSIVE_HEAP_PROFILING\n        gc_dump_alloc_table();\n        #endif\n\n        return ptr_in;\n    }\n\n    #if MICROPY_ENABLE_FINALISER\n    bool ftb_state = FTB_GET(block);\n    #else\n    bool ftb_state = false;\n    #endif\n\n    GC_EXIT();\n\n    if (!allow_move) {\n        // not allowed to move memory block so return failure\n        return NULL;\n    }\n\n    // can't resize inplace; try to find a new contiguous chain\n    void *ptr_out = gc_alloc(n_bytes, ftb_state);\n\n    // check that the alloc succeeded\n    if (ptr_out == NULL) {\n        return NULL;\n    }\n\n    DEBUG_printf(\"gc_realloc(%p -> %p)\\n\", ptr_in, ptr_out);\n    memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);\n    gc_free(ptr_in);\n    return ptr_out;\n}\n#endif // Alternative gc_realloc impl\n\nvoid gc_dump_info(void) {\n    gc_info_t info;\n    gc_info(&info);\n    mp_printf(&mp_plat_print, \"GC: total: %u, used: %u, free: %u\\n\",\n        (uint)info.total, (uint)info.used, (uint)info.free);\n    mp_printf(&mp_plat_print, \" No. of 1-blocks: %u, 2-blocks: %u, max blk sz: %u, max free sz: %u\\n\",\n        (uint)info.num_1block, (uint)info.num_2block, (uint)info.max_block, (uint)info.max_free);\n}\n\nvoid gc_dump_alloc_table(void) {\n    GC_ENTER();\n    static const size_t DUMP_BYTES_PER_LINE = 64;\n    #if !EXTENSIVE_HEAP_PROFILING\n    // When comparing heap output we don't want to print the starting\n    // pointer of the heap because it changes from run to run.\n    mp_printf(&mp_plat_print, \"GC memory layout; from %p:\", MP_STATE_MEM(gc_pool_start));\n    #endif\n    for (size_t bl = 0; bl < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; bl++) {\n        if (bl % DUMP_BYTES_PER_LINE == 0) {\n            // a new line of blocks\n            {\n                // check if this line contains only free blocks\n                size_t bl2 = bl;\n                while (bl2 < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB && ATB_GET_KIND(bl2) == AT_FREE) {\n                    bl2++;\n                }\n                if (bl2 - bl >= 2 * DUMP_BYTES_PER_LINE) {\n                    // there are at least 2 lines containing only free blocks, so abbreviate their printing\n                    mp_printf(&mp_plat_print, \"\\n       (%u lines all free)\", (uint)(bl2 - bl) / DUMP_BYTES_PER_LINE);\n                    bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1));\n                    if (bl >= MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB) {\n                        // got to end of heap\n                        break;\n                    }\n                }\n            }\n            // print header for new line of blocks\n            // (the cast to uint32_t is for 16-bit ports)\n            // mp_printf(&mp_plat_print, \"\\n%05x: \", (uint)(PTR_FROM_BLOCK(bl) & (uint32_t)0xfffff));\n            mp_printf(&mp_plat_print, \"\\n%05x: \", (uint)((bl * BYTES_PER_BLOCK) & (uint32_t)0xfffff));\n        }\n        int c = ' ';\n        switch (ATB_GET_KIND(bl)) {\n            case AT_FREE:\n                c = '.';\n                break;\n            /* this prints out if the object is reachable from BSS or STACK (for unix only)\n            case AT_HEAD: {\n                c = 'h';\n                void **ptrs = (void**)(void*)&mp_state_ctx;\n                mp_uint_t len = offsetof(mp_state_ctx_t, vm.stack_top) / sizeof(mp_uint_t);\n                for (mp_uint_t i = 0; i < len; i++) {\n                    mp_uint_t ptr = (mp_uint_t)ptrs[i];\n                    if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) {\n                        c = 'B';\n                        break;\n                    }\n                }\n                if (c == 'h') {\n                    ptrs = (void**)&c;\n                    len = ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)&c) / sizeof(mp_uint_t);\n                    for (mp_uint_t i = 0; i < len; i++) {\n                        mp_uint_t ptr = (mp_uint_t)ptrs[i];\n                        if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) {\n                            c = 'S';\n                            break;\n                        }\n                    }\n                }\n                break;\n            }\n            */\n            /* this prints the uPy object type of the head block */\n            case AT_HEAD: {\n                void **ptr = (void **)(MP_STATE_MEM(gc_pool_start) + bl * BYTES_PER_BLOCK);\n                if (*ptr == &mp_type_tuple) {\n                    c = 'T';\n                } else if (*ptr == &mp_type_list) {\n                    c = 'L';\n                } else if (*ptr == &mp_type_dict) {\n                    c = 'D';\n                } else if (*ptr == &mp_type_str || *ptr == &mp_type_bytes) {\n                    c = 'S';\n                }\n                #if MICROPY_PY_BUILTINS_BYTEARRAY\n                else if (*ptr == &mp_type_bytearray) {\n                    c = 'A';\n                }\n                #endif\n                #if MICROPY_PY_ARRAY\n                else if (*ptr == &mp_type_array) {\n                    c = 'A';\n                }\n                #endif\n                #if MICROPY_PY_BUILTINS_FLOAT\n                else if (*ptr == &mp_type_float) {\n                    c = 'F';\n                }\n                #endif\n                else if (*ptr == &mp_type_fun_bc) {\n                    c = 'B';\n                } else if (*ptr == &mp_type_module) {\n                    c = 'M';\n                } else {\n                    c = 'h';\n                    #if 0\n                    // This code prints \"Q\" for qstr-pool data, and \"q\" for qstr-str\n                    // data.  It can be useful to see how qstrs are being allocated,\n                    // but is disabled by default because it is very slow.\n                    for (qstr_pool_t *pool = MP_STATE_VM(last_pool); c == 'h' && pool != NULL; pool = pool->prev) {\n                        if ((qstr_pool_t *)ptr == pool) {\n                            c = 'Q';\n                            break;\n                        }\n                        for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {\n                            if ((const byte *)ptr == *q) {\n                                c = 'q';\n                                break;\n                            }\n                        }\n                    }\n                    #endif\n                }\n                break;\n            }\n            case AT_TAIL:\n                c = '=';\n                break;\n            case AT_MARK:\n                c = 'm';\n                break;\n        }\n        mp_printf(&mp_plat_print, \"%c\", c);\n    }\n    mp_print_str(&mp_plat_print, \"\\n\");\n    GC_EXIT();\n}\n\n#if 0\n// For testing the GC functions\nvoid gc_test(void) {\n    mp_uint_t len = 500;\n    mp_uint_t *heap = malloc(len);\n    gc_init(heap, heap + len / sizeof(mp_uint_t));\n    void *ptrs[100];\n    {\n        mp_uint_t **p = gc_alloc(16, false);\n        p[0] = gc_alloc(64, false);\n        p[1] = gc_alloc(1, false);\n        p[2] = gc_alloc(1, false);\n        p[3] = gc_alloc(1, false);\n        mp_uint_t ***p2 = gc_alloc(16, false);\n        p2[0] = p;\n        p2[1] = p;\n        ptrs[0] = p2;\n    }\n    for (int i = 0; i < 25; i += 2) {\n        mp_uint_t *p = gc_alloc(i, false);\n        printf(\"p=%p\\n\", p);\n        if (i & 3) {\n            // ptrs[i] = p;\n        }\n    }\n\n    printf(\"Before GC:\\n\");\n    gc_dump_alloc_table();\n    printf(\"Starting GC...\\n\");\n    gc_collect_start();\n    gc_collect_root(ptrs, sizeof(ptrs) / sizeof(void *));\n    gc_collect_end();\n    printf(\"After GC:\\n\");\n    gc_dump_alloc_table();\n}\n#endif\n\n#endif // MICROPY_ENABLE_GC\n"
  },
  {
    "path": "py/gc.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_GC_H\n#define MICROPY_INCLUDED_PY_GC_H\n\n#include <stdint.h>\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n\nvoid gc_init(void *start, void *end);\n\n// These lock/unlock functions can be nested.\n// They can be used to prevent the GC from allocating/freeing.\nvoid gc_lock(void);\nvoid gc_unlock(void);\nbool gc_is_locked(void);\n\n// A given port must implement gc_collect by using the other collect functions.\nvoid gc_collect(void);\nvoid gc_collect_start(void);\nvoid gc_collect_root(void **ptrs, size_t len);\nvoid gc_collect_end(void);\n\n// Use this function to sweep the whole heap and run all finalisers\nvoid gc_sweep_all(void);\n\nenum {\n    GC_ALLOC_FLAG_HAS_FINALISER = 1,\n};\n\nvoid *gc_alloc(size_t n_bytes, unsigned int alloc_flags);\nvoid gc_free(void *ptr); // does not call finaliser\nsize_t gc_nbytes(const void *ptr);\nvoid *gc_realloc(void *ptr, size_t n_bytes, bool allow_move);\n\ntypedef struct _gc_info_t {\n    size_t total;\n    size_t used;\n    size_t free;\n    size_t max_free;\n    size_t num_1block;\n    size_t num_2block;\n    size_t max_block;\n} gc_info_t;\n\nvoid gc_info(gc_info_t *info);\nvoid gc_dump_info(void);\nvoid gc_dump_alloc_table(void);\n\n#endif // MICROPY_INCLUDED_PY_GC_H\n"
  },
  {
    "path": "py/grammar.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2020 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n// *FORMAT-OFF*\n\n// rules for writing rules:\n// - zero_or_more is implemented using opt_rule around a one_or_more rule\n// - don't put opt_rule in arguments of or rule; instead, wrap the call to this or rule in opt_rule\n\n// Generic sub-rules used by multiple rules below.\n\nDEF_RULE_NC(generic_colon_test, and_ident(2), tok(DEL_COLON), rule(test))\nDEF_RULE_NC(generic_equal_test, and_ident(2), tok(DEL_EQUAL), rule(test))\n\n// # Start symbols for the grammar:\n// #       single_input is a single interactive statement;\n// #       file_input is a module or sequence of commands read from an input file;\n// #       eval_input is the input for the eval() functions.\n// # NB: compound_stmt in single_input is followed by extra NEWLINE! --> not in MicroPython\n// single_input: NEWLINE | simple_stmt | compound_stmt\n// file_input: (NEWLINE | stmt)* ENDMARKER\n// eval_input: testlist NEWLINE* ENDMARKER\n\nDEF_RULE_NC(single_input, or(3), tok(NEWLINE), rule(simple_stmt), rule(compound_stmt))\nDEF_RULE(file_input, c(generic_all_nodes), and_ident(1), opt_rule(file_input_2))\nDEF_RULE(file_input_2, c(generic_all_nodes), one_or_more, rule(file_input_3))\nDEF_RULE_NC(file_input_3, or(2), tok(NEWLINE), rule(stmt))\nDEF_RULE_NC(eval_input, and_ident(2), rule(testlist), opt_rule(eval_input_2))\nDEF_RULE_NC(eval_input_2, and(1), tok(NEWLINE))\n\n// decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE\n// decorators: decorator+\n// decorated: decorators (classdef | funcdef | async_funcdef)\n// funcdef: 'def' NAME parameters ['->' test] ':' suite\n// async_funcdef: 'async' funcdef\n// parameters: '(' [typedargslist] ')'\n// typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* [',' ['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]] | '*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef\n// tfpdef: NAME [':' test]\n// varargslist: vfpdef ['=' test] (',' vfpdef ['=' test])* [',' ['*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef]] |  '*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef\n// vfpdef: NAME\n\nDEF_RULE_NC(decorator, and(4), tok(OP_AT), rule(dotted_name), opt_rule(trailer_paren), tok(NEWLINE))\nDEF_RULE_NC(decorators, one_or_more, rule(decorator))\nDEF_RULE(decorated, c(decorated), and_ident(2), rule(decorators), rule(decorated_body))\n#if MICROPY_PY_ASYNC_AWAIT\nDEF_RULE_NC(decorated_body, or(3), rule(classdef), rule(funcdef), rule(async_funcdef))\nDEF_RULE_NC(async_funcdef, and(2), tok(KW_ASYNC), rule(funcdef))\n#else\nDEF_RULE_NC(decorated_body, or(2), rule(classdef), rule(funcdef))\n#endif\nDEF_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))\nDEF_RULE_NC(funcdefrettype, and_ident(2), tok(DEL_MINUS_MORE), rule(test))\n// note: typedargslist lets through more than is allowed, compiler does further checks\nDEF_RULE_NC(typedargslist, list_with_end, rule(typedargslist_item), tok(DEL_COMMA))\nDEF_RULE_NC(typedargslist_item, or(3), rule(typedargslist_name), rule(typedargslist_star), rule(typedargslist_dbl_star))\nDEF_RULE_NC(typedargslist_name, and_ident(3), tok(NAME), opt_rule(generic_colon_test), opt_rule(generic_equal_test))\nDEF_RULE_NC(typedargslist_star, and(2), tok(OP_STAR), opt_rule(tfpdef))\nDEF_RULE_NC(typedargslist_dbl_star, and(3), tok(OP_DBL_STAR), tok(NAME), opt_rule(generic_colon_test))\nDEF_RULE_NC(tfpdef, and(2), tok(NAME), opt_rule(generic_colon_test))\n// note: varargslist lets through more than is allowed, compiler does further checks\nDEF_RULE_NC(varargslist, list_with_end, rule(varargslist_item), tok(DEL_COMMA))\nDEF_RULE_NC(varargslist_item, or(3), rule(varargslist_name), rule(varargslist_star), rule(varargslist_dbl_star))\nDEF_RULE_NC(varargslist_name, and_ident(2), tok(NAME), opt_rule(generic_equal_test))\nDEF_RULE_NC(varargslist_star, and(2), tok(OP_STAR), opt_rule(vfpdef))\nDEF_RULE_NC(varargslist_dbl_star, and(2), tok(OP_DBL_STAR), tok(NAME))\nDEF_RULE_NC(vfpdef, and_ident(1), tok(NAME))\n\n// stmt: compound_stmt | simple_stmt\n\nDEF_RULE_NC(stmt, or(2), rule(compound_stmt), rule(simple_stmt))\n\n// simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE\n\nDEF_RULE_NC(simple_stmt, and_ident(2), rule(simple_stmt_2), tok(NEWLINE))\nDEF_RULE(simple_stmt_2, c(generic_all_nodes), list_with_end, rule(small_stmt), tok(DEL_SEMICOLON))\n\n// small_stmt: expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt\n// expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*)\n// testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']\n// annassign: ':' test ['=' (yield_expr|testlist_star_expr)]\n// augassign: '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='\n// # For normal and annotated assignments, additional restrictions enforced by the interpreter\n\nDEF_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))\nDEF_RULE(expr_stmt, c(expr_stmt), and(2), rule(testlist_star_expr), opt_rule(expr_stmt_2))\nDEF_RULE_NC(expr_stmt_2, or(3), rule(annassign), rule(expr_stmt_augassign), rule(expr_stmt_assign_list))\nDEF_RULE_NC(expr_stmt_augassign, and_ident(2), rule(augassign), rule(expr_stmt_6))\nDEF_RULE_NC(expr_stmt_assign_list, one_or_more, rule(expr_stmt_assign))\nDEF_RULE_NC(expr_stmt_assign, and_ident(2), tok(DEL_EQUAL), rule(expr_stmt_6))\nDEF_RULE_NC(expr_stmt_6, or(2), rule(yield_expr), rule(testlist_star_expr))\nDEF_RULE(testlist_star_expr, c(generic_tuple), list_with_end, rule(testlist_star_expr_2), tok(DEL_COMMA))\nDEF_RULE_NC(testlist_star_expr_2, or(2), rule(star_expr), rule(test))\nDEF_RULE_NC(annassign, and(3), tok(DEL_COLON), rule(test), opt_rule(expr_stmt_assign))\nDEF_RULE_NC(augassign, or(13), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DEL_STAR_EQUAL), tok(DEL_AT_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))\n\n// del_stmt: 'del' exprlist\n// pass_stmt: 'pass'\n// flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt\n// break_stmt: 'break'\n// continue_stmt: 'continue'\n// return_stmt: 'return' [testlist]\n// yield_stmt: yield_expr\n// raise_stmt: 'raise' [test ['from' test]]\n\nDEF_RULE(del_stmt, c(del_stmt), and(2), tok(KW_DEL), rule(exprlist))\nDEF_RULE(pass_stmt, c(generic_all_nodes), and(1), tok(KW_PASS))\nDEF_RULE_NC(flow_stmt, or(5), rule(break_stmt), rule(continue_stmt), rule(return_stmt), rule(raise_stmt), rule(yield_stmt))\nDEF_RULE(break_stmt, c(break_cont_stmt), and(1), tok(KW_BREAK))\nDEF_RULE(continue_stmt, c(break_cont_stmt), and(1), tok(KW_CONTINUE))\nDEF_RULE(return_stmt, c(return_stmt), and(2), tok(KW_RETURN), opt_rule(testlist))\nDEF_RULE(yield_stmt, c(yield_stmt), and(1), rule(yield_expr))\nDEF_RULE(raise_stmt, c(raise_stmt), and(2), tok(KW_RAISE), opt_rule(raise_stmt_arg))\nDEF_RULE_NC(raise_stmt_arg, and_ident(2), rule(test), opt_rule(raise_stmt_from))\nDEF_RULE_NC(raise_stmt_from, and_ident(2), tok(KW_FROM), rule(test))\n\n// import_stmt: import_name | import_from\n// import_name: 'import' dotted_as_names\n// import_from: 'from' (('.' | '...')* dotted_name | ('.' | '...')+) 'import' ('*' | '(' import_as_names ')' | import_as_names)\n// import_as_name: NAME ['as' NAME]\n// dotted_as_name: dotted_name ['as' NAME]\n// import_as_names: import_as_name (',' import_as_name)* [',']\n// dotted_as_names: dotted_as_name (',' dotted_as_name)*\n// dotted_name: NAME ('.' NAME)*\n// global_stmt: 'global' NAME (',' NAME)*\n// nonlocal_stmt: 'nonlocal' NAME (',' NAME)*\n// assert_stmt: 'assert' test [',' test]\n\nDEF_RULE_NC(import_stmt, or(2), rule(import_name), rule(import_from))\nDEF_RULE(import_name, c(import_name), and(2), tok(KW_IMPORT), rule(dotted_as_names))\nDEF_RULE(import_from, c(import_from), and(4), tok(KW_FROM), rule(import_from_2), tok(KW_IMPORT), rule(import_from_3))\nDEF_RULE_NC(import_from_2, or(2), rule(dotted_name), rule(import_from_2b))\nDEF_RULE_NC(import_from_2b, and_ident(2), rule(one_or_more_period_or_ellipsis), opt_rule(dotted_name))\nDEF_RULE_NC(import_from_3, or(3), tok(OP_STAR), rule(import_as_names_paren), rule(import_as_names))\nDEF_RULE_NC(import_as_names_paren, and_ident(3), tok(DEL_PAREN_OPEN), rule(import_as_names), tok(DEL_PAREN_CLOSE))\nDEF_RULE_NC(one_or_more_period_or_ellipsis, one_or_more, rule(period_or_ellipsis))\nDEF_RULE_NC(period_or_ellipsis, or(2), tok(DEL_PERIOD), tok(ELLIPSIS))\nDEF_RULE_NC(import_as_name, and(2), tok(NAME), opt_rule(as_name))\nDEF_RULE_NC(dotted_as_name, and_ident(2), rule(dotted_name), opt_rule(as_name))\nDEF_RULE_NC(as_name, and_ident(2), tok(KW_AS), tok(NAME))\nDEF_RULE_NC(import_as_names, list_with_end, rule(import_as_name), tok(DEL_COMMA))\nDEF_RULE_NC(dotted_as_names, list, rule(dotted_as_name), tok(DEL_COMMA))\nDEF_RULE_NC(dotted_name, list, tok(NAME), tok(DEL_PERIOD))\nDEF_RULE(global_stmt, c(global_nonlocal_stmt), and(2), tok(KW_GLOBAL), rule(name_list))\nDEF_RULE(nonlocal_stmt, c(global_nonlocal_stmt), and(2), tok(KW_NONLOCAL), rule(name_list))\nDEF_RULE_NC(name_list, list, tok(NAME), tok(DEL_COMMA))\nDEF_RULE(assert_stmt, c(assert_stmt), and(3), tok(KW_ASSERT), rule(test), opt_rule(assert_stmt_extra))\nDEF_RULE_NC(assert_stmt_extra, and_ident(2), tok(DEL_COMMA), rule(test))\n\n// compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt\n// if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]\n// while_stmt: 'while' test ':' suite ['else' ':' suite]\n// for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]\n// try_stmt: 'try' ':' suite ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite] | 'finally' ':' suite)\n// # NB compile.c makes sure that the default except clause is last\n// except_clause: 'except' [test ['as' NAME]]\n// with_stmt: 'with' with_item (',' with_item)* ':' suite\n// with_item: test ['as' expr]\n// suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT\n// async_stmt: 'async' (funcdef | with_stmt | for_stmt)\n\n#if MICROPY_PY_ASYNC_AWAIT\nDEF_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))\nDEF_RULE(async_stmt, c(async_stmt), and(2), tok(KW_ASYNC), rule(async_stmt_2))\nDEF_RULE_NC(async_stmt_2, or(3), rule(funcdef), rule(with_stmt), rule(for_stmt))\n#else\nDEF_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))\n#endif\nDEF_RULE(if_stmt, c(if_stmt), and(6), tok(KW_IF), rule(namedexpr_test), tok(DEL_COLON), rule(suite), opt_rule(if_stmt_elif_list), opt_rule(else_stmt))\nDEF_RULE_NC(if_stmt_elif_list, one_or_more, rule(if_stmt_elif))\nDEF_RULE_NC(if_stmt_elif, and(4), tok(KW_ELIF), rule(namedexpr_test), tok(DEL_COLON), rule(suite))\nDEF_RULE(while_stmt, c(while_stmt), and(5), tok(KW_WHILE), rule(namedexpr_test), tok(DEL_COLON), rule(suite), opt_rule(else_stmt))\nDEF_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))\nDEF_RULE(try_stmt, c(try_stmt), and(4), tok(KW_TRY), tok(DEL_COLON), rule(suite), rule(try_stmt_2))\nDEF_RULE_NC(try_stmt_2, or(2), rule(try_stmt_except_and_more), rule(try_stmt_finally))\nDEF_RULE_NC(try_stmt_except_and_more, and_ident(3), rule(try_stmt_except_list), opt_rule(else_stmt), opt_rule(try_stmt_finally))\nDEF_RULE_NC(try_stmt_except, and(4), tok(KW_EXCEPT), opt_rule(try_stmt_as_name), tok(DEL_COLON), rule(suite))\nDEF_RULE_NC(try_stmt_as_name, and_ident(2), rule(test), opt_rule(as_name))\nDEF_RULE_NC(try_stmt_except_list, one_or_more, rule(try_stmt_except))\nDEF_RULE_NC(try_stmt_finally, and(3), tok(KW_FINALLY), tok(DEL_COLON), rule(suite))\nDEF_RULE_NC(else_stmt, and_ident(3), tok(KW_ELSE), tok(DEL_COLON), rule(suite))\nDEF_RULE(with_stmt, c(with_stmt), and(4), tok(KW_WITH), rule(with_stmt_list), tok(DEL_COLON), rule(suite))\nDEF_RULE_NC(with_stmt_list, list, rule(with_item), tok(DEL_COMMA))\nDEF_RULE_NC(with_item, and_ident(2), rule(test), opt_rule(with_item_as))\nDEF_RULE_NC(with_item_as, and_ident(2), tok(KW_AS), rule(expr))\nDEF_RULE_NC(suite, or(2), rule(suite_block), rule(simple_stmt))\nDEF_RULE_NC(suite_block, and_ident(4), tok(NEWLINE), tok(INDENT), rule(suite_block_stmts), tok(DEDENT))\nDEF_RULE(suite_block_stmts, c(generic_all_nodes), one_or_more, rule(stmt))\n\n// test: or_test ['if' or_test 'else' test] | lambdef\n// test_nocond: or_test | lambdef_nocond\n// lambdef: 'lambda' [varargslist] ':' test\n// lambdef_nocond: 'lambda' [varargslist] ':' test_nocond\n\n#if MICROPY_PY_ASSIGN_EXPR\nDEF_RULE(namedexpr_test, c(namedexpr), and_ident(2), rule(test), opt_rule(namedexpr_test_2))\nDEF_RULE_NC(namedexpr_test_2, and_ident(2), tok(OP_ASSIGN), rule(test))\n#else\nDEF_RULE_NC(namedexpr_test, or(1), rule(test))\n#endif\nDEF_RULE_NC(test, or(2), rule(lambdef), rule(test_if_expr))\nDEF_RULE(test_if_expr, c(test_if_expr), and_ident(2), rule(or_test), opt_rule(test_if_else))\nDEF_RULE_NC(test_if_else, and(4), tok(KW_IF), rule(or_test), tok(KW_ELSE), rule(test))\nDEF_RULE_NC(test_nocond, or(2), rule(lambdef_nocond), rule(or_test))\nDEF_RULE(lambdef, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(varargslist), tok(DEL_COLON), rule(test))\nDEF_RULE(lambdef_nocond, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(varargslist), tok(DEL_COLON), rule(test_nocond))\n\n// or_test: and_test ('or' and_test)*\n// and_test: not_test ('and' not_test)*\n// not_test: 'not' not_test | comparison\n// comparison: expr (comp_op expr)*\n// comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'in'|'not' 'in'|'is'|'is' 'not'\n// star_expr: '*' expr\n// expr: xor_expr ('|' xor_expr)*\n// xor_expr: and_expr ('^' and_expr)*\n// and_expr: shift_expr ('&' shift_expr)*\n// shift_expr: arith_expr (('<<'|'>>') arith_expr)*\n// arith_expr: term (('+'|'-') term)*\n// term: factor (('*'|'@'|'/'|'%'|'//') factor)*\n// factor: ('+'|'-'|'~') factor | power\n// power: atom_expr ['**' factor]\n// atom_expr: 'await' atom trailer* | atom trailer*\n\nDEF_RULE(or_test, c(or_and_test), list, rule(and_test), tok(KW_OR))\nDEF_RULE(and_test, c(or_and_test), list, rule(not_test), tok(KW_AND))\nDEF_RULE_NC(not_test, or(2), rule(not_test_2), rule(comparison))\nDEF_RULE(not_test_2, c(not_test_2), and(2), tok(KW_NOT), rule(not_test))\nDEF_RULE(comparison, c(comparison), list, rule(expr), rule(comp_op))\nDEF_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))\nDEF_RULE_NC(comp_op_not_in, and(2), tok(KW_NOT), tok(KW_IN))\nDEF_RULE_NC(comp_op_is, and(2), tok(KW_IS), opt_rule(comp_op_is_not))\nDEF_RULE_NC(comp_op_is_not, and(1), tok(KW_NOT))\nDEF_RULE(star_expr, c(star_expr), and(2), tok(OP_STAR), rule(expr))\nDEF_RULE(expr, c(binary_op), list, rule(xor_expr), tok(OP_PIPE))\nDEF_RULE(xor_expr, c(binary_op), list, rule(and_expr), tok(OP_CARET))\nDEF_RULE(and_expr, c(binary_op), list, rule(shift_expr), tok(OP_AMPERSAND))\nDEF_RULE(shift_expr, c(term), list, rule(arith_expr), rule(shift_op))\nDEF_RULE_NC(shift_op, or(2), tok(OP_DBL_LESS), tok(OP_DBL_MORE))\nDEF_RULE(arith_expr, c(term), list, rule(term), rule(arith_op))\nDEF_RULE_NC(arith_op, or(2), tok(OP_PLUS), tok(OP_MINUS))\nDEF_RULE(term, c(term), list, rule(factor), rule(term_op))\nDEF_RULE_NC(term_op, or(5), tok(OP_STAR), tok(OP_AT), tok(OP_SLASH), tok(OP_PERCENT), tok(OP_DBL_SLASH))\nDEF_RULE_NC(factor, or(2), rule(factor_2), rule(power))\nDEF_RULE(factor_2, c(factor_2), and_ident(2), rule(factor_op), rule(factor))\nDEF_RULE_NC(factor_op, or(3), tok(OP_PLUS), tok(OP_MINUS), tok(OP_TILDE))\nDEF_RULE(power, c(power), and_ident(2), rule(atom_expr), opt_rule(power_dbl_star))\n#if MICROPY_PY_ASYNC_AWAIT\nDEF_RULE_NC(atom_expr, or(2), rule(atom_expr_await), rule(atom_expr_normal))\nDEF_RULE(atom_expr_await, c(atom_expr_await), and(3), tok(KW_AWAIT), rule(atom), opt_rule(atom_expr_trailers))\n#else\nDEF_RULE_NC(atom_expr, or(1), rule(atom_expr_normal))\n#endif\nDEF_RULE(atom_expr_normal, c(atom_expr_normal), and_ident(2), rule(atom), opt_rule(atom_expr_trailers))\nDEF_RULE_NC(atom_expr_trailers, one_or_more, rule(trailer))\nDEF_RULE_NC(power_dbl_star, and_ident(2), tok(OP_DBL_STAR), rule(factor))\n\n// atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False'\n// testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )\n// trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME\n\nDEF_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))\nDEF_RULE(atom_paren, c(atom_paren), and(3), tok(DEL_PAREN_OPEN), opt_rule(atom_2b), tok(DEL_PAREN_CLOSE))\nDEF_RULE_NC(atom_2b, or(2), rule(yield_expr), rule(testlist_comp))\nDEF_RULE(atom_bracket, c(atom_bracket), and(3), tok(DEL_BRACKET_OPEN), opt_rule(testlist_comp), tok(DEL_BRACKET_CLOSE))\nDEF_RULE(atom_brace, c(atom_brace), and(3), tok(DEL_BRACE_OPEN), opt_rule(dictorsetmaker), tok(DEL_BRACE_CLOSE))\nDEF_RULE_NC(testlist_comp, and_ident(2), rule(testlist_comp_2), opt_rule(testlist_comp_3))\nDEF_RULE_NC(testlist_comp_2, or(2), rule(star_expr), rule(namedexpr_test))\nDEF_RULE_NC(testlist_comp_3, or(2), rule(comp_for), rule(testlist_comp_3b))\nDEF_RULE_NC(testlist_comp_3b, and_ident(2), tok(DEL_COMMA), opt_rule(testlist_comp_3c))\nDEF_RULE_NC(testlist_comp_3c, list_with_end, rule(testlist_comp_2), tok(DEL_COMMA))\nDEF_RULE_NC(trailer, or(3), rule(trailer_paren), rule(trailer_bracket), rule(trailer_period))\nDEF_RULE(trailer_paren, c(trailer_paren), and(3), tok(DEL_PAREN_OPEN), opt_rule(arglist), tok(DEL_PAREN_CLOSE))\nDEF_RULE(trailer_bracket, c(trailer_bracket), and(3), tok(DEL_BRACKET_OPEN), rule(subscriptlist), tok(DEL_BRACKET_CLOSE))\nDEF_RULE(trailer_period, c(trailer_period), and(2), tok(DEL_PERIOD), tok(NAME))\n\n// subscriptlist: subscript (',' subscript)* [',']\n// subscript: test | [test] ':' [test] [sliceop]\n// sliceop: ':' [test]\n\n#if MICROPY_PY_BUILTINS_SLICE\nDEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(subscript), tok(DEL_COMMA))\nDEF_RULE_NC(subscript, or(2), rule(subscript_3), rule(subscript_2))\nDEF_RULE(subscript_2, c(subscript), and_ident(2), rule(test), opt_rule(subscript_3))\nDEF_RULE(subscript_3, c(subscript), and(2), tok(DEL_COLON), opt_rule(subscript_3b))\nDEF_RULE_NC(subscript_3b, or(2), rule(subscript_3c), rule(subscript_3d))\nDEF_RULE_NC(subscript_3c, and(2), tok(DEL_COLON), opt_rule(test))\nDEF_RULE_NC(subscript_3d, and_ident(2), rule(test), opt_rule(sliceop))\nDEF_RULE_NC(sliceop, and(2), tok(DEL_COLON), opt_rule(test))\n#else\nDEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(test), tok(DEL_COMMA))\n#endif\n\n// exprlist: (expr|star_expr) (',' (expr|star_expr))* [',']\n// testlist: test (',' test)* [',']\n// dictorsetmaker: (test ':' test (comp_for | (',' test ':' test)* [','])) | (test (comp_for | (',' test)* [',']))\n\nDEF_RULE_NC(exprlist, list_with_end, rule(exprlist_2), tok(DEL_COMMA))\nDEF_RULE_NC(exprlist_2, or(2), rule(star_expr), rule(expr))\nDEF_RULE(testlist, c(generic_tuple), list_with_end, rule(test), tok(DEL_COMMA))\n// TODO dictorsetmaker lets through more than is allowed\nDEF_RULE_NC(dictorsetmaker, and_ident(2), rule(dictorsetmaker_item), opt_rule(dictorsetmaker_tail))\n#if MICROPY_PY_BUILTINS_SET\nDEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and_ident(2), rule(test), opt_rule(generic_colon_test))\n#else\nDEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and(3), rule(test), tok(DEL_COLON), rule(test))\n#endif\nDEF_RULE_NC(dictorsetmaker_tail, or(2), rule(comp_for), rule(dictorsetmaker_list))\nDEF_RULE_NC(dictorsetmaker_list, and(2), tok(DEL_COMMA), opt_rule(dictorsetmaker_list2))\nDEF_RULE_NC(dictorsetmaker_list2, list_with_end, rule(dictorsetmaker_item), tok(DEL_COMMA))\n\n// classdef: 'class' NAME ['(' [arglist] ')'] ':' suite\n\nDEF_RULE(classdef, c(classdef), and_blank(5), tok(KW_CLASS), tok(NAME), opt_rule(classdef_2), tok(DEL_COLON), rule(suite))\nDEF_RULE_NC(classdef_2, and_ident(3), tok(DEL_PAREN_OPEN), opt_rule(arglist), tok(DEL_PAREN_CLOSE))\n\n// arglist: (argument ',')* (argument [','] | '*' test (',' argument)* [',' '**' test] | '**' test)\n\n// TODO arglist lets through more than is allowed, compiler needs to do further verification\nDEF_RULE_NC(arglist, list_with_end, rule(arglist_2), tok(DEL_COMMA))\nDEF_RULE_NC(arglist_2, or(3), rule(arglist_star), rule(arglist_dbl_star), rule(argument))\nDEF_RULE_NC(arglist_star, and(2), tok(OP_STAR), rule(test))\nDEF_RULE_NC(arglist_dbl_star, and(2), tok(OP_DBL_STAR), rule(test))\n\n// # The reason that keywords are test nodes instead of NAME is that using NAME\n// # results in an ambiguity. ast.c makes sure it's a NAME.\n// argument: test [comp_for] | test '=' test  # Really [keyword '='] test\n// comp_iter: comp_for | comp_if\n// comp_for: 'for' exprlist 'in' or_test [comp_iter]\n// comp_if: 'if' test_nocond [comp_iter]\n\nDEF_RULE_NC(argument, and_ident(2), rule(test), opt_rule(argument_2))\n#if MICROPY_PY_ASSIGN_EXPR\nDEF_RULE_NC(argument_2, or(3), rule(comp_for), rule(generic_equal_test), rule(argument_3))\nDEF_RULE_NC(argument_3, and(2), tok(OP_ASSIGN), rule(test))\n#else\nDEF_RULE_NC(argument_2, or(2), rule(comp_for), rule(generic_equal_test))\n#endif\nDEF_RULE_NC(comp_iter, or(2), rule(comp_for), rule(comp_if))\nDEF_RULE_NC(comp_for, and_blank(5), tok(KW_FOR), rule(exprlist), tok(KW_IN), rule(or_test), opt_rule(comp_iter))\nDEF_RULE_NC(comp_if, and(3), tok(KW_IF), rule(test_nocond), opt_rule(comp_iter))\n\n// # not used in grammar, but may appear in \"node\" passed from Parser to Compiler\n// encoding_decl: NAME\n\n// yield_expr: 'yield' [yield_arg]\n// yield_arg: 'from' test | testlist\n\nDEF_RULE(yield_expr, c(yield_expr), and(2), tok(KW_YIELD), opt_rule(yield_arg))\nDEF_RULE_NC(yield_arg, or(2), rule(yield_arg_from), rule(testlist))\nDEF_RULE_NC(yield_arg_from, and(2), tok(KW_FROM), rule(test))\n"
  },
  {
    "path": "py/lexer.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/reader.h\"\n#include \"py/lexer.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_ENABLE_COMPILER\n\n#define TAB_SIZE (8)\n\n// TODO seems that CPython allows NULL byte in the input stream\n// don't know if that's intentional or not, but we don't allow it\n\n#define MP_LEXER_EOF ((unichar)MP_READER_EOF)\n#define CUR_CHAR(lex) ((lex)->chr0)\n\nSTATIC bool is_end(mp_lexer_t *lex) {\n    return lex->chr0 == MP_LEXER_EOF;\n}\n\nSTATIC bool is_physical_newline(mp_lexer_t *lex) {\n    return lex->chr0 == '\\n';\n}\n\nSTATIC bool is_char(mp_lexer_t *lex, byte c) {\n    return lex->chr0 == c;\n}\n\nSTATIC bool is_char_or(mp_lexer_t *lex, byte c1, byte c2) {\n    return lex->chr0 == c1 || lex->chr0 == c2;\n}\n\nSTATIC bool is_char_or3(mp_lexer_t *lex, byte c1, byte c2, byte c3) {\n    return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3;\n}\n\nSTATIC bool is_char_following(mp_lexer_t *lex, byte c) {\n    return lex->chr1 == c;\n}\n\nSTATIC bool is_char_following_or(mp_lexer_t *lex, byte c1, byte c2) {\n    return lex->chr1 == c1 || lex->chr1 == c2;\n}\n\nSTATIC bool is_char_following_following_or(mp_lexer_t *lex, byte c1, byte c2) {\n    return lex->chr2 == c1 || lex->chr2 == c2;\n}\n\nSTATIC bool is_char_and(mp_lexer_t *lex, byte c1, byte c2) {\n    return lex->chr0 == c1 && lex->chr1 == c2;\n}\n\nSTATIC bool is_whitespace(mp_lexer_t *lex) {\n    return unichar_isspace(lex->chr0);\n}\n\nSTATIC bool is_letter(mp_lexer_t *lex) {\n    return unichar_isalpha(lex->chr0);\n}\n\nSTATIC bool is_digit(mp_lexer_t *lex) {\n    return unichar_isdigit(lex->chr0);\n}\n\nSTATIC bool is_following_digit(mp_lexer_t *lex) {\n    return unichar_isdigit(lex->chr1);\n}\n\nSTATIC bool is_following_base_char(mp_lexer_t *lex) {\n    const unichar chr1 = lex->chr1 | 0x20;\n    return chr1 == 'b' || chr1 == 'o' || chr1 == 'x';\n}\n\nSTATIC bool is_following_odigit(mp_lexer_t *lex) {\n    return lex->chr1 >= '0' && lex->chr1 <= '7';\n}\n\nSTATIC bool is_string_or_bytes(mp_lexer_t *lex) {\n    return is_char_or(lex, '\\'', '\\\"')\n           || (is_char_or3(lex, 'r', 'u', 'b') && is_char_following_or(lex, '\\'', '\\\"'))\n           || ((is_char_and(lex, 'r', 'b') || is_char_and(lex, 'b', 'r'))\n               && is_char_following_following_or(lex, '\\'', '\\\"'));\n}\n\n// to easily parse utf-8 identifiers we allow any raw byte with high bit set\nSTATIC bool is_head_of_identifier(mp_lexer_t *lex) {\n    return is_letter(lex) || lex->chr0 == '_' || lex->chr0 >= 0x80;\n}\n\nSTATIC bool is_tail_of_identifier(mp_lexer_t *lex) {\n    return is_head_of_identifier(lex) || is_digit(lex);\n}\n\nSTATIC void next_char(mp_lexer_t *lex) {\n    if (lex->chr0 == '\\n') {\n        // a new line\n        ++lex->line;\n        lex->column = 1;\n    } else if (lex->chr0 == '\\t') {\n        // a tab\n        lex->column = (((lex->column - 1 + TAB_SIZE) / TAB_SIZE) * TAB_SIZE) + 1;\n    } else {\n        // a character worth one column\n        ++lex->column;\n    }\n\n    lex->chr0 = lex->chr1;\n    lex->chr1 = lex->chr2;\n    lex->chr2 = lex->reader.readbyte(lex->reader.data);\n\n    if (lex->chr1 == '\\r') {\n        // CR is a new line, converted to LF\n        lex->chr1 = '\\n';\n        if (lex->chr2 == '\\n') {\n            // CR LF is a single new line, throw out the extra LF\n            lex->chr2 = lex->reader.readbyte(lex->reader.data);\n        }\n    }\n\n    // check if we need to insert a newline at end of file\n    if (lex->chr2 == MP_LEXER_EOF && lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\\n') {\n        lex->chr2 = '\\n';\n    }\n}\n\nSTATIC void indent_push(mp_lexer_t *lex, size_t indent) {\n    if (lex->num_indent_level >= lex->alloc_indent_level) {\n        lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MICROPY_ALLOC_LEXEL_INDENT_INC);\n        lex->alloc_indent_level += MICROPY_ALLOC_LEXEL_INDENT_INC;\n    }\n    lex->indent_level[lex->num_indent_level++] = indent;\n}\n\nSTATIC size_t indent_top(mp_lexer_t *lex) {\n    return lex->indent_level[lex->num_indent_level - 1];\n}\n\nSTATIC void indent_pop(mp_lexer_t *lex) {\n    lex->num_indent_level -= 1;\n}\n\n// some tricky operator encoding:\n//     <op>  = begin with <op>, if this opchar matches then begin here\n//     e<op> = end with <op>, if this opchar matches then end\n//     c<op> = continue with <op>, if this opchar matches then continue matching\n// this means if the start of two ops are the same then they are equal til the last char\n\nSTATIC const char *const tok_enc =\n    \"()[]{},;~\"   // singles\n    \":e=\"         // : :=\n    \"<e=c<e=\"     // < <= << <<=\n    \">e=c>e=\"     // > >= >> >>=\n    \"*e=c*e=\"     // * *= ** **=\n    \"+e=\"         // + +=\n    \"-e=e>\"       // - -= ->\n    \"&e=\"         // & &=\n    \"|e=\"         // | |=\n    \"/e=c/e=\"     // / /= // //=\n    \"%e=\"         // % %=\n    \"^e=\"         // ^ ^=\n    \"@e=\"         // @ @=\n    \"=e=\"         // = ==\n    \"!.\";         // start of special cases: != . ...\n\n// TODO static assert that number of tokens is less than 256 so we can safely make this table with byte sized entries\nSTATIC const uint8_t tok_enc_kind[] = {\n    MP_TOKEN_DEL_PAREN_OPEN, MP_TOKEN_DEL_PAREN_CLOSE,\n    MP_TOKEN_DEL_BRACKET_OPEN, MP_TOKEN_DEL_BRACKET_CLOSE,\n    MP_TOKEN_DEL_BRACE_OPEN, MP_TOKEN_DEL_BRACE_CLOSE,\n    MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_OP_TILDE,\n\n    MP_TOKEN_DEL_COLON, MP_TOKEN_OP_ASSIGN,\n    MP_TOKEN_OP_LESS, MP_TOKEN_OP_LESS_EQUAL, MP_TOKEN_OP_DBL_LESS, MP_TOKEN_DEL_DBL_LESS_EQUAL,\n    MP_TOKEN_OP_MORE, MP_TOKEN_OP_MORE_EQUAL, MP_TOKEN_OP_DBL_MORE, MP_TOKEN_DEL_DBL_MORE_EQUAL,\n    MP_TOKEN_OP_STAR, MP_TOKEN_DEL_STAR_EQUAL, MP_TOKEN_OP_DBL_STAR, MP_TOKEN_DEL_DBL_STAR_EQUAL,\n    MP_TOKEN_OP_PLUS, MP_TOKEN_DEL_PLUS_EQUAL,\n    MP_TOKEN_OP_MINUS, MP_TOKEN_DEL_MINUS_EQUAL, MP_TOKEN_DEL_MINUS_MORE,\n    MP_TOKEN_OP_AMPERSAND, MP_TOKEN_DEL_AMPERSAND_EQUAL,\n    MP_TOKEN_OP_PIPE, MP_TOKEN_DEL_PIPE_EQUAL,\n    MP_TOKEN_OP_SLASH, MP_TOKEN_DEL_SLASH_EQUAL, MP_TOKEN_OP_DBL_SLASH, MP_TOKEN_DEL_DBL_SLASH_EQUAL,\n    MP_TOKEN_OP_PERCENT, MP_TOKEN_DEL_PERCENT_EQUAL,\n    MP_TOKEN_OP_CARET, MP_TOKEN_DEL_CARET_EQUAL,\n    MP_TOKEN_OP_AT, MP_TOKEN_DEL_AT_EQUAL,\n    MP_TOKEN_DEL_EQUAL, MP_TOKEN_OP_DBL_EQUAL,\n};\n\n// must have the same order as enum in lexer.h\n// must be sorted according to strcmp\nSTATIC const char *const tok_kw[] = {\n    \"False\",\n    \"None\",\n    \"True\",\n    \"__debug__\",\n    \"and\",\n    \"as\",\n    \"assert\",\n    #if MICROPY_PY_ASYNC_AWAIT\n    \"async\",\n    \"await\",\n    #endif\n    \"break\",\n    \"class\",\n    \"continue\",\n    \"def\",\n    \"del\",\n    \"elif\",\n    \"else\",\n    \"except\",\n    \"finally\",\n    \"for\",\n    \"from\",\n    \"global\",\n    \"if\",\n    \"import\",\n    \"in\",\n    \"is\",\n    \"lambda\",\n    \"nonlocal\",\n    \"not\",\n    \"or\",\n    \"pass\",\n    \"raise\",\n    \"return\",\n    \"try\",\n    \"while\",\n    \"with\",\n    \"yield\",\n};\n\n// This is called with CUR_CHAR() before first hex digit, and should return with\n// it pointing to last hex digit\n// num_digits must be greater than zero\nSTATIC bool get_hex(mp_lexer_t *lex, size_t num_digits, mp_uint_t *result) {\n    mp_uint_t num = 0;\n    while (num_digits-- != 0) {\n        next_char(lex);\n        unichar c = CUR_CHAR(lex);\n        if (!unichar_isxdigit(c)) {\n            return false;\n        }\n        num = (num << 4) + unichar_xdigit_value(c);\n    }\n    *result = num;\n    return true;\n}\n\nSTATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) {\n    // get first quoting character\n    char quote_char = '\\'';\n    if (is_char(lex, '\\\"')) {\n        quote_char = '\\\"';\n    }\n    next_char(lex);\n\n    // work out if it's a single or triple quoted literal\n    size_t num_quotes;\n    if (is_char_and(lex, quote_char, quote_char)) {\n        // triple quotes\n        next_char(lex);\n        next_char(lex);\n        num_quotes = 3;\n    } else {\n        // single quotes\n        num_quotes = 1;\n    }\n\n    size_t n_closing = 0;\n    while (!is_end(lex) && (num_quotes > 1 || !is_char(lex, '\\n')) && n_closing < num_quotes) {\n        if (is_char(lex, quote_char)) {\n            n_closing += 1;\n            vstr_add_char(&lex->vstr, CUR_CHAR(lex));\n        } else {\n            n_closing = 0;\n            if (is_char(lex, '\\\\')) {\n                next_char(lex);\n                unichar c = CUR_CHAR(lex);\n                if (is_raw) {\n                    // raw strings allow escaping of quotes, but the backslash is also emitted\n                    vstr_add_char(&lex->vstr, '\\\\');\n                } else {\n                    switch (c) {\n                        // note: \"c\" can never be MP_LEXER_EOF because next_char\n                        // always inserts a newline at the end of the input stream\n                        case '\\n':\n                            c = MP_LEXER_EOF;\n                            break;                          // backslash escape the newline, just ignore it\n                        case '\\\\':\n                            break;\n                        case '\\'':\n                            break;\n                        case '\"':\n                            break;\n                        case 'a':\n                            c = 0x07;\n                            break;\n                        case 'b':\n                            c = 0x08;\n                            break;\n                        case 't':\n                            c = 0x09;\n                            break;\n                        case 'n':\n                            c = 0x0a;\n                            break;\n                        case 'v':\n                            c = 0x0b;\n                            break;\n                        case 'f':\n                            c = 0x0c;\n                            break;\n                        case 'r':\n                            c = 0x0d;\n                            break;\n                        case 'u':\n                        case 'U':\n                            if (lex->tok_kind == MP_TOKEN_BYTES) {\n                                // b'\\u1234' == b'\\\\u1234'\n                                vstr_add_char(&lex->vstr, '\\\\');\n                                break;\n                            }\n                            // Otherwise fall through.\n                            MP_FALLTHROUGH\n                        case 'x': {\n                            mp_uint_t num = 0;\n                            if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) {\n                                // not enough hex chars for escape sequence\n                                lex->tok_kind = MP_TOKEN_INVALID;\n                            }\n                            c = num;\n                            break;\n                        }\n                        case 'N':\n                            // Supporting '\\N{LATIN SMALL LETTER A}' == 'a' would require keeping the\n                            // entire Unicode name table in the core. As of Unicode 6.3.0, that's nearly\n                            // 3MB of text; even gzip-compressed and with minimal structure, it'll take\n                            // roughly half a meg of storage. This form of Unicode escape may be added\n                            // later on, but it's definitely not a priority right now. -- CJA 20140607\n                            mp_raise_NotImplementedError(MP_ERROR_TEXT(\"unicode name escapes\"));\n                            break;\n                        default:\n                            if (c >= '0' && c <= '7') {\n                                // Octal sequence, 1-3 chars\n                                size_t digits = 3;\n                                mp_uint_t num = c - '0';\n                                while (is_following_odigit(lex) && --digits != 0) {\n                                    next_char(lex);\n                                    num = num * 8 + (CUR_CHAR(lex) - '0');\n                                }\n                                c = num;\n                            } else {\n                                // unrecognised escape character; CPython lets this through verbatim as '\\' and then the character\n                                vstr_add_char(&lex->vstr, '\\\\');\n                            }\n                            break;\n                    }\n                }\n                if (c != MP_LEXER_EOF) {\n                    if (MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) {\n                        if (c < 0x110000 && lex->tok_kind == MP_TOKEN_STRING) {\n                            vstr_add_char(&lex->vstr, c);\n                        } else if (c < 0x100 && lex->tok_kind == MP_TOKEN_BYTES) {\n                            vstr_add_byte(&lex->vstr, c);\n                        } else {\n                            // unicode character out of range\n                            // this raises a generic SyntaxError; could provide more info\n                            lex->tok_kind = MP_TOKEN_INVALID;\n                        }\n                    } else {\n                        // without unicode everything is just added as an 8-bit byte\n                        if (c < 0x100) {\n                            vstr_add_byte(&lex->vstr, c);\n                        } else {\n                            // 8-bit character out of range\n                            // this raises a generic SyntaxError; could provide more info\n                            lex->tok_kind = MP_TOKEN_INVALID;\n                        }\n                    }\n                }\n            } else {\n                // Add the \"character\" as a byte so that we remain 8-bit clean.\n                // This way, strings are parsed correctly whether or not they contain utf-8 chars.\n                vstr_add_byte(&lex->vstr, CUR_CHAR(lex));\n            }\n        }\n        next_char(lex);\n    }\n\n    // check we got the required end quotes\n    if (n_closing < num_quotes) {\n        lex->tok_kind = MP_TOKEN_LONELY_STRING_OPEN;\n    }\n\n    // cut off the end quotes from the token text\n    vstr_cut_tail_bytes(&lex->vstr, n_closing);\n}\n\nSTATIC bool skip_whitespace(mp_lexer_t *lex, bool stop_at_newline) {\n    bool had_physical_newline = false;\n    while (!is_end(lex)) {\n        if (is_physical_newline(lex)) {\n            if (stop_at_newline && lex->nested_bracket_level == 0) {\n                break;\n            }\n            had_physical_newline = true;\n            next_char(lex);\n        } else if (is_whitespace(lex)) {\n            next_char(lex);\n        } else if (is_char(lex, '#')) {\n            next_char(lex);\n            while (!is_end(lex) && !is_physical_newline(lex)) {\n                next_char(lex);\n            }\n            // had_physical_newline will be set on next loop\n        } else if (is_char_and(lex, '\\\\', '\\n')) {\n            // line-continuation, so don't set had_physical_newline\n            next_char(lex);\n            next_char(lex);\n        } else {\n            break;\n        }\n    }\n    return had_physical_newline;\n}\n\nvoid mp_lexer_to_next(mp_lexer_t *lex) {\n    // start new token text\n    vstr_reset(&lex->vstr);\n\n    // skip white space and comments\n    bool had_physical_newline = skip_whitespace(lex, false);\n\n    // set token source information\n    lex->tok_line = lex->line;\n    lex->tok_column = lex->column;\n\n    if (lex->emit_dent < 0) {\n        lex->tok_kind = MP_TOKEN_DEDENT;\n        lex->emit_dent += 1;\n\n    } else if (lex->emit_dent > 0) {\n        lex->tok_kind = MP_TOKEN_INDENT;\n        lex->emit_dent -= 1;\n\n    } else if (had_physical_newline && lex->nested_bracket_level == 0) {\n        lex->tok_kind = MP_TOKEN_NEWLINE;\n\n        size_t num_spaces = lex->column - 1;\n        if (num_spaces == indent_top(lex)) {\n        } else if (num_spaces > indent_top(lex)) {\n            indent_push(lex, num_spaces);\n            lex->emit_dent += 1;\n        } else {\n            while (num_spaces < indent_top(lex)) {\n                indent_pop(lex);\n                lex->emit_dent -= 1;\n            }\n            if (num_spaces != indent_top(lex)) {\n                lex->tok_kind = MP_TOKEN_DEDENT_MISMATCH;\n            }\n        }\n\n    } else if (is_end(lex)) {\n        lex->tok_kind = MP_TOKEN_END;\n\n    } else if (is_string_or_bytes(lex)) {\n        // a string or bytes literal\n\n        // Python requires adjacent string/bytes literals to be automatically\n        // concatenated.  We do it here in the tokeniser to make efficient use of RAM,\n        // because then the lexer's vstr can be used to accumulate the string literal,\n        // in contrast to creating a parse tree of strings and then joining them later\n        // in the compiler.  It's also more compact in code size to do it here.\n\n        // MP_TOKEN_END is used to indicate that this is the first string token\n        lex->tok_kind = MP_TOKEN_END;\n\n        // Loop to accumulate string/bytes literals\n        do {\n            // parse type codes\n            bool is_raw = false;\n            mp_token_kind_t kind = MP_TOKEN_STRING;\n            int n_char = 0;\n            if (is_char(lex, 'u')) {\n                n_char = 1;\n            } else if (is_char(lex, 'b')) {\n                kind = MP_TOKEN_BYTES;\n                n_char = 1;\n                if (is_char_following(lex, 'r')) {\n                    is_raw = true;\n                    n_char = 2;\n                }\n            } else if (is_char(lex, 'r')) {\n                is_raw = true;\n                n_char = 1;\n                if (is_char_following(lex, 'b')) {\n                    kind = MP_TOKEN_BYTES;\n                    n_char = 2;\n                }\n            }\n\n            // Set or check token kind\n            if (lex->tok_kind == MP_TOKEN_END) {\n                lex->tok_kind = kind;\n            } else if (lex->tok_kind != kind) {\n                // Can't concatenate string with bytes\n                break;\n            }\n\n            // Skip any type code characters\n            if (n_char != 0) {\n                next_char(lex);\n                if (n_char == 2) {\n                    next_char(lex);\n                }\n            }\n\n            // Parse the literal\n            parse_string_literal(lex, is_raw);\n\n            // Skip whitespace so we can check if there's another string following\n            skip_whitespace(lex, true);\n\n        } while (is_string_or_bytes(lex));\n\n    } else if (is_head_of_identifier(lex)) {\n        lex->tok_kind = MP_TOKEN_NAME;\n\n        // get first char (add as byte to remain 8-bit clean and support utf-8)\n        vstr_add_byte(&lex->vstr, CUR_CHAR(lex));\n        next_char(lex);\n\n        // get tail chars\n        while (!is_end(lex) && is_tail_of_identifier(lex)) {\n            vstr_add_byte(&lex->vstr, CUR_CHAR(lex));\n            next_char(lex);\n        }\n\n        // Check if the name is a keyword.\n        // We also check for __debug__ here and convert it to its value.  This is\n        // so the parser gives a syntax error on, eg, x.__debug__.  Otherwise, we\n        // need to check for this special token in many places in the compiler.\n        const char *s = vstr_null_terminated_str(&lex->vstr);\n        for (size_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) {\n            int cmp = strcmp(s, tok_kw[i]);\n            if (cmp == 0) {\n                lex->tok_kind = MP_TOKEN_KW_FALSE + i;\n                if (lex->tok_kind == MP_TOKEN_KW___DEBUG__) {\n                    lex->tok_kind = (MP_STATE_VM(mp_optimise_value) == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE);\n                }\n                break;\n            } else if (cmp < 0) {\n                // Table is sorted and comparison was less-than, so stop searching\n                break;\n            }\n        }\n\n    } else if (is_digit(lex) || (is_char(lex, '.') && is_following_digit(lex))) {\n        bool forced_integer = false;\n        if (is_char(lex, '.')) {\n            lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG;\n        } else {\n            lex->tok_kind = MP_TOKEN_INTEGER;\n            if (is_char(lex, '0') && is_following_base_char(lex)) {\n                forced_integer = true;\n            }\n        }\n\n        // get first char\n        vstr_add_char(&lex->vstr, CUR_CHAR(lex));\n        next_char(lex);\n\n        // get tail chars\n        while (!is_end(lex)) {\n            if (!forced_integer && is_char_or(lex, 'e', 'E')) {\n                lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG;\n                vstr_add_char(&lex->vstr, 'e');\n                next_char(lex);\n                if (is_char(lex, '+') || is_char(lex, '-')) {\n                    vstr_add_char(&lex->vstr, CUR_CHAR(lex));\n                    next_char(lex);\n                }\n            } else if (is_letter(lex) || is_digit(lex) || is_char(lex, '.')) {\n                if (is_char_or3(lex, '.', 'j', 'J')) {\n                    lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG;\n                }\n                vstr_add_char(&lex->vstr, CUR_CHAR(lex));\n                next_char(lex);\n            } else if (is_char(lex, '_')) {\n                next_char(lex);\n            } else {\n                break;\n            }\n        }\n\n    } else {\n        // search for encoded delimiter or operator\n\n        const char *t = tok_enc;\n        size_t tok_enc_index = 0;\n        for (; *t != 0 && !is_char(lex, *t); t += 1) {\n            if (*t == 'e' || *t == 'c') {\n                t += 1;\n            }\n            tok_enc_index += 1;\n        }\n\n        next_char(lex);\n\n        if (*t == 0) {\n            // didn't match any delimiter or operator characters\n            lex->tok_kind = MP_TOKEN_INVALID;\n\n        } else if (*t == '!') {\n            // \"!=\" is a special case because \"!\" is not a valid operator\n            if (is_char(lex, '=')) {\n                next_char(lex);\n                lex->tok_kind = MP_TOKEN_OP_NOT_EQUAL;\n            } else {\n                lex->tok_kind = MP_TOKEN_INVALID;\n            }\n\n        } else if (*t == '.') {\n            // \".\" and \"...\" are special cases because \"..\" is not a valid operator\n            if (is_char_and(lex, '.', '.')) {\n                next_char(lex);\n                next_char(lex);\n                lex->tok_kind = MP_TOKEN_ELLIPSIS;\n            } else {\n                lex->tok_kind = MP_TOKEN_DEL_PERIOD;\n            }\n\n        } else {\n            // matched a delimiter or operator character\n\n            // get the maximum characters for a valid token\n            t += 1;\n            size_t t_index = tok_enc_index;\n            while (*t == 'c' || *t == 'e') {\n                t_index += 1;\n                if (is_char(lex, t[1])) {\n                    next_char(lex);\n                    tok_enc_index = t_index;\n                    if (*t == 'e') {\n                        break;\n                    }\n                } else if (*t == 'c') {\n                    break;\n                }\n                t += 2;\n            }\n\n            // set token kind\n            lex->tok_kind = tok_enc_kind[tok_enc_index];\n\n            // compute bracket level for implicit line joining\n            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) {\n                lex->nested_bracket_level += 1;\n            } 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) {\n                lex->nested_bracket_level -= 1;\n            }\n        }\n    }\n}\n\nmp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) {\n    mp_lexer_t *lex = m_new_obj(mp_lexer_t);\n\n    lex->source_name = src_name;\n    lex->reader = reader;\n    lex->line = 1;\n    lex->column = (size_t)-2; // account for 3 dummy bytes\n    lex->emit_dent = 0;\n    lex->nested_bracket_level = 0;\n    lex->alloc_indent_level = MICROPY_ALLOC_LEXER_INDENT_INIT;\n    lex->num_indent_level = 1;\n    lex->indent_level = m_new(uint16_t, lex->alloc_indent_level);\n    vstr_init(&lex->vstr, 32);\n\n    // store sentinel for first indentation level\n    lex->indent_level[0] = 0;\n\n    // load lexer with start of file, advancing lex->column to 1\n    // start with dummy bytes and use next_char() for proper EOL/EOF handling\n    lex->chr0 = lex->chr1 = lex->chr2 = 0;\n    next_char(lex);\n    next_char(lex);\n    next_char(lex);\n\n    // preload first token\n    mp_lexer_to_next(lex);\n\n    // Check that the first token is in the first column.  If it's not then we\n    // convert the token kind to INDENT so that the parser gives a syntax error.\n    if (lex->tok_column != 1) {\n        lex->tok_kind = MP_TOKEN_INDENT;\n    }\n\n    return lex;\n}\n\nmp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, size_t len, size_t free_len) {\n    mp_reader_t reader;\n    mp_reader_new_mem(&reader, (const byte *)str, len, free_len);\n    return mp_lexer_new(src_name, reader);\n}\n\n#if MICROPY_READER_POSIX || MICROPY_READER_VFS\n\nmp_lexer_t *mp_lexer_new_from_file(const char *filename) {\n    mp_reader_t reader;\n    mp_reader_new_file(&reader, filename);\n    return mp_lexer_new(qstr_from_str(filename), reader);\n}\n\n#if MICROPY_HELPER_LEXER_UNIX\n\nmp_lexer_t *mp_lexer_new_from_fd(qstr filename, int fd, bool close_fd) {\n    mp_reader_t reader;\n    mp_reader_new_file_from_fd(&reader, fd, close_fd);\n    return mp_lexer_new(filename, reader);\n}\n\n#endif\n\n#endif\n\nvoid mp_lexer_free(mp_lexer_t *lex) {\n    if (lex) {\n        lex->reader.close(lex->reader.data);\n        vstr_clear(&lex->vstr);\n        m_del(uint16_t, lex->indent_level, lex->alloc_indent_level);\n        m_del_obj(mp_lexer_t, lex);\n    }\n}\n\n#if 0\n// This function is used to print the current token and should only be\n// needed to debug the lexer, so it's not available via a config option.\nvoid mp_lexer_show_token(const mp_lexer_t *lex) {\n    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);\n    if (lex->vstr.len > 0) {\n        const byte *i = (const byte *)lex->vstr.buf;\n        const byte *j = (const byte *)i + lex->vstr.len;\n        printf(\" \");\n        while (i < j) {\n            unichar c = utf8_get_char(i);\n            i = utf8_next_char(i);\n            if (unichar_isprint(c)) {\n                printf(\"%c\", (int)c);\n            } else {\n                printf(\"?\");\n            }\n        }\n    }\n    printf(\"\\n\");\n}\n#endif\n\n#endif // MICROPY_ENABLE_COMPILER\n"
  },
  {
    "path": "py/lexer.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_LEXER_H\n#define MICROPY_INCLUDED_PY_LEXER_H\n\n#include <stdint.h>\n\n#include \"py/mpconfig.h\"\n#include \"py/qstr.h\"\n#include \"py/reader.h\"\n\n/* lexer.h -- simple tokeniser for MicroPython\n *\n * Uses (byte) length instead of null termination.\n * Tokens are the same - UTF-8 with (byte) length.\n */\n\ntypedef enum _mp_token_kind_t {\n    MP_TOKEN_END,\n\n    MP_TOKEN_INVALID,\n    MP_TOKEN_DEDENT_MISMATCH,\n    MP_TOKEN_LONELY_STRING_OPEN,\n\n    MP_TOKEN_NEWLINE,\n    MP_TOKEN_INDENT,\n    MP_TOKEN_DEDENT,\n\n    MP_TOKEN_NAME,\n    MP_TOKEN_INTEGER,\n    MP_TOKEN_FLOAT_OR_IMAG,\n    MP_TOKEN_STRING,\n    MP_TOKEN_BYTES,\n\n    MP_TOKEN_ELLIPSIS,\n\n    MP_TOKEN_KW_FALSE,\n    MP_TOKEN_KW_NONE,\n    MP_TOKEN_KW_TRUE,\n    MP_TOKEN_KW___DEBUG__,\n    MP_TOKEN_KW_AND,\n    MP_TOKEN_KW_AS,\n    MP_TOKEN_KW_ASSERT,\n    #if MICROPY_PY_ASYNC_AWAIT\n    MP_TOKEN_KW_ASYNC,\n    MP_TOKEN_KW_AWAIT,\n    #endif\n    MP_TOKEN_KW_BREAK,\n    MP_TOKEN_KW_CLASS,\n    MP_TOKEN_KW_CONTINUE,\n    MP_TOKEN_KW_DEF,\n    MP_TOKEN_KW_DEL,\n    MP_TOKEN_KW_ELIF,\n    MP_TOKEN_KW_ELSE,\n    MP_TOKEN_KW_EXCEPT,\n    MP_TOKEN_KW_FINALLY,\n    MP_TOKEN_KW_FOR,\n    MP_TOKEN_KW_FROM,\n    MP_TOKEN_KW_GLOBAL,\n    MP_TOKEN_KW_IF,\n    MP_TOKEN_KW_IMPORT,\n    MP_TOKEN_KW_IN,\n    MP_TOKEN_KW_IS,\n    MP_TOKEN_KW_LAMBDA,\n    MP_TOKEN_KW_NONLOCAL,\n    MP_TOKEN_KW_NOT,\n    MP_TOKEN_KW_OR,\n    MP_TOKEN_KW_PASS,\n    MP_TOKEN_KW_RAISE,\n    MP_TOKEN_KW_RETURN,\n    MP_TOKEN_KW_TRY,\n    MP_TOKEN_KW_WHILE,\n    MP_TOKEN_KW_WITH,\n    MP_TOKEN_KW_YIELD,\n\n    MP_TOKEN_OP_ASSIGN,\n    MP_TOKEN_OP_TILDE,\n\n    // Order of these 6 matches corresponding mp_binary_op_t operator\n    MP_TOKEN_OP_LESS,\n    MP_TOKEN_OP_MORE,\n    MP_TOKEN_OP_DBL_EQUAL,\n    MP_TOKEN_OP_LESS_EQUAL,\n    MP_TOKEN_OP_MORE_EQUAL,\n    MP_TOKEN_OP_NOT_EQUAL,\n\n    // Order of these 13 matches corresponding mp_binary_op_t operator\n    MP_TOKEN_OP_PIPE,\n    MP_TOKEN_OP_CARET,\n    MP_TOKEN_OP_AMPERSAND,\n    MP_TOKEN_OP_DBL_LESS,\n    MP_TOKEN_OP_DBL_MORE,\n    MP_TOKEN_OP_PLUS,\n    MP_TOKEN_OP_MINUS,\n    MP_TOKEN_OP_STAR,\n    MP_TOKEN_OP_AT,\n    MP_TOKEN_OP_DBL_SLASH,\n    MP_TOKEN_OP_SLASH,\n    MP_TOKEN_OP_PERCENT,\n    MP_TOKEN_OP_DBL_STAR,\n\n    // Order of these 13 matches corresponding mp_binary_op_t operator\n    MP_TOKEN_DEL_PIPE_EQUAL,\n    MP_TOKEN_DEL_CARET_EQUAL,\n    MP_TOKEN_DEL_AMPERSAND_EQUAL,\n    MP_TOKEN_DEL_DBL_LESS_EQUAL,\n    MP_TOKEN_DEL_DBL_MORE_EQUAL,\n    MP_TOKEN_DEL_PLUS_EQUAL,\n    MP_TOKEN_DEL_MINUS_EQUAL,\n    MP_TOKEN_DEL_STAR_EQUAL,\n    MP_TOKEN_DEL_AT_EQUAL,\n    MP_TOKEN_DEL_DBL_SLASH_EQUAL,\n    MP_TOKEN_DEL_SLASH_EQUAL,\n    MP_TOKEN_DEL_PERCENT_EQUAL,\n    MP_TOKEN_DEL_DBL_STAR_EQUAL,\n\n    MP_TOKEN_DEL_PAREN_OPEN,\n    MP_TOKEN_DEL_PAREN_CLOSE,\n    MP_TOKEN_DEL_BRACKET_OPEN,\n    MP_TOKEN_DEL_BRACKET_CLOSE,\n    MP_TOKEN_DEL_BRACE_OPEN,\n    MP_TOKEN_DEL_BRACE_CLOSE,\n    MP_TOKEN_DEL_COMMA,\n    MP_TOKEN_DEL_COLON,\n    MP_TOKEN_DEL_PERIOD,\n    MP_TOKEN_DEL_SEMICOLON,\n    MP_TOKEN_DEL_EQUAL,\n    MP_TOKEN_DEL_MINUS_MORE,\n} mp_token_kind_t;\n\n// this data structure is exposed for efficiency\n// public members are: source_name, tok_line, tok_column, tok_kind, vstr\ntypedef struct _mp_lexer_t {\n    qstr source_name;           // name of source\n    mp_reader_t reader;         // stream source\n\n    unichar chr0, chr1, chr2;   // current cached characters from source\n\n    size_t line;                // current source line\n    size_t column;              // current source column\n\n    mp_int_t emit_dent;             // non-zero when there are INDENT/DEDENT tokens to emit\n    mp_int_t nested_bracket_level;  // >0 when there are nested brackets over multiple lines\n\n    size_t alloc_indent_level;\n    size_t num_indent_level;\n    uint16_t *indent_level;\n\n    size_t tok_line;            // token source line\n    size_t tok_column;          // token source column\n    mp_token_kind_t tok_kind;   // token kind\n    vstr_t vstr;                // token data\n} mp_lexer_t;\n\nmp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader);\nmp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, size_t len, size_t free_len);\n\nvoid mp_lexer_free(mp_lexer_t *lex);\nvoid mp_lexer_to_next(mp_lexer_t *lex);\n\n/******************************************************************/\n// platform specific import function; must be implemented for a specific port\n// TODO tidy up, rename, or put elsewhere\n\ntypedef enum {\n    MP_IMPORT_STAT_NO_EXIST,\n    MP_IMPORT_STAT_DIR,\n    MP_IMPORT_STAT_FILE,\n} mp_import_stat_t;\n\nmp_import_stat_t mp_import_stat(const char *path);\nmp_lexer_t *mp_lexer_new_from_file(const char *filename);\n\n#if MICROPY_HELPER_LEXER_UNIX\nmp_lexer_t *mp_lexer_new_from_fd(qstr filename, int fd, bool close_fd);\n#endif\n\n#endif // MICROPY_INCLUDED_PY_LEXER_H\n"
  },
  {
    "path": "py/makecompresseddata.py",
    "content": "from __future__ import print_function\n\nimport collections\nimport re\nimport sys\n\nimport gzip\nimport zlib\n\n\n_COMPRESSED_MARKER = 0xFF\n\n\ndef check_non_ascii(msg):\n    for c in msg:\n        if ord(c) >= 0x80:\n            print(\n                'Unable to generate compressed data: message \"{}\" contains a non-ascii character \"{}\".'.format(\n                    msg, c\n                ),\n                file=sys.stderr,\n            )\n            sys.exit(1)\n\n\n# Replace <char><space> with <char | 0x80>.\n# Trival scheme to demo/test.\ndef space_compression(error_strings):\n    for line in error_strings:\n        check_non_ascii(line)\n        result = \"\"\n        for i in range(len(line)):\n            if i > 0 and line[i] == \" \":\n                result = result[:-1]\n                result += \"\\\\{:03o}\".format(ord(line[i - 1]))\n            else:\n                result += line[i]\n        error_strings[line] = result\n    return None\n\n\n# Replace common words with <0x80 | index>.\n# Index is into a table of words stored as aaaaa<0x80|a>bbb<0x80|b>...\n# Replaced words are assumed to have spaces either side to avoid having to store the spaces in the compressed strings.\ndef word_compression(error_strings):\n    topn = collections.Counter()\n\n    for line in error_strings.keys():\n        check_non_ascii(line)\n        for word in line.split(\" \"):\n            topn[word] += 1\n\n    # Order not just by frequency, but by expected saving. i.e. prefer a longer string that is used less frequently.\n    # Use the word itself for ties so that compression is deterministic.\n    def bytes_saved(item):\n        w, n = item\n        return -((len(w) + 1) * (n - 1)), w\n\n    top128 = sorted(topn.items(), key=bytes_saved)[:128]\n\n    index = [w for w, _ in top128]\n    index_lookup = {w: i for i, w in enumerate(index)}\n\n    for line in error_strings.keys():\n        result = \"\"\n        need_space = False\n        for word in line.split(\" \"):\n            if word in index_lookup:\n                result += \"\\\\{:03o}\".format(0b10000000 | index_lookup[word])\n                need_space = False\n            else:\n                if need_space:\n                    result += \" \"\n                need_space = True\n                result += word\n        error_strings[line] = result.strip()\n\n    return \"\".join(w[:-1] + \"\\\\{:03o}\".format(0b10000000 | ord(w[-1])) for w in index)\n\n\n# Replace chars in text with variable length bit sequence.\n# For comparison only (the table is not emitted).\ndef huffman_compression(error_strings):\n    # https://github.com/tannewt/huffman\n    import huffman\n\n    all_strings = \"\".join(error_strings)\n    cb = huffman.codebook(collections.Counter(all_strings).items())\n\n    for line in error_strings:\n        b = \"1\"\n        for c in line:\n            b += cb[c]\n        n = len(b)\n        if n % 8 != 0:\n            n += 8 - (n % 8)\n        result = \"\"\n        for i in range(0, n, 8):\n            result += \"\\\\{:03o}\".format(int(b[i : i + 8], 2))\n        if len(result) > len(line) * 4:\n            result = line\n        error_strings[line] = result\n\n    # TODO: This would be the prefix lengths and the table ordering.\n    return \"_\" * (10 + len(cb))\n\n\n# Replace common N-letter sequences with <0x80 | index>, where\n# the common sequences are stored in a separate table.\n# This isn't very useful, need a smarter way to find top-ngrams.\ndef ngram_compression(error_strings):\n    topn = collections.Counter()\n    N = 2\n\n    for line in error_strings.keys():\n        check_non_ascii(line)\n        if len(line) < N:\n            continue\n        for i in range(0, len(line) - N, N):\n            topn[line[i : i + N]] += 1\n\n    def bytes_saved(item):\n        w, n = item\n        return -(len(w) * (n - 1))\n\n    top128 = sorted(topn.items(), key=bytes_saved)[:128]\n\n    index = [w for w, _ in top128]\n    index_lookup = {w: i for i, w in enumerate(index)}\n\n    for line in error_strings.keys():\n        result = \"\"\n        for i in range(0, len(line) - N + 1, N):\n            word = line[i : i + N]\n            if word in index_lookup:\n                result += \"\\\\{:03o}\".format(0b10000000 | index_lookup[word])\n            else:\n                result += word\n        if len(line) % N != 0:\n            result += line[len(line) - len(line) % N :]\n        error_strings[line] = result.strip()\n\n    return \"\".join(index)\n\n\ndef main(collected_path, fn):\n    error_strings = collections.OrderedDict()\n    max_uncompressed_len = 0\n    num_uses = 0\n\n    # Read in all MP_ERROR_TEXT strings.\n    with open(collected_path, \"r\") as f:\n        for line in f:\n            line = line.strip()\n            if not line:\n                continue\n            num_uses += 1\n            error_strings[line] = None\n            max_uncompressed_len = max(max_uncompressed_len, len(line))\n\n    # So that objexcept.c can figure out how big the buffer needs to be.\n    print(\"#define MP_MAX_UNCOMPRESSED_TEXT_LEN ({})\".format(max_uncompressed_len))\n\n    # Run the compression.\n    compressed_data = fn(error_strings)\n\n    # Print the data table.\n    print('MP_COMPRESSED_DATA(\"{}\")'.format(compressed_data))\n\n    # Print the replacements.\n    for uncomp, comp in error_strings.items():\n        if uncomp == comp:\n            prefix = \"\"\n        else:\n            prefix = \"\\\\{:03o}\".format(_COMPRESSED_MARKER)\n        print('MP_MATCH_COMPRESSED(\"{}\", \"{}{}\")'.format(uncomp, prefix, comp))\n\n    # Used to calculate the \"true\" length of the (escaped) compressed strings.\n    def unescape(s):\n        return re.sub(r\"\\\\\\d\\d\\d\", \"!\", s)\n\n    # Stats. Note this doesn't include the cost of the decompressor code.\n    uncomp_len = sum(len(s) + 1 for s in error_strings.keys())\n    comp_len = sum(1 + len(unescape(s)) + 1 for s in error_strings.values())\n    data_len = len(compressed_data) + 1 if compressed_data else 0\n    print(\"// Total input length:      {}\".format(uncomp_len))\n    print(\"// Total compressed length: {}\".format(comp_len))\n    print(\"// Total data length:       {}\".format(data_len))\n    print(\"// Predicted saving:        {}\".format(uncomp_len - comp_len - data_len))\n\n    # Somewhat meaningless comparison to zlib/gzip.\n    all_input_bytes = \"\\\\0\".join(error_strings.keys()).encode()\n    print()\n    if hasattr(gzip, \"compress\"):\n        gzip_len = len(gzip.compress(all_input_bytes)) + num_uses * 4\n        print(\"// gzip length:             {}\".format(gzip_len))\n        print(\"// Percentage of gzip:      {:.1f}%\".format(100 * (comp_len + data_len) / gzip_len))\n    if hasattr(zlib, \"compress\"):\n        zlib_len = len(zlib.compress(all_input_bytes)) + num_uses * 4\n        print(\"// zlib length:             {}\".format(zlib_len))\n        print(\"// Percentage of zlib:      {:.1f}%\".format(100 * (comp_len + data_len) / zlib_len))\n\n\nif __name__ == \"__main__\":\n    main(sys.argv[1], word_compression)\n"
  },
  {
    "path": "py/makemoduledefs.py",
    "content": "#!/usr/bin/env python\n\n# This pre-processor parses provided objects' c files for\n# MP_REGISTER_MODULE(module_name, obj_module, enabled_define)\n# These are used to generate a header with the required entries for\n# \"mp_rom_map_elem_t mp_builtin_module_table[]\" in py/objmodule.c\n\nfrom __future__ import print_function\n\nimport re\nimport io\nimport os\nimport argparse\n\n\npattern = re.compile(r\"[\\n;]\\s*MP_REGISTER_MODULE\\((.*?),\\s*(.*?),\\s*(.*?)\\);\", flags=re.DOTALL)\n\n\ndef find_c_file(obj_file, vpath):\n    \"\"\"Search vpaths for the c file that matches the provided object_file.\n\n    :param str obj_file: object file to find the matching c file for\n    :param List[str] vpath: List of base paths, similar to gcc vpath\n    :return: str path to c file or None\n    \"\"\"\n    c_file = None\n    relative_c_file = os.path.splitext(obj_file)[0] + \".c\"\n    relative_c_file = relative_c_file.lstrip(\"/\\\\\")\n    for p in vpath:\n        possible_c_file = os.path.join(p, relative_c_file)\n        if os.path.exists(possible_c_file):\n            c_file = possible_c_file\n            break\n\n    return c_file\n\n\ndef find_module_registrations(c_file):\n    \"\"\"Find any MP_REGISTER_MODULE definitions in the provided c file.\n\n    :param str c_file: path to c file to check\n    :return: List[(module_name, obj_module, enabled_define)]\n    \"\"\"\n    global pattern\n\n    if c_file is None:\n        # No c file to match the object file, skip\n        return set()\n\n    with io.open(c_file, encoding=\"utf-8\") as c_file_obj:\n        return set(re.findall(pattern, c_file_obj.read()))\n\n\ndef generate_module_table_header(modules):\n    \"\"\"Generate header with module table entries for builtin modules.\n\n    :param List[(module_name, obj_module, enabled_define)] modules: module defs\n    :return: None\n    \"\"\"\n\n    # Print header file for all external modules.\n    mod_defs = []\n    print(\"// Automatically generated by makemoduledefs.py.\\n\")\n    for module_name, obj_module, enabled_define in modules:\n        mod_def = \"MODULE_DEF_{}\".format(module_name.upper())\n        mod_defs.append(mod_def)\n        print(\n            (\n                \"#if ({enabled_define})\\n\"\n                \"    extern const struct _mp_obj_module_t {obj_module};\\n\"\n                \"    #define {mod_def} {{ MP_ROM_QSTR({module_name}), MP_ROM_PTR(&{obj_module}) }},\\n\"\n                \"#else\\n\"\n                \"    #define {mod_def}\\n\"\n                \"#endif\\n\"\n            ).format(\n                module_name=module_name,\n                obj_module=obj_module,\n                enabled_define=enabled_define,\n                mod_def=mod_def,\n            )\n        )\n\n    print(\"\\n#define MICROPY_REGISTERED_MODULES \\\\\")\n\n    for mod_def in mod_defs:\n        print(\"    {mod_def} \\\\\".format(mod_def=mod_def))\n\n    print(\"// MICROPY_REGISTERED_MODULES\")\n\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\n        \"--vpath\", default=\".\", help=\"comma separated list of folders to search for c files in\"\n    )\n    parser.add_argument(\"files\", nargs=\"*\", help=\"list of c files to search\")\n    args = parser.parse_args()\n\n    vpath = [p.strip() for p in args.vpath.split(\",\")]\n\n    modules = set()\n    for obj_file in args.files:\n        c_file = find_c_file(obj_file, vpath)\n        modules |= find_module_registrations(c_file)\n\n    generate_module_table_header(sorted(modules))\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "py/makeqstrdata.py",
    "content": "\"\"\"\nProcess raw qstr file and output qstr data with length, hash and data bytes.\n\nThis script works with Python 2.6, 2.7, 3.3 and 3.4.\n\"\"\"\n\nfrom __future__ import print_function\n\nimport re\nimport sys\n\n# Python 2/3 compatibility:\n#   - iterating through bytes is different\n#   - codepoint2name lives in a different module\nimport platform\n\nif platform.python_version_tuple()[0] == \"2\":\n    bytes_cons = lambda val, enc=None: bytearray(val)\n    from htmlentitydefs import codepoint2name\nelif platform.python_version_tuple()[0] == \"3\":\n    bytes_cons = bytes\n    from html.entities import codepoint2name\n# end compatibility code\n\ncodepoint2name[ord(\"-\")] = \"hyphen\"\n\n# add some custom names to map characters that aren't in HTML\ncodepoint2name[ord(\" \")] = \"space\"\ncodepoint2name[ord(\"'\")] = \"squot\"\ncodepoint2name[ord(\",\")] = \"comma\"\ncodepoint2name[ord(\".\")] = \"dot\"\ncodepoint2name[ord(\":\")] = \"colon\"\ncodepoint2name[ord(\";\")] = \"semicolon\"\ncodepoint2name[ord(\"/\")] = \"slash\"\ncodepoint2name[ord(\"%\")] = \"percent\"\ncodepoint2name[ord(\"#\")] = \"hash\"\ncodepoint2name[ord(\"(\")] = \"paren_open\"\ncodepoint2name[ord(\")\")] = \"paren_close\"\ncodepoint2name[ord(\"[\")] = \"bracket_open\"\ncodepoint2name[ord(\"]\")] = \"bracket_close\"\ncodepoint2name[ord(\"{\")] = \"brace_open\"\ncodepoint2name[ord(\"}\")] = \"brace_close\"\ncodepoint2name[ord(\"*\")] = \"star\"\ncodepoint2name[ord(\"!\")] = \"bang\"\ncodepoint2name[ord(\"\\\\\")] = \"backslash\"\ncodepoint2name[ord(\"+\")] = \"plus\"\ncodepoint2name[ord(\"$\")] = \"dollar\"\ncodepoint2name[ord(\"=\")] = \"equals\"\ncodepoint2name[ord(\"?\")] = \"question\"\ncodepoint2name[ord(\"@\")] = \"at_sign\"\ncodepoint2name[ord(\"^\")] = \"caret\"\ncodepoint2name[ord(\"|\")] = \"pipe\"\ncodepoint2name[ord(\"~\")] = \"tilde\"\n\n# static qstrs, should be sorted\n\nstatic_qstr_list = [\n    \"\",\n    \"__dir__\",  # Put __dir__ after empty qstr for builtin dir() to work\n    \"\\n\",\n    \" \",\n    \"*\",\n    \"/\",\n    \"<module>\",\n    \"_\",\n    \"__call__\",\n    \"__class__\",\n    \"__delitem__\",\n    \"__enter__\",\n    \"__exit__\",\n    \"__getattr__\",\n    \"__getitem__\",\n    \"__hash__\",\n    \"__init__\",\n    \"__int__\",\n    \"__iter__\",\n    \"__len__\",\n    \"__main__\",\n    \"__module__\",\n    \"__name__\",\n    \"__new__\",\n    \"__next__\",\n    \"__qualname__\",\n    \"__repr__\",\n    \"__setitem__\",\n    \"__str__\",\n    \"ArithmeticError\",\n    \"AssertionError\",\n    \"AttributeError\",\n    \"BaseException\",\n    \"EOFError\",\n    \"Ellipsis\",\n    \"Exception\",\n    \"GeneratorExit\",\n    \"ImportError\",\n    \"IndentationError\",\n    \"IndexError\",\n    \"KeyError\",\n    \"KeyboardInterrupt\",\n    \"LookupError\",\n    \"MemoryError\",\n    \"NameError\",\n    \"NoneType\",\n    \"NotImplementedError\",\n    \"OSError\",\n    \"OverflowError\",\n    \"RuntimeError\",\n    \"StopIteration\",\n    \"SyntaxError\",\n    \"SystemExit\",\n    \"TypeError\",\n    \"ValueError\",\n    \"ZeroDivisionError\",\n    \"abs\",\n    \"all\",\n    \"any\",\n    \"append\",\n    \"args\",\n    \"bool\",\n    \"builtins\",\n    \"bytearray\",\n    \"bytecode\",\n    \"bytes\",\n    \"callable\",\n    \"chr\",\n    \"classmethod\",\n    \"clear\",\n    \"close\",\n    \"const\",\n    \"copy\",\n    \"count\",\n    \"dict\",\n    \"dir\",\n    \"divmod\",\n    \"end\",\n    \"endswith\",\n    \"eval\",\n    \"exec\",\n    \"extend\",\n    \"find\",\n    \"format\",\n    \"from_bytes\",\n    \"get\",\n    \"getattr\",\n    \"globals\",\n    \"hasattr\",\n    \"hash\",\n    \"id\",\n    \"index\",\n    \"insert\",\n    \"int\",\n    \"isalpha\",\n    \"isdigit\",\n    \"isinstance\",\n    \"islower\",\n    \"isspace\",\n    \"issubclass\",\n    \"isupper\",\n    \"items\",\n    \"iter\",\n    \"join\",\n    \"key\",\n    \"keys\",\n    \"len\",\n    \"list\",\n    \"little\",\n    \"locals\",\n    \"lower\",\n    \"lstrip\",\n    \"main\",\n    \"map\",\n    \"micropython\",\n    \"next\",\n    \"object\",\n    \"open\",\n    \"ord\",\n    \"pop\",\n    \"popitem\",\n    \"pow\",\n    \"print\",\n    \"range\",\n    \"read\",\n    \"readinto\",\n    \"readline\",\n    \"remove\",\n    \"replace\",\n    \"repr\",\n    \"reverse\",\n    \"rfind\",\n    \"rindex\",\n    \"round\",\n    \"rsplit\",\n    \"rstrip\",\n    \"self\",\n    \"send\",\n    \"sep\",\n    \"set\",\n    \"setattr\",\n    \"setdefault\",\n    \"sort\",\n    \"sorted\",\n    \"split\",\n    \"start\",\n    \"startswith\",\n    \"staticmethod\",\n    \"step\",\n    \"stop\",\n    \"str\",\n    \"strip\",\n    \"sum\",\n    \"super\",\n    \"throw\",\n    \"to_bytes\",\n    \"tuple\",\n    \"type\",\n    \"update\",\n    \"upper\",\n    \"utf-8\",\n    \"value\",\n    \"values\",\n    \"write\",\n    \"zip\",\n]\n\n# this must match the equivalent function in qstr.c\ndef compute_hash(qstr, bytes_hash):\n    hash = 5381\n    for b in qstr:\n        hash = (hash * 33) ^ b\n    # Make sure that valid hash is never zero, zero means \"hash not computed\"\n    return (hash & ((1 << (8 * bytes_hash)) - 1)) or 1\n\n\ndef qstr_escape(qst):\n    def esc_char(m):\n        c = ord(m.group(0))\n        try:\n            name = codepoint2name[c]\n        except KeyError:\n            name = \"0x%02x\" % c\n        return \"_\" + name + \"_\"\n\n    return re.sub(r\"[^A-Za-z0-9_]\", esc_char, qst)\n\n\ndef parse_input_headers(infiles):\n    qcfgs = {}\n    qstrs = {}\n\n    # add static qstrs\n    for qstr in static_qstr_list:\n        # work out the corresponding qstr name\n        ident = qstr_escape(qstr)\n\n        # don't add duplicates\n        assert ident not in qstrs\n\n        # add the qstr to the list, with order number to retain original order in file\n        order = len(qstrs) - 300000\n        qstrs[ident] = (order, ident, qstr)\n\n    # read the qstrs in from the input files\n    for infile in infiles:\n        with open(infile, \"rt\") as f:\n            for line in f:\n                line = line.strip()\n\n                # is this a config line?\n                match = re.match(r\"^QCFG\\((.+), (.+)\\)\", line)\n                if match:\n                    value = match.group(2)\n                    if value[0] == \"(\" and value[-1] == \")\":\n                        # strip parenthesis from config value\n                        value = value[1:-1]\n                    qcfgs[match.group(1)] = value\n                    continue\n\n                # is this a QSTR line?\n                match = re.match(r\"^Q\\((.*)\\)$\", line)\n                if not match:\n                    continue\n\n                # get the qstr value\n                qstr = match.group(1)\n\n                # special cases to specify control characters\n                if qstr == \"\\\\n\":\n                    qstr = \"\\n\"\n                elif qstr == \"\\\\r\\\\n\":\n                    qstr = \"\\r\\n\"\n\n                # work out the corresponding qstr name\n                ident = qstr_escape(qstr)\n\n                # don't add duplicates\n                if ident in qstrs:\n                    continue\n\n                # add the qstr to the list, with order number to retain original order in file\n                order = len(qstrs)\n                # but put special method names like __add__ at the top of list, so\n                # that their id's fit into a byte\n                if ident == \"\":\n                    # Sort empty qstr above all still\n                    order = -200000\n                elif ident == \"__dir__\":\n                    # Put __dir__ after empty qstr for builtin dir() to work\n                    order = -190000\n                elif ident.startswith(\"__\"):\n                    order -= 100000\n                qstrs[ident] = (order, ident, qstr)\n\n    if not qcfgs:\n        sys.stderr.write(\"ERROR: Empty preprocessor output - check for errors above\\n\")\n        sys.exit(1)\n\n    return qcfgs, qstrs\n\n\ndef make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr):\n    qbytes = bytes_cons(qstr, \"utf8\")\n    qlen = len(qbytes)\n    qhash = compute_hash(qbytes, cfg_bytes_hash)\n    if all(32 <= ord(c) <= 126 and c != \"\\\\\" and c != '\"' for c in qstr):\n        # qstr is all printable ASCII so render it as-is (for easier debugging)\n        qdata = qstr\n    else:\n        # qstr contains non-printable codes so render entire thing as hex pairs\n        qdata = \"\".join((\"\\\\x%02x\" % b) for b in qbytes)\n    if qlen >= (1 << (8 * cfg_bytes_len)):\n        print(\"qstr is too long:\", qstr)\n        assert False\n    qlen_str = (\"\\\\x%02x\" * cfg_bytes_len) % tuple(\n        ((qlen >> (8 * i)) & 0xFF) for i in range(cfg_bytes_len)\n    )\n    qhash_str = (\"\\\\x%02x\" * cfg_bytes_hash) % tuple(\n        ((qhash >> (8 * i)) & 0xFF) for i in range(cfg_bytes_hash)\n    )\n    return '(const byte*)\"%s%s\" \"%s\"' % (qhash_str, qlen_str, qdata)\n\n\ndef print_qstr_data(qcfgs, qstrs):\n    # get config variables\n    cfg_bytes_len = int(qcfgs[\"BYTES_IN_LEN\"])\n    cfg_bytes_hash = int(qcfgs[\"BYTES_IN_HASH\"])\n\n    # print out the starter of the generated C header file\n    print(\"// This file was automatically generated by makeqstrdata.py\")\n    print(\"\")\n\n    # add NULL qstr with no hash or data\n    print(\n        'QDEF(MP_QSTRnull, (const byte*)\"%s%s\" \"\")'\n        % (\"\\\\x00\" * cfg_bytes_hash, \"\\\\x00\" * cfg_bytes_len)\n    )\n\n    # go through each qstr and print it out\n    for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]):\n        qbytes = make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr)\n        print(\"QDEF(MP_QSTR_%s, %s)\" % (ident, qbytes))\n\n\ndef do_work(infiles):\n    qcfgs, qstrs = parse_input_headers(infiles)\n    print_qstr_data(qcfgs, qstrs)\n\n\nif __name__ == \"__main__\":\n    do_work(sys.argv[1:])\n"
  },
  {
    "path": "py/makeqstrdefs.py",
    "content": "\"\"\"\nThis script processes the output from the C preprocessor and extracts all\nqstr. Each qstr is transformed into a qstr definition of the form 'Q(...)'.\n\nThis script works with Python 2.6, 2.7, 3.3 and 3.4.\n\"\"\"\n\nfrom __future__ import print_function\n\nimport re\nimport subprocess\nimport sys\nimport io\nimport os\n\n\n# Extract MP_QSTR_FOO macros.\n_MODE_QSTR = \"qstr\"\n\n# Extract MP_COMPRESSED_ROM_TEXT(\"\") macros.  (Which come from MP_ERROR_TEXT)\n_MODE_COMPRESS = \"compress\"\n\n\ndef preprocess():\n    if any(src in args.dependencies for src in args.changed_sources):\n        sources = args.sources\n    elif any(args.changed_sources):\n        sources = args.changed_sources\n    else:\n        sources = args.sources\n    csources = []\n    cxxsources = []\n    for source in sources:\n        if source.endswith(\".cpp\"):\n            cxxsources.append(source)\n        else:\n            csources.append(source)\n    try:\n        os.makedirs(os.path.dirname(args.output[0]))\n    except OSError:\n        pass\n    with open(args.output[0], \"w\") as out_file:\n        if csources:\n            subprocess.check_call(args.pp + args.cflags + csources, stdout=out_file)\n        if cxxsources:\n            subprocess.check_call(args.pp + args.cxxflags + cxxsources, stdout=out_file)\n\n\ndef write_out(fname, output):\n    if output:\n        for m, r in [(\"/\", \"__\"), (\"\\\\\", \"__\"), (\":\", \"@\"), (\"..\", \"@@\")]:\n            fname = fname.replace(m, r)\n        with open(args.output_dir + \"/\" + fname + \".\" + args.mode, \"w\") as f:\n            f.write(\"\\n\".join(output) + \"\\n\")\n\n\ndef process_file(f):\n    re_line = re.compile(r\"#[line]*\\s\\d+\\s\\\"([^\\\"]+)\\\"\")\n    if args.mode == _MODE_QSTR:\n        re_match = re.compile(r\"MP_QSTR_[_a-zA-Z0-9]+\")\n    elif args.mode == _MODE_COMPRESS:\n        re_match = re.compile(r'MP_COMPRESSED_ROM_TEXT\\(\"([^\"]*)\"\\)')\n    output = []\n    last_fname = None\n    for line in f:\n        if line.isspace():\n            continue\n        # match gcc-like output (# n \"file\") and msvc-like output (#line n \"file\")\n        if line.startswith((\"# \", \"#line\")):\n            m = re_line.match(line)\n            assert m is not None\n            fname = m.group(1)\n            if os.path.splitext(fname)[1] not in [\".c\", \".cpp\"]:\n                continue\n            if fname != last_fname:\n                write_out(last_fname, output)\n                output = []\n                last_fname = fname\n            continue\n        for match in re_match.findall(line):\n            if args.mode == _MODE_QSTR:\n                name = match.replace(\"MP_QSTR_\", \"\")\n                output.append(\"Q(\" + name + \")\")\n            elif args.mode == _MODE_COMPRESS:\n                output.append(match)\n\n    if last_fname:\n        write_out(last_fname, output)\n    return \"\"\n\n\ndef cat_together():\n    import glob\n    import hashlib\n\n    hasher = hashlib.md5()\n    all_lines = []\n    outf = open(args.output_dir + \"/out\", \"wb\")\n    for fname in glob.glob(args.output_dir + \"/*.\" + args.mode):\n        with open(fname, \"rb\") as f:\n            lines = f.readlines()\n            all_lines += lines\n    all_lines.sort()\n    all_lines = b\"\\n\".join(all_lines)\n    outf.write(all_lines)\n    outf.close()\n    hasher.update(all_lines)\n    new_hash = hasher.hexdigest()\n    # print(new_hash)\n    old_hash = None\n    try:\n        with open(args.output_file + \".hash\") as f:\n            old_hash = f.read()\n    except IOError:\n        pass\n    mode_full = \"QSTR\"\n    if args.mode == _MODE_COMPRESS:\n        mode_full = \"Compressed data\"\n    if old_hash != new_hash:\n        print(mode_full, \"updated\")\n        try:\n            # rename below might fail if file exists\n            os.remove(args.output_file)\n        except:\n            pass\n        os.rename(args.output_dir + \"/out\", args.output_file)\n        with open(args.output_file + \".hash\", \"w\") as f:\n            f.write(new_hash)\n    else:\n        print(mode_full, \"not updated\")\n\n\nif __name__ == \"__main__\":\n    if len(sys.argv) < 6:\n        print(\"usage: %s command mode input_filename output_dir output_file\" % sys.argv[0])\n        sys.exit(2)\n\n    class Args:\n        pass\n\n    args = Args()\n    args.command = sys.argv[1]\n\n    if args.command == \"pp\":\n        named_args = {\n            s: []\n            for s in [\n                \"pp\",\n                \"output\",\n                \"cflags\",\n                \"cxxflags\",\n                \"sources\",\n                \"changed_sources\",\n                \"dependencies\",\n            ]\n        }\n\n        for arg in sys.argv[1:]:\n            if arg in named_args:\n                current_tok = arg\n            else:\n                named_args[current_tok].append(arg)\n\n        if not named_args[\"pp\"] or len(named_args[\"output\"]) != 1:\n            print(\"usage: %s %s ...\" % (sys.argv[0], \" ... \".join(named_args)))\n            sys.exit(2)\n\n        for k, v in named_args.items():\n            setattr(args, k, v)\n\n        preprocess()\n        sys.exit(0)\n\n    args.mode = sys.argv[2]\n    args.input_filename = sys.argv[3]  # Unused for command=cat\n    args.output_dir = sys.argv[4]\n    args.output_file = None if len(sys.argv) == 5 else sys.argv[5]  # Unused for command=split\n\n    if args.mode not in (_MODE_QSTR, _MODE_COMPRESS):\n        print(\"error: mode %s unrecognised\" % sys.argv[2])\n        sys.exit(2)\n\n    try:\n        os.makedirs(args.output_dir)\n    except OSError:\n        pass\n\n    if args.command == \"split\":\n        with io.open(args.input_filename, encoding=\"utf-8\") as infile:\n            process_file(infile)\n\n    if args.command == \"cat\":\n        cat_together()\n"
  },
  {
    "path": "py/makeversionhdr.py",
    "content": "\"\"\"\nGenerate header file with macros defining MicroPython version info.\n\nThis script works with Python 2.6, 2.7, 3.3 and 3.4.\n\"\"\"\n\nfrom __future__ import print_function\n\nimport sys\nimport os\nimport datetime\nimport subprocess\n\n\ndef get_version_info_from_git():\n    # Python 2.6 doesn't have check_output, so check for that\n    try:\n        subprocess.check_output\n        subprocess.check_call\n    except AttributeError:\n        return None\n\n    # Note: git describe doesn't work if no tag is available\n    try:\n        git_tag = subprocess.check_output(\n            [\"git\", \"describe\", \"--dirty\", \"--always\", \"--match\", \"v[1-9].*\"],\n            stderr=subprocess.STDOUT,\n            universal_newlines=True,\n        ).strip()\n    except subprocess.CalledProcessError as er:\n        if er.returncode == 128:\n            # git exit code of 128 means no repository found\n            return None\n        git_tag = \"\"\n    except OSError:\n        return None\n    try:\n        git_hash = subprocess.check_output(\n            [\"git\", \"rev-parse\", \"--short\", \"HEAD\"],\n            stderr=subprocess.STDOUT,\n            universal_newlines=True,\n        ).strip()\n    except subprocess.CalledProcessError:\n        git_hash = \"unknown\"\n    except OSError:\n        return None\n\n    try:\n        # Check if there are any modified files.\n        subprocess.check_call(\n            [\"git\", \"diff\", \"--no-ext-diff\", \"--quiet\", \"--exit-code\"], stderr=subprocess.STDOUT\n        )\n        # Check if there are any staged files.\n        subprocess.check_call(\n            [\"git\", \"diff-index\", \"--cached\", \"--quiet\", \"HEAD\", \"--\"], stderr=subprocess.STDOUT\n        )\n    except subprocess.CalledProcessError:\n        git_hash += \"-dirty\"\n    except OSError:\n        return None\n\n    return git_tag, git_hash\n\n\ndef get_version_info_from_docs_conf():\n    with open(os.path.join(os.path.dirname(sys.argv[0]), \"..\", \"docs\", \"conf.py\")) as f:\n        for line in f:\n            if line.startswith(\"version = release = '\"):\n                ver = line.strip().split(\" = \")[2].strip(\"'\")\n                git_tag = \"v\" + ver\n                return git_tag, \"<no hash>\"\n    return None\n\n\ndef make_version_header(filename):\n    # Get version info using git, with fallback to docs/conf.py\n    info = get_version_info_from_git()\n    if info is None:\n        info = get_version_info_from_docs_conf()\n\n    git_tag, git_hash = info\n\n    # Generate the file with the git and version info\n    file_data = \"\"\"\\\n// This file was generated by py/makeversionhdr.py\n#define MICROPY_GIT_TAG \"%s\"\n#define MICROPY_GIT_HASH \"%s\"\n#define MICROPY_BUILD_DATE \"%s\"\n\"\"\" % (\n        git_tag,\n        git_hash,\n        datetime.date.today().strftime(\"%Y-%m-%d\"),\n    )\n\n    # Check if the file contents changed from last time\n    write_file = True\n    if os.path.isfile(filename):\n        with open(filename, \"r\") as f:\n            existing_data = f.read()\n        if existing_data == file_data:\n            write_file = False\n\n    # Only write the file if we need to\n    if write_file:\n        print(\"GEN %s\" % filename)\n        with open(filename, \"w\") as f:\n            f.write(file_data)\n\n\nif __name__ == \"__main__\":\n    make_version_header(sys.argv[1])\n"
  },
  {
    "path": "py/malloc.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n#include \"py/mpstate.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_printf DEBUG_printf\n#else // don't print debugging info\n#define DEBUG_printf(...) (void)0\n#endif\n\n#if MICROPY_MEM_STATS\n#if !MICROPY_MALLOC_USES_ALLOCATED_SIZE\n#error MICROPY_MEM_STATS requires MICROPY_MALLOC_USES_ALLOCATED_SIZE\n#endif\n#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); }\n#endif\n\n#if MICROPY_ENABLE_GC\n#include \"py/gc.h\"\n\n// We redirect standard alloc functions to GC heap - just for the rest of\n// this module. In the rest of MicroPython source, system malloc can be\n// freely accessed - for interfacing with system and 3rd-party libs for\n// example. On the other hand, some (e.g. bare-metal) ports may use GC\n// heap as system heap, so, to avoid warnings, we do undef's first.\n#undef malloc\n#undef free\n#undef realloc\n#define malloc(b) gc_alloc((b), false)\n#define malloc_with_finaliser(b) gc_alloc((b), true)\n#define free gc_free\n#define realloc(ptr, n) gc_realloc(ptr, n, true)\n#define realloc_ext(ptr, n, mv) gc_realloc(ptr, n, mv)\n#else\n\n// GC is disabled.  Use system malloc/realloc/free.\n\n#if MICROPY_ENABLE_FINALISER\n#error MICROPY_ENABLE_FINALISER requires MICROPY_ENABLE_GC\n#endif\n\nSTATIC void *realloc_ext(void *ptr, size_t n_bytes, bool allow_move) {\n    if (allow_move) {\n        return realloc(ptr, n_bytes);\n    } else {\n        // We are asked to resize, but without moving the memory region pointed to\n        // by ptr.  Unless the underlying memory manager has special provision for\n        // this behaviour there is nothing we can do except fail to resize.\n        return NULL;\n    }\n}\n\n#endif // MICROPY_ENABLE_GC\n\nvoid *m_malloc(size_t num_bytes) {\n    void *ptr = malloc(num_bytes);\n    if (ptr == NULL && num_bytes != 0) {\n        m_malloc_fail(num_bytes);\n    }\n    #if MICROPY_MEM_STATS\n    MP_STATE_MEM(total_bytes_allocated) += num_bytes;\n    MP_STATE_MEM(current_bytes_allocated) += num_bytes;\n    UPDATE_PEAK();\n    #endif\n    DEBUG_printf(\"malloc %d : %p\\n\", num_bytes, ptr);\n    return ptr;\n}\n\nvoid *m_malloc_maybe(size_t num_bytes) {\n    void *ptr = malloc(num_bytes);\n    #if MICROPY_MEM_STATS\n    MP_STATE_MEM(total_bytes_allocated) += num_bytes;\n    MP_STATE_MEM(current_bytes_allocated) += num_bytes;\n    UPDATE_PEAK();\n    #endif\n    DEBUG_printf(\"malloc %d : %p\\n\", num_bytes, ptr);\n    return ptr;\n}\n\n#if MICROPY_ENABLE_FINALISER\nvoid *m_malloc_with_finaliser(size_t num_bytes) {\n    void *ptr = malloc_with_finaliser(num_bytes);\n    if (ptr == NULL && num_bytes != 0) {\n        m_malloc_fail(num_bytes);\n    }\n    #if MICROPY_MEM_STATS\n    MP_STATE_MEM(total_bytes_allocated) += num_bytes;\n    MP_STATE_MEM(current_bytes_allocated) += num_bytes;\n    UPDATE_PEAK();\n    #endif\n    DEBUG_printf(\"malloc %d : %p\\n\", num_bytes, ptr);\n    return ptr;\n}\n#endif\n\nvoid *m_malloc0(size_t num_bytes) {\n    void *ptr = m_malloc(num_bytes);\n    // If this config is set then the GC clears all memory, so we don't need to.\n    #if !MICROPY_GC_CONSERVATIVE_CLEAR\n    memset(ptr, 0, num_bytes);\n    #endif\n    return ptr;\n}\n\n#if MICROPY_MALLOC_USES_ALLOCATED_SIZE\nvoid *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes)\n#else\nvoid *m_realloc(void *ptr, size_t new_num_bytes)\n#endif\n{\n    void *new_ptr = realloc(ptr, new_num_bytes);\n    if (new_ptr == NULL && new_num_bytes != 0) {\n        m_malloc_fail(new_num_bytes);\n    }\n    #if MICROPY_MEM_STATS\n    // At first thought, \"Total bytes allocated\" should only grow,\n    // after all, it's *total*. But consider for example 2K block\n    // shrunk to 1K and then grown to 2K again. It's still 2K\n    // allocated total. If we process only positive increments,\n    // we'll count 3K.\n    size_t diff = new_num_bytes - old_num_bytes;\n    MP_STATE_MEM(total_bytes_allocated) += diff;\n    MP_STATE_MEM(current_bytes_allocated) += diff;\n    UPDATE_PEAK();\n    #endif\n    #if MICROPY_MALLOC_USES_ALLOCATED_SIZE\n    DEBUG_printf(\"realloc %p, %d, %d : %p\\n\", ptr, old_num_bytes, new_num_bytes, new_ptr);\n    #else\n    DEBUG_printf(\"realloc %p, %d : %p\\n\", ptr, new_num_bytes, new_ptr);\n    #endif\n    return new_ptr;\n}\n\n#if MICROPY_MALLOC_USES_ALLOCATED_SIZE\nvoid *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move)\n#else\nvoid *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move)\n#endif\n{\n    void *new_ptr = realloc_ext(ptr, new_num_bytes, allow_move);\n    #if MICROPY_MEM_STATS\n    // At first thought, \"Total bytes allocated\" should only grow,\n    // after all, it's *total*. But consider for example 2K block\n    // shrunk to 1K and then grown to 2K again. It's still 2K\n    // allocated total. If we process only positive increments,\n    // we'll count 3K.\n    // Also, don't count failed reallocs.\n    if (!(new_ptr == NULL && new_num_bytes != 0)) {\n        size_t diff = new_num_bytes - old_num_bytes;\n        MP_STATE_MEM(total_bytes_allocated) += diff;\n        MP_STATE_MEM(current_bytes_allocated) += diff;\n        UPDATE_PEAK();\n    }\n    #endif\n    #if MICROPY_MALLOC_USES_ALLOCATED_SIZE\n    DEBUG_printf(\"realloc %p, %d, %d : %p\\n\", ptr, old_num_bytes, new_num_bytes, new_ptr);\n    #else\n    DEBUG_printf(\"realloc %p, %d, %d : %p\\n\", ptr, new_num_bytes, new_ptr);\n    #endif\n    return new_ptr;\n}\n\n#if MICROPY_MALLOC_USES_ALLOCATED_SIZE\nvoid m_free(void *ptr, size_t num_bytes)\n#else\nvoid m_free(void *ptr)\n#endif\n{\n    free(ptr);\n    #if MICROPY_MEM_STATS\n    MP_STATE_MEM(current_bytes_allocated) -= num_bytes;\n    #endif\n    #if MICROPY_MALLOC_USES_ALLOCATED_SIZE\n    DEBUG_printf(\"free %p, %d\\n\", ptr, num_bytes);\n    #else\n    DEBUG_printf(\"free %p\\n\", ptr);\n    #endif\n}\n\n#if MICROPY_MEM_STATS\nsize_t m_get_total_bytes_allocated(void) {\n    return MP_STATE_MEM(total_bytes_allocated);\n}\n\nsize_t m_get_current_bytes_allocated(void) {\n    return MP_STATE_MEM(current_bytes_allocated);\n}\n\nsize_t m_get_peak_bytes_allocated(void) {\n    return MP_STATE_MEM(peak_bytes_allocated);\n}\n#endif\n"
  },
  {
    "path": "py/map.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_PRINT (1)\n#else // don't print debugging info\n#define DEBUG_PRINT (0)\n#define DEBUG_printf(...) (void)0\n#endif\n\n// This table of sizes is used to control the growth of hash tables.\n// The first set of sizes are chosen so the allocation fits exactly in a\n// 4-word GC block, and it's not so important for these small values to be\n// prime.  The latter sizes are prime and increase at an increasing rate.\nSTATIC const uint16_t hash_allocation_sizes[] = {\n    0, 2, 4, 6, 8, 10, 12, // +2\n    17, 23, 29, 37, 47, 59, 73, // *1.25\n    97, 127, 167, 223, 293, 389, 521, 691, 919, 1223, 1627, 2161, // *1.33\n    3229, 4831, 7243, 10861, 16273, 24407, 36607, 54907, // *1.5\n};\n\nSTATIC size_t get_hash_alloc_greater_or_equal_to(size_t x) {\n    for (size_t i = 0; i < MP_ARRAY_SIZE(hash_allocation_sizes); i++) {\n        if (hash_allocation_sizes[i] >= x) {\n            return hash_allocation_sizes[i];\n        }\n    }\n    // ran out of primes in the table!\n    // return something sensible, at least make it odd\n    return (x + x / 2) | 1;\n}\n\n/******************************************************************************/\n/* map                                                                        */\n\nvoid mp_map_init(mp_map_t *map, size_t n) {\n    if (n == 0) {\n        map->alloc = 0;\n        map->table = NULL;\n    } else {\n        map->alloc = n;\n        map->table = m_new0(mp_map_elem_t, map->alloc);\n    }\n    map->used = 0;\n    map->all_keys_are_qstrs = 1;\n    map->is_fixed = 0;\n    map->is_ordered = 0;\n}\n\nvoid mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table) {\n    map->alloc = n;\n    map->used = n;\n    map->all_keys_are_qstrs = 1;\n    map->is_fixed = 1;\n    map->is_ordered = 1;\n    map->table = (mp_map_elem_t *)table;\n}\n\n// Differentiate from mp_map_clear() - semantics is different\nvoid mp_map_deinit(mp_map_t *map) {\n    if (!map->is_fixed) {\n        m_del(mp_map_elem_t, map->table, map->alloc);\n    }\n    map->used = map->alloc = 0;\n}\n\nvoid mp_map_clear(mp_map_t *map) {\n    if (!map->is_fixed) {\n        m_del(mp_map_elem_t, map->table, map->alloc);\n    }\n    map->alloc = 0;\n    map->used = 0;\n    map->all_keys_are_qstrs = 1;\n    map->is_fixed = 0;\n    map->table = NULL;\n}\n\nSTATIC void mp_map_rehash(mp_map_t *map) {\n    size_t old_alloc = map->alloc;\n    size_t new_alloc = get_hash_alloc_greater_or_equal_to(map->alloc + 1);\n    DEBUG_printf(\"mp_map_rehash(%p): \" UINT_FMT \" -> \" UINT_FMT \"\\n\", map, old_alloc, new_alloc);\n    mp_map_elem_t *old_table = map->table;\n    mp_map_elem_t *new_table = m_new0(mp_map_elem_t, new_alloc);\n    // If we reach this point, table resizing succeeded, now we can edit the old map.\n    map->alloc = new_alloc;\n    map->used = 0;\n    map->all_keys_are_qstrs = 1;\n    map->table = new_table;\n    for (size_t i = 0; i < old_alloc; i++) {\n        if (old_table[i].key != MP_OBJ_NULL && old_table[i].key != MP_OBJ_SENTINEL) {\n            mp_map_lookup(map, old_table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = old_table[i].value;\n        }\n    }\n    m_del(mp_map_elem_t, old_table, old_alloc);\n}\n\n// MP_MAP_LOOKUP behaviour:\n//  - returns NULL if not found, else the slot it was found in with key,value non-null\n// MP_MAP_LOOKUP_ADD_IF_NOT_FOUND behaviour:\n//  - returns slot, with key non-null and value=MP_OBJ_NULL if it was added\n// MP_MAP_LOOKUP_REMOVE_IF_FOUND behaviour:\n//  - returns NULL if not found, else the slot if was found in with key null and value non-null\nmp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {\n    // If the map is a fixed array then we must only be called for a lookup\n    assert(!map->is_fixed || lookup_kind == MP_MAP_LOOKUP);\n\n    // Work out if we can compare just pointers\n    bool compare_only_ptrs = map->all_keys_are_qstrs;\n    if (compare_only_ptrs) {\n        if (mp_obj_is_qstr(index)) {\n            // Index is a qstr, so can just do ptr comparison.\n        } else if (mp_obj_is_type(index, &mp_type_str)) {\n            // Index is a non-interned string.\n            // We can either intern the string, or force a full equality comparison.\n            // We chose the latter, since interning costs time and potentially RAM,\n            // and it won't necessarily benefit subsequent calls because these calls\n            // most likely won't pass the newly-interned string.\n            compare_only_ptrs = false;\n        } else if (lookup_kind != MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {\n            // If we are not adding, then we can return straight away a failed\n            // lookup because we know that the index will never be found.\n            return NULL;\n        }\n    }\n\n    // if the map is an ordered array then we must do a brute force linear search\n    if (map->is_ordered) {\n        for (mp_map_elem_t *elem = &map->table[0], *top = &map->table[map->used]; elem < top; elem++) {\n            if (elem->key == index || (!compare_only_ptrs && mp_obj_equal(elem->key, index))) {\n                #if MICROPY_PY_COLLECTIONS_ORDEREDDICT\n                if (MP_UNLIKELY(lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND)) {\n                    // remove the found element by moving the rest of the array down\n                    mp_obj_t value = elem->value;\n                    --map->used;\n                    memmove(elem, elem + 1, (top - elem - 1) * sizeof(*elem));\n                    // put the found element after the end so the caller can access it if needed\n                    // note: caller must NULL the value so the GC can clean up (e.g. see dict_get_helper).\n                    elem = &map->table[map->used];\n                    elem->key = MP_OBJ_NULL;\n                    elem->value = value;\n                }\n                #endif\n                return elem;\n            }\n        }\n        #if MICROPY_PY_COLLECTIONS_ORDEREDDICT\n        if (MP_LIKELY(lookup_kind != MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)) {\n            return NULL;\n        }\n        if (map->used == map->alloc) {\n            // TODO: Alloc policy\n            map->alloc += 4;\n            map->table = m_renew(mp_map_elem_t, map->table, map->used, map->alloc);\n            mp_seq_clear(map->table, map->used, map->alloc, sizeof(*map->table));\n        }\n        mp_map_elem_t *elem = map->table + map->used++;\n        elem->key = index;\n        if (!mp_obj_is_qstr(index)) {\n            map->all_keys_are_qstrs = 0;\n        }\n        return elem;\n        #else\n        return NULL;\n        #endif\n    }\n\n    // map is a hash table (not an ordered array), so do a hash lookup\n\n    if (map->alloc == 0) {\n        if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {\n            mp_map_rehash(map);\n        } else {\n            return NULL;\n        }\n    }\n\n    // get hash of index, with fast path for common case of qstr\n    mp_uint_t hash;\n    if (mp_obj_is_qstr(index)) {\n        hash = qstr_hash(MP_OBJ_QSTR_VALUE(index));\n    } else {\n        hash = MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, index));\n    }\n\n    size_t pos = hash % map->alloc;\n    size_t start_pos = pos;\n    mp_map_elem_t *avail_slot = NULL;\n    for (;;) {\n        mp_map_elem_t *slot = &map->table[pos];\n        if (slot->key == MP_OBJ_NULL) {\n            // found NULL slot, so index is not in table\n            if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {\n                map->used += 1;\n                if (avail_slot == NULL) {\n                    avail_slot = slot;\n                }\n                avail_slot->key = index;\n                avail_slot->value = MP_OBJ_NULL;\n                if (!mp_obj_is_qstr(index)) {\n                    map->all_keys_are_qstrs = 0;\n                }\n                return avail_slot;\n            } else {\n                return NULL;\n            }\n        } else if (slot->key == MP_OBJ_SENTINEL) {\n            // found deleted slot, remember for later\n            if (avail_slot == NULL) {\n                avail_slot = slot;\n            }\n        } else if (slot->key == index || (!compare_only_ptrs && mp_obj_equal(slot->key, index))) {\n            // found index\n            // Note: CPython does not replace the index; try x={True:'true'};x[1]='one';x\n            if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {\n                // delete element in this slot\n                map->used--;\n                if (map->table[(pos + 1) % map->alloc].key == MP_OBJ_NULL) {\n                    // optimisation if next slot is empty\n                    slot->key = MP_OBJ_NULL;\n                } else {\n                    slot->key = MP_OBJ_SENTINEL;\n                }\n                // keep slot->value so that caller can access it if needed\n            }\n            return slot;\n        }\n\n        // not yet found, keep searching in this table\n        pos = (pos + 1) % map->alloc;\n\n        if (pos == start_pos) {\n            // search got back to starting position, so index is not in table\n            if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {\n                if (avail_slot != NULL) {\n                    // there was an available slot, so use that\n                    map->used++;\n                    avail_slot->key = index;\n                    avail_slot->value = MP_OBJ_NULL;\n                    if (!mp_obj_is_qstr(index)) {\n                        map->all_keys_are_qstrs = 0;\n                    }\n                    return avail_slot;\n                } else {\n                    // not enough room in table, rehash it\n                    mp_map_rehash(map);\n                    // restart the search for the new element\n                    start_pos = pos = hash % map->alloc;\n                }\n            } else {\n                return NULL;\n            }\n        }\n    }\n}\n\n/******************************************************************************/\n/* set                                                                        */\n\n#if MICROPY_PY_BUILTINS_SET\n\nvoid mp_set_init(mp_set_t *set, size_t n) {\n    set->alloc = n;\n    set->used = 0;\n    set->table = m_new0(mp_obj_t, set->alloc);\n}\n\nSTATIC void mp_set_rehash(mp_set_t *set) {\n    size_t old_alloc = set->alloc;\n    mp_obj_t *old_table = set->table;\n    set->alloc = get_hash_alloc_greater_or_equal_to(set->alloc + 1);\n    set->used = 0;\n    set->table = m_new0(mp_obj_t, set->alloc);\n    for (size_t i = 0; i < old_alloc; i++) {\n        if (old_table[i] != MP_OBJ_NULL && old_table[i] != MP_OBJ_SENTINEL) {\n            mp_set_lookup(set, old_table[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);\n        }\n    }\n    m_del(mp_obj_t, old_table, old_alloc);\n}\n\nmp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {\n    // Note: lookup_kind can be MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND which\n    // is handled by using bitwise operations.\n\n    if (set->alloc == 0) {\n        if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {\n            mp_set_rehash(set);\n        } else {\n            return MP_OBJ_NULL;\n        }\n    }\n    mp_uint_t hash = MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, index));\n    size_t pos = hash % set->alloc;\n    size_t start_pos = pos;\n    mp_obj_t *avail_slot = NULL;\n    for (;;) {\n        mp_obj_t elem = set->table[pos];\n        if (elem == MP_OBJ_NULL) {\n            // found NULL slot, so index is not in table\n            if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {\n                if (avail_slot == NULL) {\n                    avail_slot = &set->table[pos];\n                }\n                set->used++;\n                *avail_slot = index;\n                return index;\n            } else {\n                return MP_OBJ_NULL;\n            }\n        } else if (elem == MP_OBJ_SENTINEL) {\n            // found deleted slot, remember for later\n            if (avail_slot == NULL) {\n                avail_slot = &set->table[pos];\n            }\n        } else if (mp_obj_equal(elem, index)) {\n            // found index\n            if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) {\n                // delete element\n                set->used--;\n                if (set->table[(pos + 1) % set->alloc] == MP_OBJ_NULL) {\n                    // optimisation if next slot is empty\n                    set->table[pos] = MP_OBJ_NULL;\n                } else {\n                    set->table[pos] = MP_OBJ_SENTINEL;\n                }\n            }\n            return elem;\n        }\n\n        // not yet found, keep searching in this table\n        pos = (pos + 1) % set->alloc;\n\n        if (pos == start_pos) {\n            // search got back to starting position, so index is not in table\n            if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {\n                if (avail_slot != NULL) {\n                    // there was an available slot, so use that\n                    set->used++;\n                    *avail_slot = index;\n                    return index;\n                } else {\n                    // not enough room in table, rehash it\n                    mp_set_rehash(set);\n                    // restart the search for the new element\n                    start_pos = pos = hash % set->alloc;\n                }\n            } else {\n                return MP_OBJ_NULL;\n            }\n        }\n    }\n}\n\nmp_obj_t mp_set_remove_first(mp_set_t *set) {\n    for (size_t pos = 0; pos < set->alloc; pos++) {\n        if (mp_set_slot_is_filled(set, pos)) {\n            mp_obj_t elem = set->table[pos];\n            // delete element\n            set->used--;\n            if (set->table[(pos + 1) % set->alloc] == MP_OBJ_NULL) {\n                // optimisation if next slot is empty\n                set->table[pos] = MP_OBJ_NULL;\n            } else {\n                set->table[pos] = MP_OBJ_SENTINEL;\n            }\n            return elem;\n        }\n    }\n    return MP_OBJ_NULL;\n}\n\nvoid mp_set_clear(mp_set_t *set) {\n    m_del(mp_obj_t, set->table, set->alloc);\n    set->alloc = 0;\n    set->used = 0;\n    set->table = NULL;\n}\n\n#endif // MICROPY_PY_BUILTINS_SET\n\n#if defined(DEBUG_PRINT) && DEBUG_PRINT\nvoid mp_map_dump(mp_map_t *map) {\n    for (size_t i = 0; i < map->alloc; i++) {\n        if (map->table[i].key != MP_OBJ_NULL) {\n            mp_obj_print(map->table[i].key, PRINT_REPR);\n        } else {\n            DEBUG_printf(\"(nil)\");\n        }\n        DEBUG_printf(\": %p\\n\", map->table[i].value);\n    }\n    DEBUG_printf(\"---\\n\");\n}\n#endif\n"
  },
  {
    "path": "py/misc.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_MISC_H\n#define MICROPY_INCLUDED_PY_MISC_H\n\n// a mini library of useful types and functions\n\n/** types *******************************************************/\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <stddef.h>\n\ntypedef unsigned char byte;\ntypedef unsigned int uint;\n\n/** generic ops *************************************************/\n\n#ifndef MIN\n#define MIN(x, y) ((x) < (y) ? (x) : (y))\n#endif\n#ifndef MAX\n#define MAX(x, y) ((x) > (y) ? (x) : (y))\n#endif\n\n// Classical double-indirection stringification of preprocessor macro's value\n#define MP_STRINGIFY_HELPER(x) #x\n#define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x)\n\n// Static assertion macro\n#define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)]))\n\n/** memory allocation ******************************************/\n\n// TODO make a lazy m_renew that can increase by a smaller amount than requested (but by at least 1 more element)\n\n#define m_new(type, num) ((type *)(m_malloc(sizeof(type) * (num))))\n#define m_new_maybe(type, num) ((type *)(m_malloc_maybe(sizeof(type) * (num))))\n#define m_new0(type, num) ((type *)(m_malloc0(sizeof(type) * (num))))\n#define m_new_obj(type) (m_new(type, 1))\n#define m_new_obj_maybe(type) (m_new_maybe(type, 1))\n#define m_new_obj_var(obj_type, var_type, var_num) ((obj_type *)m_malloc(sizeof(obj_type) + sizeof(var_type) * (var_num)))\n#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)))\n#if MICROPY_ENABLE_FINALISER\n#define m_new_obj_with_finaliser(type) ((type *)(m_malloc_with_finaliser(sizeof(type))))\n#define m_new_obj_var_with_finaliser(type, var_type, var_num) ((type *)m_malloc_with_finaliser(sizeof(type) + sizeof(var_type) * (var_num)))\n#else\n#define m_new_obj_with_finaliser(type) m_new_obj(type)\n#define m_new_obj_var_with_finaliser(type, var_type, var_num) m_new_obj_var(type, var_type, var_num)\n#endif\n#if MICROPY_MALLOC_USES_ALLOCATED_SIZE\n#define m_renew(type, ptr, old_num, new_num) ((type *)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num))))\n#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))))\n#define m_del(type, ptr, num) m_free(ptr, sizeof(type) * (num))\n#define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num)))\n#else\n#define m_renew(type, ptr, old_num, new_num) ((type *)(m_realloc((ptr), sizeof(type) * (new_num))))\n#define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type *)(m_realloc_maybe((ptr), sizeof(type) * (new_num), (allow_move))))\n#define m_del(type, ptr, num) ((void)(num), m_free(ptr))\n#define m_del_var(obj_type, var_type, var_num, ptr) ((void)(var_num), m_free(ptr))\n#endif\n#define m_del_obj(type, ptr) (m_del(type, ptr, 1))\n\nvoid *m_malloc(size_t num_bytes);\nvoid *m_malloc_maybe(size_t num_bytes);\nvoid *m_malloc_with_finaliser(size_t num_bytes);\nvoid *m_malloc0(size_t num_bytes);\n#if MICROPY_MALLOC_USES_ALLOCATED_SIZE\nvoid *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes);\nvoid *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move);\nvoid m_free(void *ptr, size_t num_bytes);\n#else\nvoid *m_realloc(void *ptr, size_t new_num_bytes);\nvoid *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move);\nvoid m_free(void *ptr);\n#endif\nNORETURN void m_malloc_fail(size_t num_bytes);\n\n#if MICROPY_MEM_STATS\nsize_t m_get_total_bytes_allocated(void);\nsize_t m_get_current_bytes_allocated(void);\nsize_t m_get_peak_bytes_allocated(void);\n#endif\n\n/** array helpers ***********************************************/\n\n// get the number of elements in a fixed-size array\n#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))\n\n// align ptr to the nearest multiple of \"alignment\"\n#define MP_ALIGN(ptr, alignment) (void *)(((uintptr_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1))\n\n/** unichar / UTF-8 *********************************************/\n\n#if MICROPY_PY_BUILTINS_STR_UNICODE\n// with unicode enabled we need a type which can fit chars up to 0x10ffff\ntypedef uint32_t unichar;\n#else\n// without unicode enabled we can only need to fit chars up to 0xff\n// (on 16-bit archs uint is 16-bits and more efficient than uint32_t)\ntypedef uint unichar;\n#endif\n\n#if MICROPY_PY_BUILTINS_STR_UNICODE\nunichar utf8_get_char(const byte *s);\nconst byte *utf8_next_char(const byte *s);\nsize_t utf8_charlen(const byte *str, size_t len);\n#else\nstatic inline unichar utf8_get_char(const byte *s) {\n    return *s;\n}\nstatic inline const byte *utf8_next_char(const byte *s) {\n    return s + 1;\n}\nstatic inline size_t utf8_charlen(const byte *str, size_t len) {\n    (void)str;\n    return len;\n}\n#endif\n\nbool unichar_isspace(unichar c);\nbool unichar_isalpha(unichar c);\nbool unichar_isprint(unichar c);\nbool unichar_isdigit(unichar c);\nbool unichar_isxdigit(unichar c);\nbool unichar_isident(unichar c);\nbool unichar_isalnum(unichar c);\nbool unichar_isupper(unichar c);\nbool unichar_islower(unichar c);\nunichar unichar_tolower(unichar c);\nunichar unichar_toupper(unichar c);\nmp_uint_t unichar_xdigit_value(unichar c);\n#define UTF8_IS_NONASCII(ch) ((ch) & 0x80)\n#define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80)\n\n/** variable string *********************************************/\n\ntypedef struct _vstr_t {\n    size_t alloc;\n    size_t len;\n    char *buf;\n    bool fixed_buf : 1;\n} vstr_t;\n\n// convenience macro to declare a vstr with a fixed size buffer on the stack\n#define VSTR_FIXED(vstr, alloc) vstr_t vstr; char vstr##_buf[(alloc)]; vstr_init_fixed_buf(&vstr, (alloc), vstr##_buf);\n\nvoid vstr_init(vstr_t *vstr, size_t alloc);\nvoid vstr_init_len(vstr_t *vstr, size_t len);\nvoid vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf);\nstruct _mp_print_t;\nvoid vstr_init_print(vstr_t *vstr, size_t alloc, struct _mp_print_t *print);\nvoid vstr_clear(vstr_t *vstr);\nvstr_t *vstr_new(size_t alloc);\nvoid vstr_free(vstr_t *vstr);\nstatic inline void vstr_reset(vstr_t *vstr) {\n    vstr->len = 0;\n}\nstatic inline char *vstr_str(vstr_t *vstr) {\n    return vstr->buf;\n}\nstatic inline size_t vstr_len(vstr_t *vstr) {\n    return vstr->len;\n}\nvoid vstr_hint_size(vstr_t *vstr, size_t size);\nchar *vstr_extend(vstr_t *vstr, size_t size);\nchar *vstr_add_len(vstr_t *vstr, size_t len);\nchar *vstr_null_terminated_str(vstr_t *vstr);\nvoid vstr_add_byte(vstr_t *vstr, byte v);\nvoid vstr_add_char(vstr_t *vstr, unichar chr);\nvoid vstr_add_str(vstr_t *vstr, const char *str);\nvoid vstr_add_strn(vstr_t *vstr, const char *str, size_t len);\nvoid vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b);\nvoid vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr);\nvoid vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut);\nvoid vstr_cut_tail_bytes(vstr_t *vstr, size_t bytes_to_cut);\nvoid vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut);\nvoid vstr_printf(vstr_t *vstr, const char *fmt, ...);\n\n/** non-dynamic size-bounded variable buffer/string *************/\n\n#define CHECKBUF(buf, max_size) char buf[max_size + 1]; size_t buf##_len = max_size; char *buf##_p = buf;\n#define CHECKBUF_RESET(buf, max_size) buf##_len = max_size; buf##_p = buf;\n#define CHECKBUF_APPEND(buf, src, src_len) \\\n    { size_t l = MIN(src_len, buf##_len); \\\n      memcpy(buf##_p, src, l); \\\n      buf##_len -= l; \\\n      buf##_p += l; }\n#define CHECKBUF_APPEND_0(buf) { *buf##_p = 0; }\n#define CHECKBUF_LEN(buf) (buf##_p - buf)\n\n#ifdef va_start\nvoid vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap);\n#endif\n\n// Debugging helpers\nint DEBUG_printf(const char *fmt, ...);\n\nextern mp_uint_t mp_verbose_flag;\n\n/** float internals *************/\n\n#if MICROPY_PY_BUILTINS_FLOAT\n\n#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE\n#define MP_FLOAT_EXP_BITS (11)\n#define MP_FLOAT_FRAC_BITS (52)\ntypedef uint64_t mp_float_uint_t;\n#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n#define MP_FLOAT_EXP_BITS (8)\n#define MP_FLOAT_FRAC_BITS (23)\ntypedef uint32_t mp_float_uint_t;\n#endif\n\n#define MP_FLOAT_EXP_BIAS ((1 << (MP_FLOAT_EXP_BITS - 1)) - 1)\n\ntypedef union _mp_float_union_t {\n    mp_float_t f;\n    #if MP_ENDIANNESS_LITTLE\n    struct {\n        mp_float_uint_t frc : MP_FLOAT_FRAC_BITS;\n        mp_float_uint_t exp : MP_FLOAT_EXP_BITS;\n        mp_float_uint_t sgn : 1;\n    } p;\n    #else\n    struct {\n        mp_float_uint_t sgn : 1;\n        mp_float_uint_t exp : MP_FLOAT_EXP_BITS;\n        mp_float_uint_t frc : MP_FLOAT_FRAC_BITS;\n    } p;\n    #endif\n    mp_float_uint_t i;\n} mp_float_union_t;\n\n#endif // MICROPY_PY_BUILTINS_FLOAT\n\n/** ROM string compression *************/\n\n#if MICROPY_ROM_TEXT_COMPRESSION\n\n#ifdef NO_QSTR\n\n// Compression enabled but doing QSTR extraction.\n// So leave MP_COMPRESSED_ROM_TEXT in place for makeqstrdefs.py / makecompresseddata.py to find them.\n\n#else\n\n// Compression enabled and doing a regular build.\n// Map MP_COMPRESSED_ROM_TEXT to the compressed strings.\n\n// Force usage of the MP_ERROR_TEXT macro by requiring an opaque type.\ntypedef struct {\n    #ifdef __clang__\n    // Fix \"error: empty struct has size 0 in C, size 1 in C++\".\n    char dummy;\n    #endif\n} *mp_rom_error_text_t;\n\n#include <string.h>\n\ninline __attribute__((always_inline)) const char *MP_COMPRESSED_ROM_TEXT(const char *msg) {\n    // \"genhdr/compressed.data.h\" contains an invocation of the MP_MATCH_COMPRESSED macro for each compressed string.\n    // The giant if(strcmp) tree is optimized by the compiler, which turns this into a direct return of the compressed data.\n    #define MP_MATCH_COMPRESSED(a, b) if (strcmp(msg, a) == 0) { return b; } else\n\n    // It also contains a single invocation of the MP_COMPRESSED_DATA macro, we don't need that here.\n    #define MP_COMPRESSED_DATA(x)\n\n    #include \"genhdr/compressed.data.h\"\n\n#undef MP_COMPRESSED_DATA\n#undef MP_MATCH_COMPRESSED\n\n    return msg;\n}\n\n#endif\n\n#else\n\n// Compression not enabled, just make it a no-op.\n\ntypedef const char *mp_rom_error_text_t;\n#define MP_COMPRESSED_ROM_TEXT(x) x\n\n#endif // MICROPY_ROM_TEXT_COMPRESSION\n\n// Might add more types of compressed text in the future.\n// For now, forward directly to MP_COMPRESSED_ROM_TEXT.\n#define MP_ERROR_TEXT(x) (mp_rom_error_text_t)MP_COMPRESSED_ROM_TEXT(x)\n\n#endif // MICROPY_INCLUDED_PY_MISC_H\n"
  },
  {
    "path": "py/mkenv.mk",
    "content": "ifneq ($(lastword a b),b)\n$(error These Makefiles require make 3.81 or newer)\nendif\n\n# Set TOP to be the path to get from the current directory (where make was\n# invoked) to the top of the tree. $(lastword $(MAKEFILE_LIST)) returns\n# the name of this makefile relative to where make was invoked.\n#\n# We assume that this file is in the py directory so we use $(dir ) twice\n# to get to the top of the tree.\n\nTHIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))\nTOP := $(patsubst %/py/mkenv.mk,%,$(THIS_MAKEFILE))\n\n# Turn on increased build verbosity by defining BUILD_VERBOSE in your main\n# Makefile or in your environment. You can also use V=1 on the make command\n# line.\n\nifeq (\"$(origin V)\", \"command line\")\nBUILD_VERBOSE=$(V)\nendif\nifndef BUILD_VERBOSE\nBUILD_VERBOSE = 0\nendif\nifeq ($(BUILD_VERBOSE),0)\nQ = @\nelse\nQ =\nendif\n# Since this is a new feature, advertise it\nifeq ($(BUILD_VERBOSE),0)\n$(info Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.)\nendif\n\n# default settings; can be overridden in main Makefile\n\nPY_SRC ?= $(TOP)/py\nBUILD ?= build\n\nRM = rm\nECHO = @echo\nCP = cp\nMKDIR = mkdir\nSED = sed\nCAT = cat\nTOUCH = touch\nPYTHON = python3\n\nAS = $(CROSS_COMPILE)as\nCC = $(CROSS_COMPILE)gcc\nCXX = $(CROSS_COMPILE)g++\nGDB = $(CROSS_COMPILE)gdb\nLD = $(CROSS_COMPILE)ld\nOBJCOPY = $(CROSS_COMPILE)objcopy\nSIZE = $(CROSS_COMPILE)size\nSTRIP = $(CROSS_COMPILE)strip\nAR = $(CROSS_COMPILE)ar\n\nMAKE_MANIFEST = $(PYTHON) $(TOP)/tools/makemanifest.py\nMAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py\nMPY_CROSS = $(TOP)/mpy-cross/mpy-cross\nMPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py\n\nMPY_LIB_DIR = $(TOP)/../micropython-lib\n\nall:\n.PHONY: all\n\n.DELETE_ON_ERROR:\n\nMKENV_INCLUDED = 1\n"
  },
  {
    "path": "py/mkrules.mk",
    "content": "ifneq ($(MKENV_INCLUDED),1)\n# We assume that mkenv is in the same directory as this file.\nTHIS_MAKEFILE = $(lastword $(MAKEFILE_LIST))\ninclude $(dir $(THIS_MAKEFILE))mkenv.mk\nendif\n\n# Extra deps that need to happen before object compilation.\nOBJ_EXTRA_ORDER_DEPS =\n\nifeq ($(MICROPY_ROM_TEXT_COMPRESSION),1)\n# If compression is enabled, trigger the build of compressed.data.h...\nOBJ_EXTRA_ORDER_DEPS += $(HEADER_BUILD)/compressed.data.h\n# ...and enable the MP_COMPRESSED_ROM_TEXT macro (used by MP_ERROR_TEXT).\nCFLAGS += -DMICROPY_ROM_TEXT_COMPRESSION=1\nendif\n\n# QSTR generation uses the same CFLAGS, with these modifications.\nQSTR_GEN_FLAGS = -DNO_QSTR -I$(BUILD)/tmp\n# Note: := to force evalulation immediately.\nQSTR_GEN_CFLAGS := $(CFLAGS)\nQSTR_GEN_CFLAGS += $(QSTR_GEN_FLAGS)\nQSTR_GEN_CXXFLAGS := $(CXXFLAGS)\nQSTR_GEN_CXXFLAGS += $(QSTR_GEN_FLAGS)\n\n# This file expects that OBJ contains a list of all of the object files.\n# The directory portion of each object file is used to locate the source\n# and should not contain any ..'s but rather be relative to the top of the\n# tree.\n#\n# So for example, py/map.c would have an object file name py/map.o\n# The object files will go into the build directory and mantain the same\n# directory structure as the source tree. So the final dependency will look\n# like this:\n#\n# build/py/map.o: py/map.c\n#\n# We set vpath to point to the top of the tree so that the source files\n# can be located. By following this scheme, it allows a single build rule\n# to be used to compile all .c files.\n\nvpath %.S . $(TOP) $(USER_C_MODULES)\n$(BUILD)/%.o: %.S\n\t$(ECHO) \"CC $<\"\n\t$(Q)$(CC) $(CFLAGS) -c -o $@ $<\n\nvpath %.s . $(TOP) $(USER_C_MODULES)\n$(BUILD)/%.o: %.s\n\t$(ECHO) \"AS $<\"\n\t$(Q)$(AS) -o $@ $<\n\ndefine compile_c\n$(ECHO) \"CC $<\"\n$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $<\n@# The following fixes the dependency file.\n@# See http://make.paulandlesley.org/autodep.html for details.\n@# Regex adjusted from the above to play better with Windows paths, etc.\n@$(CP) $(@:.o=.d) $(@:.o=.P); \\\n  $(SED) -e 's/#.*//' -e 's/^.*:  *//' -e 's/ *\\\\$$//' \\\n      -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \\\n  $(RM) -f $(@:.o=.d)\nendef\n\ndefine compile_cxx\n$(ECHO) \"CXX $<\"\n$(Q)$(CXX) $(CXXFLAGS) -c -MD -o $@ $<\n@# The following fixes the dependency file.\n@# See http://make.paulandlesley.org/autodep.html for details.\n@# Regex adjusted from the above to play better with Windows paths, etc.\n@$(CP) $(@:.o=.d) $(@:.o=.P); \\\n  $(SED) -e 's/#.*//' -e 's/^.*:  *//' -e 's/ *\\\\$$//' \\\n      -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \\\n  $(RM) -f $(@:.o=.d)\nendef\n\nvpath %.c . $(TOP) $(USER_C_MODULES)\n$(BUILD)/%.o: %.c\n\t$(call compile_c)\n\nvpath %.c . $(TOP) $(USER_C_MODULES)\n\nvpath %.cpp . $(TOP) $(USER_C_MODULES)\n$(BUILD)/%.o: %.cpp\n\t$(call compile_cxx)\n\n$(BUILD)/%.pp: %.c\n\t$(ECHO) \"PreProcess $<\"\n\t$(Q)$(CPP) $(CFLAGS) -Wp,-C,-dD,-dI -o $@ $<\n\n# The following rule uses | to create an order only prerequisite. Order only\n# prerequisites only get built if they don't exist. They don't cause timestamp\n# checking to be performed.\n#\n# We don't know which source files actually need the generated.h (since\n# it is #included from str.h). The compiler generated dependencies will cause\n# the right .o's to get recompiled if the generated.h file changes. Adding\n# an order-only dependency to all of the .o's will cause the generated .h\n# to get built before we try to compile any of them.\n$(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h $(OBJ_EXTRA_ORDER_DEPS)\n\n# The logic for qstr regeneration (applied by makeqstrdefs.py) is:\n# - if anything in QSTR_GLOBAL_DEPENDENCIES is newer, then process all source files ($^)\n# - else, if list of newer prerequisites ($?) is not empty, then process just these ($?)\n# - else, process all source files ($^) [this covers \"make -B\" which can set $? to empty]\n# See more information about this process in docs/develop/qstr.rst.\n$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(QSTR_GLOBAL_REQUIREMENTS)\n\t$(ECHO) \"GEN $@\"\n\t$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py pp $(CPP) output $(HEADER_BUILD)/qstr.i.last cflags $(QSTR_GEN_CFLAGS) cxxflags $(QSTR_GEN_CXXFLAGS) sources $^ dependencies $(QSTR_GLOBAL_DEPENDENCIES) changed_sources $?\n\n$(HEADER_BUILD)/qstr.split: $(HEADER_BUILD)/qstr.i.last\n\t$(ECHO) \"GEN $@\"\n\t$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py split qstr $< $(HEADER_BUILD)/qstr _\n\t$(Q)$(TOUCH) $@\n\n$(QSTR_DEFS_COLLECTED): $(HEADER_BUILD)/qstr.split\n\t$(ECHO) \"GEN $@\"\n\t$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py cat qstr _ $(HEADER_BUILD)/qstr $@\n\n# Compressed error strings.\n$(HEADER_BUILD)/compressed.split: $(HEADER_BUILD)/qstr.i.last\n\t$(ECHO) \"GEN $@\"\n\t$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py split compress $< $(HEADER_BUILD)/compress _\n\t$(Q)$(TOUCH) $@\n\n$(HEADER_BUILD)/compressed.collected: $(HEADER_BUILD)/compressed.split\n\t$(ECHO) \"GEN $@\"\n\t$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py cat compress _ $(HEADER_BUILD)/compress $@\n\n# $(sort $(var)) removes duplicates\n#\n# The net effect of this, is it causes the objects to depend on the\n# object directories (but only for existence), and the object directories\n# will be created if they don't exist.\nOBJ_DIRS = $(sort $(dir $(OBJ)))\n$(OBJ): | $(OBJ_DIRS)\n$(OBJ_DIRS):\n\t$(MKDIR) -p $@\n\n$(HEADER_BUILD):\n\t$(MKDIR) -p $@\n\nifneq ($(FROZEN_MANIFEST),)\n# to build frozen_content.c from a manifest\n$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h\n\t$(Q)$(MAKE_MANIFEST) -o $@ -v \"MPY_DIR=$(TOP)\" -v \"MPY_LIB_DIR=$(MPY_LIB_DIR)\" -v \"PORT_DIR=$(shell pwd)\" -v \"BOARD_DIR=$(BOARD_DIR)\" -b \"$(BUILD)\" $(if $(MPY_CROSS_FLAGS),-f\"$(MPY_CROSS_FLAGS)\",) $(FROZEN_MANIFEST)\n\nifneq ($(FROZEN_DIR),)\n$(error FROZEN_DIR cannot be used in conjunction with FROZEN_MANIFEST)\nendif\n\nifneq ($(FROZEN_MPY_DIR),)\n$(error FROZEN_MPY_DIR cannot be used in conjunction with FROZEN_MANIFEST)\nendif\nendif\n\nifneq ($(FROZEN_DIR),)\n$(info Warning: FROZEN_DIR is deprecated in favour of FROZEN_MANIFEST)\n$(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS)\n\t$(ECHO) \"GEN $@\"\n\t$(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@\nendif\n\nifneq ($(FROZEN_MPY_DIR),)\n$(info Warning: FROZEN_MPY_DIR is deprecated in favour of FROZEN_MANIFEST)\n# make a list of all the .py files that need compiling and freezing\nFROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==')\nFROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy))\n\n# to build .mpy files from .py files\n$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py\n\t@$(ECHO) \"MPY $<\"\n\t$(Q)$(MKDIR) -p $(dir $@)\n\t$(Q)$(MPY_CROSS) -o $@ -s $(<:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $<\n\n# to build frozen_mpy.c from all .mpy files\n$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h\n\t@$(ECHO) \"GEN $@\"\n\t$(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@\nendif\n\nifneq ($(PROG),)\n# Build a standalone executable (unix does this)\n\nall: $(PROG)\n\n$(PROG): $(OBJ)\n\t$(ECHO) \"LINK $@\"\n# Do not pass COPT here - it's *C* compiler optimizations. For example,\n# we may want to compile using Thumb, but link with non-Thumb libc.\n\t$(Q)$(CC) -o $@ $^ $(LIB) $(LDFLAGS)\nifndef DEBUG\n\t$(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)\nendif\n\t$(Q)$(SIZE) $$(find $(BUILD) -path \"$(BUILD)/build/frozen*.o\") $(PROG)\n\nclean: clean-prog\nclean-prog:\n\t$(RM) -f $(PROG)\n\t$(RM) -f $(PROG).map\n\n.PHONY: clean-prog\nendif\n\nsubmodules:\n\t$(ECHO) \"Updating submodules: $(GIT_SUBMODULES)\"\nifneq ($(GIT_SUBMODULES),)\n\t$(Q)git submodule update --init $(addprefix $(TOP)/,$(GIT_SUBMODULES))\nendif\n.PHONY: submodules\n\nLIBMICROPYTHON = libmicropython.a\n\n# We can execute extra commands after library creation using\n# LIBMICROPYTHON_EXTRA_CMD. This may be needed e.g. to integrate\n# with 3rd-party projects which don't have proper dependency\n# tracking. Then LIBMICROPYTHON_EXTRA_CMD can e.g. touch some\n# other file to cause needed effect, e.g. relinking with new lib.\nlib $(LIBMICROPYTHON): $(OBJ)\n\t$(AR) rcs $(LIBMICROPYTHON) $^\n\t$(LIBMICROPYTHON_EXTRA_CMD)\n\nclean:\n\t$(RM) -rf $(BUILD) $(CLEAN_EXTRA)\n.PHONY: clean\n\n# Clean every non-git file from FROZEN_DIR/FROZEN_MPY_DIR, but making a backup.\n# We run rmdir below to avoid empty backup dir (it will silently fail if backup\n# is non-empty).\nclean-frozen:\n\tif [ -n \"$(FROZEN_MPY_DIR)\" ]; then \\\n\tbackup_dir=$(FROZEN_MPY_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \\\n\tcd $(FROZEN_MPY_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \\\n\t| xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \\\n\trmdir ../$$backup_dir 2>/dev/null || true; \\\n\tgit clean -d -f .; \\\n\tfi\n\n\tif [ -n \"$(FROZEN_DIR)\" ]; then \\\n\tbackup_dir=$(FROZEN_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \\\n\tcd $(FROZEN_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \\\n\t| xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \\\n\trmdir ../$$backup_dir 2>/dev/null || true; \\\n\tgit clean -d -f .; \\\n\tfi\n.PHONY: clean-frozen\n\nprint-cfg:\n\t$(ECHO) \"PY_SRC = $(PY_SRC)\"\n\t$(ECHO) \"BUILD  = $(BUILD)\"\n\t$(ECHO) \"OBJ    = $(OBJ)\"\n.PHONY: print-cfg\n\nprint-def:\n\t@$(ECHO) \"The following defines are built into the $(CC) compiler\"\n\t$(TOUCH) __empty__.c\n\t@$(CC) -E -Wp,-dM __empty__.c\n\t@$(RM) -f __empty__.c\n\n-include $(OBJ:.o=.P)\n"
  },
  {
    "path": "py/modarray.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/builtin.h\"\n\n#if MICROPY_PY_ARRAY\n\nSTATIC const mp_rom_map_elem_t mp_module_array_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uarray) },\n    { MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_type_array) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_array_globals, mp_module_array_globals_table);\n\nconst mp_obj_module_t mp_module_uarray = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_array_globals,\n};\n\nMP_REGISTER_MODULE(MP_QSTR_uarray, mp_module_uarray, MICROPY_PY_ARRAY);\n\n#endif\n"
  },
  {
    "path": "py/modbuiltins.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <assert.h>\n\n#include \"py/smallint.h\"\n#include \"py/objint.h\"\n#include \"py/objstr.h\"\n#include \"py/objtype.h\"\n#include \"py/runtime.h\"\n#include \"py/builtin.h\"\n#include \"py/stream.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT\n#include <math.h>\n#endif\n\n#if MICROPY_PY_IO\nextern struct _mp_dummy_t mp_sys_stdout_obj; // type is irrelevant, just need pointer\n#endif\n\n// args[0] is function from class body\n// args[1] is class name\n// args[2:] are base objects\nSTATIC mp_obj_t mp_builtin___build_class__(size_t n_args, const mp_obj_t *args) {\n    assert(2 <= n_args);\n\n    // set the new classes __locals__ object\n    mp_obj_dict_t *old_locals = mp_locals_get();\n    mp_obj_t class_locals = mp_obj_new_dict(0);\n    mp_locals_set(MP_OBJ_TO_PTR(class_locals));\n\n    // call the class code\n    mp_obj_t cell = mp_call_function_0(args[0]);\n\n    // restore old __locals__ object\n    mp_locals_set(old_locals);\n\n    // get the class type (meta object) from the base objects\n    mp_obj_t meta;\n    if (n_args == 2) {\n        // no explicit bases, so use 'type'\n        meta = MP_OBJ_FROM_PTR(&mp_type_type);\n    } else {\n        // use type of first base object\n        meta = MP_OBJ_FROM_PTR(mp_obj_get_type(args[2]));\n    }\n\n    // TODO do proper metaclass resolution for multiple base objects\n\n    // create the new class using a call to the meta object\n    mp_obj_t meta_args[3];\n    meta_args[0] = args[1]; // class name\n    meta_args[1] = mp_obj_new_tuple(n_args - 2, args + 2); // tuple of bases\n    meta_args[2] = class_locals; // dict of members\n    mp_obj_t new_class = mp_call_function_n_kw(meta, 3, 0, meta_args);\n\n    // store into cell if neede\n    if (cell != mp_const_none) {\n        mp_obj_cell_set(cell, new_class);\n    }\n\n    return new_class;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj, 2, mp_builtin___build_class__);\n\nSTATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) {\n    return mp_unary_op(MP_UNARY_OP_ABS, o_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_abs_obj, mp_builtin_abs);\n\nSTATIC mp_obj_t mp_builtin_all(mp_obj_t o_in) {\n    mp_obj_iter_buf_t iter_buf;\n    mp_obj_t iterable = mp_getiter(o_in, &iter_buf);\n    mp_obj_t item;\n    while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n        if (!mp_obj_is_true(item)) {\n            return mp_const_false;\n        }\n    }\n    return mp_const_true;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_all_obj, mp_builtin_all);\n\nSTATIC mp_obj_t mp_builtin_any(mp_obj_t o_in) {\n    mp_obj_iter_buf_t iter_buf;\n    mp_obj_t iterable = mp_getiter(o_in, &iter_buf);\n    mp_obj_t item;\n    while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n        if (mp_obj_is_true(item)) {\n            return mp_const_true;\n        }\n    }\n    return mp_const_false;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any);\n\nSTATIC mp_obj_t mp_builtin_bin(mp_obj_t o_in) {\n    mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_b_brace_close_), o_in };\n    return mp_obj_str_format(MP_ARRAY_SIZE(args), args, NULL);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin);\n\nSTATIC mp_obj_t mp_builtin_callable(mp_obj_t o_in) {\n    if (mp_obj_is_callable(o_in)) {\n        return mp_const_true;\n    } else {\n        return mp_const_false;\n    }\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable);\n\nSTATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {\n    #if MICROPY_PY_BUILTINS_STR_UNICODE\n    mp_uint_t c = mp_obj_get_int(o_in);\n    uint8_t str[4];\n    int len = 0;\n    if (c < 0x80) {\n        *str = c;\n        len = 1;\n    } else if (c < 0x800) {\n        str[0] = (c >> 6) | 0xC0;\n        str[1] = (c & 0x3F) | 0x80;\n        len = 2;\n    } else if (c < 0x10000) {\n        str[0] = (c >> 12) | 0xE0;\n        str[1] = ((c >> 6) & 0x3F) | 0x80;\n        str[2] = (c & 0x3F) | 0x80;\n        len = 3;\n    } else if (c < 0x110000) {\n        str[0] = (c >> 18) | 0xF0;\n        str[1] = ((c >> 12) & 0x3F) | 0x80;\n        str[2] = ((c >> 6) & 0x3F) | 0x80;\n        str[3] = (c & 0x3F) | 0x80;\n        len = 4;\n    } else {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"chr() arg not in range(0x110000)\"));\n    }\n    return mp_obj_new_str_via_qstr((char *)str, len);\n    #else\n    mp_int_t ord = mp_obj_get_int(o_in);\n    if (0 <= ord && ord <= 0xff) {\n        uint8_t str[1] = {ord};\n        return mp_obj_new_str_via_qstr((char *)str, 1);\n    } else {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"chr() arg not in range(256)\"));\n    }\n    #endif\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr);\n\nSTATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t dir = mp_obj_new_list(0, NULL);\n    if (n_args == 0) {\n        // Make a list of names in the local namespace\n        mp_obj_dict_t *dict = mp_locals_get();\n        for (size_t i = 0; i < dict->map.alloc; i++) {\n            if (mp_map_slot_is_filled(&dict->map, i)) {\n                mp_obj_list_append(dir, dict->map.table[i].key);\n            }\n        }\n    } else { // n_args == 1\n        // Make a list of names in the given object\n        // Implemented by probing all possible qstrs with mp_load_method_maybe\n        size_t nqstr = QSTR_TOTAL();\n        for (size_t i = MP_QSTR_ + 1; i < nqstr; ++i) {\n            mp_obj_t dest[2];\n            mp_load_method_protected(args[0], i, dest, false);\n            if (dest[0] != MP_OBJ_NULL) {\n                #if MICROPY_PY_ALL_SPECIAL_METHODS\n                // Support for __dir__: see if we can dispatch to this special method\n                // This relies on MP_QSTR__dir__ being first after MP_QSTR_\n                if (i == MP_QSTR___dir__ && dest[1] != MP_OBJ_NULL) {\n                    return mp_call_method_n_kw(0, 0, dest);\n                }\n                #endif\n                mp_obj_list_append(dir, MP_OBJ_NEW_QSTR(i));\n            }\n        }\n    }\n    return dir;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj, 0, 1, mp_builtin_dir);\n\nSTATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {\n    return mp_binary_op(MP_BINARY_OP_DIVMOD, o1_in, o2_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj, mp_builtin_divmod);\n\nSTATIC mp_obj_t mp_builtin_hash(mp_obj_t o_in) {\n    // result is guaranteed to be a (small) int\n    return mp_unary_op(MP_UNARY_OP_HASH, o_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hash_obj, mp_builtin_hash);\n\nSTATIC mp_obj_t mp_builtin_hex(mp_obj_t o_in) {\n    #if MICROPY_PY_BUILTINS_STR_OP_MODULO\n    return mp_binary_op(MP_BINARY_OP_MODULO, MP_OBJ_NEW_QSTR(MP_QSTR__percent__hash_x), o_in);\n    #else\n    mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_x_brace_close_), o_in };\n    return mp_obj_str_format(MP_ARRAY_SIZE(args), args, NULL);\n    #endif\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hex_obj, mp_builtin_hex);\n\n#if MICROPY_PY_BUILTINS_INPUT\n\n#include \"py/mphal.h\"\n#include \"lib/mp-readline/readline.h\"\n\n// A port can define mp_hal_readline if they want to use a custom function here\n#ifndef mp_hal_readline\n#define mp_hal_readline readline\n#endif\n\nSTATIC mp_obj_t mp_builtin_input(size_t n_args, const mp_obj_t *args) {\n    if (n_args == 1) {\n        mp_obj_print(args[0], PRINT_STR);\n    }\n    vstr_t line;\n    vstr_init(&line, 16);\n    int ret = mp_hal_readline(&line, \"\");\n    if (ret == CHAR_CTRL_C) {\n        mp_raise_type(&mp_type_KeyboardInterrupt);\n    }\n    if (line.len == 0 && ret == CHAR_CTRL_D) {\n        mp_raise_type(&mp_type_EOFError);\n    }\n    return mp_obj_new_str_from_vstr(&mp_type_str, &line);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_input_obj, 0, 1, mp_builtin_input);\n\n#endif\n\nSTATIC mp_obj_t mp_builtin_iter(mp_obj_t o_in) {\n    return mp_getiter(o_in, NULL);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);\n\n#if MICROPY_PY_BUILTINS_MIN_MAX\n\nSTATIC mp_obj_t mp_builtin_min_max(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs, mp_uint_t op) {\n    mp_map_elem_t *key_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_key), MP_MAP_LOOKUP);\n    mp_map_elem_t *default_elem;\n    mp_obj_t key_fn = key_elem == NULL ? MP_OBJ_NULL : key_elem->value;\n    if (n_args == 1) {\n        // given an iterable\n        mp_obj_iter_buf_t iter_buf;\n        mp_obj_t iterable = mp_getiter(args[0], &iter_buf);\n        mp_obj_t best_key = MP_OBJ_NULL;\n        mp_obj_t best_obj = MP_OBJ_NULL;\n        mp_obj_t item;\n        while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n            mp_obj_t key = key_fn == MP_OBJ_NULL ? item : mp_call_function_1(key_fn, item);\n            if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) {\n                best_key = key;\n                best_obj = item;\n            }\n        }\n        if (best_obj == MP_OBJ_NULL) {\n            default_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_default), MP_MAP_LOOKUP);\n            if (default_elem != NULL) {\n                best_obj = default_elem->value;\n            } else {\n                mp_raise_ValueError(MP_ERROR_TEXT(\"arg is an empty sequence\"));\n            }\n        }\n        return best_obj;\n    } else {\n        // given many args\n        mp_obj_t best_key = MP_OBJ_NULL;\n        mp_obj_t best_obj = MP_OBJ_NULL;\n        for (size_t i = 0; i < n_args; i++) {\n            mp_obj_t key = key_fn == MP_OBJ_NULL ? args[i] : mp_call_function_1(key_fn, args[i]);\n            if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) {\n                best_key = key;\n                best_obj = args[i];\n            }\n        }\n        return best_obj;\n    }\n}\n\nSTATIC mp_obj_t mp_builtin_max(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {\n    return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_MORE);\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_max_obj, 1, mp_builtin_max);\n\nSTATIC mp_obj_t mp_builtin_min(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {\n    return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_LESS);\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_min_obj, 1, mp_builtin_min);\n\n#endif\n\n#if MICROPY_PY_BUILTINS_NEXT2\nSTATIC mp_obj_t mp_builtin_next(size_t n_args, const mp_obj_t *args) {\n    if (n_args == 1) {\n        mp_obj_t ret = mp_iternext_allow_raise(args[0]);\n        if (ret == MP_OBJ_STOP_ITERATION) {\n            mp_raise_type(&mp_type_StopIteration);\n        } else {\n            return ret;\n        }\n    } else {\n        mp_obj_t ret = mp_iternext(args[0]);\n        return ret == MP_OBJ_STOP_ITERATION ? args[1] : ret;\n    }\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_next_obj, 1, 2, mp_builtin_next);\n#else\nSTATIC mp_obj_t mp_builtin_next(mp_obj_t o) {\n    mp_obj_t ret = mp_iternext_allow_raise(o);\n    if (ret == MP_OBJ_STOP_ITERATION) {\n        mp_raise_type(&mp_type_StopIteration);\n    } else {\n        return ret;\n    }\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_next_obj, mp_builtin_next);\n#endif\n\nSTATIC mp_obj_t mp_builtin_oct(mp_obj_t o_in) {\n    #if MICROPY_PY_BUILTINS_STR_OP_MODULO\n    return mp_binary_op(MP_BINARY_OP_MODULO, MP_OBJ_NEW_QSTR(MP_QSTR__percent__hash_o), o_in);\n    #else\n    mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_o_brace_close_), o_in };\n    return mp_obj_str_format(MP_ARRAY_SIZE(args), args, NULL);\n    #endif\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct);\n\nSTATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {\n    size_t len;\n    const byte *str = (const byte *)mp_obj_str_get_data(o_in, &len);\n    #if MICROPY_PY_BUILTINS_STR_UNICODE\n    if (mp_obj_is_str(o_in)) {\n        len = utf8_charlen(str, len);\n        if (len == 1) {\n            return mp_obj_new_int(utf8_get_char(str));\n        }\n    } else\n    #endif\n    {\n        // a bytes object, or a str without unicode support (don't sign extend the char)\n        if (len == 1) {\n            return MP_OBJ_NEW_SMALL_INT(str[0]);\n        }\n    }\n\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    mp_raise_TypeError(MP_ERROR_TEXT(\"ord expects a character\"));\n    #else\n    mp_raise_msg_varg(&mp_type_TypeError,\n        MP_ERROR_TEXT(\"ord() expected a character, but string of length %d found\"), (int)len);\n    #endif\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord);\n\nSTATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) {\n    switch (n_args) {\n        case 2:\n            return mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]);\n        default:\n            #if !MICROPY_PY_BUILTINS_POW3\n            mp_raise_NotImplementedError(MP_ERROR_TEXT(\"3-arg pow() not supported\"));\n            #elif MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_MPZ\n            return mp_binary_op(MP_BINARY_OP_MODULO, mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]), args[2]);\n            #else\n            return mp_obj_int_pow3(args[0], args[1], args[2]);\n            #endif\n    }\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow);\n\nSTATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_sep, ARG_end, ARG_file };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_sep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__space_)} },\n        { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__0x0a_)} },\n        #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES\n        { MP_QSTR_file, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_sys_stdout_obj)} },\n        #endif\n    };\n\n    // parse args (a union is used to reduce the amount of C stack that is needed)\n    union {\n        mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n        size_t len[2];\n    } u;\n    mp_arg_parse_all(0, NULL, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, u.args);\n\n    #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES\n    mp_get_stream_raise(u.args[ARG_file].u_obj, MP_STREAM_OP_WRITE);\n    mp_print_t print = {MP_OBJ_TO_PTR(u.args[ARG_file].u_obj), mp_stream_write_adaptor};\n    #endif\n\n    // extract the objects first because we are going to use the other part of the union\n    mp_obj_t sep = u.args[ARG_sep].u_obj;\n    mp_obj_t end = u.args[ARG_end].u_obj;\n    const char *sep_data = mp_obj_str_get_data(sep, &u.len[0]);\n    const char *end_data = mp_obj_str_get_data(end, &u.len[1]);\n\n    for (size_t i = 0; i < n_args; i++) {\n        if (i > 0) {\n            #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES\n            mp_stream_write_adaptor(print.data, sep_data, u.len[0]);\n            #else\n            mp_print_strn(&mp_plat_print, sep_data, u.len[0], 0, 0, 0);\n            #endif\n        }\n        #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES\n        mp_obj_print_helper(&print, pos_args[i], PRINT_STR);\n        #else\n        mp_obj_print_helper(&mp_plat_print, pos_args[i], PRINT_STR);\n        #endif\n    }\n    #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES\n    mp_stream_write_adaptor(print.data, end_data, u.len[1]);\n    #else\n    mp_print_strn(&mp_plat_print, end_data, u.len[1], 0, 0, 0);\n    #endif\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_print_obj, 0, mp_builtin_print);\n\nSTATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {\n    if (o != mp_const_none) {\n        mp_obj_print_helper(MP_PYTHON_PRINTER, o, PRINT_REPR);\n        mp_print_str(MP_PYTHON_PRINTER, \"\\n\");\n        #if MICROPY_CAN_OVERRIDE_BUILTINS\n        // Set \"_\" special variable\n        mp_obj_t dest[2] = {MP_OBJ_SENTINEL, o};\n        mp_type_module.attr(MP_OBJ_FROM_PTR(&mp_module_builtins), MP_QSTR__, dest);\n        #endif\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__);\n\nSTATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) {\n    vstr_t vstr;\n    mp_print_t print;\n    vstr_init_print(&vstr, 16, &print);\n    mp_obj_print_helper(&print, o_in, PRINT_REPR);\n    return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr);\n\nSTATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t o_in = args[0];\n    if (mp_obj_is_int(o_in)) {\n        if (n_args <= 1) {\n            return o_in;\n        }\n\n        #if !MICROPY_PY_BUILTINS_ROUND_INT\n        mp_raise_NotImplementedError(NULL);\n        #else\n        mp_int_t num_dig = mp_obj_get_int(args[1]);\n        if (num_dig >= 0) {\n            return o_in;\n        }\n\n        mp_obj_t mult = mp_binary_op(MP_BINARY_OP_POWER, MP_OBJ_NEW_SMALL_INT(10), MP_OBJ_NEW_SMALL_INT(-num_dig));\n        mp_obj_t half_mult = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, mult, MP_OBJ_NEW_SMALL_INT(2));\n        mp_obj_t modulo = mp_binary_op(MP_BINARY_OP_MODULO, o_in, mult);\n        mp_obj_t rounded = mp_binary_op(MP_BINARY_OP_SUBTRACT, o_in, modulo);\n        if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, half_mult, modulo))) {\n            return rounded;\n        } else if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, modulo, half_mult))) {\n            return mp_binary_op(MP_BINARY_OP_ADD, rounded, mult);\n        } else {\n            // round to even number\n            mp_obj_t floor = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, o_in, mult);\n            if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_AND, floor, MP_OBJ_NEW_SMALL_INT(1)))) {\n                return mp_binary_op(MP_BINARY_OP_ADD, rounded, mult);\n            } else {\n                return rounded;\n            }\n        }\n        #endif\n    }\n    #if MICROPY_PY_BUILTINS_FLOAT\n    mp_float_t val = mp_obj_get_float(o_in);\n    if (n_args > 1) {\n        mp_int_t num_dig = mp_obj_get_int(args[1]);\n        mp_float_t mult = MICROPY_FLOAT_C_FUN(pow)(10, (mp_float_t)num_dig);\n        // TODO may lead to overflow\n        mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val * mult) / mult;\n        return mp_obj_new_float(rounded);\n    }\n    mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val);\n    return mp_obj_new_int_from_float(rounded);\n    #else\n    mp_int_t r = mp_obj_get_int(o_in);\n    return mp_obj_new_int(r);\n    #endif\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj, 1, 2, mp_builtin_round);\n\nSTATIC mp_obj_t mp_builtin_sum(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t value;\n    switch (n_args) {\n        case 1:\n            value = MP_OBJ_NEW_SMALL_INT(0);\n            break;\n        default:\n            value = args[1];\n            break;\n    }\n    mp_obj_iter_buf_t iter_buf;\n    mp_obj_t iterable = mp_getiter(args[0], &iter_buf);\n    mp_obj_t item;\n    while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n        value = mp_binary_op(MP_BINARY_OP_ADD, value, item);\n    }\n    return value;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum);\n\nSTATIC mp_obj_t mp_builtin_sorted(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {\n    if (n_args > 1) {\n        mp_raise_TypeError(MP_ERROR_TEXT(\"must use keyword argument for key function\"));\n    }\n    mp_obj_t self = mp_type_list.make_new(&mp_type_list, 1, 0, args);\n    mp_obj_list_sort(1, &self, kwargs);\n\n    return self;\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted);\n\n// See mp_load_attr() if making any changes\nstatic inline mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t defval) {\n    mp_obj_t dest[2];\n    // use load_method, raising or not raising exception\n    if (defval == MP_OBJ_NULL) {\n        mp_load_method(base, attr, dest);\n    } else {\n        mp_load_method_protected(base, attr, dest, false);\n    }\n    if (dest[0] == MP_OBJ_NULL) {\n        return defval;\n    } else if (dest[1] == MP_OBJ_NULL) {\n        // load_method returned just a normal attribute\n        return dest[0];\n    } else {\n        // load_method returned a method, so build a bound method object\n        return mp_obj_new_bound_meth(dest[0], dest[1]);\n    }\n}\n\nSTATIC mp_obj_t mp_builtin_getattr(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t defval = MP_OBJ_NULL;\n    if (n_args > 2) {\n        defval = args[2];\n    }\n    return mp_load_attr_default(args[0], mp_obj_str_get_qstr(args[1]), defval);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj, 2, 3, mp_builtin_getattr);\n\nSTATIC mp_obj_t mp_builtin_setattr(mp_obj_t base, mp_obj_t attr, mp_obj_t value) {\n    mp_store_attr(base, mp_obj_str_get_qstr(attr), value);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj, mp_builtin_setattr);\n\n#if MICROPY_CPYTHON_COMPAT\nSTATIC mp_obj_t mp_builtin_delattr(mp_obj_t base, mp_obj_t attr) {\n    return mp_builtin_setattr(base, attr, MP_OBJ_NULL);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr);\n#endif\n\nSTATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {\n    qstr attr = mp_obj_str_get_qstr(attr_in);\n    mp_obj_t dest[2];\n    mp_load_method_protected(object_in, attr, dest, false);\n    return mp_obj_new_bool(dest[0] != MP_OBJ_NULL);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr);\n\nSTATIC mp_obj_t mp_builtin_globals(void) {\n    return MP_OBJ_FROM_PTR(mp_globals_get());\n}\nMP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_globals_obj, mp_builtin_globals);\n\nSTATIC mp_obj_t mp_builtin_locals(void) {\n    return MP_OBJ_FROM_PTR(mp_locals_get());\n}\nMP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_builtin_locals);\n\n// These are defined in terms of MicroPython API functions right away\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_obj_id);\nMP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len);\n\nSTATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_builtins) },\n\n    // built-in core functions\n    { MP_ROM_QSTR(MP_QSTR___build_class__), MP_ROM_PTR(&mp_builtin___build_class___obj) },\n    { MP_ROM_QSTR(MP_QSTR___import__), MP_ROM_PTR(&mp_builtin___import___obj) },\n    { MP_ROM_QSTR(MP_QSTR___repl_print__), MP_ROM_PTR(&mp_builtin___repl_print___obj) },\n\n    // built-in types\n    { MP_ROM_QSTR(MP_QSTR_bool), MP_ROM_PTR(&mp_type_bool) },\n    { MP_ROM_QSTR(MP_QSTR_bytes), MP_ROM_PTR(&mp_type_bytes) },\n    #if MICROPY_PY_BUILTINS_BYTEARRAY\n    { MP_ROM_QSTR(MP_QSTR_bytearray), MP_ROM_PTR(&mp_type_bytearray) },\n    #endif\n    #if MICROPY_PY_BUILTINS_COMPLEX\n    { MP_ROM_QSTR(MP_QSTR_complex), MP_ROM_PTR(&mp_type_complex) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_dict), MP_ROM_PTR(&mp_type_dict) },\n    #if MICROPY_PY_BUILTINS_ENUMERATE\n    { MP_ROM_QSTR(MP_QSTR_enumerate), MP_ROM_PTR(&mp_type_enumerate) },\n    #endif\n    #if MICROPY_PY_BUILTINS_FILTER\n    { MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&mp_type_filter) },\n    #endif\n    #if MICROPY_PY_BUILTINS_FLOAT\n    { MP_ROM_QSTR(MP_QSTR_float), MP_ROM_PTR(&mp_type_float) },\n    #endif\n    #if MICROPY_PY_BUILTINS_SET && MICROPY_PY_BUILTINS_FROZENSET\n    { MP_ROM_QSTR(MP_QSTR_frozenset), MP_ROM_PTR(&mp_type_frozenset) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_int), MP_ROM_PTR(&mp_type_int) },\n    { MP_ROM_QSTR(MP_QSTR_list), MP_ROM_PTR(&mp_type_list) },\n    { MP_ROM_QSTR(MP_QSTR_map), MP_ROM_PTR(&mp_type_map) },\n    #if MICROPY_PY_BUILTINS_MEMORYVIEW\n    { MP_ROM_QSTR(MP_QSTR_memoryview), MP_ROM_PTR(&mp_type_memoryview) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_object), MP_ROM_PTR(&mp_type_object) },\n    #if MICROPY_PY_BUILTINS_PROPERTY\n    { MP_ROM_QSTR(MP_QSTR_property), MP_ROM_PTR(&mp_type_property) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_range), MP_ROM_PTR(&mp_type_range) },\n    #if MICROPY_PY_BUILTINS_REVERSED\n    { MP_ROM_QSTR(MP_QSTR_reversed), MP_ROM_PTR(&mp_type_reversed) },\n    #endif\n    #if MICROPY_PY_BUILTINS_SET\n    { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mp_type_set) },\n    #endif\n    #if MICROPY_PY_BUILTINS_SLICE\n    { MP_ROM_QSTR(MP_QSTR_slice), MP_ROM_PTR(&mp_type_slice) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_str), MP_ROM_PTR(&mp_type_str) },\n    { MP_ROM_QSTR(MP_QSTR_super), MP_ROM_PTR(&mp_type_super) },\n    { MP_ROM_QSTR(MP_QSTR_tuple), MP_ROM_PTR(&mp_type_tuple) },\n    { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&mp_type_type) },\n    { MP_ROM_QSTR(MP_QSTR_zip), MP_ROM_PTR(&mp_type_zip) },\n\n    { MP_ROM_QSTR(MP_QSTR_classmethod), MP_ROM_PTR(&mp_type_classmethod) },\n    { MP_ROM_QSTR(MP_QSTR_staticmethod), MP_ROM_PTR(&mp_type_staticmethod) },\n\n    // built-in objects\n    { MP_ROM_QSTR(MP_QSTR_Ellipsis), MP_ROM_PTR(&mp_const_ellipsis_obj) },\n    #if MICROPY_PY_BUILTINS_NOTIMPLEMENTED\n    { MP_ROM_QSTR(MP_QSTR_NotImplemented), MP_ROM_PTR(&mp_const_notimplemented_obj) },\n    #endif\n\n    // built-in user functions\n    { MP_ROM_QSTR(MP_QSTR_abs), MP_ROM_PTR(&mp_builtin_abs_obj) },\n    { MP_ROM_QSTR(MP_QSTR_all), MP_ROM_PTR(&mp_builtin_all_obj) },\n    { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&mp_builtin_any_obj) },\n    { MP_ROM_QSTR(MP_QSTR_bin), MP_ROM_PTR(&mp_builtin_bin_obj) },\n    { MP_ROM_QSTR(MP_QSTR_callable), MP_ROM_PTR(&mp_builtin_callable_obj) },\n    #if MICROPY_PY_BUILTINS_COMPILE\n    { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mp_builtin_compile_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_chr), MP_ROM_PTR(&mp_builtin_chr_obj) },\n    #if MICROPY_CPYTHON_COMPAT\n    { MP_ROM_QSTR(MP_QSTR_delattr), MP_ROM_PTR(&mp_builtin_delattr_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_dir), MP_ROM_PTR(&mp_builtin_dir_obj) },\n    { MP_ROM_QSTR(MP_QSTR_divmod), MP_ROM_PTR(&mp_builtin_divmod_obj) },\n    #if MICROPY_PY_BUILTINS_EVAL_EXEC\n    { MP_ROM_QSTR(MP_QSTR_eval), MP_ROM_PTR(&mp_builtin_eval_obj) },\n    { MP_ROM_QSTR(MP_QSTR_exec), MP_ROM_PTR(&mp_builtin_exec_obj) },\n    #endif\n    #if MICROPY_PY_BUILTINS_EXECFILE\n    { MP_ROM_QSTR(MP_QSTR_execfile), MP_ROM_PTR(&mp_builtin_execfile_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_getattr), MP_ROM_PTR(&mp_builtin_getattr_obj) },\n    { MP_ROM_QSTR(MP_QSTR_setattr), MP_ROM_PTR(&mp_builtin_setattr_obj) },\n    { MP_ROM_QSTR(MP_QSTR_globals), MP_ROM_PTR(&mp_builtin_globals_obj) },\n    { MP_ROM_QSTR(MP_QSTR_hasattr), MP_ROM_PTR(&mp_builtin_hasattr_obj) },\n    { MP_ROM_QSTR(MP_QSTR_hash), MP_ROM_PTR(&mp_builtin_hash_obj) },\n    #if MICROPY_PY_BUILTINS_HELP\n    { MP_ROM_QSTR(MP_QSTR_help), MP_ROM_PTR(&mp_builtin_help_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_hex), MP_ROM_PTR(&mp_builtin_hex_obj) },\n    { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&mp_builtin_id_obj) },\n    #if MICROPY_PY_BUILTINS_INPUT\n    { MP_ROM_QSTR(MP_QSTR_input), MP_ROM_PTR(&mp_builtin_input_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_isinstance), MP_ROM_PTR(&mp_builtin_isinstance_obj) },\n    { MP_ROM_QSTR(MP_QSTR_issubclass), MP_ROM_PTR(&mp_builtin_issubclass_obj) },\n    { MP_ROM_QSTR(MP_QSTR_iter), MP_ROM_PTR(&mp_builtin_iter_obj) },\n    { MP_ROM_QSTR(MP_QSTR_len), MP_ROM_PTR(&mp_builtin_len_obj) },\n    { MP_ROM_QSTR(MP_QSTR_locals), MP_ROM_PTR(&mp_builtin_locals_obj) },\n    #if MICROPY_PY_BUILTINS_MIN_MAX\n    { MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&mp_builtin_max_obj) },\n    { MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&mp_builtin_min_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_next), MP_ROM_PTR(&mp_builtin_next_obj) },\n    { MP_ROM_QSTR(MP_QSTR_oct), MP_ROM_PTR(&mp_builtin_oct_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ord), MP_ROM_PTR(&mp_builtin_ord_obj) },\n    { MP_ROM_QSTR(MP_QSTR_pow), MP_ROM_PTR(&mp_builtin_pow_obj) },\n    { MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&mp_builtin_print_obj) },\n    { MP_ROM_QSTR(MP_QSTR_repr), MP_ROM_PTR(&mp_builtin_repr_obj) },\n    { MP_ROM_QSTR(MP_QSTR_round), MP_ROM_PTR(&mp_builtin_round_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sorted), MP_ROM_PTR(&mp_builtin_sorted_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sum), MP_ROM_PTR(&mp_builtin_sum_obj) },\n\n    // built-in exceptions\n    { MP_ROM_QSTR(MP_QSTR_BaseException), MP_ROM_PTR(&mp_type_BaseException) },\n    { MP_ROM_QSTR(MP_QSTR_ArithmeticError), MP_ROM_PTR(&mp_type_ArithmeticError) },\n    { MP_ROM_QSTR(MP_QSTR_AssertionError), MP_ROM_PTR(&mp_type_AssertionError) },\n    { MP_ROM_QSTR(MP_QSTR_AttributeError), MP_ROM_PTR(&mp_type_AttributeError) },\n    { MP_ROM_QSTR(MP_QSTR_EOFError), MP_ROM_PTR(&mp_type_EOFError) },\n    { MP_ROM_QSTR(MP_QSTR_Exception), MP_ROM_PTR(&mp_type_Exception) },\n    { MP_ROM_QSTR(MP_QSTR_GeneratorExit), MP_ROM_PTR(&mp_type_GeneratorExit) },\n    { MP_ROM_QSTR(MP_QSTR_ImportError), MP_ROM_PTR(&mp_type_ImportError) },\n    { MP_ROM_QSTR(MP_QSTR_IndentationError), MP_ROM_PTR(&mp_type_IndentationError) },\n    { MP_ROM_QSTR(MP_QSTR_IndexError), MP_ROM_PTR(&mp_type_IndexError) },\n    { MP_ROM_QSTR(MP_QSTR_KeyboardInterrupt), MP_ROM_PTR(&mp_type_KeyboardInterrupt) },\n    { MP_ROM_QSTR(MP_QSTR_KeyError), MP_ROM_PTR(&mp_type_KeyError) },\n    { MP_ROM_QSTR(MP_QSTR_LookupError), MP_ROM_PTR(&mp_type_LookupError) },\n    { MP_ROM_QSTR(MP_QSTR_MemoryError), MP_ROM_PTR(&mp_type_MemoryError) },\n    { MP_ROM_QSTR(MP_QSTR_NameError), MP_ROM_PTR(&mp_type_NameError) },\n    { MP_ROM_QSTR(MP_QSTR_NotImplementedError), MP_ROM_PTR(&mp_type_NotImplementedError) },\n    { MP_ROM_QSTR(MP_QSTR_OSError), MP_ROM_PTR(&mp_type_OSError) },\n    { MP_ROM_QSTR(MP_QSTR_OverflowError), MP_ROM_PTR(&mp_type_OverflowError) },\n    { MP_ROM_QSTR(MP_QSTR_RuntimeError), MP_ROM_PTR(&mp_type_RuntimeError) },\n    #if MICROPY_PY_ASYNC_AWAIT\n    { MP_ROM_QSTR(MP_QSTR_StopAsyncIteration), MP_ROM_PTR(&mp_type_StopAsyncIteration) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_StopIteration), MP_ROM_PTR(&mp_type_StopIteration) },\n    { MP_ROM_QSTR(MP_QSTR_SyntaxError), MP_ROM_PTR(&mp_type_SyntaxError) },\n    { MP_ROM_QSTR(MP_QSTR_SystemExit), MP_ROM_PTR(&mp_type_SystemExit) },\n    { MP_ROM_QSTR(MP_QSTR_TypeError), MP_ROM_PTR(&mp_type_TypeError) },\n    #if MICROPY_PY_BUILTINS_STR_UNICODE\n    { MP_ROM_QSTR(MP_QSTR_UnicodeError), MP_ROM_PTR(&mp_type_UnicodeError) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_ValueError), MP_ROM_PTR(&mp_type_ValueError) },\n    #if MICROPY_EMIT_NATIVE\n    { MP_ROM_QSTR(MP_QSTR_ViperTypeError), MP_ROM_PTR(&mp_type_ViperTypeError) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_ZeroDivisionError), MP_ROM_PTR(&mp_type_ZeroDivisionError) },\n\n    // Extra builtins as defined by a port\n    MICROPY_PORT_BUILTINS\n};\n\nMP_DEFINE_CONST_DICT(mp_module_builtins_globals, mp_module_builtins_globals_table);\n\nconst mp_obj_module_t mp_module_builtins = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_builtins_globals,\n};\n"
  },
  {
    "path": "py/modcmath.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/builtin.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_BUILTINS_COMPLEX && MICROPY_PY_CMATH\n\n#include <math.h>\n\n// phase(z): returns the phase of the number z in the range (-pi, +pi]\nSTATIC mp_obj_t mp_cmath_phase(mp_obj_t z_obj) {\n    mp_float_t real, imag;\n    mp_obj_get_complex(z_obj, &real, &imag);\n    return mp_obj_new_float(MICROPY_FLOAT_C_FUN(atan2)(imag, real));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_phase_obj, mp_cmath_phase);\n\n// polar(z): returns the polar form of z as a tuple\nSTATIC mp_obj_t mp_cmath_polar(mp_obj_t z_obj) {\n    mp_float_t real, imag;\n    mp_obj_get_complex(z_obj, &real, &imag);\n    mp_obj_t tuple[2] = {\n        mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real * real + imag * imag)),\n        mp_obj_new_float(MICROPY_FLOAT_C_FUN(atan2)(imag, real)),\n    };\n    return mp_obj_new_tuple(2, tuple);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_polar_obj, mp_cmath_polar);\n\n// rect(r, phi): returns the complex number with modulus r and phase phi\nSTATIC mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) {\n    mp_float_t r = mp_obj_get_float(r_obj);\n    mp_float_t phi = mp_obj_get_float(phi_obj);\n    return mp_obj_new_complex(r * MICROPY_FLOAT_C_FUN(cos)(phi), r * MICROPY_FLOAT_C_FUN(sin)(phi));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_cmath_rect_obj, mp_cmath_rect);\n\n// exp(z): return the exponential of z\nSTATIC mp_obj_t mp_cmath_exp(mp_obj_t z_obj) {\n    mp_float_t real, imag;\n    mp_obj_get_complex(z_obj, &real, &imag);\n    mp_float_t exp_real = MICROPY_FLOAT_C_FUN(exp)(real);\n    return mp_obj_new_complex(exp_real * MICROPY_FLOAT_C_FUN(cos)(imag), exp_real * MICROPY_FLOAT_C_FUN(sin)(imag));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp);\n\n// log(z): return the natural logarithm of z, with branch cut along the negative real axis\n// TODO can take second argument, being the base\nSTATIC mp_obj_t mp_cmath_log(mp_obj_t z_obj) {\n    mp_float_t real, imag;\n    mp_obj_get_complex(z_obj, &real, &imag);\n    return mp_obj_new_complex(MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(log)(real * real + imag * imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);\n\n#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS\n// log10(z): return the base-10 logarithm of z, with branch cut along the negative real axis\nSTATIC mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {\n    mp_float_t real, imag;\n    mp_obj_get_complex(z_obj, &real, &imag);\n    return mp_obj_new_complex(MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(log10)(real * real + imag * imag), MICROPY_FLOAT_CONST(0.4342944819032518) * MICROPY_FLOAT_C_FUN(atan2)(imag, real));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);\n#endif\n\n// sqrt(z): return the square-root of z\nSTATIC mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {\n    mp_float_t real, imag;\n    mp_obj_get_complex(z_obj, &real, &imag);\n    mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real * real + imag * imag, MICROPY_FLOAT_CONST(0.25));\n    mp_float_t theta = MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(atan2)(imag, real);\n    return mp_obj_new_complex(sqrt_abs * MICROPY_FLOAT_C_FUN(cos)(theta), sqrt_abs * MICROPY_FLOAT_C_FUN(sin)(theta));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt);\n\n// cos(z): return the cosine of z\nSTATIC mp_obj_t mp_cmath_cos(mp_obj_t z_obj) {\n    mp_float_t real, imag;\n    mp_obj_get_complex(z_obj, &real, &imag);\n    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));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_cos_obj, mp_cmath_cos);\n\n// sin(z): return the sine of z\nSTATIC mp_obj_t mp_cmath_sin(mp_obj_t z_obj) {\n    mp_float_t real, imag;\n    mp_obj_get_complex(z_obj, &real, &imag);\n    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));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sin_obj, mp_cmath_sin);\n\nSTATIC const mp_rom_map_elem_t mp_module_cmath_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cmath) },\n    { MP_ROM_QSTR(MP_QSTR_e), mp_const_float_e },\n    { MP_ROM_QSTR(MP_QSTR_pi), mp_const_float_pi },\n    { MP_ROM_QSTR(MP_QSTR_phase), MP_ROM_PTR(&mp_cmath_phase_obj) },\n    { MP_ROM_QSTR(MP_QSTR_polar), MP_ROM_PTR(&mp_cmath_polar_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&mp_cmath_rect_obj) },\n    { MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&mp_cmath_exp_obj) },\n    { MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&mp_cmath_log_obj) },\n    #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS\n    { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_cmath_log10_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_cmath_sqrt_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_cmath_acos_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_cmath_asin_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_cmath_atan_obj) },\n    { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_cmath_cos_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_cmath_sin_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_cmath_tan_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_cmath_acosh_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_cmath_asinh_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_cmath_atanh_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_cmath_cosh_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_cmath_sinh_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_cmath_tanh_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_cmath_isfinite_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_cmath_isinf_obj) },\n    // { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_cmath_isnan_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_cmath_globals, mp_module_cmath_globals_table);\n\nconst mp_obj_module_t mp_module_cmath = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_cmath_globals,\n};\n\n#endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH\n"
  },
  {
    "path": "py/modcollections.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/builtin.h\"\n\n#if MICROPY_PY_COLLECTIONS\n\nSTATIC const mp_rom_map_elem_t mp_module_collections_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ucollections) },\n    #if MICROPY_PY_COLLECTIONS_DEQUE\n    { MP_ROM_QSTR(MP_QSTR_deque), MP_ROM_PTR(&mp_type_deque) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_namedtuple), MP_ROM_PTR(&mp_namedtuple_obj) },\n    #if MICROPY_PY_COLLECTIONS_ORDEREDDICT\n    { MP_ROM_QSTR(MP_QSTR_OrderedDict), MP_ROM_PTR(&mp_type_ordereddict) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_collections_globals, mp_module_collections_globals_table);\n\nconst mp_obj_module_t mp_module_collections = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_collections_globals,\n};\n\n#endif // MICROPY_PY_COLLECTIONS\n"
  },
  {
    "path": "py/modgc.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpstate.h\"\n#include \"py/obj.h\"\n#include \"py/gc.h\"\n\n#if MICROPY_PY_GC && MICROPY_ENABLE_GC\n\n// collect(): run a garbage collection\nSTATIC mp_obj_t py_gc_collect(void) {\n    gc_collect();\n    #if MICROPY_PY_GC_COLLECT_RETVAL\n    return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_collected));\n    #else\n    return mp_const_none;\n    #endif\n}\nMP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);\n\n// disable(): disable the garbage collector\nSTATIC mp_obj_t gc_disable(void) {\n    MP_STATE_MEM(gc_auto_collect_enabled) = 0;\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);\n\n// enable(): enable the garbage collector\nSTATIC mp_obj_t gc_enable(void) {\n    MP_STATE_MEM(gc_auto_collect_enabled) = 1;\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);\n\nSTATIC mp_obj_t gc_isenabled(void) {\n    return mp_obj_new_bool(MP_STATE_MEM(gc_auto_collect_enabled));\n}\nMP_DEFINE_CONST_FUN_OBJ_0(gc_isenabled_obj, gc_isenabled);\n\n// mem_free(): return the number of bytes of available heap RAM\nSTATIC mp_obj_t gc_mem_free(void) {\n    gc_info_t info;\n    gc_info(&info);\n    return MP_OBJ_NEW_SMALL_INT(info.free);\n}\nMP_DEFINE_CONST_FUN_OBJ_0(gc_mem_free_obj, gc_mem_free);\n\n// mem_alloc(): return the number of bytes of heap RAM that are allocated\nSTATIC mp_obj_t gc_mem_alloc(void) {\n    gc_info_t info;\n    gc_info(&info);\n    return MP_OBJ_NEW_SMALL_INT(info.used);\n}\nMP_DEFINE_CONST_FUN_OBJ_0(gc_mem_alloc_obj, gc_mem_alloc);\n\n#if MICROPY_GC_ALLOC_THRESHOLD\nSTATIC mp_obj_t gc_threshold(size_t n_args, const mp_obj_t *args) {\n    if (n_args == 0) {\n        if (MP_STATE_MEM(gc_alloc_threshold) == (size_t)-1) {\n            return MP_OBJ_NEW_SMALL_INT(-1);\n        }\n        return mp_obj_new_int(MP_STATE_MEM(gc_alloc_threshold) * MICROPY_BYTES_PER_GC_BLOCK);\n    }\n    mp_int_t val = mp_obj_get_int(args[0]);\n    if (val < 0) {\n        MP_STATE_MEM(gc_alloc_threshold) = (size_t)-1;\n    } else {\n        MP_STATE_MEM(gc_alloc_threshold) = val / MICROPY_BYTES_PER_GC_BLOCK;\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gc_threshold_obj, 0, 1, gc_threshold);\n#endif\n\nSTATIC const mp_rom_map_elem_t mp_module_gc_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gc) },\n    { MP_ROM_QSTR(MP_QSTR_collect), MP_ROM_PTR(&gc_collect_obj) },\n    { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&gc_disable_obj) },\n    { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&gc_enable_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isenabled), MP_ROM_PTR(&gc_isenabled_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mem_free), MP_ROM_PTR(&gc_mem_free_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mem_alloc), MP_ROM_PTR(&gc_mem_alloc_obj) },\n    #if MICROPY_GC_ALLOC_THRESHOLD\n    { MP_ROM_QSTR(MP_QSTR_threshold), MP_ROM_PTR(&gc_threshold_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_gc_globals, mp_module_gc_globals_table);\n\nconst mp_obj_module_t mp_module_gc = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_gc_globals,\n};\n\n#endif\n"
  },
  {
    "path": "py/modio.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/builtin.h\"\n#include \"py/stream.h\"\n#include \"py/binary.h\"\n#include \"py/objarray.h\"\n#include \"py/objstringio.h\"\n#include \"py/frozenmod.h\"\n\n#if MICROPY_PY_IO\n\nextern const mp_obj_type_t mp_type_fileio;\nextern const mp_obj_type_t mp_type_textio;\n\n#if MICROPY_PY_IO_IOBASE\n\nSTATIC const mp_obj_type_t mp_type_iobase;\n\nSTATIC const mp_obj_base_t iobase_singleton = {&mp_type_iobase};\n\nSTATIC mp_obj_t iobase_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    (void)type;\n    (void)n_args;\n    (void)n_kw;\n    (void)args;\n    return MP_OBJ_FROM_PTR(&iobase_singleton);\n}\n\nSTATIC mp_uint_t iobase_read_write(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode, qstr qst) {\n    mp_obj_t dest[3];\n    mp_load_method(obj, qst, dest);\n    mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, size, buf};\n    dest[2] = MP_OBJ_FROM_PTR(&ar);\n    mp_obj_t ret_obj = mp_call_method_n_kw(1, 0, dest);\n    if (ret_obj == mp_const_none) {\n        *errcode = MP_EAGAIN;\n        return MP_STREAM_ERROR;\n    }\n    mp_int_t ret = mp_obj_get_int(ret_obj);\n    if (ret >= 0) {\n        return ret;\n    } else {\n        *errcode = -ret;\n        return MP_STREAM_ERROR;\n    }\n}\nSTATIC mp_uint_t iobase_read(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) {\n    return iobase_read_write(obj, buf, size, errcode, MP_QSTR_readinto);\n}\n\nSTATIC mp_uint_t iobase_write(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode) {\n    return iobase_read_write(obj, (void *)buf, size, errcode, MP_QSTR_write);\n}\n\nSTATIC mp_uint_t iobase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode) {\n    mp_obj_t dest[4];\n    mp_load_method(obj, MP_QSTR_ioctl, dest);\n    dest[2] = mp_obj_new_int_from_uint(request);\n    dest[3] = mp_obj_new_int_from_uint(arg);\n    mp_int_t ret = mp_obj_get_int(mp_call_method_n_kw(2, 0, dest));\n    if (ret >= 0) {\n        return ret;\n    } else {\n        *errcode = -ret;\n        return MP_STREAM_ERROR;\n    }\n}\n\nSTATIC const mp_stream_p_t iobase_p = {\n    .read = iobase_read,\n    .write = iobase_write,\n    .ioctl = iobase_ioctl,\n};\n\nSTATIC const mp_obj_type_t mp_type_iobase = {\n    { &mp_type_type },\n    .name = MP_QSTR_IOBase,\n    .make_new = iobase_make_new,\n    .protocol = &iobase_p,\n};\n\n#endif // MICROPY_PY_IO_IOBASE\n\n#if MICROPY_PY_IO_BUFFEREDWRITER\ntypedef struct _mp_obj_bufwriter_t {\n    mp_obj_base_t base;\n    mp_obj_t stream;\n    size_t alloc;\n    size_t len;\n    byte buf[0];\n} mp_obj_bufwriter_t;\n\nSTATIC 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) {\n    mp_arg_check_num(n_args, n_kw, 2, 2, false);\n    size_t alloc = mp_obj_get_int(args[1]);\n    mp_obj_bufwriter_t *o = m_new_obj_var(mp_obj_bufwriter_t, byte, alloc);\n    o->base.type = type;\n    o->stream = args[0];\n    o->alloc = alloc;\n    o->len = 0;\n    return o;\n}\n\nSTATIC mp_uint_t bufwriter_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {\n    mp_obj_bufwriter_t *self = MP_OBJ_TO_PTR(self_in);\n\n    mp_uint_t org_size = size;\n\n    while (size > 0) {\n        mp_uint_t rem = self->alloc - self->len;\n        if (size < rem) {\n            memcpy(self->buf + self->len, buf, size);\n            self->len += size;\n            return org_size;\n        }\n\n        // Buffer flushing policy here is to flush entire buffer all the time.\n        // This allows e.g. to have a block device as backing storage and write\n        // entire block to it. memcpy below is not ideal and could be optimized\n        // in some cases. But the way it is now it at least ensures that buffer\n        // is word-aligned, to guard against obscure cases when it matters, e.g.\n        // https://github.com/micropython/micropython/issues/1863\n        memcpy(self->buf + self->len, buf, rem);\n        buf = (byte *)buf + rem;\n        size -= rem;\n        mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->alloc, errcode);\n        (void)out_sz;\n        if (*errcode != 0) {\n            return MP_STREAM_ERROR;\n        }\n        // TODO: try to recover from a case of non-blocking stream, e.g. move\n        // remaining chunk to the beginning of buffer.\n        assert(out_sz == self->alloc);\n        self->len = 0;\n    }\n\n    return org_size;\n}\n\nSTATIC mp_obj_t bufwriter_flush(mp_obj_t self_in) {\n    mp_obj_bufwriter_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (self->len != 0) {\n        int err;\n        mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->len, &err);\n        (void)out_sz;\n        // TODO: try to recover from a case of non-blocking stream, e.g. move\n        // remaining chunk to the beginning of buffer.\n        assert(out_sz == self->len);\n        self->len = 0;\n        if (err != 0) {\n            mp_raise_OSError(err);\n        }\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(bufwriter_flush_obj, bufwriter_flush);\n\nSTATIC const mp_rom_map_elem_t bufwriter_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&bufwriter_flush_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(bufwriter_locals_dict, bufwriter_locals_dict_table);\n\nSTATIC const mp_stream_p_t bufwriter_stream_p = {\n    .write = bufwriter_write,\n};\n\nSTATIC const mp_obj_type_t bufwriter_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_BufferedWriter,\n    .make_new = bufwriter_make_new,\n    .protocol = &bufwriter_stream_p,\n    .locals_dict = (mp_obj_dict_t *)&bufwriter_locals_dict,\n};\n#endif // MICROPY_PY_IO_BUFFEREDWRITER\n\n#if MICROPY_PY_IO_RESOURCE_STREAM\nSTATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) {\n    VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX);\n    size_t len;\n\n    // As an extension to pkg_resources.resource_stream(), we support\n    // package parameter being None, the path_in is interpreted as a\n    // raw path.\n    if (package_in != mp_const_none) {\n        // Pass \"True\" as sentinel value in fromlist to force returning of leaf module\n        mp_obj_t pkg = mp_import_name(mp_obj_str_get_qstr(package_in), mp_const_true, MP_OBJ_NEW_SMALL_INT(0));\n\n        mp_obj_t dest[2];\n        mp_load_method_maybe(pkg, MP_QSTR___path__, dest);\n        if (dest[0] == MP_OBJ_NULL) {\n            mp_raise_TypeError(NULL);\n        }\n\n        const char *path = mp_obj_str_get_data(dest[0], &len);\n        vstr_add_strn(&path_buf, path, len);\n        vstr_add_byte(&path_buf, '/');\n    }\n\n    const char *path = mp_obj_str_get_data(path_in, &len);\n    vstr_add_strn(&path_buf, path, len);\n\n    len = path_buf.len;\n    const char *data = mp_find_frozen_str(path_buf.buf, &len);\n    if (data != NULL) {\n        mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);\n        o->base.type = &mp_type_bytesio;\n        o->vstr = m_new_obj(vstr_t);\n        vstr_init_fixed_buf(o->vstr, len + 1, (char *)data);\n        o->vstr->len = len;\n        o->pos = 0;\n        return MP_OBJ_FROM_PTR(o);\n    }\n\n    mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len);\n    return mp_builtin_open(1, &path_out, (mp_map_t *)&mp_const_empty_map);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream);\n#endif\n\nSTATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uio) },\n    // Note: mp_builtin_open_obj should be defined by port, it's not\n    // part of the core.\n    { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },\n    #if MICROPY_PY_IO_IOBASE\n    { MP_ROM_QSTR(MP_QSTR_IOBase), MP_ROM_PTR(&mp_type_iobase) },\n    #endif\n    #if MICROPY_PY_IO_RESOURCE_STREAM\n    { MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) },\n    #endif\n    #if MICROPY_PY_IO_FILEIO\n    { MP_ROM_QSTR(MP_QSTR_FileIO), MP_ROM_PTR(&mp_type_fileio) },\n    #if MICROPY_CPYTHON_COMPAT\n    { MP_ROM_QSTR(MP_QSTR_TextIOWrapper), MP_ROM_PTR(&mp_type_textio) },\n    #endif\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_StringIO), MP_ROM_PTR(&mp_type_stringio) },\n    #if MICROPY_PY_IO_BYTESIO\n    { MP_ROM_QSTR(MP_QSTR_BytesIO), MP_ROM_PTR(&mp_type_bytesio) },\n    #endif\n    #if MICROPY_PY_IO_BUFFEREDWRITER\n    { MP_ROM_QSTR(MP_QSTR_BufferedWriter), MP_ROM_PTR(&bufwriter_type) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_io_globals, mp_module_io_globals_table);\n\nconst mp_obj_module_t mp_module_io = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_io_globals,\n};\n\n#endif\n"
  },
  {
    "path": "py/modmath.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/builtin.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH\n\n#include <math.h>\n\n// M_PI is not part of the math.h standard and may not be defined\n// And by defining our own we can ensure it uses the correct const format.\n#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846)\n#define MP_PI_4 MICROPY_FLOAT_CONST(0.78539816339744830962)\n#define MP_3_PI_4 MICROPY_FLOAT_CONST(2.35619449019234492885)\n\nSTATIC NORETURN void math_error(void) {\n    mp_raise_ValueError(MP_ERROR_TEXT(\"math domain error\"));\n}\n\nSTATIC mp_obj_t math_generic_1(mp_obj_t x_obj, mp_float_t (*f)(mp_float_t)) {\n    mp_float_t x = mp_obj_get_float(x_obj);\n    mp_float_t ans = f(x);\n    if ((isnan(ans) && !isnan(x)) || (isinf(ans) && !isinf(x))) {\n        math_error();\n    }\n    return mp_obj_new_float(ans);\n}\n\nSTATIC mp_obj_t math_generic_2(mp_obj_t x_obj, mp_obj_t y_obj, mp_float_t (*f)(mp_float_t, mp_float_t)) {\n    mp_float_t x = mp_obj_get_float(x_obj);\n    mp_float_t y = mp_obj_get_float(y_obj);\n    mp_float_t ans = f(x, y);\n    if ((isnan(ans) && !isnan(x) && !isnan(y)) || (isinf(ans) && !isinf(x))) {\n        math_error();\n    }\n    return mp_obj_new_float(ans);\n}\n\n#define MATH_FUN_1(py_name, c_name) \\\n    STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { \\\n        return math_generic_1(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \\\n    } \\\n    STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);\n\n#define MATH_FUN_1_TO_BOOL(py_name, c_name) \\\n    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))); } \\\n    STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);\n\n#define MATH_FUN_1_TO_INT(py_name, c_name) \\\n    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))); } \\\n    STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);\n\n#define MATH_FUN_2(py_name, c_name) \\\n    STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \\\n        return math_generic_2(x_obj, y_obj, MICROPY_FLOAT_C_FUN(c_name)); \\\n    } \\\n    STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_##py_name##_obj, mp_math_##py_name);\n\n#define MATH_FUN_2_FLT_INT(py_name, c_name) \\\n    STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \\\n        return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_int(y_obj))); \\\n    } \\\n    STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_##py_name##_obj, mp_math_##py_name);\n\n#if MP_NEED_LOG2\n#undef log2\n#undef log2f\n// 1.442695040888963407354163704 is 1/_M_LN2\nmp_float_t MICROPY_FLOAT_C_FUN(log2)(mp_float_t x) {\n    return MICROPY_FLOAT_C_FUN(log)(x) * MICROPY_FLOAT_CONST(1.442695040888963407354163704);\n}\n#endif\n\n// sqrt(x): returns the square root of x\nMATH_FUN_1(sqrt, sqrt)\n// pow(x, y): returns x to the power of y\n#if MICROPY_PY_MATH_POW_FIX_NAN\nmp_float_t pow_func(mp_float_t x, mp_float_t y) {\n    // pow(base, 0) returns 1 for any base, even when base is NaN\n    // pow(+1, exponent) returns 1 for any exponent, even when exponent is NaN\n    if (x == MICROPY_FLOAT_CONST(1.0) || y == MICROPY_FLOAT_CONST(0.0)) {\n        return MICROPY_FLOAT_CONST(1.0);\n    }\n    return MICROPY_FLOAT_C_FUN(pow)(x, y);\n}\nMATH_FUN_2(pow, pow_func)\n#else\nMATH_FUN_2(pow, pow)\n#endif\n// exp(x)\nMATH_FUN_1(exp, exp)\n#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS\n// expm1(x)\nMATH_FUN_1(expm1, expm1)\n// log2(x)\nMATH_FUN_1(log2, log2)\n// log10(x)\nMATH_FUN_1(log10, log10)\n// cosh(x)\nMATH_FUN_1(cosh, cosh)\n// sinh(x)\nMATH_FUN_1(sinh, sinh)\n// tanh(x)\nMATH_FUN_1(tanh, tanh)\n// acosh(x)\nMATH_FUN_1(acosh, acosh)\n// asinh(x)\nMATH_FUN_1(asinh, asinh)\n// atanh(x)\nMATH_FUN_1(atanh, atanh)\n#endif\n// cos(x)\nMATH_FUN_1(cos, cos)\n// sin(x)\nMATH_FUN_1(sin, sin)\n// tan(x)\nMATH_FUN_1(tan, tan)\n// acos(x)\nMATH_FUN_1(acos, acos)\n// asin(x)\nMATH_FUN_1(asin, asin)\n// atan(x)\nMATH_FUN_1(atan, atan)\n// atan2(y, x)\n#if MICROPY_PY_MATH_ATAN2_FIX_INFNAN\nmp_float_t atan2_func(mp_float_t x, mp_float_t y) {\n    if (isinf(x) && isinf(y)) {\n        return copysign(y < 0 ? MP_3_PI_4 : MP_PI_4, x);\n    }\n    return atan2(x, y);\n}\nMATH_FUN_2(atan2, atan2_func)\n#else\nMATH_FUN_2(atan2, atan2)\n#endif\n// ceil(x)\nMATH_FUN_1_TO_INT(ceil, ceil)\n// copysign(x, y)\nSTATIC mp_float_t MICROPY_FLOAT_C_FUN(copysign_func)(mp_float_t x, mp_float_t y) {\n    return MICROPY_FLOAT_C_FUN(copysign)(x, y);\n}\nMATH_FUN_2(copysign, copysign_func)\n// fabs(x)\nSTATIC mp_float_t MICROPY_FLOAT_C_FUN(fabs_func)(mp_float_t x) {\n    return MICROPY_FLOAT_C_FUN(fabs)(x);\n}\nMATH_FUN_1(fabs, fabs_func)\n// floor(x)\nMATH_FUN_1_TO_INT(floor, floor) // TODO: delegate to x.__floor__() if x is not a float\n// fmod(x, y)\n#if MICROPY_PY_MATH_FMOD_FIX_INFNAN\nmp_float_t fmod_func(mp_float_t x, mp_float_t y) {\n    return (!isinf(x) && isinf(y)) ? x : fmod(x, y);\n}\nMATH_FUN_2(fmod, fmod_func)\n#else\nMATH_FUN_2(fmod, fmod)\n#endif\n// isfinite(x)\nMATH_FUN_1_TO_BOOL(isfinite, isfinite)\n// isinf(x)\nMATH_FUN_1_TO_BOOL(isinf, isinf)\n// isnan(x)\nMATH_FUN_1_TO_BOOL(isnan, isnan)\n// trunc(x)\nMATH_FUN_1_TO_INT(trunc, trunc)\n// ldexp(x, exp)\nMATH_FUN_2_FLT_INT(ldexp, ldexp)\n#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS\n// erf(x): return the error function of x\nMATH_FUN_1(erf, erf)\n// erfc(x): return the complementary error function of x\nMATH_FUN_1(erfc, erfc)\n// gamma(x): return the gamma function of x\nMATH_FUN_1(gamma, tgamma)\n// lgamma(x): return the natural logarithm of the gamma function of x\nMATH_FUN_1(lgamma, lgamma)\n#endif\n// TODO: fsum\n\n#if MICROPY_PY_MATH_ISCLOSE\nSTATIC mp_obj_t mp_math_isclose(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_a, ARG_b, ARG_rel_tol, ARG_abs_tol };\n    static const mp_arg_t allowed_args[] = {\n        {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},\n        {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},\n        {MP_QSTR_rel_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},\n        {MP_QSTR_abs_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(0)}},\n    };\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n    const mp_float_t a = mp_obj_get_float(args[ARG_a].u_obj);\n    const mp_float_t b = mp_obj_get_float(args[ARG_b].u_obj);\n    const mp_float_t rel_tol = args[ARG_rel_tol].u_obj == MP_OBJ_NULL\n        ? (mp_float_t)1e-9 : mp_obj_get_float(args[ARG_rel_tol].u_obj);\n    const mp_float_t abs_tol = mp_obj_get_float(args[ARG_abs_tol].u_obj);\n    if (rel_tol < (mp_float_t)0.0 || abs_tol < (mp_float_t)0.0) {\n        math_error();\n    }\n    if (a == b) {\n        return mp_const_true;\n    }\n    const mp_float_t difference = MICROPY_FLOAT_C_FUN(fabs)(a - b);\n    if (isinf(difference)) { // Either a or b is inf\n        return mp_const_false;\n    }\n    if ((difference <= abs_tol) ||\n        (difference <= MICROPY_FLOAT_C_FUN(fabs)(rel_tol * a)) ||\n        (difference <= MICROPY_FLOAT_C_FUN(fabs)(rel_tol * b))) {\n        return mp_const_true;\n    }\n    return mp_const_false;\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(mp_math_isclose_obj, 2, mp_math_isclose);\n#endif\n\n// Function that takes a variable number of arguments\n\n// log(x[, base])\nSTATIC mp_obj_t mp_math_log(size_t n_args, const mp_obj_t *args) {\n    mp_float_t x = mp_obj_get_float(args[0]);\n    if (x <= (mp_float_t)0.0) {\n        math_error();\n    }\n    mp_float_t l = MICROPY_FLOAT_C_FUN(log)(x);\n    if (n_args == 1) {\n        return mp_obj_new_float(l);\n    } else {\n        mp_float_t base = mp_obj_get_float(args[1]);\n        if (base <= (mp_float_t)0.0) {\n            math_error();\n        } else if (base == (mp_float_t)1.0) {\n            mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT(\"divide by zero\"));\n        }\n        return mp_obj_new_float(l / MICROPY_FLOAT_C_FUN(log)(base));\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_math_log_obj, 1, 2, mp_math_log);\n\n// Functions that return a tuple\n\n// frexp(x): converts a floating-point number to fractional and integral components\nSTATIC mp_obj_t mp_math_frexp(mp_obj_t x_obj) {\n    int int_exponent = 0;\n    mp_float_t significand = MICROPY_FLOAT_C_FUN(frexp)(mp_obj_get_float(x_obj), &int_exponent);\n    mp_obj_t tuple[2];\n    tuple[0] = mp_obj_new_float(significand);\n    tuple[1] = mp_obj_new_int(int_exponent);\n    return mp_obj_new_tuple(2, tuple);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp);\n\n// modf(x)\nSTATIC mp_obj_t mp_math_modf(mp_obj_t x_obj) {\n    mp_float_t int_part = 0.0;\n    mp_float_t x = mp_obj_get_float(x_obj);\n    mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(x, &int_part);\n    #if MICROPY_PY_MATH_MODF_FIX_NEGZERO\n    if (fractional_part == MICROPY_FLOAT_CONST(0.0)) {\n        fractional_part = copysign(fractional_part, x);\n    }\n    #endif\n    mp_obj_t tuple[2];\n    tuple[0] = mp_obj_new_float(fractional_part);\n    tuple[1] = mp_obj_new_float(int_part);\n    return mp_obj_new_tuple(2, tuple);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf);\n\n// Angular conversions\n\n// radians(x)\nSTATIC mp_obj_t mp_math_radians(mp_obj_t x_obj) {\n    return mp_obj_new_float(mp_obj_get_float(x_obj) * (MP_PI / MICROPY_FLOAT_CONST(180.0)));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians);\n\n// degrees(x)\nSTATIC mp_obj_t mp_math_degrees(mp_obj_t x_obj) {\n    return mp_obj_new_float(mp_obj_get_float(x_obj) * (MICROPY_FLOAT_CONST(180.0) / MP_PI));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_degrees_obj, mp_math_degrees);\n\n#if MICROPY_PY_MATH_FACTORIAL\n\n#if MICROPY_OPT_MATH_FACTORIAL\n\n// factorial(x): slightly efficient recursive implementation\nSTATIC mp_obj_t mp_math_factorial_inner(mp_uint_t start, mp_uint_t end) {\n    if (start == end) {\n        return mp_obj_new_int(start);\n    } else if (end - start == 1) {\n        return mp_binary_op(MP_BINARY_OP_MULTIPLY, MP_OBJ_NEW_SMALL_INT(start), MP_OBJ_NEW_SMALL_INT(end));\n    } else if (end - start == 2) {\n        mp_obj_t left = MP_OBJ_NEW_SMALL_INT(start);\n        mp_obj_t middle = MP_OBJ_NEW_SMALL_INT(start + 1);\n        mp_obj_t right = MP_OBJ_NEW_SMALL_INT(end);\n        mp_obj_t tmp = mp_binary_op(MP_BINARY_OP_MULTIPLY, left, middle);\n        return mp_binary_op(MP_BINARY_OP_MULTIPLY, tmp, right);\n    } else {\n        mp_uint_t middle = start + ((end - start) >> 1);\n        mp_obj_t left = mp_math_factorial_inner(start, middle);\n        mp_obj_t right = mp_math_factorial_inner(middle + 1, end);\n        return mp_binary_op(MP_BINARY_OP_MULTIPLY, left, right);\n    }\n}\nSTATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) {\n    mp_int_t max = mp_obj_get_int(x_obj);\n    if (max < 0) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"negative factorial\"));\n    } else if (max == 0) {\n        return MP_OBJ_NEW_SMALL_INT(1);\n    }\n    return mp_math_factorial_inner(1, max);\n}\n\n#else\n\n// factorial(x): squared difference implementation\n// based on http://www.luschny.de/math/factorial/index.html\nSTATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) {\n    mp_int_t max = mp_obj_get_int(x_obj);\n    if (max < 0) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"negative factorial\"));\n    } else if (max <= 1) {\n        return MP_OBJ_NEW_SMALL_INT(1);\n    }\n    mp_int_t h = max >> 1;\n    mp_int_t q = h * h;\n    mp_int_t r = q << 1;\n    if (max & 1) {\n        r *= max;\n    }\n    mp_obj_t prod = MP_OBJ_NEW_SMALL_INT(r);\n    for (mp_int_t num = 1; num < max - 2; num += 2) {\n        q -= num;\n        prod = mp_binary_op(MP_BINARY_OP_MULTIPLY, prod, MP_OBJ_NEW_SMALL_INT(q));\n    }\n    return prod;\n}\n\n#endif\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_factorial_obj, mp_math_factorial);\n\n#endif\n\nSTATIC const mp_rom_map_elem_t mp_module_math_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_math) },\n    { MP_ROM_QSTR(MP_QSTR_e), mp_const_float_e },\n    { MP_ROM_QSTR(MP_QSTR_pi), mp_const_float_pi },\n    { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_math_sqrt_obj) },\n    { MP_ROM_QSTR(MP_QSTR_pow), MP_ROM_PTR(&mp_math_pow_obj) },\n    { MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&mp_math_exp_obj) },\n    #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS\n    { MP_ROM_QSTR(MP_QSTR_expm1), MP_ROM_PTR(&mp_math_expm1_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&mp_math_log_obj) },\n    #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS\n    { MP_ROM_QSTR(MP_QSTR_log2), MP_ROM_PTR(&mp_math_log2_obj) },\n    { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_math_log10_obj) },\n    { MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_math_cosh_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_math_sinh_obj) },\n    { MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_math_tanh_obj) },\n    { MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_math_acosh_obj) },\n    { MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_math_asinh_obj) },\n    { MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_math_atanh_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_math_cos_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_math_sin_obj) },\n    { MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_math_tan_obj) },\n    { MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_math_acos_obj) },\n    { MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_math_asin_obj) },\n    { MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_math_atan_obj) },\n    { MP_ROM_QSTR(MP_QSTR_atan2), MP_ROM_PTR(&mp_math_atan2_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ceil), MP_ROM_PTR(&mp_math_ceil_obj) },\n    { MP_ROM_QSTR(MP_QSTR_copysign), MP_ROM_PTR(&mp_math_copysign_obj) },\n    { MP_ROM_QSTR(MP_QSTR_fabs), MP_ROM_PTR(&mp_math_fabs_obj) },\n    { MP_ROM_QSTR(MP_QSTR_floor), MP_ROM_PTR(&mp_math_floor_obj) },\n    { MP_ROM_QSTR(MP_QSTR_fmod), MP_ROM_PTR(&mp_math_fmod_obj) },\n    { MP_ROM_QSTR(MP_QSTR_frexp), MP_ROM_PTR(&mp_math_frexp_obj) },\n    { MP_ROM_QSTR(MP_QSTR_ldexp), MP_ROM_PTR(&mp_math_ldexp_obj) },\n    { MP_ROM_QSTR(MP_QSTR_modf), MP_ROM_PTR(&mp_math_modf_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_math_isfinite_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_math_isinf_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_math_isnan_obj) },\n    #if MICROPY_PY_MATH_ISCLOSE\n    { MP_ROM_QSTR(MP_QSTR_isclose), MP_ROM_PTR(&mp_math_isclose_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_trunc), MP_ROM_PTR(&mp_math_trunc_obj) },\n    { MP_ROM_QSTR(MP_QSTR_radians), MP_ROM_PTR(&mp_math_radians_obj) },\n    { MP_ROM_QSTR(MP_QSTR_degrees), MP_ROM_PTR(&mp_math_degrees_obj) },\n    #if MICROPY_PY_MATH_FACTORIAL\n    { MP_ROM_QSTR(MP_QSTR_factorial), MP_ROM_PTR(&mp_math_factorial_obj) },\n    #endif\n    #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS\n    { MP_ROM_QSTR(MP_QSTR_erf), MP_ROM_PTR(&mp_math_erf_obj) },\n    { MP_ROM_QSTR(MP_QSTR_erfc), MP_ROM_PTR(&mp_math_erfc_obj) },\n    { MP_ROM_QSTR(MP_QSTR_gamma), MP_ROM_PTR(&mp_math_gamma_obj) },\n    { MP_ROM_QSTR(MP_QSTR_lgamma), MP_ROM_PTR(&mp_math_lgamma_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_math_globals, mp_module_math_globals_table);\n\nconst mp_obj_module_t mp_module_math = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_math_globals,\n};\n\n#endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH\n"
  },
  {
    "path": "py/modmicropython.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n\n#include \"py/builtin.h\"\n#include \"py/stackctrl.h\"\n#include \"py/runtime.h\"\n#include \"py/gc.h\"\n#include \"py/mphal.h\"\n\n// Various builtins specific to MicroPython runtime,\n// living in micropython module\n\n#if MICROPY_ENABLE_COMPILER\nSTATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) {\n    if (n_args == 0) {\n        return MP_OBJ_NEW_SMALL_INT(MP_STATE_VM(mp_optimise_value));\n    } else {\n        MP_STATE_VM(mp_optimise_value) = mp_obj_get_int(args[0]);\n        return mp_const_none;\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_opt_level_obj, 0, 1, mp_micropython_opt_level);\n#endif\n\n#if MICROPY_PY_MICROPYTHON_MEM_INFO\n\n#if MICROPY_MEM_STATS\nSTATIC mp_obj_t mp_micropython_mem_total(void) {\n    return MP_OBJ_NEW_SMALL_INT(m_get_total_bytes_allocated());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_total_obj, mp_micropython_mem_total);\n\nSTATIC mp_obj_t mp_micropython_mem_current(void) {\n    return MP_OBJ_NEW_SMALL_INT(m_get_current_bytes_allocated());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_current_obj, mp_micropython_mem_current);\n\nSTATIC mp_obj_t mp_micropython_mem_peak(void) {\n    return MP_OBJ_NEW_SMALL_INT(m_get_peak_bytes_allocated());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem_peak);\n#endif\n\nmp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args) {\n    (void)args;\n    #if MICROPY_MEM_STATS\n    mp_printf(&mp_plat_print, \"mem: total=\" UINT_FMT \", current=\" UINT_FMT \", peak=\" UINT_FMT \"\\n\",\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());\n    #endif\n    #if MICROPY_STACK_CHECK\n    mp_printf(&mp_plat_print, \"stack: \" UINT_FMT \" out of \" UINT_FMT \"\\n\",\n        mp_stack_usage(), (mp_uint_t)MP_STATE_THREAD(stack_limit));\n    #else\n    mp_printf(&mp_plat_print, \"stack: \" UINT_FMT \"\\n\", mp_stack_usage());\n    #endif\n    #if MICROPY_ENABLE_GC\n    gc_dump_info();\n    if (n_args == 1) {\n        // arg given means dump gc allocation table\n        gc_dump_alloc_table();\n    }\n    #else\n    (void)n_args;\n    #endif\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_mem_info_obj, 0, 1, mp_micropython_mem_info);\n\nSTATIC mp_obj_t mp_micropython_qstr_info(size_t n_args, const mp_obj_t *args) {\n    (void)args;\n    size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;\n    qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);\n    mp_printf(&mp_plat_print, \"qstr pool: n_pool=%u, n_qstr=%u, n_str_data_bytes=%u, n_total_bytes=%u\\n\",\n        n_pool, n_qstr, n_str_data_bytes, n_total_bytes);\n    if (n_args == 1) {\n        // arg given means dump qstr data\n        qstr_dump_data();\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_qstr_info_obj, 0, 1, mp_micropython_qstr_info);\n\n#endif // MICROPY_PY_MICROPYTHON_MEM_INFO\n\n#if MICROPY_PY_MICROPYTHON_STACK_USE\nSTATIC mp_obj_t mp_micropython_stack_use(void) {\n    return MP_OBJ_NEW_SMALL_INT(mp_stack_usage());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_stack_use_obj, mp_micropython_stack_use);\n#endif\n\n#if MICROPY_ENABLE_PYSTACK\nSTATIC mp_obj_t mp_micropython_pystack_use(void) {\n    return MP_OBJ_NEW_SMALL_INT(mp_pystack_usage());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_pystack_use_obj, mp_micropython_pystack_use);\n#endif\n\n#if MICROPY_ENABLE_GC\nSTATIC mp_obj_t mp_micropython_heap_lock(void) {\n    gc_lock();\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_lock_obj, mp_micropython_heap_lock);\n\nSTATIC mp_obj_t mp_micropython_heap_unlock(void) {\n    gc_unlock();\n    return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_lock_depth));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_unlock_obj, mp_micropython_heap_unlock);\n\n#if MICROPY_PY_MICROPYTHON_HEAP_LOCKED\nSTATIC mp_obj_t mp_micropython_heap_locked(void) {\n    return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_lock_depth));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_locked_obj, mp_micropython_heap_locked);\n#endif\n#endif\n\n#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf);\n#endif\n\n#if MICROPY_KBD_EXCEPTION\nSTATIC mp_obj_t mp_micropython_kbd_intr(mp_obj_t int_chr_in) {\n    mp_hal_set_interrupt_char(mp_obj_get_int(int_chr_in));\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd_intr);\n#endif\n\n#if MICROPY_ENABLE_SCHEDULER\nSTATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) {\n    if (!mp_sched_schedule(function, arg)) {\n        mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"schedule queue full\"));\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_micropython_schedule_obj, mp_micropython_schedule);\n#endif\n\nSTATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) },\n    { MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) },\n    #if MICROPY_ENABLE_COMPILER\n    { MP_ROM_QSTR(MP_QSTR_opt_level), MP_ROM_PTR(&mp_micropython_opt_level_obj) },\n    #endif\n    #if MICROPY_PY_MICROPYTHON_MEM_INFO\n    #if MICROPY_MEM_STATS\n    { MP_ROM_QSTR(MP_QSTR_mem_total), MP_ROM_PTR(&mp_micropython_mem_total_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mem_current), MP_ROM_PTR(&mp_micropython_mem_current_obj) },\n    { MP_ROM_QSTR(MP_QSTR_mem_peak), MP_ROM_PTR(&mp_micropython_mem_peak_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_mem_info), MP_ROM_PTR(&mp_micropython_mem_info_obj) },\n    { MP_ROM_QSTR(MP_QSTR_qstr_info), MP_ROM_PTR(&mp_micropython_qstr_info_obj) },\n    #endif\n    #if MICROPY_PY_MICROPYTHON_STACK_USE\n    { MP_ROM_QSTR(MP_QSTR_stack_use), MP_ROM_PTR(&mp_micropython_stack_use_obj) },\n    #endif\n    #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)\n    { MP_ROM_QSTR(MP_QSTR_alloc_emergency_exception_buf), MP_ROM_PTR(&mp_alloc_emergency_exception_buf_obj) },\n    #endif\n    #if MICROPY_ENABLE_PYSTACK\n    { MP_ROM_QSTR(MP_QSTR_pystack_use), MP_ROM_PTR(&mp_micropython_pystack_use_obj) },\n    #endif\n    #if MICROPY_ENABLE_GC\n    { MP_ROM_QSTR(MP_QSTR_heap_lock), MP_ROM_PTR(&mp_micropython_heap_lock_obj) },\n    { MP_ROM_QSTR(MP_QSTR_heap_unlock), MP_ROM_PTR(&mp_micropython_heap_unlock_obj) },\n    #if MICROPY_PY_MICROPYTHON_HEAP_LOCKED\n    { MP_ROM_QSTR(MP_QSTR_heap_locked), MP_ROM_PTR(&mp_micropython_heap_locked_obj) },\n    #endif\n    #endif\n    #if MICROPY_KBD_EXCEPTION\n    { MP_ROM_QSTR(MP_QSTR_kbd_intr), MP_ROM_PTR(&mp_micropython_kbd_intr_obj) },\n    #endif\n    #if MICROPY_ENABLE_SCHEDULER\n    { MP_ROM_QSTR(MP_QSTR_schedule), MP_ROM_PTR(&mp_micropython_schedule_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_micropython_globals, mp_module_micropython_globals_table);\n\nconst mp_obj_module_t mp_module_micropython = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_micropython_globals,\n};\n"
  },
  {
    "path": "py/modstruct.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/builtin.h\"\n#include \"py/objtuple.h\"\n#include \"py/binary.h\"\n#include \"py/parsenum.h\"\n\n#if MICROPY_PY_STRUCT\n\n/*\n    This module implements most of character typecodes from CPython, with\n    some extensions:\n\n    O - (Pointer to) an arbitrary Python object. This is useful for callback\n        data, etc. Note that you must keep reference to passed object in\n        your Python application, otherwise it may be garbage-collected,\n        and then when you get back this value from callback it may be\n        invalid (and lead to crash).\n    S - Pointer to a string (returned as a Python string). Note the\n        difference from \"Ns\", - the latter says \"in this place of structure\n        is character data of up to N bytes length\", while \"S\" means\n        \"in this place of a structure is a pointer to zero-terminated\n        character data\".\n */\n\nSTATIC char get_fmt_type(const char **fmt) {\n    char t = **fmt;\n    switch (t) {\n        case '!':\n            t = '>';\n            break;\n        case '@':\n        case '=':\n        case '<':\n        case '>':\n            break;\n        default:\n            return '@';\n    }\n    // Skip type char\n    (*fmt)++;\n    return t;\n}\n\nSTATIC mp_uint_t get_fmt_num(const char **p) {\n    const char *num = *p;\n    uint len = 1;\n    while (unichar_isdigit(*++num)) {\n        len++;\n    }\n    mp_uint_t val = (mp_uint_t)MP_OBJ_SMALL_INT_VALUE(mp_parse_num_integer(*p, len, 10, NULL));\n    *p = num;\n    return val;\n}\n\nSTATIC size_t calc_size_items(const char *fmt, size_t *total_sz) {\n    char fmt_type = get_fmt_type(&fmt);\n    size_t total_cnt = 0;\n    size_t size;\n    for (size = 0; *fmt; fmt++) {\n        mp_uint_t cnt = 1;\n        if (unichar_isdigit(*fmt)) {\n            cnt = get_fmt_num(&fmt);\n        }\n\n        if (*fmt == 's') {\n            total_cnt += 1;\n            size += cnt;\n        } else {\n            total_cnt += cnt;\n            size_t align;\n            size_t sz = mp_binary_get_size(fmt_type, *fmt, &align);\n            while (cnt--) {\n                // Apply alignment\n                size = (size + align - 1) & ~(align - 1);\n                size += sz;\n            }\n        }\n    }\n    *total_sz = size;\n    return total_cnt;\n}\n\nSTATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {\n    const char *fmt = mp_obj_str_get_str(fmt_in);\n    size_t size;\n    calc_size_items(fmt, &size);\n    return MP_OBJ_NEW_SMALL_INT(size);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(struct_calcsize_obj, struct_calcsize);\n\nSTATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {\n    // unpack requires that the buffer be exactly the right size.\n    // unpack_from requires that the buffer be \"big enough\".\n    // Since we implement unpack and unpack_from using the same function\n    // we relax the \"exact\" requirement, and only implement \"big enough\".\n    const char *fmt = mp_obj_str_get_str(args[0]);\n    size_t total_sz;\n    size_t num_items = calc_size_items(fmt, &total_sz);\n    char fmt_type = get_fmt_type(&fmt);\n    mp_obj_tuple_t *res = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_items, NULL));\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);\n    byte *p = bufinfo.buf;\n    byte *end_p = &p[bufinfo.len];\n    mp_int_t offset = 0;\n\n    if (n_args > 2) {\n        // offset arg provided\n        offset = mp_obj_get_int(args[2]);\n        if (offset < 0) {\n            // negative offsets are relative to the end of the buffer\n            offset = bufinfo.len + offset;\n            if (offset < 0) {\n                mp_raise_ValueError(MP_ERROR_TEXT(\"buffer too small\"));\n            }\n        }\n        p += offset;\n    }\n    byte *p_base = p;\n\n    // Check that the input buffer is big enough to unpack all the values\n    if (p + total_sz > end_p) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"buffer too small\"));\n    }\n\n    for (size_t i = 0; i < num_items;) {\n        mp_uint_t cnt = 1;\n        if (unichar_isdigit(*fmt)) {\n            cnt = get_fmt_num(&fmt);\n        }\n        mp_obj_t item;\n        if (*fmt == 's') {\n            item = mp_obj_new_bytes(p, cnt);\n            p += cnt;\n            res->items[i++] = item;\n        } else {\n            while (cnt--) {\n                item = mp_binary_get_val(fmt_type, *fmt, p_base, &p);\n                res->items[i++] = item;\n            }\n        }\n        fmt++;\n    }\n    return MP_OBJ_FROM_PTR(res);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_unpack_from_obj, 2, 3, struct_unpack_from);\n\n// This function assumes there is enough room in p to store all the values\nSTATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, const mp_obj_t *args) {\n    const char *fmt = mp_obj_str_get_str(fmt_in);\n    char fmt_type = get_fmt_type(&fmt);\n\n    byte *p_base = p;\n    size_t i;\n    for (i = 0; i < n_args;) {\n        mp_uint_t cnt = 1;\n        if (*fmt == '\\0') {\n            // more arguments given than used by format string; CPython raises struct.error here\n            break;\n        }\n        if (unichar_isdigit(*fmt)) {\n            cnt = get_fmt_num(&fmt);\n        }\n\n        if (*fmt == 's') {\n            mp_buffer_info_t bufinfo;\n            mp_get_buffer_raise(args[i++], &bufinfo, MP_BUFFER_READ);\n            mp_uint_t to_copy = cnt;\n            if (bufinfo.len < to_copy) {\n                to_copy = bufinfo.len;\n            }\n            memcpy(p, bufinfo.buf, to_copy);\n            memset(p + to_copy, 0, cnt - to_copy);\n            p += cnt;\n        } else {\n            // If we run out of args then we just finish; CPython would raise struct.error\n            while (cnt-- && i < n_args) {\n                mp_binary_set_val(fmt_type, *fmt, args[i++], p_base, &p);\n            }\n        }\n        fmt++;\n    }\n}\n\nSTATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t *args) {\n    // TODO: \"The arguments must match the values required by the format exactly.\"\n    mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));\n    vstr_t vstr;\n    vstr_init_len(&vstr, size);\n    byte *p = (byte *)vstr.buf;\n    memset(p, 0, size);\n    struct_pack_into_internal(args[0], p, n_args - 1, &args[1]);\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_obj, 1, MP_OBJ_FUN_ARGS_MAX, struct_pack);\n\nSTATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);\n    mp_int_t offset = mp_obj_get_int(args[2]);\n    if (offset < 0) {\n        // negative offsets are relative to the end of the buffer\n        offset = (mp_int_t)bufinfo.len + offset;\n        if (offset < 0) {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"buffer too small\"));\n        }\n    }\n    byte *p = (byte *)bufinfo.buf;\n    byte *end_p = &p[bufinfo.len];\n    p += offset;\n\n    // Check that the output buffer is big enough to hold all the values\n    mp_int_t sz = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));\n    if (p + sz > end_p) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"buffer too small\"));\n    }\n\n    struct_pack_into_internal(args[0], p, n_args - 3, &args[3]);\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_into_obj, 3, MP_OBJ_FUN_ARGS_MAX, struct_pack_into);\n\nSTATIC const mp_rom_map_elem_t mp_module_struct_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ustruct) },\n    { MP_ROM_QSTR(MP_QSTR_calcsize), MP_ROM_PTR(&struct_calcsize_obj) },\n    { MP_ROM_QSTR(MP_QSTR_pack), MP_ROM_PTR(&struct_pack_obj) },\n    { MP_ROM_QSTR(MP_QSTR_pack_into), MP_ROM_PTR(&struct_pack_into_obj) },\n    { MP_ROM_QSTR(MP_QSTR_unpack), MP_ROM_PTR(&struct_unpack_from_obj) },\n    { MP_ROM_QSTR(MP_QSTR_unpack_from), MP_ROM_PTR(&struct_unpack_from_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_struct_globals, mp_module_struct_globals_table);\n\nconst mp_obj_module_t mp_module_ustruct = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_struct_globals,\n};\n\n#endif\n"
  },
  {
    "path": "py/modsys.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014-2017 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/builtin.h\"\n#include \"py/objlist.h\"\n#include \"py/objtuple.h\"\n#include \"py/objstr.h\"\n#include \"py/objint.h\"\n#include \"py/objtype.h\"\n#include \"py/stream.h\"\n#include \"py/smallint.h\"\n#include \"py/runtime.h\"\n#include \"py/persistentcode.h\"\n\n#if MICROPY_PY_SYS_SETTRACE\n#include \"py/objmodule.h\"\n#include \"py/profile.h\"\n#endif\n\n#if MICROPY_PY_SYS\n\n// defined per port; type of these is irrelevant, just need pointer\nextern struct _mp_dummy_t mp_sys_stdin_obj;\nextern struct _mp_dummy_t mp_sys_stdout_obj;\nextern struct _mp_dummy_t mp_sys_stderr_obj;\n\n#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES\nconst mp_print_t mp_sys_stdout_print = {&mp_sys_stdout_obj, mp_stream_write_adaptor};\n#endif\n\n// version - Python language version that this implementation conforms to, as a string\nSTATIC const MP_DEFINE_STR_OBJ(mp_sys_version_obj, \"3.4.0\");\n\n// version_info - Python language version that this implementation conforms to, as a tuple of ints\n#define I(n) MP_OBJ_NEW_SMALL_INT(n)\n// TODO: CPython is now at 5-element array, but save 2 els so far...\nSTATIC const mp_obj_tuple_t mp_sys_version_info_obj = {{&mp_type_tuple}, 3, {I(3), I(4), I(0)}};\n\n// sys.implementation object\n// this holds the MicroPython version\nSTATIC const mp_obj_tuple_t mp_sys_implementation_version_info_obj = {\n    {&mp_type_tuple},\n    3,\n    { I(MICROPY_VERSION_MAJOR), I(MICROPY_VERSION_MINOR), I(MICROPY_VERSION_MICRO) }\n};\n#if MICROPY_PERSISTENT_CODE_LOAD\n#define SYS_IMPLEMENTATION_ELEMS \\\n    MP_ROM_QSTR(MP_QSTR_micropython), \\\n    MP_ROM_PTR(&mp_sys_implementation_version_info_obj), \\\n    MP_ROM_INT(MPY_FILE_HEADER_INT)\n#else\n#define SYS_IMPLEMENTATION_ELEMS \\\n    MP_ROM_QSTR(MP_QSTR_micropython), \\\n    MP_ROM_PTR(&mp_sys_implementation_version_info_obj)\n#endif\n#if MICROPY_PY_ATTRTUPLE\nSTATIC const qstr impl_fields[] = {\n    MP_QSTR_name,\n    MP_QSTR_version,\n    #if MICROPY_PERSISTENT_CODE_LOAD\n    MP_QSTR_mpy,\n    #endif\n};\nSTATIC MP_DEFINE_ATTRTUPLE(\n    mp_sys_implementation_obj,\n    impl_fields,\n    2 + MICROPY_PERSISTENT_CODE_LOAD,\n    SYS_IMPLEMENTATION_ELEMS\n    );\n#else\nSTATIC const mp_rom_obj_tuple_t mp_sys_implementation_obj = {\n    {&mp_type_tuple},\n    2 + MICROPY_PERSISTENT_CODE_LOAD,\n    {\n        SYS_IMPLEMENTATION_ELEMS\n    }\n};\n#endif\n\n#undef I\n\n#ifdef MICROPY_PY_SYS_PLATFORM\n// platform - the platform that MicroPython is running on\nSTATIC const MP_DEFINE_STR_OBJ(mp_sys_platform_obj, MICROPY_PY_SYS_PLATFORM);\n#endif\n\n// exit([retval]): raise SystemExit, with optional argument given to the exception\nSTATIC mp_obj_t mp_sys_exit(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t exc;\n    if (n_args == 0) {\n        exc = mp_obj_new_exception(&mp_type_SystemExit);\n    } else {\n        exc = mp_obj_new_exception_arg1(&mp_type_SystemExit, args[0]);\n    }\n    nlr_raise(exc);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit);\n\nSTATIC mp_obj_t mp_sys_print_exception(size_t n_args, const mp_obj_t *args) {\n    #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES\n    void *stream_obj = &mp_sys_stdout_obj;\n    if (n_args > 1) {\n        mp_get_stream_raise(args[1], MP_STREAM_OP_WRITE);\n        stream_obj = MP_OBJ_TO_PTR(args[1]);\n    }\n\n    mp_print_t print = {stream_obj, mp_stream_write_adaptor};\n    mp_obj_print_exception(&print, args[0]);\n    #else\n    (void)n_args;\n    mp_obj_print_exception(&mp_plat_print, args[0]);\n    #endif\n\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_print_exception_obj, 1, 2, mp_sys_print_exception);\n\n#if MICROPY_PY_SYS_EXC_INFO\nSTATIC mp_obj_t mp_sys_exc_info(void) {\n    mp_obj_t cur_exc = MP_OBJ_FROM_PTR(MP_STATE_VM(cur_exception));\n    mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));\n\n    if (cur_exc == MP_OBJ_NULL) {\n        t->items[0] = mp_const_none;\n        t->items[1] = mp_const_none;\n        t->items[2] = mp_const_none;\n        return MP_OBJ_FROM_PTR(t);\n    }\n\n    t->items[0] = MP_OBJ_FROM_PTR(mp_obj_get_type(cur_exc));\n    t->items[1] = cur_exc;\n    t->items[2] = mp_const_none;\n    return MP_OBJ_FROM_PTR(t);\n}\nMP_DEFINE_CONST_FUN_OBJ_0(mp_sys_exc_info_obj, mp_sys_exc_info);\n#endif\n\n#if MICROPY_PY_SYS_GETSIZEOF\nSTATIC mp_obj_t mp_sys_getsizeof(mp_obj_t obj) {\n    return mp_unary_op(MP_UNARY_OP_SIZEOF, obj);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof);\n#endif\n\n#if MICROPY_PY_SYS_ATEXIT\n// atexit(callback): Callback is called when sys.exit is called.\nSTATIC mp_obj_t mp_sys_atexit(mp_obj_t obj) {\n    mp_obj_t old = MP_STATE_VM(sys_exitfunc);\n    MP_STATE_VM(sys_exitfunc) = obj;\n    return old;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_atexit_obj, mp_sys_atexit);\n#endif\n\n#if MICROPY_PY_SYS_SETTRACE\n// settrace(tracefunc): Set the system’s trace function.\nSTATIC mp_obj_t mp_sys_settrace(mp_obj_t obj) {\n    return mp_prof_settrace(obj);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_sys_settrace_obj, mp_sys_settrace);\n#endif // MICROPY_PY_SYS_SETTRACE\n\nSTATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys) },\n\n    { MP_ROM_QSTR(MP_QSTR_path), MP_ROM_PTR(&MP_STATE_VM(mp_sys_path_obj)) },\n    { MP_ROM_QSTR(MP_QSTR_argv), MP_ROM_PTR(&MP_STATE_VM(mp_sys_argv_obj)) },\n    { MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&mp_sys_version_obj) },\n    { MP_ROM_QSTR(MP_QSTR_version_info), MP_ROM_PTR(&mp_sys_version_info_obj) },\n    { MP_ROM_QSTR(MP_QSTR_implementation), MP_ROM_PTR(&mp_sys_implementation_obj) },\n    #ifdef MICROPY_PY_SYS_PLATFORM\n    { MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&mp_sys_platform_obj) },\n    #endif\n    #if MP_ENDIANNESS_LITTLE\n    { MP_ROM_QSTR(MP_QSTR_byteorder), MP_ROM_QSTR(MP_QSTR_little) },\n    #else\n    { MP_ROM_QSTR(MP_QSTR_byteorder), MP_ROM_QSTR(MP_QSTR_big) },\n    #endif\n\n    #if MICROPY_PY_SYS_MAXSIZE\n    #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE\n    // Maximum mp_int_t value is not representable as small int, so we have\n    // little choice but to use MP_SMALL_INT_MAX. Apps also should be careful\n    // to not try to compare sys.maxsize to some literal number (as this\n    // number might not fit in available int size), but instead count number\n    // of \"one\" bits in sys.maxsize.\n    { MP_ROM_QSTR(MP_QSTR_maxsize), MP_ROM_INT(MP_SMALL_INT_MAX) },\n    #else\n    { MP_ROM_QSTR(MP_QSTR_maxsize), MP_ROM_PTR(&mp_sys_maxsize_obj) },\n    #endif\n    #endif\n\n    #if MICROPY_PY_SYS_EXIT\n    { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mp_sys_exit_obj) },\n    #endif\n\n    #if MICROPY_PY_SYS_SETTRACE\n    { MP_ROM_QSTR(MP_QSTR_settrace), MP_ROM_PTR(&mp_sys_settrace_obj) },\n    #endif\n\n    #if MICROPY_PY_SYS_STDFILES\n    { MP_ROM_QSTR(MP_QSTR_stdin), MP_ROM_PTR(&mp_sys_stdin_obj) },\n    { MP_ROM_QSTR(MP_QSTR_stdout), MP_ROM_PTR(&mp_sys_stdout_obj) },\n    { MP_ROM_QSTR(MP_QSTR_stderr), MP_ROM_PTR(&mp_sys_stderr_obj) },\n    #endif\n\n    #if MICROPY_PY_SYS_MODULES\n    { MP_ROM_QSTR(MP_QSTR_modules), MP_ROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)) },\n    #endif\n    #if MICROPY_PY_SYS_EXC_INFO\n    { MP_ROM_QSTR(MP_QSTR_exc_info), MP_ROM_PTR(&mp_sys_exc_info_obj) },\n    #endif\n    #if MICROPY_PY_SYS_GETSIZEOF\n    { MP_ROM_QSTR(MP_QSTR_getsizeof), MP_ROM_PTR(&mp_sys_getsizeof_obj) },\n    #endif\n\n    /*\n     * Extensions to CPython\n     */\n\n    { MP_ROM_QSTR(MP_QSTR_print_exception), MP_ROM_PTR(&mp_sys_print_exception_obj) },\n    #if MICROPY_PY_SYS_ATEXIT\n    { MP_ROM_QSTR(MP_QSTR_atexit), MP_ROM_PTR(&mp_sys_atexit_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table);\n\nconst mp_obj_module_t mp_module_sys = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_sys_globals,\n};\n\n#endif\n"
  },
  {
    "path": "py/modthread.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/runtime.h\"\n#include \"py/stackctrl.h\"\n\n#if MICROPY_PY_THREAD\n\n#include \"py/mpthread.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_PRINT (1)\n#define DEBUG_printf DEBUG_printf\n#else // don't print debugging info\n#define DEBUG_PRINT (0)\n#define DEBUG_printf(...) (void)0\n#endif\n\n/****************************************************************/\n// Lock object\n\nSTATIC const mp_obj_type_t mp_type_thread_lock;\n\ntypedef struct _mp_obj_thread_lock_t {\n    mp_obj_base_t base;\n    mp_thread_mutex_t mutex;\n    volatile bool locked;\n} mp_obj_thread_lock_t;\n\nSTATIC mp_obj_thread_lock_t *mp_obj_new_thread_lock(void) {\n    mp_obj_thread_lock_t *self = m_new_obj(mp_obj_thread_lock_t);\n    self->base.type = &mp_type_thread_lock;\n    mp_thread_mutex_init(&self->mutex);\n    self->locked = false;\n    return self;\n}\n\nSTATIC mp_obj_t thread_lock_acquire(size_t n_args, const mp_obj_t *args) {\n    mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(args[0]);\n    bool wait = true;\n    if (n_args > 1) {\n        wait = mp_obj_get_int(args[1]);\n        // TODO support timeout arg\n    }\n    MP_THREAD_GIL_EXIT();\n    int ret = mp_thread_mutex_lock(&self->mutex, wait);\n    MP_THREAD_GIL_ENTER();\n    if (ret == 0) {\n        return mp_const_false;\n    } else if (ret == 1) {\n        self->locked = true;\n        return mp_const_true;\n    } else {\n        mp_raise_OSError(-ret);\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock_acquire_obj, 1, 3, thread_lock_acquire);\n\nSTATIC mp_obj_t thread_lock_release(mp_obj_t self_in) {\n    mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in);\n    if (!self->locked) {\n        mp_raise_msg(&mp_type_RuntimeError, NULL);\n    }\n    self->locked = false;\n    MP_THREAD_GIL_EXIT();\n    mp_thread_mutex_unlock(&self->mutex);\n    MP_THREAD_GIL_ENTER();\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_release_obj, thread_lock_release);\n\nSTATIC mp_obj_t thread_lock_locked(mp_obj_t self_in) {\n    mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in);\n    return mp_obj_new_bool(self->locked);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_locked_obj, thread_lock_locked);\n\nSTATIC mp_obj_t thread_lock___exit__(size_t n_args, const mp_obj_t *args) {\n    (void)n_args; // unused\n    return thread_lock_release(args[0]);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock___exit___obj, 4, 4, thread_lock___exit__);\n\nSTATIC const mp_rom_map_elem_t thread_lock_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_acquire), MP_ROM_PTR(&thread_lock_acquire_obj) },\n    { MP_ROM_QSTR(MP_QSTR_release), MP_ROM_PTR(&thread_lock_release_obj) },\n    { MP_ROM_QSTR(MP_QSTR_locked), MP_ROM_PTR(&thread_lock_locked_obj) },\n    { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&thread_lock_acquire_obj) },\n    { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&thread_lock___exit___obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(thread_lock_locals_dict, thread_lock_locals_dict_table);\n\nSTATIC const mp_obj_type_t mp_type_thread_lock = {\n    { &mp_type_type },\n    .name = MP_QSTR_lock,\n    .locals_dict = (mp_obj_dict_t *)&thread_lock_locals_dict,\n};\n\n/****************************************************************/\n// _thread module\n\nSTATIC size_t thread_stack_size = 0;\n\nSTATIC mp_obj_t mod_thread_get_ident(void) {\n    return mp_obj_new_int_from_uint((uintptr_t)mp_thread_get_state());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_get_ident_obj, mod_thread_get_ident);\n\nSTATIC mp_obj_t mod_thread_stack_size(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t ret = mp_obj_new_int_from_uint(thread_stack_size);\n    if (n_args == 0) {\n        thread_stack_size = 0;\n    } else {\n        thread_stack_size = mp_obj_get_int(args[0]);\n    }\n    return ret;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_stack_size_obj, 0, 1, mod_thread_stack_size);\n\ntypedef struct _thread_entry_args_t {\n    mp_obj_dict_t *dict_locals;\n    mp_obj_dict_t *dict_globals;\n    size_t stack_size;\n    mp_obj_t fun;\n    size_t n_args;\n    size_t n_kw;\n    mp_obj_t args[];\n} thread_entry_args_t;\n\nSTATIC void *thread_entry(void *args_in) {\n    // Execution begins here for a new thread.  We do not have the GIL.\n\n    thread_entry_args_t *args = (thread_entry_args_t *)args_in;\n\n    mp_state_thread_t ts;\n    mp_thread_set_state(&ts);\n\n    mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan\n    mp_stack_set_limit(args->stack_size);\n\n    #if MICROPY_ENABLE_PYSTACK\n    // TODO threading and pystack is not fully supported, for now just make a small stack\n    mp_obj_t mini_pystack[128];\n    mp_pystack_init(mini_pystack, &mini_pystack[128]);\n    #endif\n\n    // set locals and globals from the calling context\n    mp_locals_set(args->dict_locals);\n    mp_globals_set(args->dict_globals);\n\n    MP_THREAD_GIL_ENTER();\n\n    // signal that we are set up and running\n    mp_thread_start();\n\n    // TODO set more thread-specific state here:\n    //  mp_pending_exception? (root pointer)\n    //  cur_exception (root pointer)\n\n    DEBUG_printf(\"[thread] start ts=%p args=%p stack=%p\\n\", &ts, &args, MP_STATE_THREAD(stack_top));\n\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        mp_call_function_n_kw(args->fun, args->n_args, args->n_kw, args->args);\n        nlr_pop();\n    } else {\n        // uncaught exception\n        // check for SystemExit\n        mp_obj_base_t *exc = (mp_obj_base_t *)nlr.ret_val;\n        if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {\n            // swallow exception silently\n        } else {\n            // print exception out\n            mp_printf(MICROPY_ERROR_PRINTER, \"Unhandled exception in thread started by \");\n            mp_obj_print_helper(MICROPY_ERROR_PRINTER, args->fun, PRINT_REPR);\n            mp_printf(MICROPY_ERROR_PRINTER, \"\\n\");\n            mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(exc));\n        }\n    }\n\n    DEBUG_printf(\"[thread] finish ts=%p\\n\", &ts);\n\n    // signal that we are finished\n    mp_thread_finish();\n\n    MP_THREAD_GIL_EXIT();\n\n    return NULL;\n}\n\nSTATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) {\n    // This structure holds the Python function and arguments for thread entry.\n    // We copy all arguments into this structure to keep ownership of them.\n    // We must be very careful about root pointers because this pointer may\n    // disappear from our address space before the thread is created.\n    thread_entry_args_t *th_args;\n\n    // get positional arguments\n    size_t pos_args_len;\n    mp_obj_t *pos_args_items;\n    mp_obj_get_array(args[1], &pos_args_len, &pos_args_items);\n\n    // check for keyword arguments\n    if (n_args == 2) {\n        // just position arguments\n        th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len);\n        th_args->n_kw = 0;\n    } else {\n        // positional and keyword arguments\n        if (mp_obj_get_type(args[2]) != &mp_type_dict) {\n            mp_raise_TypeError(MP_ERROR_TEXT(\"expecting a dict for keyword args\"));\n        }\n        mp_map_t *map = &((mp_obj_dict_t *)MP_OBJ_TO_PTR(args[2]))->map;\n        th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used);\n        th_args->n_kw = map->used;\n        // copy across the keyword arguments\n        for (size_t i = 0, n = pos_args_len; i < map->alloc; ++i) {\n            if (mp_map_slot_is_filled(map, i)) {\n                th_args->args[n++] = map->table[i].key;\n                th_args->args[n++] = map->table[i].value;\n            }\n        }\n    }\n\n    // copy across the positional arguments\n    th_args->n_args = pos_args_len;\n    memcpy(th_args->args, pos_args_items, pos_args_len * sizeof(mp_obj_t));\n\n    // pass our locals and globals into the new thread\n    th_args->dict_locals = mp_locals_get();\n    th_args->dict_globals = mp_globals_get();\n\n    // set the stack size to use\n    th_args->stack_size = thread_stack_size;\n\n    // set the function for thread entry\n    th_args->fun = args[0];\n\n    // spawn the thread!\n    mp_thread_create(thread_entry, th_args, &th_args->stack_size);\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_start_new_thread_obj, 2, 3, mod_thread_start_new_thread);\n\nSTATIC mp_obj_t mod_thread_exit(void) {\n    mp_raise_type(&mp_type_SystemExit);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_exit_obj, mod_thread_exit);\n\nSTATIC mp_obj_t mod_thread_allocate_lock(void) {\n    return MP_OBJ_FROM_PTR(mp_obj_new_thread_lock());\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_allocate_lock_obj, mod_thread_allocate_lock);\n\nSTATIC const mp_rom_map_elem_t mp_module_thread_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__thread) },\n    { MP_ROM_QSTR(MP_QSTR_LockType), MP_ROM_PTR(&mp_type_thread_lock) },\n    { MP_ROM_QSTR(MP_QSTR_get_ident), MP_ROM_PTR(&mod_thread_get_ident_obj) },\n    { MP_ROM_QSTR(MP_QSTR_stack_size), MP_ROM_PTR(&mod_thread_stack_size_obj) },\n    { MP_ROM_QSTR(MP_QSTR_start_new_thread), MP_ROM_PTR(&mod_thread_start_new_thread_obj) },\n    { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mod_thread_exit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_allocate_lock), MP_ROM_PTR(&mod_thread_allocate_lock_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_thread_globals, mp_module_thread_globals_table);\n\nconst mp_obj_module_t mp_module_thread = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_thread_globals,\n};\n\n#endif // MICROPY_PY_THREAD\n"
  },
  {
    "path": "py/moduerrno.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <string.h>\n\n#include \"py/obj.h\"\n#include \"py/mperrno.h\"\n\n#if MICROPY_PY_UERRNO\n\n// This list can be defined per port in mpconfigport.h to tailor it to a\n// specific port's needs.  If it's not defined then we provide a default.\n#ifndef MICROPY_PY_UERRNO_LIST\n#define MICROPY_PY_UERRNO_LIST \\\n    X(EPERM) \\\n    X(ENOENT) \\\n    X(EIO) \\\n    X(EBADF) \\\n    X(EAGAIN) \\\n    X(ENOMEM) \\\n    X(EACCES) \\\n    X(EEXIST) \\\n    X(ENODEV) \\\n    X(EISDIR) \\\n    X(EINVAL) \\\n    X(EOPNOTSUPP) \\\n    X(EADDRINUSE) \\\n    X(ECONNABORTED) \\\n    X(ECONNRESET) \\\n    X(ENOBUFS) \\\n    X(ENOTCONN) \\\n    X(ETIMEDOUT) \\\n    X(ECONNREFUSED) \\\n    X(EHOSTUNREACH) \\\n    X(EALREADY) \\\n    X(EINPROGRESS) \\\n\n#endif\n\n#if MICROPY_PY_UERRNO_ERRORCODE\nSTATIC const mp_rom_map_elem_t errorcode_table[] = {\n    #define X(e) { MP_ROM_INT(MP_##e), MP_ROM_QSTR(MP_QSTR_##e) },\n    MICROPY_PY_UERRNO_LIST\n#undef X\n};\n\nSTATIC const mp_obj_dict_t errorcode_dict = {\n    .base = {&mp_type_dict},\n    .map = {\n        .all_keys_are_qstrs = 0, // keys are integers\n        .is_fixed = 1,\n        .is_ordered = 1,\n        .used = MP_ARRAY_SIZE(errorcode_table),\n        .alloc = MP_ARRAY_SIZE(errorcode_table),\n        .table = (mp_map_elem_t *)(mp_rom_map_elem_t *)errorcode_table,\n    },\n};\n#endif\n\nSTATIC const mp_rom_map_elem_t mp_module_uerrno_globals_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uerrno) },\n    #if MICROPY_PY_UERRNO_ERRORCODE\n    { MP_ROM_QSTR(MP_QSTR_errorcode), MP_ROM_PTR(&errorcode_dict) },\n    #endif\n\n    #define X(e) { MP_ROM_QSTR(MP_QSTR_##e), MP_ROM_INT(MP_##e) },\n    MICROPY_PY_UERRNO_LIST\n#undef X\n};\n\nSTATIC MP_DEFINE_CONST_DICT(mp_module_uerrno_globals, mp_module_uerrno_globals_table);\n\nconst mp_obj_module_t mp_module_uerrno = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&mp_module_uerrno_globals,\n};\n\nqstr mp_errno_to_str(mp_obj_t errno_val) {\n    #if MICROPY_PY_UERRNO_ERRORCODE\n    // We have the errorcode dict so can do a lookup using the hash map\n    mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&errorcode_dict.map, errno_val, MP_MAP_LOOKUP);\n    if (elem == NULL) {\n        return MP_QSTRnull;\n    } else {\n        return MP_OBJ_QSTR_VALUE(elem->value);\n    }\n    #else\n    // We don't have the errorcode dict so do a simple search in the modules dict\n    for (size_t i = 0; i < MP_ARRAY_SIZE(mp_module_uerrno_globals_table); ++i) {\n        if (errno_val == mp_module_uerrno_globals_table[i].value) {\n            return MP_OBJ_QSTR_VALUE(mp_module_uerrno_globals_table[i].key);\n        }\n    }\n    return MP_QSTRnull;\n    #endif\n}\n\n#endif // MICROPY_PY_UERRNO\n"
  },
  {
    "path": "py/mpconfig.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_MPCONFIG_H\n#define MICROPY_INCLUDED_PY_MPCONFIG_H\n\n// Current version of MicroPython\n#define MICROPY_VERSION_MAJOR 1\n#define MICROPY_VERSION_MINOR 13\n#define MICROPY_VERSION_MICRO 0\n\n// Combined version as a 32-bit number for convenience\n#define MICROPY_VERSION ( \\\n    MICROPY_VERSION_MAJOR << 16 \\\n        | MICROPY_VERSION_MINOR << 8 \\\n        | MICROPY_VERSION_MICRO)\n\n// String version\n#define MICROPY_VERSION_STRING \\\n    MP_STRINGIFY(MICROPY_VERSION_MAJOR) \".\" \\\n    MP_STRINGIFY(MICROPY_VERSION_MINOR) \".\" \\\n    MP_STRINGIFY(MICROPY_VERSION_MICRO)\n\n// This file contains default configuration settings for MicroPython.\n// You can override any of the options below using mpconfigport.h file\n// located in a directory of your port.\n\n// mpconfigport.h is a file containing configuration settings for a\n// particular port. mpconfigport.h is actually a default name for\n// such config, and it can be overridden using MP_CONFIGFILE preprocessor\n// define (you can do that by passing CFLAGS_EXTRA='-DMP_CONFIGFILE=\"<file.h>\"'\n// argument to make when using standard MicroPython makefiles).\n// This is useful to have more than one config per port, for example,\n// release vs debug configs, etc. Note that if you switch from one config\n// to another, you must rebuild from scratch using \"-B\" switch to make.\n\n#ifdef MP_CONFIGFILE\n#include MP_CONFIGFILE\n#else\n#include <mpconfigport.h>\n#endif\n\n// Any options not explicitly set in mpconfigport.h will get default\n// values below.\n\n/*****************************************************************************/\n/* Object representation                                                     */\n\n// A MicroPython object is a machine word having the following form:\n//  - xxxx...xxx1 : a small int, bits 1 and above are the value\n//  - xxxx...x010 : a qstr, bits 3 and above are the value\n//  - xxxx...x110 : an immediate object, bits 3 and above are the value\n//  - xxxx...xx00 : a pointer to an mp_obj_base_t (unless a fake object)\n#define MICROPY_OBJ_REPR_A (0)\n\n// A MicroPython object is a machine word having the following form:\n//  - xxxx...xx01 : a small int, bits 2 and above are the value\n//  - xxxx...x011 : a qstr, bits 3 and above are the value\n//  - xxxx...x111 : an immediate object, bits 3 and above are the value\n//  - xxxx...xxx0 : a pointer to an mp_obj_base_t (unless a fake object)\n#define MICROPY_OBJ_REPR_B (1)\n\n// A MicroPython object is a machine word having the following form (called R):\n//  - iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int with 31-bit signed value\n//  - 01111111 1qqqqqqq qqqqqqqq qqqq0110 str with 19-bit qstr value\n//  - 01111111 10000000 00000000 ssss1110 immediate object with 4-bit value\n//  - s1111111 10000000 00000000 00000010 +/- inf\n//  - s1111111 1xxxxxxx xxxxxxxx xxxxx010 nan, x != 0\n//  - seeeeeee efffffff ffffffff ffffff10 30-bit fp, e != 0xff\n//  - pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment)\n// Str, immediate and float stored as O = R + 0x80800000, retrieved as R = O - 0x80800000.\n// This makes strs/immediates easier to encode/decode as they have zeros in the top 9 bits.\n// This scheme only works with 32-bit word size and float enabled.\n#define MICROPY_OBJ_REPR_C (2)\n\n// A MicroPython object is a 64-bit word having the following form (called R):\n//  - seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 64-bit fp, e != 0x7ff\n//  - s1111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000 +/- inf\n//  - 01111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000 normalised nan\n//  - 01111111 11111101 iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int\n//  - 01111111 11111110 00000000 00000000 qqqqqqqq qqqqqqqq qqqqqqqq qqqqqqq1 str\n//  - 01111111 11111111 ss000000 00000000 00000000 00000000 00000000 00000000 immediate object\n//  - 01111111 11111100 00000000 00000000 pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment)\n// Stored as O = R + 0x8004000000000000, retrieved as R = O - 0x8004000000000000.\n// This makes pointers have all zeros in the top 32 bits.\n// Small-ints and strs have 1 as LSB to make sure they don't look like pointers\n// to the garbage collector.\n#define MICROPY_OBJ_REPR_D (3)\n\n#ifndef MICROPY_OBJ_REPR\n#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A)\n#endif\n\n// Whether to encode None/False/True as immediate objects instead of pointers to\n// real objects.  Reduces code size by a decent amount without hurting\n// performance, for all representations except D on some architectures.\n#ifndef MICROPY_OBJ_IMMEDIATE_OBJS\n#define MICROPY_OBJ_IMMEDIATE_OBJS (MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D)\n#endif\n\n/*****************************************************************************/\n/* Memory allocation policy                                                  */\n\n// Number of bytes in memory allocation/GC block. Any size allocated will be\n// rounded up to be multiples of this.\n#ifndef MICROPY_BYTES_PER_GC_BLOCK\n#define MICROPY_BYTES_PER_GC_BLOCK (4 * BYTES_PER_WORD)\n#endif\n\n// Number of words allocated (in BSS) to the GC stack (minimum is 1)\n#ifndef MICROPY_ALLOC_GC_STACK_SIZE\n#define MICROPY_ALLOC_GC_STACK_SIZE (64)\n#endif\n\n// The C-type to use for entries in the GC stack.  By default it allows the\n// heap to be as large as the address space, but the bit-width of this type can\n// be reduced to save memory when the heap is small enough.  The type must be\n// big enough to index all blocks in the heap, which is set by\n// heap-size-in-bytes / MICROPY_BYTES_PER_GC_BLOCK.\n#ifndef MICROPY_GC_STACK_ENTRY_TYPE\n#define MICROPY_GC_STACK_ENTRY_TYPE size_t\n#endif\n\n// Be conservative and always clear to zero newly (re)allocated memory in the GC.\n// This helps eliminate stray pointers that hold on to memory that's no longer\n// used.  It decreases performance due to unnecessary memory clearing.\n// A memory manager which always clears memory can set this to 0.\n// TODO Do analysis to understand why some memory is not properly cleared and\n// find a more efficient way to clear it.\n#ifndef MICROPY_GC_CONSERVATIVE_CLEAR\n#define MICROPY_GC_CONSERVATIVE_CLEAR (MICROPY_ENABLE_GC)\n#endif\n\n// Support automatic GC when reaching allocation threshold,\n// configurable by gc.threshold().\n#ifndef MICROPY_GC_ALLOC_THRESHOLD\n#define MICROPY_GC_ALLOC_THRESHOLD (1)\n#endif\n\n// Number of bytes to allocate initially when creating new chunks to store\n// interned string data.  Smaller numbers lead to more chunks being needed\n// and more wastage at the end of the chunk.  Larger numbers lead to wasted\n// space at the end when no more strings need interning.\n#ifndef MICROPY_ALLOC_QSTR_CHUNK_INIT\n#define MICROPY_ALLOC_QSTR_CHUNK_INIT (128)\n#endif\n\n// Initial amount for lexer indentation level\n#ifndef MICROPY_ALLOC_LEXER_INDENT_INIT\n#define MICROPY_ALLOC_LEXER_INDENT_INIT (10)\n#endif\n\n// Increment for lexer indentation level\n#ifndef MICROPY_ALLOC_LEXEL_INDENT_INC\n#define MICROPY_ALLOC_LEXEL_INDENT_INC (8)\n#endif\n\n// Initial amount for parse rule stack\n#ifndef MICROPY_ALLOC_PARSE_RULE_INIT\n#define MICROPY_ALLOC_PARSE_RULE_INIT (64)\n#endif\n\n// Increment for parse rule stack\n#ifndef MICROPY_ALLOC_PARSE_RULE_INC\n#define MICROPY_ALLOC_PARSE_RULE_INC (16)\n#endif\n\n// Initial amount for parse result stack\n#ifndef MICROPY_ALLOC_PARSE_RESULT_INIT\n#define MICROPY_ALLOC_PARSE_RESULT_INIT (32)\n#endif\n\n// Increment for parse result stack\n#ifndef MICROPY_ALLOC_PARSE_RESULT_INC\n#define MICROPY_ALLOC_PARSE_RESULT_INC (16)\n#endif\n\n// Strings this length or less will be interned by the parser\n#ifndef MICROPY_ALLOC_PARSE_INTERN_STRING_LEN\n#define MICROPY_ALLOC_PARSE_INTERN_STRING_LEN (10)\n#endif\n\n// Number of bytes to allocate initially when creating new chunks to store\n// parse nodes.  Small leads to fragmentation, large leads to excess use.\n#ifndef MICROPY_ALLOC_PARSE_CHUNK_INIT\n#define MICROPY_ALLOC_PARSE_CHUNK_INIT (128)\n#endif\n\n// Initial amount for ids in a scope\n#ifndef MICROPY_ALLOC_SCOPE_ID_INIT\n#define MICROPY_ALLOC_SCOPE_ID_INIT (4)\n#endif\n\n// Increment for ids in a scope\n#ifndef MICROPY_ALLOC_SCOPE_ID_INC\n#define MICROPY_ALLOC_SCOPE_ID_INC (6)\n#endif\n\n// Maximum length of a path in the filesystem\n// So we can allocate a buffer on the stack for path manipulation in import\n#ifndef MICROPY_ALLOC_PATH_MAX\n#define MICROPY_ALLOC_PATH_MAX (512)\n#endif\n\n// Initial size of module dict\n#ifndef MICROPY_MODULE_DICT_SIZE\n#define MICROPY_MODULE_DICT_SIZE (1)\n#endif\n\n// Whether realloc/free should be passed allocated memory region size\n// You must enable this if MICROPY_MEM_STATS is enabled\n#ifndef MICROPY_MALLOC_USES_ALLOCATED_SIZE\n#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (0)\n#endif\n\n// Number of bytes used to store qstr length\n// Dictates hard limit on maximum Python identifier length, but 1 byte\n// (limit of 255 bytes in an identifier) should be enough for everyone\n#ifndef MICROPY_QSTR_BYTES_IN_LEN\n#define MICROPY_QSTR_BYTES_IN_LEN (1)\n#endif\n\n// Number of bytes used to store qstr hash\n#ifndef MICROPY_QSTR_BYTES_IN_HASH\n#define MICROPY_QSTR_BYTES_IN_HASH (2)\n#endif\n\n// Avoid using C stack when making Python function calls. C stack still\n// may be used if there's no free heap.\n#ifndef MICROPY_STACKLESS\n#define MICROPY_STACKLESS (0)\n#endif\n\n// Never use C stack when making Python function calls. This may break\n// testsuite as will subtly change which exception is thrown in case\n// of too deep recursion and other similar cases.\n#ifndef MICROPY_STACKLESS_STRICT\n#define MICROPY_STACKLESS_STRICT (0)\n#endif\n\n// Don't use alloca calls. As alloca() is not part of ANSI C, this\n// workaround option is provided for compilers lacking this de-facto\n// standard function. The way it works is allocating from heap, and\n// relying on garbage collection to free it eventually. This is of\n// course much less optimal than real alloca().\n#if defined(MICROPY_NO_ALLOCA) && MICROPY_NO_ALLOCA\n#undef alloca\n#define alloca(x) m_malloc(x)\n#endif\n\n/*****************************************************************************/\n/* MicroPython emitters                                                     */\n\n// Whether to support loading of persistent code\n#ifndef MICROPY_PERSISTENT_CODE_LOAD\n#define MICROPY_PERSISTENT_CODE_LOAD (0)\n#endif\n\n// Whether to support saving of persistent code\n#ifndef MICROPY_PERSISTENT_CODE_SAVE\n#define MICROPY_PERSISTENT_CODE_SAVE (0)\n#endif\n\n// Whether generated code can persist independently of the VM/runtime instance\n// This is enabled automatically when needed by other features\n#ifndef MICROPY_PERSISTENT_CODE\n#define MICROPY_PERSISTENT_CODE (MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE || MICROPY_MODULE_FROZEN_MPY)\n#endif\n\n// Whether to emit x64 native code\n#ifndef MICROPY_EMIT_X64\n#define MICROPY_EMIT_X64 (0)\n#endif\n\n// Whether to emit x86 native code\n#ifndef MICROPY_EMIT_X86\n#define MICROPY_EMIT_X86 (0)\n#endif\n\n// Whether to emit thumb native code\n#ifndef MICROPY_EMIT_THUMB\n#define MICROPY_EMIT_THUMB (0)\n#endif\n\n// Whether to enable the thumb inline assembler\n#ifndef MICROPY_EMIT_INLINE_THUMB\n#define MICROPY_EMIT_INLINE_THUMB (0)\n#endif\n\n// Whether to enable ARMv7-M instruction support in the Thumb2 inline assembler\n#ifndef MICROPY_EMIT_INLINE_THUMB_ARMV7M\n#define MICROPY_EMIT_INLINE_THUMB_ARMV7M (1)\n#endif\n\n// Whether to enable float support in the Thumb2 inline assembler\n#ifndef MICROPY_EMIT_INLINE_THUMB_FLOAT\n#define MICROPY_EMIT_INLINE_THUMB_FLOAT (1)\n#endif\n\n// Whether to emit ARM native code\n#ifndef MICROPY_EMIT_ARM\n#define MICROPY_EMIT_ARM (0)\n#endif\n\n// Whether to emit Xtensa native code\n#ifndef MICROPY_EMIT_XTENSA\n#define MICROPY_EMIT_XTENSA (0)\n#endif\n\n// Whether to enable the Xtensa inline assembler\n#ifndef MICROPY_EMIT_INLINE_XTENSA\n#define MICROPY_EMIT_INLINE_XTENSA (0)\n#endif\n\n// Whether to emit Xtensa-Windowed native code\n#ifndef MICROPY_EMIT_XTENSAWIN\n#define MICROPY_EMIT_XTENSAWIN (0)\n#endif\n\n// Convenience definition for whether any native emitter is enabled\n#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA || MICROPY_EMIT_XTENSAWIN)\n\n// Select prelude-as-bytes-object for certain emitters\n#define MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ (MICROPY_EMIT_XTENSAWIN)\n\n// Convenience definition for whether any inline assembler emitter is enabled\n#define MICROPY_EMIT_INLINE_ASM (MICROPY_EMIT_INLINE_THUMB || MICROPY_EMIT_INLINE_XTENSA)\n\n// Convenience definition for whether any native or inline assembler emitter is enabled\n#define MICROPY_EMIT_MACHINE_CODE (MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM)\n\n// Whether native relocatable code loaded from .mpy files is explicitly tracked\n// so that the GC cannot reclaim it.  Needed on architectures that allocate\n// executable memory on the MicroPython heap and don't explicitly track this\n// data some other way.\n#ifndef MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE\n#if !MICROPY_EMIT_MACHINE_CODE || defined(MP_PLAT_ALLOC_EXEC) || defined(MP_PLAT_COMMIT_EXEC)\n#define MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE (0)\n#else\n#define MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE (1)\n#endif\n#endif\n\n/*****************************************************************************/\n/* Compiler configuration                                                    */\n\n// Whether to include the compiler\n#ifndef MICROPY_ENABLE_COMPILER\n#define MICROPY_ENABLE_COMPILER (1)\n#endif\n\n// Whether the compiler is dynamically configurable (ie at runtime)\n// This will disable the ability to execute native/viper code\n#ifndef MICROPY_DYNAMIC_COMPILER\n#define MICROPY_DYNAMIC_COMPILER (0)\n#endif\n\n// Configure dynamic compiler macros\n#if MICROPY_DYNAMIC_COMPILER\n#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC (mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode)\n#define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC (mp_dynamic_compiler.py_builtins_str_unicode)\n#else\n#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE\n#define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC MICROPY_PY_BUILTINS_STR_UNICODE\n#endif\n\n// Whether to enable constant folding; eg 1+2 rewritten as 3\n#ifndef MICROPY_COMP_CONST_FOLDING\n#define MICROPY_COMP_CONST_FOLDING (1)\n#endif\n\n// Whether to enable optimisations for constant literals, eg OrderedDict\n#ifndef MICROPY_COMP_CONST_LITERAL\n#define MICROPY_COMP_CONST_LITERAL (1)\n#endif\n\n// Whether to enable lookup of constants in modules; eg module.CONST\n#ifndef MICROPY_COMP_MODULE_CONST\n#define MICROPY_COMP_MODULE_CONST (0)\n#endif\n\n// Whether to enable constant optimisation; id = const(value)\n#ifndef MICROPY_COMP_CONST\n#define MICROPY_COMP_CONST (1)\n#endif\n\n// Whether to enable optimisation of: a, b = c, d\n// Costs 124 bytes (Thumb2)\n#ifndef MICROPY_COMP_DOUBLE_TUPLE_ASSIGN\n#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1)\n#endif\n\n// Whether to enable optimisation of: a, b, c = d, e, f\n// Requires MICROPY_COMP_DOUBLE_TUPLE_ASSIGN and costs 68 bytes (Thumb2)\n#ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN\n#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)\n#endif\n\n// Whether to enable optimisation of: return a if b else c\n// Costs about 80 bytes (Thumb2) and saves 2 bytes of bytecode for each use\n#ifndef MICROPY_COMP_RETURN_IF_EXPR\n#define MICROPY_COMP_RETURN_IF_EXPR (0)\n#endif\n\n/*****************************************************************************/\n/* Internal debugging stuff                                                  */\n\n// Whether to collect memory allocation stats\n#ifndef MICROPY_MEM_STATS\n#define MICROPY_MEM_STATS (0)\n#endif\n\n// The mp_print_t printer used for debugging output\n#ifndef MICROPY_DEBUG_PRINTER\n#define MICROPY_DEBUG_PRINTER (&mp_plat_print)\n#endif\n\n// Whether to build functions that print debugging info:\n//   mp_bytecode_print\n//   mp_parse_node_print\n#ifndef MICROPY_DEBUG_PRINTERS\n#define MICROPY_DEBUG_PRINTERS (0)\n#endif\n\n// Whether to enable all debugging outputs (it will be extremely verbose)\n#ifndef MICROPY_DEBUG_VERBOSE\n#define MICROPY_DEBUG_VERBOSE (0)\n#endif\n\n// Whether to enable debugging versions of MP_OBJ_NULL/STOP_ITERATION/SENTINEL\n#ifndef MICROPY_DEBUG_MP_OBJ_SENTINELS\n#define MICROPY_DEBUG_MP_OBJ_SENTINELS (0)\n#endif\n\n// Whether to print parse rule names (rather than integers) in mp_parse_node_print\n#ifndef MICROPY_DEBUG_PARSE_RULE_NAME\n#define MICROPY_DEBUG_PARSE_RULE_NAME (0)\n#endif\n\n// Whether to enable a simple VM stack overflow check\n#ifndef MICROPY_DEBUG_VM_STACK_OVERFLOW\n#define MICROPY_DEBUG_VM_STACK_OVERFLOW (0)\n#endif\n\n/*****************************************************************************/\n/* Optimisations                                                             */\n\n// Whether to use computed gotos in the VM, or a switch\n// Computed gotos are roughly 10% faster, and increase VM code size by a little\n// Note: enabling this will use the gcc-specific extensions of ranged designated\n// initialisers and addresses of labels, which are not part of the C99 standard.\n#ifndef MICROPY_OPT_COMPUTED_GOTO\n#define MICROPY_OPT_COMPUTED_GOTO (0)\n#endif\n\n// Whether to cache result of map lookups in LOAD_NAME, LOAD_GLOBAL, LOAD_ATTR,\n// STORE_ATTR bytecodes.  Uses 1 byte extra RAM for each of these opcodes and\n// uses a bit of extra code ROM, but greatly improves lookup speed.\n#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE\n#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)\n#endif\n\n// Whether to use fast versions of bitwise operations (and, or, xor) when the\n// arguments are both positive.  Increases Thumb2 code size by about 250 bytes.\n#ifndef MICROPY_OPT_MPZ_BITWISE\n#define MICROPY_OPT_MPZ_BITWISE (0)\n#endif\n\n\n// Whether math.factorial is large, fast and recursive (1) or small and slow (0).\n#ifndef MICROPY_OPT_MATH_FACTORIAL\n#define MICROPY_OPT_MATH_FACTORIAL (0)\n#endif\n\n/*****************************************************************************/\n/* Python internal features                                                  */\n\n// Whether to enable import of external modules\n// When disabled, only importing of built-in modules is supported\n// When enabled, a port must implement mp_import_stat (among other things)\n#ifndef MICROPY_ENABLE_EXTERNAL_IMPORT\n#define MICROPY_ENABLE_EXTERNAL_IMPORT (1)\n#endif\n\n// Whether to use the POSIX reader for importing files\n#ifndef MICROPY_READER_POSIX\n#define MICROPY_READER_POSIX (0)\n#endif\n\n// Whether to use the VFS reader for importing files\n#ifndef MICROPY_READER_VFS\n#define MICROPY_READER_VFS (0)\n#endif\n\n// Whether any readers have been defined\n#ifndef MICROPY_HAS_FILE_READER\n#define MICROPY_HAS_FILE_READER (MICROPY_READER_POSIX || MICROPY_READER_VFS)\n#endif\n\n// Hook for the VM at the start of the opcode loop (can contain variable\n// definitions usable by the other hook functions)\n#ifndef MICROPY_VM_HOOK_INIT\n#define MICROPY_VM_HOOK_INIT\n#endif\n\n// Hook for the VM during the opcode loop (but only after jump opcodes)\n#ifndef MICROPY_VM_HOOK_LOOP\n#define MICROPY_VM_HOOK_LOOP\n#endif\n\n// Hook for the VM just before return opcode is finished being interpreted\n#ifndef MICROPY_VM_HOOK_RETURN\n#define MICROPY_VM_HOOK_RETURN\n#endif\n\n// Whether to include the garbage collector\n#ifndef MICROPY_ENABLE_GC\n#define MICROPY_ENABLE_GC (0)\n#endif\n\n// Whether to enable finalisers in the garbage collector (ie call __del__)\n#ifndef MICROPY_ENABLE_FINALISER\n#define MICROPY_ENABLE_FINALISER (0)\n#endif\n\n// Whether to enable a separate allocator for the Python stack.\n// If enabled then the code must call mp_pystack_init before mp_init.\n#ifndef MICROPY_ENABLE_PYSTACK\n#define MICROPY_ENABLE_PYSTACK (0)\n#endif\n\n// Number of bytes that memory returned by mp_pystack_alloc will be aligned by.\n#ifndef MICROPY_PYSTACK_ALIGN\n#define MICROPY_PYSTACK_ALIGN (8)\n#endif\n\n// Whether to check C stack usage. C stack used for calling Python functions,\n// etc. Not checking means segfault on overflow.\n#ifndef MICROPY_STACK_CHECK\n#define MICROPY_STACK_CHECK (0)\n#endif\n\n// Whether to have an emergency exception buffer\n#ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)\n#endif\n#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n#ifndef MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE\n#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)      // 0 - implies dynamic allocation\n#endif\n#endif\n\n// Whether to provide the mp_kbd_exception object, and micropython.kbd_intr function\n#ifndef MICROPY_KBD_EXCEPTION\n#define MICROPY_KBD_EXCEPTION (0)\n#endif\n\n// Prefer to raise KeyboardInterrupt asynchronously (from signal or interrupt\n// handler) - if supported by a particular port.\n#ifndef MICROPY_ASYNC_KBD_INTR\n#define MICROPY_ASYNC_KBD_INTR (0)\n#endif\n\n// Whether to include REPL helper function\n#ifndef MICROPY_HELPER_REPL\n#define MICROPY_HELPER_REPL (0)\n#endif\n\n// Allow enabling debug prints after each REPL line\n#ifndef MICROPY_REPL_INFO\n#define MICROPY_REPL_INFO (0)\n#endif\n\n// Whether to include emacs-style readline behavior in REPL\n#ifndef MICROPY_REPL_EMACS_KEYS\n#define MICROPY_REPL_EMACS_KEYS (0)\n#endif\n\n// Whether to include emacs-style word movement/kill readline behavior in REPL.\n// This adds Alt+F, Alt+B, Alt+D and Alt+Backspace for forward-word, backward-word, forward-kill-word\n// and backward-kill-word, respectively.\n#ifndef MICROPY_REPL_EMACS_WORDS_MOVE\n#define MICROPY_REPL_EMACS_WORDS_MOVE (0)\n#endif\n\n// Whether to include extra convenience keys for word movement/kill in readline REPL.\n// This adds Ctrl+Right, Ctrl+Left and Ctrl+W for forward-word, backward-word and backward-kill-word\n// respectively. Ctrl+Delete is not implemented because it's a very different escape sequence.\n// Depends on MICROPY_REPL_EMACS_WORDS_MOVE.\n#ifndef MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE\n#define MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE (0)\n#endif\n\n// Whether to implement auto-indent in REPL\n#ifndef MICROPY_REPL_AUTO_INDENT\n#define MICROPY_REPL_AUTO_INDENT (0)\n#endif\n\n// Whether port requires event-driven REPL functions\n#ifndef MICROPY_REPL_EVENT_DRIVEN\n#define MICROPY_REPL_EVENT_DRIVEN (0)\n#endif\n\n// Whether to include lexer helper function for unix\n#ifndef MICROPY_HELPER_LEXER_UNIX\n#define MICROPY_HELPER_LEXER_UNIX (0)\n#endif\n\n// Long int implementation\n#define MICROPY_LONGINT_IMPL_NONE (0)\n#define MICROPY_LONGINT_IMPL_LONGLONG (1)\n#define MICROPY_LONGINT_IMPL_MPZ (2)\n\n#ifndef MICROPY_LONGINT_IMPL\n#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)\n#endif\n\n#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG\ntypedef long long mp_longint_impl_t;\n#endif\n\n// Whether to include information in the byte code to determine source\n// line number (increases RAM usage, but doesn't slow byte code execution)\n#ifndef MICROPY_ENABLE_SOURCE_LINE\n#define MICROPY_ENABLE_SOURCE_LINE (0)\n#endif\n\n// Whether to include doc strings (increases RAM usage)\n#ifndef MICROPY_ENABLE_DOC_STRING\n#define MICROPY_ENABLE_DOC_STRING (0)\n#endif\n\n// Exception messages are short static strings\n#define MICROPY_ERROR_REPORTING_TERSE    (1)\n// Exception messages provide basic error details\n#define MICROPY_ERROR_REPORTING_NORMAL   (2)\n// Exception messages provide full info, e.g. object names\n#define MICROPY_ERROR_REPORTING_DETAILED (3)\n\n#ifndef MICROPY_ERROR_REPORTING\n#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)\n#endif\n\n// Whether issue warnings during compiling/execution\n#ifndef MICROPY_WARNINGS\n#define MICROPY_WARNINGS (0)\n#endif\n\n// Whether to support warning categories\n#ifndef MICROPY_WARNINGS_CATEGORY\n#define MICROPY_WARNINGS_CATEGORY (0)\n#endif\n\n// This macro is used when printing runtime warnings and errors\n#ifndef MICROPY_ERROR_PRINTER\n#define MICROPY_ERROR_PRINTER (&mp_plat_print)\n#endif\n\n// Float and complex implementation\n#define MICROPY_FLOAT_IMPL_NONE (0)\n#define MICROPY_FLOAT_IMPL_FLOAT (1)\n#define MICROPY_FLOAT_IMPL_DOUBLE (2)\n\n#ifndef MICROPY_FLOAT_IMPL\n#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)\n#endif\n\n#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n#define MICROPY_PY_BUILTINS_FLOAT (1)\n#define MICROPY_FLOAT_CONST(x) x##F\n#define MICROPY_FLOAT_C_FUN(fun) fun##f\ntypedef float mp_float_t;\n#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE\n#define MICROPY_PY_BUILTINS_FLOAT (1)\n#define MICROPY_FLOAT_CONST(x) x\n#define MICROPY_FLOAT_C_FUN(fun) fun\ntypedef double mp_float_t;\n#else\n#define MICROPY_PY_BUILTINS_FLOAT (0)\n#endif\n\n#ifndef MICROPY_PY_BUILTINS_COMPLEX\n#define MICROPY_PY_BUILTINS_COMPLEX (MICROPY_PY_BUILTINS_FLOAT)\n#endif\n\n// Whether to provide a high-quality hash for float and complex numbers.\n// Otherwise the default is a very simple but correct hashing function.\n#ifndef MICROPY_FLOAT_HIGH_QUALITY_HASH\n#define MICROPY_FLOAT_HIGH_QUALITY_HASH (0)\n#endif\n\n// Enable features which improve CPython compatibility\n// but may lead to more code size/memory usage.\n// TODO: Originally intended as generic category to not\n// add bunch of once-off options. May need refactoring later\n#ifndef MICROPY_CPYTHON_COMPAT\n#define MICROPY_CPYTHON_COMPAT (1)\n#endif\n\n// Perform full checks as done by CPython. Disabling this\n// may produce incorrect results, if incorrect data is fed,\n// but should not lead to MicroPython crashes or similar\n// grave issues (in other words, only user app should be,\n// affected, not system).\n#ifndef MICROPY_FULL_CHECKS\n#define MICROPY_FULL_CHECKS (1)\n#endif\n\n// Whether POSIX-semantics non-blocking streams are supported\n#ifndef MICROPY_STREAMS_NON_BLOCK\n#define MICROPY_STREAMS_NON_BLOCK (0)\n#endif\n\n// Whether to provide stream functions with POSIX-like signatures\n// (useful for porting existing libraries to MicroPython).\n#ifndef MICROPY_STREAMS_POSIX_API\n#define MICROPY_STREAMS_POSIX_API (0)\n#endif\n\n// Whether to call __init__ when importing builtin modules for the first time\n#ifndef MICROPY_MODULE_BUILTIN_INIT\n#define MICROPY_MODULE_BUILTIN_INIT (0)\n#endif\n\n// Whether to support module-level __getattr__ (see PEP 562)\n#ifndef MICROPY_MODULE_GETATTR\n#define MICROPY_MODULE_GETATTR (1)\n#endif\n\n// Whether module weak links are supported\n#ifndef MICROPY_MODULE_WEAK_LINKS\n#define MICROPY_MODULE_WEAK_LINKS (0)\n#endif\n\n// Whether frozen modules are supported in the form of strings\n#ifndef MICROPY_MODULE_FROZEN_STR\n#define MICROPY_MODULE_FROZEN_STR (0)\n#endif\n\n// Whether frozen modules are supported in the form of .mpy files\n#ifndef MICROPY_MODULE_FROZEN_MPY\n#define MICROPY_MODULE_FROZEN_MPY (0)\n#endif\n\n// Convenience macro for whether frozen modules are supported\n#ifndef MICROPY_MODULE_FROZEN\n#define MICROPY_MODULE_FROZEN (MICROPY_MODULE_FROZEN_STR || MICROPY_MODULE_FROZEN_MPY)\n#endif\n\n// Whether you can override builtins in the builtins module\n#ifndef MICROPY_CAN_OVERRIDE_BUILTINS\n#define MICROPY_CAN_OVERRIDE_BUILTINS (0)\n#endif\n\n// Whether to check that the \"self\" argument of a builtin method has the\n// correct type.  Such an explicit check is only needed if a builtin\n// method escapes to Python land without a first argument, eg\n// list.append([], 1).  Without this check such calls will have undefined\n// behaviour (usually segfault) if the first argument is the wrong type.\n#ifndef MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG\n#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1)\n#endif\n\n// Whether to use internally defined errno's (otherwise system provided ones)\n#ifndef MICROPY_USE_INTERNAL_ERRNO\n#define MICROPY_USE_INTERNAL_ERRNO (0)\n#endif\n\n// Whether to use internally defined *printf() functions (otherwise external ones)\n#ifndef MICROPY_USE_INTERNAL_PRINTF\n#define MICROPY_USE_INTERNAL_PRINTF (1)\n#endif\n\n// Support for internal scheduler\n#ifndef MICROPY_ENABLE_SCHEDULER\n#define MICROPY_ENABLE_SCHEDULER (0)\n#endif\n\n// Maximum number of entries in the scheduler\n#ifndef MICROPY_SCHEDULER_DEPTH\n#define MICROPY_SCHEDULER_DEPTH (4)\n#endif\n\n// Support for generic VFS sub-system\n#ifndef MICROPY_VFS\n#define MICROPY_VFS (0)\n#endif\n\n// Support for VFS POSIX component, to mount a POSIX filesystem within VFS\n#ifndef MICROPY_VFS\n#define MICROPY_VFS_POSIX (0)\n#endif\n\n// Support for VFS FAT component, to mount a FAT filesystem within VFS\n#ifndef MICROPY_VFS\n#define MICROPY_VFS_FAT (0)\n#endif\n\n/*****************************************************************************/\n/* Fine control over Python builtins, classes, modules, etc                  */\n\n// Whether to support multiple inheritance of Python classes.  Multiple\n// inheritance makes some C functions inherently recursive, and adds a bit of\n// code overhead.\n#ifndef MICROPY_MULTIPLE_INHERITANCE\n#define MICROPY_MULTIPLE_INHERITANCE (1)\n#endif\n\n// Whether to implement attributes on functions\n#ifndef MICROPY_PY_FUNCTION_ATTRS\n#define MICROPY_PY_FUNCTION_ATTRS (0)\n#endif\n\n// Whether to support the descriptors __get__, __set__, __delete__\n// This costs some code size and makes load/store/delete of instance\n// attributes slower for the classes that use this feature\n#ifndef MICROPY_PY_DESCRIPTORS\n#define MICROPY_PY_DESCRIPTORS (0)\n#endif\n\n// Whether to support class __delattr__ and __setattr__ methods\n// This costs some code size and makes store/delete of instance\n// attributes slower for the classes that use this feature\n#ifndef MICROPY_PY_DELATTR_SETATTR\n#define MICROPY_PY_DELATTR_SETATTR (0)\n#endif\n\n// Support for async/await/async for/async with\n#ifndef MICROPY_PY_ASYNC_AWAIT\n#define MICROPY_PY_ASYNC_AWAIT (1)\n#endif\n\n// Support for assignment expressions with := (see PEP 572, Python 3.8+)\n#ifndef MICROPY_PY_ASSIGN_EXPR\n#define MICROPY_PY_ASSIGN_EXPR (1)\n#endif\n\n// Non-standard .pend_throw() method for generators, allowing for\n// Future-like behavior with respect to exception handling: an\n// exception set with .pend_throw() will activate on the next call\n// to generator's .send() or .__next__(). (This is useful to implement\n// async schedulers.)\n#ifndef MICROPY_PY_GENERATOR_PEND_THROW\n#define MICROPY_PY_GENERATOR_PEND_THROW (1)\n#endif\n\n// Issue a warning when comparing str and bytes objects\n#ifndef MICROPY_PY_STR_BYTES_CMP_WARN\n#define MICROPY_PY_STR_BYTES_CMP_WARN (0)\n#endif\n\n// Whether str object is proper unicode\n#ifndef MICROPY_PY_BUILTINS_STR_UNICODE\n#define MICROPY_PY_BUILTINS_STR_UNICODE (0)\n#endif\n\n// Whether to check for valid UTF-8 when converting bytes to str\n#ifndef MICROPY_PY_BUILTINS_STR_UNICODE_CHECK\n#define MICROPY_PY_BUILTINS_STR_UNICODE_CHECK (MICROPY_PY_BUILTINS_STR_UNICODE)\n#endif\n\n// Whether str.center() method provided\n#ifndef MICROPY_PY_BUILTINS_STR_CENTER\n#define MICROPY_PY_BUILTINS_STR_CENTER (0)\n#endif\n\n// Whether str.count() method provided\n#ifndef MICROPY_PY_BUILTINS_STR_COUNT\n#define MICROPY_PY_BUILTINS_STR_COUNT (1)\n#endif\n\n// Whether str % (...) formatting operator provided\n#ifndef MICROPY_PY_BUILTINS_STR_OP_MODULO\n#define MICROPY_PY_BUILTINS_STR_OP_MODULO (1)\n#endif\n\n// Whether str.partition()/str.rpartition() method provided\n#ifndef MICROPY_PY_BUILTINS_STR_PARTITION\n#define MICROPY_PY_BUILTINS_STR_PARTITION (0)\n#endif\n\n// Whether str.splitlines() method provided\n#ifndef MICROPY_PY_BUILTINS_STR_SPLITLINES\n#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0)\n#endif\n\n// Whether to support bytearray object\n#ifndef MICROPY_PY_BUILTINS_BYTEARRAY\n#define MICROPY_PY_BUILTINS_BYTEARRAY (1)\n#endif\n\n// Whether to support dict.fromkeys() class method\n#ifndef MICROPY_PY_BUILTINS_DICT_FROMKEYS\n#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (1)\n#endif\n\n// Whether to support memoryview object\n#ifndef MICROPY_PY_BUILTINS_MEMORYVIEW\n#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)\n#endif\n\n// Whether to support memoryview.itemsize attribute\n#ifndef MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE\n#define MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE (0)\n#endif\n\n// Whether to support set object\n#ifndef MICROPY_PY_BUILTINS_SET\n#define MICROPY_PY_BUILTINS_SET (1)\n#endif\n\n// Whether to support slice subscript operators and slice object\n#ifndef MICROPY_PY_BUILTINS_SLICE\n#define MICROPY_PY_BUILTINS_SLICE (1)\n#endif\n\n// Whether to support slice attribute read access,\n// i.e. slice.start, slice.stop, slice.step\n#ifndef MICROPY_PY_BUILTINS_SLICE_ATTRS\n#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0)\n#endif\n\n// Whether to support the .indices(len) method on slice objects\n#ifndef MICROPY_PY_BUILTINS_SLICE_INDICES\n#define MICROPY_PY_BUILTINS_SLICE_INDICES (0)\n#endif\n\n// Whether to support frozenset object\n#ifndef MICROPY_PY_BUILTINS_FROZENSET\n#define MICROPY_PY_BUILTINS_FROZENSET (0)\n#endif\n\n// Whether to support property object\n#ifndef MICROPY_PY_BUILTINS_PROPERTY\n#define MICROPY_PY_BUILTINS_PROPERTY (1)\n#endif\n\n// Whether to implement the start/stop/step attributes (readback) on\n// the \"range\" builtin type. Rarely used, and costs ~60 bytes (x86).\n#ifndef MICROPY_PY_BUILTINS_RANGE_ATTRS\n#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1)\n#endif\n\n// Whether to support binary ops [only (in)equality is defined] between range\n// objects.  With this option disabled all range objects that are not exactly\n// the same object will compare as not-equal.  With it enabled the semantics\n// match CPython and ranges are equal if they yield the same sequence of items.\n#ifndef MICROPY_PY_BUILTINS_RANGE_BINOP\n#define MICROPY_PY_BUILTINS_RANGE_BINOP (0)\n#endif\n\n// Support for callling next() with second argument\n#ifndef MICROPY_PY_BUILTINS_NEXT2\n#define MICROPY_PY_BUILTINS_NEXT2 (0)\n#endif\n\n// Whether to support rounding of integers (incl bignum); eg round(123,-1)=120\n#ifndef MICROPY_PY_BUILTINS_ROUND_INT\n#define MICROPY_PY_BUILTINS_ROUND_INT (0)\n#endif\n\n// Whether to support complete set of special methods for user\n// classes, or only the most used ones. \"Inplace\" methods are\n// controlled by MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS below.\n// \"Reverse\" methods are controlled by\n// MICROPY_PY_REVERSE_SPECIAL_METHODS below.\n#ifndef MICROPY_PY_ALL_SPECIAL_METHODS\n#define MICROPY_PY_ALL_SPECIAL_METHODS (0)\n#endif\n\n// Whether to support all inplace arithmetic operarion methods\n// (__imul__, etc.)\n#ifndef MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS\n#define MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS (0)\n#endif\n\n// Whether to support reverse arithmetic operarion methods\n// (__radd__, etc.). Additionally gated by\n// MICROPY_PY_ALL_SPECIAL_METHODS.\n#ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS\n#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0)\n#endif\n\n// Whether to support compile function\n#ifndef MICROPY_PY_BUILTINS_COMPILE\n#define MICROPY_PY_BUILTINS_COMPILE (0)\n#endif\n\n// Whether to support enumerate function(type)\n#ifndef MICROPY_PY_BUILTINS_ENUMERATE\n#define MICROPY_PY_BUILTINS_ENUMERATE (1)\n#endif\n\n// Whether to support eval and exec functions\n// By default they are supported if the compiler is enabled\n#ifndef MICROPY_PY_BUILTINS_EVAL_EXEC\n#define MICROPY_PY_BUILTINS_EVAL_EXEC (MICROPY_ENABLE_COMPILER)\n#endif\n\n// Whether to support the Python 2 execfile function\n#ifndef MICROPY_PY_BUILTINS_EXECFILE\n#define MICROPY_PY_BUILTINS_EXECFILE (0)\n#endif\n\n// Whether to support filter function(type)\n#ifndef MICROPY_PY_BUILTINS_FILTER\n#define MICROPY_PY_BUILTINS_FILTER (1)\n#endif\n\n// Whether to support reversed function(type)\n#ifndef MICROPY_PY_BUILTINS_REVERSED\n#define MICROPY_PY_BUILTINS_REVERSED (1)\n#endif\n\n// Whether to define \"NotImplemented\" special constant\n#ifndef MICROPY_PY_BUILTINS_NOTIMPLEMENTED\n#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (0)\n#endif\n\n// Whether to provide the built-in input() function. The implementation of this\n// uses mp-readline, so can only be enabled if the port uses this readline.\n#ifndef MICROPY_PY_BUILTINS_INPUT\n#define MICROPY_PY_BUILTINS_INPUT (0)\n#endif\n\n// Whether to support min/max functions\n#ifndef MICROPY_PY_BUILTINS_MIN_MAX\n#define MICROPY_PY_BUILTINS_MIN_MAX (1)\n#endif\n\n// Support for calls to pow() with 3 integer arguments\n#ifndef MICROPY_PY_BUILTINS_POW3\n#define MICROPY_PY_BUILTINS_POW3 (0)\n#endif\n\n// Whether to provide the help function\n#ifndef MICROPY_PY_BUILTINS_HELP\n#define MICROPY_PY_BUILTINS_HELP (0)\n#endif\n\n// Use this to configure the help text shown for help().  It should be a\n// variable with the type \"const char*\".  A sensible default is provided.\n#ifndef MICROPY_PY_BUILTINS_HELP_TEXT\n#define MICROPY_PY_BUILTINS_HELP_TEXT mp_help_default_text\n#endif\n\n// Add the ability to list the available modules when executing help('modules')\n#ifndef MICROPY_PY_BUILTINS_HELP_MODULES\n#define MICROPY_PY_BUILTINS_HELP_MODULES (0)\n#endif\n\n// Whether to set __file__ for imported modules\n#ifndef MICROPY_PY___FILE__\n#define MICROPY_PY___FILE__ (1)\n#endif\n\n// Whether to provide mem-info related functions in micropython module\n#ifndef MICROPY_PY_MICROPYTHON_MEM_INFO\n#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)\n#endif\n\n// Whether to provide \"micropython.stack_use\" function\n#ifndef MICROPY_PY_MICROPYTHON_STACK_USE\n#define MICROPY_PY_MICROPYTHON_STACK_USE (MICROPY_PY_MICROPYTHON_MEM_INFO)\n#endif\n\n// Whether to provide the \"micropython.heap_locked\" function\n#ifndef MICROPY_PY_MICROPYTHON_HEAP_LOCKED\n#define MICROPY_PY_MICROPYTHON_HEAP_LOCKED (0)\n#endif\n\n// Whether to provide \"array\" module. Note that large chunk of the\n// underlying code is shared with \"bytearray\" builtin type, so to\n// get real savings, it should be disabled too.\n#ifndef MICROPY_PY_ARRAY\n#define MICROPY_PY_ARRAY (1)\n#endif\n\n// Whether to support slice assignments for array (and bytearray).\n// This is rarely used, but adds ~0.5K of code.\n#ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN\n#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0)\n#endif\n\n// Whether to support attrtuple type (MicroPython extension)\n// It provides space-efficient tuples with attribute access\n#ifndef MICROPY_PY_ATTRTUPLE\n#define MICROPY_PY_ATTRTUPLE (1)\n#endif\n\n// Whether to provide \"collections\" module\n#ifndef MICROPY_PY_COLLECTIONS\n#define MICROPY_PY_COLLECTIONS (1)\n#endif\n\n// Whether to provide \"ucollections.deque\" type\n#ifndef MICROPY_PY_COLLECTIONS_DEQUE\n#define MICROPY_PY_COLLECTIONS_DEQUE (0)\n#endif\n\n// Whether to provide \"collections.OrderedDict\" type\n#ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT\n#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0)\n#endif\n\n// Whether to provide the _asdict function for namedtuple\n#ifndef MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT\n#define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (0)\n#endif\n\n// Whether to provide \"math\" module\n#ifndef MICROPY_PY_MATH\n#define MICROPY_PY_MATH (1)\n#endif\n\n// Whether to provide special math functions: math.{erf,erfc,gamma,lgamma}\n#ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS\n#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (0)\n#endif\n\n// Whether to provide math.factorial function\n#ifndef MICROPY_PY_MATH_FACTORIAL\n#define MICROPY_PY_MATH_FACTORIAL (0)\n#endif\n\n// Whether to provide math.isclose function\n#ifndef MICROPY_PY_MATH_ISCLOSE\n#define MICROPY_PY_MATH_ISCLOSE (0)\n#endif\n\n// Whether to provide fix for atan2 Inf handling.\n#ifndef MICROPY_PY_MATH_ATAN2_FIX_INFNAN\n#define MICROPY_PY_MATH_ATAN2_FIX_INFNAN (0)\n#endif\n\n// Whether to provide fix for fmod Inf handling.\n#ifndef MICROPY_PY_MATH_FMOD_FIX_INFNAN\n#define MICROPY_PY_MATH_FMOD_FIX_INFNAN (0)\n#endif\n\n// Whether to provide fix for modf negative zero handling.\n#ifndef MICROPY_PY_MATH_MODF_FIX_NEGZERO\n#define MICROPY_PY_MATH_MODF_FIX_NEGZERO (0)\n#endif\n\n// Whether to provide fix for pow(1, NaN) and pow(NaN, 0), which both should be 1 not NaN.\n#ifndef MICROPY_PY_MATH_POW_FIX_NAN\n#define MICROPY_PY_MATH_POW_FIX_NAN (0)\n#endif\n\n// Whether to provide \"cmath\" module\n#ifndef MICROPY_PY_CMATH\n#define MICROPY_PY_CMATH (0)\n#endif\n\n// Whether to provide \"gc\" module\n#ifndef MICROPY_PY_GC\n#define MICROPY_PY_GC (1)\n#endif\n\n// Whether to return number of collected objects from gc.collect()\n#ifndef MICROPY_PY_GC_COLLECT_RETVAL\n#define MICROPY_PY_GC_COLLECT_RETVAL (0)\n#endif\n\n// Whether to provide \"io\" module\n#ifndef MICROPY_PY_IO\n#define MICROPY_PY_IO (1)\n#endif\n\n// Whether to provide \"io.IOBase\" class to support user streams\n#ifndef MICROPY_PY_IO_IOBASE\n#define MICROPY_PY_IO_IOBASE (0)\n#endif\n\n// Whether to provide \"uio.resource_stream()\" function with\n// the semantics of CPython's pkg_resources.resource_stream()\n// (allows to access binary resources in frozen source packages).\n// Note that the same functionality can be achieved in \"pure\n// Python\" by prepocessing binary resources into Python source\n// and bytecode-freezing it (with a simple helper module available\n// e.g. in micropython-lib).\n#ifndef MICROPY_PY_IO_RESOURCE_STREAM\n#define MICROPY_PY_IO_RESOURCE_STREAM (0)\n#endif\n\n// Whether to provide \"io.FileIO\" class\n#ifndef MICROPY_PY_IO_FILEIO\n#define MICROPY_PY_IO_FILEIO (0)\n#endif\n\n// Whether to provide \"io.BytesIO\" class\n#ifndef MICROPY_PY_IO_BYTESIO\n#define MICROPY_PY_IO_BYTESIO (1)\n#endif\n\n// Whether to provide \"io.BufferedWriter\" class\n#ifndef MICROPY_PY_IO_BUFFEREDWRITER\n#define MICROPY_PY_IO_BUFFEREDWRITER (0)\n#endif\n\n// Whether to provide \"struct\" module\n#ifndef MICROPY_PY_STRUCT\n#define MICROPY_PY_STRUCT (1)\n#endif\n\n// Whether to provide \"sys\" module\n#ifndef MICROPY_PY_SYS\n#define MICROPY_PY_SYS (1)\n#endif\n\n// Whether to provide \"sys.maxsize\" constant\n#ifndef MICROPY_PY_SYS_MAXSIZE\n#define MICROPY_PY_SYS_MAXSIZE (0)\n#endif\n\n// Whether to provide \"sys.modules\" dictionary\n#ifndef MICROPY_PY_SYS_MODULES\n#define MICROPY_PY_SYS_MODULES (1)\n#endif\n\n// Whether to provide \"sys.exc_info\" function\n// Avoid enabling this, this function is Python2 heritage\n#ifndef MICROPY_PY_SYS_EXC_INFO\n#define MICROPY_PY_SYS_EXC_INFO (0)\n#endif\n\n// Whether to provide \"sys.exit\" function\n#ifndef MICROPY_PY_SYS_EXIT\n#define MICROPY_PY_SYS_EXIT (1)\n#endif\n\n// Whether to provide \"sys.atexit\" function (MicroPython extension)\n#ifndef MICROPY_PY_SYS_ATEXIT\n#define MICROPY_PY_SYS_ATEXIT (0)\n#endif\n\n// Whether to provide \"sys.settrace\" function\n#ifndef MICROPY_PY_SYS_SETTRACE\n#define MICROPY_PY_SYS_SETTRACE (0)\n#endif\n\n// Whether to provide \"sys.getsizeof\" function\n#ifndef MICROPY_PY_SYS_GETSIZEOF\n#define MICROPY_PY_SYS_GETSIZEOF (0)\n#endif\n\n// Whether to provide sys.{stdin,stdout,stderr} objects\n#ifndef MICROPY_PY_SYS_STDFILES\n#define MICROPY_PY_SYS_STDFILES (0)\n#endif\n\n// Whether to provide sys.{stdin,stdout,stderr}.buffer object\n// This is implemented per-port\n#ifndef MICROPY_PY_SYS_STDIO_BUFFER\n#define MICROPY_PY_SYS_STDIO_BUFFER (0)\n#endif\n\n// Whether to provide \"uerrno\" module\n#ifndef MICROPY_PY_UERRNO\n#define MICROPY_PY_UERRNO (0)\n#endif\n\n// Whether to provide the uerrno.errorcode dict\n#ifndef MICROPY_PY_UERRNO_ERRORCODE\n#define MICROPY_PY_UERRNO_ERRORCODE (1)\n#endif\n\n// Whether to provide \"uselect\" module (baremetal implementation)\n#ifndef MICROPY_PY_USELECT\n#define MICROPY_PY_USELECT (0)\n#endif\n\n// Whether to provide \"utime\" module functions implementation\n// in terms of mp_hal_* functions.\n#ifndef MICROPY_PY_UTIME_MP_HAL\n#define MICROPY_PY_UTIME_MP_HAL (0)\n#endif\n\n// Period of values returned by utime.ticks_ms(), ticks_us(), ticks_cpu()\n// functions. Should be power of two. All functions above use the same\n// period, so if underlying hardware/API has different periods, the\n// minimum of them should be used. The value below is the maximum value\n// this parameter can take (corresponding to 30 bit tick values on 32-bit\n// system).\n#ifndef MICROPY_PY_UTIME_TICKS_PERIOD\n#define MICROPY_PY_UTIME_TICKS_PERIOD (MP_SMALL_INT_POSITIVE_MASK + 1)\n#endif\n\n// Whether to provide \"_thread\" module\n#ifndef MICROPY_PY_THREAD\n#define MICROPY_PY_THREAD (0)\n#endif\n\n// Whether to make the VM/runtime thread-safe using a global lock\n// If not enabled then thread safety must be provided at the Python level\n#ifndef MICROPY_PY_THREAD_GIL\n#define MICROPY_PY_THREAD_GIL (MICROPY_PY_THREAD)\n#endif\n\n// Number of VM jump-loops to do before releasing the GIL.\n// Set this to 0 to disable the divisor.\n#ifndef MICROPY_PY_THREAD_GIL_VM_DIVISOR\n#define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32)\n#endif\n\n// Extended modules\n\n#ifndef MICROPY_PY_UASYNCIO\n#define MICROPY_PY_UASYNCIO (0)\n#endif\n\n#ifndef MICROPY_PY_UCTYPES\n#define MICROPY_PY_UCTYPES (0)\n#endif\n\n// Whether to provide SHORT, INT, LONG, etc. types in addition to\n// exact-bitness types like INT16, INT32, etc.\n#ifndef MICROPY_PY_UCTYPES_NATIVE_C_TYPES\n#define MICROPY_PY_UCTYPES_NATIVE_C_TYPES (1)\n#endif\n\n#ifndef MICROPY_PY_UZLIB\n#define MICROPY_PY_UZLIB (0)\n#endif\n\n#ifndef MICROPY_PY_UJSON\n#define MICROPY_PY_UJSON (0)\n#endif\n\n#ifndef MICROPY_PY_URE\n#define MICROPY_PY_URE (0)\n#endif\n\n#ifndef MICROPY_PY_URE_DEBUG\n#define MICROPY_PY_URE_DEBUG (0)\n#endif\n\n#ifndef MICROPY_PY_URE_MATCH_GROUPS\n#define MICROPY_PY_URE_MATCH_GROUPS (0)\n#endif\n\n#ifndef MICROPY_PY_URE_MATCH_SPAN_START_END\n#define MICROPY_PY_URE_MATCH_SPAN_START_END (0)\n#endif\n\n#ifndef MICROPY_PY_URE_SUB\n#define MICROPY_PY_URE_SUB (0)\n#endif\n\n#ifndef MICROPY_PY_UHEAPQ\n#define MICROPY_PY_UHEAPQ (0)\n#endif\n\n// Optimized heap queue for relative timestamps\n#ifndef MICROPY_PY_UTIMEQ\n#define MICROPY_PY_UTIMEQ (0)\n#endif\n\n#ifndef MICROPY_PY_UHASHLIB\n#define MICROPY_PY_UHASHLIB (0)\n#endif\n\n#ifndef MICROPY_PY_UHASHLIB_MD5\n#define MICROPY_PY_UHASHLIB_MD5 (0)\n#endif\n\n#ifndef MICROPY_PY_UHASHLIB_SHA1\n#define MICROPY_PY_UHASHLIB_SHA1  (0)\n#endif\n\n#ifndef MICROPY_PY_UHASHLIB_SHA256\n#define MICROPY_PY_UHASHLIB_SHA256 (1)\n#endif\n\n#ifndef MICROPY_PY_UCRYPTOLIB\n#define MICROPY_PY_UCRYPTOLIB (0)\n#endif\n\n// Depends on MICROPY_PY_UCRYPTOLIB\n#ifndef MICROPY_PY_UCRYPTOLIB_CTR\n#define MICROPY_PY_UCRYPTOLIB_CTR (0)\n#endif\n\n#ifndef MICROPY_PY_UCRYPTOLIB_CONSTS\n#define MICROPY_PY_UCRYPTOLIB_CONSTS (0)\n#endif\n\n#ifndef MICROPY_PY_UBINASCII\n#define MICROPY_PY_UBINASCII (0)\n#endif\n\n// Depends on MICROPY_PY_UZLIB\n#ifndef MICROPY_PY_UBINASCII_CRC32\n#define MICROPY_PY_UBINASCII_CRC32 (0)\n#endif\n\n#ifndef MICROPY_PY_URANDOM\n#define MICROPY_PY_URANDOM (0)\n#endif\n\n// Whether to include: randrange, randint, choice, random, uniform\n#ifndef MICROPY_PY_URANDOM_EXTRA_FUNCS\n#define MICROPY_PY_URANDOM_EXTRA_FUNCS (0)\n#endif\n\n#ifndef MICROPY_PY_MACHINE\n#define MICROPY_PY_MACHINE (0)\n#endif\n\n// Whether to include: time_pulse_us\n#ifndef MICROPY_PY_MACHINE_PULSE\n#define MICROPY_PY_MACHINE_PULSE (0)\n#endif\n\n#ifndef MICROPY_PY_MACHINE_I2C\n#define MICROPY_PY_MACHINE_I2C (0)\n#endif\n\n#ifndef MICROPY_PY_MACHINE_SPI\n#define MICROPY_PY_MACHINE_SPI (0)\n#endif\n\n#ifndef MICROPY_PY_USSL\n#define MICROPY_PY_USSL (0)\n// Whether to add finaliser code to ussl objects\n#define MICROPY_PY_USSL_FINALISER (0)\n#endif\n\n#ifndef MICROPY_PY_UWEBSOCKET\n#define MICROPY_PY_UWEBSOCKET (0)\n#endif\n\n#ifndef MICROPY_PY_FRAMEBUF\n#define MICROPY_PY_FRAMEBUF (0)\n#endif\n\n#ifndef MICROPY_PY_BTREE\n#define MICROPY_PY_BTREE (0)\n#endif\n\n/*****************************************************************************/\n/* Hooks for a port to add builtins                                          */\n\n// Additional builtin function definitions - see modbuiltins.c:mp_module_builtins_globals_table for format.\n#ifndef MICROPY_PORT_BUILTINS\n#define MICROPY_PORT_BUILTINS\n#endif\n\n// Additional builtin module definitions - see objmodule.c:mp_builtin_module_table for format.\n#ifndef MICROPY_PORT_BUILTIN_MODULES\n#define MICROPY_PORT_BUILTIN_MODULES\n#endif\n\n// Additional constant definitions for the compiler - see compile.c:mp_constants_table.\n#ifndef MICROPY_PORT_CONSTANTS\n#define MICROPY_PORT_CONSTANTS\n#endif\n\n// Any root pointers for GC scanning - see mpstate.c\n#ifndef MICROPY_PORT_ROOT_POINTERS\n#define MICROPY_PORT_ROOT_POINTERS\n#endif\n\n/*****************************************************************************/\n/* Hooks for a port to wrap functions with attributes                        */\n\n#ifndef MICROPY_WRAP_MP_KEYBOARD_INTERRUPT\n#define MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(f) f\n#endif\n\n#ifndef MICROPY_WRAP_MP_SCHED_SCHEDULE\n#define MICROPY_WRAP_MP_SCHED_SCHEDULE(f) f\n#endif\n\n/*****************************************************************************/\n/* Miscellaneous settings                                                    */\n\n// All uPy objects in ROM must be aligned on at least a 4 byte boundary\n// so that the small-int/qstr/pointer distinction can be made.  For machines\n// that don't do this (eg 16-bit CPU), define the following macro to something\n// like __attribute__((aligned(4))).\n#ifndef MICROPY_OBJ_BASE_ALIGNMENT\n#define MICROPY_OBJ_BASE_ALIGNMENT\n#endif\n\n// On embedded platforms, these will typically enable/disable irqs.\n#ifndef MICROPY_BEGIN_ATOMIC_SECTION\n#define MICROPY_BEGIN_ATOMIC_SECTION() (0)\n#endif\n#ifndef MICROPY_END_ATOMIC_SECTION\n#define MICROPY_END_ATOMIC_SECTION(state) (void)(state)\n#endif\n\n// Allow to override static modifier for global objects, e.g. to use with\n// object code analysis tools which don't support static symbols.\n#ifndef STATIC\n#define STATIC static\n#endif\n\n// Number of bytes in a word\n#ifndef BYTES_PER_WORD\n#define BYTES_PER_WORD (sizeof(mp_uint_t))\n#endif\n\n#ifndef BITS_PER_BYTE\n#define BITS_PER_BYTE (8)\n#endif\n#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD)\n// mp_int_t value with most significant bit set\n#define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1))\n\n// Make sure both MP_ENDIANNESS_LITTLE and MP_ENDIANNESS_BIG are\n// defined and that they are the opposite of each other.\n#if defined(MP_ENDIANNESS_LITTLE)\n#define MP_ENDIANNESS_BIG (!MP_ENDIANNESS_LITTLE)\n#elif defined(MP_ENDIANNESS_BIG)\n#define MP_ENDIANNESS_LITTLE (!MP_ENDIANNESS_BIG)\n#else\n// Endianness not defined by port so try to autodetect it.\n  #if defined(__BYTE_ORDER__)\n    #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n      #define MP_ENDIANNESS_LITTLE (1)\n    #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n      #define MP_ENDIANNESS_LITTLE (0)\n    #endif\n  #else\n    #include <endian.h>\n      #if defined(__BYTE_ORDER)\n        #if __BYTE_ORDER == __LITTLE_ENDIAN\n          #define MP_ENDIANNESS_LITTLE (1)\n        #elif __BYTE_ORDER == __BIG_ENDIAN\n          #define MP_ENDIANNESS_LITTLE (0)\n        #endif\n      #endif\n  #endif\n  #ifndef MP_ENDIANNESS_LITTLE\n    #error endianness not defined and cannot detect it\n  #endif\n  #define MP_ENDIANNESS_BIG (!MP_ENDIANNESS_LITTLE)\n#endif\n\n// Make a pointer to RAM callable (eg set lower bit for Thumb code)\n// (This scheme won't work if we want to mix Thumb and normal ARM code.)\n#ifndef MICROPY_MAKE_POINTER_CALLABLE\n#define MICROPY_MAKE_POINTER_CALLABLE(p) (p)\n#endif\n\n// If these MP_PLAT_*_EXEC macros are overridden then the memory allocated by them\n// must be somehow reachable for marking by the GC, since the native code\n// generators store pointers to GC managed memory in the code.\n#ifndef MP_PLAT_ALLOC_EXEC\n#define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) do { *ptr = m_new(byte, min_size); *size = min_size; } while (0)\n#endif\n\n#ifndef MP_PLAT_FREE_EXEC\n#define MP_PLAT_FREE_EXEC(ptr, size) m_del(byte, ptr, size)\n#endif\n\n// This macro is used to do all output (except when MICROPY_PY_IO is defined)\n#ifndef MP_PLAT_PRINT_STRN\n#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)\n#endif\n\n#ifndef MP_SSIZE_MAX\n#define MP_SSIZE_MAX SSIZE_MAX\n#endif\n\n// printf format spec to use for mp_int_t and friends\n#ifndef INT_FMT\n#if defined(__LP64__)\n// Archs where mp_int_t == long, long != int\n#define UINT_FMT \"%lu\"\n#define INT_FMT \"%ld\"\n#elif defined(_WIN64)\n#define UINT_FMT \"%llu\"\n#define INT_FMT \"%lld\"\n#else\n// Archs where mp_int_t == int\n#define UINT_FMT \"%u\"\n#define INT_FMT \"%d\"\n#endif\n#endif // INT_FMT\n\n// Modifier for function which doesn't return\n#ifndef NORETURN\n#define NORETURN __attribute__((noreturn))\n#endif\n\n// Modifier for weak functions\n#ifndef MP_WEAK\n#define MP_WEAK __attribute__((weak))\n#endif\n\n// Modifier for functions which should be never inlined\n#ifndef MP_NOINLINE\n#define MP_NOINLINE __attribute__((noinline))\n#endif\n\n// Modifier for functions which should be always inlined\n#ifndef MP_ALWAYSINLINE\n#define MP_ALWAYSINLINE __attribute__((always_inline))\n#endif\n\n// Condition is likely to be true, to help branch prediction\n#ifndef MP_LIKELY\n#define MP_LIKELY(x) __builtin_expect((x), 1)\n#endif\n\n// Condition is likely to be false, to help branch prediction\n#ifndef MP_UNLIKELY\n#define MP_UNLIKELY(x) __builtin_expect((x), 0)\n#endif\n\n// To annotate that code is unreachable\n#ifndef MP_UNREACHABLE\n#if defined(__GNUC__)\n#define MP_UNREACHABLE __builtin_unreachable();\n#else\n#define MP_UNREACHABLE for (;;);\n#endif\n#endif\n\n// Explicitly annotate switch case fall throughs\n#if defined(__GNUC__) && __GNUC__ >= 7\n#define MP_FALLTHROUGH __attribute__((fallthrough));\n#else\n#define MP_FALLTHROUGH\n#endif\n\n#ifndef MP_HTOBE16\n#if MP_ENDIANNESS_LITTLE\n#define MP_HTOBE16(x) ((uint16_t)((((x) & 0xff) << 8) | (((x) >> 8) & 0xff)))\n#define MP_BE16TOH(x) MP_HTOBE16(x)\n#else\n#define MP_HTOBE16(x) (x)\n#define MP_BE16TOH(x) (x)\n#endif\n#endif\n\n#ifndef MP_HTOBE32\n#if MP_ENDIANNESS_LITTLE\n#define MP_HTOBE32(x) ((uint32_t)((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff)))\n#define MP_BE32TOH(x) MP_HTOBE32(x)\n#else\n#define MP_HTOBE32(x) (x)\n#define MP_BE32TOH(x) (x)\n#endif\n#endif\n\n// Warning categories are by default implemented as strings, though\n// hook is left for a port to define them as something else.\n#if MICROPY_WARNINGS_CATEGORY\n#ifndef MP_WARN_CAT\n#define MP_WARN_CAT(x) #x\n#endif\n#else\n#undef MP_WARN_CAT\n#define MP_WARN_CAT(x) (NULL)\n#endif\n\n// Feature dependency check.\n#if MICROPY_PY_SYS_SETTRACE\n#if !MICROPY_PERSISTENT_CODE_SAVE\n#error \"MICROPY_PY_SYS_SETTRACE requires MICROPY_PERSISTENT_CODE_SAVE to be enabled\"\n#endif\n#if MICROPY_COMP_CONST\n#error \"MICROPY_PY_SYS_SETTRACE requires MICROPY_COMP_CONST to be disabled\"\n#endif\n#endif\n\n#endif // MICROPY_INCLUDED_PY_MPCONFIG_H\n"
  },
  {
    "path": "py/mperrno.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_MPERRNO_H\n#define MICROPY_INCLUDED_PY_MPERRNO_H\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_USE_INTERNAL_ERRNO\n\n// MP_Exxx errno's are defined directly as numeric values\n// (Linux constants are used as a reference)\n\n#define MP_EPERM              (1) // Operation not permitted\n#define MP_ENOENT             (2) // No such file or directory\n#define MP_ESRCH              (3) // No such process\n#define MP_EINTR              (4) // Interrupted system call\n#define MP_EIO                (5) // I/O error\n#define MP_ENXIO              (6) // No such device or address\n#define MP_E2BIG              (7) // Argument list too long\n#define MP_ENOEXEC            (8) // Exec format error\n#define MP_EBADF              (9) // Bad file number\n#define MP_ECHILD            (10) // No child processes\n#define MP_EAGAIN            (11) // Try again\n#define MP_ENOMEM            (12) // Out of memory\n#define MP_EACCES            (13) // Permission denied\n#define MP_EFAULT            (14) // Bad address\n#define MP_ENOTBLK           (15) // Block device required\n#define MP_EBUSY             (16) // Device or resource busy\n#define MP_EEXIST            (17) // File exists\n#define MP_EXDEV             (18) // Cross-device link\n#define MP_ENODEV            (19) // No such device\n#define MP_ENOTDIR           (20) // Not a directory\n#define MP_EISDIR            (21) // Is a directory\n#define MP_EINVAL            (22) // Invalid argument\n#define MP_ENFILE            (23) // File table overflow\n#define MP_EMFILE            (24) // Too many open files\n#define MP_ENOTTY            (25) // Not a typewriter\n#define MP_ETXTBSY           (26) // Text file busy\n#define MP_EFBIG             (27) // File too large\n#define MP_ENOSPC            (28) // No space left on device\n#define MP_ESPIPE            (29) // Illegal seek\n#define MP_EROFS             (30) // Read-only file system\n#define MP_EMLINK            (31) // Too many links\n#define MP_EPIPE             (32) // Broken pipe\n#define MP_EDOM              (33) // Math argument out of domain of func\n#define MP_ERANGE            (34) // Math result not representable\n#define MP_EWOULDBLOCK  MP_EAGAIN // Operation would block\n#define MP_EOPNOTSUPP        (95) // Operation not supported on transport endpoint\n#define MP_EAFNOSUPPORT      (97) // Address family not supported by protocol\n#define MP_EADDRINUSE        (98) // Address already in use\n#define MP_ECONNABORTED     (103) // Software caused connection abort\n#define MP_ECONNRESET       (104) // Connection reset by peer\n#define MP_ENOBUFS          (105) // No buffer space available\n#define MP_EISCONN          (106) // Transport endpoint is already connected\n#define MP_ENOTCONN         (107) // Transport endpoint is not connected\n#define MP_ETIMEDOUT        (110) // Connection timed out\n#define MP_ECONNREFUSED     (111) // Connection refused\n#define MP_EHOSTUNREACH     (113) // No route to host\n#define MP_EALREADY         (114) // Operation already in progress\n#define MP_EINPROGRESS      (115) // Operation now in progress\n\n#else\n\n// MP_Exxx errno's are defined in terms of system supplied ones\n\n#include <errno.h>\n\n#define MP_EPERM            EPERM\n#define MP_ENOENT           ENOENT\n#define MP_ESRCH            ESRCH\n#define MP_EINTR            EINTR\n#define MP_EIO              EIO\n#define MP_ENXIO            ENXIO\n#define MP_E2BIG            E2BIG\n#define MP_ENOEXEC          ENOEXEC\n#define MP_EBADF            EBADF\n#define MP_ECHILD           ECHILD\n#define MP_EAGAIN           EAGAIN\n#define MP_ENOMEM           ENOMEM\n#define MP_EACCES           EACCES\n#define MP_EFAULT           EFAULT\n#define MP_ENOTBLK          ENOTBLK\n#define MP_EBUSY            EBUSY\n#define MP_EEXIST           EEXIST\n#define MP_EXDEV            EXDEV\n#define MP_ENODEV           ENODEV\n#define MP_ENOTDIR          ENOTDIR\n#define MP_EISDIR           EISDIR\n#define MP_EINVAL           EINVAL\n#define MP_ENFILE           ENFILE\n#define MP_EMFILE           EMFILE\n#define MP_ENOTTY           ENOTTY\n#define MP_ETXTBSY          ETXTBSY\n#define MP_EFBIG            EFBIG\n#define MP_ENOSPC           ENOSPC\n#define MP_ESPIPE           ESPIPE\n#define MP_EROFS            EROFS\n#define MP_EMLINK           EMLINK\n#define MP_EPIPE            EPIPE\n#define MP_EDOM             EDOM\n#define MP_ERANGE           ERANGE\n#define MP_EWOULDBLOCK      EWOULDBLOCK\n#define MP_EOPNOTSUPP       EOPNOTSUPP\n#define MP_EAFNOSUPPORT     EAFNOSUPPORT\n#define MP_EADDRINUSE       EADDRINUSE\n#define MP_ECONNABORTED     ECONNABORTED\n#define MP_ECONNRESET       ECONNRESET\n#define MP_ENOBUFS          ENOBUFS\n#define MP_EISCONN          EISCONN\n#define MP_ENOTCONN         ENOTCONN\n#define MP_ETIMEDOUT        ETIMEDOUT\n#define MP_ECONNREFUSED     ECONNREFUSED\n#define MP_EHOSTUNREACH     EHOSTUNREACH\n#define MP_EALREADY         EALREADY\n#define MP_EINPROGRESS      EINPROGRESS\n\n#endif\n\n#if MICROPY_PY_UERRNO\n\n#include \"py/obj.h\"\n\nqstr mp_errno_to_str(mp_obj_t errno_val);\n\n#endif\n\n#endif // MICROPY_INCLUDED_PY_MPERRNO_H\n"
  },
  {
    "path": "py/mphal.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_MPHAL_H\n#define MICROPY_INCLUDED_PY_MPHAL_H\n\n#include <stdint.h>\n#include \"py/mpconfig.h\"\n\n#ifdef MICROPY_MPHALPORT_H\n#include MICROPY_MPHALPORT_H\n#else\n#include <mphalport.h>\n#endif\n\n#ifndef mp_hal_stdio_poll\nuintptr_t mp_hal_stdio_poll(uintptr_t poll_flags);\n#endif\n\n#ifndef mp_hal_stdin_rx_chr\nint mp_hal_stdin_rx_chr(void);\n#endif\n\n#ifndef mp_hal_stdout_tx_str\nvoid mp_hal_stdout_tx_str(const char *str);\n#endif\n\n#ifndef mp_hal_stdout_tx_strn\nvoid mp_hal_stdout_tx_strn(const char *str, size_t len);\n#endif\n\n#ifndef mp_hal_stdout_tx_strn_cooked\nvoid mp_hal_stdout_tx_strn_cooked(const char *str, size_t len);\n#endif\n\n#ifndef mp_hal_delay_ms\nvoid mp_hal_delay_ms(mp_uint_t ms);\n#endif\n\n#ifndef mp_hal_delay_us\nvoid mp_hal_delay_us(mp_uint_t us);\n#endif\n\n#ifndef mp_hal_ticks_ms\nmp_uint_t mp_hal_ticks_ms(void);\n#endif\n\n#ifndef mp_hal_ticks_us\nmp_uint_t mp_hal_ticks_us(void);\n#endif\n\n#ifndef mp_hal_ticks_cpu\nmp_uint_t mp_hal_ticks_cpu(void);\n#endif\n\n#ifndef mp_hal_time_ns\n// Nanoseconds since the Epoch.\nuint64_t mp_hal_time_ns(void);\n#endif\n\n// If port HAL didn't define its own pin API, use generic\n// \"virtual pin\" API from the core.\n#ifndef mp_hal_pin_obj_t\n#define mp_hal_pin_obj_t mp_obj_t\n#define mp_hal_get_pin_obj(pin) (pin)\n#define mp_hal_pin_read(pin) mp_virtual_pin_read(pin)\n#define mp_hal_pin_write(pin, v) mp_virtual_pin_write(pin, v)\n#include \"extmod/virtpin.h\"\n#endif\n\n#endif // MICROPY_INCLUDED_PY_MPHAL_H\n"
  },
  {
    "path": "py/mpprint.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2015 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <stdarg.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/mphal.h\"\n#include \"py/mpprint.h\"\n#include \"py/obj.h\"\n#include \"py/objint.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT\n#include \"py/formatfloat.h\"\n#endif\n\nstatic const char pad_spaces[] = \"                \";\nstatic const char pad_zeroes[] = \"0000000000000000\";\n\nSTATIC void plat_print_strn(void *env, const char *str, size_t len) {\n    (void)env;\n    MP_PLAT_PRINT_STRN(str, len);\n}\n\nconst mp_print_t mp_plat_print = {NULL, plat_print_strn};\n\nint mp_print_str(const mp_print_t *print, const char *str) {\n    size_t len = strlen(str);\n    if (len) {\n        print->print_strn(print->data, str, len);\n    }\n    return len;\n}\n\nint mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width) {\n    int left_pad = 0;\n    int right_pad = 0;\n    int pad = width - len;\n    int pad_size;\n    int total_chars_printed = 0;\n    const char *pad_chars;\n\n    if (!fill || fill == ' ') {\n        pad_chars = pad_spaces;\n        pad_size = sizeof(pad_spaces) - 1;\n    } else if (fill == '0') {\n        pad_chars = pad_zeroes;\n        pad_size = sizeof(pad_zeroes) - 1;\n    } else {\n        // Other pad characters are fairly unusual, so we'll take the hit\n        // and output them 1 at a time.\n        pad_chars = &fill;\n        pad_size = 1;\n    }\n\n    if (flags & PF_FLAG_CENTER_ADJUST) {\n        left_pad = pad / 2;\n        right_pad = pad - left_pad;\n    } else if (flags & PF_FLAG_LEFT_ADJUST) {\n        right_pad = pad;\n    } else {\n        left_pad = pad;\n    }\n\n    if (left_pad > 0) {\n        total_chars_printed += left_pad;\n        while (left_pad > 0) {\n            int p = left_pad;\n            if (p > pad_size) {\n                p = pad_size;\n            }\n            print->print_strn(print->data, pad_chars, p);\n            left_pad -= p;\n        }\n    }\n    if (len) {\n        print->print_strn(print->data, str, len);\n        total_chars_printed += len;\n    }\n    if (right_pad > 0) {\n        total_chars_printed += right_pad;\n        while (right_pad > 0) {\n            int p = right_pad;\n            if (p > pad_size) {\n                p = pad_size;\n            }\n            print->print_strn(print->data, pad_chars, p);\n            right_pad -= p;\n        }\n    }\n    return total_chars_printed;\n}\n\n// 32-bits is 10 digits, add 3 for commas, 1 for sign, 1 for terminating null\n// We can use 16 characters for 32-bit and 32 characters for 64-bit\n#define INT_BUF_SIZE (sizeof(mp_int_t) * 4)\n\n// Our mp_vprintf function below does not support the '#' format modifier to\n// print the prefix of a non-base-10 number, so we don't need code for this.\n#define SUPPORT_INT_BASE_PREFIX (0)\n\n// This function is used exclusively by mp_vprintf to format ints.\n// It needs to be a separate function to mp_print_mp_int, since converting to a mp_int looses the MSB.\nSTATIC 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) {\n    char sign = 0;\n    if (sgn) {\n        if ((mp_int_t)x < 0) {\n            sign = '-';\n            x = -x;\n        } else if (flags & PF_FLAG_SHOW_SIGN) {\n            sign = '+';\n        } else if (flags & PF_FLAG_SPACE_SIGN) {\n            sign = ' ';\n        }\n    }\n\n    char buf[INT_BUF_SIZE];\n    char *b = buf + INT_BUF_SIZE;\n\n    if (x == 0) {\n        *(--b) = '0';\n    } else {\n        do {\n            int c = x % base;\n            x /= base;\n            if (c >= 10) {\n                c += base_char - 10;\n            } else {\n                c += '0';\n            }\n            *(--b) = c;\n        } while (b > buf && x != 0);\n    }\n\n    #if SUPPORT_INT_BASE_PREFIX\n    char prefix_char = '\\0';\n\n    if (flags & PF_FLAG_SHOW_PREFIX) {\n        if (base == 2) {\n            prefix_char = base_char + 'b' - 'a';\n        } else if (base == 8) {\n            prefix_char = base_char + 'o' - 'a';\n        } else if (base == 16) {\n            prefix_char = base_char + 'x' - 'a';\n        }\n    }\n    #endif\n\n    int len = 0;\n    if (flags & PF_FLAG_PAD_AFTER_SIGN) {\n        if (sign) {\n            len += mp_print_strn(print, &sign, 1, flags, fill, 1);\n            width--;\n        }\n        #if SUPPORT_INT_BASE_PREFIX\n        if (prefix_char) {\n            len += mp_print_strn(print, \"0\", 1, flags, fill, 1);\n            len += mp_print_strn(print, &prefix_char, 1, flags, fill, 1);\n            width -= 2;\n        }\n        #endif\n    } else {\n        #if SUPPORT_INT_BASE_PREFIX\n        if (prefix_char && b > &buf[1]) {\n            *(--b) = prefix_char;\n            *(--b) = '0';\n        }\n        #endif\n        if (sign && b > buf) {\n            *(--b) = sign;\n        }\n    }\n\n    len += mp_print_strn(print, b, buf + INT_BUF_SIZE - b, flags, fill, width);\n    return len;\n}\n\nint 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) {\n    // These are the only values for \"base\" that are required to be supported by this\n    // function, since Python only allows the user to format integers in these bases.\n    // If needed this function could be generalised to handle other values.\n    assert(base == 2 || base == 8 || base == 10 || base == 16);\n\n    if (!mp_obj_is_int(x)) {\n        // This will convert booleans to int, or raise an error for\n        // non-integer types.\n        x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x));\n    }\n\n    if ((flags & (PF_FLAG_LEFT_ADJUST | PF_FLAG_CENTER_ADJUST)) == 0 && fill == '0') {\n        if (prec > width) {\n            width = prec;\n        }\n        prec = 0;\n    }\n    char prefix_buf[4];\n    char *prefix = prefix_buf;\n\n    if (mp_obj_int_sign(x) >= 0) {\n        if (flags & PF_FLAG_SHOW_SIGN) {\n            *prefix++ = '+';\n        } else if (flags & PF_FLAG_SPACE_SIGN) {\n            *prefix++ = ' ';\n        }\n    }\n\n    if (flags & PF_FLAG_SHOW_PREFIX) {\n        if (base == 2) {\n            *prefix++ = '0';\n            *prefix++ = base_char + 'b' - 'a';\n        } else if (base == 8) {\n            *prefix++ = '0';\n            if (flags & PF_FLAG_SHOW_OCTAL_LETTER) {\n                *prefix++ = base_char + 'o' - 'a';\n            }\n        } else if (base == 16) {\n            *prefix++ = '0';\n            *prefix++ = base_char + 'x' - 'a';\n        }\n    }\n    *prefix = '\\0';\n    int prefix_len = prefix - prefix_buf;\n    prefix = prefix_buf;\n\n    char comma = '\\0';\n    if (flags & PF_FLAG_SHOW_COMMA) {\n        comma = ',';\n    }\n\n    // The size of this buffer is rather arbitrary. If it's not large\n    // enough, a dynamic one will be allocated.\n    char stack_buf[sizeof(mp_int_t) * 4];\n    char *buf = stack_buf;\n    size_t buf_size = sizeof(stack_buf);\n    size_t fmt_size = 0;\n    char *str;\n\n    if (prec > 1) {\n        flags |= PF_FLAG_PAD_AFTER_SIGN;\n    }\n    char sign = '\\0';\n    if (flags & PF_FLAG_PAD_AFTER_SIGN) {\n        // We add the pad in this function, so since the pad goes after\n        // the sign & prefix, we format without a prefix\n        str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size,\n            x, base, NULL, base_char, comma);\n        if (*str == '-') {\n            sign = *str++;\n            fmt_size--;\n        }\n    } else {\n        str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size,\n            x, base, prefix, base_char, comma);\n    }\n\n    int spaces_before = 0;\n    int spaces_after = 0;\n\n    if (prec > 1) {\n        // If prec was specified, then prec specifies the width to zero-pad the\n        // the number to. This zero-padded number then gets left or right\n        // aligned in width characters.\n\n        int prec_width = fmt_size;  // The digits\n        if (prec_width < prec) {\n            prec_width = prec;\n        }\n        if (flags & PF_FLAG_PAD_AFTER_SIGN) {\n            if (sign) {\n                prec_width++;\n            }\n            prec_width += prefix_len;\n        }\n        if (prec_width < width) {\n            if (flags & PF_FLAG_LEFT_ADJUST) {\n                spaces_after = width - prec_width;\n            } else {\n                spaces_before = width - prec_width;\n            }\n        }\n        fill = '0';\n        flags &= ~PF_FLAG_LEFT_ADJUST;\n    }\n\n    int len = 0;\n    if (spaces_before) {\n        len += mp_print_strn(print, \"\", 0, 0, ' ', spaces_before);\n    }\n    if (flags & PF_FLAG_PAD_AFTER_SIGN) {\n        // pad after sign implies pad after prefix as well.\n        if (sign) {\n            len += mp_print_strn(print, &sign, 1, 0, 0, 1);\n            width--;\n        }\n        if (prefix_len) {\n            len += mp_print_strn(print, prefix, prefix_len, 0, 0, 1);\n            width -= prefix_len;\n        }\n    }\n    if (prec > 1) {\n        width = prec;\n    }\n\n    len += mp_print_strn(print, str, fmt_size, flags, fill, width);\n\n    if (spaces_after) {\n        len += mp_print_strn(print, \"\", 0, 0, ' ', spaces_after);\n    }\n\n    if (buf != stack_buf) {\n        m_del(char, buf, buf_size);\n    }\n    return len;\n}\n\n#if MICROPY_PY_BUILTINS_FLOAT\nint mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec) {\n    char buf[32];\n    char sign = '\\0';\n    int chrs = 0;\n\n    if (flags & PF_FLAG_SHOW_SIGN) {\n        sign = '+';\n    } else\n    if (flags & PF_FLAG_SPACE_SIGN) {\n        sign = ' ';\n    }\n\n    int len = mp_format_float(f, buf, sizeof(buf), fmt, prec, sign);\n\n    char *s = buf;\n\n    if ((flags & PF_FLAG_ADD_PERCENT) && (size_t)(len + 1) < sizeof(buf)) {\n        buf[len++] = '%';\n        buf[len] = '\\0';\n    }\n\n    // buf[0] < '0' returns true if the first character is space, + or -\n    if ((flags & PF_FLAG_PAD_AFTER_SIGN) && buf[0] < '0') {\n        // We have a sign character\n        s++;\n        chrs += mp_print_strn(print, &buf[0], 1, 0, 0, 1);\n        width--;\n        len--;\n    }\n\n    chrs += mp_print_strn(print, s, len, flags, fill, width);\n\n    return chrs;\n}\n#endif\n\nint mp_printf(const mp_print_t *print, const char *fmt, ...) {\n    va_list ap;\n    va_start(ap, fmt);\n    int ret = mp_vprintf(print, fmt, ap);\n    va_end(ap);\n    return ret;\n}\n\nint mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {\n    int chrs = 0;\n    for (;;) {\n        {\n            const char *f = fmt;\n            while (*f != '\\0' && *f != '%') {\n                ++f; // XXX UTF8 advance char\n            }\n            if (f > fmt) {\n                print->print_strn(print->data, fmt, f - fmt);\n                chrs += f - fmt;\n                fmt = f;\n            }\n        }\n\n        if (*fmt == '\\0') {\n            break;\n        }\n\n        // move past % character\n        ++fmt;\n\n        // parse flags, if they exist\n        int flags = 0;\n        char fill = ' ';\n        while (*fmt != '\\0') {\n            if (*fmt == '-') {\n                flags |= PF_FLAG_LEFT_ADJUST;\n            } else if (*fmt == '+') {\n                flags |= PF_FLAG_SHOW_SIGN;\n            } else if (*fmt == ' ') {\n                flags |= PF_FLAG_SPACE_SIGN;\n            } else if (*fmt == '!') {\n                flags |= PF_FLAG_NO_TRAILZ;\n            } else if (*fmt == '0') {\n                flags |= PF_FLAG_PAD_AFTER_SIGN;\n                fill = '0';\n            } else {\n                break;\n            }\n            ++fmt;\n        }\n\n        // parse width, if it exists\n        int width = 0;\n        for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {\n            width = width * 10 + *fmt - '0';\n        }\n\n        // parse precision, if it exists\n        int prec = -1;\n        if (*fmt == '.') {\n            ++fmt;\n            if (*fmt == '*') {\n                ++fmt;\n                prec = va_arg(args, int);\n            } else {\n                prec = 0;\n                for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {\n                    prec = prec * 10 + *fmt - '0';\n                }\n            }\n            if (prec < 0) {\n                prec = 0;\n            }\n        }\n\n        // parse long specifiers (only for LP64 model where they make a difference)\n        #ifndef __LP64__\n        const\n        #endif\n        bool long_arg = false;\n        if (*fmt == 'l') {\n            ++fmt;\n            #ifdef __LP64__\n            long_arg = true;\n            #endif\n        }\n\n        if (*fmt == '\\0') {\n            break;\n        }\n\n        switch (*fmt) {\n            case 'b':\n                if (va_arg(args, int)) {\n                    chrs += mp_print_strn(print, \"true\", 4, flags, fill, width);\n                } else {\n                    chrs += mp_print_strn(print, \"false\", 5, flags, fill, width);\n                }\n                break;\n            case 'c': {\n                char str = va_arg(args, int);\n                chrs += mp_print_strn(print, &str, 1, flags, fill, width);\n                break;\n            }\n            case 'q': {\n                qstr qst = va_arg(args, qstr);\n                size_t len;\n                const char *str = (const char *)qstr_data(qst, &len);\n                if (prec < 0) {\n                    prec = len;\n                }\n                chrs += mp_print_strn(print, str, prec, flags, fill, width);\n                break;\n            }\n            case 's': {\n                const char *str = va_arg(args, const char *);\n                #ifndef NDEBUG\n                // With debugging enabled, catch printing of null string pointers\n                if (prec != 0 && str == NULL) {\n                    chrs += mp_print_strn(print, \"(null)\", 6, flags, fill, width);\n                    break;\n                }\n                #endif\n                if (prec < 0) {\n                    prec = strlen(str);\n                }\n                chrs += mp_print_strn(print, str, prec, flags, fill, width);\n                break;\n            }\n            case 'd': {\n                mp_int_t val;\n                if (long_arg) {\n                    val = va_arg(args, long int);\n                } else {\n                    val = va_arg(args, int);\n                }\n                chrs += mp_print_int(print, val, 1, 10, 'a', flags, fill, width);\n                break;\n            }\n            case 'u':\n            case 'x':\n            case 'X': {\n                int base = 16 - ((*fmt + 1) & 6); // maps char u/x/X to base 10/16/16\n                char fmt_c = (*fmt & 0xf0) - 'P' + 'A'; // maps char u/x/X to char a/a/A\n                mp_uint_t val;\n                if (long_arg) {\n                    val = va_arg(args, unsigned long int);\n                } else {\n                    val = va_arg(args, unsigned int);\n                }\n                chrs += mp_print_int(print, val, 0, base, fmt_c, flags, fill, width);\n                break;\n            }\n            case 'p':\n            case 'P': // don't bother to handle upcase for 'P'\n                // Use unsigned long int to work on both ILP32 and LP64 systems\n                chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width);\n                break;\n            #if MICROPY_PY_BUILTINS_FLOAT\n            case 'e':\n            case 'E':\n            case 'f':\n            case 'F':\n            case 'g':\n            case 'G': {\n                #if ((MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT) || (MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE))\n                mp_float_t f = (mp_float_t)va_arg(args, double);\n                chrs += mp_print_float(print, f, *fmt, flags, fill, width, prec);\n                #else\n                #error Unknown MICROPY FLOAT IMPL\n                #endif\n                break;\n            }\n            #endif\n                // Because 'l' is eaten above, another 'l' means %ll.  We need to support\n                // this length specifier for OBJ_REPR_D (64-bit NaN boxing).\n                // TODO Either enable this unconditionally, or provide a specific config var.\n            #if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64)\n            case 'l': {\n                unsigned long long int arg_value = va_arg(args, unsigned long long int);\n                ++fmt;\n                if (*fmt == 'u' || *fmt == 'd') {\n                    chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width);\n                    break;\n                }\n                assert(!\"unsupported fmt char\");\n            }\n            #endif\n            default:\n                // if it's not %% then it's an unsupported format character\n                assert(*fmt == '%' || !\"unsupported fmt char\");\n                print->print_strn(print->data, fmt, 1);\n                chrs += 1;\n                break;\n        }\n        ++fmt;\n    }\n    return chrs;\n}\n"
  },
  {
    "path": "py/mpprint.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_MPPRINT_H\n#define MICROPY_INCLUDED_PY_MPPRINT_H\n\n#include \"py/mpconfig.h\"\n\n#define PF_FLAG_LEFT_ADJUST       (0x001)\n#define PF_FLAG_SHOW_SIGN         (0x002)\n#define PF_FLAG_SPACE_SIGN        (0x004)\n#define PF_FLAG_NO_TRAILZ         (0x008)\n#define PF_FLAG_SHOW_PREFIX       (0x010)\n#define PF_FLAG_SHOW_COMMA        (0x020)\n#define PF_FLAG_PAD_AFTER_SIGN    (0x040)\n#define PF_FLAG_CENTER_ADJUST     (0x080)\n#define PF_FLAG_ADD_PERCENT       (0x100)\n#define PF_FLAG_SHOW_OCTAL_LETTER (0x200)\n\n#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES\n#define MP_PYTHON_PRINTER &mp_sys_stdout_print\n#else\n#define MP_PYTHON_PRINTER &mp_plat_print\n#endif\n\ntypedef void (*mp_print_strn_t)(void *data, const char *str, size_t len);\n\ntypedef struct _mp_print_t {\n    void *data;\n    mp_print_strn_t print_strn;\n} mp_print_t;\n\n// All (non-debug) prints go through one of the two interfaces below.\n// 1) Wrapper for platform print function, which wraps MP_PLAT_PRINT_STRN.\nextern const mp_print_t mp_plat_print;\n#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES\n// 2) Wrapper for printing to sys.stdout.\nextern const mp_print_t mp_sys_stdout_print;\n#endif\n\nint mp_print_str(const mp_print_t *print, const char *str);\nint mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width);\n#if MICROPY_PY_BUILTINS_FLOAT\nint mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec);\n#endif\n\nint mp_printf(const mp_print_t *print, const char *fmt, ...);\n#ifdef va_start\nint mp_vprintf(const mp_print_t *print, const char *fmt, va_list args);\n#endif\n\n#endif // MICROPY_INCLUDED_PY_MPPRINT_H\n"
  },
  {
    "path": "py/mpstate.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpstate.h\"\n\n#if MICROPY_DYNAMIC_COMPILER\nmp_dynamic_compiler_t mp_dynamic_compiler = {0};\n#endif\n\nmp_state_ctx_t mp_state_ctx;\n"
  },
  {
    "path": "py/mpstate.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_MPSTATE_H\n#define MICROPY_INCLUDED_PY_MPSTATE_H\n\n#include <stdint.h>\n\n#include \"py/mpconfig.h\"\n#include \"py/mpthread.h\"\n#include \"py/misc.h\"\n#include \"py/nlr.h\"\n#include \"py/obj.h\"\n#include \"py/objlist.h\"\n#include \"py/objexcept.h\"\n\n// This file contains structures defining the state of the MicroPython\n// memory system, runtime and virtual machine.  The state is a global\n// variable, but in the future it is hoped that the state can become local.\n\n// This structure contains dynamic configuration for the compiler.\n#if MICROPY_DYNAMIC_COMPILER\ntypedef struct mp_dynamic_compiler_t {\n    uint8_t small_int_bits; // must be <= host small_int_bits\n    bool opt_cache_map_lookup_in_bytecode;\n    bool py_builtins_str_unicode;\n    uint8_t native_arch;\n    uint8_t nlr_buf_num_regs;\n} mp_dynamic_compiler_t;\nextern mp_dynamic_compiler_t mp_dynamic_compiler;\n#endif\n\n// These are the values for sched_state\n#define MP_SCHED_IDLE (1)\n#define MP_SCHED_LOCKED (-1)\n#define MP_SCHED_PENDING (0) // 0 so it's a quick check in the VM\n\ntypedef struct _mp_sched_item_t {\n    mp_obj_t func;\n    mp_obj_t arg;\n} mp_sched_item_t;\n\n// This structure hold information about the memory allocation system.\ntypedef struct _mp_state_mem_t {\n    #if MICROPY_MEM_STATS\n    size_t total_bytes_allocated;\n    size_t current_bytes_allocated;\n    size_t peak_bytes_allocated;\n    #endif\n\n    byte *gc_alloc_table_start;\n    size_t gc_alloc_table_byte_len;\n    #if MICROPY_ENABLE_FINALISER\n    byte *gc_finaliser_table_start;\n    #endif\n    byte *gc_pool_start;\n    byte *gc_pool_end;\n\n    int gc_stack_overflow;\n    MICROPY_GC_STACK_ENTRY_TYPE gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];\n    uint16_t gc_lock_depth;\n\n    // This variable controls auto garbage collection.  If set to 0 then the\n    // GC won't automatically run when gc_alloc can't find enough blocks.  But\n    // you can still allocate/free memory and also explicitly call gc_collect.\n    uint16_t gc_auto_collect_enabled;\n\n    #if MICROPY_GC_ALLOC_THRESHOLD\n    size_t gc_alloc_amount;\n    size_t gc_alloc_threshold;\n    #endif\n\n    size_t gc_last_free_atb_index;\n\n    #if MICROPY_PY_GC_COLLECT_RETVAL\n    size_t gc_collected;\n    #endif\n\n    #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL\n    // This is a global mutex used to make the GC thread-safe.\n    mp_thread_mutex_t gc_mutex;\n    #endif\n} mp_state_mem_t;\n\n// This structure hold runtime and VM information.  It includes a section\n// which contains root pointers that must be scanned by the GC.\ntypedef struct _mp_state_vm_t {\n    //\n    // CONTINUE ROOT POINTER SECTION\n    // This must start at the start of this structure and follows\n    // the state in the mp_state_thread_t structure, continuing\n    // the root pointer section from there.\n    //\n\n    qstr_pool_t *last_pool;\n\n    // non-heap memory for creating an exception if we can't allocate RAM\n    mp_obj_exception_t mp_emergency_exception_obj;\n\n    // memory for exception arguments if we can't allocate RAM\n    #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n    #if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0\n    // statically allocated buf (needs to be aligned to mp_obj_t)\n    mp_obj_t mp_emergency_exception_buf[MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE / sizeof(mp_obj_t)];\n    #else\n    // dynamically allocated buf\n    byte *mp_emergency_exception_buf;\n    #endif\n    #endif\n\n    #if MICROPY_KBD_EXCEPTION\n    // exception object of type KeyboardInterrupt\n    mp_obj_exception_t mp_kbd_exception;\n    #endif\n\n    // dictionary with loaded modules (may be exposed as sys.modules)\n    mp_obj_dict_t mp_loaded_modules_dict;\n\n    // pending exception object (MP_OBJ_NULL if not pending)\n    volatile mp_obj_t mp_pending_exception;\n\n    #if MICROPY_ENABLE_SCHEDULER\n    mp_sched_item_t sched_queue[MICROPY_SCHEDULER_DEPTH];\n    #endif\n\n    // current exception being handled, for sys.exc_info()\n    #if MICROPY_PY_SYS_EXC_INFO\n    mp_obj_base_t *cur_exception;\n    #endif\n\n    #if MICROPY_PY_SYS_ATEXIT\n    // exposed through sys.atexit function\n    mp_obj_t sys_exitfunc;\n    #endif\n\n    // dictionary for the __main__ module\n    mp_obj_dict_t dict_main;\n\n    // these two lists must be initialised per port, after the call to mp_init\n    mp_obj_list_t mp_sys_path_obj;\n    mp_obj_list_t mp_sys_argv_obj;\n\n    // dictionary for overridden builtins\n    #if MICROPY_CAN_OVERRIDE_BUILTINS\n    mp_obj_dict_t *mp_module_builtins_override_dict;\n    #endif\n\n    #if MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE\n    // An mp_obj_list_t that tracks relocated native code to prevent the GC from reclaiming them.\n    mp_obj_t track_reloc_code_list;\n    #endif\n\n    // include any root pointers defined by a port\n    MICROPY_PORT_ROOT_POINTERS\n\n    // root pointers for extmod\n\n    #if MICROPY_REPL_EVENT_DRIVEN\n    vstr_t *repl_line;\n    #endif\n\n    #if MICROPY_PY_OS_DUPTERM\n    mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM];\n    #endif\n\n    #if MICROPY_PY_LWIP_SLIP\n    mp_obj_t lwip_slip_stream;\n    #endif\n\n    #if MICROPY_VFS\n    struct _mp_vfs_mount_t *vfs_cur;\n    struct _mp_vfs_mount_t *vfs_mount_table;\n    #endif\n\n    #if MICROPY_PY_BLUETOOTH\n    mp_obj_t bluetooth;\n    #endif\n\n    //\n    // END ROOT POINTER SECTION\n    ////////////////////////////////////////////////////////////\n\n    // pointer and sizes to store interned string data\n    // (qstr_last_chunk can be root pointer but is also stored in qstr pool)\n    byte *qstr_last_chunk;\n    size_t qstr_last_alloc;\n    size_t qstr_last_used;\n\n    #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL\n    // This is a global mutex used to make qstr interning thread-safe.\n    mp_thread_mutex_t qstr_mutex;\n    #endif\n\n    #if MICROPY_ENABLE_COMPILER\n    mp_uint_t mp_optimise_value;\n    #if MICROPY_EMIT_NATIVE\n    uint8_t default_emit_opt; // one of MP_EMIT_OPT_xxx\n    #endif\n    #endif\n\n    // size of the emergency exception buf, if it's dynamically allocated\n    #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0\n    mp_int_t mp_emergency_exception_buf_size;\n    #endif\n\n    #if MICROPY_ENABLE_SCHEDULER\n    volatile int16_t sched_state;\n    uint8_t sched_len;\n    uint8_t sched_idx;\n    #endif\n\n    #if MICROPY_PY_THREAD_GIL\n    // This is a global mutex used to make the VM/runtime thread-safe.\n    mp_thread_mutex_t gil_mutex;\n    #endif\n} mp_state_vm_t;\n\n// This structure holds state that is specific to a given thread.\n// Everything in this structure is scanned for root pointers.\ntypedef struct _mp_state_thread_t {\n    // Stack top at the start of program\n    char *stack_top;\n\n    #if MICROPY_STACK_CHECK\n    size_t stack_limit;\n    #endif\n\n    #if MICROPY_ENABLE_PYSTACK\n    uint8_t *pystack_start;\n    uint8_t *pystack_end;\n    uint8_t *pystack_cur;\n    #endif\n\n    ////////////////////////////////////////////////////////////\n    // START ROOT POINTER SECTION\n    // Everything that needs GC scanning must start here, and\n    // is followed by state in the mp_state_vm_t structure.\n    //\n\n    mp_obj_dict_t *dict_locals;\n    mp_obj_dict_t *dict_globals;\n\n    nlr_buf_t *nlr_top;\n\n    #if MICROPY_PY_SYS_SETTRACE\n    mp_obj_t prof_trace_callback;\n    bool prof_callback_is_executing;\n    struct _mp_code_state_t *current_code_state;\n    #endif\n} mp_state_thread_t;\n\n// This structure combines the above 3 structures.\n// The order of the entries are important for root pointer scanning in the GC to work.\ntypedef struct _mp_state_ctx_t {\n    mp_state_thread_t thread;\n    mp_state_vm_t vm;\n    mp_state_mem_t mem;\n} mp_state_ctx_t;\n\nextern mp_state_ctx_t mp_state_ctx;\n\n#define MP_STATE_VM(x) (mp_state_ctx.vm.x)\n#define MP_STATE_MEM(x) (mp_state_ctx.mem.x)\n\n#if MICROPY_PY_THREAD\nextern mp_state_thread_t *mp_thread_get_state(void);\n#define MP_STATE_THREAD(x) (mp_thread_get_state()->x)\n#else\n#define MP_STATE_THREAD(x) (mp_state_ctx.thread.x)\n#endif\n\n#endif // MICROPY_INCLUDED_PY_MPSTATE_H\n"
  },
  {
    "path": "py/mpthread.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_MPTHREAD_H\n#define MICROPY_INCLUDED_PY_MPTHREAD_H\n\n#include \"py/mpconfig.h\"\n\n#if MICROPY_PY_THREAD\n\nstruct _mp_state_thread_t;\n\n#ifdef MICROPY_MPTHREADPORT_H\n#include MICROPY_MPTHREADPORT_H\n#else\n#include <mpthreadport.h>\n#endif\n\nstruct _mp_state_thread_t *mp_thread_get_state(void);\nvoid mp_thread_set_state(struct _mp_state_thread_t *state);\nvoid mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size);\nvoid mp_thread_start(void);\nvoid mp_thread_finish(void);\nvoid mp_thread_mutex_init(mp_thread_mutex_t *mutex);\nint mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait);\nvoid mp_thread_mutex_unlock(mp_thread_mutex_t *mutex);\n\n#endif // MICROPY_PY_THREAD\n\n#if MICROPY_PY_THREAD && MICROPY_PY_THREAD_GIL\n#include \"py/mpstate.h\"\n#define MP_THREAD_GIL_ENTER() mp_thread_mutex_lock(&MP_STATE_VM(gil_mutex), 1)\n#define MP_THREAD_GIL_EXIT() mp_thread_mutex_unlock(&MP_STATE_VM(gil_mutex))\n#else\n#define MP_THREAD_GIL_ENTER()\n#define MP_THREAD_GIL_EXIT()\n#endif\n\n#endif // MICROPY_INCLUDED_PY_MPTHREAD_H\n"
  },
  {
    "path": "py/mpz.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <assert.h>\n\n#include \"py/mpz.h\"\n\n#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ\n\n#define DIG_SIZE (MPZ_DIG_SIZE)\n#define DIG_MASK ((MPZ_LONG_1 << DIG_SIZE) - 1)\n#define DIG_MSB  (MPZ_LONG_1 << (DIG_SIZE - 1))\n#define DIG_BASE (MPZ_LONG_1 << DIG_SIZE)\n\n/*\n mpz is an arbitrary precision integer type with a public API.\n\n mpn functions act on non-negative integers represented by an array of generalised\n digits (eg a word per digit).  You also need to specify separately the length of the\n array.  There is no public API for mpn.  Rather, the functions are used by mpz to\n implement its features.\n\n Integer values are stored little endian (first digit is first in memory).\n\n Definition of normalise: ?\n*/\n\nSTATIC size_t mpn_remove_trailing_zeros(mpz_dig_t *oidig, mpz_dig_t *idig) {\n    for (--idig; idig >= oidig && *idig == 0; --idig) {\n    }\n    return idig + 1 - oidig;\n}\n\n/* compares i with j\n   returns sign(i - j)\n   assumes i, j are normalised\n*/\nSTATIC int mpn_cmp(const mpz_dig_t *idig, size_t ilen, const mpz_dig_t *jdig, size_t jlen) {\n    if (ilen < jlen) {\n        return -1;\n    }\n    if (ilen > jlen) {\n        return 1;\n    }\n\n    for (idig += ilen, jdig += ilen; ilen > 0; --ilen) {\n        mpz_dbl_dig_signed_t cmp = (mpz_dbl_dig_t)*(--idig) - (mpz_dbl_dig_t)*(--jdig);\n        if (cmp < 0) {\n            return -1;\n        }\n        if (cmp > 0) {\n            return 1;\n        }\n    }\n\n    return 0;\n}\n\n/* computes i = j << n\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised j; assumes n > 0\n   can have i, j pointing to same memory\n*/\nSTATIC size_t mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mp_uint_t n) {\n    mp_uint_t n_whole = (n + DIG_SIZE - 1) / DIG_SIZE;\n    mp_uint_t n_part = n % DIG_SIZE;\n    if (n_part == 0) {\n        n_part = DIG_SIZE;\n    }\n\n    // start from the high end of the digit arrays\n    idig += jlen + n_whole - 1;\n    jdig += jlen - 1;\n\n    // shift the digits\n    mpz_dbl_dig_t d = 0;\n    for (size_t i = jlen; i > 0; i--, idig--, jdig--) {\n        d |= *jdig;\n        *idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;\n        d <<= DIG_SIZE;\n    }\n\n    // store remaining bits\n    *idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;\n    idig -= n_whole - 1;\n    memset(idig, 0, (n_whole - 1) * sizeof(mpz_dig_t));\n\n    // work out length of result\n    jlen += n_whole;\n    while (jlen != 0 && idig[jlen - 1] == 0) {\n        jlen--;\n    }\n\n    // return length of result\n    return jlen;\n}\n\n/* computes i = j >> n\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised j; assumes n > 0\n   can have i, j pointing to same memory\n*/\nSTATIC size_t mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mp_uint_t n) {\n    mp_uint_t n_whole = n / DIG_SIZE;\n    mp_uint_t n_part = n % DIG_SIZE;\n\n    if (n_whole >= jlen) {\n        return 0;\n    }\n\n    jdig += n_whole;\n    jlen -= n_whole;\n\n    for (size_t i = jlen; i > 0; i--, idig++, jdig++) {\n        mpz_dbl_dig_t d = *jdig;\n        if (i > 1) {\n            d |= (mpz_dbl_dig_t)jdig[1] << DIG_SIZE;\n        }\n        d >>= n_part;\n        *idig = d & DIG_MASK;\n    }\n\n    if (idig[-1] == 0) {\n        jlen--;\n    }\n\n    return jlen;\n}\n\n/* computes i = j + k\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen\n   can have i, j, k pointing to same memory\n*/\nSTATIC size_t mpn_add(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) {\n    mpz_dig_t *oidig = idig;\n    mpz_dbl_dig_t carry = 0;\n\n    jlen -= klen;\n\n    for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {\n        carry += (mpz_dbl_dig_t)*jdig + (mpz_dbl_dig_t)*kdig;\n        *idig = carry & DIG_MASK;\n        carry >>= DIG_SIZE;\n    }\n\n    for (; jlen > 0; --jlen, ++idig, ++jdig) {\n        carry += *jdig;\n        *idig = carry & DIG_MASK;\n        carry >>= DIG_SIZE;\n    }\n\n    if (carry != 0) {\n        *idig++ = carry;\n    }\n\n    return idig - oidig;\n}\n\n/* computes i = j - k\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised j, k; assumes j >= k\n   can have i, j, k pointing to same memory\n*/\nSTATIC size_t mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) {\n    mpz_dig_t *oidig = idig;\n    mpz_dbl_dig_signed_t borrow = 0;\n\n    jlen -= klen;\n\n    for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {\n        borrow += (mpz_dbl_dig_t)*jdig - (mpz_dbl_dig_t)*kdig;\n        *idig = borrow & DIG_MASK;\n        borrow >>= DIG_SIZE;\n    }\n\n    for (; jlen > 0; --jlen, ++idig, ++jdig) {\n        borrow += *jdig;\n        *idig = borrow & DIG_MASK;\n        borrow >>= DIG_SIZE;\n    }\n\n    return mpn_remove_trailing_zeros(oidig, idig);\n}\n\n#if MICROPY_OPT_MPZ_BITWISE\n\n/* computes i = j & k\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen (jlen argument not needed)\n   can have i, j, k pointing to same memory\n*/\nSTATIC size_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, const mpz_dig_t *kdig, size_t klen) {\n    mpz_dig_t *oidig = idig;\n\n    for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {\n        *idig = *jdig & *kdig;\n    }\n\n    return mpn_remove_trailing_zeros(oidig, idig);\n}\n\n#endif\n\n/*  i = -((-j) & (-k))                = ~((~j + 1) & (~k + 1)) + 1\n    i =  (j & (-k)) =  (j & (~k + 1)) =  (  j      & (~k + 1))\n    i =  ((-j) & k) =  ((~j + 1) & k) =  ((~j + 1) &   k     )\n   computes general form:\n   i = (im ^ (((j ^ jm) + jc) & ((k ^ km) + kc))) + ic  where Xm = Xc == 0 ? 0 : DIG_MASK\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised j, k; assumes length j >= length k\n   can have i, j, k pointing to same memory\n*/\nSTATIC 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,\n    mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {\n    mpz_dig_t *oidig = idig;\n    mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;\n    mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;\n    mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;\n\n    for (; jlen > 0; ++idig, ++jdig) {\n        carryj += *jdig ^ jmask;\n        carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;\n        carryi += ((carryj & carryk) ^ imask) & DIG_MASK;\n        *idig = carryi & DIG_MASK;\n        carryk >>= DIG_SIZE;\n        carryj >>= DIG_SIZE;\n        carryi >>= DIG_SIZE;\n    }\n\n    if (0 != carryi) {\n        *idig++ = carryi;\n    }\n\n    return mpn_remove_trailing_zeros(oidig, idig);\n}\n\n#if MICROPY_OPT_MPZ_BITWISE\n\n/* computes i = j | k\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen\n   can have i, j, k pointing to same memory\n*/\nSTATIC size_t mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) {\n    mpz_dig_t *oidig = idig;\n\n    jlen -= klen;\n\n    for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {\n        *idig = *jdig | *kdig;\n    }\n\n    for (; jlen > 0; --jlen, ++idig, ++jdig) {\n        *idig = *jdig;\n    }\n\n    return idig - oidig;\n}\n\n#endif\n\n/*  i = -((-j) | (-k))                = ~((~j + 1) | (~k + 1)) + 1\n    i = -(j | (-k)) = -(j | (~k + 1)) = ~(  j      | (~k + 1)) + 1\n    i = -((-j) | k) = -((~j + 1) | k) = ~((~j + 1) |   k     ) + 1\n   computes general form:\n   i = ~(((j ^ jm) + jc) | ((k ^ km) + kc)) + 1  where Xm = Xc == 0 ? 0 : DIG_MASK\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised j, k; assumes length j >= length k\n   can have i, j, k pointing to same memory\n*/\n\n#if MICROPY_OPT_MPZ_BITWISE\n\nSTATIC 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,\n    mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {\n    mpz_dig_t *oidig = idig;\n    mpz_dbl_dig_t carryi = 1;\n    mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;\n    mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;\n\n    for (; jlen > 0; ++idig, ++jdig) {\n        carryj += *jdig ^ jmask;\n        carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;\n        carryi += ((carryj | carryk) ^ DIG_MASK) & DIG_MASK;\n        *idig = carryi & DIG_MASK;\n        carryk >>= DIG_SIZE;\n        carryj >>= DIG_SIZE;\n        carryi >>= DIG_SIZE;\n    }\n\n    // At least one of j,k must be negative so the above for-loop runs at least\n    // once.  For carryi to be non-zero here it must be equal to 1 at the end of\n    // each iteration of the loop.  So the accumulation of carryi must overflow\n    // each time, ie carryi += 0xff..ff.  So carryj|carryk must be 0 in the\n    // DIG_MASK bits on each iteration.  But considering all cases of signs of\n    // j,k one sees that this is not possible.\n    assert(carryi == 0);\n\n    return mpn_remove_trailing_zeros(oidig, idig);\n}\n\n#else\n\nSTATIC 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,\n    mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {\n    mpz_dig_t *oidig = idig;\n    mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;\n    mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;\n    mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;\n\n    for (; jlen > 0; ++idig, ++jdig) {\n        carryj += *jdig ^ jmask;\n        carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;\n        carryi += ((carryj | carryk) ^ imask) & DIG_MASK;\n        *idig = carryi & DIG_MASK;\n        carryk >>= DIG_SIZE;\n        carryj >>= DIG_SIZE;\n        carryi >>= DIG_SIZE;\n    }\n\n    // See comment in above mpn_or_neg for why carryi must be 0.\n    assert(carryi == 0);\n\n    return mpn_remove_trailing_zeros(oidig, idig);\n}\n\n#endif\n\n#if MICROPY_OPT_MPZ_BITWISE\n\n/* computes i = j ^ k\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen\n   can have i, j, k pointing to same memory\n*/\nSTATIC size_t mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) {\n    mpz_dig_t *oidig = idig;\n\n    jlen -= klen;\n\n    for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {\n        *idig = *jdig ^ *kdig;\n    }\n\n    for (; jlen > 0; --jlen, ++idig, ++jdig) {\n        *idig = *jdig;\n    }\n\n    return mpn_remove_trailing_zeros(oidig, idig);\n}\n\n#endif\n\n/*  i = (-j) ^ (-k) = ~(j - 1) ^ ~(k - 1)                   = (j - 1) ^ (k - 1)\n    i = -(j ^ (-k)) = -(j ^ ~(k - 1)) = ~(j ^ ~(k - 1)) + 1 = (j ^ (k - 1)) + 1\n    i = -((-j) ^ k) = -(~(j - 1) ^ k) = ~(~(j - 1) ^ k) + 1 = ((j - 1) ^ k) + 1\n   computes general form:\n   i = ((j - 1 + jc) ^ (k - 1 + kc)) + ic\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised j, k; assumes length j >= length k\n   can have i, j, k pointing to same memory\n*/\nSTATIC 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,\n    mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {\n    mpz_dig_t *oidig = idig;\n\n    for (; jlen > 0; ++idig, ++jdig) {\n        carryj += *jdig + DIG_MASK;\n        carryk += (--klen <= --jlen) ? (*kdig++ + DIG_MASK) : DIG_MASK;\n        carryi += (carryj ^ carryk) & DIG_MASK;\n        *idig = carryi & DIG_MASK;\n        carryk >>= DIG_SIZE;\n        carryj >>= DIG_SIZE;\n        carryi >>= DIG_SIZE;\n    }\n\n    if (0 != carryi) {\n        *idig++ = carryi;\n    }\n\n    return mpn_remove_trailing_zeros(oidig, idig);\n}\n\n/* computes i = i * d1 + d2\n   returns number of digits in i\n   assumes enough memory in i; assumes normalised i; assumes dmul != 0\n*/\nSTATIC size_t mpn_mul_dig_add_dig(mpz_dig_t *idig, size_t ilen, mpz_dig_t dmul, mpz_dig_t dadd) {\n    mpz_dig_t *oidig = idig;\n    mpz_dbl_dig_t carry = dadd;\n\n    for (; ilen > 0; --ilen, ++idig) {\n        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\n        *idig = carry & DIG_MASK;\n        carry >>= DIG_SIZE;\n    }\n\n    if (carry != 0) {\n        *idig++ = carry;\n    }\n\n    return idig - oidig;\n}\n\n/* computes i = j * k\n   returns number of digits in i\n   assumes enough memory in i; assumes i is zeroed; assumes normalised j, k\n   can have j, k point to same memory\n*/\nSTATIC size_t mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mpz_dig_t *kdig, size_t klen) {\n    mpz_dig_t *oidig = idig;\n    size_t ilen = 0;\n\n    for (; klen > 0; --klen, ++idig, ++kdig) {\n        mpz_dig_t *id = idig;\n        mpz_dbl_dig_t carry = 0;\n\n        size_t jl = jlen;\n        for (mpz_dig_t *jd = jdig; jl > 0; --jl, ++jd, ++id) {\n            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\n            *id = carry & DIG_MASK;\n            carry >>= DIG_SIZE;\n        }\n\n        if (carry != 0) {\n            *id++ = carry;\n        }\n\n        ilen = id - oidig;\n    }\n\n    return ilen;\n}\n\n/* natural_div - quo * den + new_num = old_num (ie num is replaced with rem)\n   assumes den != 0\n   assumes num_dig has enough memory to be extended by 1 digit\n   assumes quo_dig has enough memory (as many digits as num)\n   assumes quo_dig is filled with zeros\n*/\nSTATIC 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) {\n    mpz_dig_t *orig_num_dig = num_dig;\n    mpz_dig_t *orig_quo_dig = quo_dig;\n    mpz_dig_t norm_shift = 0;\n    mpz_dbl_dig_t lead_den_digit;\n\n    // handle simple cases\n    {\n        int cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);\n        if (cmp == 0) {\n            *num_len = 0;\n            quo_dig[0] = 1;\n            *quo_len = 1;\n            return;\n        } else if (cmp < 0) {\n            // numerator remains the same\n            *quo_len = 0;\n            return;\n        }\n    }\n\n    // We need to normalise the denominator (leading bit of leading digit is 1)\n    // so that the division routine works.  Since the denominator memory is\n    // read-only we do the normalisation on the fly, each time a digit of the\n    // denominator is needed.  We need to know is how many bits to shift by.\n\n    // count number of leading zeros in leading digit of denominator\n    {\n        mpz_dig_t d = den_dig[den_len - 1];\n        while ((d & DIG_MSB) == 0) {\n            d <<= 1;\n            ++norm_shift;\n        }\n    }\n\n    // now need to shift numerator by same amount as denominator\n    // first, increase length of numerator in case we need more room to shift\n    num_dig[*num_len] = 0;\n    ++(*num_len);\n    for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) {\n        mpz_dig_t n = *num;\n        *num = ((n << norm_shift) | carry) & DIG_MASK;\n        carry = (mpz_dbl_dig_t)n >> (DIG_SIZE - norm_shift);\n    }\n\n    // cache the leading digit of the denominator\n    lead_den_digit = (mpz_dbl_dig_t)den_dig[den_len - 1] << norm_shift;\n    if (den_len >= 2) {\n        lead_den_digit |= (mpz_dbl_dig_t)den_dig[den_len - 2] >> (DIG_SIZE - norm_shift);\n    }\n\n    // point num_dig to last digit in numerator\n    num_dig += *num_len - 1;\n\n    // calculate number of digits in quotient\n    *quo_len = *num_len - den_len;\n\n    // point to last digit to store for quotient\n    quo_dig += *quo_len - 1;\n\n    // keep going while we have enough digits to divide\n    while (*num_len > den_len) {\n        mpz_dbl_dig_t quo = ((mpz_dbl_dig_t)*num_dig << DIG_SIZE) | num_dig[-1];\n\n        // get approximate quotient\n        quo /= lead_den_digit;\n\n        // Multiply quo by den and subtract from num to get remainder.\n        // We have different code here to handle different compile-time\n        // configurations of mpz:\n        //\n        //   1. DIG_SIZE is stricly less than half the number of bits\n        //      available in mpz_dbl_dig_t.  In this case we can use a\n        //      slightly more optimal (in time and space) routine that\n        //      uses the extra bits in mpz_dbl_dig_signed_t to store a\n        //      sign bit.\n        //\n        //   2. DIG_SIZE is exactly half the number of bits available in\n        //      mpz_dbl_dig_t.  In this (common) case we need to be careful\n        //      not to overflow the borrow variable.  And the shifting of\n        //      borrow needs some special logic (it's a shift right with\n        //      round up).\n        //\n        const mpz_dig_t *d = den_dig;\n        mpz_dbl_dig_t d_norm = 0;\n        mpz_dbl_dig_t borrow = 0;\n        for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {\n            d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);\n            mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK);\n            #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2\n            borrow += (mpz_dbl_dig_t)*n - x; // will overflow if DIG_SIZE >= MPZ_DBL_DIG_SIZE/2\n            *n = borrow & DIG_MASK;\n            borrow = (mpz_dbl_dig_signed_t)borrow >> DIG_SIZE;\n            #else // DIG_SIZE == MPZ_DBL_DIG_SIZE / 2\n            if (x >= *n || *n - x <= borrow) {\n                borrow += x - (mpz_dbl_dig_t)*n;\n                *n = (-borrow) & DIG_MASK;\n                borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up\n            } else {\n                *n = ((mpz_dbl_dig_t)*n - x - borrow) & DIG_MASK;\n                borrow = 0;\n            }\n            #endif\n        }\n\n        #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2\n        // Borrow was negative in the above for-loop, make it positive for next if-block.\n        borrow = -borrow;\n        #endif\n\n        // At this point we have either:\n        //\n        //   1. quo was the correct value and the most-sig-digit of num is exactly\n        //      cancelled by borrow (borrow == *num_dig).  In this case there is\n        //      nothing more to do.\n        //\n        //   2. quo was too large, we subtracted too many den from num, and the\n        //      most-sig-digit of num is 1 less than borrow (borrow == *num_dig + 1).\n        //      In this case we must reduce quo and add back den to num until the\n        //      carry from this operation cancels out the borrow.\n        //\n        borrow -= *num_dig;\n        for (; borrow != 0; --quo) {\n            d = den_dig;\n            d_norm = 0;\n            mpz_dbl_dig_t carry = 0;\n            for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {\n                d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);\n                carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK);\n                *n = carry & DIG_MASK;\n                carry >>= DIG_SIZE;\n            }\n            borrow -= carry;\n        }\n\n        // store this digit of the quotient\n        *quo_dig = quo & DIG_MASK;\n        --quo_dig;\n\n        // move down to next digit of numerator\n        --num_dig;\n        --(*num_len);\n    }\n\n    // unnormalise numerator (remainder now)\n    for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) {\n        mpz_dig_t n = *num;\n        *num = ((n >> norm_shift) | carry) & DIG_MASK;\n        carry = (mpz_dbl_dig_t)n << (DIG_SIZE - norm_shift);\n    }\n\n    // strip trailing zeros\n\n    while (*quo_len > 0 && orig_quo_dig[*quo_len - 1] == 0) {\n        --(*quo_len);\n    }\n\n    while (*num_len > 0 && orig_num_dig[*num_len - 1] == 0) {\n        --(*num_len);\n    }\n}\n\n#define MIN_ALLOC (2)\n\nvoid mpz_init_zero(mpz_t *z) {\n    z->neg = 0;\n    z->fixed_dig = 0;\n    z->alloc = 0;\n    z->len = 0;\n    z->dig = NULL;\n}\n\nvoid mpz_init_from_int(mpz_t *z, mp_int_t val) {\n    mpz_init_zero(z);\n    mpz_set_from_int(z, val);\n}\n\nvoid mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, size_t alloc, mp_int_t val) {\n    z->neg = 0;\n    z->fixed_dig = 1;\n    z->alloc = alloc;\n    z->len = 0;\n    z->dig = dig;\n    mpz_set_from_int(z, val);\n}\n\nvoid mpz_deinit(mpz_t *z) {\n    if (z != NULL && !z->fixed_dig) {\n        m_del(mpz_dig_t, z->dig, z->alloc);\n    }\n}\n\n#if 0\nthese functions are unused\n\nmpz_t *mpz_zero(void) {\n    mpz_t *z = m_new_obj(mpz_t);\n    mpz_init_zero(z);\n    return z;\n}\n\nmpz_t *mpz_from_int(mp_int_t val) {\n    mpz_t *z = mpz_zero();\n    mpz_set_from_int(z, val);\n    return z;\n}\n\nmpz_t *mpz_from_ll(long long val, bool is_signed) {\n    mpz_t *z = mpz_zero();\n    mpz_set_from_ll(z, val, is_signed);\n    return z;\n}\n\n#if MICROPY_PY_BUILTINS_FLOAT\nmpz_t *mpz_from_float(mp_float_t val) {\n    mpz_t *z = mpz_zero();\n    mpz_set_from_float(z, val);\n    return z;\n}\n#endif\n\nmpz_t *mpz_from_str(const char *str, size_t len, bool neg, unsigned int base) {\n    mpz_t *z = mpz_zero();\n    mpz_set_from_str(z, str, len, neg, base);\n    return z;\n}\n#endif\n\nSTATIC void mpz_free(mpz_t *z) {\n    if (z != NULL) {\n        m_del(mpz_dig_t, z->dig, z->alloc);\n        m_del_obj(mpz_t, z);\n    }\n}\n\nSTATIC void mpz_need_dig(mpz_t *z, size_t need) {\n    if (need < MIN_ALLOC) {\n        need = MIN_ALLOC;\n    }\n\n    if (z->dig == NULL || z->alloc < need) {\n        // if z has fixed digit buffer there's not much we can do as the caller will\n        // be expecting a buffer with at least \"need\" bytes (but it shouldn't happen)\n        assert(!z->fixed_dig);\n        z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need);\n        z->alloc = need;\n    }\n}\n\nSTATIC mpz_t *mpz_clone(const mpz_t *src) {\n    assert(src->alloc != 0);\n    mpz_t *z = m_new_obj(mpz_t);\n    z->neg = src->neg;\n    z->fixed_dig = 0;\n    z->alloc = src->alloc;\n    z->len = src->len;\n    z->dig = m_new(mpz_dig_t, z->alloc);\n    memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t));\n    return z;\n}\n\n/* sets dest = src\n   can have dest, src the same\n*/\nvoid mpz_set(mpz_t *dest, const mpz_t *src) {\n    mpz_need_dig(dest, src->len);\n    dest->neg = src->neg;\n    dest->len = src->len;\n    memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));\n}\n\nvoid mpz_set_from_int(mpz_t *z, mp_int_t val) {\n    if (val == 0) {\n        z->len = 0;\n        return;\n    }\n\n    mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);\n\n    mp_uint_t uval;\n    if (val < 0) {\n        z->neg = 1;\n        uval = -val;\n    } else {\n        z->neg = 0;\n        uval = val;\n    }\n\n    z->len = 0;\n    while (uval > 0) {\n        z->dig[z->len++] = uval & DIG_MASK;\n        uval >>= DIG_SIZE;\n    }\n}\n\nvoid mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {\n    mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL);\n\n    unsigned long long uval;\n    if (is_signed && val < 0) {\n        z->neg = 1;\n        uval = -val;\n    } else {\n        z->neg = 0;\n        uval = val;\n    }\n\n    z->len = 0;\n    while (uval > 0) {\n        z->dig[z->len++] = uval & DIG_MASK;\n        uval >>= DIG_SIZE;\n    }\n}\n\n#if MICROPY_PY_BUILTINS_FLOAT\nvoid mpz_set_from_float(mpz_t *z, mp_float_t src) {\n    mp_float_union_t u = {src};\n    z->neg = u.p.sgn;\n    if (u.p.exp == 0) {\n        // value == 0 || value < 1\n        mpz_set_from_int(z, 0);\n    } else if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) {\n        // u.p.frc == 0 indicates inf, else NaN\n        // should be handled by caller\n        mpz_set_from_int(z, 0);\n    } else {\n        const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;\n        if (adj_exp < 0) {\n            // value < 1 , truncates to 0\n            mpz_set_from_int(z, 0);\n        } else if (adj_exp == 0) {\n            // 1 <= value < 2 , so truncates to 1\n            mpz_set_from_int(z, 1);\n        } else {\n            // 2 <= value\n            const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE;\n            const unsigned int rem = adj_exp % DIG_SIZE;\n            int dig_ind, shft;\n            mp_float_uint_t frc = u.p.frc | ((mp_float_uint_t)1 << MP_FLOAT_FRAC_BITS);\n\n            if (adj_exp < MP_FLOAT_FRAC_BITS) {\n                shft = 0;\n                dig_ind = 0;\n                frc >>= MP_FLOAT_FRAC_BITS - adj_exp;\n            } else {\n                shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE;\n                dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE;\n            }\n            mpz_need_dig(z, dig_cnt);\n            z->len = dig_cnt;\n            if (dig_ind != 0) {\n                memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t));\n            }\n            if (shft != 0) {\n                z->dig[dig_ind++] = (frc << shft) & DIG_MASK;\n                frc >>= DIG_SIZE - shft;\n            }\n            #if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1)\n            while (dig_ind != dig_cnt) {\n                z->dig[dig_ind++] = frc & DIG_MASK;\n                frc >>= DIG_SIZE;\n            }\n            #else\n            if (dig_ind != dig_cnt) {\n                z->dig[dig_ind] = frc;\n            }\n            #endif\n        }\n    }\n}\n#endif\n\n// returns number of bytes from str that were processed\nsize_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigned int base) {\n    assert(base <= 36);\n\n    const char *cur = str;\n    const char *top = str + len;\n\n    mpz_need_dig(z, len * 8 / DIG_SIZE + 1);\n\n    if (neg) {\n        z->neg = 1;\n    } else {\n        z->neg = 0;\n    }\n\n    z->len = 0;\n    for (; cur < top; ++cur) { // XXX UTF8 next char\n        // mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char\n        mp_uint_t v = *cur;\n        if ('0' <= v && v <= '9') {\n            v -= '0';\n        } else if ('A' <= v && v <= 'Z') {\n            v -= 'A' - 10;\n        } else if ('a' <= v && v <= 'z') {\n            v -= 'a' - 10;\n        } else {\n            break;\n        }\n        if (v >= base) {\n            break;\n        }\n        z->len = mpn_mul_dig_add_dig(z->dig, z->len, base, v);\n    }\n\n    return cur - str;\n}\n\nvoid mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf) {\n    int delta = 1;\n    if (big_endian) {\n        buf += len - 1;\n        delta = -1;\n    }\n\n    mpz_need_dig(z, (len * 8 + DIG_SIZE - 1) / DIG_SIZE);\n\n    mpz_dig_t d = 0;\n    int num_bits = 0;\n    z->neg = 0;\n    z->len = 0;\n    while (len) {\n        while (len && num_bits < DIG_SIZE) {\n            d |= *buf << num_bits;\n            num_bits += 8;\n            buf += delta;\n            len--;\n        }\n        z->dig[z->len++] = d & DIG_MASK;\n        // Need this #if because it's C undefined behavior to do: uint32_t >> 32\n        #if DIG_SIZE != 8 && DIG_SIZE != 16 && DIG_SIZE != 32\n        d >>= DIG_SIZE;\n        #else\n        d = 0;\n        #endif\n        num_bits -= DIG_SIZE;\n    }\n\n    z->len = mpn_remove_trailing_zeros(z->dig, z->dig + z->len);\n}\n\n#if 0\nthese functions are unused\n\nbool mpz_is_pos(const mpz_t *z) {\n    return z->len > 0 && z->neg == 0;\n}\n\nbool mpz_is_odd(const mpz_t *z) {\n    return z->len > 0 && (z->dig[0] & 1) != 0;\n}\n\nbool mpz_is_even(const mpz_t *z) {\n    return z->len == 0 || (z->dig[0] & 1) == 0;\n}\n#endif\n\nint mpz_cmp(const mpz_t *z1, const mpz_t *z2) {\n    // to catch comparison of -0 with +0\n    if (z1->len == 0 && z2->len == 0) {\n        return 0;\n    }\n    int cmp = (int)z2->neg - (int)z1->neg;\n    if (cmp != 0) {\n        return cmp;\n    }\n    cmp = mpn_cmp(z1->dig, z1->len, z2->dig, z2->len);\n    if (z1->neg != 0) {\n        cmp = -cmp;\n    }\n    return cmp;\n}\n\n#if 0\n// obsolete\n// compares mpz with an integer that fits within DIG_SIZE bits\nmp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {\n    mp_int_t cmp;\n    if (z->neg == 0) {\n        if (sml_int < 0) {\n            return 1;\n        }\n        if (sml_int == 0) {\n            if (z->len == 0) {\n                return 0;\n            }\n            return 1;\n        }\n        if (z->len == 0) {\n            return -1;\n        }\n        assert(sml_int < (1 << DIG_SIZE));\n        if (z->len != 1) {\n            return 1;\n        }\n        cmp = z->dig[0] - sml_int;\n    } else {\n        if (sml_int > 0) {\n            return -1;\n        }\n        if (sml_int == 0) {\n            if (z->len == 0) {\n                return 0;\n            }\n            return -1;\n        }\n        if (z->len == 0) {\n            return 1;\n        }\n        assert(sml_int > -(1 << DIG_SIZE));\n        if (z->len != 1) {\n            return -1;\n        }\n        cmp = -z->dig[0] - sml_int;\n    }\n    if (cmp < 0) {\n        return -1;\n    }\n    if (cmp > 0) {\n        return 1;\n    }\n    return 0;\n}\n#endif\n\n#if 0\nthese functions are unused\n\n/* returns abs(z)\n*/\nmpz_t *mpz_abs(const mpz_t *z) {\n    // TODO: handle case of z->alloc=0\n    mpz_t *z2 = mpz_clone(z);\n    z2->neg = 0;\n    return z2;\n}\n\n/* returns -z\n*/\nmpz_t *mpz_neg(const mpz_t *z) {\n    // TODO: handle case of z->alloc=0\n    mpz_t *z2 = mpz_clone(z);\n    z2->neg = 1 - z2->neg;\n    return z2;\n}\n\n/* returns lhs + rhs\n   can have lhs, rhs the same\n*/\nmpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs) {\n    mpz_t *z = mpz_zero();\n    mpz_add_inpl(z, lhs, rhs);\n    return z;\n}\n\n/* returns lhs - rhs\n   can have lhs, rhs the same\n*/\nmpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs) {\n    mpz_t *z = mpz_zero();\n    mpz_sub_inpl(z, lhs, rhs);\n    return z;\n}\n\n/* returns lhs * rhs\n   can have lhs, rhs the same\n*/\nmpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs) {\n    mpz_t *z = mpz_zero();\n    mpz_mul_inpl(z, lhs, rhs);\n    return z;\n}\n\n/* returns lhs ** rhs\n   can have lhs, rhs the same\n*/\nmpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) {\n    mpz_t *z = mpz_zero();\n    mpz_pow_inpl(z, lhs, rhs);\n    return z;\n}\n\n/* computes new integers in quo and rem such that:\n       quo * rhs + rem = lhs\n       0 <= rem < rhs\n   can have lhs, rhs the same\n*/\nvoid mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) {\n    *quo = mpz_zero();\n    *rem = mpz_zero();\n    mpz_divmod_inpl(*quo, *rem, lhs, rhs);\n}\n#endif\n\n/* computes dest = abs(z)\n   can have dest, z the same\n*/\nvoid mpz_abs_inpl(mpz_t *dest, const mpz_t *z) {\n    if (dest != z) {\n        mpz_set(dest, z);\n    }\n    dest->neg = 0;\n}\n\n/* computes dest = -z\n   can have dest, z the same\n*/\nvoid mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {\n    if (dest != z) {\n        mpz_set(dest, z);\n    }\n    dest->neg = 1 - dest->neg;\n}\n\n/* computes dest = ~z (= -z - 1)\n   can have dest, z the same\n*/\nvoid mpz_not_inpl(mpz_t *dest, const mpz_t *z) {\n    if (dest != z) {\n        mpz_set(dest, z);\n    }\n    if (dest->len == 0) {\n        mpz_need_dig(dest, 1);\n        dest->dig[0] = 1;\n        dest->len = 1;\n        dest->neg = 1;\n    } else if (dest->neg) {\n        dest->neg = 0;\n        mpz_dig_t k = 1;\n        dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1);\n    } else {\n        mpz_need_dig(dest, dest->len + 1);\n        mpz_dig_t k = 1;\n        dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1);\n        dest->neg = 1;\n    }\n}\n\n/* computes dest = lhs << rhs\n   can have dest, lhs the same\n*/\nvoid mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) {\n    if (lhs->len == 0 || rhs == 0) {\n        mpz_set(dest, lhs);\n    } else {\n        mpz_need_dig(dest, lhs->len + (rhs + DIG_SIZE - 1) / DIG_SIZE);\n        dest->len = mpn_shl(dest->dig, lhs->dig, lhs->len, rhs);\n        dest->neg = lhs->neg;\n    }\n}\n\n/* computes dest = lhs >> rhs\n   can have dest, lhs the same\n*/\nvoid mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) {\n    if (lhs->len == 0 || rhs == 0) {\n        mpz_set(dest, lhs);\n    } else {\n        mpz_need_dig(dest, lhs->len);\n        dest->len = mpn_shr(dest->dig, lhs->dig, lhs->len, rhs);\n        dest->neg = lhs->neg;\n        if (dest->neg) {\n            // arithmetic shift right, rounding to negative infinity\n            mp_uint_t n_whole = rhs / DIG_SIZE;\n            mp_uint_t n_part = rhs % DIG_SIZE;\n            mpz_dig_t round_up = 0;\n            for (size_t i = 0; i < lhs->len && i < n_whole; i++) {\n                if (lhs->dig[i] != 0) {\n                    round_up = 1;\n                    break;\n                }\n            }\n            if (n_whole < lhs->len && (lhs->dig[n_whole] & ((1 << n_part) - 1)) != 0) {\n                round_up = 1;\n            }\n            if (round_up) {\n                if (dest->len == 0) {\n                    // dest == 0, so need to add 1 by hand (answer will be -1)\n                    dest->dig[0] = 1;\n                    dest->len = 1;\n                } else {\n                    // dest > 0, so can use mpn_add to add 1\n                    dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);\n                }\n            }\n        }\n    }\n}\n\n/* computes dest = lhs + rhs\n   can have dest, lhs, rhs the same\n*/\nvoid mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {\n    if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {\n        const mpz_t *temp = lhs;\n        lhs = rhs;\n        rhs = temp;\n    }\n\n    if (lhs->neg == rhs->neg) {\n        mpz_need_dig(dest, lhs->len + 1);\n        dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);\n    } else {\n        mpz_need_dig(dest, lhs->len);\n        dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);\n    }\n\n    dest->neg = lhs->neg;\n}\n\n/* computes dest = lhs - rhs\n   can have dest, lhs, rhs the same\n*/\nvoid mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {\n    bool neg = false;\n\n    if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {\n        const mpz_t *temp = lhs;\n        lhs = rhs;\n        rhs = temp;\n        neg = true;\n    }\n\n    if (lhs->neg != rhs->neg) {\n        mpz_need_dig(dest, lhs->len + 1);\n        dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);\n    } else {\n        mpz_need_dig(dest, lhs->len);\n        dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);\n    }\n\n    if (neg) {\n        dest->neg = 1 - lhs->neg;\n    } else {\n        dest->neg = lhs->neg;\n    }\n}\n\n/* computes dest = lhs & rhs\n   can have dest, lhs, rhs the same\n*/\nvoid mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {\n    // make sure lhs has the most digits\n    if (lhs->len < rhs->len) {\n        const mpz_t *temp = lhs;\n        lhs = rhs;\n        rhs = temp;\n    }\n\n    #if MICROPY_OPT_MPZ_BITWISE\n\n    if ((0 == lhs->neg) && (0 == rhs->neg)) {\n        mpz_need_dig(dest, lhs->len);\n        dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len);\n        dest->neg = 0;\n    } else {\n        mpz_need_dig(dest, lhs->len + 1);\n        dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,\n            lhs->neg == rhs->neg, 0 != lhs->neg, 0 != rhs->neg);\n        dest->neg = lhs->neg & rhs->neg;\n    }\n\n    #else\n\n    mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));\n    dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,\n        (lhs->neg == rhs->neg) ? lhs->neg : 0, lhs->neg, rhs->neg);\n    dest->neg = lhs->neg & rhs->neg;\n\n    #endif\n}\n\n/* computes dest = lhs | rhs\n   can have dest, lhs, rhs the same\n*/\nvoid mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {\n    // make sure lhs has the most digits\n    if (lhs->len < rhs->len) {\n        const mpz_t *temp = lhs;\n        lhs = rhs;\n        rhs = temp;\n    }\n\n    #if MICROPY_OPT_MPZ_BITWISE\n\n    if ((0 == lhs->neg) && (0 == rhs->neg)) {\n        mpz_need_dig(dest, lhs->len);\n        dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);\n        dest->neg = 0;\n    } else {\n        mpz_need_dig(dest, lhs->len + 1);\n        dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,\n            0 != lhs->neg, 0 != rhs->neg);\n        dest->neg = 1;\n    }\n\n    #else\n\n    mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));\n    dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,\n        (lhs->neg || rhs->neg), lhs->neg, rhs->neg);\n    dest->neg = lhs->neg | rhs->neg;\n\n    #endif\n}\n\n/* computes dest = lhs ^ rhs\n   can have dest, lhs, rhs the same\n*/\nvoid mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {\n    // make sure lhs has the most digits\n    if (lhs->len < rhs->len) {\n        const mpz_t *temp = lhs;\n        lhs = rhs;\n        rhs = temp;\n    }\n\n    #if MICROPY_OPT_MPZ_BITWISE\n\n    if (lhs->neg == rhs->neg) {\n        mpz_need_dig(dest, lhs->len);\n        if (lhs->neg == 0) {\n            dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);\n        } else {\n            dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 0, 0, 0);\n        }\n        dest->neg = 0;\n    } else {\n        mpz_need_dig(dest, lhs->len + 1);\n        dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 1,\n            0 == lhs->neg, 0 == rhs->neg);\n        dest->neg = 1;\n    }\n\n    #else\n\n    mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));\n    dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,\n        (lhs->neg != rhs->neg), 0 == lhs->neg, 0 == rhs->neg);\n    dest->neg = lhs->neg ^ rhs->neg;\n\n    #endif\n}\n\n/* computes dest = lhs * rhs\n   can have dest, lhs, rhs the same\n*/\nvoid mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {\n    if (lhs->len == 0 || rhs->len == 0) {\n        mpz_set_from_int(dest, 0);\n        return;\n    }\n\n    mpz_t *temp = NULL;\n    if (lhs == dest) {\n        lhs = temp = mpz_clone(lhs);\n        if (rhs == dest) {\n            rhs = lhs;\n        }\n    } else if (rhs == dest) {\n        rhs = temp = mpz_clone(rhs);\n    }\n\n    mpz_need_dig(dest, lhs->len + rhs->len); // min mem l+r-1, max mem l+r\n    memset(dest->dig, 0, dest->alloc * sizeof(mpz_dig_t));\n    dest->len = mpn_mul(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);\n\n    if (lhs->neg == rhs->neg) {\n        dest->neg = 0;\n    } else {\n        dest->neg = 1;\n    }\n\n    mpz_free(temp);\n}\n\n/* computes dest = lhs ** rhs\n   can have dest, lhs, rhs the same\n*/\nvoid mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {\n    if (lhs->len == 0 || rhs->neg != 0) {\n        mpz_set_from_int(dest, 0);\n        return;\n    }\n\n    if (rhs->len == 0) {\n        mpz_set_from_int(dest, 1);\n        return;\n    }\n\n    mpz_t *x = mpz_clone(lhs);\n    mpz_t *n = mpz_clone(rhs);\n\n    mpz_set_from_int(dest, 1);\n\n    while (n->len > 0) {\n        if ((n->dig[0] & 1) != 0) {\n            mpz_mul_inpl(dest, dest, x);\n        }\n        n->len = mpn_shr(n->dig, n->dig, n->len, 1);\n        if (n->len == 0) {\n            break;\n        }\n        mpz_mul_inpl(x, x, x);\n    }\n\n    mpz_free(x);\n    mpz_free(n);\n}\n\n/* computes dest = (lhs ** rhs) % mod\n   can have dest, lhs, rhs the same; mod can't be the same as dest\n*/\nvoid mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) {\n    if (lhs->len == 0 || rhs->neg != 0 || (mod->len == 1 && mod->dig[0] == 1)) {\n        mpz_set_from_int(dest, 0);\n        return;\n    }\n\n    mpz_set_from_int(dest, 1);\n\n    if (rhs->len == 0) {\n        return;\n    }\n\n    mpz_t *x = mpz_clone(lhs);\n    mpz_t *n = mpz_clone(rhs);\n    mpz_t quo;\n    mpz_init_zero(&quo);\n\n    while (n->len > 0) {\n        if ((n->dig[0] & 1) != 0) {\n            mpz_mul_inpl(dest, dest, x);\n            mpz_divmod_inpl(&quo, dest, dest, mod);\n        }\n        n->len = mpn_shr(n->dig, n->dig, n->len, 1);\n        if (n->len == 0) {\n            break;\n        }\n        mpz_mul_inpl(x, x, x);\n        mpz_divmod_inpl(&quo, x, x, mod);\n    }\n\n    mpz_deinit(&quo);\n    mpz_free(x);\n    mpz_free(n);\n}\n\n#if 0\nthese functions are unused\n\n/* computes gcd(z1, z2)\n   based on Knuth's modified gcd algorithm (I think?)\n   gcd(z1, z2) >= 0\n   gcd(0, 0) = 0\n   gcd(z, 0) = abs(z)\n*/\nmpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {\n    if (z1->len == 0) {\n        // TODO: handle case of z2->alloc=0\n        mpz_t *a = mpz_clone(z2);\n        a->neg = 0;\n        return a;\n    } else if (z2->len == 0) {\n        mpz_t *a = mpz_clone(z1);\n        a->neg = 0;\n        return a;\n    }\n\n    mpz_t *a = mpz_clone(z1);\n    mpz_t *b = mpz_clone(z2);\n    mpz_t c;\n    mpz_init_zero(&c);\n    a->neg = 0;\n    b->neg = 0;\n\n    for (;;) {\n        if (mpz_cmp(a, b) < 0) {\n            if (a->len == 0) {\n                mpz_free(a);\n                mpz_deinit(&c);\n                return b;\n            }\n            mpz_t *t = a;\n            a = b;\n            b = t;\n        }\n        if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0\n            break;\n        }\n        mpz_set(&c, b);\n        do {\n            mpz_add_inpl(&c, &c, &c);\n        } while (mpz_cmp(&c, a) <= 0);\n        c.len = mpn_shr(c.dig, c.dig, c.len, 1);\n        mpz_sub_inpl(a, a, &c);\n    }\n\n    mpz_deinit(&c);\n\n    if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0\n        mpz_free(a);\n        return b;\n    } else {\n        mpz_free(b);\n        return a;\n    }\n}\n\n/* computes lcm(z1, z2)\n     = abs(z1) / gcd(z1, z2) * abs(z2)\n  lcm(z1, z1) >= 0\n  lcm(0, 0) = 0\n  lcm(z, 0) = 0\n*/\nmpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {\n    if (z1->len == 0 || z2->len == 0) {\n        return mpz_zero();\n    }\n\n    mpz_t *gcd = mpz_gcd(z1, z2);\n    mpz_t *quo = mpz_zero();\n    mpz_t *rem = mpz_zero();\n    mpz_divmod_inpl(quo, rem, z1, gcd);\n    mpz_mul_inpl(rem, quo, z2);\n    mpz_free(gcd);\n    mpz_free(quo);\n    rem->neg = 0;\n    return rem;\n}\n#endif\n\n/* computes new integers in quo and rem such that:\n       quo * rhs + rem = lhs\n       0 <= rem < rhs\n   can have lhs, rhs the same\n   assumes rhs != 0 (undefined behaviour if it is)\n*/\nvoid mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) {\n    assert(!mpz_is_zero(rhs));\n\n    mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?\n    memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));\n    dest_quo->len = 0;\n    mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?\n    mpz_set(dest_rem, lhs);\n    mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);\n\n    // check signs and do Python style modulo\n    if (lhs->neg != rhs->neg) {\n        dest_quo->neg = 1;\n        if (!mpz_is_zero(dest_rem)) {\n            mpz_t mpzone;\n            mpz_init_from_int(&mpzone, -1);\n            mpz_add_inpl(dest_quo, dest_quo, &mpzone);\n            mpz_add_inpl(dest_rem, dest_rem, rhs);\n        }\n    }\n}\n\n#if 0\nthese functions are unused\n\n/* computes floor(lhs / rhs)\n   can have lhs, rhs the same\n*/\nmpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {\n    mpz_t *quo = mpz_zero();\n    mpz_t rem;\n    mpz_init_zero(&rem);\n    mpz_divmod_inpl(quo, &rem, lhs, rhs);\n    mpz_deinit(&rem);\n    return quo;\n}\n\n/* computes lhs % rhs ( >= 0)\n   can have lhs, rhs the same\n*/\nmpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {\n    mpz_t quo;\n    mpz_init_zero(&quo);\n    mpz_t *rem = mpz_zero();\n    mpz_divmod_inpl(&quo, rem, lhs, rhs);\n    mpz_deinit(&quo);\n    return rem;\n}\n#endif\n\n// must return actual int value if it fits in mp_int_t\nmp_int_t mpz_hash(const mpz_t *z) {\n    mp_uint_t val = 0;\n    mpz_dig_t *d = z->dig + z->len;\n\n    while (d-- > z->dig) {\n        val = (val << DIG_SIZE) | *d;\n    }\n\n    if (z->neg != 0) {\n        val = -val;\n    }\n\n    return val;\n}\n\nbool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {\n    mp_uint_t val = 0;\n    mpz_dig_t *d = i->dig + i->len;\n\n    while (d-- > i->dig) {\n        if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {\n            // will overflow\n            return false;\n        }\n        val = (val << DIG_SIZE) | *d;\n    }\n\n    if (i->neg != 0) {\n        val = -val;\n    }\n\n    *value = val;\n    return true;\n}\n\nbool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {\n    if (i->neg != 0) {\n        // can't represent signed values\n        return false;\n    }\n\n    mp_uint_t val = 0;\n    mpz_dig_t *d = i->dig + i->len;\n\n    while (d-- > i->dig) {\n        if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {\n            // will overflow\n            return false;\n        }\n        val = (val << DIG_SIZE) | *d;\n    }\n\n    *value = val;\n    return true;\n}\n\n// writes at most len bytes to buf (so buf should be zeroed before calling)\nvoid mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf) {\n    byte *b = buf;\n    if (big_endian) {\n        b += len;\n    }\n    mpz_dig_t *zdig = z->dig;\n    int bits = 0;\n    mpz_dbl_dig_t d = 0;\n    mpz_dbl_dig_t carry = 1;\n    for (size_t zlen = z->len; zlen > 0; --zlen) {\n        bits += DIG_SIZE;\n        d = (d << DIG_SIZE) | *zdig++;\n        for (; bits >= 8; bits -= 8, d >>= 8) {\n            mpz_dig_t val = d;\n            if (z->neg) {\n                val = (~val & 0xff) + carry;\n                carry = val >> 8;\n            }\n            if (big_endian) {\n                *--b = val;\n                if (b == buf) {\n                    return;\n                }\n            } else {\n                *b++ = val;\n                if (b == buf + len) {\n                    return;\n                }\n            }\n        }\n    }\n}\n\n#if MICROPY_PY_BUILTINS_FLOAT\nmp_float_t mpz_as_float(const mpz_t *i) {\n    mp_float_t val = 0;\n    mpz_dig_t *d = i->dig + i->len;\n\n    while (d-- > i->dig) {\n        val = val * DIG_BASE + *d;\n    }\n\n    if (i->neg != 0) {\n        val = -val;\n    }\n\n    return val;\n}\n#endif\n\n#if 0\nthis function is unused\nchar *mpz_as_str(const mpz_t *i, unsigned int base) {\n    char *s = m_new(char, mp_int_format_size(mpz_max_num_bits(i), base, NULL, '\\0'));\n    mpz_as_str_inpl(i, base, NULL, 'a', '\\0', s);\n    return s;\n}\n#endif\n\n// assumes enough space in str as calculated by mp_int_format_size\n// base must be between 2 and 32 inclusive\n// returns length of string, not including null byte\nsize_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, char base_char, char comma, char *str) {\n    assert(str != NULL);\n    assert(2 <= base && base <= 32);\n\n    size_t ilen = i->len;\n\n    char *s = str;\n    if (ilen == 0) {\n        if (prefix) {\n            while (*prefix) {\n                *s++ = *prefix++;\n            }\n        }\n        *s++ = '0';\n        *s = '\\0';\n        return s - str;\n    }\n\n    // make a copy of mpz digits, so we can do the div/mod calculation\n    mpz_dig_t *dig = m_new(mpz_dig_t, ilen);\n    memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t));\n\n    // convert\n    char *last_comma = str;\n    bool done;\n    do {\n        mpz_dig_t *d = dig + ilen;\n        mpz_dbl_dig_t a = 0;\n\n        // compute next remainder\n        while (--d >= dig) {\n            a = (a << DIG_SIZE) | *d;\n            *d = a / base;\n            a %= base;\n        }\n\n        // convert to character\n        a += '0';\n        if (a > '9') {\n            a += base_char - '9' - 1;\n        }\n        *s++ = a;\n\n        // check if number is zero\n        done = true;\n        for (d = dig; d < dig + ilen; ++d) {\n            if (*d != 0) {\n                done = false;\n                break;\n            }\n        }\n        if (comma && (s - last_comma) == 3) {\n            *s++ = comma;\n            last_comma = s;\n        }\n    }\n    while (!done);\n\n    // free the copy of the digits array\n    m_del(mpz_dig_t, dig, ilen);\n\n    if (prefix) {\n        const char *p = &prefix[strlen(prefix)];\n        while (p > prefix) {\n            *s++ = *--p;\n        }\n    }\n    if (i->neg != 0) {\n        *s++ = '-';\n    }\n\n    // reverse string\n    for (char *u = str, *v = s - 1; u < v; ++u, --v) {\n        char temp = *u;\n        *u = *v;\n        *v = temp;\n    }\n\n    *s = '\\0'; // null termination\n\n    return s - str;\n}\n\n#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ\n"
  },
  {
    "path": "py/mpz.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_MPZ_H\n#define MICROPY_INCLUDED_PY_MPZ_H\n\n#include <stdint.h>\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n\n// This mpz module implements arbitrary precision integers.\n//\n// The storage for each digit is defined by mpz_dig_t.  The actual number of\n// bits in mpz_dig_t that are used is defined by MPZ_DIG_SIZE.  The machine must\n// also provide a type that is twice as wide as mpz_dig_t, in both signed and\n// unsigned versions.\n//\n// MPZ_DIG_SIZE can be between 4 and 8*sizeof(mpz_dig_t), but it makes most\n// sense to have it as large as possible.  If MPZ_DIG_SIZE is not already\n// defined then it is auto-detected below, depending on the machine.  The types\n// are then set based on the value of MPZ_DIG_SIZE (although they can be freely\n// changed so long as the constraints mentioned above are met).\n\n#ifndef MPZ_DIG_SIZE\n  #if defined(__x86_64__) || defined(_WIN64)\n// 64-bit machine, using 32-bit storage for digits\n    #define MPZ_DIG_SIZE (32)\n  #else\n// default: 32-bit machine, using 16-bit storage for digits\n    #define MPZ_DIG_SIZE (16)\n  #endif\n#endif\n\n#if MPZ_DIG_SIZE > 16\n#define MPZ_DBL_DIG_SIZE (64)\ntypedef uint32_t mpz_dig_t;\ntypedef uint64_t mpz_dbl_dig_t;\ntypedef int64_t mpz_dbl_dig_signed_t;\n#elif MPZ_DIG_SIZE > 8\n#define MPZ_DBL_DIG_SIZE (32)\ntypedef uint16_t mpz_dig_t;\ntypedef uint32_t mpz_dbl_dig_t;\ntypedef int32_t mpz_dbl_dig_signed_t;\n#elif MPZ_DIG_SIZE > 4\n#define MPZ_DBL_DIG_SIZE (16)\ntypedef uint8_t mpz_dig_t;\ntypedef uint16_t mpz_dbl_dig_t;\ntypedef int16_t mpz_dbl_dig_signed_t;\n#else\n#define MPZ_DBL_DIG_SIZE (8)\ntypedef uint8_t mpz_dig_t;\ntypedef uint8_t mpz_dbl_dig_t;\ntypedef int8_t mpz_dbl_dig_signed_t;\n#endif\n\n#ifdef _WIN64\n  #ifdef __MINGW32__\n    #define MPZ_LONG_1 1LL\n  #else\n    #define MPZ_LONG_1 1i64\n  #endif\n#else\n  #define MPZ_LONG_1 1L\n#endif\n\n// these define the maximum storage needed to hold an int or long long\n#define MPZ_NUM_DIG_FOR_INT ((sizeof(mp_int_t) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE)\n#define MPZ_NUM_DIG_FOR_LL ((sizeof(long long) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE)\n\ntypedef struct _mpz_t {\n    size_t neg : 1;\n    size_t fixed_dig : 1;\n    size_t alloc : (8 * sizeof(size_t) - 2);\n    size_t len;\n    mpz_dig_t *dig;\n} mpz_t;\n\n// convenience macro to declare an mpz with a digit array from the stack, initialised by an integer\n#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);\n\nvoid mpz_init_zero(mpz_t *z);\nvoid mpz_init_from_int(mpz_t *z, mp_int_t val);\nvoid mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, size_t dig_alloc, mp_int_t val);\nvoid mpz_deinit(mpz_t *z);\n\nvoid mpz_set(mpz_t *dest, const mpz_t *src);\nvoid mpz_set_from_int(mpz_t *z, mp_int_t src);\nvoid mpz_set_from_ll(mpz_t *z, long long i, bool is_signed);\n#if MICROPY_PY_BUILTINS_FLOAT\nvoid mpz_set_from_float(mpz_t *z, mp_float_t src);\n#endif\nsize_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigned int base);\nvoid mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf);\n\nstatic inline bool mpz_is_zero(const mpz_t *z) {\n    return z->len == 0;\n}\nstatic inline bool mpz_is_neg(const mpz_t *z) {\n    return z->len != 0 && z->neg != 0;\n}\nint mpz_cmp(const mpz_t *lhs, const mpz_t *rhs);\n\nvoid mpz_abs_inpl(mpz_t *dest, const mpz_t *z);\nvoid mpz_neg_inpl(mpz_t *dest, const mpz_t *z);\nvoid mpz_not_inpl(mpz_t *dest, const mpz_t *z);\nvoid mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs);\nvoid mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs);\nvoid mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);\nvoid mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);\nvoid mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);\nvoid mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);\nvoid mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod);\nvoid mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);\nvoid mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);\nvoid mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);\nvoid mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs);\n\nstatic inline size_t mpz_max_num_bits(const mpz_t *z) {\n    return z->len * MPZ_DIG_SIZE;\n}\nmp_int_t mpz_hash(const mpz_t *z);\nbool mpz_as_int_checked(const mpz_t *z, mp_int_t *value);\nbool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value);\nvoid mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf);\n#if MICROPY_PY_BUILTINS_FLOAT\nmp_float_t mpz_as_float(const mpz_t *z);\n#endif\nsize_t mpz_as_str_inpl(const mpz_t *z, unsigned int base, const char *prefix, char base_char, char comma, char *str);\n\n#endif // MICROPY_INCLUDED_PY_MPZ_H\n"
  },
  {
    "path": "py/nativeglue.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdarg.h>\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n#include \"py/smallint.h\"\n#include \"py/nativeglue.h\"\n#include \"py/gc.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_printf DEBUG_printf\n#else // don't print debugging info\n#define DEBUG_printf(...) (void)0\n#endif\n\n#if MICROPY_EMIT_NATIVE\n\nint mp_native_type_from_qstr(qstr qst) {\n    switch (qst) {\n        case MP_QSTR_object:\n            return MP_NATIVE_TYPE_OBJ;\n        case MP_QSTR_bool:\n            return MP_NATIVE_TYPE_BOOL;\n        case MP_QSTR_int:\n            return MP_NATIVE_TYPE_INT;\n        case MP_QSTR_uint:\n            return MP_NATIVE_TYPE_UINT;\n        case MP_QSTR_ptr:\n            return MP_NATIVE_TYPE_PTR;\n        case MP_QSTR_ptr8:\n            return MP_NATIVE_TYPE_PTR8;\n        case MP_QSTR_ptr16:\n            return MP_NATIVE_TYPE_PTR16;\n        case MP_QSTR_ptr32:\n            return MP_NATIVE_TYPE_PTR32;\n        default:\n            return -1;\n    }\n}\n\n// convert a MicroPython object to a valid native value based on type\nmp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) {\n    DEBUG_printf(\"mp_native_from_obj(%p, \" UINT_FMT \")\\n\", obj, type);\n    switch (type & 0xf) {\n        case MP_NATIVE_TYPE_OBJ:\n            return (mp_uint_t)obj;\n        case MP_NATIVE_TYPE_BOOL:\n            return mp_obj_is_true(obj);\n        case MP_NATIVE_TYPE_INT:\n        case MP_NATIVE_TYPE_UINT:\n            return mp_obj_get_int_truncated(obj);\n        default: { // cast obj to a pointer\n            mp_buffer_info_t bufinfo;\n            if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_READ)) {\n                return (mp_uint_t)bufinfo.buf;\n            } else {\n                // assume obj is an integer that represents an address\n                return mp_obj_get_int_truncated(obj);\n            }\n        }\n    }\n}\n\n#endif\n\n#if MICROPY_EMIT_MACHINE_CODE\n\n// convert a native value to a MicroPython object based on type\nmp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) {\n    DEBUG_printf(\"mp_native_to_obj(\" UINT_FMT \", \" UINT_FMT \")\\n\", val, type);\n    switch (type & 0xf) {\n        case MP_NATIVE_TYPE_OBJ:\n            return (mp_obj_t)val;\n        case MP_NATIVE_TYPE_BOOL:\n            return mp_obj_new_bool(val);\n        case MP_NATIVE_TYPE_INT:\n            return mp_obj_new_int(val);\n        case MP_NATIVE_TYPE_UINT:\n            return mp_obj_new_int_from_uint(val);\n        default: // a pointer\n            // we return just the value of the pointer as an integer\n            return mp_obj_new_int_from_uint(val);\n    }\n}\n\n#endif\n\n#if MICROPY_EMIT_NATIVE && !MICROPY_DYNAMIC_COMPILER\n\n#if !MICROPY_PY_BUILTINS_SET\nmp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) {\n    (void)n_args;\n    (void)items;\n    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"set unsupported\"));\n}\n\nvoid mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) {\n    (void)self_in;\n    (void)item;\n    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"set unsupported\"));\n}\n#endif\n\n#if !MICROPY_PY_BUILTINS_SLICE\nmp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) {\n    (void)ostart;\n    (void)ostop;\n    (void)ostep;\n    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"slice unsupported\"));\n}\n#endif\n\nSTATIC mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals) {\n    if (new_globals == NULL) {\n        // Globals were the originally the same so don't restore them\n        return NULL;\n    }\n    mp_obj_dict_t *old_globals = mp_globals_get();\n    if (old_globals == new_globals) {\n        // Don't set globals if they are the same, and return NULL to indicate this\n        return NULL;\n    }\n    mp_globals_set(new_globals);\n    return old_globals;\n}\n\n// wrapper that accepts n_args and n_kw in one argument\n// (native emitter can only pass at most 3 arguments to a function)\nSTATIC mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args) {\n    return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args);\n}\n\n// wrapper that makes raise obj and raises it\n// END_FINALLY opcode requires that we don't raise if o==None\nSTATIC void mp_native_raise(mp_obj_t o) {\n    if (o != MP_OBJ_NULL && o != mp_const_none) {\n        nlr_raise(mp_make_raise_obj(o));\n    }\n}\n\n// wrapper that handles iterator buffer\nSTATIC mp_obj_t mp_native_getiter(mp_obj_t obj, mp_obj_iter_buf_t *iter) {\n    if (iter == NULL) {\n        return mp_getiter(obj, NULL);\n    } else {\n        obj = mp_getiter(obj, iter);\n        if (obj != MP_OBJ_FROM_PTR(iter)) {\n            // Iterator didn't use the stack so indicate that with MP_OBJ_NULL.\n            iter->base.type = MP_OBJ_NULL;\n            iter->buf[0] = obj;\n        }\n        return NULL;\n    }\n}\n\n// wrapper that handles iterator buffer\nSTATIC mp_obj_t mp_native_iternext(mp_obj_iter_buf_t *iter) {\n    mp_obj_t obj;\n    if (iter->base.type == MP_OBJ_NULL) {\n        obj = iter->buf[0];\n    } else {\n        obj = MP_OBJ_FROM_PTR(iter);\n    }\n    return mp_iternext(obj);\n}\n\nSTATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *ret_value) {\n    mp_vm_return_kind_t ret_kind;\n    nlr_buf_t nlr_buf;\n    mp_obj_t throw_value = *ret_value;\n    if (nlr_push(&nlr_buf) == 0) {\n        if (throw_value != MP_OBJ_NULL) {\n            send_value = MP_OBJ_NULL;\n        }\n        ret_kind = mp_resume(gen, send_value, throw_value, ret_value);\n        nlr_pop();\n    } else {\n        ret_kind = MP_VM_RETURN_EXCEPTION;\n        *ret_value = nlr_buf.ret_val;\n    }\n\n    if (ret_kind == MP_VM_RETURN_YIELD) {\n        return true;\n    } else if (ret_kind == MP_VM_RETURN_NORMAL) {\n        if (*ret_value == MP_OBJ_STOP_ITERATION) {\n            *ret_value = mp_const_none;\n        }\n    } else {\n        assert(ret_kind == MP_VM_RETURN_EXCEPTION);\n        if (!mp_obj_exception_match(*ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) {\n            nlr_raise(*ret_value);\n        }\n        *ret_value = mp_obj_exception_get_value(*ret_value);\n    }\n\n    if (throw_value != MP_OBJ_NULL && mp_obj_exception_match(throw_value, MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) {\n        nlr_raise(mp_make_raise_obj(throw_value));\n    }\n\n    return false;\n}\n\n#if !MICROPY_PY_BUILTINS_FLOAT\n\nSTATIC mp_obj_t mp_obj_new_float_from_f(float f) {\n    (void)f;\n    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"float unsupported\"));\n}\n\nSTATIC mp_obj_t mp_obj_new_float_from_d(double d) {\n    (void)d;\n    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"float unsupported\"));\n}\n\nSTATIC float mp_obj_get_float_to_f(mp_obj_t o) {\n    (void)o;\n    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"float unsupported\"));\n}\n\nSTATIC double mp_obj_get_float_to_d(mp_obj_t o) {\n    (void)o;\n    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"float unsupported\"));\n}\n\n#endif\n\n// these must correspond to the respective enum in nativeglue.h\nconst mp_fun_table_t mp_fun_table = {\n    mp_const_none,\n    mp_const_false,\n    mp_const_true,\n    mp_native_from_obj,\n    mp_native_to_obj,\n    mp_native_swap_globals,\n    mp_load_name,\n    mp_load_global,\n    mp_load_build_class,\n    mp_load_attr,\n    mp_load_method,\n    mp_load_super_method,\n    mp_store_name,\n    mp_store_global,\n    mp_store_attr,\n    mp_obj_subscr,\n    mp_obj_is_true,\n    mp_unary_op,\n    mp_binary_op,\n    mp_obj_new_tuple,\n    mp_obj_new_list,\n    mp_obj_new_dict,\n    mp_obj_new_set,\n    mp_obj_set_store,\n    mp_obj_list_append,\n    mp_obj_dict_store,\n    mp_make_function_from_raw_code,\n    mp_native_call_function_n_kw,\n    mp_call_method_n_kw,\n    mp_call_method_n_kw_var,\n    mp_native_getiter,\n    mp_native_iternext,\n    #if MICROPY_NLR_SETJMP\n    nlr_push_tail,\n    #else\n    nlr_push,\n    #endif\n    nlr_pop,\n    mp_native_raise,\n    mp_import_name,\n    mp_import_from,\n    mp_import_all,\n    mp_obj_new_slice,\n    mp_unpack_sequence,\n    mp_unpack_ex,\n    mp_delete_name,\n    mp_delete_global,\n    mp_make_closure_from_raw_code,\n    mp_arg_check_num_sig,\n    mp_setup_code_state,\n    mp_small_int_floor_divide,\n    mp_small_int_modulo,\n    mp_native_yield_from,\n    #if MICROPY_NLR_SETJMP\n    setjmp,\n    #else\n    NULL,\n    #endif\n    // Additional entries for dynamic runtime, starts at index 50\n    memset,\n    memmove,\n    gc_realloc,\n    mp_printf,\n    mp_vprintf,\n    mp_raise_msg,\n    mp_obj_get_type,\n    mp_obj_new_str,\n    mp_obj_new_bytes,\n    mp_obj_new_bytearray_by_ref,\n    mp_obj_new_float_from_f,\n    mp_obj_new_float_from_d,\n    mp_obj_get_float_to_f,\n    mp_obj_get_float_to_d,\n    mp_get_buffer_raise,\n    mp_get_stream_raise,\n    &mp_plat_print,\n    &mp_type_type,\n    &mp_type_str,\n    &mp_type_list,\n    &mp_type_dict,\n    &mp_type_fun_builtin_0,\n    &mp_type_fun_builtin_1,\n    &mp_type_fun_builtin_2,\n    &mp_type_fun_builtin_3,\n    &mp_type_fun_builtin_var,\n    &mp_stream_read_obj,\n    &mp_stream_readinto_obj,\n    &mp_stream_unbuffered_readline_obj,\n    &mp_stream_write_obj,\n};\n\n#endif // MICROPY_EMIT_NATIVE\n"
  },
  {
    "path": "py/nativeglue.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2019 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_NATIVEGLUE_H\n#define MICROPY_INCLUDED_PY_NATIVEGLUE_H\n\n#include <stdarg.h>\n#include \"py/obj.h\"\n#include \"py/persistentcode.h\"\n#include \"py/stream.h\"\n\ntypedef enum {\n    MP_F_CONST_NONE_OBJ = 0,\n    MP_F_CONST_FALSE_OBJ,\n    MP_F_CONST_TRUE_OBJ,\n    MP_F_CONVERT_OBJ_TO_NATIVE,\n    MP_F_CONVERT_NATIVE_TO_OBJ,\n    MP_F_NATIVE_SWAP_GLOBALS,\n    MP_F_LOAD_NAME,\n    MP_F_LOAD_GLOBAL,\n    MP_F_LOAD_BUILD_CLASS,\n    MP_F_LOAD_ATTR,\n    MP_F_LOAD_METHOD,\n    MP_F_LOAD_SUPER_METHOD,\n    MP_F_STORE_NAME,\n    MP_F_STORE_GLOBAL,\n    MP_F_STORE_ATTR,\n    MP_F_OBJ_SUBSCR,\n    MP_F_OBJ_IS_TRUE,\n    MP_F_UNARY_OP,\n    MP_F_BINARY_OP,\n    MP_F_BUILD_TUPLE,\n    MP_F_BUILD_LIST,\n    MP_F_BUILD_MAP,\n    MP_F_BUILD_SET,\n    MP_F_STORE_SET,\n    MP_F_LIST_APPEND,\n    MP_F_STORE_MAP,\n    MP_F_MAKE_FUNCTION_FROM_RAW_CODE,\n    MP_F_NATIVE_CALL_FUNCTION_N_KW,\n    MP_F_CALL_METHOD_N_KW,\n    MP_F_CALL_METHOD_N_KW_VAR,\n    MP_F_NATIVE_GETITER,\n    MP_F_NATIVE_ITERNEXT,\n    MP_F_NLR_PUSH,\n    MP_F_NLR_POP,\n    MP_F_NATIVE_RAISE,\n    MP_F_IMPORT_NAME,\n    MP_F_IMPORT_FROM,\n    MP_F_IMPORT_ALL,\n    MP_F_NEW_SLICE,\n    MP_F_UNPACK_SEQUENCE,\n    MP_F_UNPACK_EX,\n    MP_F_DELETE_NAME,\n    MP_F_DELETE_GLOBAL,\n    MP_F_MAKE_CLOSURE_FROM_RAW_CODE,\n    MP_F_ARG_CHECK_NUM_SIG,\n    MP_F_SETUP_CODE_STATE,\n    MP_F_SMALL_INT_FLOOR_DIVIDE,\n    MP_F_SMALL_INT_MODULO,\n    MP_F_NATIVE_YIELD_FROM,\n    MP_F_SETJMP,\n    MP_F_NUMBER_OF,\n} mp_fun_kind_t;\n\ntypedef struct _mp_fun_table_t {\n    mp_const_obj_t const_none;\n    mp_const_obj_t const_false;\n    mp_const_obj_t const_true;\n    mp_uint_t (*native_from_obj)(mp_obj_t obj, mp_uint_t type);\n    mp_obj_t (*native_to_obj)(mp_uint_t val, mp_uint_t type);\n    mp_obj_dict_t *(*swap_globals)(mp_obj_dict_t * new_globals);\n    mp_obj_t (*load_name)(qstr qst);\n    mp_obj_t (*load_global)(qstr qst);\n    mp_obj_t (*load_build_class)(void);\n    mp_obj_t (*load_attr)(mp_obj_t base, qstr attr);\n    void (*load_method)(mp_obj_t base, qstr attr, mp_obj_t *dest);\n    void (*load_super_method)(qstr attr, mp_obj_t *dest);\n    void (*store_name)(qstr qst, mp_obj_t obj);\n    void (*store_global)(qstr qst, mp_obj_t obj);\n    void (*store_attr)(mp_obj_t base, qstr attr, mp_obj_t val);\n    mp_obj_t (*obj_subscr)(mp_obj_t base, mp_obj_t index, mp_obj_t val);\n    bool (*obj_is_true)(mp_obj_t arg);\n    mp_obj_t (*unary_op)(mp_unary_op_t op, mp_obj_t arg);\n    mp_obj_t (*binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs);\n    mp_obj_t (*new_tuple)(size_t n, const mp_obj_t *items);\n    mp_obj_t (*new_list)(size_t n, mp_obj_t *items);\n    mp_obj_t (*new_dict)(size_t n_args);\n    mp_obj_t (*new_set)(size_t n_args, mp_obj_t *items);\n    void (*set_store)(mp_obj_t self_in, mp_obj_t item);\n    mp_obj_t (*list_append)(mp_obj_t self_in, mp_obj_t arg);\n    mp_obj_t (*dict_store)(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);\n    mp_obj_t (*make_function_from_raw_code)(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);\n    mp_obj_t (*call_function_n_kw)(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args);\n    mp_obj_t (*call_method_n_kw)(size_t n_args, size_t n_kw, const mp_obj_t *args);\n    mp_obj_t (*call_method_n_kw_var)(bool have_self, size_t n_args_n_kw, const mp_obj_t *args);\n    mp_obj_t (*getiter)(mp_obj_t obj, mp_obj_iter_buf_t *iter);\n    mp_obj_t (*iternext)(mp_obj_iter_buf_t *iter);\n    unsigned int (*nlr_push)(nlr_buf_t *);\n    void (*nlr_pop)(void);\n    void (*raise)(mp_obj_t o);\n    mp_obj_t (*import_name)(qstr name, mp_obj_t fromlist, mp_obj_t level);\n    mp_obj_t (*import_from)(mp_obj_t module, qstr name);\n    void (*import_all)(mp_obj_t module);\n    mp_obj_t (*new_slice)(mp_obj_t start, mp_obj_t stop, mp_obj_t step);\n    void (*unpack_sequence)(mp_obj_t seq, size_t num, mp_obj_t *items);\n    void (*unpack_ex)(mp_obj_t seq, size_t num, mp_obj_t *items);\n    void (*delete_name)(qstr qst);\n    void (*delete_global)(qstr qst);\n    mp_obj_t (*make_closure_from_raw_code)(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);\n    void (*arg_check_num_sig)(size_t n_args, size_t n_kw, uint32_t sig);\n    void (*setup_code_state)(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args);\n    mp_int_t (*small_int_floor_divide)(mp_int_t num, mp_int_t denom);\n    mp_int_t (*small_int_modulo)(mp_int_t dividend, mp_int_t divisor);\n    bool (*yield_from)(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *ret_value);\n    void *setjmp_;\n    // Additional entries for dynamic runtime, starts at index 50\n    void *(*memset_)(void *s, int c, size_t n);\n    void *(*memmove_)(void *dest, const void *src, size_t n);\n    void *(*realloc_)(void *ptr, size_t n_bytes, bool allow_move);\n    int (*printf_)(const mp_print_t *print, const char *fmt, ...);\n    int (*vprintf_)(const mp_print_t *print, const char *fmt, va_list args);\n    #if defined(__GNUC__)\n    NORETURN // Only certain compilers support no-return attributes in function pointer declarations\n    #endif\n    void (*raise_msg)(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg);\n    const mp_obj_type_t *(*obj_get_type)(mp_const_obj_t o_in);\n    mp_obj_t (*obj_new_str)(const char *data, size_t len);\n    mp_obj_t (*obj_new_bytes)(const byte *data, size_t len);\n    mp_obj_t (*obj_new_bytearray_by_ref)(size_t n, void *items);\n    mp_obj_t (*obj_new_float_from_f)(float f);\n    mp_obj_t (*obj_new_float_from_d)(double d);\n    float (*obj_get_float_to_f)(mp_obj_t o);\n    double (*obj_get_float_to_d)(mp_obj_t o);\n    void (*get_buffer_raise)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);\n    const mp_stream_p_t *(*get_stream_raise)(mp_obj_t self_in, int flags);\n    const mp_print_t *plat_print;\n    const mp_obj_type_t *type_type;\n    const mp_obj_type_t *type_str;\n    const mp_obj_type_t *type_list;\n    const mp_obj_type_t *type_dict;\n    const mp_obj_type_t *type_fun_builtin_0;\n    const mp_obj_type_t *type_fun_builtin_1;\n    const mp_obj_type_t *type_fun_builtin_2;\n    const mp_obj_type_t *type_fun_builtin_3;\n    const mp_obj_type_t *type_fun_builtin_var;\n    const mp_obj_fun_builtin_var_t *stream_read_obj;\n    const mp_obj_fun_builtin_var_t *stream_readinto_obj;\n    const mp_obj_fun_builtin_var_t *stream_unbuffered_readline_obj;\n    const mp_obj_fun_builtin_var_t *stream_write_obj;\n} mp_fun_table_t;\n\nextern const mp_fun_table_t mp_fun_table;\n\n#endif // MICROPY_INCLUDED_PY_NATIVEGLUE_H\n"
  },
  {
    "path": "py/nlr.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpstate.h\"\n\n#if !MICROPY_NLR_SETJMP\n// When not using setjmp, nlr_push_tail is called from inline asm so needs special care\n#if MICROPY_NLR_X86 && MICROPY_NLR_OS_WINDOWS\n// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading underscore\nunsigned int nlr_push_tail(nlr_buf_t *nlr) asm (\"nlr_push_tail\");\n#else\n// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as used\n__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);\n#endif\n#endif\n\nunsigned int nlr_push_tail(nlr_buf_t *nlr) {\n    nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);\n    nlr->prev = *top;\n    MP_NLR_SAVE_PYSTACK(nlr);\n    *top = nlr;\n    return 0; // normal return\n}\n\nvoid nlr_pop(void) {\n    nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);\n    *top = (*top)->prev;\n}\n"
  },
  {
    "path": "py/nlr.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_NLR_H\n#define MICROPY_INCLUDED_PY_NLR_H\n\n// non-local return\n// exception handling, basically a stack of setjmp/longjmp buffers\n\n#include <limits.h>\n#include <assert.h>\n\n#include \"py/mpconfig.h\"\n\n#define MICROPY_NLR_NUM_REGS_X86            (6)\n#define MICROPY_NLR_NUM_REGS_X64            (8)\n#define MICROPY_NLR_NUM_REGS_X64_WIN        (10)\n#define MICROPY_NLR_NUM_REGS_ARM_THUMB      (10)\n#define MICROPY_NLR_NUM_REGS_ARM_THUMB_FP   (10 + 6)\n#define MICROPY_NLR_NUM_REGS_XTENSA         (10)\n#define MICROPY_NLR_NUM_REGS_XTENSAWIN      (17)\n\n// *FORMAT-OFF*\n\n// If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch\n#if !MICROPY_NLR_SETJMP\n// A lot of nlr-related things need different treatment on Windows\n#if defined(_WIN32) || defined(__CYGWIN__)\n#define MICROPY_NLR_OS_WINDOWS 1\n#else\n#define MICROPY_NLR_OS_WINDOWS 0\n#endif\n#if defined(__i386__)\n    #define MICROPY_NLR_X86 (1)\n    #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X86)\n#elif defined(__x86_64__)\n    #define MICROPY_NLR_X64 (1)\n    #if MICROPY_NLR_OS_WINDOWS\n        #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X64_WIN)\n    #else\n        #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X64)\n    #endif\n#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)\n    #define MICROPY_NLR_THUMB (1)\n    #if defined(__SOFTFP__)\n        #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_ARM_THUMB)\n    #else\n        // With hardware FP registers s16-s31 are callee save so in principle\n        // should be saved and restored by the NLR code.  gcc only uses s16-s21\n        // so only save/restore those as an optimisation.\n        #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_ARM_THUMB_FP)\n    #endif\n#elif defined(__xtensa__)\n    #define MICROPY_NLR_XTENSA (1)\n    #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_XTENSA)\n#elif defined(__powerpc__)\n    #define MICROPY_NLR_POWERPC (1)\n    // this could be less but using 128 for safety\n    #define MICROPY_NLR_NUM_REGS (128)\n#else\n    #define MICROPY_NLR_SETJMP (1)\n    //#warning \"No native NLR support for this arch, using setjmp implementation\"\n#endif\n#endif\n\n// *FORMAT-ON*\n\n#if MICROPY_NLR_SETJMP\n#include <setjmp.h>\n#endif\n\ntypedef struct _nlr_buf_t nlr_buf_t;\nstruct _nlr_buf_t {\n    // the entries here must all be machine word size\n    nlr_buf_t *prev;\n    void *ret_val; // always a concrete object (an exception instance)\n\n    #if MICROPY_NLR_SETJMP\n    jmp_buf jmpbuf;\n    #else\n    void *regs[MICROPY_NLR_NUM_REGS];\n    #endif\n\n    #if MICROPY_ENABLE_PYSTACK\n    void *pystack;\n    #endif\n};\n\n// Helper macros to save/restore the pystack state\n#if MICROPY_ENABLE_PYSTACK\n#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur)\n#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack\n#else\n#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf\n#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf\n#endif\n\n// Helper macro to use at the start of a specific nlr_jump implementation\n#define MP_NLR_JUMP_HEAD(val, top) \\\n    nlr_buf_t **_top_ptr = &MP_STATE_THREAD(nlr_top); \\\n    nlr_buf_t *top = *_top_ptr; \\\n    if (top == NULL) { \\\n        nlr_jump_fail(val); \\\n    } \\\n    top->ret_val = val; \\\n    MP_NLR_RESTORE_PYSTACK(top); \\\n    *_top_ptr = top->prev; \\\n\n#if MICROPY_NLR_SETJMP\n// nlr_push() must be defined as a macro, because \"The stack context will be\n// invalidated if the function which called setjmp() returns.\"\n// For this case it is safe to call nlr_push_tail() first.\n#define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf))\n#else\nunsigned int nlr_push(nlr_buf_t *);\n#endif\n\nunsigned int nlr_push_tail(nlr_buf_t *top);\nvoid nlr_pop(void);\nNORETURN void nlr_jump(void *val);\n\n// This must be implemented by a port.  It's called by nlr_jump\n// if no nlr buf has been pushed.  It must not return, but rather\n// should bail out with a fatal error.\nNORETURN void nlr_jump_fail(void *val);\n\n// use nlr_raise instead of nlr_jump so that debugging is easier\n#ifndef MICROPY_DEBUG_NLR\n#define nlr_raise(val) nlr_jump(MP_OBJ_TO_PTR(val))\n#else\n#include \"mpstate.h\"\n#define nlr_raise(val) \\\n    do { \\\n        /*printf(\"nlr_raise: nlr_top=%p\\n\", MP_STATE_THREAD(nlr_top)); \\\n        fflush(stdout);*/ \\\n        void *_val = MP_OBJ_TO_PTR(val); \\\n        assert(_val != NULL); \\\n        assert(mp_obj_is_exception_instance(val)); \\\n        nlr_jump(_val); \\\n    } while (0)\n\n#if !MICROPY_NLR_SETJMP\n#define nlr_push(val) \\\n    assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val)\n\n/*\n#define nlr_push(val) \\\n    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)\n*/\n#endif\n\n#endif\n\n#endif // MICROPY_INCLUDED_PY_NLR_H\n"
  },
  {
    "path": "py/nlrpowerpc.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019, Michael Neuling, IBM Corporation.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpstate.h\"\n\n#if MICROPY_NLR_POWERPC\n\n#undef nlr_push\n\n// Saving all ABI non-vol registers here\n\nunsigned int nlr_push(nlr_buf_t *nlr) {\n\n    __asm__ volatile (\n        \"li     4, 0x4eed ; \"  // Store canary\n        \"std    4,  0x00(%0) ;\"\n        \"std    0,  0x08(%0) ;\"\n        \"std    1,  0x10(%0) ;\"\n        \"std    2,  0x18(%0) ;\"\n        \"std    14, 0x20(%0) ;\"\n        \"std    15, 0x28(%0) ;\"\n        \"std    16, 0x30(%0) ;\"\n        \"std    17, 0x38(%0) ;\"\n        \"std    18, 0x40(%0) ;\"\n        \"std    19, 0x48(%0) ;\"\n        \"std    20, 0x50(%0) ;\"\n        \"std    21, 0x58(%0) ;\"\n        \"std    22, 0x60(%0) ;\"\n        \"std    23, 0x68(%0) ;\"\n        \"std    24, 0x70(%0) ;\"\n        \"std    25, 0x78(%0) ;\"\n        \"std    26, 0x80(%0) ;\"\n        \"std    27, 0x88(%0) ;\"\n        \"std    28, 0x90(%0) ;\"\n        \"std    29, 0x98(%0) ;\"\n        \"std    30, 0xA0(%0) ;\"\n        \"std    31, 0xA8(%0) ;\"\n\n        \"mfcr   4 ; \"\n        \"std    4, 0xB0(%0) ;\"\n        \"mflr   4 ;\"\n        \"std    4, 0xB8(%0) ;\"\n        \"li     4, nlr_push_tail@l ;\"\n        \"oris   4, 4, nlr_push_tail@h ;\"\n        \"mtctr  4 ;\"\n        \"mr    3, %1 ; \"\n        \"bctr  ;\"\n        :\n        : \"r\" (&nlr->regs), \"r\" (nlr)\n        :\n        );\n\n    return 0;\n}\n\nNORETURN void nlr_jump(void *val) {\n    MP_NLR_JUMP_HEAD(val, top)\n\n    __asm__ volatile (\n        \"ld    3, 0x0(%0) ;\"\n        \"cmpdi 3, 0x4eed ; \" // Check canary\n        \"bne   . ; \"\n        \"ld    0,  0x08(%0) ;\"\n        \"ld    1,  0x10(%0) ;\"\n        \"ld    2,  0x18(%0) ;\"\n        \"ld    14, 0x20(%0) ;\"\n        \"ld    15, 0x28(%0) ;\"\n        \"ld    16, 0x30(%0) ;\"\n        \"ld    17, 0x38(%0) ;\"\n        \"ld    18, 0x40(%0) ;\"\n        \"ld    19, 0x48(%0) ;\"\n        \"ld    20, 0x50(%0) ;\"\n        \"ld    21, 0x58(%0) ;\"\n        \"ld    22, 0x60(%0) ;\"\n        \"ld    23, 0x68(%0) ;\"\n        \"ld    24, 0x70(%0) ;\"\n        \"ld    25, 0x78(%0) ;\"\n        \"ld    26, 0x80(%0) ;\"\n        \"ld    27, 0x88(%0) ;\"\n        \"ld    28, 0x90(%0) ;\"\n        \"ld    29, 0x98(%0) ;\"\n        \"ld    30, 0xA0(%0) ;\"\n        \"ld    31, 0xA8(%0) ;\"\n        \"ld    3,  0xB0(%0) ;\"\n        \"mtcr  3 ;\"\n        \"ld    3, 0xB8(%0) ;\"\n        \"mtlr  3 ; \"\n        \"li    3, 1;\"\n        \"blr ;\"\n        :\n        : \"r\" (&top->regs)\n        :\n        );\n\n    MP_UNREACHABLE;\n}\n\n#endif // MICROPY_NLR_POWERPC\n"
  },
  {
    "path": "py/nlrsetjmp.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpstate.h\"\n\n#if MICROPY_NLR_SETJMP\n\nvoid nlr_jump(void *val) {\n    nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);\n    nlr_buf_t *top = *top_ptr;\n    if (top == NULL) {\n        nlr_jump_fail(val);\n    }\n    top->ret_val = val;\n    MP_NLR_RESTORE_PYSTACK(top);\n    *top_ptr = top->prev;\n    longjmp(top->jmpbuf, 1);\n}\n\n#endif\n"
  },
  {
    "path": "py/nlrthumb.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpstate.h\"\n\n#if MICROPY_NLR_THUMB\n\n#undef nlr_push\n\n// We only need the functions here if we are on arm/thumb, and we are not\n// using setjmp/longjmp.\n//\n// For reference, arm/thumb callee save regs are:\n//      r4-r11, r13=sp\n\n__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {\n\n    __asm volatile (\n        \"str    r4, [r0, #12]       \\n\" // store r4 into nlr_buf\n        \"str    r5, [r0, #16]       \\n\" // store r5 into nlr_buf\n        \"str    r6, [r0, #20]       \\n\" // store r6 into nlr_buf\n        \"str    r7, [r0, #24]       \\n\" // store r7 into nlr_buf\n\n        #if !defined(__thumb2__)\n        \"mov    r1, r8              \\n\"\n        \"str    r1, [r0, #28]       \\n\" // store r8 into nlr_buf\n        \"mov    r1, r9              \\n\"\n        \"str    r1, [r0, #32]       \\n\" // store r9 into nlr_buf\n        \"mov    r1, r10             \\n\"\n        \"str    r1, [r0, #36]       \\n\" // store r10 into nlr_buf\n        \"mov    r1, r11             \\n\"\n        \"str    r1, [r0, #40]       \\n\" // store r11 into nlr_buf\n        \"mov    r1, r13             \\n\"\n        \"str    r1, [r0, #44]       \\n\" // store r13=sp into nlr_buf\n        \"mov    r1, lr              \\n\"\n        \"str    r1, [r0, #8]        \\n\" // store lr into nlr_buf\n        #else\n        \"str    r8, [r0, #28]       \\n\" // store r8 into nlr_buf\n        \"str    r9, [r0, #32]       \\n\" // store r9 into nlr_buf\n        \"str    r10, [r0, #36]      \\n\" // store r10 into nlr_buf\n        \"str    r11, [r0, #40]      \\n\" // store r11 into nlr_buf\n        \"str    r13, [r0, #44]      \\n\" // store r13=sp into nlr_buf\n        #if MICROPY_NLR_NUM_REGS == 16\n        \"vstr   d8, [r0, #48]       \\n\" // store s16-s17 into nlr_buf\n        \"vstr   d9, [r0, #56]       \\n\" // store s18-s19 into nlr_buf\n        \"vstr   d10, [r0, #64]      \\n\" // store s20-s21 into nlr_buf\n        #endif\n        \"str    lr, [r0, #8]        \\n\" // store lr into nlr_buf\n        #endif\n\n        #if !defined(__thumb2__)\n        \"ldr    r1, nlr_push_tail_var \\n\"\n        \"bx     r1                  \\n\" // do the rest in C\n        \".align 2                   \\n\"\n        \"nlr_push_tail_var: .word nlr_push_tail \\n\"\n        #else\n        #if defined(__APPLE__) || defined(__MACH__)\n        \"b      _nlr_push_tail      \\n\" // do the rest in C\n        #else\n        \"b      nlr_push_tail       \\n\" // do the rest in C\n        #endif\n        #endif\n        );\n\n    #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))\n    // Older versions of gcc give an error when naked functions don't return a value\n    // Additionally exclude Clang as it also defines __GNUC__ but doesn't need this statement\n    return 0;\n    #endif\n}\n\nNORETURN void nlr_jump(void *val) {\n    MP_NLR_JUMP_HEAD(val, top)\n\n    __asm volatile (\n        \"mov    r0, %0              \\n\" // r0 points to nlr_buf\n        \"ldr    r4, [r0, #12]       \\n\" // load r4 from nlr_buf\n        \"ldr    r5, [r0, #16]       \\n\" // load r5 from nlr_buf\n        \"ldr    r6, [r0, #20]       \\n\" // load r6 from nlr_buf\n        \"ldr    r7, [r0, #24]       \\n\" // load r7 from nlr_buf\n\n        #if !defined(__thumb2__)\n        \"ldr    r1, [r0, #28]       \\n\" // load r8 from nlr_buf\n        \"mov    r8, r1              \\n\"\n        \"ldr    r1, [r0, #32]       \\n\" // load r9 from nlr_buf\n        \"mov    r9, r1              \\n\"\n        \"ldr    r1, [r0, #36]       \\n\" // load r10 from nlr_buf\n        \"mov    r10, r1             \\n\"\n        \"ldr    r1, [r0, #40]       \\n\" // load r11 from nlr_buf\n        \"mov    r11, r1             \\n\"\n        \"ldr    r1, [r0, #44]       \\n\" // load r13=sp from nlr_buf\n        \"mov    r13, r1             \\n\"\n        \"ldr    r1, [r0, #8]        \\n\" // load lr from nlr_buf\n        \"mov    lr, r1              \\n\"\n        #else\n        \"ldr    r8, [r0, #28]       \\n\" // load r8 from nlr_buf\n        \"ldr    r9, [r0, #32]       \\n\" // load r9 from nlr_buf\n        \"ldr    r10, [r0, #36]      \\n\" // load r10 from nlr_buf\n        \"ldr    r11, [r0, #40]      \\n\" // load r11 from nlr_buf\n        \"ldr    r13, [r0, #44]      \\n\" // load r13=sp from nlr_buf\n        #if MICROPY_NLR_NUM_REGS == 16\n        \"vldr   d8, [r0, #48]       \\n\" // load s16-s17 from nlr_buf\n        \"vldr   d9, [r0, #56]       \\n\" // load s18-s19 from nlr_buf\n        \"vldr   d10, [r0, #64]      \\n\" // load s20-s21 from nlr_buf\n        #endif\n        \"ldr    lr, [r0, #8]        \\n\" // load lr from nlr_buf\n        #endif\n        \"movs   r0, #1              \\n\" // return 1, non-local return\n        \"bx     lr                  \\n\" // return\n        :                           // output operands\n        : \"r\" (top)                 // input operands\n        :                           // clobbered registers\n        );\n\n    MP_UNREACHABLE\n}\n\n#endif // MICROPY_NLR_THUMB\n"
  },
  {
    "path": "py/nlrx64.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpstate.h\"\n\n#if MICROPY_NLR_X64\n\n#undef nlr_push\n\n// x86-64 callee-save registers are:\n//  rbx, rbp, rsp, r12, r13, r14, r15\n\n__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);\n\nunsigned int nlr_push(nlr_buf_t *nlr) {\n    (void)nlr;\n\n    #if MICROPY_NLR_OS_WINDOWS\n\n    __asm volatile (\n        \"movq   (%rsp), %rax        \\n\" // load return %rip\n        \"movq   %rax, 16(%rcx)      \\n\" // store %rip into nlr_buf\n        \"movq   %rbp, 24(%rcx)      \\n\" // store %rbp into nlr_buf\n        \"movq   %rsp, 32(%rcx)      \\n\" // store %rsp into nlr_buf\n        \"movq   %rbx, 40(%rcx)      \\n\" // store %rbx into nlr_buf\n        \"movq   %r12, 48(%rcx)      \\n\" // store %r12 into nlr_buf\n        \"movq   %r13, 56(%rcx)      \\n\" // store %r13 into nlr_buf\n        \"movq   %r14, 64(%rcx)      \\n\" // store %r14 into nlr_buf\n        \"movq   %r15, 72(%rcx)      \\n\" // store %r15 into nlr_buf\n        \"movq   %rdi, 80(%rcx)      \\n\" // store %rdr into nlr_buf\n        \"movq   %rsi, 88(%rcx)      \\n\" // store %rsi into nlr_buf\n        \"jmp    nlr_push_tail       \\n\" // do the rest in C\n        );\n\n    #else\n\n    __asm volatile (\n        #if defined(__APPLE__) || defined(__MACH__)\n        \"pop    %rbp                \\n\" // undo function's prelude\n        #endif\n        \"movq   (%rsp), %rax        \\n\" // load return %rip\n        \"movq   %rax, 16(%rdi)      \\n\" // store %rip into nlr_buf\n        \"movq   %rbp, 24(%rdi)      \\n\" // store %rbp into nlr_buf\n        \"movq   %rsp, 32(%rdi)      \\n\" // store %rsp into nlr_buf\n        \"movq   %rbx, 40(%rdi)      \\n\" // store %rbx into nlr_buf\n        \"movq   %r12, 48(%rdi)      \\n\" // store %r12 into nlr_buf\n        \"movq   %r13, 56(%rdi)      \\n\" // store %r13 into nlr_buf\n        \"movq   %r14, 64(%rdi)      \\n\" // store %r14 into nlr_buf\n        \"movq   %r15, 72(%rdi)      \\n\" // store %r15 into nlr_buf\n        #if defined(__APPLE__) || defined(__MACH__)\n        \"jmp    _nlr_push_tail      \\n\" // do the rest in C\n        #else\n        \"jmp    nlr_push_tail       \\n\" // do the rest in C\n        #endif\n        );\n\n    #endif\n\n    return 0; // needed to silence compiler warning\n}\n\nNORETURN void nlr_jump(void *val) {\n    MP_NLR_JUMP_HEAD(val, top)\n\n    __asm volatile (\n        \"movq   %0, %%rcx           \\n\" // %rcx points to nlr_buf\n        #if MICROPY_NLR_OS_WINDOWS\n        \"movq   88(%%rcx), %%rsi    \\n\" // load saved %rsi\n        \"movq   80(%%rcx), %%rdi    \\n\" // load saved %rdr\n        #endif\n        \"movq   72(%%rcx), %%r15    \\n\" // load saved %r15\n        \"movq   64(%%rcx), %%r14    \\n\" // load saved %r14\n        \"movq   56(%%rcx), %%r13    \\n\" // load saved %r13\n        \"movq   48(%%rcx), %%r12    \\n\" // load saved %r12\n        \"movq   40(%%rcx), %%rbx    \\n\" // load saved %rbx\n        \"movq   32(%%rcx), %%rsp    \\n\" // load saved %rsp\n        \"movq   24(%%rcx), %%rbp    \\n\" // load saved %rbp\n        \"movq   16(%%rcx), %%rax    \\n\" // load saved %rip\n        \"movq   %%rax, (%%rsp)      \\n\" // store saved %rip to stack\n        \"xorq   %%rax, %%rax        \\n\" // clear return register\n        \"inc    %%al                \\n\" // increase to make 1, non-local return\n        \"ret                        \\n\" // return\n        :                           // output operands\n        : \"r\" (top)                 // input operands\n        :                           // clobbered registers\n        );\n\n    MP_UNREACHABLE\n}\n\n#endif // MICROPY_NLR_X64\n"
  },
  {
    "path": "py/nlrx86.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpstate.h\"\n\n#if MICROPY_NLR_X86\n\n#undef nlr_push\n\n// For reference, x86 callee save regs are:\n//  ebx, esi, edi, ebp, esp, eip\n\n#if MICROPY_NLR_OS_WINDOWS\nunsigned int nlr_push_tail(nlr_buf_t *nlr) asm (\"nlr_push_tail\");\n#else\n__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);\n#endif\n\n#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 8\n// Since gcc 8.0 the naked attribute is supported\n#define USE_NAKED (1)\n#define UNDO_PRELUDE (0)\n#elif defined(__ZEPHYR__) || defined(__ANDROID__)\n// Zephyr and Android use a different calling convention by default\n#define USE_NAKED (0)\n#define UNDO_PRELUDE (0)\n#else\n#define USE_NAKED (0)\n#define UNDO_PRELUDE (1)\n#endif\n\n#if USE_NAKED\n__attribute__((naked))\n#endif\nunsigned int nlr_push(nlr_buf_t *nlr) {\n    (void)nlr;\n\n    __asm volatile (\n        #if UNDO_PRELUDE\n        \"pop    %ebp                \\n\" // undo function's prelude\n        #endif\n        \"mov    4(%esp), %edx       \\n\" // load nlr_buf\n        \"mov    (%esp), %eax        \\n\" // load return %eip\n        \"mov    %eax, 8(%edx)       \\n\" // store %eip into nlr_buf\n        \"mov    %ebp, 12(%edx)      \\n\" // store %ebp into nlr_buf\n        \"mov    %esp, 16(%edx)      \\n\" // store %esp into nlr_buf\n        \"mov    %ebx, 20(%edx)      \\n\" // store %ebx into nlr_buf\n        \"mov    %edi, 24(%edx)      \\n\" // store %edi into nlr_buf\n        \"mov    %esi, 28(%edx)      \\n\" // store %esi into nlr_buf\n        \"jmp    nlr_push_tail       \\n\" // do the rest in C\n        );\n\n    #if !USE_NAKED\n    return 0; // needed to silence compiler warning\n    #endif\n}\n\nNORETURN void nlr_jump(void *val) {\n    MP_NLR_JUMP_HEAD(val, top)\n\n    __asm volatile (\n        \"mov    %0, %%edx           \\n\" // %edx points to nlr_buf\n        \"mov    28(%%edx), %%esi    \\n\" // load saved %esi\n        \"mov    24(%%edx), %%edi    \\n\" // load saved %edi\n        \"mov    20(%%edx), %%ebx    \\n\" // load saved %ebx\n        \"mov    16(%%edx), %%esp    \\n\" // load saved %esp\n        \"mov    12(%%edx), %%ebp    \\n\" // load saved %ebp\n        \"mov    8(%%edx), %%eax     \\n\" // load saved %eip\n        \"mov    %%eax, (%%esp)      \\n\" // store saved %eip to stack\n        \"xor    %%eax, %%eax        \\n\" // clear return register\n        \"inc    %%al                \\n\" // increase to make 1, non-local return\n        \"ret                        \\n\" // return\n        :                           // output operands\n        : \"r\" (top)                 // input operands\n        :                           // clobbered registers\n        );\n\n    MP_UNREACHABLE\n}\n\n#endif // MICROPY_NLR_X86\n"
  },
  {
    "path": "py/nlrxtensa.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpstate.h\"\n\n#if MICROPY_NLR_XTENSA\n\n#undef nlr_push\n\n// Xtensa calling conventions:\n//  a0 = return address\n//  a1 = stack pointer\n//  a2 = first arg, return value\n//  a3-a7 = rest of args\n\nunsigned int nlr_push(nlr_buf_t *nlr) {\n\n    __asm volatile (\n        \"s32i.n  a0, a2, 8          \\n\" // save regs...\n        \"s32i.n  a1, a2, 12         \\n\"\n        \"s32i.n  a8, a2, 16         \\n\"\n        \"s32i.n  a9, a2, 20         \\n\"\n        \"s32i.n  a10, a2, 24        \\n\"\n        \"s32i.n  a11, a2, 28        \\n\"\n        \"s32i.n  a12, a2, 32        \\n\"\n        \"s32i.n  a13, a2, 36        \\n\"\n        \"s32i.n  a14, a2, 40        \\n\"\n        \"s32i.n  a15, a2, 44        \\n\"\n        \"j      nlr_push_tail       \\n\" // do the rest in C\n        );\n\n    return 0; // needed to silence compiler warning\n}\n\nNORETURN void nlr_jump(void *val) {\n    MP_NLR_JUMP_HEAD(val, top)\n\n    __asm volatile (\n        \"mov.n   a2, %0             \\n\" // a2 points to nlr_buf\n        \"l32i.n  a0, a2, 8          \\n\" // restore regs...\n        \"l32i.n  a1, a2, 12         \\n\"\n        \"l32i.n  a8, a2, 16         \\n\"\n        \"l32i.n  a9, a2, 20         \\n\"\n        \"l32i.n  a10, a2, 24        \\n\"\n        \"l32i.n  a11, a2, 28        \\n\"\n        \"l32i.n  a12, a2, 32        \\n\"\n        \"l32i.n  a13, a2, 36        \\n\"\n        \"l32i.n  a14, a2, 40        \\n\"\n        \"l32i.n  a15, a2, 44        \\n\"\n        \"movi.n a2, 1               \\n\" // return 1, non-local return\n        \"ret.n                      \\n\" // return\n        :                           // output operands\n        : \"r\" (top)                 // input operands\n        :                           // clobbered registers\n        );\n\n    MP_UNREACHABLE\n}\n\n#endif // MICROPY_NLR_XTENSA\n"
  },
  {
    "path": "py/obj.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <assert.h>\n\n#include \"py/obj.h\"\n#include \"py/objtype.h\"\n#include \"py/objint.h\"\n#include \"py/objstr.h\"\n#include \"py/runtime.h\"\n#include \"py/stackctrl.h\"\n#include \"py/stream.h\" // for mp_obj_print\n\nconst mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {\n    #if MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A\n\n    if (mp_obj_is_obj(o_in)) {\n        const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);\n        return o->type;\n    } else {\n        static const mp_obj_type_t *const types[] = {\n            NULL, &mp_type_int, &mp_type_str, &mp_type_int,\n            NULL, &mp_type_int, &mp_type_NoneType, &mp_type_int,\n            NULL, &mp_type_int, &mp_type_str, &mp_type_int,\n            NULL, &mp_type_int, &mp_type_bool, &mp_type_int,\n        };\n        return types[(uintptr_t)o_in & 0xf];\n    }\n\n    #elif MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C\n\n    if (mp_obj_is_small_int(o_in)) {\n        return &mp_type_int;\n    } else if (mp_obj_is_obj(o_in)) {\n        const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);\n        return o->type;\n    #if MICROPY_PY_BUILTINS_FLOAT\n    } else if ((((mp_uint_t)(o_in)) & 0xff800007) != 0x00000006) {\n        return &mp_type_float;\n    #endif\n    } else {\n        static const mp_obj_type_t *const types[] = {\n            &mp_type_str, &mp_type_NoneType, &mp_type_str, &mp_type_bool,\n        };\n        return types[((uintptr_t)o_in >> 3) & 3];\n    }\n\n    #else\n\n    if (mp_obj_is_small_int(o_in)) {\n        return &mp_type_int;\n    } else if (mp_obj_is_qstr(o_in)) {\n        return &mp_type_str;\n        #if MICROPY_PY_BUILTINS_FLOAT && ( \\\n            MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D)\n    } else if (mp_obj_is_float(o_in)) {\n        return &mp_type_float;\n        #endif\n    #if MICROPY_OBJ_IMMEDIATE_OBJS\n    } else if (mp_obj_is_immediate_obj(o_in)) {\n        static const mp_obj_type_t *const types[2] = {&mp_type_NoneType, &mp_type_bool};\n        return types[MP_OBJ_IMMEDIATE_OBJ_VALUE(o_in) & 1];\n    #endif\n    } else {\n        const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);\n        return o->type;\n    }\n\n    #endif\n}\n\nconst char *mp_obj_get_type_str(mp_const_obj_t o_in) {\n    return qstr_str(mp_obj_get_type(o_in)->name);\n}\n\nvoid mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    // There can be data structures nested too deep, or just recursive\n    MP_STACK_CHECK();\n    #ifndef NDEBUG\n    if (o_in == MP_OBJ_NULL) {\n        mp_print_str(print, \"(nil)\");\n        return;\n    }\n    #endif\n    const mp_obj_type_t *type = mp_obj_get_type(o_in);\n    if (type->print != NULL) {\n        type->print((mp_print_t *)print, o_in, kind);\n    } else {\n        mp_printf(print, \"<%q>\", type->name);\n    }\n}\n\nvoid mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {\n    mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind);\n}\n\n// helper function to print an exception with traceback\nvoid mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) {\n    if (mp_obj_is_exception_instance(exc)) {\n        size_t n, *values;\n        mp_obj_exception_get_traceback(exc, &n, &values);\n        if (n > 0) {\n            assert(n % 3 == 0);\n            mp_print_str(print, \"Traceback (most recent call last):\\n\");\n            for (int i = n - 3; i >= 0; i -= 3) {\n                #if MICROPY_ENABLE_SOURCE_LINE\n                mp_printf(print, \"  File \\\"%q\\\", line %d\", values[i], (int)values[i + 1]);\n                #else\n                mp_printf(print, \"  File \\\"%q\\\"\", values[i]);\n                #endif\n                // the block name can be NULL if it's unknown\n                qstr block = values[i + 2];\n                if (block == MP_QSTRnull) {\n                    mp_print_str(print, \"\\n\");\n                } else {\n                    mp_printf(print, \", in %q\\n\", block);\n                }\n            }\n        }\n    }\n    mp_obj_print_helper(print, exc, PRINT_EXC);\n    mp_print_str(print, \"\\n\");\n}\n\nbool mp_obj_is_true(mp_obj_t arg) {\n    if (arg == mp_const_false) {\n        return 0;\n    } else if (arg == mp_const_true) {\n        return 1;\n    } else if (arg == mp_const_none) {\n        return 0;\n    } else if (mp_obj_is_small_int(arg)) {\n        if (arg == MP_OBJ_NEW_SMALL_INT(0)) {\n            return 0;\n        } else {\n            return 1;\n        }\n    } else {\n        const mp_obj_type_t *type = mp_obj_get_type(arg);\n        if (type->unary_op != NULL) {\n            mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg);\n            if (result != MP_OBJ_NULL) {\n                return result == mp_const_true;\n            }\n        }\n\n        mp_obj_t len = mp_obj_len_maybe(arg);\n        if (len != MP_OBJ_NULL) {\n            // obj has a length, truth determined if len != 0\n            return len != MP_OBJ_NEW_SMALL_INT(0);\n        } else {\n            // any other obj is true per Python semantics\n            return 1;\n        }\n    }\n}\n\nbool mp_obj_is_callable(mp_obj_t o_in) {\n    const mp_call_fun_t call = mp_obj_get_type(o_in)->call;\n    if (call != mp_obj_instance_call) {\n        return call != NULL;\n    }\n    return mp_obj_instance_is_callable(o_in);\n}\n\n// This function implements the '==' and '!=' operators.\n//\n// From the Python language reference:\n// (https://docs.python.org/3/reference/expressions.html#not-in)\n// \"The objects need not have the same type. If both are numbers, they are converted\n// to a common type. Otherwise, the == and != operators always consider objects of\n// different types to be unequal.\"\n//\n// This means that False==0 and True==1 are true expressions.\n//\n// Furthermore, from the v3.4.2 code for object.c: \"Practical amendments: If rich\n// comparison returns NotImplemented, == and != are decided by comparing the object\n// pointer.\"\nmp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2) {\n    mp_obj_t local_true = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_false : mp_const_true;\n    mp_obj_t local_false = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_true : mp_const_false;\n    int pass_number = 0;\n\n    // Shortcut for very common cases\n    if (o1 == o2 &&\n        (mp_obj_is_small_int(o1) || !(mp_obj_get_type(o1)->flags & MP_TYPE_FLAG_EQ_NOT_REFLEXIVE))) {\n        return local_true;\n    }\n\n    // fast path for strings\n    if (mp_obj_is_str(o1)) {\n        if (mp_obj_is_str(o2)) {\n            // both strings, use special function\n            return mp_obj_str_equal(o1, o2) ? local_true : local_false;\n        #if MICROPY_PY_STR_BYTES_CMP_WARN\n        } else if (mp_obj_is_type(o2, &mp_type_bytes)) {\n        str_bytes_cmp:\n            mp_warning(MP_WARN_CAT(BytesWarning), \"Comparison between bytes and str\");\n            return local_false;\n        #endif\n        } else {\n            goto skip_one_pass;\n        }\n    #if MICROPY_PY_STR_BYTES_CMP_WARN\n    } else if (mp_obj_is_str(o2) && mp_obj_is_type(o1, &mp_type_bytes)) {\n        // o1 is not a string (else caught above), so the objects are not equal\n        goto str_bytes_cmp;\n    #endif\n    }\n\n    // fast path for small ints\n    if (mp_obj_is_small_int(o1)) {\n        if (mp_obj_is_small_int(o2)) {\n            // both SMALL_INT, and not equal if we get here\n            return local_false;\n        } else {\n            goto skip_one_pass;\n        }\n    }\n\n    // generic type, call binary_op(MP_BINARY_OP_EQUAL)\n    while (pass_number < 2) {\n        const mp_obj_type_t *type = mp_obj_get_type(o1);\n        // If a full equality test is not needed and the other object is a different\n        // type then we don't need to bother trying the comparison.\n        if (type->binary_op != NULL &&\n            ((type->flags & MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE) || mp_obj_get_type(o2) == type)) {\n            // CPython is asymmetric: it will try __eq__ if there's no __ne__ but not the\n            // other way around.  If the class doesn't need a full test we can skip __ne__.\n            if (op == MP_BINARY_OP_NOT_EQUAL && (type->flags & MP_TYPE_FLAG_EQ_HAS_NEQ_TEST)) {\n                mp_obj_t r = type->binary_op(MP_BINARY_OP_NOT_EQUAL, o1, o2);\n                if (r != MP_OBJ_NULL) {\n                    return r;\n                }\n            }\n\n            // Try calling __eq__.\n            mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2);\n            if (r != MP_OBJ_NULL) {\n                if (op == MP_BINARY_OP_EQUAL) {\n                    return r;\n                } else {\n                    return mp_obj_is_true(r) ? local_true : local_false;\n                }\n            }\n        }\n\n    skip_one_pass:\n        // Try the other way around if none of the above worked\n        ++pass_number;\n        mp_obj_t temp = o1;\n        o1 = o2;\n        o2 = temp;\n    }\n\n    // equality not implemented, so fall back to pointer conparison\n    return (o1 == o2) ? local_true : local_false;\n}\n\nbool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {\n    return mp_obj_is_true(mp_obj_equal_not_equal(MP_BINARY_OP_EQUAL, o1, o2));\n}\n\nmp_int_t mp_obj_get_int(mp_const_obj_t arg) {\n    // This function essentially performs implicit type conversion to int\n    // Note that Python does NOT provide implicit type conversion from\n    // float to int in the core expression language, try some_list[1.0].\n    if (arg == mp_const_false) {\n        return 0;\n    } else if (arg == mp_const_true) {\n        return 1;\n    } else if (mp_obj_is_small_int(arg)) {\n        return MP_OBJ_SMALL_INT_VALUE(arg);\n    } else if (mp_obj_is_type(arg, &mp_type_int)) {\n        return mp_obj_int_get_checked(arg);\n    } else {\n        mp_obj_t res = mp_unary_op(MP_UNARY_OP_INT, (mp_obj_t)arg);\n        return mp_obj_int_get_checked(res);\n    }\n}\n\nmp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) {\n    if (mp_obj_is_int(arg)) {\n        return mp_obj_int_get_truncated(arg);\n    } else {\n        return mp_obj_get_int(arg);\n    }\n}\n\n// returns false if arg is not of integral type\n// returns true and sets *value if it is of integral type\n// can throw OverflowError if arg is of integral type, but doesn't fit in a mp_int_t\nbool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) {\n    if (arg == mp_const_false) {\n        *value = 0;\n    } else if (arg == mp_const_true) {\n        *value = 1;\n    } else if (mp_obj_is_small_int(arg)) {\n        *value = MP_OBJ_SMALL_INT_VALUE(arg);\n    } else if (mp_obj_is_type(arg, &mp_type_int)) {\n        *value = mp_obj_int_get_checked(arg);\n    } else {\n        return false;\n    }\n    return true;\n}\n\n#if MICROPY_PY_BUILTINS_FLOAT\nbool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value) {\n    mp_float_t val;\n\n    if (arg == mp_const_false) {\n        val = 0;\n    } else if (arg == mp_const_true) {\n        val = 1;\n    } else if (mp_obj_is_small_int(arg)) {\n        val = (mp_float_t)MP_OBJ_SMALL_INT_VALUE(arg);\n    #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE\n    } else if (mp_obj_is_type(arg, &mp_type_int)) {\n        val = mp_obj_int_as_float_impl(arg);\n    #endif\n    } else if (mp_obj_is_float(arg)) {\n        val = mp_obj_float_get(arg);\n    } else {\n        return false;\n    }\n\n    *value = val;\n    return true;\n}\n\nmp_float_t mp_obj_get_float(mp_obj_t arg) {\n    mp_float_t val;\n\n    if (!mp_obj_get_float_maybe(arg, &val)) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_TypeError(MP_ERROR_TEXT(\"can't convert to float\"));\n        #else\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"can't convert %s to float\"), mp_obj_get_type_str(arg));\n        #endif\n    }\n\n    return val;\n}\n\n#if MICROPY_PY_BUILTINS_COMPLEX\nbool mp_obj_get_complex_maybe(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {\n    if (arg == mp_const_false) {\n        *real = 0;\n        *imag = 0;\n    } else if (arg == mp_const_true) {\n        *real = 1;\n        *imag = 0;\n    } else if (mp_obj_is_small_int(arg)) {\n        *real = (mp_float_t)MP_OBJ_SMALL_INT_VALUE(arg);\n        *imag = 0;\n    #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE\n    } else if (mp_obj_is_type(arg, &mp_type_int)) {\n        *real = mp_obj_int_as_float_impl(arg);\n        *imag = 0;\n    #endif\n    } else if (mp_obj_is_float(arg)) {\n        *real = mp_obj_float_get(arg);\n        *imag = 0;\n    } else if (mp_obj_is_type(arg, &mp_type_complex)) {\n        mp_obj_complex_get(arg, real, imag);\n    } else {\n        return false;\n    }\n    return true;\n}\n\nvoid mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {\n    if (!mp_obj_get_complex_maybe(arg, real, imag)) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_TypeError(MP_ERROR_TEXT(\"can't convert to complex\"));\n        #else\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"can't convert %s to complex\"), mp_obj_get_type_str(arg));\n        #endif\n    }\n}\n#endif\n#endif\n\n// note: returned value in *items may point to the interior of a GC block\nvoid mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) {\n    if (mp_obj_is_type(o, &mp_type_tuple)) {\n        mp_obj_tuple_get(o, len, items);\n    } else if (mp_obj_is_type(o, &mp_type_list)) {\n        mp_obj_list_get(o, len, items);\n    } else {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_TypeError(MP_ERROR_TEXT(\"expected tuple/list\"));\n        #else\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"object '%s' isn't a tuple or list\"), mp_obj_get_type_str(o));\n        #endif\n    }\n}\n\n// note: returned value in *items may point to the interior of a GC block\nvoid mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) {\n    size_t seq_len;\n    mp_obj_get_array(o, &seq_len, items);\n    if (seq_len != len) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_ValueError(MP_ERROR_TEXT(\"tuple/list has wrong length\"));\n        #else\n        mp_raise_msg_varg(&mp_type_ValueError,\n            MP_ERROR_TEXT(\"requested length %d but object has length %d\"), (int)len, (int)seq_len);\n        #endif\n    }\n}\n\n// is_slice determines whether the index is a slice index\nsize_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice) {\n    mp_int_t i;\n    if (mp_obj_is_small_int(index)) {\n        i = MP_OBJ_SMALL_INT_VALUE(index);\n    } else if (!mp_obj_get_int_maybe(index, &i)) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_TypeError(MP_ERROR_TEXT(\"indices must be integers\"));\n        #else\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"%q indices must be integers, not %s\"),\n            type->name, mp_obj_get_type_str(index));\n        #endif\n    }\n\n    if (i < 0) {\n        i += len;\n    }\n    if (is_slice) {\n        if (i < 0) {\n            i = 0;\n        } else if ((mp_uint_t)i > len) {\n            i = len;\n        }\n    } else {\n        if (i < 0 || (mp_uint_t)i >= len) {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT(\"index out of range\"));\n            #else\n            mp_raise_msg_varg(&mp_type_IndexError, MP_ERROR_TEXT(\"%q index out of range\"), type->name);\n            #endif\n        }\n    }\n\n    // By this point 0 <= i <= len and so fits in a size_t\n    return (size_t)i;\n}\n\nmp_obj_t mp_obj_id(mp_obj_t o_in) {\n    mp_int_t id = (mp_int_t)o_in;\n    if (!mp_obj_is_obj(o_in)) {\n        return mp_obj_new_int(id);\n    } else if (id >= 0) {\n        // Many OSes and CPUs have affinity for putting \"user\" memories\n        // into low half of address space, and \"system\" into upper half.\n        // We're going to take advantage of that and return small int\n        // (signed) for such \"user\" addresses.\n        return MP_OBJ_NEW_SMALL_INT(id);\n    } else {\n        // If that didn't work, well, let's return long int, just as\n        // a (big) positive value, so it will never clash with the range\n        // of small int returned in previous case.\n        return mp_obj_new_int_from_uint((mp_uint_t)id);\n    }\n}\n\n// will raise a TypeError if object has no length\nmp_obj_t mp_obj_len(mp_obj_t o_in) {\n    mp_obj_t len = mp_obj_len_maybe(o_in);\n    if (len == MP_OBJ_NULL) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_TypeError(MP_ERROR_TEXT(\"object has no len\"));\n        #else\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"object of type '%s' has no len()\"), mp_obj_get_type_str(o_in));\n        #endif\n    } else {\n        return len;\n    }\n}\n\n// may return MP_OBJ_NULL\nmp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {\n    if (\n        #if !MICROPY_PY_BUILTINS_STR_UNICODE\n        // It's simple - unicode is slow, non-unicode is fast\n        mp_obj_is_str(o_in) ||\n        #endif\n        mp_obj_is_type(o_in, &mp_type_bytes)) {\n        GET_STR_LEN(o_in, l);\n        return MP_OBJ_NEW_SMALL_INT(l);\n    } else {\n        const mp_obj_type_t *type = mp_obj_get_type(o_in);\n        if (type->unary_op != NULL) {\n            return type->unary_op(MP_UNARY_OP_LEN, o_in);\n        } else {\n            return MP_OBJ_NULL;\n        }\n    }\n}\n\nmp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {\n    const mp_obj_type_t *type = mp_obj_get_type(base);\n    if (type->subscr != NULL) {\n        mp_obj_t ret = type->subscr(base, index, value);\n        if (ret != MP_OBJ_NULL) {\n            return ret;\n        }\n        // TODO: call base classes here?\n    }\n    if (value == MP_OBJ_NULL) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_TypeError(MP_ERROR_TEXT(\"object doesn't support item deletion\"));\n        #else\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"'%s' object doesn't support item deletion\"), mp_obj_get_type_str(base));\n        #endif\n    } else if (value == MP_OBJ_SENTINEL) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_TypeError(MP_ERROR_TEXT(\"object isn't subscriptable\"));\n        #else\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"'%s' object isn't subscriptable\"), mp_obj_get_type_str(base));\n        #endif\n    } else {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_TypeError(MP_ERROR_TEXT(\"object doesn't support item assignment\"));\n        #else\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"'%s' object doesn't support item assignment\"), mp_obj_get_type_str(base));\n        #endif\n    }\n}\n\n// Return input argument. Useful as .getiter for objects which are\n// their own iterators, etc.\nmp_obj_t mp_identity(mp_obj_t self) {\n    return self;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity);\n\nmp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf) {\n    (void)iter_buf;\n    return self;\n}\n\nbool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {\n    const mp_obj_type_t *type = mp_obj_get_type(obj);\n    if (type->buffer_p.get_buffer == NULL) {\n        return false;\n    }\n    int ret = type->buffer_p.get_buffer(obj, bufinfo, flags);\n    if (ret != 0) {\n        return false;\n    }\n    return true;\n}\n\nvoid mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {\n    if (!mp_get_buffer(obj, bufinfo, flags)) {\n        mp_raise_TypeError(MP_ERROR_TEXT(\"object with buffer protocol required\"));\n    }\n}\n\nmp_obj_t mp_generic_unary_op(mp_unary_op_t op, mp_obj_t o_in) {\n    switch (op) {\n        case MP_UNARY_OP_HASH:\n            return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in);\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n"
  },
  {
    "path": "py/obj.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJ_H\n#define MICROPY_INCLUDED_PY_OBJ_H\n\n#include <assert.h>\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n#include \"py/qstr.h\"\n#include \"py/mpprint.h\"\n#include \"py/runtime0.h\"\n\n// This is the definition of the opaque MicroPython object type.\n// All concrete objects have an encoding within this type and the\n// particular encoding is specified by MICROPY_OBJ_REPR.\n#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D\ntypedef uint64_t mp_obj_t;\ntypedef uint64_t mp_const_obj_t;\n#else\ntypedef void *mp_obj_t;\ntypedef const void *mp_const_obj_t;\n#endif\n\n// This mp_obj_type_t struct is a concrete MicroPython object which holds info\n// about a type.  See below for actual definition of the struct.\ntypedef struct _mp_obj_type_t mp_obj_type_t;\n\n// Anything that wants to be a concrete MicroPython object must have mp_obj_base_t\n// as its first member (small ints, qstr objs and inline floats are not concrete).\nstruct _mp_obj_base_t {\n    const mp_obj_type_t *type MICROPY_OBJ_BASE_ALIGNMENT;\n};\ntypedef struct _mp_obj_base_t mp_obj_base_t;\n\n// These fake objects are used to indicate certain things in arguments or return\n// values, and should only be used when explicitly allowed.\n//\n//  - MP_OBJ_NULL : used to indicate the absence of an object, or unsupported operation.\n//  - MP_OBJ_STOP_ITERATION : used instead of throwing a StopIteration, for efficiency.\n//  - MP_OBJ_SENTINEL : used for various internal purposes where one needs\n//    an object which is unique from all other objects, including MP_OBJ_NULL.\n//\n// For debugging purposes they are all different.  For non-debug mode, we alias\n// as many as we can to MP_OBJ_NULL because it's cheaper to load/compare 0.\n\n#if MICROPY_DEBUG_MP_OBJ_SENTINELS\n#define MP_OBJ_NULL             (MP_OBJ_FROM_PTR((void *)0))\n#define MP_OBJ_STOP_ITERATION   (MP_OBJ_FROM_PTR((void *)4))\n#define MP_OBJ_SENTINEL         (MP_OBJ_FROM_PTR((void *)8))\n#else\n#define MP_OBJ_NULL             (MP_OBJ_FROM_PTR((void *)0))\n#define MP_OBJ_STOP_ITERATION   (MP_OBJ_FROM_PTR((void *)0))\n#define MP_OBJ_SENTINEL         (MP_OBJ_FROM_PTR((void *)4))\n#endif\n\n// These macros/inline functions operate on objects and depend on the\n// particular object representation.  They are used to query, pack and\n// unpack small ints, qstrs and full object pointers.\n\n#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A\n\nstatic inline bool mp_obj_is_small_int(mp_const_obj_t o) {\n    return (((mp_int_t)(o)) & 1) != 0;\n}\n#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)\n#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1))\n\nstatic inline bool mp_obj_is_qstr(mp_const_obj_t o) {\n    return (((mp_int_t)(o)) & 7) == 2;\n}\n#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3)\n#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 2))\n\nstatic inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {\n    return (((mp_int_t)(o)) & 7) == 6;\n}\n#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 3)\n#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) ((mp_obj_t)(((val) << 3) | 6))\n\n#if MICROPY_PY_BUILTINS_FLOAT\n#define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj)\n#define mp_const_float_pi MP_ROM_PTR(&mp_const_float_pi_obj)\nextern const struct _mp_obj_float_t mp_const_float_e_obj;\nextern const struct _mp_obj_float_t mp_const_float_pi_obj;\n\n#define mp_obj_is_float(o) mp_obj_is_type((o), &mp_type_float)\nmp_float_t mp_obj_float_get(mp_obj_t self_in);\nmp_obj_t mp_obj_new_float(mp_float_t value);\n#endif\n\nstatic inline bool mp_obj_is_obj(mp_const_obj_t o) {\n    return (((mp_int_t)(o)) & 3) == 0;\n}\n\n#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B\n\nstatic inline bool mp_obj_is_small_int(mp_const_obj_t o) {\n    return (((mp_int_t)(o)) & 3) == 1;\n}\n#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 2)\n#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 2) | 1))\n\nstatic inline bool mp_obj_is_qstr(mp_const_obj_t o) {\n    return (((mp_int_t)(o)) & 7) == 3;\n}\n#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3)\n#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 3))\n\nstatic inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {\n    return (((mp_int_t)(o)) & 7) == 7;\n}\n#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 3)\n#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) ((mp_obj_t)(((val) << 3) | 7))\n\n#if MICROPY_PY_BUILTINS_FLOAT\n#define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj)\n#define mp_const_float_pi MP_ROM_PTR(&mp_const_float_pi_obj)\nextern const struct _mp_obj_float_t mp_const_float_e_obj;\nextern const struct _mp_obj_float_t mp_const_float_pi_obj;\n\n#define mp_obj_is_float(o) mp_obj_is_type((o), &mp_type_float)\nmp_float_t mp_obj_float_get(mp_obj_t self_in);\nmp_obj_t mp_obj_new_float(mp_float_t value);\n#endif\n\nstatic inline bool mp_obj_is_obj(mp_const_obj_t o) {\n    return (((mp_int_t)(o)) & 1) == 0;\n}\n\n#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C\n\nstatic inline bool mp_obj_is_small_int(mp_const_obj_t o) {\n    return (((mp_int_t)(o)) & 1) != 0;\n}\n#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)\n#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1))\n\n#if MICROPY_PY_BUILTINS_FLOAT\n#define mp_const_float_e MP_ROM_PTR((mp_obj_t)(((0x402df854 & ~3) | 2) + 0x80800000))\n#define mp_const_float_pi MP_ROM_PTR((mp_obj_t)(((0x40490fdb & ~3) | 2) + 0x80800000))\n\nstatic inline bool mp_obj_is_float(mp_const_obj_t o) {\n    return (((mp_uint_t)(o)) & 3) == 2 && (((mp_uint_t)(o)) & 0xff800007) != 0x00000006;\n}\nstatic inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {\n    union {\n        mp_float_t f;\n        mp_uint_t u;\n    } num = {.u = ((mp_uint_t)o - 0x80800000) & ~3};\n    return num.f;\n}\nstatic inline mp_obj_t mp_obj_new_float(mp_float_t f) {\n    union {\n        mp_float_t f;\n        mp_uint_t u;\n    } num = {.f = f};\n    return (mp_obj_t)(((num.u & ~0x3) | 2) + 0x80800000);\n}\n#endif\n\nstatic inline bool mp_obj_is_qstr(mp_const_obj_t o) {\n    return (((mp_uint_t)(o)) & 0xff80000f) == 0x00000006;\n}\n#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 4)\n#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 4) | 0x00000006))\n\nstatic inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {\n    return (((mp_uint_t)(o)) & 0xff80000f) == 0x0000000e;\n}\n#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 4)\n#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) ((mp_obj_t)(((val) << 4) | 0xe))\n\nstatic inline bool mp_obj_is_obj(mp_const_obj_t o) {\n    return (((mp_int_t)(o)) & 3) == 0;\n}\n\n#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D\n\nstatic inline bool mp_obj_is_small_int(mp_const_obj_t o) {\n    return (((uint64_t)(o)) & 0xffff000000000000) == 0x0001000000000000;\n}\n#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)((o) << 16)) >> 17)\n#define MP_OBJ_NEW_SMALL_INT(small_int) (((((uint64_t)(small_int)) & 0x7fffffffffff) << 1) | 0x0001000000000001)\n\nstatic inline bool mp_obj_is_qstr(mp_const_obj_t o) {\n    return (((uint64_t)(o)) & 0xffff000000000000) == 0x0002000000000000;\n}\n#define MP_OBJ_QSTR_VALUE(o) ((((uint32_t)(o)) >> 1) & 0xffffffff)\n#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)(((uint64_t)(((uint32_t)(qst)) << 1)) | 0x0002000000000001))\n\nstatic inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {\n    return (((uint64_t)(o)) & 0xffff000000000000) == 0x0003000000000000;\n}\n#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) ((((uint32_t)(o)) >> 46) & 3)\n#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) (((uint64_t)(val) << 46) | 0x0003000000000000)\n\n#if MICROPY_PY_BUILTINS_FLOAT\n\n#if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_DOUBLE\n#error MICROPY_OBJ_REPR_D requires MICROPY_FLOAT_IMPL_DOUBLE\n#endif\n\n#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))}\n#define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))}\n\nstatic inline bool mp_obj_is_float(mp_const_obj_t o) {\n    return ((uint64_t)(o) & 0xfffc000000000000) != 0;\n}\nstatic inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {\n    union {\n        mp_float_t f;\n        uint64_t r;\n    } num = {.r = o - 0x8004000000000000};\n    return num.f;\n}\nstatic inline mp_obj_t mp_obj_new_float(mp_float_t f) {\n    union {\n        mp_float_t f;\n        uint64_t r;\n    } num = {.f = f};\n    return num.r + 0x8004000000000000;\n}\n#endif\n\nstatic inline bool mp_obj_is_obj(mp_const_obj_t o) {\n    return (((uint64_t)(o)) & 0xffff000000000000) == 0x0000000000000000;\n}\n#define MP_OBJ_TO_PTR(o) ((void *)(uintptr_t)(o))\n#define MP_OBJ_FROM_PTR(p) ((mp_obj_t)((uintptr_t)(p)))\n\n// rom object storage needs special handling to widen 32-bit pointer to 64-bits\ntypedef union _mp_rom_obj_t { uint64_t u64;\n                              struct { const void *lo, *hi;\n                              } u32;\n} mp_rom_obj_t;\n#define MP_ROM_INT(i) {MP_OBJ_NEW_SMALL_INT(i)}\n#define MP_ROM_QSTR(q) {MP_OBJ_NEW_QSTR(q)}\n#if MP_ENDIANNESS_LITTLE\n#define MP_ROM_PTR(p) {.u32 = {.lo = (p), .hi = NULL}}\n#else\n#define MP_ROM_PTR(p) {.u32 = {.lo = NULL, .hi = (p)}}\n#endif\n\n#endif\n\n// Macros to convert between mp_obj_t and concrete object types.\n// These are identity operations in MicroPython, but ability to override\n// these operations are provided to experiment with other methods of\n// object representation and memory management.\n\n// Cast mp_obj_t to object pointer\n#ifndef MP_OBJ_TO_PTR\n#define MP_OBJ_TO_PTR(o) ((void *)o)\n#endif\n\n// Cast object pointer to mp_obj_t\n#ifndef MP_OBJ_FROM_PTR\n#define MP_OBJ_FROM_PTR(p) ((mp_obj_t)p)\n#endif\n\n// Macros to create objects that are stored in ROM.\n\n#ifndef MP_ROM_NONE\n#if MICROPY_OBJ_IMMEDIATE_OBJS\n#define MP_ROM_NONE mp_const_none\n#else\n#define MP_ROM_NONE MP_ROM_PTR(&mp_const_none_obj)\n#endif\n#endif\n\n#ifndef MP_ROM_FALSE\n#if MICROPY_OBJ_IMMEDIATE_OBJS\n#define MP_ROM_FALSE mp_const_false\n#define MP_ROM_TRUE mp_const_true\n#else\n#define MP_ROM_FALSE MP_ROM_PTR(&mp_const_false_obj)\n#define MP_ROM_TRUE MP_ROM_PTR(&mp_const_true_obj)\n#endif\n#endif\n\n#ifndef MP_ROM_INT\ntypedef mp_const_obj_t mp_rom_obj_t;\n#define MP_ROM_INT(i) MP_OBJ_NEW_SMALL_INT(i)\n#define MP_ROM_QSTR(q) MP_OBJ_NEW_QSTR(q)\n#define MP_ROM_PTR(p) (p)\n/* for testing\ntypedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t;\n#define MP_ROM_INT(i) {MP_OBJ_NEW_SMALL_INT(i)}\n#define MP_ROM_QSTR(q) {MP_OBJ_NEW_QSTR(q)}\n#define MP_ROM_PTR(p) {.o = p}\n*/\n#endif\n\n// These macros are used to declare and define constant function objects\n// You can put \"static\" in front of the definitions to make them local\n\n#define MP_DECLARE_CONST_FUN_OBJ_0(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name\n#define MP_DECLARE_CONST_FUN_OBJ_1(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name\n#define MP_DECLARE_CONST_FUN_OBJ_2(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name\n#define MP_DECLARE_CONST_FUN_OBJ_3(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name\n#define MP_DECLARE_CONST_FUN_OBJ_VAR(obj_name) extern const mp_obj_fun_builtin_var_t obj_name\n#define MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name) extern const mp_obj_fun_builtin_var_t obj_name\n#define MP_DECLARE_CONST_FUN_OBJ_KW(obj_name) extern const mp_obj_fun_builtin_var_t obj_name\n\n#define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below\n#define MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, takes_kw) ((uint32_t)((((uint32_t)(n_args_min)) << 17) | (((uint32_t)(n_args_max)) << 1) | ((takes_kw) ? 1 : 0)))\n\n#define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \\\n    const mp_obj_fun_builtin_fixed_t obj_name = \\\n    {{&mp_type_fun_builtin_0}, .fun._0 = fun_name}\n#define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) \\\n    const mp_obj_fun_builtin_fixed_t obj_name = \\\n    {{&mp_type_fun_builtin_1}, .fun._1 = fun_name}\n#define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) \\\n    const mp_obj_fun_builtin_fixed_t obj_name = \\\n    {{&mp_type_fun_builtin_2}, .fun._2 = fun_name}\n#define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) \\\n    const mp_obj_fun_builtin_fixed_t obj_name = \\\n    {{&mp_type_fun_builtin_3}, .fun._3 = fun_name}\n#define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) \\\n    const mp_obj_fun_builtin_var_t obj_name = \\\n    {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, false), .fun.var = fun_name}\n#define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) \\\n    const mp_obj_fun_builtin_var_t obj_name = \\\n    {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, false), .fun.var = fun_name}\n#define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \\\n    const mp_obj_fun_builtin_var_t obj_name = \\\n    {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name}\n\n// These macros are used to define constant map/dict objects\n// You can put \"static\" in front of the definition to make it local\n\n#define MP_DEFINE_CONST_MAP(map_name, table_name) \\\n    const mp_map_t map_name = { \\\n        .all_keys_are_qstrs = 1, \\\n        .is_fixed = 1, \\\n        .is_ordered = 1, \\\n        .used = MP_ARRAY_SIZE(table_name), \\\n        .alloc = MP_ARRAY_SIZE(table_name), \\\n        .table = (mp_map_elem_t *)(mp_rom_map_elem_t *)table_name, \\\n    }\n\n#define MP_DEFINE_CONST_DICT(dict_name, table_name) \\\n    const mp_obj_dict_t dict_name = { \\\n        .base = {&mp_type_dict}, \\\n        .map = { \\\n            .all_keys_are_qstrs = 1, \\\n            .is_fixed = 1, \\\n            .is_ordered = 1, \\\n            .used = MP_ARRAY_SIZE(table_name), \\\n            .alloc = MP_ARRAY_SIZE(table_name), \\\n            .table = (mp_map_elem_t *)(mp_rom_map_elem_t *)table_name, \\\n        }, \\\n    }\n\n// These macros are used to declare and define constant staticmethond and classmethod objects\n// You can put \"static\" in front of the definitions to make them local\n\n#define MP_DECLARE_CONST_STATICMETHOD_OBJ(obj_name) extern const mp_rom_obj_static_class_method_t obj_name\n#define MP_DECLARE_CONST_CLASSMETHOD_OBJ(obj_name) extern const mp_rom_obj_static_class_method_t obj_name\n\n#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}\n#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}\n\n// Declare a module as a builtin, processed by makemoduledefs.py\n// param module_name: MP_QSTR_<module name>\n// param obj_module: mp_obj_module_t instance\n// prarm enabled_define: used as `#if (enabled_define) around entry`\n\n#define MP_REGISTER_MODULE(module_name, obj_module, enabled_define)\n\n// Underlying map/hash table implementation (not dict object or map function)\n\ntypedef struct _mp_map_elem_t {\n    mp_obj_t key;\n    mp_obj_t value;\n} mp_map_elem_t;\n\ntypedef struct _mp_rom_map_elem_t {\n    mp_rom_obj_t key;\n    mp_rom_obj_t value;\n} mp_rom_map_elem_t;\n\ntypedef struct _mp_map_t {\n    size_t all_keys_are_qstrs : 1;\n    size_t is_fixed : 1;    // if set, table is fixed/read-only and can't be modified\n    size_t is_ordered : 1;  // if set, table is an ordered array, not a hash map\n    size_t used : (8 * sizeof(size_t) - 3);\n    size_t alloc;\n    mp_map_elem_t *table;\n} mp_map_t;\n\n// mp_set_lookup requires these constants to have the values they do\ntypedef enum _mp_map_lookup_kind_t {\n    MP_MAP_LOOKUP = 0,\n    MP_MAP_LOOKUP_ADD_IF_NOT_FOUND = 1,\n    MP_MAP_LOOKUP_REMOVE_IF_FOUND = 2,\n    MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND = 3, // only valid for mp_set_lookup\n} mp_map_lookup_kind_t;\n\nstatic inline bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) {\n    assert(pos < map->alloc);\n    return (map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL;\n}\n\nvoid mp_map_init(mp_map_t *map, size_t n);\nvoid mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table);\nmp_map_t *mp_map_new(size_t n);\nvoid mp_map_deinit(mp_map_t *map);\nvoid mp_map_free(mp_map_t *map);\nmp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);\nvoid mp_map_clear(mp_map_t *map);\nvoid mp_map_dump(mp_map_t *map);\n\n// Underlying set implementation (not set object)\n\ntypedef struct _mp_set_t {\n    size_t alloc;\n    size_t used;\n    mp_obj_t *table;\n} mp_set_t;\n\nstatic inline bool mp_set_slot_is_filled(const mp_set_t *set, size_t pos) {\n    return (set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL;\n}\n\nvoid mp_set_init(mp_set_t *set, size_t n);\nmp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);\nmp_obj_t mp_set_remove_first(mp_set_t *set);\nvoid mp_set_clear(mp_set_t *set);\n\n// Type definitions for methods\n\ntypedef mp_obj_t (*mp_fun_0_t)(void);\ntypedef mp_obj_t (*mp_fun_1_t)(mp_obj_t);\ntypedef mp_obj_t (*mp_fun_2_t)(mp_obj_t, mp_obj_t);\ntypedef mp_obj_t (*mp_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t);\ntypedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *);\n// mp_fun_kw_t takes mp_map_t* (and not const mp_map_t*) to ease passing\n// this arg to mp_map_lookup().\ntypedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *);\n\n// Flags for type behaviour (mp_obj_type_t.flags)\n// If MP_TYPE_FLAG_EQ_NOT_REFLEXIVE is clear then __eq__ is reflexive (A==A returns True).\n// If MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE is clear then the type can't be equal to an\n// instance of any different class that also clears this flag.  If this flag is set\n// then the type may check for equality against a different type.\n// If MP_TYPE_FLAG_EQ_HAS_NEQ_TEST is clear then the type only implements the __eq__\n// operator and not the __ne__ operator.  If it's set then __ne__ may be implemented.\n// If MP_TYPE_FLAG_BINDS_SELF is set then the type as a method binds self as the first arg.\n// If MP_TYPE_FLAG_BUILTIN_FUN is set then the type is a built-in function type.\n#define MP_TYPE_FLAG_IS_SUBCLASSED (0x0001)\n#define MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002)\n#define MP_TYPE_FLAG_EQ_NOT_REFLEXIVE (0x0004)\n#define MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE (0x0008)\n#define MP_TYPE_FLAG_EQ_HAS_NEQ_TEST (0x0010)\n#define MP_TYPE_FLAG_BINDS_SELF (0x0020)\n#define MP_TYPE_FLAG_BUILTIN_FUN (0x0040)\n\ntypedef enum {\n    PRINT_STR = 0,\n    PRINT_REPR = 1,\n    PRINT_EXC = 2, // Special format for printing exception in unhandled exception message\n    PRINT_JSON = 3,\n    PRINT_RAW = 4, // Special format for printing bytes as an undercorated string\n    PRINT_EXC_SUBCLASS = 0x80, // Internal flag for printing exception subclasses\n} mp_print_kind_t;\n\ntypedef struct _mp_obj_iter_buf_t {\n    mp_obj_base_t base;\n    mp_obj_t buf[3];\n} mp_obj_iter_buf_t;\n\n// The number of slots that an mp_obj_iter_buf_t needs on the Python value stack.\n// It's rounded up in case mp_obj_base_t is smaller than mp_obj_t (eg for OBJ_REPR_D).\n#define MP_OBJ_ITER_BUF_NSLOTS ((sizeof(mp_obj_iter_buf_t) + sizeof(mp_obj_t) - 1) / sizeof(mp_obj_t))\n\ntypedef void (*mp_print_fun_t)(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind);\ntypedef 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);\ntypedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, size_t n_args, size_t n_kw, const mp_obj_t *args);\ntypedef mp_obj_t (*mp_unary_op_fun_t)(mp_unary_op_t op, mp_obj_t);\ntypedef mp_obj_t (*mp_binary_op_fun_t)(mp_binary_op_t op, mp_obj_t, mp_obj_t);\ntypedef void (*mp_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t *dest);\ntypedef mp_obj_t (*mp_subscr_fun_t)(mp_obj_t self_in, mp_obj_t index, mp_obj_t value);\ntypedef mp_obj_t (*mp_getiter_fun_t)(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf);\n\n// Buffer protocol\ntypedef struct _mp_buffer_info_t {\n    void *buf;      // can be NULL if len == 0\n    size_t len;     // in bytes\n    int typecode;   // as per binary.h\n} mp_buffer_info_t;\n#define MP_BUFFER_READ  (1)\n#define MP_BUFFER_WRITE (2)\n#define MP_BUFFER_RW (MP_BUFFER_READ | MP_BUFFER_WRITE)\ntypedef struct _mp_buffer_p_t {\n    mp_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);\n} mp_buffer_p_t;\nbool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);\nvoid mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);\n\nstruct _mp_obj_type_t {\n    // A type is an object so must start with this entry, which points to mp_type_type.\n    mp_obj_base_t base;\n\n    // Flags associated with this type.\n    uint16_t flags;\n\n    // The name of this type, a qstr.\n    uint16_t name;\n\n    // Corresponds to __repr__ and __str__ special methods.\n    mp_print_fun_t print;\n\n    // Corresponds to __new__ and __init__ special methods, to make an instance of the type.\n    mp_make_new_fun_t make_new;\n\n    // Corresponds to __call__ special method, ie T(...).\n    mp_call_fun_t call;\n\n    // Implements unary and binary operations.\n    // Can return MP_OBJ_NULL if the operation is not supported.\n    mp_unary_op_fun_t unary_op;\n    mp_binary_op_fun_t binary_op;\n\n    // Implements load, store and delete attribute.\n    //\n    // dest[0] = MP_OBJ_NULL means load\n    //  return: for fail, do nothing\n    //          for attr, dest[0] = value\n    //          for method, dest[0] = method, dest[1] = self\n    //\n    // dest[0,1] = {MP_OBJ_SENTINEL, MP_OBJ_NULL} means delete\n    // dest[0,1] = {MP_OBJ_SENTINEL, object} means store\n    //  return: for fail, do nothing\n    //          for success set dest[0] = MP_OBJ_NULL\n    mp_attr_fun_t attr;\n\n    // Implements load, store and delete subscripting:\n    //  - value = MP_OBJ_SENTINEL means load\n    //  - value = MP_OBJ_NULL means delete\n    //  - all other values mean store the value\n    // Can return MP_OBJ_NULL if operation not supported.\n    mp_subscr_fun_t subscr;\n\n    // Corresponds to __iter__ special method.\n    // Can use the given mp_obj_iter_buf_t to store iterator object,\n    // otherwise can return a pointer to an object on the heap.\n    mp_getiter_fun_t getiter;\n\n    // Corresponds to __next__ special method.  May return MP_OBJ_STOP_ITERATION\n    // as an optimisation instead of raising StopIteration() with no args.\n    mp_fun_1_t iternext;\n\n    // Implements the buffer protocol if supported by this type.\n    mp_buffer_p_t buffer_p;\n\n    // One of disjoint protocols (interfaces), like mp_stream_p_t, etc.\n    const void *protocol;\n\n    // A pointer to the parents of this type:\n    //  - 0 parents: pointer is NULL (object is implicitly the single parent)\n    //  - 1 parent: a pointer to the type of that parent\n    //  - 2 or more parents: pointer to a tuple object containing the parent types\n    const void *parent;\n\n    // A dict mapping qstrs to objects local methods/constants/etc.\n    struct _mp_obj_dict_t *locals_dict;\n};\n\n// Constant types, globally accessible\nextern const mp_obj_type_t mp_type_type;\nextern const mp_obj_type_t mp_type_object;\nextern const mp_obj_type_t mp_type_NoneType;\nextern const mp_obj_type_t mp_type_bool;\nextern const mp_obj_type_t mp_type_int;\nextern const mp_obj_type_t mp_type_str;\nextern const mp_obj_type_t mp_type_bytes;\nextern const mp_obj_type_t mp_type_bytearray;\nextern const mp_obj_type_t mp_type_memoryview;\nextern const mp_obj_type_t mp_type_float;\nextern const mp_obj_type_t mp_type_complex;\nextern const mp_obj_type_t mp_type_tuple;\nextern const mp_obj_type_t mp_type_list;\nextern const mp_obj_type_t mp_type_map; // map (the python builtin, not the dict implementation detail)\nextern const mp_obj_type_t mp_type_enumerate;\nextern const mp_obj_type_t mp_type_filter;\nextern const mp_obj_type_t mp_type_deque;\nextern const mp_obj_type_t mp_type_dict;\nextern const mp_obj_type_t mp_type_ordereddict;\nextern const mp_obj_type_t mp_type_range;\nextern const mp_obj_type_t mp_type_set;\nextern const mp_obj_type_t mp_type_frozenset;\nextern const mp_obj_type_t mp_type_slice;\nextern const mp_obj_type_t mp_type_zip;\nextern const mp_obj_type_t mp_type_array;\nextern const mp_obj_type_t mp_type_super;\nextern const mp_obj_type_t mp_type_gen_wrap;\nextern const mp_obj_type_t mp_type_native_gen_wrap;\nextern const mp_obj_type_t mp_type_gen_instance;\nextern const mp_obj_type_t mp_type_fun_builtin_0;\nextern const mp_obj_type_t mp_type_fun_builtin_1;\nextern const mp_obj_type_t mp_type_fun_builtin_2;\nextern const mp_obj_type_t mp_type_fun_builtin_3;\nextern const mp_obj_type_t mp_type_fun_builtin_var;\nextern const mp_obj_type_t mp_type_fun_bc;\nextern const mp_obj_type_t mp_type_module;\nextern const mp_obj_type_t mp_type_staticmethod;\nextern const mp_obj_type_t mp_type_classmethod;\nextern const mp_obj_type_t mp_type_property;\nextern const mp_obj_type_t mp_type_stringio;\nextern const mp_obj_type_t mp_type_bytesio;\nextern const mp_obj_type_t mp_type_reversed;\nextern const mp_obj_type_t mp_type_polymorph_iter;\n\n// Exceptions\nextern const mp_obj_type_t mp_type_BaseException;\nextern const mp_obj_type_t mp_type_ArithmeticError;\nextern const mp_obj_type_t mp_type_AssertionError;\nextern const mp_obj_type_t mp_type_AttributeError;\nextern const mp_obj_type_t mp_type_EOFError;\nextern const mp_obj_type_t mp_type_Exception;\nextern const mp_obj_type_t mp_type_GeneratorExit;\nextern const mp_obj_type_t mp_type_ImportError;\nextern const mp_obj_type_t mp_type_IndentationError;\nextern const mp_obj_type_t mp_type_IndexError;\nextern const mp_obj_type_t mp_type_KeyboardInterrupt;\nextern const mp_obj_type_t mp_type_KeyError;\nextern const mp_obj_type_t mp_type_LookupError;\nextern const mp_obj_type_t mp_type_MemoryError;\nextern const mp_obj_type_t mp_type_NameError;\nextern const mp_obj_type_t mp_type_NotImplementedError;\nextern const mp_obj_type_t mp_type_OSError;\nextern const mp_obj_type_t mp_type_OverflowError;\nextern const mp_obj_type_t mp_type_RuntimeError;\nextern const mp_obj_type_t mp_type_StopAsyncIteration;\nextern const mp_obj_type_t mp_type_StopIteration;\nextern const mp_obj_type_t mp_type_SyntaxError;\nextern const mp_obj_type_t mp_type_SystemExit;\nextern const mp_obj_type_t mp_type_TypeError;\nextern const mp_obj_type_t mp_type_UnicodeError;\nextern const mp_obj_type_t mp_type_ValueError;\nextern const mp_obj_type_t mp_type_ViperTypeError;\nextern const mp_obj_type_t mp_type_ZeroDivisionError;\n\n// Constant objects, globally accessible: None, False, True\n// These should always be accessed via the below macros.\n#if MICROPY_OBJ_IMMEDIATE_OBJS\n// None is even while False/True are odd so their types can be distinguished with 1 bit.\n#define mp_const_none MP_OBJ_NEW_IMMEDIATE_OBJ(0)\n#define mp_const_false MP_OBJ_NEW_IMMEDIATE_OBJ(1)\n#define mp_const_true MP_OBJ_NEW_IMMEDIATE_OBJ(3)\n#else\n#define mp_const_none (MP_OBJ_FROM_PTR(&mp_const_none_obj))\n#define mp_const_false (MP_OBJ_FROM_PTR(&mp_const_false_obj))\n#define mp_const_true (MP_OBJ_FROM_PTR(&mp_const_true_obj))\nextern const struct _mp_obj_none_t mp_const_none_obj;\nextern const struct _mp_obj_bool_t mp_const_false_obj;\nextern const struct _mp_obj_bool_t mp_const_true_obj;\n#endif\n\n// Constant objects, globally accessible: b'', (), {}, Ellipsis, NotImplemented, GeneratorExit()\n// The below macros are for convenience only.\n#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj))\n#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj))\n#define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj))\nextern const struct _mp_obj_str_t mp_const_empty_bytes_obj;\nextern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj;\nextern const struct _mp_obj_dict_t mp_const_empty_dict_obj;\nextern const struct _mp_obj_singleton_t mp_const_ellipsis_obj;\nextern const struct _mp_obj_singleton_t mp_const_notimplemented_obj;\nextern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj;\n\n// Fixed empty map. Useful when calling keyword-receiving functions\n// without any keywords from C, etc.\n#define mp_const_empty_map (mp_const_empty_dict_obj.map)\n\n// General API for objects\n\n// These macros are derived from more primitive ones and are used to\n// check for more specific object types.\n// Note: these are kept as macros because inline functions sometimes use much\n// more code space than the equivalent macros, depending on the compiler.\n#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\n#if MICROPY_OBJ_IMMEDIATE_OBJS\n// bool's are immediates, not real objects, so test for the 2 possible values.\n#define mp_obj_is_bool(o) ((o) == mp_const_false || (o) == mp_const_true)\n#else\n#define mp_obj_is_bool(o) mp_obj_is_type(o, &mp_type_bool)\n#endif\n#define mp_obj_is_int(o) (mp_obj_is_small_int(o) || mp_obj_is_type(o, &mp_type_int))\n#define mp_obj_is_str(o) (mp_obj_is_qstr(o) || mp_obj_is_type(o, &mp_type_str))\n#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))\n#define mp_obj_is_dict_or_ordereddict(o) (mp_obj_is_obj(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->make_new == mp_obj_dict_make_new)\n#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))\n\nmp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict);\nstatic inline mp_obj_t mp_obj_new_bool(mp_int_t x) {\n    return x ? mp_const_true : mp_const_false;\n}\nmp_obj_t mp_obj_new_cell(mp_obj_t obj);\nmp_obj_t mp_obj_new_int(mp_int_t value);\nmp_obj_t mp_obj_new_int_from_uint(mp_uint_t value);\nmp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base);\nmp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception)\nmp_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)\nmp_obj_t mp_obj_new_str(const char *data, size_t len);\nmp_obj_t mp_obj_new_str_via_qstr(const char *data, size_t len);\nmp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr);\nmp_obj_t mp_obj_new_bytes(const byte *data, size_t len);\nmp_obj_t mp_obj_new_bytearray(size_t n, void *items);\nmp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items);\n#if MICROPY_PY_BUILTINS_FLOAT\nmp_obj_t mp_obj_new_int_from_float(mp_float_t val);\nmp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);\n#endif\nmp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);\nmp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);\nmp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args);\nmp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg);\nmp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)\n#ifdef va_start\nmp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list arg); // same fmt restrictions as above\n#endif\nmp_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);\nmp_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);\nmp_obj_t mp_obj_new_fun_asm(size_t n_args, const void *fun_data, mp_uint_t type_sig);\nmp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);\nmp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed);\nmp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items);\nmp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items);\nmp_obj_t mp_obj_new_dict(size_t n_args);\nmp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items);\nmp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step);\nmp_obj_t mp_obj_new_bound_meth(mp_obj_t meth, mp_obj_t self);\nmp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf);\nmp_obj_t mp_obj_new_module(qstr module_name);\nmp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items);\n\nconst mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in);\nconst char *mp_obj_get_type_str(mp_const_obj_t o_in);\nbool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects\nmp_obj_t mp_obj_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type);\n\nvoid mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);\nvoid mp_obj_print(mp_obj_t o, mp_print_kind_t kind);\nvoid mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc);\n\nbool mp_obj_is_true(mp_obj_t arg);\nbool mp_obj_is_callable(mp_obj_t o_in);\nmp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2);\nbool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);\n\nstatic inline bool mp_obj_is_integer(mp_const_obj_t o) {\n    return mp_obj_is_int(o) || mp_obj_is_bool(o);\n}                                                                                                        // returns true if o is bool, small int or long int\nmp_int_t mp_obj_get_int(mp_const_obj_t arg);\nmp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg);\nbool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value);\n#if MICROPY_PY_BUILTINS_FLOAT\nmp_float_t mp_obj_get_float(mp_obj_t self_in);\nbool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value);\nvoid mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);\nbool mp_obj_get_complex_maybe(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);\n#endif\nvoid mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items); // *items may point inside a GC block\nvoid mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items); // *items may point inside a GC block\nsize_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice);\nmp_obj_t mp_obj_id(mp_obj_t o_in);\nmp_obj_t mp_obj_len(mp_obj_t o_in);\nmp_obj_t mp_obj_len_maybe(mp_obj_t o_in); // may return MP_OBJ_NULL\nmp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t val);\nmp_obj_t mp_generic_unary_op(mp_unary_op_t op, mp_obj_t o_in);\n\n// cell\nmp_obj_t mp_obj_cell_get(mp_obj_t self_in);\nvoid mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj);\n\n// int\n// For long int, returns value truncated to mp_int_t\nmp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in);\n// Will raise exception if value doesn't fit into mp_int_t\nmp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in);\n// Will raise exception if value is negative or doesn't fit into mp_uint_t\nmp_uint_t mp_obj_int_get_uint_checked(mp_const_obj_t self_in);\n\n// exception\n#define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new)\nbool mp_obj_is_exception_type(mp_obj_t self_in);\nbool mp_obj_is_exception_instance(mp_obj_t self_in);\nbool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type);\nvoid mp_obj_exception_clear_traceback(mp_obj_t self_in);\nvoid mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block);\nvoid mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values);\nmp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);\nmp_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);\nmp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);\nvoid mp_init_emergency_exception_buf(void);\n\n// str\nbool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2);\nqstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway convert the string to a qstr\nconst char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated\nconst char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len);\nmp_obj_t mp_obj_str_intern(mp_obj_t str);\nmp_obj_t mp_obj_str_intern_checked(mp_obj_t obj);\nvoid mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes);\n\n#if MICROPY_PY_BUILTINS_FLOAT\n// float\n#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\nstatic inline float mp_obj_get_float_to_f(mp_obj_t o) {\n    return mp_obj_get_float(o);\n}\n\nstatic inline double mp_obj_get_float_to_d(mp_obj_t o) {\n    return (double)mp_obj_get_float(o);\n}\n\nstatic inline mp_obj_t mp_obj_new_float_from_f(float o) {\n    return mp_obj_new_float(o);\n}\n\nstatic inline mp_obj_t mp_obj_new_float_from_d(double o) {\n    return mp_obj_new_float((mp_float_t)o);\n}\n#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE\nstatic inline float mp_obj_get_float_to_f(mp_obj_t o) {\n    return (float)mp_obj_get_float(o);\n}\n\nstatic inline double mp_obj_get_float_to_d(mp_obj_t o) {\n    return mp_obj_get_float(o);\n}\n\nstatic inline mp_obj_t mp_obj_new_float_from_f(float o) {\n    return mp_obj_new_float((mp_float_t)o);\n}\n\nstatic inline mp_obj_t mp_obj_new_float_from_d(double o) {\n    return mp_obj_new_float(o);\n}\n#endif\n#if MICROPY_FLOAT_HIGH_QUALITY_HASH\nmp_int_t mp_float_hash(mp_float_t val);\n#else\nstatic inline mp_int_t mp_float_hash(mp_float_t val) {\n    return (mp_int_t)val;\n}\n#endif\nmp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported\n\n// complex\nvoid mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);\nmp_obj_t mp_obj_complex_binary_op(mp_binary_op_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\n#else\n#define mp_obj_is_float(o) (false)\n#endif\n\n// tuple\nvoid mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items);\nvoid mp_obj_tuple_del(mp_obj_t self_in);\nmp_int_t mp_obj_tuple_hash(mp_obj_t self_in);\n\n// list\nmp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg);\nmp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value);\nvoid mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items);\nvoid mp_obj_list_set_len(mp_obj_t self_in, size_t len);\nvoid mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value);\nmp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);\n\n// dict\ntypedef struct _mp_obj_dict_t {\n    mp_obj_base_t base;\n    mp_map_t map;\n} mp_obj_dict_t;\nmp_obj_t mp_obj_dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);\nvoid mp_obj_dict_init(mp_obj_dict_t *dict, size_t n_args);\nsize_t mp_obj_dict_len(mp_obj_t self_in);\nmp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index);\nmp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);\nmp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key);\nmp_obj_t mp_obj_dict_copy(mp_obj_t self_in);\nstatic inline mp_map_t *mp_obj_dict_get_map(mp_obj_t dict) {\n    return &((mp_obj_dict_t *)MP_OBJ_TO_PTR(dict))->map;\n}\n\n// set\nvoid mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);\n\n// slice indexes resolved to particular sequence\ntypedef struct {\n    mp_int_t start;\n    mp_int_t stop;\n    mp_int_t step;\n} mp_bound_slice_t;\n\n// slice\ntypedef struct _mp_obj_slice_t {\n    mp_obj_base_t base;\n    mp_obj_t start;\n    mp_obj_t stop;\n    mp_obj_t step;\n} mp_obj_slice_t;\nvoid mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result);\n\n// functions\n\ntypedef struct _mp_obj_fun_builtin_fixed_t {\n    mp_obj_base_t base;\n    union {\n        mp_fun_0_t _0;\n        mp_fun_1_t _1;\n        mp_fun_2_t _2;\n        mp_fun_3_t _3;\n    } fun;\n} mp_obj_fun_builtin_fixed_t;\n\ntypedef struct _mp_obj_fun_builtin_var_t {\n    mp_obj_base_t base;\n    uint32_t sig; // see MP_OBJ_FUN_MAKE_SIG\n    union {\n        mp_fun_var_t var;\n        mp_fun_kw_t kw;\n    } fun;\n} mp_obj_fun_builtin_var_t;\n\nqstr mp_obj_fun_get_name(mp_const_obj_t fun);\nqstr mp_obj_code_get_name(const byte *code_info);\n\nmp_obj_t mp_identity(mp_obj_t self);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_identity_obj);\nmp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf);\n\n// module\ntypedef struct _mp_obj_module_t {\n    mp_obj_base_t base;\n    mp_obj_dict_t *globals;\n} mp_obj_module_t;\nstatic inline mp_obj_dict_t *mp_obj_module_get_globals(mp_obj_t module) {\n    return ((mp_obj_module_t *)MP_OBJ_TO_PTR(module))->globals;\n}\n// check if given module object is a package\nbool mp_obj_is_package(mp_obj_t module);\n\n// staticmethod and classmethod types; defined here so we can make const versions\n// this structure is used for instances of both staticmethod and classmethod\ntypedef struct _mp_obj_static_class_method_t {\n    mp_obj_base_t base;\n    mp_obj_t fun;\n} mp_obj_static_class_method_t;\ntypedef struct _mp_rom_obj_static_class_method_t {\n    mp_obj_base_t base;\n    mp_rom_obj_t fun;\n} mp_rom_obj_static_class_method_t;\n\n// property\nconst mp_obj_t *mp_obj_property_get(mp_obj_t self_in);\n\n// sequence helpers\n\nvoid mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest);\n#if MICROPY_PY_BUILTINS_SLICE\nbool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes);\n#endif\n#define mp_seq_copy(dest, src, len, item_t) memcpy(dest, src, len * sizeof(item_t))\n#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)); }\nbool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte *data2, size_t len2);\nbool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp_obj_t *items2, size_t len2);\nmp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args);\nmp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value);\nmp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes);\n\n// Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems\n#define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte *)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz))\n\n// Note: dest and slice regions may overlap\n#define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_sz) \\\n    memmove(((char *)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); \\\n    memmove(((char *)dest) + (beg + slice_len) * (item_sz), ((char *)dest) + (end) * (item_sz), (dest_len - end) * (item_sz));\n\n// Note: dest and slice regions may overlap\n#define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_sz) \\\n    memmove(((char *)dest) + (beg + slice_len) * (item_sz), ((char *)dest) + (end) * (item_sz), ((dest_len) + (len_adj) - ((beg) + (slice_len))) * (item_sz)); \\\n    memmove(((char *)dest) + (beg) * (item_sz), slice, slice_len * (item_sz));\n\n// Provide translation for legacy API\n#define MP_OBJ_IS_SMALL_INT mp_obj_is_small_int\n#define MP_OBJ_IS_QSTR mp_obj_is_qstr\n#define MP_OBJ_IS_OBJ mp_obj_is_obj\n#define MP_OBJ_IS_INT mp_obj_is_int\n#define MP_OBJ_IS_TYPE mp_obj_is_type\n#define MP_OBJ_IS_STR mp_obj_is_str\n#define MP_OBJ_IS_STR_OR_BYTES mp_obj_is_str_or_bytes\n#define MP_OBJ_IS_FUN mp_obj_is_fun\n#define MP_MAP_SLOT_IS_FILLED mp_map_slot_is_filled\n#define MP_SET_SLOT_IS_FILLED mp_set_slot_is_filled\n\n#endif // MICROPY_INCLUDED_PY_OBJ_H\n"
  },
  {
    "path": "py/objarray.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <assert.h>\n#include <stdint.h>\n\n#include \"py/runtime.h\"\n#include \"py/binary.h\"\n#include \"py/objstr.h\"\n#include \"py/objarray.h\"\n\n#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW\n\n// About memoryview object: We want to reuse as much code as possible from\n// array, and keep the memoryview object 4 words in size so it fits in 1 GC\n// block.  Also, memoryview must keep a pointer to the base of the buffer so\n// that the buffer is not GC'd if the original parent object is no longer\n// around (we are assuming that all memoryview'able objects return a pointer\n// which points to the start of a GC chunk).  Given the above constraints we\n// do the following:\n//  - typecode high bit is set if the buffer is read-write (else read-only)\n//  - free is the offset in elements to the first item in the memoryview\n//  - len is the length in elements\n//  - items points to the start of the original buffer\n// Note that we don't handle the case where the original buffer might change\n// size due to a resize of the original parent object.\n\n#if MICROPY_PY_BUILTINS_MEMORYVIEW\n#define TYPECODE_MASK (0x7f)\n#define memview_offset free\n#else\n// make (& TYPECODE_MASK) a null operation if memorview not enabled\n#define TYPECODE_MASK (~(size_t)0)\n// memview_offset should not be accessed if memoryview is not enabled,\n// so not defined to catch errors\n#endif\n\nSTATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf);\nSTATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);\nSTATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in);\nSTATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);\n\n/******************************************************************************/\n// array\n\n#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY\nSTATIC void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);\n    if (o->typecode == BYTEARRAY_TYPECODE) {\n        mp_print_str(print, \"bytearray(b\");\n        mp_str_print_quoted(print, o->items, o->len, true);\n    } else {\n        mp_printf(print, \"array('%c'\", o->typecode);\n        if (o->len > 0) {\n            mp_print_str(print, \", [\");\n            for (size_t i = 0; i < o->len; i++) {\n                if (i > 0) {\n                    mp_print_str(print, \", \");\n                }\n                mp_obj_print_helper(print, mp_binary_get_val_array(o->typecode, o->items, i), PRINT_REPR);\n            }\n            mp_print_str(print, \"]\");\n        }\n    }\n    mp_print_str(print, \")\");\n}\n#endif\n\n#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY\nSTATIC mp_obj_array_t *array_new(char typecode, size_t n) {\n    int typecode_size = mp_binary_get_size('@', typecode, NULL);\n    mp_obj_array_t *o = m_new_obj(mp_obj_array_t);\n    #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY\n    o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;\n    #elif MICROPY_PY_BUILTINS_BYTEARRAY\n    o->base.type = &mp_type_bytearray;\n    #else\n    o->base.type = &mp_type_array;\n    #endif\n    o->typecode = typecode;\n    o->free = 0;\n    o->len = n;\n    o->items = m_new(byte, typecode_size * o->len);\n    return o;\n}\n#endif\n\n#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY\nSTATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {\n    // bytearrays can be raw-initialised from anything with the buffer protocol\n    // other arrays can only be raw-initialised from bytes and bytearray objects\n    mp_buffer_info_t bufinfo;\n    if (((MICROPY_PY_BUILTINS_BYTEARRAY\n          && typecode == BYTEARRAY_TYPECODE)\n         || (MICROPY_PY_ARRAY\n             && (mp_obj_is_type(initializer, &mp_type_bytes)\n                 || (MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(initializer, &mp_type_bytearray)))))\n        && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) {\n        // construct array from raw bytes\n        // we round-down the len to make it a multiple of sz (CPython raises error)\n        size_t sz = mp_binary_get_size('@', typecode, NULL);\n        size_t len = bufinfo.len / sz;\n        mp_obj_array_t *o = array_new(typecode, len);\n        memcpy(o->items, bufinfo.buf, len * sz);\n        return MP_OBJ_FROM_PTR(o);\n    }\n\n    size_t len;\n    // Try to create array of exact len if initializer len is known\n    mp_obj_t len_in = mp_obj_len_maybe(initializer);\n    if (len_in == MP_OBJ_NULL) {\n        len = 0;\n    } else {\n        len = MP_OBJ_SMALL_INT_VALUE(len_in);\n    }\n\n    mp_obj_array_t *array = array_new(typecode, len);\n\n    mp_obj_t iterable = mp_getiter(initializer, NULL);\n    mp_obj_t item;\n    size_t i = 0;\n    while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n        if (len == 0) {\n            array_append(MP_OBJ_FROM_PTR(array), item);\n        } else {\n            mp_binary_set_val_array(typecode, array->items, i++, item);\n        }\n    }\n\n    return MP_OBJ_FROM_PTR(array);\n}\n#endif\n\n#if MICROPY_PY_ARRAY\nSTATIC 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) {\n    (void)type_in;\n    mp_arg_check_num(n_args, n_kw, 1, 2, false);\n\n    // get typecode\n    const char *typecode = mp_obj_str_get_str(args[0]);\n\n    if (n_args == 1) {\n        // 1 arg: make an empty array\n        return MP_OBJ_FROM_PTR(array_new(*typecode, 0));\n    } else {\n        // 2 args: construct the array from the given object\n        return array_construct(*typecode, args[1]);\n    }\n}\n#endif\n\n#if MICROPY_PY_BUILTINS_BYTEARRAY\nSTATIC 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) {\n    (void)type_in;\n    // Can take 2nd/3rd arg if constructs from str\n    mp_arg_check_num(n_args, n_kw, 0, 3, false);\n\n    if (n_args == 0) {\n        // no args: construct an empty bytearray\n        return MP_OBJ_FROM_PTR(array_new(BYTEARRAY_TYPECODE, 0));\n    } else if (mp_obj_is_int(args[0])) {\n        // 1 arg, an integer: construct a blank bytearray of that length\n        mp_uint_t len = mp_obj_get_int(args[0]);\n        mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len);\n        memset(o->items, 0, len);\n        return MP_OBJ_FROM_PTR(o);\n    } else {\n        // 1 arg: construct the bytearray from that\n        return array_construct(BYTEARRAY_TYPECODE, args[0]);\n    }\n}\n#endif\n\n#if MICROPY_PY_BUILTINS_MEMORYVIEW\n\nmp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) {\n    mp_obj_array_t *self = m_new_obj(mp_obj_array_t);\n    self->base.type = &mp_type_memoryview;\n    self->typecode = typecode;\n    self->memview_offset = 0;\n    self->len = nitems;\n    self->items = items;\n    return MP_OBJ_FROM_PTR(self);\n}\n\nSTATIC 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) {\n    (void)type_in;\n\n    // TODO possibly allow memoryview constructor to take start/stop so that one\n    // can do memoryview(b, 4, 8) instead of memoryview(b)[4:8] (uses less RAM)\n\n    mp_arg_check_num(n_args, n_kw, 1, 1, false);\n\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);\n\n    mp_obj_array_t *self = MP_OBJ_TO_PTR(mp_obj_new_memoryview(bufinfo.typecode,\n        bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL),\n        bufinfo.buf));\n\n    // test if the object can be written to\n    if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) {\n        self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer\n    }\n\n    return MP_OBJ_FROM_PTR(self);\n}\n\n#if MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE\nSTATIC void memoryview_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] != MP_OBJ_NULL) {\n        return;\n    }\n    if (attr == MP_QSTR_itemsize) {\n        mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in);\n        dest[0] = MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->typecode & TYPECODE_MASK, NULL));\n    }\n}\n#endif\n\n#endif\n\nSTATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) {\n    mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(o->len != 0);\n        case MP_UNARY_OP_LEN:\n            return MP_OBJ_NEW_SMALL_INT(o->len);\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n\nSTATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    mp_obj_array_t *lhs = MP_OBJ_TO_PTR(lhs_in);\n    switch (op) {\n        case MP_BINARY_OP_ADD: {\n            // allow to add anything that has the buffer protocol (extension to CPython)\n            mp_buffer_info_t lhs_bufinfo;\n            mp_buffer_info_t rhs_bufinfo;\n            array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);\n            mp_get_buffer_raise(rhs_in, &rhs_bufinfo, MP_BUFFER_READ);\n\n            size_t sz = mp_binary_get_size('@', lhs_bufinfo.typecode, NULL);\n\n            // convert byte count to element count (in case rhs is not multiple of sz)\n            size_t rhs_len = rhs_bufinfo.len / sz;\n\n            // note: lhs->len is element count of lhs, lhs_bufinfo.len is byte count\n            mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len);\n            mp_seq_cat((byte *)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte);\n            return MP_OBJ_FROM_PTR(res);\n        }\n\n        case MP_BINARY_OP_INPLACE_ADD: {\n            #if MICROPY_PY_BUILTINS_MEMORYVIEW\n            if (lhs->base.type == &mp_type_memoryview) {\n                return MP_OBJ_NULL; // op not supported\n            }\n            #endif\n            array_extend(lhs_in, rhs_in);\n            return lhs_in;\n        }\n\n        case MP_BINARY_OP_CONTAINS: {\n            #if MICROPY_PY_BUILTINS_BYTEARRAY\n            // Can search string only in bytearray\n            mp_buffer_info_t lhs_bufinfo;\n            mp_buffer_info_t rhs_bufinfo;\n            if (mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {\n                if (!mp_obj_is_type(lhs_in, &mp_type_bytearray)) {\n                    return mp_const_false;\n                }\n                array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);\n                return mp_obj_new_bool(\n                    find_subbytes(lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len, 1) != NULL);\n            }\n            #endif\n\n            // Otherwise, can only look for a scalar numeric value in an array\n            if (mp_obj_is_int(rhs_in) || mp_obj_is_float(rhs_in)) {\n                mp_raise_NotImplementedError(NULL);\n            }\n\n            return mp_const_false;\n        }\n\n        case MP_BINARY_OP_EQUAL: {\n            mp_buffer_info_t lhs_bufinfo;\n            mp_buffer_info_t rhs_bufinfo;\n            array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);\n            if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {\n                return mp_const_false;\n            }\n            return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));\n        }\n\n        default:\n            return MP_OBJ_NULL; // op not supported\n    }\n}\n\n#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY\nSTATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) {\n    // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)\n    assert((MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(self_in, &mp_type_bytearray))\n        || (MICROPY_PY_ARRAY && mp_obj_is_type(self_in, &mp_type_array)));\n    mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (self->free == 0) {\n        size_t item_sz = mp_binary_get_size('@', self->typecode, NULL);\n        // TODO: alloc policy\n        self->free = 8;\n        self->items = m_renew(byte, self->items, item_sz * self->len, item_sz * (self->len + self->free));\n        mp_seq_clear(self->items, self->len + 1, self->len + self->free, item_sz);\n    }\n    mp_binary_set_val_array(self->typecode, self->items, self->len, arg);\n    // only update length/free if set succeeded\n    self->len++;\n    self->free--;\n    return mp_const_none; // return None, as per CPython\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(array_append_obj, array_append);\n\nSTATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) {\n    // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)\n    assert((MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(self_in, &mp_type_bytearray))\n        || (MICROPY_PY_ARRAY && mp_obj_is_type(self_in, &mp_type_array)));\n    mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in);\n\n    // allow to extend by anything that has the buffer protocol (extension to CPython)\n    mp_buffer_info_t arg_bufinfo;\n    mp_get_buffer_raise(arg_in, &arg_bufinfo, MP_BUFFER_READ);\n\n    size_t sz = mp_binary_get_size('@', self->typecode, NULL);\n\n    // convert byte count to element count\n    size_t len = arg_bufinfo.len / sz;\n\n    // make sure we have enough room to extend\n    // TODO: alloc policy; at the moment we go conservative\n    if (self->free < len) {\n        self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz);\n        self->free = 0;\n    } else {\n        self->free -= len;\n    }\n\n    // extend\n    mp_seq_copy((byte *)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte);\n    self->len += len;\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(array_extend_obj, array_extend);\n#endif\n\nSTATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {\n    if (value == MP_OBJ_NULL) {\n        // delete item\n        // TODO implement\n        // TODO: confirmed that both bytearray and array.array support\n        // slice deletion\n        return MP_OBJ_NULL; // op not supported\n    } else {\n        mp_obj_array_t *o = MP_OBJ_TO_PTR(self_in);\n        #if MICROPY_PY_BUILTINS_SLICE\n        if (mp_obj_is_type(index_in, &mp_type_slice)) {\n            mp_bound_slice_t slice;\n            if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {\n                mp_raise_NotImplementedError(MP_ERROR_TEXT(\"only slices with step=1 (aka None) are supported\"));\n            }\n            if (value != MP_OBJ_SENTINEL) {\n                #if MICROPY_PY_ARRAY_SLICE_ASSIGN\n                // Assign\n                size_t src_len;\n                void *src_items;\n                size_t item_sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);\n                if (mp_obj_is_obj(value) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) {\n                    // value is array, bytearray or memoryview\n                    mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value);\n                    if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) {\n                    compat_error:\n                        mp_raise_ValueError(MP_ERROR_TEXT(\"lhs and rhs should be compatible\"));\n                    }\n                    src_len = src_slice->len;\n                    src_items = src_slice->items;\n                    #if MICROPY_PY_BUILTINS_MEMORYVIEW\n                    if (mp_obj_is_type(value, &mp_type_memoryview)) {\n                        src_items = (uint8_t *)src_items + (src_slice->memview_offset * item_sz);\n                    }\n                    #endif\n                } else if (mp_obj_is_type(value, &mp_type_bytes)) {\n                    if (item_sz != 1) {\n                        goto compat_error;\n                    }\n                    mp_buffer_info_t bufinfo;\n                    mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ);\n                    src_len = bufinfo.len;\n                    src_items = bufinfo.buf;\n                } else {\n                    mp_raise_NotImplementedError(MP_ERROR_TEXT(\"array/bytes required on right side\"));\n                }\n\n                // TODO: check src/dst compat\n                mp_int_t len_adj = src_len - (slice.stop - slice.start);\n                uint8_t *dest_items = o->items;\n                #if MICROPY_PY_BUILTINS_MEMORYVIEW\n                if (o->base.type == &mp_type_memoryview) {\n                    if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {\n                        // store to read-only memoryview not allowed\n                        return MP_OBJ_NULL;\n                    }\n                    if (len_adj != 0) {\n                        goto compat_error;\n                    }\n                    dest_items += o->memview_offset * item_sz;\n                }\n                #endif\n                if (len_adj > 0) {\n                    if ((size_t)len_adj > o->free) {\n                        // TODO: alloc policy; at the moment we go conservative\n                        o->items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz);\n                        o->free = len_adj;\n                        dest_items = o->items;\n                    }\n                    mp_seq_replace_slice_grow_inplace(dest_items, o->len,\n                        slice.start, slice.stop, src_items, src_len, len_adj, item_sz);\n                } else {\n                    mp_seq_replace_slice_no_grow(dest_items, o->len,\n                        slice.start, slice.stop, src_items, src_len, item_sz);\n                    // Clear \"freed\" elements at the end of list\n                    // TODO: This is actually only needed for typecode=='O'\n                    mp_seq_clear(dest_items, o->len + len_adj, o->len, item_sz);\n                    // TODO: alloc policy after shrinking\n                }\n                o->free -= len_adj;\n                o->len += len_adj;\n                return mp_const_none;\n                #else\n                return MP_OBJ_NULL; // op not supported\n                #endif\n            }\n\n            mp_obj_array_t *res;\n            size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);\n            assert(sz > 0);\n            #if MICROPY_PY_BUILTINS_MEMORYVIEW\n            if (o->base.type == &mp_type_memoryview) {\n                res = m_new_obj(mp_obj_array_t);\n                *res = *o;\n                res->memview_offset += slice.start;\n                res->len = slice.stop - slice.start;\n            } else\n            #endif\n            {\n                res = array_new(o->typecode, slice.stop - slice.start);\n                memcpy(res->items, (uint8_t *)o->items + slice.start * sz, (slice.stop - slice.start) * sz);\n            }\n            return MP_OBJ_FROM_PTR(res);\n        } else\n        #endif\n        {\n            size_t index = mp_get_index(o->base.type, o->len, index_in, false);\n            #if MICROPY_PY_BUILTINS_MEMORYVIEW\n            if (o->base.type == &mp_type_memoryview) {\n                index += o->memview_offset;\n                if (value != MP_OBJ_SENTINEL && !(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {\n                    // store to read-only memoryview\n                    return MP_OBJ_NULL;\n                }\n            }\n            #endif\n            if (value == MP_OBJ_SENTINEL) {\n                // load\n                return mp_binary_get_val_array(o->typecode & TYPECODE_MASK, o->items, index);\n            } else {\n                // store\n                mp_binary_set_val_array(o->typecode & TYPECODE_MASK, o->items, index, value);\n                return mp_const_none;\n            }\n        }\n    }\n}\n\nSTATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {\n    mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);\n    size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);\n    bufinfo->buf = o->items;\n    bufinfo->len = o->len * sz;\n    bufinfo->typecode = o->typecode & TYPECODE_MASK;\n    #if MICROPY_PY_BUILTINS_MEMORYVIEW\n    if (o->base.type == &mp_type_memoryview) {\n        if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW) && (flags & MP_BUFFER_WRITE)) {\n            // read-only memoryview\n            return 1;\n        }\n        bufinfo->buf = (uint8_t *)bufinfo->buf + (size_t)o->memview_offset * sz;\n    }\n    #else\n    (void)flags;\n    #endif\n    return 0;\n}\n\n#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY\nSTATIC const mp_rom_map_elem_t array_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&array_append_obj) },\n    { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&array_extend_obj) },\n    #if MICROPY_CPYTHON_COMPAT\n    { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&bytes_decode_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table);\n#endif\n\n#if MICROPY_PY_ARRAY\nconst mp_obj_type_t mp_type_array = {\n    { &mp_type_type },\n    .name = MP_QSTR_array,\n    .print = array_print,\n    .make_new = array_make_new,\n    .getiter = array_iterator_new,\n    .unary_op = array_unary_op,\n    .binary_op = array_binary_op,\n    .subscr = array_subscr,\n    .buffer_p = { .get_buffer = array_get_buffer },\n    .locals_dict = (mp_obj_dict_t *)&array_locals_dict,\n};\n#endif\n\n#if MICROPY_PY_BUILTINS_BYTEARRAY\nconst mp_obj_type_t mp_type_bytearray = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,\n    .name = MP_QSTR_bytearray,\n    .print = array_print,\n    .make_new = bytearray_make_new,\n    .getiter = array_iterator_new,\n    .unary_op = array_unary_op,\n    .binary_op = array_binary_op,\n    .subscr = array_subscr,\n    .buffer_p = { .get_buffer = array_get_buffer },\n    .locals_dict = (mp_obj_dict_t *)&array_locals_dict,\n};\n#endif\n\n#if MICROPY_PY_BUILTINS_MEMORYVIEW\nconst mp_obj_type_t mp_type_memoryview = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,\n    .name = MP_QSTR_memoryview,\n    .make_new = memoryview_make_new,\n    .getiter = array_iterator_new,\n    .unary_op = array_unary_op,\n    .binary_op = array_binary_op,\n    #if MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE\n    .attr = memoryview_attr,\n    #endif\n    .subscr = array_subscr,\n    .buffer_p = { .get_buffer = array_get_buffer },\n};\n#endif\n\n/* unused\nsize_t mp_obj_array_len(mp_obj_t self_in) {\n    return ((mp_obj_array_t *)self_in)->len;\n}\n*/\n\n#if MICROPY_PY_BUILTINS_BYTEARRAY\nmp_obj_t mp_obj_new_bytearray(size_t n, void *items) {\n    mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);\n    memcpy(o->items, items, n);\n    return MP_OBJ_FROM_PTR(o);\n}\n\n// Create bytearray which references specified memory area\nmp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items) {\n    mp_obj_array_t *o = m_new_obj(mp_obj_array_t);\n    o->base.type = &mp_type_bytearray;\n    o->typecode = BYTEARRAY_TYPECODE;\n    o->free = 0;\n    o->len = n;\n    o->items = items;\n    return MP_OBJ_FROM_PTR(o);\n}\n#endif\n\n/******************************************************************************/\n// array iterator\n\ntypedef struct _mp_obj_array_it_t {\n    mp_obj_base_t base;\n    mp_obj_array_t *array;\n    size_t offset;\n    size_t cur;\n} mp_obj_array_it_t;\n\nSTATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {\n    mp_obj_array_it_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->cur < self->array->len) {\n        return mp_binary_get_val_array(self->array->typecode & TYPECODE_MASK, self->array->items, self->offset + self->cur++);\n    } else {\n        return MP_OBJ_STOP_ITERATION;\n    }\n}\n\nSTATIC const mp_obj_type_t array_it_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_iterator,\n    .getiter = mp_identity_getiter,\n    .iternext = array_it_iternext,\n};\n\nSTATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf) {\n    assert(sizeof(mp_obj_array_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_obj_array_t *array = MP_OBJ_TO_PTR(array_in);\n    mp_obj_array_it_t *o = (mp_obj_array_it_t *)iter_buf;\n    o->base.type = &array_it_type;\n    o->array = array;\n    o->offset = 0;\n    o->cur = 0;\n    #if MICROPY_PY_BUILTINS_MEMORYVIEW\n    if (array->base.type == &mp_type_memoryview) {\n        o->offset = array->memview_offset;\n    }\n    #endif\n    return MP_OBJ_FROM_PTR(o);\n}\n\n#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW\n"
  },
  {
    "path": "py/objarray.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJARRAY_H\n#define MICROPY_INCLUDED_PY_OBJARRAY_H\n\n#include \"py/obj.h\"\n\n// Used only for memoryview types, set in \"typecode\" to indicate a writable memoryview\n#define MP_OBJ_ARRAY_TYPECODE_FLAG_RW (0x80)\n\n// This structure is used for all of bytearray, array.array, memoryview\n// objects.  Note that memoryview has different meaning for some fields,\n// see comment at the beginning of objarray.c.\ntypedef struct _mp_obj_array_t {\n    mp_obj_base_t base;\n    size_t typecode : 8;\n    // free is number of unused elements after len used elements\n    // alloc size = len + free\n    // But for memoryview, 'free' is reused as offset (in elements) into the\n    // parent object. (Union is not used to not go into a complication of\n    // union-of-bitfields with different toolchains). See comments in\n    // objarray.c.\n    size_t free : (8 * sizeof(size_t) - 8);\n    size_t len; // in elements\n    void *items;\n} mp_obj_array_t;\n\n#if MICROPY_PY_BUILTINS_MEMORYVIEW\nstatic inline void mp_obj_memoryview_init(mp_obj_array_t *self, size_t typecode, size_t offset, size_t len, void *items) {\n    self->base.type = &mp_type_memoryview;\n    self->typecode = typecode;\n    self->free = offset;\n    self->len = len;\n    self->items = items;\n}\n#endif\n\n#endif // MICROPY_INCLUDED_PY_OBJARRAY_H\n"
  },
  {
    "path": "py/objattrtuple.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/objtuple.h\"\n\n#if MICROPY_PY_ATTRTUPLE || MICROPY_PY_COLLECTIONS\n\n// this helper function is used by collections.namedtuple\n#if !MICROPY_PY_COLLECTIONS\nSTATIC\n#endif\nvoid mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields, mp_obj_tuple_t *o) {\n    mp_print_str(print, \"(\");\n    for (size_t i = 0; i < o->len; i++) {\n        if (i > 0) {\n            mp_print_str(print, \", \");\n        }\n        mp_printf(print, \"%q=\", fields[i]);\n        mp_obj_print_helper(print, o->items[i], PRINT_REPR);\n    }\n    mp_print_str(print, \")\");\n}\n\n#endif\n\n#if MICROPY_PY_ATTRTUPLE\n\nSTATIC void mp_obj_attrtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_tuple_t *o = MP_OBJ_TO_PTR(o_in);\n    const qstr *fields = (const qstr *)MP_OBJ_TO_PTR(o->items[o->len]);\n    mp_obj_attrtuple_print_helper(print, fields, o);\n}\n\nSTATIC void mp_obj_attrtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] == MP_OBJ_NULL) {\n        // load attribute\n        mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);\n        size_t len = self->len;\n        const qstr *fields = (const qstr *)MP_OBJ_TO_PTR(self->items[len]);\n        for (size_t i = 0; i < len; i++) {\n            if (fields[i] == attr) {\n                dest[0] = self->items[i];\n                return;\n            }\n        }\n    }\n}\n\nmp_obj_t mp_obj_new_attrtuple(const qstr *fields, size_t n, const mp_obj_t *items) {\n    mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n + 1);\n    o->base.type = &mp_type_attrtuple;\n    o->len = n;\n    for (size_t i = 0; i < n; i++) {\n        o->items[i] = items[i];\n    }\n    o->items[n] = MP_OBJ_FROM_PTR(fields);\n    return MP_OBJ_FROM_PTR(o);\n}\n\nconst mp_obj_type_t mp_type_attrtuple = {\n    { &mp_type_type },\n    .name = MP_QSTR_tuple, // reuse tuple to save on a qstr\n    .print = mp_obj_attrtuple_print,\n    .unary_op = mp_obj_tuple_unary_op,\n    .binary_op = mp_obj_tuple_binary_op,\n    .attr = mp_obj_attrtuple_attr,\n    .subscr = mp_obj_tuple_subscr,\n    .getiter = mp_obj_tuple_getiter,\n};\n\n#endif // MICROPY_PY_ATTRTUPLE\n"
  },
  {
    "path": "py/objbool.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n\n#include \"py/runtime.h\"\n\n#if MICROPY_OBJ_IMMEDIATE_OBJS\n\n#define BOOL_VALUE(o) ((o) == mp_const_false ? 0 : 1)\n\n#else\n\n#define BOOL_VALUE(o) (((mp_obj_bool_t *)MP_OBJ_TO_PTR(o))->value)\n\ntypedef struct _mp_obj_bool_t {\n    mp_obj_base_t base;\n    bool value;\n} mp_obj_bool_t;\n\n#endif\n\nSTATIC void bool_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    bool value = BOOL_VALUE(self_in);\n    if (MICROPY_PY_UJSON && kind == PRINT_JSON) {\n        if (value) {\n            mp_print_str(print, \"true\");\n        } else {\n            mp_print_str(print, \"false\");\n        }\n    } else {\n        if (value) {\n            mp_print_str(print, \"True\");\n        } else {\n            mp_print_str(print, \"False\");\n        }\n    }\n}\n\nSTATIC 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) {\n    (void)type_in;\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n\n    if (n_args == 0) {\n        return mp_const_false;\n    } else {\n        return mp_obj_new_bool(mp_obj_is_true(args[0]));\n    }\n}\n\nSTATIC mp_obj_t bool_unary_op(mp_unary_op_t op, mp_obj_t o_in) {\n    if (op == MP_UNARY_OP_LEN) {\n        return MP_OBJ_NULL;\n    }\n    bool value = BOOL_VALUE(o_in);\n    return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(value));\n}\n\nSTATIC mp_obj_t bool_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    bool value = BOOL_VALUE(lhs_in);\n    return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(value), rhs_in);\n}\n\nconst mp_obj_type_t mp_type_bool = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE, // can match all numeric types\n    .name = MP_QSTR_bool,\n    .print = bool_print,\n    .make_new = bool_make_new,\n    .unary_op = bool_unary_op,\n    .binary_op = bool_binary_op,\n};\n\n#if !MICROPY_OBJ_IMMEDIATE_OBJS\nconst mp_obj_bool_t mp_const_false_obj = {{&mp_type_bool}, false};\nconst mp_obj_bool_t mp_const_true_obj = {{&mp_type_bool}, true};\n#endif\n"
  },
  {
    "path": "py/objboundmeth.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n\n#include \"py/obj.h\"\n#include \"py/runtime.h\"\n\ntypedef struct _mp_obj_bound_meth_t {\n    mp_obj_base_t base;\n    mp_obj_t meth;\n    mp_obj_t self;\n} mp_obj_bound_meth_t;\n\n#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED\nSTATIC void bound_meth_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_bound_meth_t *o = MP_OBJ_TO_PTR(o_in);\n    mp_printf(print, \"<bound_method %p \", o);\n    mp_obj_print_helper(print, o->self, PRINT_REPR);\n    mp_print_str(print, \".\");\n    mp_obj_print_helper(print, o->meth, PRINT_REPR);\n    mp_print_str(print, \">\");\n}\n#endif\n\nmp_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) {\n    // need to insert self before all other args and then call meth\n    size_t n_total = n_args + 2 * n_kw;\n    mp_obj_t *args2 = NULL;\n    #if MICROPY_ENABLE_PYSTACK\n    args2 = mp_pystack_alloc(sizeof(mp_obj_t) * (1 + n_total));\n    #else\n    mp_obj_t *free_args2 = NULL;\n    if (n_total > 4) {\n        // try to use heap to allocate temporary args array\n        args2 = m_new_maybe(mp_obj_t, 1 + n_total);\n        free_args2 = args2;\n    }\n    if (args2 == NULL) {\n        // (fallback to) use stack to allocate temporary args array\n        args2 = alloca(sizeof(mp_obj_t) * (1 + n_total));\n    }\n    #endif\n    args2[0] = self;\n    memcpy(args2 + 1, args, n_total * sizeof(mp_obj_t));\n    mp_obj_t res = mp_call_function_n_kw(meth, n_args + 1, n_kw, args2);\n    #if MICROPY_ENABLE_PYSTACK\n    mp_pystack_free(args2);\n    #else\n    if (free_args2 != NULL) {\n        m_del(mp_obj_t, free_args2, 1 + n_total);\n    }\n    #endif\n    return res;\n}\n\nSTATIC mp_obj_t bound_meth_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_obj_bound_meth_t *self = MP_OBJ_TO_PTR(self_in);\n    return mp_call_method_self_n_kw(self->meth, self->self, n_args, n_kw, args);\n}\n\n#if MICROPY_PY_FUNCTION_ATTRS\nSTATIC void bound_meth_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] != MP_OBJ_NULL) {\n        // not load attribute\n        return;\n    }\n    // Delegate the load to the method object\n    mp_obj_bound_meth_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_load_method_maybe(self->meth, attr, dest);\n}\n#endif\n\nSTATIC const mp_obj_type_t mp_type_bound_meth = {\n    { &mp_type_type },\n    .name = MP_QSTR_bound_method,\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED\n    .print = bound_meth_print,\n    #endif\n    .call = bound_meth_call,\n    #if MICROPY_PY_FUNCTION_ATTRS\n    .attr = bound_meth_attr,\n    #endif\n};\n\nmp_obj_t mp_obj_new_bound_meth(mp_obj_t meth, mp_obj_t self) {\n    mp_obj_bound_meth_t *o = m_new_obj(mp_obj_bound_meth_t);\n    o->base.type = &mp_type_bound_meth;\n    o->meth = meth;\n    o->self = self;\n    return MP_OBJ_FROM_PTR(o);\n}\n"
  },
  {
    "path": "py/objcell.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/obj.h\"\n\ntypedef struct _mp_obj_cell_t {\n    mp_obj_base_t base;\n    mp_obj_t obj;\n} mp_obj_cell_t;\n\nmp_obj_t mp_obj_cell_get(mp_obj_t self_in) {\n    mp_obj_cell_t *self = MP_OBJ_TO_PTR(self_in);\n    return self->obj;\n}\n\nvoid mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj) {\n    mp_obj_cell_t *self = MP_OBJ_TO_PTR(self_in);\n    self->obj = obj;\n}\n\n#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED\nSTATIC void cell_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_cell_t *o = MP_OBJ_TO_PTR(o_in);\n    mp_printf(print, \"<cell %p \", o->obj);\n    if (o->obj == MP_OBJ_NULL) {\n        mp_print_str(print, \"(nil)\");\n    } else {\n        mp_obj_print_helper(print, o->obj, PRINT_REPR);\n    }\n    mp_print_str(print, \">\");\n}\n#endif\n\nSTATIC const mp_obj_type_t mp_type_cell = {\n    { &mp_type_type },\n    .name = MP_QSTR_, // cell representation is just value in < >\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED\n    .print = cell_print,\n    #endif\n};\n\nmp_obj_t mp_obj_new_cell(mp_obj_t obj) {\n    mp_obj_cell_t *o = m_new_obj(mp_obj_cell_t);\n    o->base.type = &mp_type_cell;\n    o->obj = obj;\n    return MP_OBJ_FROM_PTR(o);\n}\n"
  },
  {
    "path": "py/objclosure.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n\n#include \"py/obj.h\"\n#include \"py/runtime.h\"\n\ntypedef struct _mp_obj_closure_t {\n    mp_obj_base_t base;\n    mp_obj_t fun;\n    size_t n_closed;\n    mp_obj_t closed[];\n} mp_obj_closure_t;\n\nSTATIC mp_obj_t closure_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_obj_closure_t *self = MP_OBJ_TO_PTR(self_in);\n\n    // need to concatenate closed-over-vars and args\n\n    size_t n_total = self->n_closed + n_args + 2 * n_kw;\n    if (n_total <= 5) {\n        // use stack to allocate temporary args array\n        mp_obj_t args2[5];\n        memcpy(args2, self->closed, self->n_closed * sizeof(mp_obj_t));\n        memcpy(args2 + self->n_closed, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));\n        return mp_call_function_n_kw(self->fun, self->n_closed + n_args, n_kw, args2);\n    } else {\n        // use heap to allocate temporary args array\n        mp_obj_t *args2 = m_new(mp_obj_t, n_total);\n        memcpy(args2, self->closed, self->n_closed * sizeof(mp_obj_t));\n        memcpy(args2 + self->n_closed, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));\n        mp_obj_t res = mp_call_function_n_kw(self->fun, self->n_closed + n_args, n_kw, args2);\n        m_del(mp_obj_t, args2, n_total);\n        return res;\n    }\n}\n\n#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED\nSTATIC void closure_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_closure_t *o = MP_OBJ_TO_PTR(o_in);\n    mp_print_str(print, \"<closure \");\n    mp_obj_print_helper(print, o->fun, PRINT_REPR);\n    mp_printf(print, \" at %p, n_closed=%u \", o, (int)o->n_closed);\n    for (size_t i = 0; i < o->n_closed; i++) {\n        if (o->closed[i] == MP_OBJ_NULL) {\n            mp_print_str(print, \"(nil)\");\n        } else {\n            mp_obj_print_helper(print, o->closed[i], PRINT_REPR);\n        }\n        mp_print_str(print, \" \");\n    }\n    mp_print_str(print, \">\");\n}\n#endif\n\nconst mp_obj_type_t closure_type = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF,\n    .name = MP_QSTR_closure,\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED\n    .print = closure_print,\n    #endif\n    .call = closure_call,\n};\n\nmp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed_over, const mp_obj_t *closed) {\n    mp_obj_closure_t *o = m_new_obj_var(mp_obj_closure_t, mp_obj_t, n_closed_over);\n    o->base.type = &closure_type;\n    o->fun = fun;\n    o->n_closed = n_closed_over;\n    memcpy(o->closed, closed, n_closed_over * sizeof(mp_obj_t));\n    return MP_OBJ_FROM_PTR(o);\n}\n"
  },
  {
    "path": "py/objcomplex.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <assert.h>\n\n#include \"py/parsenum.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_COMPLEX\n\n#include <math.h>\n#include \"py/formatfloat.h\"\n\ntypedef struct _mp_obj_complex_t {\n    mp_obj_base_t base;\n    mp_float_t real;\n    mp_float_t imag;\n} mp_obj_complex_t;\n\nSTATIC void complex_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in);\n    #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n    char buf[16];\n    #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C\n    const int precision = 6;\n    #else\n    const int precision = 7;\n    #endif\n    #else\n    char buf[32];\n    const int precision = 16;\n    #endif\n    if (o->real == 0) {\n        mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\\0');\n        mp_printf(print, \"%sj\", buf);\n    } else {\n        mp_format_float(o->real, buf, sizeof(buf), 'g', precision, '\\0');\n        mp_printf(print, \"(%s\", buf);\n        if (o->imag >= 0 || isnan(o->imag)) {\n            mp_print_str(print, \"+\");\n        }\n        mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\\0');\n        mp_printf(print, \"%sj)\", buf);\n    }\n}\n\nSTATIC 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) {\n    (void)type_in;\n    mp_arg_check_num(n_args, n_kw, 0, 2, false);\n\n    switch (n_args) {\n        case 0:\n            return mp_obj_new_complex(0, 0);\n\n        case 1:\n            if (mp_obj_is_str(args[0])) {\n                // a string, parse it\n                size_t l;\n                const char *s = mp_obj_str_get_data(args[0], &l);\n                return mp_parse_num_decimal(s, l, true, true, NULL);\n            } else if (mp_obj_is_type(args[0], &mp_type_complex)) {\n                // a complex, just return it\n                return args[0];\n            } else {\n                // something else, try to cast it to a complex\n                return mp_obj_new_complex(mp_obj_get_float(args[0]), 0);\n            }\n\n        case 2:\n        default: {\n            mp_float_t real, imag;\n            if (mp_obj_is_type(args[0], &mp_type_complex)) {\n                mp_obj_complex_get(args[0], &real, &imag);\n            } else {\n                real = mp_obj_get_float(args[0]);\n                imag = 0;\n            }\n            if (mp_obj_is_type(args[1], &mp_type_complex)) {\n                mp_float_t real2, imag2;\n                mp_obj_complex_get(args[1], &real2, &imag2);\n                real -= imag2;\n                imag += real2;\n            } else {\n                imag += mp_obj_get_float(args[1]);\n            }\n            return mp_obj_new_complex(real, imag);\n        }\n    }\n}\n\nSTATIC mp_obj_t complex_unary_op(mp_unary_op_t op, mp_obj_t o_in) {\n    mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(o->real != 0 || o->imag != 0);\n        case MP_UNARY_OP_HASH:\n            return MP_OBJ_NEW_SMALL_INT(mp_float_hash(o->real) ^ mp_float_hash(o->imag));\n        case MP_UNARY_OP_POSITIVE:\n            return o_in;\n        case MP_UNARY_OP_NEGATIVE:\n            return mp_obj_new_complex(-o->real, -o->imag);\n        case MP_UNARY_OP_ABS:\n            return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(o->real * o->real + o->imag * o->imag));\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n\nSTATIC mp_obj_t complex_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    mp_obj_complex_t *lhs = MP_OBJ_TO_PTR(lhs_in);\n    return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in);\n}\n\nSTATIC void complex_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] != MP_OBJ_NULL) {\n        // not load attribute\n        return;\n    }\n    mp_obj_complex_t *self = MP_OBJ_TO_PTR(self_in);\n    if (attr == MP_QSTR_real) {\n        dest[0] = mp_obj_new_float(self->real);\n    } else if (attr == MP_QSTR_imag) {\n        dest[0] = mp_obj_new_float(self->imag);\n    }\n}\n\nconst mp_obj_type_t mp_type_complex = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_EQ_NOT_REFLEXIVE | MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,\n    .name = MP_QSTR_complex,\n    .print = complex_print,\n    .make_new = complex_make_new,\n    .unary_op = complex_unary_op,\n    .binary_op = complex_binary_op,\n    .attr = complex_attr,\n};\n\nmp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) {\n    mp_obj_complex_t *o = m_new_obj(mp_obj_complex_t);\n    o->base.type = &mp_type_complex;\n    o->real = real;\n    o->imag = imag;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nvoid mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag) {\n    assert(mp_obj_is_type(self_in, &mp_type_complex));\n    mp_obj_complex_t *self = MP_OBJ_TO_PTR(self_in);\n    *real = self->real;\n    *imag = self->imag;\n}\n\nmp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in) {\n    mp_float_t rhs_real, rhs_imag;\n    if (!mp_obj_get_complex_maybe(rhs_in, &rhs_real, &rhs_imag)) {\n        return MP_OBJ_NULL; // op not supported\n    }\n\n    switch (op) {\n        case MP_BINARY_OP_ADD:\n        case MP_BINARY_OP_INPLACE_ADD:\n            lhs_real += rhs_real;\n            lhs_imag += rhs_imag;\n            break;\n        case MP_BINARY_OP_SUBTRACT:\n        case MP_BINARY_OP_INPLACE_SUBTRACT:\n            lhs_real -= rhs_real;\n            lhs_imag -= rhs_imag;\n            break;\n        case MP_BINARY_OP_MULTIPLY:\n        case MP_BINARY_OP_INPLACE_MULTIPLY: {\n            mp_float_t real;\n        multiply:\n            real = lhs_real * rhs_real - lhs_imag * rhs_imag;\n            lhs_imag = lhs_real * rhs_imag + lhs_imag * rhs_real;\n            lhs_real = real;\n            break;\n        }\n        case MP_BINARY_OP_FLOOR_DIVIDE:\n        case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:\n            mp_raise_TypeError(MP_ERROR_TEXT(\"can't truncate-divide a complex number\"));\n\n        case MP_BINARY_OP_TRUE_DIVIDE:\n        case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:\n            if (rhs_imag == 0) {\n                if (rhs_real == 0) {\n                    mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT(\"complex divide by zero\"));\n                }\n                lhs_real /= rhs_real;\n                lhs_imag /= rhs_real;\n            } else if (rhs_real == 0) {\n                mp_float_t real = lhs_imag / rhs_imag;\n                lhs_imag = -lhs_real / rhs_imag;\n                lhs_real = real;\n            } else {\n                mp_float_t rhs_len_sq = rhs_real * rhs_real + rhs_imag * rhs_imag;\n                rhs_real /= rhs_len_sq;\n                rhs_imag /= -rhs_len_sq;\n                goto multiply;\n            }\n            break;\n\n        case MP_BINARY_OP_POWER:\n        case MP_BINARY_OP_INPLACE_POWER: {\n            // z1**z2 = exp(z2*ln(z1))\n            //        = exp(z2*(ln(|z1|)+i*arg(z1)))\n            //        = exp( (x2*ln1 - y2*arg1) + i*(y2*ln1 + x2*arg1) )\n            //        = exp(x3 + i*y3)\n            //        = exp(x3)*(cos(y3) + i*sin(y3))\n            mp_float_t abs1 = MICROPY_FLOAT_C_FUN(sqrt)(lhs_real * lhs_real + lhs_imag * lhs_imag);\n            if (abs1 == 0) {\n                if (rhs_imag == 0 && rhs_real >= 0) {\n                    lhs_real = (rhs_real == 0);\n                } else {\n                    mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT(\"0.0 to a complex power\"));\n                }\n            } else {\n                mp_float_t ln1 = MICROPY_FLOAT_C_FUN(log)(abs1);\n                mp_float_t arg1 = MICROPY_FLOAT_C_FUN(atan2)(lhs_imag, lhs_real);\n                mp_float_t x3 = rhs_real * ln1 - rhs_imag * arg1;\n                mp_float_t y3 = rhs_imag * ln1 + rhs_real * arg1;\n                mp_float_t exp_x3 = MICROPY_FLOAT_C_FUN(exp)(x3);\n                lhs_real = exp_x3 * MICROPY_FLOAT_C_FUN(cos)(y3);\n                lhs_imag = exp_x3 * MICROPY_FLOAT_C_FUN(sin)(y3);\n            }\n            break;\n        }\n\n        case MP_BINARY_OP_EQUAL:\n            return mp_obj_new_bool(lhs_real == rhs_real && lhs_imag == rhs_imag);\n\n        default:\n            return MP_OBJ_NULL; // op not supported\n    }\n    return mp_obj_new_complex(lhs_real, lhs_imag);\n}\n\n#endif\n"
  },
  {
    "path": "py/objdeque.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <unistd.h> // for ssize_t\n#include <string.h>\n\n#include \"py/mpconfig.h\"\n#if MICROPY_PY_COLLECTIONS_DEQUE\n\n#include \"py/runtime.h\"\n\ntypedef struct _mp_obj_deque_t {\n    mp_obj_base_t base;\n    size_t alloc;\n    size_t i_get;\n    size_t i_put;\n    mp_obj_t *items;\n    uint32_t flags;\n    #define FLAG_CHECK_OVERFLOW 1\n} mp_obj_deque_t;\n\nSTATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_arg_check_num(n_args, n_kw, 2, 3, false);\n\n    /* Initialization from existing sequence is not supported, so an empty\n       tuple must be passed as such. */\n    if (args[0] != mp_const_empty_tuple) {\n        mp_raise_ValueError(NULL);\n    }\n\n    // Protect against -1 leading to zero-length allocation and bad array access\n    mp_int_t maxlen = mp_obj_get_int(args[1]);\n    if (maxlen < 0) {\n        mp_raise_ValueError(NULL);\n    }\n\n    mp_obj_deque_t *o = m_new_obj(mp_obj_deque_t);\n    o->base.type = type;\n    o->alloc = maxlen + 1;\n    o->i_get = o->i_put = 0;\n    o->items = m_new0(mp_obj_t, o->alloc);\n\n    if (n_args > 2) {\n        o->flags = mp_obj_get_int(args[2]);\n    }\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n    mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(self->i_get != self->i_put);\n        case MP_UNARY_OP_LEN: {\n            ssize_t len = self->i_put - self->i_get;\n            if (len < 0) {\n                len += self->alloc;\n            }\n            return MP_OBJ_NEW_SMALL_INT(len);\n        }\n        #if MICROPY_PY_SYS_GETSIZEOF\n        case MP_UNARY_OP_SIZEOF: {\n            size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc;\n            return MP_OBJ_NEW_SMALL_INT(sz);\n        }\n        #endif\n        default:\n            return MP_OBJ_NULL; // op not supported\n    }\n}\n\nSTATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) {\n    mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);\n\n    size_t new_i_put = self->i_put + 1;\n    if (new_i_put == self->alloc) {\n        new_i_put = 0;\n    }\n\n    if (self->flags & FLAG_CHECK_OVERFLOW && new_i_put == self->i_get) {\n        mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT(\"full\"));\n    }\n\n    self->items[self->i_put] = arg;\n    self->i_put = new_i_put;\n\n    if (self->i_get == new_i_put) {\n        if (++self->i_get == self->alloc) {\n            self->i_get = 0;\n        }\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append);\n\nSTATIC mp_obj_t deque_popleft(mp_obj_t self_in) {\n    mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (self->i_get == self->i_put) {\n        mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT(\"empty\"));\n    }\n\n    mp_obj_t ret = self->items[self->i_get];\n    self->items[self->i_get] = MP_OBJ_NULL;\n\n    if (++self->i_get == self->alloc) {\n        self->i_get = 0;\n    }\n\n    return ret;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft);\n\n#if 0\nSTATIC mp_obj_t deque_clear(mp_obj_t self_in) {\n    mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);\n    self->i_get = self->i_put = 0;\n    mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items));\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_clear_obj, deque_clear);\n#endif\n\nSTATIC const mp_rom_map_elem_t deque_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&deque_append_obj) },\n    #if 0\n    { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&deque_clear_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&deque_popleft_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(deque_locals_dict, deque_locals_dict_table);\n\nconst mp_obj_type_t mp_type_deque = {\n    { &mp_type_type },\n    .name = MP_QSTR_deque,\n    .make_new = deque_make_new,\n    .unary_op = deque_unary_op,\n    .locals_dict = (mp_obj_dict_t *)&deque_locals_dict,\n};\n\n#endif // MICROPY_PY_COLLECTIONS_DEQUE\n"
  },
  {
    "path": "py/objdict.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014-2017 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n#include \"py/builtin.h\"\n#include \"py/objtype.h\"\n#include \"py/objstr.h\"\n\nconst mp_obj_dict_t mp_const_empty_dict_obj = {\n    .base = { .type = &mp_type_dict },\n    .map = {\n        .all_keys_are_qstrs = 0,\n        .is_fixed = 1,\n        .is_ordered = 1,\n        .used = 0,\n        .alloc = 0,\n        .table = NULL,\n    }\n};\n\nSTATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);\n\n// This is a helper function to iterate through a dictionary.  The state of\n// the iteration is held in *cur and should be initialised with zero for the\n// first call.  Will return NULL when no more elements are available.\nSTATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) {\n    size_t max = dict->map.alloc;\n    mp_map_t *map = &dict->map;\n\n    size_t i = *cur;\n    for (; i < max; i++) {\n        if (mp_map_slot_is_filled(map, i)) {\n            *cur = i + 1;\n            return &(map->table[i]);\n        }\n    }\n\n    assert(map->used == 0 || i == max);\n    return NULL;\n}\n\nSTATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);\n    bool first = true;\n    if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {\n        kind = PRINT_REPR;\n    }\n    if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) {\n        mp_printf(print, \"%q(\", self->base.type->name);\n    }\n    mp_print_str(print, \"{\");\n    size_t cur = 0;\n    mp_map_elem_t *next = NULL;\n    while ((next = dict_iter_next(self, &cur)) != NULL) {\n        if (!first) {\n            mp_print_str(print, \", \");\n        }\n        first = false;\n        bool add_quote = MICROPY_PY_UJSON && kind == PRINT_JSON && !mp_obj_is_str_or_bytes(next->key);\n        if (add_quote) {\n            mp_print_str(print, \"\\\"\");\n        }\n        mp_obj_print_helper(print, next->key, kind);\n        if (add_quote) {\n            mp_print_str(print, \"\\\"\");\n        }\n        mp_print_str(print, \": \");\n        mp_obj_print_helper(print, next->value, kind);\n    }\n    mp_print_str(print, \"}\");\n    if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) {\n        mp_print_str(print, \")\");\n    }\n}\n\nmp_obj_t mp_obj_dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_obj_t dict_out = mp_obj_new_dict(0);\n    mp_obj_dict_t *dict = MP_OBJ_TO_PTR(dict_out);\n    dict->base.type = type;\n    #if MICROPY_PY_COLLECTIONS_ORDEREDDICT\n    if (type == &mp_type_ordereddict) {\n        dict->map.is_ordered = 1;\n    }\n    #endif\n    if (n_args > 0 || n_kw > 0) {\n        mp_obj_t args2[2] = {dict_out, args[0]}; // args[0] is always valid, even if it's not a positional arg\n        mp_map_t kwargs;\n        mp_map_init_fixed_table(&kwargs, n_kw, args + n_args);\n        dict_update(n_args + 1, args2, &kwargs); // dict_update will check that n_args + 1 == 1 or 2\n    }\n    return dict_out;\n}\n\nSTATIC mp_obj_t dict_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(self->map.used != 0);\n        case MP_UNARY_OP_LEN:\n            return MP_OBJ_NEW_SMALL_INT(self->map.used);\n        #if MICROPY_PY_SYS_GETSIZEOF\n        case MP_UNARY_OP_SIZEOF: {\n            size_t sz = sizeof(*self) + sizeof(*self->map.table) * self->map.alloc;\n            return MP_OBJ_NEW_SMALL_INT(sz);\n        }\n        #endif\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n\nSTATIC mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    mp_obj_dict_t *o = MP_OBJ_TO_PTR(lhs_in);\n    switch (op) {\n        case MP_BINARY_OP_CONTAINS: {\n            mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP);\n            return mp_obj_new_bool(elem != NULL);\n        }\n        case MP_BINARY_OP_EQUAL: {\n            #if MICROPY_PY_COLLECTIONS_ORDEREDDICT\n            if (MP_UNLIKELY(mp_obj_is_type(lhs_in, &mp_type_ordereddict) && mp_obj_is_type(rhs_in, &mp_type_ordereddict))) {\n                // Iterate through both dictionaries simultaneously and compare keys and values.\n                mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in);\n                size_t c1 = 0, c2 = 0;\n                mp_map_elem_t *e1 = dict_iter_next(o, &c1), *e2 = dict_iter_next(rhs, &c2);\n                for (; e1 != NULL && e2 != NULL; e1 = dict_iter_next(o, &c1), e2 = dict_iter_next(rhs, &c2)) {\n                    if (!mp_obj_equal(e1->key, e2->key) || !mp_obj_equal(e1->value, e2->value)) {\n                        return mp_const_false;\n                    }\n                }\n                return e1 == NULL && e2 == NULL ? mp_const_true : mp_const_false;\n            }\n            #endif\n\n            if (mp_obj_is_type(rhs_in, &mp_type_dict)) {\n                mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in);\n                if (o->map.used != rhs->map.used) {\n                    return mp_const_false;\n                }\n\n                size_t cur = 0;\n                mp_map_elem_t *next = NULL;\n                while ((next = dict_iter_next(o, &cur)) != NULL) {\n                    mp_map_elem_t *elem = mp_map_lookup(&rhs->map, next->key, MP_MAP_LOOKUP);\n                    if (elem == NULL || !mp_obj_equal(next->value, elem->value)) {\n                        return mp_const_false;\n                    }\n                }\n                return mp_const_true;\n            } else {\n                // dict is not equal to instance of any other type\n                return mp_const_false;\n            }\n        }\n        default:\n            // op not supported\n            return MP_OBJ_NULL;\n    }\n}\n\n// Note: Make sure this is inlined in load part of dict_subscr() below.\nmp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) {\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP);\n    if (elem == NULL) {\n        nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index));\n    } else {\n        return elem->value;\n    }\n}\n\nSTATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {\n    if (value == MP_OBJ_NULL) {\n        // delete\n        mp_obj_dict_delete(self_in, index);\n        return mp_const_none;\n    } else if (value == MP_OBJ_SENTINEL) {\n        // load\n        mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);\n        mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP);\n        if (elem == NULL) {\n            nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index));\n        } else {\n            return elem->value;\n        }\n    } else {\n        // store\n        mp_obj_dict_store(self_in, index, value);\n        return mp_const_none;\n    }\n}\n\n/******************************************************************************/\n/* dict methods                                                               */\n\nSTATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) {\n    if (dict->map.is_fixed) {\n        mp_raise_TypeError(NULL);\n    }\n}\n\nSTATIC mp_obj_t dict_clear(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_ensure_not_fixed(self);\n\n    mp_map_clear(&self->map);\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_clear_obj, dict_clear);\n\nmp_obj_t mp_obj_dict_copy(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t other_out = mp_obj_new_dict(self->map.alloc);\n    mp_obj_dict_t *other = MP_OBJ_TO_PTR(other_out);\n    other->base.type = self->base.type;\n    other->map.used = self->map.used;\n    other->map.all_keys_are_qstrs = self->map.all_keys_are_qstrs;\n    other->map.is_fixed = 0;\n    other->map.is_ordered = self->map.is_ordered;\n    memcpy(other->map.table, self->map.table, self->map.alloc * sizeof(mp_map_elem_t));\n    return other_out;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, mp_obj_dict_copy);\n\n#if MICROPY_PY_BUILTINS_DICT_FROMKEYS\n// this is a classmethod\nSTATIC mp_obj_t dict_fromkeys(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t iter = mp_getiter(args[1], NULL);\n    mp_obj_t value = mp_const_none;\n    mp_obj_t next = MP_OBJ_NULL;\n\n    if (n_args > 2) {\n        value = args[2];\n    }\n\n    // optimisation to allocate result based on len of argument\n    mp_obj_t self_out;\n    mp_obj_t len = mp_obj_len_maybe(args[1]);\n    if (len == MP_OBJ_NULL) {\n        /* object's type doesn't have a __len__ slot */\n        self_out = mp_obj_new_dict(0);\n    } else {\n        self_out = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len));\n    }\n\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_out);\n    while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n        mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;\n    }\n\n    return self_out;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_fromkeys_fun_obj, 2, 3, dict_fromkeys);\nSTATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromkeys_fun_obj));\n#endif\n\nSTATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) {\n    mp_check_self(mp_obj_is_dict_or_ordereddict(args[0]));\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);\n    if (lookup_kind != MP_MAP_LOOKUP) {\n        mp_ensure_not_fixed(self);\n    }\n    mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind);\n    mp_obj_t value;\n    if (elem == NULL || elem->value == MP_OBJ_NULL) {\n        if (n_args == 2) {\n            if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {\n                nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, args[1]));\n            } else {\n                value = mp_const_none;\n            }\n        } else {\n            value = args[2];\n        }\n        if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {\n            elem->value = value;\n        }\n    } else {\n        value = elem->value;\n        if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {\n            elem->value = MP_OBJ_NULL; // so that GC can collect the deleted value\n        }\n    }\n    return value;\n}\n\nSTATIC mp_obj_t dict_get(size_t n_args, const mp_obj_t *args) {\n    return dict_get_helper(n_args, args, MP_MAP_LOOKUP);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_get_obj, 2, 3, dict_get);\n\nSTATIC mp_obj_t dict_pop(size_t n_args, const mp_obj_t *args) {\n    return dict_get_helper(n_args, args, MP_MAP_LOOKUP_REMOVE_IF_FOUND);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_pop_obj, 2, 3, dict_pop);\n\nSTATIC mp_obj_t dict_setdefault(size_t n_args, const mp_obj_t *args) {\n    return dict_get_helper(n_args, args, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setdefault);\n\nSTATIC mp_obj_t dict_popitem(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_ensure_not_fixed(self);\n    if (self->map.used == 0) {\n        mp_raise_msg(&mp_type_KeyError, MP_ERROR_TEXT(\"popitem(): dictionary is empty\"));\n    }\n    size_t cur = 0;\n    #if MICROPY_PY_COLLECTIONS_ORDEREDDICT\n    if (self->map.is_ordered) {\n        cur = self->map.used - 1;\n    }\n    #endif\n    mp_map_elem_t *next = dict_iter_next(self, &cur);\n    assert(next);\n    self->map.used--;\n    mp_obj_t items[] = {next->key, next->value};\n    next->key = MP_OBJ_SENTINEL; // must mark key as sentinel to indicate that it was deleted\n    next->value = MP_OBJ_NULL;\n    mp_obj_t tuple = mp_obj_new_tuple(2, items);\n\n    return tuple;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);\n\nSTATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {\n    mp_check_self(mp_obj_is_dict_or_ordereddict(args[0]));\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);\n    mp_ensure_not_fixed(self);\n\n    mp_arg_check_num(n_args, kwargs->used, 1, 2, true);\n\n    if (n_args == 2) {\n        // given a positional argument\n\n        if (mp_obj_is_dict_or_ordereddict(args[1])) {\n            // update from other dictionary (make sure other is not self)\n            if (args[1] != args[0]) {\n                size_t cur = 0;\n                mp_map_elem_t *elem = NULL;\n                while ((elem = dict_iter_next((mp_obj_dict_t *)MP_OBJ_TO_PTR(args[1]), &cur)) != NULL) {\n                    mp_map_lookup(&self->map, elem->key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = elem->value;\n                }\n            }\n        } else {\n            // update from a generic iterable of pairs\n            mp_obj_t iter = mp_getiter(args[1], NULL);\n            mp_obj_t next = MP_OBJ_NULL;\n            while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n                mp_obj_t inneriter = mp_getiter(next, NULL);\n                mp_obj_t key = mp_iternext(inneriter);\n                mp_obj_t value = mp_iternext(inneriter);\n                mp_obj_t stop = mp_iternext(inneriter);\n                if (key == MP_OBJ_STOP_ITERATION\n                    || value == MP_OBJ_STOP_ITERATION\n                    || stop != MP_OBJ_STOP_ITERATION) {\n                    mp_raise_ValueError(MP_ERROR_TEXT(\"dict update sequence has wrong length\"));\n                } else {\n                    mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;\n                }\n            }\n        }\n    }\n\n    // update the dict with any keyword args\n    for (size_t i = 0; i < kwargs->alloc; i++) {\n        if (mp_map_slot_is_filled(kwargs, i)) {\n            mp_map_lookup(&self->map, kwargs->table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = kwargs->table[i].value;\n        }\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(dict_update_obj, 1, dict_update);\n\n\n/******************************************************************************/\n/* dict views                                                                 */\n\nSTATIC const mp_obj_type_t dict_view_type;\nSTATIC const mp_obj_type_t dict_view_it_type;\n\ntypedef enum _mp_dict_view_kind_t {\n    MP_DICT_VIEW_ITEMS,\n    MP_DICT_VIEW_KEYS,\n    MP_DICT_VIEW_VALUES,\n} mp_dict_view_kind_t;\n\nSTATIC const char *const mp_dict_view_names[] = {\"dict_items\", \"dict_keys\", \"dict_values\"};\n\ntypedef struct _mp_obj_dict_view_it_t {\n    mp_obj_base_t base;\n    mp_dict_view_kind_t kind;\n    mp_obj_t dict;\n    size_t cur;\n} mp_obj_dict_view_it_t;\n\ntypedef struct _mp_obj_dict_view_t {\n    mp_obj_base_t base;\n    mp_obj_t dict;\n    mp_dict_view_kind_t kind;\n} mp_obj_dict_view_t;\n\nSTATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_type(self_in, &dict_view_it_type));\n    mp_obj_dict_view_it_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur);\n\n    if (next == NULL) {\n        return MP_OBJ_STOP_ITERATION;\n    } else {\n        switch (self->kind) {\n            case MP_DICT_VIEW_ITEMS:\n            default: {\n                mp_obj_t items[] = {next->key, next->value};\n                return mp_obj_new_tuple(2, items);\n            }\n            case MP_DICT_VIEW_KEYS:\n                return next->key;\n            case MP_DICT_VIEW_VALUES:\n                return next->value;\n        }\n    }\n}\n\nSTATIC const mp_obj_type_t dict_view_it_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_iterator,\n    .getiter = mp_identity_getiter,\n    .iternext = dict_view_it_iternext,\n};\n\nSTATIC mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf) {\n    assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_check_self(mp_obj_is_type(view_in, &dict_view_type));\n    mp_obj_dict_view_t *view = MP_OBJ_TO_PTR(view_in);\n    mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t *)iter_buf;\n    o->base.type = &dict_view_it_type;\n    o->kind = view->kind;\n    o->dict = view->dict;\n    o->cur = 0;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC void dict_view_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_check_self(mp_obj_is_type(self_in, &dict_view_type));\n    mp_obj_dict_view_t *self = MP_OBJ_TO_PTR(self_in);\n    bool first = true;\n    mp_print_str(print, mp_dict_view_names[self->kind]);\n    mp_print_str(print, \"([\");\n    mp_obj_iter_buf_t iter_buf;\n    mp_obj_t self_iter = dict_view_getiter(self_in, &iter_buf);\n    mp_obj_t next = MP_OBJ_NULL;\n    while ((next = dict_view_it_iternext(self_iter)) != MP_OBJ_STOP_ITERATION) {\n        if (!first) {\n            mp_print_str(print, \", \");\n        }\n        first = false;\n        mp_obj_print_helper(print, next, PRINT_REPR);\n    }\n    mp_print_str(print, \"])\");\n}\n\nSTATIC mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    // only supported for the 'keys' kind until sets and dicts are refactored\n    mp_obj_dict_view_t *o = MP_OBJ_TO_PTR(lhs_in);\n    if (o->kind != MP_DICT_VIEW_KEYS) {\n        return MP_OBJ_NULL; // op not supported\n    }\n    if (op != MP_BINARY_OP_CONTAINS) {\n        return MP_OBJ_NULL; // op not supported\n    }\n    return dict_binary_op(op, o->dict, rhs_in);\n}\n\nSTATIC const mp_obj_type_t dict_view_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_dict_view,\n    .print = dict_view_print,\n    .binary_op = dict_view_binary_op,\n    .getiter = dict_view_getiter,\n};\n\nSTATIC mp_obj_t mp_obj_new_dict_view(mp_obj_t dict, mp_dict_view_kind_t kind) {\n    mp_obj_dict_view_t *o = m_new_obj(mp_obj_dict_view_t);\n    o->base.type = &dict_view_type;\n    o->dict = dict;\n    o->kind = kind;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) {\n    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));\n    return mp_obj_new_dict_view(self_in, kind);\n}\n\nSTATIC mp_obj_t dict_items(mp_obj_t self_in) {\n    return dict_view(self_in, MP_DICT_VIEW_ITEMS);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_items_obj, dict_items);\n\nSTATIC mp_obj_t dict_keys(mp_obj_t self_in) {\n    return dict_view(self_in, MP_DICT_VIEW_KEYS);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_keys_obj, dict_keys);\n\nSTATIC mp_obj_t dict_values(mp_obj_t self_in) {\n    return dict_view(self_in, MP_DICT_VIEW_VALUES);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values);\n\n/******************************************************************************/\n/* dict iterator                                                              */\n\nSTATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {\n    assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));\n    mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t *)iter_buf;\n    o->base.type = &dict_view_it_type;\n    o->kind = MP_DICT_VIEW_KEYS;\n    o->dict = self_in;\n    o->cur = 0;\n    return MP_OBJ_FROM_PTR(o);\n}\n\n/******************************************************************************/\n/* dict constructors & public C API                                           */\n\nSTATIC const mp_rom_map_elem_t dict_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&dict_clear_obj) },\n    { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&dict_copy_obj) },\n    #if MICROPY_PY_BUILTINS_DICT_FROMKEYS\n    { MP_ROM_QSTR(MP_QSTR_fromkeys), MP_ROM_PTR(&dict_fromkeys_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&dict_get_obj) },\n    { MP_ROM_QSTR(MP_QSTR_items), MP_ROM_PTR(&dict_items_obj) },\n    { MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&dict_keys_obj) },\n    { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&dict_pop_obj) },\n    { MP_ROM_QSTR(MP_QSTR_popitem), MP_ROM_PTR(&dict_popitem_obj) },\n    { MP_ROM_QSTR(MP_QSTR_setdefault), MP_ROM_PTR(&dict_setdefault_obj) },\n    { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&dict_update_obj) },\n    { MP_ROM_QSTR(MP_QSTR_values), MP_ROM_PTR(&dict_values_obj) },\n    { MP_ROM_QSTR(MP_QSTR___getitem__), MP_ROM_PTR(&mp_op_getitem_obj) },\n    { MP_ROM_QSTR(MP_QSTR___setitem__), MP_ROM_PTR(&mp_op_setitem_obj) },\n    { MP_ROM_QSTR(MP_QSTR___delitem__), MP_ROM_PTR(&mp_op_delitem_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(dict_locals_dict, dict_locals_dict_table);\n\nconst mp_obj_type_t mp_type_dict = {\n    { &mp_type_type },\n    .name = MP_QSTR_dict,\n    .print = dict_print,\n    .make_new = mp_obj_dict_make_new,\n    .unary_op = dict_unary_op,\n    .binary_op = dict_binary_op,\n    .subscr = dict_subscr,\n    .getiter = dict_getiter,\n    .locals_dict = (mp_obj_dict_t *)&dict_locals_dict,\n};\n\n#if MICROPY_PY_COLLECTIONS_ORDEREDDICT\nconst mp_obj_type_t mp_type_ordereddict = {\n    { &mp_type_type },\n    .name = MP_QSTR_OrderedDict,\n    .print = dict_print,\n    .make_new = mp_obj_dict_make_new,\n    .unary_op = dict_unary_op,\n    .binary_op = dict_binary_op,\n    .subscr = dict_subscr,\n    .getiter = dict_getiter,\n    .parent = &mp_type_dict,\n    .locals_dict = (mp_obj_dict_t *)&dict_locals_dict,\n};\n#endif\n\nvoid mp_obj_dict_init(mp_obj_dict_t *dict, size_t n_args) {\n    dict->base.type = &mp_type_dict;\n    mp_map_init(&dict->map, n_args);\n}\n\nmp_obj_t mp_obj_new_dict(size_t n_args) {\n    mp_obj_dict_t *o = m_new_obj(mp_obj_dict_t);\n    mp_obj_dict_init(o, n_args);\n    return MP_OBJ_FROM_PTR(o);\n}\n\nsize_t mp_obj_dict_len(mp_obj_t self_in) {\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);\n    return self->map.used;\n}\n\nmp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {\n    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));\n    mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_ensure_not_fixed(self);\n    mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;\n    return self_in;\n}\n\nmp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key) {\n    mp_obj_t args[2] = {self_in, key};\n    dict_get_helper(2, args, MP_MAP_LOOKUP_REMOVE_IF_FOUND);\n    return self_in;\n}\n"
  },
  {
    "path": "py/objenumerate.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_ENUMERATE\n\ntypedef struct _mp_obj_enumerate_t {\n    mp_obj_base_t base;\n    mp_obj_t iter;\n    mp_int_t cur;\n} mp_obj_enumerate_t;\n\nSTATIC mp_obj_t enumerate_iternext(mp_obj_t self_in);\n\nSTATIC 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) {\n    #if MICROPY_CPYTHON_COMPAT\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_iterable, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },\n        { MP_QSTR_start, MP_ARG_INT, {.u_int = 0} },\n    };\n\n    // parse args\n    struct {\n        mp_arg_val_t iterable, start;\n    } arg_vals;\n    mp_arg_parse_all_kw_array(n_args, n_kw, args,\n        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&arg_vals);\n\n    // create enumerate object\n    mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t);\n    o->base.type = type;\n    o->iter = mp_getiter(arg_vals.iterable.u_obj, NULL);\n    o->cur = arg_vals.start.u_int;\n    #else\n    mp_arg_check_num(n_args, n_kw, 1, 2, false);\n    mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t);\n    o->base.type = type;\n    o->iter = mp_getiter(args[0], NULL);\n    o->cur = n_args > 1 ? mp_obj_get_int(args[1]) : 0;\n    #endif\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\nconst mp_obj_type_t mp_type_enumerate = {\n    { &mp_type_type },\n    .name = MP_QSTR_enumerate,\n    .make_new = enumerate_make_new,\n    .iternext = enumerate_iternext,\n    .getiter = mp_identity_getiter,\n};\n\nSTATIC mp_obj_t enumerate_iternext(mp_obj_t self_in) {\n    assert(mp_obj_is_type(self_in, &mp_type_enumerate));\n    mp_obj_enumerate_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t next = mp_iternext(self->iter);\n    if (next == MP_OBJ_STOP_ITERATION) {\n        return MP_OBJ_STOP_ITERATION;\n    } else {\n        mp_obj_t items[] = {MP_OBJ_NEW_SMALL_INT(self->cur++), next};\n        return mp_obj_new_tuple(2, items);\n    }\n}\n\n#endif // MICROPY_PY_BUILTINS_ENUMERATE\n"
  },
  {
    "path": "py/objexcept.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014-2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <stdarg.h>\n#include <assert.h>\n#include <stdio.h>\n\n#include \"py/objlist.h\"\n#include \"py/objstr.h\"\n#include \"py/objtuple.h\"\n#include \"py/objtype.h\"\n#include \"py/runtime.h\"\n#include \"py/gc.h\"\n#include \"py/mperrno.h\"\n\n#if MICROPY_ROM_TEXT_COMPRESSION && !defined(NO_QSTR)\n// Extract the MP_MAX_UNCOMPRESSED_TEXT_LEN macro from \"genhdr/compressed.data.h\".\n// Only need this if compression enabled and in a regular build (i.e. not during QSTR extraction).\n#define MP_MATCH_COMPRESSED(...) // Ignore\n#define MP_COMPRESSED_DATA(...) // Ignore\n#include \"genhdr/compressed.data.h\"\n#undef MP_MATCH_COMPRESSED\n#undef MP_COMPRESSED_DATA\n#endif\n\n// Number of items per traceback entry (file, line, block)\n#define TRACEBACK_ENTRY_LEN (3)\n\n// Optionally allocated buffer for storing some traceback, the tuple argument,\n// and possible string object and data, for when the heap is locked.\n#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n\n// When used the layout of the emergency exception buffer is:\n//  - traceback entry (file, line, block)\n//  - traceback entry (file, line, block)\n//  - mp_obj_tuple_t object\n//  - n_args * mp_obj_t for tuple\n//  - mp_obj_str_t object\n//  - string data\n#define EMG_BUF_TRACEBACK_OFFSET    (0)\n#define EMG_BUF_TRACEBACK_SIZE      (2 * TRACEBACK_ENTRY_LEN * sizeof(size_t))\n#define EMG_BUF_TUPLE_OFFSET        (EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE)\n#define EMG_BUF_TUPLE_SIZE(n_args)  (sizeof(mp_obj_tuple_t) + n_args * sizeof(mp_obj_t))\n#define EMG_BUF_STR_OFFSET          (EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(1))\n#define EMG_BUF_STR_BUF_OFFSET      (EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t))\n\n#if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0\n#define mp_emergency_exception_buf_size MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE\n\nvoid mp_init_emergency_exception_buf(void) {\n    // Nothing to do since the buffer was declared statically. We put this\n    // definition here so that the calling code can call this function\n    // regardless of how its configured (makes the calling code a bit cleaner).\n}\n\n#else\n#define mp_emergency_exception_buf_size MP_STATE_VM(mp_emergency_exception_buf_size)\n\nvoid mp_init_emergency_exception_buf(void) {\n    mp_emergency_exception_buf_size = 0;\n    MP_STATE_VM(mp_emergency_exception_buf) = NULL;\n}\n\nmp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {\n    mp_int_t size = mp_obj_get_int(size_in);\n    void *buf = NULL;\n    if (size > 0) {\n        buf = m_new(byte, size);\n    }\n\n    int old_size = mp_emergency_exception_buf_size;\n    void *old_buf = MP_STATE_VM(mp_emergency_exception_buf);\n\n    // Update the 2 variables atomically so that an interrupt can't occur\n    // between the assignments.\n    mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();\n    mp_emergency_exception_buf_size = size;\n    MP_STATE_VM(mp_emergency_exception_buf) = buf;\n    MICROPY_END_ATOMIC_SECTION(atomic_state);\n\n    if (old_buf != NULL) {\n        m_del(byte, old_buf, old_size);\n    }\n    return mp_const_none;\n}\n#endif\n#endif  // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n\nSTATIC void decompress_error_text_maybe(mp_obj_exception_t *o) {\n    #if MICROPY_ROM_TEXT_COMPRESSION\n    if (o->args->len == 1 && mp_obj_is_type(o->args->items[0], &mp_type_str)) {\n        mp_obj_str_t *o_str = MP_OBJ_TO_PTR(o->args->items[0]);\n        if (MP_IS_COMPRESSED_ROM_STRING(o_str->data)) {\n            byte *buf = m_new_maybe(byte, MP_MAX_UNCOMPRESSED_TEXT_LEN + 1);\n            if (!buf) {\n                #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n                // Try and use the emergency exception buf if enough space is available.\n                buf = (byte *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_STR_BUF_OFFSET);\n                size_t avail = (uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - buf;\n                if (avail < MP_MAX_UNCOMPRESSED_TEXT_LEN + 1) {\n                    // No way to decompress, fallback to no message text.\n                    o->args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;\n                    return;\n                }\n                #else\n                o->args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;\n                return;\n                #endif\n            }\n            mp_decompress_rom_string(buf, (mp_rom_error_text_t)o_str->data);\n            o_str->data = buf;\n            o_str->len = strlen((const char *)buf);\n            o_str->hash = 0;\n        }\n        // Lazily compute the string hash.\n        if (o_str->hash == 0) {\n            o_str->hash = qstr_compute_hash(o_str->data, o_str->len);\n        }\n    }\n    #endif\n}\n\nvoid mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    mp_obj_exception_t *o = MP_OBJ_TO_PTR(o_in);\n    mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS;\n    bool is_subclass = kind & PRINT_EXC_SUBCLASS;\n    if (!is_subclass && (k == PRINT_REPR || k == PRINT_EXC)) {\n        mp_print_str(print, qstr_str(o->base.type->name));\n    }\n\n    if (k == PRINT_EXC) {\n        mp_print_str(print, \": \");\n    }\n\n    decompress_error_text_maybe(o);\n\n    if (k == PRINT_STR || k == PRINT_EXC) {\n        if (o->args == NULL || o->args->len == 0) {\n            mp_print_str(print, \"\");\n            return;\n        } else if (o->args->len == 1) {\n            #if MICROPY_PY_UERRNO\n            // try to provide a nice OSError error message\n            if (o->base.type == &mp_type_OSError && mp_obj_is_small_int(o->args->items[0])) {\n                qstr qst = mp_errno_to_str(o->args->items[0]);\n                if (qst != MP_QSTRnull) {\n                    mp_printf(print, \"[Errno \" INT_FMT \"] %q\", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst);\n                    return;\n                }\n            }\n            #endif\n            mp_obj_print_helper(print, o->args->items[0], PRINT_STR);\n            return;\n        }\n    }\n\n    mp_obj_tuple_print(print, MP_OBJ_FROM_PTR(o->args), kind);\n}\n\nmp_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) {\n    mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false);\n\n    // Try to allocate memory for the exception, with fallback to emergency exception object\n    mp_obj_exception_t *o_exc = m_new_obj_maybe(mp_obj_exception_t);\n    if (o_exc == NULL) {\n        o_exc = &MP_STATE_VM(mp_emergency_exception_obj);\n    }\n\n    // Populate the exception object\n    o_exc->base.type = type;\n    o_exc->traceback_data = NULL;\n\n    mp_obj_tuple_t *o_tuple;\n    if (n_args == 0) {\n        // No args, can use the empty tuple straightaway\n        o_tuple = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;\n    } else {\n        // Try to allocate memory for the tuple containing the args\n        o_tuple = m_new_obj_var_maybe(mp_obj_tuple_t, mp_obj_t, n_args);\n\n        #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n        // If we are called by mp_obj_new_exception_msg_varg then it will have\n        // reserved room (after the traceback data) for a tuple with 1 element.\n        // Otherwise we are free to use the whole buffer after the traceback data.\n        if (o_tuple == NULL && mp_emergency_exception_buf_size >=\n            (mp_int_t)(EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(n_args))) {\n            o_tuple = (mp_obj_tuple_t *)\n                ((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_TUPLE_OFFSET);\n        }\n        #endif\n\n        if (o_tuple == NULL) {\n            // No memory for a tuple, fallback to an empty tuple\n            o_tuple = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;\n        } else {\n            // Have memory for a tuple so populate it\n            o_tuple->base.type = &mp_type_tuple;\n            o_tuple->len = n_args;\n            memcpy(o_tuple->items, args, n_args * sizeof(mp_obj_t));\n        }\n    }\n\n    // Store the tuple of args in the exception object\n    o_exc->args = o_tuple;\n\n    return MP_OBJ_FROM_PTR(o_exc);\n}\n\n// Get exception \"value\" - that is, first argument, or None\nmp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) {\n    mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->args->len == 0) {\n        return mp_const_none;\n    } else {\n        decompress_error_text_maybe(self);\n        return self->args->items[0];\n    }\n}\n\nvoid mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);\n    if (dest[0] != MP_OBJ_NULL) {\n        // store/delete attribute\n        if (attr == MP_QSTR___traceback__ && dest[1] == mp_const_none) {\n            // We allow 'exc.__traceback__ = None' assignment as low-level\n            // optimization of pre-allocating exception instance and raising\n            // it repeatedly - this avoids memory allocation during raise.\n            // However, uPy will keep adding traceback entries to such\n            // exception instance, so before throwing it, traceback should\n            // be cleared like above.\n            self->traceback_len = 0;\n            dest[0] = MP_OBJ_NULL; // indicate success\n        }\n        return;\n    }\n    if (attr == MP_QSTR_args) {\n        decompress_error_text_maybe(self);\n        dest[0] = MP_OBJ_FROM_PTR(self->args);\n    } else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) {\n        dest[0] = mp_obj_exception_get_value(self_in);\n    }\n}\n\nconst mp_obj_type_t mp_type_BaseException = {\n    { &mp_type_type },\n    .name = MP_QSTR_BaseException,\n    .print = mp_obj_exception_print,\n    .make_new = mp_obj_exception_make_new,\n    .attr = mp_obj_exception_attr,\n};\n\n// *FORMAT-OFF*\n\n// List of all exceptions, arranged as in the table at:\n// http://docs.python.org/3/library/exceptions.html\nMP_DEFINE_EXCEPTION(SystemExit, BaseException)\nMP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)\nMP_DEFINE_EXCEPTION(GeneratorExit, BaseException)\nMP_DEFINE_EXCEPTION(Exception, BaseException)\n  #if MICROPY_PY_ASYNC_AWAIT\n  MP_DEFINE_EXCEPTION(StopAsyncIteration, Exception)\n  #endif\n  MP_DEFINE_EXCEPTION(StopIteration, Exception)\n  MP_DEFINE_EXCEPTION(ArithmeticError, Exception)\n    //MP_DEFINE_EXCEPTION(FloatingPointError, ArithmeticError)\n    MP_DEFINE_EXCEPTION(OverflowError, ArithmeticError)\n    MP_DEFINE_EXCEPTION(ZeroDivisionError, ArithmeticError)\n  MP_DEFINE_EXCEPTION(AssertionError, Exception)\n  MP_DEFINE_EXCEPTION(AttributeError, Exception)\n  //MP_DEFINE_EXCEPTION(BufferError, Exception)\n  MP_DEFINE_EXCEPTION(EOFError, Exception)\n  MP_DEFINE_EXCEPTION(ImportError, Exception)\n  MP_DEFINE_EXCEPTION(LookupError, Exception)\n    MP_DEFINE_EXCEPTION(IndexError, LookupError)\n    MP_DEFINE_EXCEPTION(KeyError, LookupError)\n  MP_DEFINE_EXCEPTION(MemoryError, Exception)\n  MP_DEFINE_EXCEPTION(NameError, Exception)\n    /*\n    MP_DEFINE_EXCEPTION(UnboundLocalError, NameError)\n    */\n  MP_DEFINE_EXCEPTION(OSError, Exception)\n    /*\n    MP_DEFINE_EXCEPTION(BlockingIOError, OSError)\n    MP_DEFINE_EXCEPTION(ChildProcessError, OSError)\n    MP_DEFINE_EXCEPTION(ConnectionError, OSError)\n      MP_DEFINE_EXCEPTION(BrokenPipeError, ConnectionError)\n      MP_DEFINE_EXCEPTION(ConnectionAbortedError, ConnectionError)\n      MP_DEFINE_EXCEPTION(ConnectionRefusedError, ConnectionError)\n      MP_DEFINE_EXCEPTION(ConnectionResetError, ConnectionError)\n    MP_DEFINE_EXCEPTION(InterruptedError, OSError)\n    MP_DEFINE_EXCEPTION(IsADirectoryError, OSError)\n    MP_DEFINE_EXCEPTION(NotADirectoryError, OSError)\n    MP_DEFINE_EXCEPTION(PermissionError, OSError)\n    MP_DEFINE_EXCEPTION(ProcessLookupError, OSError)\n    MP_DEFINE_EXCEPTION(TimeoutError, OSError)\n    MP_DEFINE_EXCEPTION(FileExistsError, OSError)\n    MP_DEFINE_EXCEPTION(FileNotFoundError, OSError)\n    MP_DEFINE_EXCEPTION(ReferenceError, Exception)\n    */\n  MP_DEFINE_EXCEPTION(RuntimeError, Exception)\n    MP_DEFINE_EXCEPTION(NotImplementedError, RuntimeError)\n  MP_DEFINE_EXCEPTION(SyntaxError, Exception)\n    MP_DEFINE_EXCEPTION(IndentationError, SyntaxError)\n    /*\n      MP_DEFINE_EXCEPTION(TabError, IndentationError)\n      */\n  //MP_DEFINE_EXCEPTION(SystemError, Exception)\n  MP_DEFINE_EXCEPTION(TypeError, Exception)\n#if MICROPY_EMIT_NATIVE\n    MP_DEFINE_EXCEPTION(ViperTypeError, TypeError)\n#endif\n  MP_DEFINE_EXCEPTION(ValueError, Exception)\n#if MICROPY_PY_BUILTINS_STR_UNICODE\n    MP_DEFINE_EXCEPTION(UnicodeError, ValueError)\n    //TODO: Implement more UnicodeError subclasses which take arguments\n#endif\n  /*\n  MP_DEFINE_EXCEPTION(Warning, Exception)\n    MP_DEFINE_EXCEPTION(DeprecationWarning, Warning)\n    MP_DEFINE_EXCEPTION(PendingDeprecationWarning, Warning)\n    MP_DEFINE_EXCEPTION(RuntimeWarning, Warning)\n    MP_DEFINE_EXCEPTION(SyntaxWarning, Warning)\n    MP_DEFINE_EXCEPTION(UserWarning, Warning)\n    MP_DEFINE_EXCEPTION(FutureWarning, Warning)\n    MP_DEFINE_EXCEPTION(ImportWarning, Warning)\n    MP_DEFINE_EXCEPTION(UnicodeWarning, Warning)\n    MP_DEFINE_EXCEPTION(BytesWarning, Warning)\n    MP_DEFINE_EXCEPTION(ResourceWarning, Warning)\n    */\n\n// *FORMAT-ON*\n\nmp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) {\n    assert(exc_type->make_new == mp_obj_exception_make_new);\n    return mp_obj_exception_make_new(exc_type, 0, 0, NULL);\n}\n\n// \"Optimized\" version for common(?) case of having 1 exception arg\nmp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) {\n    assert(exc_type->make_new == mp_obj_exception_make_new);\n    return mp_obj_exception_make_new(exc_type, 1, 0, &arg);\n}\n\nmp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args) {\n    assert(exc_type->make_new == mp_obj_exception_make_new);\n    return mp_obj_exception_make_new(exc_type, n_args, 0, args);\n}\n\nmp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg) {\n    // Check that the given type is an exception type\n    assert(exc_type->make_new == mp_obj_exception_make_new);\n\n    // Try to allocate memory for the message\n    mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);\n\n    #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n    // If memory allocation failed and there is an emergency buffer then try to use\n    // that buffer to store the string object, reserving room at the start for the\n    // traceback and 1-tuple.\n    if (o_str == NULL\n        && mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t))) {\n        o_str = (mp_obj_str_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf)\n            + EMG_BUF_STR_OFFSET);\n    }\n    #endif\n\n    if (o_str == NULL) {\n        // No memory for the string object so create the exception with no args\n        return mp_obj_exception_make_new(exc_type, 0, 0, NULL);\n    }\n\n    // Create the string object and call mp_obj_exception_make_new to create the exception\n    o_str->base.type = &mp_type_str;\n    o_str->len = strlen((const char *)msg);\n    o_str->data = (const byte *)msg;\n    #if MICROPY_ROM_TEXT_COMPRESSION\n    o_str->hash = 0; // will be computed only if string object is accessed\n    #else\n    o_str->hash = qstr_compute_hash(o_str->data, o_str->len);\n    #endif\n    mp_obj_t arg = MP_OBJ_FROM_PTR(o_str);\n    return mp_obj_exception_make_new(exc_type, 1, 0, &arg);\n}\n\n// The following struct and function implement a simple printer that conservatively\n// allocates memory and truncates the output data if no more memory can be obtained.\n// It leaves room for a null byte at the end of the buffer.\n\nstruct _exc_printer_t {\n    bool allow_realloc;\n    size_t alloc;\n    size_t len;\n    byte *buf;\n};\n\nSTATIC void exc_add_strn(void *data, const char *str, size_t len) {\n    struct _exc_printer_t *pr = data;\n    if (pr->len + len >= pr->alloc) {\n        // Not enough room for data plus a null byte so try to grow the buffer\n        if (pr->allow_realloc) {\n            size_t new_alloc = pr->alloc + len + 16;\n            byte *new_buf = m_renew_maybe(byte, pr->buf, pr->alloc, new_alloc, true);\n            if (new_buf == NULL) {\n                pr->allow_realloc = false;\n                len = pr->alloc - pr->len - 1;\n            } else {\n                pr->alloc = new_alloc;\n                pr->buf = new_buf;\n            }\n        } else {\n            len = pr->alloc - pr->len - 1;\n        }\n    }\n    memcpy(pr->buf + pr->len, str, len);\n    pr->len += len;\n}\n\nmp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...) {\n    va_list args;\n    va_start(args, fmt);\n    mp_obj_t exc = mp_obj_new_exception_msg_vlist(exc_type, fmt, args);\n    va_end(args);\n    return exc;\n}\n\nmp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list args) {\n    assert(fmt != NULL);\n\n    // Check that the given type is an exception type\n    assert(exc_type->make_new == mp_obj_exception_make_new);\n\n    // Try to allocate memory for the message\n    mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);\n    size_t o_str_alloc = strlen((const char *)fmt) + 1;\n    byte *o_str_buf = m_new_maybe(byte, o_str_alloc);\n\n    bool used_emg_buf = false;\n    #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n    // If memory allocation failed and there is an emergency buffer then try to use\n    // that buffer to store the string object and its data (at least 16 bytes for\n    // the string data), reserving room at the start for the traceback and 1-tuple.\n    if ((o_str == NULL || o_str_buf == NULL)\n        && mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t) + 16)) {\n        used_emg_buf = true;\n        o_str = (mp_obj_str_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_STR_OFFSET);\n        o_str_buf = (byte *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_STR_BUF_OFFSET);\n        o_str_alloc = (uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - o_str_buf;\n    }\n    #endif\n\n    if (o_str == NULL) {\n        // No memory for the string object so create the exception with no args.\n        // The exception will only have a type and no message (compression is irrelevant).\n        return mp_obj_exception_make_new(exc_type, 0, 0, NULL);\n    }\n\n    if (o_str_buf == NULL) {\n        // No memory for the string buffer: assume that the fmt string is in ROM\n        // and use that data as the data of the string.\n        // The string will point directly to the compressed data -- will need to be decompressed\n        // prior to display (this case is identical to mp_obj_new_exception_msg above).\n        o_str->len = o_str_alloc - 1; // will be equal to strlen(fmt)\n        o_str->data = (const byte *)fmt;\n    } else {\n        // We have some memory to format the string.\n        // TODO: Optimise this to format-while-decompressing (and not require the temp stack space).\n        struct _exc_printer_t exc_pr = {!used_emg_buf, o_str_alloc, 0, o_str_buf};\n        mp_print_t print = {&exc_pr, exc_add_strn};\n        const char *fmt2 = (const char *)fmt;\n        #if MICROPY_ROM_TEXT_COMPRESSION\n        byte decompressed[MP_MAX_UNCOMPRESSED_TEXT_LEN];\n        if (MP_IS_COMPRESSED_ROM_STRING(fmt)) {\n            mp_decompress_rom_string(decompressed, fmt);\n            fmt2 = (const char *)decompressed;\n        }\n        #endif\n        mp_vprintf(&print, fmt2, args);\n        exc_pr.buf[exc_pr.len] = '\\0';\n        o_str->len = exc_pr.len;\n        o_str->data = exc_pr.buf;\n    }\n\n    // Create the string object and call mp_obj_exception_make_new to create the exception\n    o_str->base.type = &mp_type_str;\n    #if MICROPY_ROM_TEXT_COMPRESSION\n    o_str->hash = 0; // will be computed only if string object is accessed\n    #else\n    o_str->hash = qstr_compute_hash(o_str->data, o_str->len);\n    #endif\n    mp_obj_t arg = MP_OBJ_FROM_PTR(o_str);\n    return mp_obj_exception_make_new(exc_type, 1, 0, &arg);\n}\n\n// return true if the given object is an exception type\nbool mp_obj_is_exception_type(mp_obj_t self_in) {\n    if (mp_obj_is_type(self_in, &mp_type_type)) {\n        // optimisation when self_in is a builtin exception\n        mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);\n        if (self->make_new == mp_obj_exception_make_new) {\n            return true;\n        }\n    }\n    return mp_obj_is_subclass_fast(self_in, MP_OBJ_FROM_PTR(&mp_type_BaseException));\n}\n\n// return true if the given object is an instance of an exception type\nbool mp_obj_is_exception_instance(mp_obj_t self_in) {\n    return mp_obj_is_exception_type(MP_OBJ_FROM_PTR(mp_obj_get_type(self_in)));\n}\n\n// Return true if exception (type or instance) is a subclass of given\n// exception type.  Assumes exc_type is a subclass of BaseException, as\n// defined by mp_obj_is_exception_type(exc_type).\nbool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type) {\n    // if exc is an instance of an exception, then extract and use its type\n    if (mp_obj_is_exception_instance(exc)) {\n        exc = MP_OBJ_FROM_PTR(mp_obj_get_type(exc));\n    }\n    return mp_obj_is_subclass_fast(exc, exc_type);\n}\n\n// traceback handling functions\n\n#define GET_NATIVE_EXCEPTION(self, self_in) \\\n    /* make sure self_in is an exception instance */ \\\n    assert(mp_obj_is_exception_instance(self_in)); \\\n    mp_obj_exception_t *self; \\\n    if (mp_obj_is_native_exception_instance(self_in)) { \\\n        self = MP_OBJ_TO_PTR(self_in); \\\n    } else { \\\n        self = MP_OBJ_TO_PTR(((mp_obj_instance_t *)MP_OBJ_TO_PTR(self_in))->subobj[0]); \\\n    }\n\nvoid mp_obj_exception_clear_traceback(mp_obj_t self_in) {\n    GET_NATIVE_EXCEPTION(self, self_in);\n    // just set the traceback to the null object\n    // we don't want to call any memory management functions here\n    self->traceback_data = NULL;\n}\n\nvoid mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block) {\n    GET_NATIVE_EXCEPTION(self, self_in);\n\n    // append this traceback info to traceback data\n    // if memory allocation fails (eg because gc is locked), just return\n\n    if (self->traceback_data == NULL) {\n        self->traceback_data = m_new_maybe(size_t, TRACEBACK_ENTRY_LEN);\n        if (self->traceback_data == NULL) {\n            #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n            if (mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE)) {\n                // There is room in the emergency buffer for traceback data\n                size_t *tb = (size_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf)\n                    + EMG_BUF_TRACEBACK_OFFSET);\n                self->traceback_data = tb;\n                self->traceback_alloc = EMG_BUF_TRACEBACK_SIZE / sizeof(size_t);\n            } else {\n                // Can't allocate and no room in emergency buffer\n                return;\n            }\n            #else\n            // Can't allocate\n            return;\n            #endif\n        } else {\n            // Allocated the traceback data on the heap\n            self->traceback_alloc = TRACEBACK_ENTRY_LEN;\n        }\n        self->traceback_len = 0;\n    } else if (self->traceback_len + TRACEBACK_ENTRY_LEN > self->traceback_alloc) {\n        #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n        if (self->traceback_data == (size_t *)MP_STATE_VM(mp_emergency_exception_buf)) {\n            // Can't resize the emergency buffer\n            return;\n        }\n        #endif\n        // be conservative with growing traceback data\n        size_t *tb_data = m_renew_maybe(size_t, self->traceback_data, self->traceback_alloc,\n            self->traceback_alloc + TRACEBACK_ENTRY_LEN, true);\n        if (tb_data == NULL) {\n            return;\n        }\n        self->traceback_data = tb_data;\n        self->traceback_alloc += TRACEBACK_ENTRY_LEN;\n    }\n\n    size_t *tb_data = &self->traceback_data[self->traceback_len];\n    self->traceback_len += TRACEBACK_ENTRY_LEN;\n    tb_data[0] = file;\n    tb_data[1] = line;\n    tb_data[2] = block;\n}\n\nvoid mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values) {\n    GET_NATIVE_EXCEPTION(self, self_in);\n\n    if (self->traceback_data == NULL) {\n        *n = 0;\n        *values = NULL;\n    } else {\n        *n = self->traceback_len;\n        *values = self->traceback_data;\n    }\n}\n"
  },
  {
    "path": "py/objexcept.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJEXCEPT_H\n#define MICROPY_INCLUDED_PY_OBJEXCEPT_H\n\n#include \"py/obj.h\"\n#include \"py/objtuple.h\"\n\ntypedef struct _mp_obj_exception_t {\n    mp_obj_base_t base;\n    size_t traceback_alloc : (8 * sizeof(size_t) / 2);\n    size_t traceback_len : (8 * sizeof(size_t) / 2);\n    size_t *traceback_data;\n    mp_obj_tuple_t *args;\n} mp_obj_exception_t;\n\nvoid mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);\nvoid mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);\n\n#define MP_DEFINE_EXCEPTION(exc_name, base_name) \\\n    const mp_obj_type_t mp_type_##exc_name = { \\\n        { &mp_type_type }, \\\n        .name = MP_QSTR_##exc_name, \\\n        .print = mp_obj_exception_print, \\\n        .make_new = mp_obj_exception_make_new, \\\n        .attr = mp_obj_exception_attr, \\\n        .parent = &mp_type_##base_name, \\\n    };\n\n#endif // MICROPY_INCLUDED_PY_OBJEXCEPT_H\n"
  },
  {
    "path": "py/objfilter.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_FILTER\n\ntypedef struct _mp_obj_filter_t {\n    mp_obj_base_t base;\n    mp_obj_t fun;\n    mp_obj_t iter;\n} mp_obj_filter_t;\n\nSTATIC 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) {\n    mp_arg_check_num(n_args, n_kw, 2, 2, false);\n    mp_obj_filter_t *o = m_new_obj(mp_obj_filter_t);\n    o->base.type = type;\n    o->fun = args[0];\n    o->iter = mp_getiter(args[1], NULL);\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t filter_iternext(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_filter));\n    mp_obj_filter_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t next;\n    while ((next = mp_iternext(self->iter)) != MP_OBJ_STOP_ITERATION) {\n        mp_obj_t val;\n        if (self->fun != mp_const_none) {\n            val = mp_call_function_n_kw(self->fun, 1, 0, &next);\n        } else {\n            val = next;\n        }\n        if (mp_obj_is_true(val)) {\n            return next;\n        }\n    }\n    return MP_OBJ_STOP_ITERATION;\n}\n\nconst mp_obj_type_t mp_type_filter = {\n    { &mp_type_type },\n    .name = MP_QSTR_filter,\n    .make_new = filter_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = filter_iternext,\n};\n\n#endif // MICROPY_PY_BUILTINS_FILTER\n"
  },
  {
    "path": "py/objfloat.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/parsenum.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT\n\n#include <math.h>\n#include \"py/formatfloat.h\"\n\n#if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D\n\n// M_E and M_PI are not part of the math.h standard and may not be defined\n#ifndef M_E\n#define M_E (2.7182818284590452354)\n#endif\n#ifndef M_PI\n#define M_PI (3.14159265358979323846)\n#endif\n\ntypedef struct _mp_obj_float_t {\n    mp_obj_base_t base;\n    mp_float_t value;\n} mp_obj_float_t;\n\nconst mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, (mp_float_t)M_E};\nconst mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, (mp_float_t)M_PI};\n\n#endif\n\n#define MICROPY_FLOAT_ZERO MICROPY_FLOAT_CONST(0.0)\n\n#if MICROPY_FLOAT_HIGH_QUALITY_HASH\n// must return actual integer value if it fits in mp_int_t\nmp_int_t mp_float_hash(mp_float_t src) {\n    mp_float_union_t u = {.f = src};\n    mp_int_t val;\n    const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;\n    if (adj_exp < 0) {\n        // value < 1; must be sure to handle 0.0 correctly (ie return 0)\n        val = u.i;\n    } else {\n        // if adj_exp is max then: u.p.frc==0 indicates inf, else NaN\n        // else: 1 <= value\n        mp_float_uint_t frc = u.p.frc | ((mp_float_uint_t)1 << MP_FLOAT_FRAC_BITS);\n\n        if (adj_exp <= MP_FLOAT_FRAC_BITS) {\n            // number may have a fraction; xor the integer part with the fractional part\n            val = (frc >> (MP_FLOAT_FRAC_BITS - adj_exp))\n                ^ (frc & (((mp_float_uint_t)1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1));\n        } else if ((unsigned int)adj_exp < BITS_PER_BYTE * sizeof(mp_int_t) - 1) {\n            // the number is a (big) whole integer and will fit in val's signed-width\n            val = (mp_int_t)frc << (adj_exp - MP_FLOAT_FRAC_BITS);\n        } else {\n            // integer part will overflow val's width so just use what bits we can\n            val = frc;\n        }\n    }\n\n    if (u.p.sgn) {\n        val = -(mp_uint_t)val;\n    }\n\n    return val;\n}\n#endif\n\nSTATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_float_t o_val = mp_obj_float_get(o_in);\n    #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n    char buf[16];\n    #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C\n    const int precision = 6;\n    #else\n    const int precision = 7;\n    #endif\n    #else\n    char buf[32];\n    const int precision = 16;\n    #endif\n    mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\\0');\n    mp_print_str(print, buf);\n    if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) {\n        // Python floats always have decimal point (unless inf or nan)\n        mp_print_str(print, \".0\");\n    }\n}\n\nSTATIC 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) {\n    (void)type_in;\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n\n    switch (n_args) {\n        case 0:\n            return mp_obj_new_float(0);\n\n        case 1:\n        default: {\n            mp_buffer_info_t bufinfo;\n            if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) {\n                // a textual representation, parse it\n                return mp_parse_num_decimal(bufinfo.buf, bufinfo.len, false, false, NULL);\n            } else if (mp_obj_is_float(args[0])) {\n                // a float, just return it\n                return args[0];\n            } else {\n                // something else, try to cast it to a float\n                return mp_obj_new_float(mp_obj_get_float(args[0]));\n            }\n        }\n    }\n}\n\nSTATIC mp_obj_t float_unary_op(mp_unary_op_t op, mp_obj_t o_in) {\n    mp_float_t val = mp_obj_float_get(o_in);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(val != 0);\n        case MP_UNARY_OP_HASH:\n            return MP_OBJ_NEW_SMALL_INT(mp_float_hash(val));\n        case MP_UNARY_OP_POSITIVE:\n            return o_in;\n        case MP_UNARY_OP_NEGATIVE:\n            return mp_obj_new_float(-val);\n        case MP_UNARY_OP_ABS: {\n            if (signbit(val)) {\n                return mp_obj_new_float(-val);\n            } else {\n                return o_in;\n            }\n        }\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n\nSTATIC mp_obj_t float_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    mp_float_t lhs_val = mp_obj_float_get(lhs_in);\n    #if MICROPY_PY_BUILTINS_COMPLEX\n    if (mp_obj_is_type(rhs_in, &mp_type_complex)) {\n        return mp_obj_complex_binary_op(op, lhs_val, 0, rhs_in);\n    }\n    #endif\n    return mp_obj_float_binary_op(op, lhs_val, rhs_in);\n}\n\nconst mp_obj_type_t mp_type_float = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_EQ_NOT_REFLEXIVE | MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,\n    .name = MP_QSTR_float,\n    .print = float_print,\n    .make_new = float_make_new,\n    .unary_op = float_unary_op,\n    .binary_op = float_binary_op,\n};\n\n#if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D\n\nmp_obj_t mp_obj_new_float(mp_float_t value) {\n    mp_obj_float_t *o = m_new(mp_obj_float_t, 1);\n    o->base.type = &mp_type_float;\n    o->value = value;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nmp_float_t mp_obj_float_get(mp_obj_t self_in) {\n    assert(mp_obj_is_float(self_in));\n    mp_obj_float_t *self = MP_OBJ_TO_PTR(self_in);\n    return self->value;\n}\n\n#endif\n\nSTATIC void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) {\n    // logic here follows that of CPython\n    // https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations\n    // x == (x//y)*y + (x%y)\n    // divmod(x, y) == (x//y, x%y)\n    mp_float_t mod = MICROPY_FLOAT_C_FUN(fmod)(*x, *y);\n    mp_float_t div = (*x - mod) / *y;\n\n    // Python specs require that mod has same sign as second operand\n    if (mod == MICROPY_FLOAT_ZERO) {\n        mod = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *y);\n    } else {\n        if ((mod < MICROPY_FLOAT_ZERO) != (*y < MICROPY_FLOAT_ZERO)) {\n            mod += *y;\n            div -= MICROPY_FLOAT_CONST(1.0);\n        }\n    }\n\n    mp_float_t floordiv;\n    if (div == MICROPY_FLOAT_ZERO) {\n        // if division is zero, take the correct sign of zero\n        floordiv = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *x / *y);\n    } else {\n        // Python specs require that x == (x//y)*y + (x%y)\n        floordiv = MICROPY_FLOAT_C_FUN(floor)(div);\n        if (div - floordiv > MICROPY_FLOAT_CONST(0.5)) {\n            floordiv += MICROPY_FLOAT_CONST(1.0);\n        }\n    }\n\n    // return results\n    *x = floordiv;\n    *y = mod;\n}\n\nmp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t rhs_in) {\n    mp_float_t rhs_val;\n    if (!mp_obj_get_float_maybe(rhs_in, &rhs_val)) {\n        return MP_OBJ_NULL; // op not supported\n    }\n\n    switch (op) {\n        case MP_BINARY_OP_ADD:\n        case MP_BINARY_OP_INPLACE_ADD:\n            lhs_val += rhs_val;\n            break;\n        case MP_BINARY_OP_SUBTRACT:\n        case MP_BINARY_OP_INPLACE_SUBTRACT:\n            lhs_val -= rhs_val;\n            break;\n        case MP_BINARY_OP_MULTIPLY:\n        case MP_BINARY_OP_INPLACE_MULTIPLY:\n            lhs_val *= rhs_val;\n            break;\n        case MP_BINARY_OP_FLOOR_DIVIDE:\n        case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:\n            if (rhs_val == 0) {\n            zero_division_error:\n                mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT(\"divide by zero\"));\n            }\n            // Python specs require that x == (x//y)*y + (x%y) so we must\n            // call divmod to compute the correct floor division, which\n            // returns the floor divide in lhs_val.\n            mp_obj_float_divmod(&lhs_val, &rhs_val);\n            break;\n        case MP_BINARY_OP_TRUE_DIVIDE:\n        case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:\n            if (rhs_val == 0) {\n                goto zero_division_error;\n            }\n            lhs_val /= rhs_val;\n            break;\n        case MP_BINARY_OP_MODULO:\n        case MP_BINARY_OP_INPLACE_MODULO:\n            if (rhs_val == MICROPY_FLOAT_ZERO) {\n                goto zero_division_error;\n            }\n            lhs_val = MICROPY_FLOAT_C_FUN(fmod)(lhs_val, rhs_val);\n            // Python specs require that mod has same sign as second operand\n            if (lhs_val == MICROPY_FLOAT_ZERO) {\n                lhs_val = MICROPY_FLOAT_C_FUN(copysign)(0.0, rhs_val);\n            } else {\n                if ((lhs_val < MICROPY_FLOAT_ZERO) != (rhs_val < MICROPY_FLOAT_ZERO)) {\n                    lhs_val += rhs_val;\n                }\n            }\n            break;\n        case MP_BINARY_OP_POWER:\n        case MP_BINARY_OP_INPLACE_POWER:\n            if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) {\n                goto zero_division_error;\n            }\n            if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val) && !isnan(rhs_val)) {\n                #if MICROPY_PY_BUILTINS_COMPLEX\n                return mp_obj_complex_binary_op(MP_BINARY_OP_POWER, lhs_val, 0, rhs_in);\n                #else\n                mp_raise_ValueError(MP_ERROR_TEXT(\"complex values not supported\"));\n                #endif\n            }\n            #if MICROPY_PY_MATH_POW_FIX_NAN // Also see modmath.c.\n            if (lhs_val == MICROPY_FLOAT_CONST(1.0) || rhs_val == MICROPY_FLOAT_CONST(0.0)) {\n                lhs_val = MICROPY_FLOAT_CONST(1.0);\n                break;\n            }\n            #endif\n            lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val);\n            break;\n        case MP_BINARY_OP_DIVMOD: {\n            if (rhs_val == 0) {\n                goto zero_division_error;\n            }\n            mp_obj_float_divmod(&lhs_val, &rhs_val);\n            mp_obj_t tuple[2] = {\n                mp_obj_new_float(lhs_val),\n                mp_obj_new_float(rhs_val),\n            };\n            return mp_obj_new_tuple(2, tuple);\n        }\n        case MP_BINARY_OP_LESS:\n            return mp_obj_new_bool(lhs_val < rhs_val);\n        case MP_BINARY_OP_MORE:\n            return mp_obj_new_bool(lhs_val > rhs_val);\n        case MP_BINARY_OP_EQUAL:\n            return mp_obj_new_bool(lhs_val == rhs_val);\n        case MP_BINARY_OP_LESS_EQUAL:\n            return mp_obj_new_bool(lhs_val <= rhs_val);\n        case MP_BINARY_OP_MORE_EQUAL:\n            return mp_obj_new_bool(lhs_val >= rhs_val);\n\n        default:\n            return MP_OBJ_NULL; // op not supported\n    }\n    return mp_obj_new_float(lhs_val);\n}\n\n#endif // MICROPY_PY_BUILTINS_FLOAT\n"
  },
  {
    "path": "py/objfun.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <assert.h>\n\n#include \"py/objtuple.h\"\n#include \"py/objfun.h\"\n#include \"py/runtime.h\"\n#include \"py/bc.h\"\n#include \"py/stackctrl.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_PRINT (1)\n#else // don't print debugging info\n#define DEBUG_PRINT (0)\n#define DEBUG_printf(...) (void)0\n#endif\n\n// Note: the \"name\" entry in mp_obj_type_t for a function type must be\n// MP_QSTR_function because it is used to determine if an object is of generic\n// function type.\n\n/******************************************************************************/\n/* builtin functions                                                          */\n\nSTATIC 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) {\n    (void)args;\n    assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_0));\n    mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_arg_check_num(n_args, n_kw, 0, 0, false);\n    return self->fun._0();\n}\n\nconst mp_obj_type_t mp_type_fun_builtin_0 = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,\n    .name = MP_QSTR_function,\n    .call = fun_builtin_0_call,\n    .unary_op = mp_generic_unary_op,\n};\n\nSTATIC 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) {\n    assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_1));\n    mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_arg_check_num(n_args, n_kw, 1, 1, false);\n    return self->fun._1(args[0]);\n}\n\nconst mp_obj_type_t mp_type_fun_builtin_1 = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,\n    .name = MP_QSTR_function,\n    .call = fun_builtin_1_call,\n    .unary_op = mp_generic_unary_op,\n};\n\nSTATIC 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) {\n    assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_2));\n    mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_arg_check_num(n_args, n_kw, 2, 2, false);\n    return self->fun._2(args[0], args[1]);\n}\n\nconst mp_obj_type_t mp_type_fun_builtin_2 = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,\n    .name = MP_QSTR_function,\n    .call = fun_builtin_2_call,\n    .unary_op = mp_generic_unary_op,\n};\n\nSTATIC 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) {\n    assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_3));\n    mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_arg_check_num(n_args, n_kw, 3, 3, false);\n    return self->fun._3(args[0], args[1], args[2]);\n}\n\nconst mp_obj_type_t mp_type_fun_builtin_3 = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,\n    .name = MP_QSTR_function,\n    .call = fun_builtin_3_call,\n    .unary_op = mp_generic_unary_op,\n};\n\nSTATIC 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) {\n    assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_var));\n    mp_obj_fun_builtin_var_t *self = MP_OBJ_TO_PTR(self_in);\n\n    // check number of arguments\n    mp_arg_check_num_sig(n_args, n_kw, self->sig);\n\n    if (self->sig & 1) {\n        // function allows keywords\n\n        // we create a map directly from the given args array\n        mp_map_t kw_args;\n        mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);\n\n        return self->fun.kw(n_args, args, &kw_args);\n\n    } else {\n        // function takes a variable number of arguments, but no keywords\n\n        return self->fun.var(n_args, args);\n    }\n}\n\nconst mp_obj_type_t mp_type_fun_builtin_var = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,\n    .name = MP_QSTR_function,\n    .call = fun_builtin_var_call,\n    .unary_op = mp_generic_unary_op,\n};\n\n/******************************************************************************/\n/* byte code functions                                                        */\n\nqstr mp_obj_code_get_name(const byte *code_info) {\n    MP_BC_PRELUDE_SIZE_DECODE(code_info);\n    #if MICROPY_PERSISTENT_CODE\n    return code_info[0] | (code_info[1] << 8);\n    #else\n    return mp_decode_uint_value(code_info);\n    #endif\n}\n\n#if MICROPY_EMIT_NATIVE\nSTATIC const mp_obj_type_t mp_type_fun_native;\n#endif\n\nqstr mp_obj_fun_get_name(mp_const_obj_t fun_in) {\n    const mp_obj_fun_bc_t *fun = MP_OBJ_TO_PTR(fun_in);\n    #if MICROPY_EMIT_NATIVE\n    if (fun->base.type == &mp_type_fun_native || fun->base.type == &mp_type_native_gen_wrap) {\n        // TODO native functions don't have name stored\n        return MP_QSTR_;\n    }\n    #endif\n\n    const byte *bc = fun->bytecode;\n    MP_BC_PRELUDE_SIG_DECODE(bc);\n    return mp_obj_code_get_name(bc);\n}\n\n#if MICROPY_CPYTHON_COMPAT\nSTATIC void fun_bc_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_fun_bc_t *o = MP_OBJ_TO_PTR(o_in);\n    mp_printf(print, \"<function %q at 0x%p>\", mp_obj_fun_get_name(o_in), o);\n}\n#endif\n\n#if DEBUG_PRINT\nSTATIC void dump_args(const mp_obj_t *a, size_t sz) {\n    DEBUG_printf(\"%p: \", a);\n    for (size_t i = 0; i < sz; i++) {\n        DEBUG_printf(\"%p \", a[i]);\n    }\n    DEBUG_printf(\"\\n\");\n}\n#else\n#define dump_args(...) (void)0\n#endif\n\n// With this macro you can tune the maximum number of function state bytes\n// that will be allocated on the stack.  Any function that needs more\n// than this will try to use the heap, with fallback to stack allocation.\n#define VM_MAX_STATE_ON_STACK (sizeof(mp_uint_t) * 11)\n\n#define DECODE_CODESTATE_SIZE(bytecode, n_state_out_var, state_size_out_var) \\\n    { \\\n        const uint8_t *ip = bytecode; \\\n        size_t n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_args; \\\n        MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state_out_var, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_args); \\\n                                    \\\n        /* state size in bytes */                                                 \\\n        state_size_out_var = n_state_out_var * sizeof(mp_obj_t)                   \\\n            + n_exc_stack * sizeof(mp_exc_stack_t);                \\\n    }\n\n#define INIT_CODESTATE(code_state, _fun_bc, _n_state, n_args, n_kw, args) \\\n    code_state->fun_bc = _fun_bc; \\\n    code_state->ip = 0; \\\n    code_state->n_state = _n_state; \\\n    mp_setup_code_state(code_state, n_args, n_kw, args); \\\n    code_state->old_globals = mp_globals_get();\n\n#if MICROPY_STACKLESS\nmp_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) {\n    MP_STACK_CHECK();\n    mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);\n\n    size_t n_state, state_size;\n    DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size);\n\n    mp_code_state_t *code_state;\n    #if MICROPY_ENABLE_PYSTACK\n    code_state = mp_pystack_alloc(sizeof(mp_code_state_t) + state_size);\n    #else\n    // If we use m_new_obj_var(), then on no memory, MemoryError will be\n    // raised. But this is not correct exception for a function call,\n    // RuntimeError should be raised instead. So, we use m_new_obj_var_maybe(),\n    // return NULL, then vm.c takes the needed action (either raise\n    // RuntimeError or fallback to stack allocation).\n    code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size);\n    if (!code_state) {\n        return NULL;\n    }\n    #endif\n\n    INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args);\n\n    // execute the byte code with the correct globals context\n    mp_globals_set(self->globals);\n\n    return code_state;\n}\n#endif\n\nSTATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    MP_STACK_CHECK();\n\n    DEBUG_printf(\"Input n_args: \" UINT_FMT \", n_kw: \" UINT_FMT \"\\n\", n_args, n_kw);\n    DEBUG_printf(\"Input pos args: \");\n    dump_args(args, n_args);\n    DEBUG_printf(\"Input kw args: \");\n    dump_args(args + n_args, n_kw * 2);\n\n    mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);\n\n    size_t n_state, state_size;\n    DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size);\n\n    // allocate state for locals and stack\n    mp_code_state_t *code_state = NULL;\n    #if MICROPY_ENABLE_PYSTACK\n    code_state = mp_pystack_alloc(sizeof(mp_code_state_t) + state_size);\n    #else\n    if (state_size > VM_MAX_STATE_ON_STACK) {\n        code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size);\n        #if MICROPY_DEBUG_VM_STACK_OVERFLOW\n        if (code_state != NULL) {\n            memset(code_state->state, 0, state_size);\n        }\n        #endif\n    }\n    if (code_state == NULL) {\n        code_state = alloca(sizeof(mp_code_state_t) + state_size);\n        #if MICROPY_DEBUG_VM_STACK_OVERFLOW\n        memset(code_state->state, 0, state_size);\n        #endif\n        state_size = 0; // indicate that we allocated using alloca\n    }\n    #endif\n\n    INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args);\n\n    // execute the byte code with the correct globals context\n    mp_globals_set(self->globals);\n    mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL);\n    mp_globals_set(code_state->old_globals);\n\n    #if MICROPY_DEBUG_VM_STACK_OVERFLOW\n    if (vm_return_kind == MP_VM_RETURN_NORMAL) {\n        if (code_state->sp < code_state->state) {\n            mp_printf(MICROPY_DEBUG_PRINTER, \"VM stack underflow: \" INT_FMT \"\\n\", code_state->sp - code_state->state);\n            assert(0);\n        }\n    }\n    const byte *bytecode_ptr = self->bytecode;\n    size_t n_state_unused, n_exc_stack_unused, scope_flags_unused;\n    size_t n_pos_args, n_kwonly_args, n_def_args_unused;\n    MP_BC_PRELUDE_SIG_DECODE_INTO(bytecode_ptr, n_state_unused, n_exc_stack_unused,\n        scope_flags_unused, n_pos_args, n_kwonly_args, n_def_args_unused);\n    // We can't check the case when an exception is returned in state[0]\n    // and there are no arguments, because in this case our detection slot may have\n    // been overwritten by the returned exception (which is allowed).\n    if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && n_pos_args + n_kwonly_args == 0)) {\n        // Just check to see that we have at least 1 null object left in the state.\n        bool overflow = true;\n        for (size_t i = 0; i < n_state - n_pos_args - n_kwonly_args; ++i) {\n            if (code_state->state[i] == MP_OBJ_NULL) {\n                overflow = false;\n                break;\n            }\n        }\n        if (overflow) {\n            mp_printf(MICROPY_DEBUG_PRINTER, \"VM stack overflow state=%p n_state+1=\" UINT_FMT \"\\n\", code_state->state, n_state);\n            assert(0);\n        }\n    }\n    #endif\n\n    mp_obj_t result;\n    if (vm_return_kind == MP_VM_RETURN_NORMAL) {\n        // return value is in *sp\n        result = *code_state->sp;\n    } else {\n        // must be an exception because normal functions can't yield\n        assert(vm_return_kind == MP_VM_RETURN_EXCEPTION);\n        // returned exception is in state[0]\n        result = code_state->state[0];\n    }\n\n    #if MICROPY_ENABLE_PYSTACK\n    mp_pystack_free(code_state);\n    #else\n    // free the state if it was allocated on the heap\n    if (state_size != 0) {\n        m_del_var(mp_code_state_t, byte, state_size, code_state);\n    }\n    #endif\n\n    if (vm_return_kind == MP_VM_RETURN_NORMAL) {\n        return result;\n    } else { // MP_VM_RETURN_EXCEPTION\n        nlr_raise(result);\n    }\n}\n\n#if MICROPY_PY_FUNCTION_ATTRS\nvoid mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] != MP_OBJ_NULL) {\n        // not load attribute\n        return;\n    }\n    if (attr == MP_QSTR___name__) {\n        dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(self_in));\n    }\n}\n#endif\n\nconst mp_obj_type_t mp_type_fun_bc = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF,\n    .name = MP_QSTR_function,\n    #if MICROPY_CPYTHON_COMPAT\n    .print = fun_bc_print,\n    #endif\n    .call = fun_bc_call,\n    .unary_op = mp_generic_unary_op,\n    #if MICROPY_PY_FUNCTION_ATTRS\n    .attr = mp_obj_fun_bc_attr,\n    #endif\n};\n\nmp_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) {\n    size_t n_def_args = 0;\n    size_t n_extra_args = 0;\n    mp_obj_tuple_t *def_args = MP_OBJ_TO_PTR(def_args_in);\n    if (def_args_in != MP_OBJ_NULL) {\n        assert(mp_obj_is_type(def_args_in, &mp_type_tuple));\n        n_def_args = def_args->len;\n        n_extra_args = def_args->len;\n    }\n    if (def_kw_args != MP_OBJ_NULL) {\n        n_extra_args += 1;\n    }\n    mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args);\n    o->base.type = &mp_type_fun_bc;\n    o->globals = mp_globals_get();\n    o->bytecode = code;\n    o->const_table = const_table;\n    if (def_args != NULL) {\n        memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));\n    }\n    if (def_kw_args != MP_OBJ_NULL) {\n        o->extra_args[n_def_args] = def_kw_args;\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\n/******************************************************************************/\n/* native functions                                                           */\n\n#if MICROPY_EMIT_NATIVE\n\nSTATIC mp_obj_t fun_native_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    MP_STACK_CHECK();\n    mp_obj_fun_bc_t *self = self_in;\n    mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void *)self->bytecode);\n    return fun(self_in, n_args, n_kw, args);\n}\n\nSTATIC const mp_obj_type_t mp_type_fun_native = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF,\n    .name = MP_QSTR_function,\n    .call = fun_native_call,\n    .unary_op = mp_generic_unary_op,\n};\n\nmp_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) {\n    mp_obj_fun_bc_t *o = mp_obj_new_fun_bc(def_args_in, def_kw_args, (const byte *)fun_data, const_table);\n    o->base.type = &mp_type_fun_native;\n    return o;\n}\n\n#endif // MICROPY_EMIT_NATIVE\n\n/******************************************************************************/\n/* inline assembler functions                                                 */\n\n#if MICROPY_EMIT_INLINE_ASM\n\ntypedef struct _mp_obj_fun_asm_t {\n    mp_obj_base_t base;\n    size_t n_args;\n    const void *fun_data; // GC must be able to trace this pointer\n    mp_uint_t type_sig;\n} mp_obj_fun_asm_t;\n\ntypedef mp_uint_t (*inline_asm_fun_0_t)(void);\ntypedef mp_uint_t (*inline_asm_fun_1_t)(mp_uint_t);\ntypedef mp_uint_t (*inline_asm_fun_2_t)(mp_uint_t, mp_uint_t);\ntypedef mp_uint_t (*inline_asm_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t);\ntypedef mp_uint_t (*inline_asm_fun_4_t)(mp_uint_t, mp_uint_t, mp_uint_t, mp_uint_t);\n\n// convert a MicroPython object to a sensible value for inline asm\nSTATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {\n    // TODO for byte_array, pass pointer to the array\n    if (mp_obj_is_small_int(obj)) {\n        return MP_OBJ_SMALL_INT_VALUE(obj);\n    } else if (obj == mp_const_none) {\n        return 0;\n    } else if (obj == mp_const_false) {\n        return 0;\n    } else if (obj == mp_const_true) {\n        return 1;\n    } else if (mp_obj_is_type(obj, &mp_type_int)) {\n        return mp_obj_int_get_truncated(obj);\n    } else if (mp_obj_is_str(obj)) {\n        // pointer to the string (it's probably constant though!)\n        size_t l;\n        return (mp_uint_t)mp_obj_str_get_data(obj, &l);\n    } else {\n        const mp_obj_type_t *type = mp_obj_get_type(obj);\n        #if MICROPY_PY_BUILTINS_FLOAT\n        if (type == &mp_type_float) {\n            // convert float to int (could also pass in float registers)\n            return (mp_int_t)mp_obj_float_get(obj);\n        }\n        #endif\n        if (type == &mp_type_tuple || type == &mp_type_list) {\n            // pointer to start of tuple (could pass length, but then could use len(x) for that)\n            size_t len;\n            mp_obj_t *items;\n            mp_obj_get_array(obj, &len, &items);\n            return (mp_uint_t)items;\n        } else {\n            mp_buffer_info_t bufinfo;\n            if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_READ)) {\n                // supports the buffer protocol, return a pointer to the data\n                return (mp_uint_t)bufinfo.buf;\n            } else {\n                // just pass along a pointer to the object\n                return (mp_uint_t)obj;\n            }\n        }\n    }\n}\n\nSTATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_obj_fun_asm_t *self = self_in;\n\n    mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);\n\n    const void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);\n\n    mp_uint_t ret;\n    if (n_args == 0) {\n        ret = ((inline_asm_fun_0_t)fun)();\n    } else if (n_args == 1) {\n        ret = ((inline_asm_fun_1_t)fun)(convert_obj_for_inline_asm(args[0]));\n    } else if (n_args == 2) {\n        ret = ((inline_asm_fun_2_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]));\n    } else if (n_args == 3) {\n        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]));\n    } else {\n        // compiler allows at most 4 arguments\n        assert(n_args == 4);\n        ret = ((inline_asm_fun_4_t)fun)(\n            convert_obj_for_inline_asm(args[0]),\n            convert_obj_for_inline_asm(args[1]),\n            convert_obj_for_inline_asm(args[2]),\n            convert_obj_for_inline_asm(args[3])\n            );\n    }\n\n    return mp_native_to_obj(ret, self->type_sig);\n}\n\nSTATIC const mp_obj_type_t mp_type_fun_asm = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF,\n    .name = MP_QSTR_function,\n    .call = fun_asm_call,\n    .unary_op = mp_generic_unary_op,\n};\n\nmp_obj_t mp_obj_new_fun_asm(size_t n_args, const void *fun_data, mp_uint_t type_sig) {\n    mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);\n    o->base.type = &mp_type_fun_asm;\n    o->n_args = n_args;\n    o->fun_data = fun_data;\n    o->type_sig = type_sig;\n    return o;\n}\n\n#endif // MICROPY_EMIT_INLINE_ASM\n"
  },
  {
    "path": "py/objfun.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJFUN_H\n#define MICROPY_INCLUDED_PY_OBJFUN_H\n\n#include \"py/obj.h\"\n\ntypedef struct _mp_obj_fun_bc_t {\n    mp_obj_base_t base;\n    mp_obj_dict_t *globals;         // the context within which this function was defined\n    const byte *bytecode;           // bytecode for the function\n    const mp_uint_t *const_table;   // constant table\n    #if MICROPY_PY_SYS_SETTRACE\n    const struct _mp_raw_code_t *rc;\n    #endif\n    // the following extra_args array is allocated space to take (in order):\n    //  - values of positional default args (if any)\n    //  - a single slot for default kw args dict (if it has them)\n    //  - a single slot for var args tuple (if it takes them)\n    //  - a single slot for kw args dict (if it takes them)\n    mp_obj_t extra_args[];\n} mp_obj_fun_bc_t;\n\nvoid mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);\n\n#endif // MICROPY_INCLUDED_PY_OBJFUN_H\n"
  },
  {
    "path": "py/objgenerator.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2019 Damien P. George\n * Copyright (c) 2014-2017 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n#include \"py/bc.h\"\n#include \"py/objstr.h\"\n#include \"py/objgenerator.h\"\n#include \"py/objfun.h\"\n#include \"py/stackctrl.h\"\n\n// Instance of GeneratorExit exception - needed by generator.close()\nconst mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t *)&mp_const_empty_tuple_obj};\n\n/******************************************************************************/\n/* generator wrapper                                                          */\n\ntypedef struct _mp_obj_gen_instance_t {\n    mp_obj_base_t base;\n    // mp_const_none: Not-running, no exception.\n    // MP_OBJ_NULL: Running, no exception.\n    // other: Not running, pending exception.\n    mp_obj_t pend_exc;\n    mp_code_state_t code_state;\n} mp_obj_gen_instance_t;\n\nSTATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    // A generating function is just a bytecode function with type mp_type_gen_wrap\n    mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in);\n\n    // bytecode prelude: get state size and exception stack size\n    const uint8_t *ip = self_fun->bytecode;\n    MP_BC_PRELUDE_SIG_DECODE(ip);\n\n    // allocate the generator object, with room for local stack and exception stack\n    mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte,\n        n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t));\n    o->base.type = &mp_type_gen_instance;\n\n    o->pend_exc = mp_const_none;\n    o->code_state.fun_bc = self_fun;\n    o->code_state.ip = 0;\n    o->code_state.n_state = n_state;\n    mp_setup_code_state(&o->code_state, n_args, n_kw, args);\n    return MP_OBJ_FROM_PTR(o);\n}\n\nconst mp_obj_type_t mp_type_gen_wrap = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF,\n    .name = MP_QSTR_generator,\n    .call = gen_wrap_call,\n    .unary_op = mp_generic_unary_op,\n    #if MICROPY_PY_FUNCTION_ATTRS\n    .attr = mp_obj_fun_bc_attr,\n    #endif\n};\n\n/******************************************************************************/\n// native generator wrapper\n\n#if MICROPY_EMIT_NATIVE\n\nSTATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    // The state for a native generating function is held in the same struct as a bytecode function\n    mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in);\n\n    // Determine start of prelude, and extract n_state from it\n    uintptr_t prelude_offset = ((uintptr_t *)self_fun->bytecode)[0];\n    #if MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ\n    // Prelude is in bytes object in const_table, at index prelude_offset\n    mp_obj_str_t *prelude_bytes = MP_OBJ_TO_PTR(self_fun->const_table[prelude_offset]);\n    prelude_offset = (const byte *)prelude_bytes->data - self_fun->bytecode;\n    #endif\n    const uint8_t *ip = self_fun->bytecode + prelude_offset;\n    size_t n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args;\n    MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args);\n    size_t n_exc_stack = 0;\n\n    // Allocate the generator object, with room for local stack and exception stack\n    mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte,\n        n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t));\n    o->base.type = &mp_type_gen_instance;\n\n    // Parse the input arguments and set up the code state\n    o->pend_exc = mp_const_none;\n    o->code_state.fun_bc = self_fun;\n    o->code_state.ip = (const byte *)prelude_offset;\n    o->code_state.n_state = n_state;\n    mp_setup_code_state(&o->code_state, n_args, n_kw, args);\n\n    // Indicate we are a native function, which doesn't use this variable\n    o->code_state.exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_SENTINEL;\n\n    // Prepare the generator instance for execution\n    uintptr_t start_offset = ((uintptr_t *)self_fun->bytecode)[1];\n    o->code_state.ip = MICROPY_MAKE_POINTER_CALLABLE((void *)(self_fun->bytecode + start_offset));\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\nconst mp_obj_type_t mp_type_native_gen_wrap = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF,\n    .name = MP_QSTR_generator,\n    .call = native_gen_wrap_call,\n    .unary_op = mp_generic_unary_op,\n    #if MICROPY_PY_FUNCTION_ATTRS\n    .attr = mp_obj_fun_bc_attr,\n    #endif\n};\n\n#endif // MICROPY_EMIT_NATIVE\n\n/******************************************************************************/\n/* generator instance                                                         */\n\nSTATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<generator object '%q' at %p>\", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self);\n}\n\nmp_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) {\n    MP_STACK_CHECK();\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_gen_instance));\n    mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->code_state.ip == 0) {\n        // Trying to resume already stopped generator\n        *ret_val = MP_OBJ_STOP_ITERATION;\n        return MP_VM_RETURN_NORMAL;\n    }\n\n    // Ensure the generator cannot be reentered during execution\n    if (self->pend_exc == MP_OBJ_NULL) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"generator already executing\"));\n    }\n\n    #if MICROPY_PY_GENERATOR_PEND_THROW\n    // If exception is pending (set using .pend_throw()), process it now.\n    if (self->pend_exc != mp_const_none) {\n        throw_value = self->pend_exc;\n    }\n    #endif\n\n    // If the generator is started, allow sending a value.\n    if (self->code_state.sp == self->code_state.state - 1) {\n        if (send_value != mp_const_none) {\n            mp_raise_TypeError(MP_ERROR_TEXT(\"can't send non-None value to a just-started generator\"));\n        }\n    } else {\n        *self->code_state.sp = send_value;\n    }\n\n    // Mark as running\n    self->pend_exc = MP_OBJ_NULL;\n\n    // Set up the correct globals context for the generator and execute it\n    self->code_state.old_globals = mp_globals_get();\n    mp_globals_set(self->code_state.fun_bc->globals);\n\n    mp_vm_return_kind_t ret_kind;\n\n    #if MICROPY_EMIT_NATIVE\n    if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) {\n        // A native generator, with entry point 2 words into the \"bytecode\" pointer\n        typedef uintptr_t (*mp_fun_native_gen_t)(void *, mp_obj_t);\n        mp_fun_native_gen_t fun = MICROPY_MAKE_POINTER_CALLABLE((const void *)(self->code_state.fun_bc->bytecode + 2 * sizeof(uintptr_t)));\n        ret_kind = fun((void *)&self->code_state, throw_value);\n    } else\n    #endif\n    {\n        // A bytecode generator\n        ret_kind = mp_execute_bytecode(&self->code_state, throw_value);\n    }\n\n    mp_globals_set(self->code_state.old_globals);\n\n    // Mark as not running\n    self->pend_exc = mp_const_none;\n\n    switch (ret_kind) {\n        case MP_VM_RETURN_NORMAL:\n        default:\n            // Explicitly mark generator as completed. If we don't do this,\n            // subsequent next() may re-execute statements after last yield\n            // again and again, leading to side effects.\n            self->code_state.ip = 0;\n            *ret_val = *self->code_state.sp;\n            break;\n\n        case MP_VM_RETURN_YIELD:\n            *ret_val = *self->code_state.sp;\n            #if MICROPY_PY_GENERATOR_PEND_THROW\n            *self->code_state.sp = mp_const_none;\n            #endif\n            break;\n\n        case MP_VM_RETURN_EXCEPTION: {\n            self->code_state.ip = 0;\n            *ret_val = self->code_state.state[0];\n            // PEP479: if StopIteration is raised inside a generator it is replaced with RuntimeError\n            if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(*ret_val)), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) {\n                *ret_val = mp_obj_new_exception_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"generator raised StopIteration\"));\n            }\n            break;\n        }\n    }\n\n    return ret_kind;\n}\n\nSTATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value) {\n    mp_obj_t ret;\n    switch (mp_obj_gen_resume(self_in, send_value, throw_value, &ret)) {\n        case MP_VM_RETURN_NORMAL:\n        default:\n            // Optimize return w/o value in case generator is used in for loop\n            if (ret == mp_const_none || ret == MP_OBJ_STOP_ITERATION) {\n                return MP_OBJ_STOP_ITERATION;\n            } else {\n                nlr_raise(mp_obj_new_exception_arg1(&mp_type_StopIteration, ret));\n            }\n\n        case MP_VM_RETURN_YIELD:\n            return ret;\n\n        case MP_VM_RETURN_EXCEPTION:\n            nlr_raise(ret);\n    }\n}\n\nSTATIC mp_obj_t gen_instance_iternext(mp_obj_t self_in) {\n    return gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL);\n}\n\nSTATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) {\n    mp_obj_t ret = gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL);\n    if (ret == MP_OBJ_STOP_ITERATION) {\n        mp_raise_type(&mp_type_StopIteration);\n    } else {\n        return ret;\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send);\n\nSTATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) {\n    // The signature of this function is: throw(type[, value[, traceback]])\n    // CPython will pass all given arguments through the call chain and process them\n    // at the point they are used (native generators will handle them differently to\n    // user-defined generators with a throw() method).  To save passing multiple\n    // values, MicroPython instead does partial processing here to reduce it down to\n    // one argument and passes that through:\n    // - if only args[1] is given, or args[2] is given but is None, args[1] is\n    //   passed through (in the standard case it is an exception class or instance)\n    // - if args[2] is given and not None it is passed through (in the standard\n    //   case it would be an exception instance and args[1] its corresponding class)\n    // - args[3] is always ignored\n\n    mp_obj_t exc = args[1];\n    if (n_args > 2 && args[2] != mp_const_none) {\n        exc = args[2];\n    }\n\n    mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc);\n    if (ret == MP_OBJ_STOP_ITERATION) {\n        mp_raise_type(&mp_type_StopIteration);\n    } else {\n        return ret;\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw);\n\nSTATIC mp_obj_t gen_instance_close(mp_obj_t self_in) {\n    mp_obj_t ret;\n    switch (mp_obj_gen_resume(self_in, mp_const_none, MP_OBJ_FROM_PTR(&mp_const_GeneratorExit_obj), &ret)) {\n        case MP_VM_RETURN_YIELD:\n            mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"generator ignored GeneratorExit\"));\n\n        // Swallow GeneratorExit (== successful close), and re-raise any other\n        case MP_VM_RETURN_EXCEPTION:\n            // ret should always be an instance of an exception class\n            if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(ret)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) {\n                return mp_const_none;\n            }\n            nlr_raise(ret);\n\n        default:\n            // The only choice left is MP_VM_RETURN_NORMAL which is successful close\n            return mp_const_none;\n    }\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close);\n\n#if MICROPY_PY_GENERATOR_PEND_THROW\nSTATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) {\n    mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->pend_exc == MP_OBJ_NULL) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"generator already executing\"));\n    }\n    mp_obj_t prev = self->pend_exc;\n    self->pend_exc = exc_in;\n    return prev;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_pend_throw_obj, gen_instance_pend_throw);\n#endif\n\nSTATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&gen_instance_close_obj) },\n    { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&gen_instance_send_obj) },\n    { MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&gen_instance_throw_obj) },\n    #if MICROPY_PY_GENERATOR_PEND_THROW\n    { MP_ROM_QSTR(MP_QSTR_pend_throw), MP_ROM_PTR(&gen_instance_pend_throw_obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table);\n\nconst mp_obj_type_t mp_type_gen_instance = {\n    { &mp_type_type },\n    .name = MP_QSTR_generator,\n    .print = gen_instance_print,\n    .unary_op = mp_generic_unary_op,\n    .getiter = mp_identity_getiter,\n    .iternext = gen_instance_iternext,\n    .locals_dict = (mp_obj_dict_t *)&gen_instance_locals_dict,\n};\n"
  },
  {
    "path": "py/objgenerator.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJGENERATOR_H\n#define MICROPY_INCLUDED_PY_OBJGENERATOR_H\n\n#include \"py/obj.h\"\n#include \"py/runtime.h\"\n\nmp_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);\n\n#endif // MICROPY_INCLUDED_PY_OBJGENERATOR_H\n"
  },
  {
    "path": "py/objgetitemiter.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n\n#include \"py/runtime.h\"\n\n// this is a wrapper object that turns something that has a __getitem__ method into an iterator\n\ntypedef struct _mp_obj_getitem_iter_t {\n    mp_obj_base_t base;\n    mp_obj_t args[3];\n} mp_obj_getitem_iter_t;\n\nSTATIC mp_obj_t it_iternext(mp_obj_t self_in) {\n    mp_obj_getitem_iter_t *self = MP_OBJ_TO_PTR(self_in);\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        // try to get next item\n        mp_obj_t value = mp_call_method_n_kw(1, 0, self->args);\n        self->args[2] = MP_OBJ_NEW_SMALL_INT(MP_OBJ_SMALL_INT_VALUE(self->args[2]) + 1);\n        nlr_pop();\n        return value;\n    } else {\n        // an exception was raised\n        mp_obj_type_t *t = (mp_obj_type_t *)((mp_obj_base_t *)nlr.ret_val)->type;\n        if (t == &mp_type_StopIteration || t == &mp_type_IndexError) {\n            // return MP_OBJ_STOP_ITERATION instead of raising\n            return MP_OBJ_STOP_ITERATION;\n        } else {\n            // re-raise exception\n            nlr_jump(nlr.ret_val);\n        }\n    }\n}\n\nSTATIC const mp_obj_type_t it_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_iterator,\n    .getiter = mp_identity_getiter,\n    .iternext = it_iternext,\n};\n\n// args are those returned from mp_load_method_maybe (ie either an attribute or a method)\nmp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf) {\n    assert(sizeof(mp_obj_getitem_iter_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_obj_getitem_iter_t *o = (mp_obj_getitem_iter_t *)iter_buf;\n    o->base.type = &it_type;\n    o->args[0] = args[0];\n    o->args[1] = args[1];\n    o->args[2] = MP_OBJ_NEW_SMALL_INT(0);\n    return MP_OBJ_FROM_PTR(o);\n}\n"
  },
  {
    "path": "py/objint.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <assert.h>\n#include <string.h>\n\n#include \"py/parsenum.h\"\n#include \"py/smallint.h\"\n#include \"py/objint.h\"\n#include \"py/objstr.h\"\n#include \"py/runtime.h\"\n#include \"py/binary.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT\n#include <math.h>\n#endif\n\n// This dispatcher function is expected to be independent of the implementation of long int\nSTATIC 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) {\n    (void)type_in;\n    mp_arg_check_num(n_args, n_kw, 0, 2, false);\n\n    switch (n_args) {\n        case 0:\n            return MP_OBJ_NEW_SMALL_INT(0);\n\n        case 1:\n            if (mp_obj_is_int(args[0])) {\n                // already an int (small or long), just return it\n                return args[0];\n            } else if (mp_obj_is_str_or_bytes(args[0])) {\n                // a string, parse it\n                size_t l;\n                const char *s = mp_obj_str_get_data(args[0], &l);\n                return mp_parse_num_integer(s, l, 0, NULL);\n            #if MICROPY_PY_BUILTINS_FLOAT\n            } else if (mp_obj_is_float(args[0])) {\n                return mp_obj_new_int_from_float(mp_obj_float_get(args[0]));\n            #endif\n            } else {\n                return mp_unary_op(MP_UNARY_OP_INT, args[0]);\n            }\n\n        case 2:\n        default: {\n            // should be a string, parse it\n            size_t l;\n            const char *s = mp_obj_str_get_data(args[0], &l);\n            return mp_parse_num_integer(s, l, mp_obj_get_int(args[1]), NULL);\n        }\n    }\n}\n\n#if MICROPY_PY_BUILTINS_FLOAT\n\ntypedef enum {\n    MP_FP_CLASS_FIT_SMALLINT,\n    MP_FP_CLASS_FIT_LONGINT,\n    MP_FP_CLASS_OVERFLOW\n} mp_fp_as_int_class_t;\n\nSTATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) {\n    union {\n        mp_float_t f;\n        #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n        uint32_t i;\n        #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE\n        uint32_t i[2];\n        #endif\n    } u = {val};\n\n    uint32_t e;\n    #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n    e = u.i;\n    #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE\n    e = u.i[MP_ENDIANNESS_LITTLE];\n    #endif\n#define MP_FLOAT_SIGN_SHIFT_I32 ((MP_FLOAT_FRAC_BITS + MP_FLOAT_EXP_BITS) % 32)\n#define MP_FLOAT_EXP_SHIFT_I32 (MP_FLOAT_FRAC_BITS % 32)\n\n    if (e & (1U << MP_FLOAT_SIGN_SHIFT_I32)) {\n        #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE\n        e |= u.i[MP_ENDIANNESS_BIG] != 0;\n        #endif\n        if ((e & ~(1 << MP_FLOAT_SIGN_SHIFT_I32)) == 0) {\n            // handle case of -0 (when sign is set but rest of bits are zero)\n            e = 0;\n        } else {\n            e += ((1 << MP_FLOAT_EXP_BITS) - 1) << MP_FLOAT_EXP_SHIFT_I32;\n        }\n    } else {\n        e &= ~((1 << MP_FLOAT_EXP_SHIFT_I32) - 1);\n    }\n    // 8 * sizeof(uintptr_t) counts the number of bits for a small int\n    // TODO provide a way to configure this properly\n    if (e <= ((8 * sizeof(uintptr_t) + MP_FLOAT_EXP_BIAS - 3) << MP_FLOAT_EXP_SHIFT_I32)) {\n        return MP_FP_CLASS_FIT_SMALLINT;\n    }\n    #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG\n    if (e <= (((sizeof(long long) * BITS_PER_BYTE) + MP_FLOAT_EXP_BIAS - 2) << MP_FLOAT_EXP_SHIFT_I32)) {\n        return MP_FP_CLASS_FIT_LONGINT;\n    }\n    #endif\n    #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ\n    return MP_FP_CLASS_FIT_LONGINT;\n    #else\n    return MP_FP_CLASS_OVERFLOW;\n    #endif\n}\n#undef MP_FLOAT_SIGN_SHIFT_I32\n#undef MP_FLOAT_EXP_SHIFT_I32\n\nmp_obj_t mp_obj_new_int_from_float(mp_float_t val) {\n    mp_float_union_t u = {val};\n    // IEEE-754: if biased exponent is all 1 bits...\n    if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) {\n        // ...then number is Inf (positive or negative) if fraction is 0, else NaN.\n        if (u.p.frc == 0) {\n            mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT(\"can't convert inf to int\"));\n        } else {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"can't convert NaN to int\"));\n        }\n    } else {\n        mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val);\n        if (icl == MP_FP_CLASS_FIT_SMALLINT) {\n            return MP_OBJ_NEW_SMALL_INT((mp_int_t)val);\n        #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ\n        } else {\n            mp_obj_int_t *o = mp_obj_int_new_mpz();\n            mpz_set_from_float(&o->mpz, val);\n            return MP_OBJ_FROM_PTR(o);\n        }\n        #else\n        #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG\n        } else if (icl == MP_FP_CLASS_FIT_LONGINT) {\n            return mp_obj_new_int_from_ll((long long)val);\n        #endif\n        } else {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"float too big\"));\n        }\n        #endif\n    }\n}\n\n#endif\n\n#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG\ntypedef mp_longint_impl_t fmt_int_t;\ntypedef unsigned long long fmt_uint_t;\n#else\ntypedef mp_int_t fmt_int_t;\ntypedef mp_uint_t fmt_uint_t;\n#endif\n\nvoid mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    // The size of this buffer is rather arbitrary. If it's not large\n    // enough, a dynamic one will be allocated.\n    char stack_buf[sizeof(fmt_int_t) * 4];\n    char *buf = stack_buf;\n    size_t buf_size = sizeof(stack_buf);\n    size_t fmt_size;\n\n    char *str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, self_in, 10, NULL, '\\0', '\\0');\n    mp_print_str(print, str);\n\n    if (buf != stack_buf) {\n        m_del(char, buf, buf_size);\n    }\n}\n\nSTATIC const uint8_t log_base2_floor[] = {\n    0, 1, 1, 2,\n    2, 2, 2, 3,\n    3, 3, 3, 3,\n    3, 3, 3, 4,\n    /* if needed, these are the values for higher bases\n    4, 4, 4, 4,\n    4, 4, 4, 4,\n    4, 4, 4, 4,\n    4, 4, 4, 5\n    */\n};\n\nsize_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma) {\n    assert(2 <= base && base <= 16);\n    size_t num_digits = num_bits / log_base2_floor[base - 1] + 1;\n    size_t num_commas = comma ? num_digits / 3 : 0;\n    size_t prefix_len = prefix ? strlen(prefix) : 0;\n    return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte\n}\n\n// This routine expects you to pass in a buffer and size (in *buf and *buf_size).\n// If, for some reason, this buffer is too small, then it will allocate a\n// buffer and return the allocated buffer and size in *buf and *buf_size. It\n// is the callers responsibility to free this allocated buffer.\n//\n// The resulting formatted string will be returned from this function and the\n// formatted size will be in *fmt_size.\nchar *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,\n    int base, const char *prefix, char base_char, char comma) {\n    fmt_int_t num;\n    #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE\n    // Only have small ints; get the integer value to format.\n    num = MP_OBJ_SMALL_INT_VALUE(self_in);\n    #else\n    if (mp_obj_is_small_int(self_in)) {\n        // A small int; get the integer value to format.\n        num = MP_OBJ_SMALL_INT_VALUE(self_in);\n    } else {\n        assert(mp_obj_is_type(self_in, &mp_type_int));\n        // Not a small int.\n        #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG\n        const mp_obj_int_t *self = self_in;\n        // Get the value to format; mp_obj_get_int truncates to mp_int_t.\n        num = self->val;\n        #else\n        // Delegate to the implementation for the long int.\n        return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma);\n        #endif\n    }\n    #endif\n\n    char sign = '\\0';\n    if (num < 0) {\n        num = -num;\n        sign = '-';\n    }\n\n    size_t needed_size = mp_int_format_size(sizeof(fmt_int_t) * 8, base, prefix, comma);\n    if (needed_size > *buf_size) {\n        *buf = m_new(char, needed_size);\n        *buf_size = needed_size;\n    }\n    char *str = *buf;\n\n    char *b = str + needed_size;\n    *(--b) = '\\0';\n    char *last_comma = b;\n\n    if (num == 0) {\n        *(--b) = '0';\n    } else {\n        do {\n            // The cast to fmt_uint_t is because num is positive and we want unsigned arithmetic\n            int c = (fmt_uint_t)num % base;\n            num = (fmt_uint_t)num / base;\n            if (c >= 10) {\n                c += base_char - 10;\n            } else {\n                c += '0';\n            }\n            *(--b) = c;\n            if (comma && num != 0 && b > str && (last_comma - b) == 3) {\n                *(--b) = comma;\n                last_comma = b;\n            }\n        }\n        while (b > str && num != 0);\n    }\n    if (prefix) {\n        size_t prefix_len = strlen(prefix);\n        char *p = b - prefix_len;\n        if (p > str) {\n            b = p;\n            while (*prefix) {\n                *p++ = *prefix++;\n            }\n        }\n    }\n    if (sign && b > str) {\n        *(--b) = sign;\n    }\n    *fmt_size = *buf + needed_size - b - 1;\n\n    return b;\n}\n\n#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE\n\nint mp_obj_int_sign(mp_obj_t self_in) {\n    mp_int_t val = mp_obj_get_int(self_in);\n    if (val < 0) {\n        return -1;\n    } else if (val > 0) {\n        return 1;\n    } else {\n        return 0;\n    }\n}\n\n// This is called for operations on SMALL_INT that are not handled by mp_unary_op\nmp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) {\n    return MP_OBJ_NULL; // op not supported\n}\n\n// This is called for operations on SMALL_INT that are not handled by mp_binary_op\nmp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);\n}\n\n// This is called only with strings whose value doesn't fit in SMALL_INT\nmp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) {\n    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT(\"long int not supported in this build\"));\n    return mp_const_none;\n}\n\n// This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT)\nmp_obj_t mp_obj_new_int_from_ll(long long val) {\n    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT(\"small int overflow\"));\n    return mp_const_none;\n}\n\n// This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT)\nmp_obj_t mp_obj_new_int_from_ull(unsigned long long val) {\n    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT(\"small int overflow\"));\n    return mp_const_none;\n}\n\nmp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {\n    // SMALL_INT accepts only signed numbers, so make sure the input\n    // value fits completely in the small-int positive range.\n    if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) {\n        return MP_OBJ_NEW_SMALL_INT(value);\n    }\n    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT(\"small int overflow\"));\n    return mp_const_none;\n}\n\nmp_obj_t mp_obj_new_int(mp_int_t value) {\n    if (MP_SMALL_INT_FITS(value)) {\n        return MP_OBJ_NEW_SMALL_INT(value);\n    }\n    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT(\"small int overflow\"));\n    return mp_const_none;\n}\n\nmp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) {\n    return MP_OBJ_SMALL_INT_VALUE(self_in);\n}\n\nmp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {\n    return MP_OBJ_SMALL_INT_VALUE(self_in);\n}\n\n#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE\n\n// This dispatcher function is expected to be independent of the implementation of long int\n// It handles the extra cases for integer-like arithmetic\nmp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    if (rhs_in == mp_const_false) {\n        // false acts as 0\n        return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(0));\n    } else if (rhs_in == mp_const_true) {\n        // true acts as 0\n        return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));\n    } else if (op == MP_BINARY_OP_MULTIPLY) {\n        if (mp_obj_is_str_or_bytes(rhs_in) || mp_obj_is_type(rhs_in, &mp_type_tuple) || mp_obj_is_type(rhs_in, &mp_type_list)) {\n            // multiply is commutative for these types, so delegate to them\n            return mp_binary_op(op, rhs_in, lhs_in);\n        }\n    }\n    return MP_OBJ_NULL; // op not supported\n}\n\n// this is a classmethod\nSTATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {\n    // TODO: Support signed param (assumes signed=False at the moment)\n    (void)n_args;\n\n    // get the buffer info\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);\n\n    const byte *buf = (const byte *)bufinfo.buf;\n    int delta = 1;\n    if (args[2] == MP_OBJ_NEW_QSTR(MP_QSTR_little)) {\n        buf += bufinfo.len - 1;\n        delta = -1;\n    }\n\n    mp_uint_t value = 0;\n    size_t len = bufinfo.len;\n    for (; len--; buf += delta) {\n        #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE\n        if (value > (MP_SMALL_INT_MAX >> 8)) {\n            // Result will overflow a small-int so construct a big-int\n            return mp_obj_int_from_bytes_impl(args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf);\n        }\n        #endif\n        value = (value << 8) | *buf;\n    }\n    return mp_obj_new_int_from_uint(value);\n}\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 3, 4, int_from_bytes);\nSTATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_bytes_fun_obj));\n\nSTATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) {\n    // TODO: Support signed param (assumes signed=False)\n    (void)n_args;\n\n    mp_int_t len = mp_obj_get_int(args[1]);\n    if (len < 0) {\n        mp_raise_ValueError(NULL);\n    }\n    bool big_endian = args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little);\n\n    vstr_t vstr;\n    vstr_init_len(&vstr, len);\n    byte *data = (byte *)vstr.buf;\n    memset(data, 0, len);\n\n    #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE\n    if (!mp_obj_is_small_int(args[0])) {\n        mp_obj_int_to_bytes_impl(args[0], big_endian, len, data);\n    } else\n    #endif\n    {\n        mp_int_t val = MP_OBJ_SMALL_INT_VALUE(args[0]);\n        size_t l = MIN((size_t)len, sizeof(val));\n        mp_binary_set_int(l, big_endian, data + (big_endian ? (len - l) : 0), val);\n    }\n\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 3, 4, int_to_bytes);\n\nSTATIC const mp_rom_map_elem_t int_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_from_bytes), MP_ROM_PTR(&int_from_bytes_obj) },\n    { MP_ROM_QSTR(MP_QSTR_to_bytes), MP_ROM_PTR(&int_to_bytes_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(int_locals_dict, int_locals_dict_table);\n\nconst mp_obj_type_t mp_type_int = {\n    { &mp_type_type },\n    .name = MP_QSTR_int,\n    .print = mp_obj_int_print,\n    .make_new = mp_obj_int_make_new,\n    .unary_op = mp_obj_int_unary_op,\n    .binary_op = mp_obj_int_binary_op,\n    .locals_dict = (mp_obj_dict_t *)&int_locals_dict,\n};\n"
  },
  {
    "path": "py/objint.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJINT_H\n#define MICROPY_INCLUDED_PY_OBJINT_H\n\n#include \"py/mpz.h\"\n#include \"py/obj.h\"\n\ntypedef struct _mp_obj_int_t {\n    mp_obj_base_t base;\n    #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG\n    mp_longint_impl_t val;\n    #elif MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ\n    mpz_t mpz;\n    #endif\n} mp_obj_int_t;\n\nextern const mp_obj_int_t mp_sys_maxsize_obj;\n\n#if MICROPY_PY_BUILTINS_FLOAT\nmp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in);\n#endif\n\nsize_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma);\n\nmp_obj_int_t *mp_obj_int_new_mpz(void);\n\nvoid mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);\nchar *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,\n    int base, const char *prefix, char base_char, char comma);\nchar *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,\n    int base, const char *prefix, char base_char, char comma);\nmp_int_t mp_obj_int_hash(mp_obj_t self_in);\nmp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf);\nvoid mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf);\nint mp_obj_int_sign(mp_obj_t self_in);\nmp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in);\nmp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in);\nmp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in);\nmp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent,  mp_obj_t modulus);\n\n#endif // MICROPY_INCLUDED_PY_OBJINT_H\n"
  },
  {
    "path": "py/objint_longlong.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"py/smallint.h\"\n#include \"py/objint.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT\n#include <math.h>\n#endif\n\n#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG\n\n#if MICROPY_PY_SYS_MAXSIZE\n// Export value for sys.maxsize\nconst mp_obj_int_t mp_sys_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX};\n#endif\n\nmp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) {\n    int delta = 1;\n    if (!big_endian) {\n        buf += len - 1;\n        delta = -1;\n    }\n\n    mp_longint_impl_t value = 0;\n    for (; len--; buf += delta) {\n        value = (value << 8) | *buf;\n    }\n    return mp_obj_new_int_from_ll(value);\n}\n\nvoid mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) {\n    assert(mp_obj_is_type(self_in, &mp_type_int));\n    mp_obj_int_t *self = self_in;\n    long long val = self->val;\n    if (big_endian) {\n        byte *b = buf + len;\n        while (b > buf) {\n            *--b = val;\n            val >>= 8;\n        }\n    } else {\n        for (; len > 0; --len) {\n            *buf++ = val;\n            val >>= 8;\n        }\n    }\n}\n\nint mp_obj_int_sign(mp_obj_t self_in) {\n    mp_longint_impl_t val;\n    if (mp_obj_is_small_int(self_in)) {\n        val = MP_OBJ_SMALL_INT_VALUE(self_in);\n    } else {\n        mp_obj_int_t *self = self_in;\n        val = self->val;\n    }\n    if (val < 0) {\n        return -1;\n    } else if (val > 0) {\n        return 1;\n    } else {\n        return 0;\n    }\n}\n\nmp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) {\n    mp_obj_int_t *o = o_in;\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(o->val != 0);\n\n        // truncate value to fit in mp_int_t, which gives the same hash as\n        // small int if the value fits without truncation\n        case MP_UNARY_OP_HASH:\n            return MP_OBJ_NEW_SMALL_INT((mp_int_t)o->val);\n\n        case MP_UNARY_OP_POSITIVE:\n            return o_in;\n        case MP_UNARY_OP_NEGATIVE:\n            return mp_obj_new_int_from_ll(-o->val);\n        case MP_UNARY_OP_INVERT:\n            return mp_obj_new_int_from_ll(~o->val);\n        case MP_UNARY_OP_ABS: {\n            mp_obj_int_t *self = MP_OBJ_TO_PTR(o_in);\n            if (self->val >= 0) {\n                return o_in;\n            }\n            self = mp_obj_new_int_from_ll(self->val);\n            // TODO could overflow long long\n            self->val = -self->val;\n            return MP_OBJ_FROM_PTR(self);\n        }\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n\nmp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    long long lhs_val;\n    long long rhs_val;\n\n    if (mp_obj_is_small_int(lhs_in)) {\n        lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in);\n    } else {\n        assert(mp_obj_is_type(lhs_in, &mp_type_int));\n        lhs_val = ((mp_obj_int_t *)lhs_in)->val;\n    }\n\n    if (mp_obj_is_small_int(rhs_in)) {\n        rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in);\n    } else if (mp_obj_is_type(rhs_in, &mp_type_int)) {\n        rhs_val = ((mp_obj_int_t *)rhs_in)->val;\n    } else {\n        // delegate to generic function to check for extra cases\n        return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);\n    }\n\n    switch (op) {\n        case MP_BINARY_OP_ADD:\n        case MP_BINARY_OP_INPLACE_ADD:\n            return mp_obj_new_int_from_ll(lhs_val + rhs_val);\n        case MP_BINARY_OP_SUBTRACT:\n        case MP_BINARY_OP_INPLACE_SUBTRACT:\n            return mp_obj_new_int_from_ll(lhs_val - rhs_val);\n        case MP_BINARY_OP_MULTIPLY:\n        case MP_BINARY_OP_INPLACE_MULTIPLY:\n            return mp_obj_new_int_from_ll(lhs_val * rhs_val);\n        case MP_BINARY_OP_FLOOR_DIVIDE:\n        case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:\n            if (rhs_val == 0) {\n                goto zero_division;\n            }\n            return mp_obj_new_int_from_ll(lhs_val / rhs_val);\n        case MP_BINARY_OP_MODULO:\n        case MP_BINARY_OP_INPLACE_MODULO:\n            if (rhs_val == 0) {\n                goto zero_division;\n            }\n            return mp_obj_new_int_from_ll(lhs_val % rhs_val);\n\n        case MP_BINARY_OP_AND:\n        case MP_BINARY_OP_INPLACE_AND:\n            return mp_obj_new_int_from_ll(lhs_val & rhs_val);\n        case MP_BINARY_OP_OR:\n        case MP_BINARY_OP_INPLACE_OR:\n            return mp_obj_new_int_from_ll(lhs_val | rhs_val);\n        case MP_BINARY_OP_XOR:\n        case MP_BINARY_OP_INPLACE_XOR:\n            return mp_obj_new_int_from_ll(lhs_val ^ rhs_val);\n\n        case MP_BINARY_OP_LSHIFT:\n        case MP_BINARY_OP_INPLACE_LSHIFT:\n            return mp_obj_new_int_from_ll(lhs_val << (int)rhs_val);\n        case MP_BINARY_OP_RSHIFT:\n        case MP_BINARY_OP_INPLACE_RSHIFT:\n            return mp_obj_new_int_from_ll(lhs_val >> (int)rhs_val);\n\n        case MP_BINARY_OP_POWER:\n        case MP_BINARY_OP_INPLACE_POWER: {\n            if (rhs_val < 0) {\n                #if MICROPY_PY_BUILTINS_FLOAT\n                return mp_obj_float_binary_op(op, lhs_val, rhs_in);\n                #else\n                mp_raise_ValueError(MP_ERROR_TEXT(\"negative power with no float support\"));\n                #endif\n            }\n            long long ans = 1;\n            while (rhs_val > 0) {\n                if (rhs_val & 1) {\n                    ans *= lhs_val;\n                }\n                if (rhs_val == 1) {\n                    break;\n                }\n                rhs_val /= 2;\n                lhs_val *= lhs_val;\n            }\n            return mp_obj_new_int_from_ll(ans);\n        }\n\n        case MP_BINARY_OP_LESS:\n            return mp_obj_new_bool(lhs_val < rhs_val);\n        case MP_BINARY_OP_MORE:\n            return mp_obj_new_bool(lhs_val > rhs_val);\n        case MP_BINARY_OP_LESS_EQUAL:\n            return mp_obj_new_bool(lhs_val <= rhs_val);\n        case MP_BINARY_OP_MORE_EQUAL:\n            return mp_obj_new_bool(lhs_val >= rhs_val);\n        case MP_BINARY_OP_EQUAL:\n            return mp_obj_new_bool(lhs_val == rhs_val);\n\n        default:\n            return MP_OBJ_NULL; // op not supported\n    }\n\nzero_division:\n    mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT(\"divide by zero\"));\n}\n\nmp_obj_t mp_obj_new_int(mp_int_t value) {\n    if (MP_SMALL_INT_FITS(value)) {\n        return MP_OBJ_NEW_SMALL_INT(value);\n    }\n    return mp_obj_new_int_from_ll(value);\n}\n\nmp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {\n    // SMALL_INT accepts only signed numbers, so make sure the input\n    // value fits completely in the small-int positive range.\n    if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) {\n        return MP_OBJ_NEW_SMALL_INT(value);\n    }\n    return mp_obj_new_int_from_ll(value);\n}\n\nmp_obj_t mp_obj_new_int_from_ll(long long val) {\n    mp_obj_int_t *o = m_new_obj(mp_obj_int_t);\n    o->base.type = &mp_type_int;\n    o->val = val;\n    return o;\n}\n\nmp_obj_t mp_obj_new_int_from_ull(unsigned long long val) {\n    // TODO raise an exception if the unsigned long long won't fit\n    if (val >> (sizeof(unsigned long long) * 8 - 1) != 0) {\n        mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT(\"ulonglong too large\"));\n    }\n    mp_obj_int_t *o = m_new_obj(mp_obj_int_t);\n    o->base.type = &mp_type_int;\n    o->val = val;\n    return o;\n}\n\nmp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) {\n    // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated\n    // TODO check overflow\n    mp_obj_int_t *o = m_new_obj(mp_obj_int_t);\n    o->base.type = &mp_type_int;\n    char *endptr;\n    o->val = strtoll(*str, &endptr, base);\n    *str = endptr;\n    return o;\n}\n\nmp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) {\n    if (mp_obj_is_small_int(self_in)) {\n        return MP_OBJ_SMALL_INT_VALUE(self_in);\n    } else {\n        const mp_obj_int_t *self = self_in;\n        return self->val;\n    }\n}\n\nmp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {\n    // TODO: Check overflow\n    return mp_obj_int_get_truncated(self_in);\n}\n\n#if MICROPY_PY_BUILTINS_FLOAT\nmp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) {\n    assert(mp_obj_is_type(self_in, &mp_type_int));\n    mp_obj_int_t *self = self_in;\n    return self->val;\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "py/objint_mpz.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <assert.h>\n\n#include \"py/parsenumbase.h\"\n#include \"py/smallint.h\"\n#include \"py/objint.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT\n#include <math.h>\n#endif\n\n#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ\n\n#if MICROPY_PY_SYS_MAXSIZE\n// Export value for sys.maxsize\n// *FORMAT-OFF*\n#define DIG_MASK ((MPZ_LONG_1 << MPZ_DIG_SIZE) - 1)\nSTATIC const mpz_dig_t maxsize_dig[] = {\n    #define NUM_DIG 1\n    (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 0) & DIG_MASK,\n    #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 0) > DIG_MASK\n     #undef NUM_DIG\n     #define NUM_DIG 2\n     (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) & DIG_MASK,\n     #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) > DIG_MASK\n      #undef NUM_DIG\n      #define NUM_DIG 3\n      (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) & DIG_MASK,\n      #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) > DIG_MASK\n       #undef NUM_DIG\n       #define NUM_DIG 4\n       (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) & DIG_MASK,\n       #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) > DIG_MASK\n        #error cannot encode MP_SSIZE_MAX as mpz\n       #endif\n      #endif\n     #endif\n    #endif\n};\n// *FORMAT-ON*\nconst mp_obj_int_t mp_sys_maxsize_obj = {\n    {&mp_type_int},\n    {.fixed_dig = 1, .len = NUM_DIG, .alloc = NUM_DIG, .dig = (mpz_dig_t *)maxsize_dig}\n};\n#undef DIG_MASK\n#undef NUM_DIG\n#endif\n\nmp_obj_int_t *mp_obj_int_new_mpz(void) {\n    mp_obj_int_t *o = m_new_obj(mp_obj_int_t);\n    o->base.type = &mp_type_int;\n    mpz_init_zero(&o->mpz);\n    return o;\n}\n\n// This routine expects you to pass in a buffer and size (in *buf and buf_size).\n// If, for some reason, this buffer is too small, then it will allocate a\n// buffer and return the allocated buffer and size in *buf and *buf_size. It\n// is the callers responsibility to free this allocated buffer.\n//\n// The resulting formatted string will be returned from this function and the\n// formatted size will be in *fmt_size.\n//\n// This particular routine should only be called for the mpz representation of the int.\nchar *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,\n    int base, const char *prefix, char base_char, char comma) {\n    assert(mp_obj_is_type(self_in, &mp_type_int));\n    const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);\n\n    size_t needed_size = mp_int_format_size(mpz_max_num_bits(&self->mpz), base, prefix, comma);\n    if (needed_size > *buf_size) {\n        *buf = m_new(char, needed_size);\n        *buf_size = needed_size;\n    }\n    char *str = *buf;\n\n    *fmt_size = mpz_as_str_inpl(&self->mpz, base, prefix, base_char, comma, str);\n\n    return str;\n}\n\nmp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) {\n    mp_obj_int_t *o = mp_obj_int_new_mpz();\n    mpz_set_from_bytes(&o->mpz, big_endian, len, buf);\n    return MP_OBJ_FROM_PTR(o);\n}\n\nvoid mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) {\n    assert(mp_obj_is_type(self_in, &mp_type_int));\n    mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);\n    memset(buf, 0, len);\n    mpz_as_bytes(&self->mpz, big_endian, len, buf);\n}\n\nint mp_obj_int_sign(mp_obj_t self_in) {\n    if (mp_obj_is_small_int(self_in)) {\n        mp_int_t val = MP_OBJ_SMALL_INT_VALUE(self_in);\n        if (val < 0) {\n            return -1;\n        } else if (val > 0) {\n            return 1;\n        } else {\n            return 0;\n        }\n    }\n    mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->mpz.len == 0) {\n        return 0;\n    } else if (self->mpz.neg == 0) {\n        return 1;\n    } else {\n        return -1;\n    }\n}\n\nmp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) {\n    mp_obj_int_t *o = MP_OBJ_TO_PTR(o_in);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(!mpz_is_zero(&o->mpz));\n        case MP_UNARY_OP_HASH:\n            return MP_OBJ_NEW_SMALL_INT(mpz_hash(&o->mpz));\n        case MP_UNARY_OP_POSITIVE:\n            return o_in;\n        case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz();\n                                     mpz_neg_inpl(&o2->mpz, &o->mpz);\n                                     return MP_OBJ_FROM_PTR(o2);\n        }\n        case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz();\n                                   mpz_not_inpl(&o2->mpz, &o->mpz);\n                                   return MP_OBJ_FROM_PTR(o2);\n        }\n        case MP_UNARY_OP_ABS: {\n            mp_obj_int_t *self = MP_OBJ_TO_PTR(o_in);\n            if (self->mpz.neg == 0) {\n                return o_in;\n            }\n            mp_obj_int_t *self2 = mp_obj_int_new_mpz();\n            mpz_abs_inpl(&self2->mpz, &self->mpz);\n            return MP_OBJ_FROM_PTR(self2);\n        }\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n\nmp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    const mpz_t *zlhs;\n    const mpz_t *zrhs;\n    mpz_t z_int;\n    mpz_dig_t z_int_dig[MPZ_NUM_DIG_FOR_INT];\n\n    // lhs could be a small int (eg small-int + mpz)\n    if (mp_obj_is_small_int(lhs_in)) {\n        mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(lhs_in));\n        zlhs = &z_int;\n    } else {\n        assert(mp_obj_is_type(lhs_in, &mp_type_int));\n        zlhs = &((mp_obj_int_t *)MP_OBJ_TO_PTR(lhs_in))->mpz;\n    }\n\n    // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it)\n    if (mp_obj_is_small_int(rhs_in)) {\n        mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(rhs_in));\n        zrhs = &z_int;\n    } else if (mp_obj_is_type(rhs_in, &mp_type_int)) {\n        zrhs = &((mp_obj_int_t *)MP_OBJ_TO_PTR(rhs_in))->mpz;\n    #if MICROPY_PY_BUILTINS_FLOAT\n    } else if (mp_obj_is_float(rhs_in)) {\n        return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in);\n    #endif\n    #if MICROPY_PY_BUILTINS_COMPLEX\n    } else if (mp_obj_is_type(rhs_in, &mp_type_complex)) {\n        return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in);\n    #endif\n    } else {\n        // delegate to generic function to check for extra cases\n        return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);\n    }\n\n    #if MICROPY_PY_BUILTINS_FLOAT\n    if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) {\n        if (mpz_is_zero(zrhs)) {\n            goto zero_division_error;\n        }\n        mp_float_t flhs = mpz_as_float(zlhs);\n        mp_float_t frhs = mpz_as_float(zrhs);\n        return mp_obj_new_float(flhs / frhs);\n    }\n    #endif\n\n    if (op >= MP_BINARY_OP_INPLACE_OR && op < MP_BINARY_OP_CONTAINS) {\n        mp_obj_int_t *res = mp_obj_int_new_mpz();\n\n        switch (op) {\n            case MP_BINARY_OP_ADD:\n            case MP_BINARY_OP_INPLACE_ADD:\n                mpz_add_inpl(&res->mpz, zlhs, zrhs);\n                break;\n            case MP_BINARY_OP_SUBTRACT:\n            case MP_BINARY_OP_INPLACE_SUBTRACT:\n                mpz_sub_inpl(&res->mpz, zlhs, zrhs);\n                break;\n            case MP_BINARY_OP_MULTIPLY:\n            case MP_BINARY_OP_INPLACE_MULTIPLY:\n                mpz_mul_inpl(&res->mpz, zlhs, zrhs);\n                break;\n            case MP_BINARY_OP_FLOOR_DIVIDE:\n            case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: {\n                if (mpz_is_zero(zrhs)) {\n                zero_division_error:\n                    mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT(\"divide by zero\"));\n                }\n                mpz_t rem;\n                mpz_init_zero(&rem);\n                mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs);\n                mpz_deinit(&rem);\n                break;\n            }\n            case MP_BINARY_OP_MODULO:\n            case MP_BINARY_OP_INPLACE_MODULO: {\n                if (mpz_is_zero(zrhs)) {\n                    goto zero_division_error;\n                }\n                mpz_t quo;\n                mpz_init_zero(&quo);\n                mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs);\n                mpz_deinit(&quo);\n                break;\n            }\n\n            case MP_BINARY_OP_AND:\n            case MP_BINARY_OP_INPLACE_AND:\n                mpz_and_inpl(&res->mpz, zlhs, zrhs);\n                break;\n            case MP_BINARY_OP_OR:\n            case MP_BINARY_OP_INPLACE_OR:\n                mpz_or_inpl(&res->mpz, zlhs, zrhs);\n                break;\n            case MP_BINARY_OP_XOR:\n            case MP_BINARY_OP_INPLACE_XOR:\n                mpz_xor_inpl(&res->mpz, zlhs, zrhs);\n                break;\n\n            case MP_BINARY_OP_LSHIFT:\n            case MP_BINARY_OP_INPLACE_LSHIFT:\n            case MP_BINARY_OP_RSHIFT:\n            case MP_BINARY_OP_INPLACE_RSHIFT: {\n                mp_int_t irhs = mp_obj_int_get_checked(rhs_in);\n                if (irhs < 0) {\n                    mp_raise_ValueError(MP_ERROR_TEXT(\"negative shift count\"));\n                }\n                if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) {\n                    mpz_shl_inpl(&res->mpz, zlhs, irhs);\n                } else {\n                    mpz_shr_inpl(&res->mpz, zlhs, irhs);\n                }\n                break;\n            }\n\n            case MP_BINARY_OP_POWER:\n            case MP_BINARY_OP_INPLACE_POWER:\n                if (mpz_is_neg(zrhs)) {\n                    #if MICROPY_PY_BUILTINS_FLOAT\n                    return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in);\n                    #else\n                    mp_raise_ValueError(MP_ERROR_TEXT(\"negative power with no float support\"));\n                    #endif\n                }\n                mpz_pow_inpl(&res->mpz, zlhs, zrhs);\n                break;\n\n            default: {\n                assert(op == MP_BINARY_OP_DIVMOD);\n                if (mpz_is_zero(zrhs)) {\n                    goto zero_division_error;\n                }\n                mp_obj_int_t *quo = mp_obj_int_new_mpz();\n                mpz_divmod_inpl(&quo->mpz, &res->mpz, zlhs, zrhs);\n                mp_obj_t tuple[2] = {MP_OBJ_FROM_PTR(quo), MP_OBJ_FROM_PTR(res)};\n                return mp_obj_new_tuple(2, tuple);\n            }\n        }\n\n        return MP_OBJ_FROM_PTR(res);\n\n    } else {\n        int cmp = mpz_cmp(zlhs, zrhs);\n        switch (op) {\n            case MP_BINARY_OP_LESS:\n                return mp_obj_new_bool(cmp < 0);\n            case MP_BINARY_OP_MORE:\n                return mp_obj_new_bool(cmp > 0);\n            case MP_BINARY_OP_LESS_EQUAL:\n                return mp_obj_new_bool(cmp <= 0);\n            case MP_BINARY_OP_MORE_EQUAL:\n                return mp_obj_new_bool(cmp >= 0);\n            case MP_BINARY_OP_EQUAL:\n                return mp_obj_new_bool(cmp == 0);\n\n            default:\n                return MP_OBJ_NULL; // op not supported\n        }\n    }\n}\n\n#if MICROPY_PY_BUILTINS_POW3\nSTATIC mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) {\n    if (mp_obj_is_small_int(arg)) {\n        mpz_init_from_int(temp, MP_OBJ_SMALL_INT_VALUE(arg));\n        return temp;\n    } else {\n        mp_obj_int_t *arp_p = MP_OBJ_TO_PTR(arg);\n        return &(arp_p->mpz);\n    }\n}\n\nmp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent,  mp_obj_t modulus) {\n    if (!mp_obj_is_int(base) || !mp_obj_is_int(exponent) || !mp_obj_is_int(modulus)) {\n        mp_raise_TypeError(MP_ERROR_TEXT(\"pow() with 3 arguments requires integers\"));\n    } else {\n        mp_obj_t result = mp_obj_new_int_from_ull(0); // Use the _from_ull version as this forces an mpz int\n        mp_obj_int_t *res_p = (mp_obj_int_t *)MP_OBJ_TO_PTR(result);\n\n        mpz_t l_temp, r_temp, m_temp;\n        mpz_t *lhs = mp_mpz_for_int(base,     &l_temp);\n        mpz_t *rhs = mp_mpz_for_int(exponent, &r_temp);\n        mpz_t *mod = mp_mpz_for_int(modulus,  &m_temp);\n\n        mpz_pow3_inpl(&(res_p->mpz), lhs, rhs, mod);\n\n        if (lhs == &l_temp) {\n            mpz_deinit(lhs);\n        }\n        if (rhs == &r_temp) {\n            mpz_deinit(rhs);\n        }\n        if (mod == &m_temp) {\n            mpz_deinit(mod);\n        }\n        return result;\n    }\n}\n#endif\n\nmp_obj_t mp_obj_new_int(mp_int_t value) {\n    if (MP_SMALL_INT_FITS(value)) {\n        return MP_OBJ_NEW_SMALL_INT(value);\n    }\n    return mp_obj_new_int_from_ll(value);\n}\n\nmp_obj_t mp_obj_new_int_from_ll(long long val) {\n    mp_obj_int_t *o = mp_obj_int_new_mpz();\n    mpz_set_from_ll(&o->mpz, val, true);\n    return MP_OBJ_FROM_PTR(o);\n}\n\nmp_obj_t mp_obj_new_int_from_ull(unsigned long long val) {\n    mp_obj_int_t *o = mp_obj_int_new_mpz();\n    mpz_set_from_ll(&o->mpz, val, false);\n    return MP_OBJ_FROM_PTR(o);\n}\n\nmp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {\n    // SMALL_INT accepts only signed numbers, so make sure the input\n    // value fits completely in the small-int positive range.\n    if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) {\n        return MP_OBJ_NEW_SMALL_INT(value);\n    }\n    return mp_obj_new_int_from_ull(value);\n}\n\nmp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) {\n    mp_obj_int_t *o = mp_obj_int_new_mpz();\n    size_t n = mpz_set_from_str(&o->mpz, *str, len, neg, base);\n    *str += n;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nmp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) {\n    if (mp_obj_is_small_int(self_in)) {\n        return MP_OBJ_SMALL_INT_VALUE(self_in);\n    } else {\n        const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);\n        // hash returns actual int value if it fits in mp_int_t\n        return mpz_hash(&self->mpz);\n    }\n}\n\nmp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {\n    if (mp_obj_is_small_int(self_in)) {\n        return MP_OBJ_SMALL_INT_VALUE(self_in);\n    } else {\n        const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);\n        mp_int_t value;\n        if (mpz_as_int_checked(&self->mpz, &value)) {\n            return value;\n        } else {\n            // overflow\n            mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT(\"overflow converting long int to machine word\"));\n        }\n    }\n}\n\nmp_uint_t mp_obj_int_get_uint_checked(mp_const_obj_t self_in) {\n    if (mp_obj_is_small_int(self_in)) {\n        if (MP_OBJ_SMALL_INT_VALUE(self_in) >= 0) {\n            return MP_OBJ_SMALL_INT_VALUE(self_in);\n        }\n    } else {\n        const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);\n        mp_uint_t value;\n        if (mpz_as_uint_checked(&self->mpz, &value)) {\n            return value;\n        }\n    }\n\n    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT(\"overflow converting long int to machine word\"));\n}\n\n#if MICROPY_PY_BUILTINS_FLOAT\nmp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) {\n    assert(mp_obj_is_type(self_in, &mp_type_int));\n    mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);\n    return mpz_as_float(&self->mpz);\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "py/objlist.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <assert.h>\n\n#include \"py/objlist.h\"\n#include \"py/runtime.h\"\n#include \"py/stackctrl.h\"\n\nSTATIC mp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t *iter_buf);\nSTATIC mp_obj_list_t *list_new(size_t n);\nSTATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in);\nSTATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args);\n\n// TODO: Move to mpconfig.h\n#define LIST_MIN_ALLOC 4\n\n/******************************************************************************/\n/* list                                                                       */\n\nSTATIC void list_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    mp_obj_list_t *o = MP_OBJ_TO_PTR(o_in);\n    if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {\n        kind = PRINT_REPR;\n    }\n    mp_print_str(print, \"[\");\n    for (size_t i = 0; i < o->len; i++) {\n        if (i > 0) {\n            mp_print_str(print, \", \");\n        }\n        mp_obj_print_helper(print, o->items[i], kind);\n    }\n    mp_print_str(print, \"]\");\n}\n\nSTATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) {\n    mp_obj_t iter = mp_getiter(iterable, NULL);\n    mp_obj_t item;\n    while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n        mp_obj_list_append(list, item);\n    }\n    return list;\n}\n\nSTATIC 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) {\n    (void)type_in;\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n\n    switch (n_args) {\n        case 0:\n            // return a new, empty list\n            return mp_obj_new_list(0, NULL);\n\n        case 1:\n        default: {\n            // make list from iterable\n            // TODO: optimize list/tuple\n            mp_obj_t list = mp_obj_new_list(0, NULL);\n            return list_extend_from_iter(list, args[0]);\n        }\n    }\n}\n\nSTATIC mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(self->len != 0);\n        case MP_UNARY_OP_LEN:\n            return MP_OBJ_NEW_SMALL_INT(self->len);\n        #if MICROPY_PY_SYS_GETSIZEOF\n        case MP_UNARY_OP_SIZEOF: {\n            size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc;\n            return MP_OBJ_NEW_SMALL_INT(sz);\n        }\n        #endif\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n\nSTATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {\n    mp_obj_list_t *o = MP_OBJ_TO_PTR(lhs);\n    switch (op) {\n        case MP_BINARY_OP_ADD: {\n            if (!mp_obj_is_type(rhs, &mp_type_list)) {\n                return MP_OBJ_NULL; // op not supported\n            }\n            mp_obj_list_t *p = MP_OBJ_TO_PTR(rhs);\n            mp_obj_list_t *s = list_new(o->len + p->len);\n            mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t);\n            return MP_OBJ_FROM_PTR(s);\n        }\n        case MP_BINARY_OP_INPLACE_ADD: {\n            list_extend(lhs, rhs);\n            return lhs;\n        }\n        case MP_BINARY_OP_MULTIPLY: {\n            mp_int_t n;\n            if (!mp_obj_get_int_maybe(rhs, &n)) {\n                return MP_OBJ_NULL; // op not supported\n            }\n            if (n < 0) {\n                n = 0;\n            }\n            mp_obj_list_t *s = list_new(o->len * n);\n            mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);\n            return MP_OBJ_FROM_PTR(s);\n        }\n        case MP_BINARY_OP_EQUAL:\n        case MP_BINARY_OP_LESS:\n        case MP_BINARY_OP_LESS_EQUAL:\n        case MP_BINARY_OP_MORE:\n        case MP_BINARY_OP_MORE_EQUAL: {\n            if (!mp_obj_is_type(rhs, &mp_type_list)) {\n                if (op == MP_BINARY_OP_EQUAL) {\n                    return mp_const_false;\n                }\n                return MP_OBJ_NULL; // op not supported\n            }\n\n            mp_obj_list_t *another = MP_OBJ_TO_PTR(rhs);\n            bool res = mp_seq_cmp_objs(op, o->items, o->len, another->items, another->len);\n            return mp_obj_new_bool(res);\n        }\n\n        default:\n            return MP_OBJ_NULL; // op not supported\n    }\n}\n\nSTATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {\n    if (value == MP_OBJ_NULL) {\n        // delete\n        #if MICROPY_PY_BUILTINS_SLICE\n        if (mp_obj_is_type(index, &mp_type_slice)) {\n            mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n            mp_bound_slice_t slice;\n            if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {\n                mp_raise_NotImplementedError(NULL);\n            }\n\n            mp_int_t len_adj = slice.start - slice.stop;\n            assert(len_adj <= 0);\n            mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items /*NULL*/, 0, sizeof(*self->items));\n            // Clear \"freed\" elements at the end of list\n            mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));\n            self->len += len_adj;\n            return mp_const_none;\n        }\n        #endif\n        mp_obj_t args[2] = {self_in, index};\n        list_pop(2, args);\n        return mp_const_none;\n    } else if (value == MP_OBJ_SENTINEL) {\n        // load\n        mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n        #if MICROPY_PY_BUILTINS_SLICE\n        if (mp_obj_is_type(index, &mp_type_slice)) {\n            mp_bound_slice_t slice;\n            if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {\n                return mp_seq_extract_slice(self->len, self->items, &slice);\n            }\n            mp_obj_list_t *res = list_new(slice.stop - slice.start);\n            mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t);\n            return MP_OBJ_FROM_PTR(res);\n        }\n        #endif\n        size_t index_val = mp_get_index(self->base.type, self->len, index, false);\n        return self->items[index_val];\n    } else {\n        #if MICROPY_PY_BUILTINS_SLICE\n        if (mp_obj_is_type(index, &mp_type_slice)) {\n            mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n            size_t value_len;\n            mp_obj_t *value_items;\n            mp_obj_get_array(value, &value_len, &value_items);\n            mp_bound_slice_t slice_out;\n            if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) {\n                mp_raise_NotImplementedError(NULL);\n            }\n            mp_int_t len_adj = value_len - (slice_out.stop - slice_out.start);\n            if (len_adj > 0) {\n                if (self->len + len_adj > self->alloc) {\n                    // TODO: Might optimize memory copies here by checking if block can\n                    // be grown inplace or not\n                    self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj);\n                    self->alloc = self->len + len_adj;\n                }\n                mp_seq_replace_slice_grow_inplace(self->items, self->len,\n                    slice_out.start, slice_out.stop, value_items, value_len, len_adj, sizeof(*self->items));\n            } else {\n                mp_seq_replace_slice_no_grow(self->items, self->len,\n                    slice_out.start, slice_out.stop, value_items, value_len, sizeof(*self->items));\n                // Clear \"freed\" elements at the end of list\n                mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));\n                // TODO: apply allocation policy re: alloc_size\n            }\n            self->len += len_adj;\n            return mp_const_none;\n        }\n        #endif\n        mp_obj_list_store(self_in, index, value);\n        return mp_const_none;\n    }\n}\n\nSTATIC mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {\n    return mp_obj_new_list_iterator(o_in, 0, iter_buf);\n}\n\nmp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_list));\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->len >= self->alloc) {\n        self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2);\n        self->alloc *= 2;\n        mp_seq_clear(self->items, self->len + 1, self->alloc, sizeof(*self->items));\n    }\n    self->items[self->len++] = arg;\n    return mp_const_none; // return None, as per CPython\n}\n\nSTATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_list));\n    if (mp_obj_is_type(arg_in, &mp_type_list)) {\n        mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n        mp_obj_list_t *arg = MP_OBJ_TO_PTR(arg_in);\n\n        if (self->len + arg->len > self->alloc) {\n            // TODO: use alloc policy for \"4\"\n            self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + arg->len + 4);\n            self->alloc = self->len + arg->len + 4;\n            mp_seq_clear(self->items, self->len + arg->len, self->alloc, sizeof(*self->items));\n        }\n\n        memcpy(self->items + self->len, arg->items, sizeof(mp_obj_t) * arg->len);\n        self->len += arg->len;\n    } else {\n        list_extend_from_iter(self_in, arg_in);\n    }\n    return mp_const_none; // return None, as per CPython\n}\n\nSTATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) {\n    mp_check_self(mp_obj_is_type(args[0], &mp_type_list));\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]);\n    if (self->len == 0) {\n        mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT(\"pop from empty list\"));\n    }\n    size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false);\n    mp_obj_t ret = self->items[index];\n    self->len -= 1;\n    memmove(self->items + index, self->items + index + 1, (self->len - index) * sizeof(mp_obj_t));\n    // Clear stale pointer from slot which just got freed to prevent GC issues\n    self->items[self->len] = MP_OBJ_NULL;\n    if (self->alloc > LIST_MIN_ALLOC && self->alloc > 2 * self->len) {\n        self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc / 2);\n        self->alloc /= 2;\n    }\n    return ret;\n}\n\nSTATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj_t binop_less_result) {\n    MP_STACK_CHECK();\n    while (head < tail) {\n        mp_obj_t *h = head - 1;\n        mp_obj_t *t = tail;\n        mp_obj_t v = key_fn == MP_OBJ_NULL ? tail[0] : mp_call_function_1(key_fn, tail[0]); // get pivot using key_fn\n        for (;;) {\n            do {++h;\n            } 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);\n            do {--t;\n            } 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);\n            if (h >= t) {\n                break;\n            }\n            mp_obj_t x = h[0];\n            h[0] = t[0];\n            t[0] = x;\n        }\n        mp_obj_t x = h[0];\n        h[0] = tail[0];\n        tail[0] = x;\n        // do the smaller recursive call first, to keep stack within O(log(N))\n        if (t - head < tail - h - 1) {\n            mp_quicksort(head, t, key_fn, binop_less_result);\n            head = h + 1;\n        } else {\n            mp_quicksort(h + 1, tail, key_fn, binop_less_result);\n            tail = t;\n        }\n    }\n}\n\n// TODO Python defines sort to be stable but ours is not\nmp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_reverse, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },\n    };\n\n    // parse args\n    struct {\n        mp_arg_val_t key, reverse;\n    } args;\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,\n        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);\n\n    mp_check_self(mp_obj_is_type(pos_args[0], &mp_type_list));\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(pos_args[0]);\n\n    if (self->len > 1) {\n        mp_quicksort(self->items, self->items + self->len - 1,\n            args.key.u_obj == mp_const_none ? MP_OBJ_NULL : args.key.u_obj,\n            args.reverse.u_bool ? mp_const_false : mp_const_true);\n    }\n\n    return mp_const_none;\n}\n\nSTATIC mp_obj_t list_clear(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_list));\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n    self->len = 0;\n    self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC);\n    self->alloc = LIST_MIN_ALLOC;\n    mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items));\n    return mp_const_none;\n}\n\nSTATIC mp_obj_t list_copy(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_list));\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n    return mp_obj_new_list(self->len, self->items);\n}\n\nSTATIC mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_list));\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n    return mp_seq_count_obj(self->items, self->len, value);\n}\n\nSTATIC mp_obj_t list_index(size_t n_args, const mp_obj_t *args) {\n    mp_check_self(mp_obj_is_type(args[0], &mp_type_list));\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]);\n    return mp_seq_index_obj(self->items, self->len, n_args, args);\n}\n\nSTATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_list));\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n    // insert has its own strange index logic\n    mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx);\n    if (index < 0) {\n        index += self->len;\n    }\n    if (index < 0) {\n        index = 0;\n    }\n    if ((size_t)index > self->len) {\n        index = self->len;\n    }\n\n    mp_obj_list_append(self_in, mp_const_none);\n\n    for (mp_int_t i = self->len - 1; i > index; i--) {\n        self->items[i] = self->items[i - 1];\n    }\n    self->items[index] = obj;\n\n    return mp_const_none;\n}\n\nmp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_list));\n    mp_obj_t args[] = {self_in, value};\n    args[1] = list_index(2, args);\n    list_pop(2, args);\n\n    return mp_const_none;\n}\n\nSTATIC mp_obj_t list_reverse(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_list));\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n\n    mp_int_t len = self->len;\n    for (mp_int_t i = 0; i < len / 2; i++) {\n        mp_obj_t a = self->items[i];\n        self->items[i] = self->items[len - i - 1];\n        self->items[len - i - 1] = a;\n    }\n\n    return mp_const_none;\n}\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(list_append_obj, mp_obj_list_append);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(list_extend_obj, list_extend);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(list_clear_obj, list_clear);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(list_copy_obj, list_copy);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(list_count_obj, list_count);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_index_obj, 2, 4, list_index);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_3(list_insert_obj, list_insert);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_pop_obj, 1, 2, list_pop);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(list_remove_obj, mp_obj_list_remove);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(list_reverse_obj, list_reverse);\nSTATIC MP_DEFINE_CONST_FUN_OBJ_KW(list_sort_obj, 1, mp_obj_list_sort);\n\nSTATIC const mp_rom_map_elem_t list_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&list_append_obj) },\n    { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&list_clear_obj) },\n    { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&list_copy_obj) },\n    { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&list_count_obj) },\n    { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&list_extend_obj) },\n    { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&list_index_obj) },\n    { MP_ROM_QSTR(MP_QSTR_insert), MP_ROM_PTR(&list_insert_obj) },\n    { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&list_pop_obj) },\n    { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&list_remove_obj) },\n    { MP_ROM_QSTR(MP_QSTR_reverse), MP_ROM_PTR(&list_reverse_obj) },\n    { MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&list_sort_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(list_locals_dict, list_locals_dict_table);\n\nconst mp_obj_type_t mp_type_list = {\n    { &mp_type_type },\n    .name = MP_QSTR_list,\n    .print = list_print,\n    .make_new = list_make_new,\n    .unary_op = list_unary_op,\n    .binary_op = list_binary_op,\n    .subscr = list_subscr,\n    .getiter = list_getiter,\n    .locals_dict = (mp_obj_dict_t *)&list_locals_dict,\n};\n\nvoid mp_obj_list_init(mp_obj_list_t *o, size_t n) {\n    o->base.type = &mp_type_list;\n    o->alloc = n < LIST_MIN_ALLOC ? LIST_MIN_ALLOC : n;\n    o->len = n;\n    o->items = m_new(mp_obj_t, o->alloc);\n    mp_seq_clear(o->items, n, o->alloc, sizeof(*o->items));\n}\n\nSTATIC mp_obj_list_t *list_new(size_t n) {\n    mp_obj_list_t *o = m_new_obj(mp_obj_list_t);\n    mp_obj_list_init(o, n);\n    return o;\n}\n\nmp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items) {\n    mp_obj_list_t *o = list_new(n);\n    if (items != NULL) {\n        for (size_t i = 0; i < n; i++) {\n            o->items[i] = items[i];\n        }\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nvoid mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) {\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n    *len = self->len;\n    *items = self->items;\n}\n\nvoid mp_obj_list_set_len(mp_obj_t self_in, size_t len) {\n    // trust that the caller knows what it's doing\n    // TODO realloc if len got much smaller than alloc\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n    self->len = len;\n}\n\nvoid mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {\n    mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n    size_t i = mp_get_index(self->base.type, self->len, index, false);\n    self->items[i] = value;\n}\n\n/******************************************************************************/\n/* list iterator                                                              */\n\ntypedef struct _mp_obj_list_it_t {\n    mp_obj_base_t base;\n    mp_fun_1_t iternext;\n    mp_obj_t list;\n    size_t cur;\n} mp_obj_list_it_t;\n\nSTATIC mp_obj_t list_it_iternext(mp_obj_t self_in) {\n    mp_obj_list_it_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list);\n    if (self->cur < list->len) {\n        mp_obj_t o_out = list->items[self->cur];\n        self->cur += 1;\n        return o_out;\n    } else {\n        return MP_OBJ_STOP_ITERATION;\n    }\n}\n\nmp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t *iter_buf) {\n    assert(sizeof(mp_obj_list_it_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_obj_list_it_t *o = (mp_obj_list_it_t *)iter_buf;\n    o->base.type = &mp_type_polymorph_iter;\n    o->iternext = list_it_iternext;\n    o->list = list;\n    o->cur = cur;\n    return MP_OBJ_FROM_PTR(o);\n}\n"
  },
  {
    "path": "py/objlist.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJLIST_H\n#define MICROPY_INCLUDED_PY_OBJLIST_H\n\n#include \"py/obj.h\"\n\ntypedef struct _mp_obj_list_t {\n    mp_obj_base_t base;\n    size_t alloc;\n    size_t len;\n    mp_obj_t *items;\n} mp_obj_list_t;\n\nvoid mp_obj_list_init(mp_obj_list_t *o, size_t n);\n\n#endif // MICROPY_INCLUDED_PY_OBJLIST_H\n"
  },
  {
    "path": "py/objmap.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n\ntypedef struct _mp_obj_map_t {\n    mp_obj_base_t base;\n    size_t n_iters;\n    mp_obj_t fun;\n    mp_obj_t iters[];\n} mp_obj_map_t;\n\nSTATIC 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) {\n    mp_arg_check_num(n_args, n_kw, 2, MP_OBJ_FUN_ARGS_MAX, false);\n    mp_obj_map_t *o = m_new_obj_var(mp_obj_map_t, mp_obj_t, n_args - 1);\n    o->base.type = type;\n    o->n_iters = n_args - 1;\n    o->fun = args[0];\n    for (size_t i = 0; i < n_args - 1; i++) {\n        o->iters[i] = mp_getiter(args[i + 1], NULL);\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t map_iternext(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_map));\n    mp_obj_map_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t *nextses = m_new(mp_obj_t, self->n_iters);\n\n    for (size_t i = 0; i < self->n_iters; i++) {\n        mp_obj_t next = mp_iternext(self->iters[i]);\n        if (next == MP_OBJ_STOP_ITERATION) {\n            m_del(mp_obj_t, nextses, self->n_iters);\n            return MP_OBJ_STOP_ITERATION;\n        }\n        nextses[i] = next;\n    }\n    return mp_call_function_n_kw(self->fun, self->n_iters, 0, nextses);\n}\n\nconst mp_obj_type_t mp_type_map = {\n    { &mp_type_type },\n    .name = MP_QSTR_map,\n    .make_new = map_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = map_iternext,\n};\n"
  },
  {
    "path": "py/objmodule.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2019 Damien P. George\n * Copyright (c) 2014-2015 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/objmodule.h\"\n#include \"py/runtime.h\"\n#include \"py/builtin.h\"\n\n#include \"genhdr/moduledefs.h\"\n\nSTATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);\n\n    const char *module_name = \"\";\n    mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_MAP_LOOKUP);\n    if (elem != NULL) {\n        module_name = mp_obj_str_get_str(elem->value);\n    }\n\n    #if MICROPY_PY___FILE__\n    // If we store __file__ to imported modules then try to lookup this\n    // symbol to give more information about the module.\n    elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP);\n    if (elem != NULL) {\n        mp_printf(print, \"<module '%s' from '%s'>\", module_name, mp_obj_str_get_str(elem->value));\n        return;\n    }\n    #endif\n\n    mp_printf(print, \"<module '%s'>\", module_name);\n}\n\nSTATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);\n    if (dest[0] == MP_OBJ_NULL) {\n        // load attribute\n        mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);\n        if (elem != NULL) {\n            dest[0] = elem->value;\n        #if MICROPY_MODULE_GETATTR\n        } else if (attr != MP_QSTR___getattr__) {\n            elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___getattr__), MP_MAP_LOOKUP);\n            if (elem != NULL) {\n                dest[0] = mp_call_function_1(elem->value, MP_OBJ_NEW_QSTR(attr));\n            }\n        #endif\n        }\n    } else {\n        // delete/store attribute\n        mp_obj_dict_t *dict = self->globals;\n        if (dict->map.is_fixed) {\n            #if MICROPY_CAN_OVERRIDE_BUILTINS\n            if (dict == &mp_module_builtins_globals) {\n                if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) {\n                    MP_STATE_VM(mp_module_builtins_override_dict) = MP_OBJ_TO_PTR(mp_obj_new_dict(1));\n                }\n                dict = MP_STATE_VM(mp_module_builtins_override_dict);\n            } else\n            #endif\n            {\n                // can't delete or store to fixed map\n                return;\n            }\n        }\n        if (dest[1] == MP_OBJ_NULL) {\n            // delete attribute\n            mp_obj_dict_delete(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr));\n        } else {\n            // store attribute\n            mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr), dest[1]);\n        }\n        dest[0] = MP_OBJ_NULL; // indicate success\n    }\n}\n\nconst mp_obj_type_t mp_type_module = {\n    { &mp_type_type },\n    .name = MP_QSTR_module,\n    .print = module_print,\n    .attr = module_attr,\n};\n\nmp_obj_t mp_obj_new_module(qstr module_name) {\n    mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;\n    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);\n    // We could error out if module already exists, but let C extensions\n    // add new members to existing modules.\n    if (el->value != MP_OBJ_NULL) {\n        return el->value;\n    }\n\n    // create new module object\n    mp_obj_module_t *o = m_new_obj(mp_obj_module_t);\n    o->base.type = &mp_type_module;\n    o->globals = MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE));\n\n    // store __name__ entry in the module\n    mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(module_name));\n\n    // store the new module into the slot in the global dict holding all modules\n    el->value = MP_OBJ_FROM_PTR(o);\n\n    // return the new module\n    return MP_OBJ_FROM_PTR(o);\n}\n\n/******************************************************************************/\n// Global module table and related functions\n\nSTATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {\n    { MP_ROM_QSTR(MP_QSTR___main__), MP_ROM_PTR(&mp_module___main__) },\n    { MP_ROM_QSTR(MP_QSTR_builtins), MP_ROM_PTR(&mp_module_builtins) },\n    { MP_ROM_QSTR(MP_QSTR_micropython), MP_ROM_PTR(&mp_module_micropython) },\n\n    #if MICROPY_PY_IO\n    { MP_ROM_QSTR(MP_QSTR_uio), MP_ROM_PTR(&mp_module_io) },\n    #endif\n    #if MICROPY_PY_COLLECTIONS\n    { MP_ROM_QSTR(MP_QSTR_ucollections), MP_ROM_PTR(&mp_module_collections) },\n    #endif\n    #if MICROPY_PY_STRUCT\n    { MP_ROM_QSTR(MP_QSTR_ustruct), MP_ROM_PTR(&mp_module_ustruct) },\n    #endif\n\n    #if MICROPY_PY_BUILTINS_FLOAT\n    #if MICROPY_PY_MATH\n    { MP_ROM_QSTR(MP_QSTR_math), MP_ROM_PTR(&mp_module_math) },\n    #endif\n    #if MICROPY_PY_BUILTINS_COMPLEX && MICROPY_PY_CMATH\n    { MP_ROM_QSTR(MP_QSTR_cmath), MP_ROM_PTR(&mp_module_cmath) },\n    #endif\n    #endif\n    #if MICROPY_PY_SYS\n    { MP_ROM_QSTR(MP_QSTR_usys), MP_ROM_PTR(&mp_module_sys) },\n    #endif\n    #if MICROPY_PY_GC && MICROPY_ENABLE_GC\n    { MP_ROM_QSTR(MP_QSTR_gc), MP_ROM_PTR(&mp_module_gc) },\n    #endif\n    #if MICROPY_PY_THREAD\n    { MP_ROM_QSTR(MP_QSTR__thread), MP_ROM_PTR(&mp_module_thread) },\n    #endif\n\n    // extmod modules\n\n    #if MICROPY_PY_UASYNCIO\n    { MP_ROM_QSTR(MP_QSTR__uasyncio), MP_ROM_PTR(&mp_module_uasyncio) },\n    #endif\n    #if MICROPY_PY_UERRNO\n    { MP_ROM_QSTR(MP_QSTR_uerrno), MP_ROM_PTR(&mp_module_uerrno) },\n    #endif\n    #if MICROPY_PY_UCTYPES\n    { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) },\n    #endif\n    #if MICROPY_PY_UZLIB\n    { MP_ROM_QSTR(MP_QSTR_uzlib), MP_ROM_PTR(&mp_module_uzlib) },\n    #endif\n    #if MICROPY_PY_UJSON\n    { MP_ROM_QSTR(MP_QSTR_ujson), MP_ROM_PTR(&mp_module_ujson) },\n    #endif\n    #if MICROPY_PY_URE\n    { MP_ROM_QSTR(MP_QSTR_ure), MP_ROM_PTR(&mp_module_ure) },\n    #endif\n    #if MICROPY_PY_UHEAPQ\n    { MP_ROM_QSTR(MP_QSTR_uheapq), MP_ROM_PTR(&mp_module_uheapq) },\n    #endif\n    #if MICROPY_PY_UTIMEQ\n    { MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&mp_module_utimeq) },\n    #endif\n    #if MICROPY_PY_UHASHLIB\n    { MP_ROM_QSTR(MP_QSTR_uhashlib), MP_ROM_PTR(&mp_module_uhashlib) },\n    #endif\n    #if MICROPY_PY_UCRYPTOLIB\n    { MP_ROM_QSTR(MP_QSTR_ucryptolib), MP_ROM_PTR(&mp_module_ucryptolib) },\n    #endif\n    #if MICROPY_PY_UBINASCII\n    { MP_ROM_QSTR(MP_QSTR_ubinascii), MP_ROM_PTR(&mp_module_ubinascii) },\n    #endif\n    #if MICROPY_PY_URANDOM\n    { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mp_module_urandom) },\n    #endif\n    #if MICROPY_PY_USELECT\n    { MP_ROM_QSTR(MP_QSTR_uselect), MP_ROM_PTR(&mp_module_uselect) },\n    #endif\n    #if MICROPY_PY_USSL\n    { MP_ROM_QSTR(MP_QSTR_ussl), MP_ROM_PTR(&mp_module_ussl) },\n    #endif\n    #if MICROPY_PY_LWIP\n    { MP_ROM_QSTR(MP_QSTR_lwip), MP_ROM_PTR(&mp_module_lwip) },\n    #endif\n    #if MICROPY_PY_UWEBSOCKET\n    { MP_ROM_QSTR(MP_QSTR_uwebsocket), MP_ROM_PTR(&mp_module_uwebsocket) },\n    #endif\n    #if MICROPY_PY_WEBREPL\n    { MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&mp_module_webrepl) },\n    #endif\n    #if MICROPY_PY_FRAMEBUF\n    { MP_ROM_QSTR(MP_QSTR_framebuf), MP_ROM_PTR(&mp_module_framebuf) },\n    #endif\n    #if MICROPY_PY_BTREE\n    { MP_ROM_QSTR(MP_QSTR_btree), MP_ROM_PTR(&mp_module_btree) },\n    #endif\n    #if MICROPY_PY_BLUETOOTH\n    { MP_ROM_QSTR(MP_QSTR_ubluetooth), MP_ROM_PTR(&mp_module_ubluetooth) },\n    #endif\n\n    // extra builtin modules as defined by a port\n    MICROPY_PORT_BUILTIN_MODULES\n\n    #ifdef MICROPY_REGISTERED_MODULES\n    // builtin modules declared with MP_REGISTER_MODULE()\n    MICROPY_REGISTERED_MODULES\n    #endif\n};\n\nMP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table);\n\n// returns MP_OBJ_NULL if not found\nmp_obj_t mp_module_get(qstr module_name) {\n    mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;\n    // lookup module\n    mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);\n\n    if (el == NULL) {\n        // module not found, look for builtin module names\n        el = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);\n        if (el == NULL) {\n            return MP_OBJ_NULL;\n        }\n        mp_module_call_init(module_name, el->value);\n    }\n\n    // module found, return it\n    return el->value;\n}\n\nvoid mp_module_register(qstr qst, mp_obj_t module) {\n    mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;\n    mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module;\n}\n\n#if MICROPY_MODULE_WEAK_LINKS\n// Search for u\"foo\" in built-in modules, return MP_OBJ_NULL if not found\nmp_obj_t mp_module_search_umodule(const char *module_str) {\n    for (size_t i = 0; i < MP_ARRAY_SIZE(mp_builtin_module_table); ++i) {\n        const mp_map_elem_t *entry = (const mp_map_elem_t *)&mp_builtin_module_table[i];\n        const char *key = qstr_str(MP_OBJ_QSTR_VALUE(entry->key));\n        if (key[0] == 'u' && strcmp(&key[1], module_str) == 0) {\n            return (mp_obj_t)entry->value;\n        }\n\n    }\n    return MP_OBJ_NULL;\n}\n#endif\n\n#if MICROPY_MODULE_BUILTIN_INIT\nvoid mp_module_call_init(qstr module_name, mp_obj_t module_obj) {\n    // Look for __init__ and call it if it exists\n    mp_obj_t dest[2];\n    mp_load_method_maybe(module_obj, MP_QSTR___init__, dest);\n    if (dest[0] != MP_OBJ_NULL) {\n        mp_call_method_n_kw(0, 0, dest);\n        // Register module so __init__ is not called again.\n        // If a module can be referenced by more than one name (eg due to weak links)\n        // then __init__ will still be called for each distinct import, and it's then\n        // up to the particular module to make sure it's __init__ code only runs once.\n        mp_module_register(module_name, module_obj);\n    }\n}\n#endif\n"
  },
  {
    "path": "py/objmodule.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2019 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJMODULE_H\n#define MICROPY_INCLUDED_PY_OBJMODULE_H\n\n#include \"py/obj.h\"\n\nextern const mp_map_t mp_builtin_module_map;\n\nmp_obj_t mp_module_get(qstr module_name);\nvoid mp_module_register(qstr qstr, mp_obj_t module);\n\nmp_obj_t mp_module_search_umodule(const char *module_str);\n\n#if MICROPY_MODULE_BUILTIN_INIT\nvoid mp_module_call_init(qstr module_name, mp_obj_t module_obj);\n#else\nstatic inline void mp_module_call_init(qstr module_name, mp_obj_t module_obj) {\n    (void)module_name;\n    (void)module_obj;\n}\n#endif\n\n#endif // MICROPY_INCLUDED_PY_OBJMODULE_H\n"
  },
  {
    "path": "py/objnamedtuple.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n\n#include \"py/objtuple.h\"\n#include \"py/runtime.h\"\n#include \"py/objstr.h\"\n#include \"py/objnamedtuple.h\"\n\n#if MICROPY_PY_COLLECTIONS\n\nsize_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) {\n    for (size_t i = 0; i < type->n_fields; i++) {\n        if (type->fields[i] == name) {\n            return i;\n        }\n    }\n    return (size_t)-1;\n}\n\n#if MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT\nSTATIC mp_obj_t namedtuple_asdict(mp_obj_t self_in) {\n    mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in);\n    const qstr *fields = ((mp_obj_namedtuple_type_t *)self->tuple.base.type)->fields;\n    mp_obj_t dict = mp_obj_new_dict(self->tuple.len);\n    // make it an OrderedDict\n    mp_obj_dict_t *dictObj = MP_OBJ_TO_PTR(dict);\n    dictObj->base.type = &mp_type_ordereddict;\n    dictObj->map.is_ordered = 1;\n    for (size_t i = 0; i < self->tuple.len; ++i) {\n        mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(fields[i]), self->tuple.items[i]);\n    }\n    return dict;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(namedtuple_asdict_obj, namedtuple_asdict);\n#endif\n\nSTATIC void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_namedtuple_t *o = MP_OBJ_TO_PTR(o_in);\n    mp_printf(print, \"%q\", o->tuple.base.type->name);\n    const qstr *fields = ((mp_obj_namedtuple_type_t *)o->tuple.base.type)->fields;\n    mp_obj_attrtuple_print_helper(print, fields, &o->tuple);\n}\n\nSTATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] == MP_OBJ_NULL) {\n        // load attribute\n        mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in);\n        #if MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT\n        if (attr == MP_QSTR__asdict) {\n            dest[0] = MP_OBJ_FROM_PTR(&namedtuple_asdict_obj);\n            dest[1] = self_in;\n            return;\n        }\n        #endif\n        size_t id = mp_obj_namedtuple_find_field((mp_obj_namedtuple_type_t *)self->tuple.base.type, attr);\n        if (id == (size_t)-1) {\n            return;\n        }\n        dest[0] = self->tuple.items[id];\n    } else {\n        // delete/store attribute\n        // provide more detailed error message than we'd get by just returning\n        mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT(\"can't set attribute\"));\n    }\n}\n\nSTATIC 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) {\n    const mp_obj_namedtuple_type_t *type = (const mp_obj_namedtuple_type_t *)type_in;\n    size_t num_fields = type->n_fields;\n    if (n_args + n_kw != num_fields) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_arg_error_terse_mismatch();\n        #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"function takes %d positional arguments but %d were given\"),\n            num_fields, n_args + n_kw);\n        #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"%q() takes %d positional arguments but %d were given\"),\n            type->base.name, num_fields, n_args + n_kw);\n        #endif\n    }\n\n    // Create a tuple and set the type to this namedtuple\n    mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_fields, NULL));\n    tuple->base.type = type_in;\n\n    // Copy the positional args into the first slots of the namedtuple\n    memcpy(&tuple->items[0], args, sizeof(mp_obj_t) * n_args);\n\n    // Fill in the remaining slots with the keyword args\n    memset(&tuple->items[n_args], 0, sizeof(mp_obj_t) * n_kw);\n    for (size_t i = n_args; i < n_args + 2 * n_kw; i += 2) {\n        qstr kw = mp_obj_str_get_qstr(args[i]);\n        size_t id = mp_obj_namedtuple_find_field(type, kw);\n        if (id == (size_t)-1) {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_arg_error_terse_mismatch();\n            #else\n            mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT(\"unexpected keyword argument '%q'\"), kw);\n            #endif\n        }\n        if (tuple->items[id] != MP_OBJ_NULL) {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_arg_error_terse_mismatch();\n            #else\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"function got multiple values for argument '%q'\"), kw);\n            #endif\n        }\n        tuple->items[id] = args[i + 1];\n    }\n\n    return MP_OBJ_FROM_PTR(tuple);\n}\n\nmp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields) {\n    mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, qstr, n_fields);\n    memset(&o->base, 0, sizeof(o->base));\n    o->n_fields = n_fields;\n    for (size_t i = 0; i < n_fields; i++) {\n        o->fields[i] = mp_obj_str_get_qstr(fields[i]);\n    }\n    return o;\n}\n\nSTATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) {\n    mp_obj_namedtuple_type_t *o = mp_obj_new_namedtuple_base(n_fields, fields);\n    o->base.base.type = &mp_type_type;\n    o->base.flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE; // can match tuple\n    o->base.name = name;\n    o->base.print = namedtuple_print;\n    o->base.make_new = namedtuple_make_new;\n    o->base.unary_op = mp_obj_tuple_unary_op;\n    o->base.binary_op = mp_obj_tuple_binary_op;\n    o->base.attr = namedtuple_attr;\n    o->base.subscr = mp_obj_tuple_subscr;\n    o->base.getiter = mp_obj_tuple_getiter;\n    o->base.parent = &mp_type_tuple;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) {\n    qstr name = mp_obj_str_get_qstr(name_in);\n    size_t n_fields;\n    mp_obj_t *fields;\n    #if MICROPY_CPYTHON_COMPAT\n    if (mp_obj_is_str(fields_in)) {\n        fields_in = mp_obj_str_split(1, &fields_in);\n    }\n    #endif\n    mp_obj_get_array(fields_in, &n_fields, &fields);\n    return mp_obj_new_namedtuple_type(name, n_fields, fields);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type);\n\n#endif // MICROPY_PY_COLLECTIONS\n"
  },
  {
    "path": "py/objnamedtuple.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2017 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H\n#define MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H\n\n#include \"py/objtuple.h\"\n\ntypedef struct _mp_obj_namedtuple_type_t {\n    mp_obj_type_t base;\n    size_t n_fields;\n    qstr fields[];\n} mp_obj_namedtuple_type_t;\n\ntypedef struct _mp_obj_namedtuple_t {\n    mp_obj_tuple_t tuple;\n} mp_obj_namedtuple_t;\n\nsize_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name);\nmp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields);\n\n#endif // MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H\n"
  },
  {
    "path": "py/objnone.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n\n#include \"py/obj.h\"\n\n#if !MICROPY_OBJ_IMMEDIATE_OBJS\ntypedef struct _mp_obj_none_t {\n    mp_obj_base_t base;\n} mp_obj_none_t;\n#endif\n\nSTATIC void none_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)self_in;\n    if (MICROPY_PY_UJSON && kind == PRINT_JSON) {\n        mp_print_str(print, \"null\");\n    } else {\n        mp_print_str(print, \"None\");\n    }\n}\n\nconst mp_obj_type_t mp_type_NoneType = {\n    { &mp_type_type },\n    .name = MP_QSTR_NoneType,\n    .print = none_print,\n    .unary_op = mp_generic_unary_op,\n};\n\n#if !MICROPY_OBJ_IMMEDIATE_OBJS\nconst mp_obj_none_t mp_const_none_obj = {{&mp_type_NoneType}};\n#endif\n"
  },
  {
    "path": "py/objobject.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n\n#include \"py/objtype.h\"\n#include \"py/runtime.h\"\n\ntypedef struct _mp_obj_object_t {\n    mp_obj_base_t base;\n} mp_obj_object_t;\n\nSTATIC 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) {\n    (void)args;\n    mp_arg_check_num(n_args, n_kw, 0, 0, false);\n    mp_obj_object_t *o = m_new_obj(mp_obj_object_t);\n    o->base.type = type;\n    return MP_OBJ_FROM_PTR(o);\n}\n\n#if MICROPY_CPYTHON_COMPAT\nSTATIC mp_obj_t object___init__(mp_obj_t self) {\n    (void)self;\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__);\n\nSTATIC mp_obj_t object___new__(mp_obj_t cls) {\n    if (!mp_obj_is_type(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t *)MP_OBJ_TO_PTR(cls))) {\n        mp_raise_TypeError(MP_ERROR_TEXT(\"arg must be user-type\"));\n    }\n    // This executes only \"__new__\" part of instance creation.\n    // TODO: This won't work well for classes with native bases.\n    // TODO: This is a hack, should be resolved along the lines of\n    // https://github.com/micropython/micropython/issues/606#issuecomment-43685883\n    const mp_obj_type_t *native_base;\n    return MP_OBJ_FROM_PTR(mp_obj_new_instance(MP_OBJ_TO_PTR(cls), &native_base));\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__);\nSTATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, MP_ROM_PTR(&object___new___fun_obj));\n\n#if MICROPY_PY_DELATTR_SETATTR\nSTATIC mp_obj_t object___setattr__(mp_obj_t self_in, mp_obj_t attr, mp_obj_t value) {\n    if (!mp_obj_is_instance_type(mp_obj_get_type(self_in))) {\n        mp_raise_TypeError(MP_ERROR_TEXT(\"arg must be user-type\"));\n    }\n\n    if (!mp_obj_is_str(attr)) {\n        mp_raise_TypeError(NULL);\n    }\n\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_map_lookup(&self->members, attr, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_3(object___setattr___obj, object___setattr__);\n\nSTATIC mp_obj_t object___delattr__(mp_obj_t self_in, mp_obj_t attr) {\n    if (!mp_obj_is_instance_type(mp_obj_get_type(self_in))) {\n        mp_raise_TypeError(MP_ERROR_TEXT(\"arg must be user-type\"));\n    }\n\n    if (!mp_obj_is_str(attr)) {\n        mp_raise_TypeError(NULL);\n    }\n\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    if (mp_map_lookup(&self->members, attr, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == NULL) {\n        mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT(\"no such attribute\"));\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(object___delattr___obj, object___delattr__);\n#endif\n\nSTATIC const mp_rom_map_elem_t object_locals_dict_table[] = {\n    #if MICROPY_CPYTHON_COMPAT\n    { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&object___init___obj) },\n    #endif\n    #if MICROPY_CPYTHON_COMPAT\n    { MP_ROM_QSTR(MP_QSTR___new__), MP_ROM_PTR(&object___new___obj) },\n    #endif\n    #if MICROPY_PY_DELATTR_SETATTR\n    { MP_ROM_QSTR(MP_QSTR___setattr__), MP_ROM_PTR(&object___setattr___obj) },\n    { MP_ROM_QSTR(MP_QSTR___delattr__), MP_ROM_PTR(&object___delattr___obj) },\n    #endif\n};\n\nSTATIC MP_DEFINE_CONST_DICT(object_locals_dict, object_locals_dict_table);\n#endif\n\nconst mp_obj_type_t mp_type_object = {\n    { &mp_type_type },\n    .name = MP_QSTR_object,\n    .make_new = object_make_new,\n    #if MICROPY_CPYTHON_COMPAT\n    .locals_dict = (mp_obj_dict_t *)&object_locals_dict,\n    #endif\n};\n"
  },
  {
    "path": "py/objpolyiter.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n\n#include \"py/runtime.h\"\n\n// This is universal iterator type which calls \"iternext\" method stored in\n// particular object instance. (So, each instance of this time can have its\n// own iteration behavior.) Having this type saves to define type objects\n// for various internal iterator objects.\n\n// Any instance should have these 2 fields at the beginning\ntypedef struct _mp_obj_polymorph_iter_t {\n    mp_obj_base_t base;\n    mp_fun_1_t iternext;\n} mp_obj_polymorph_iter_t;\n\nSTATIC mp_obj_t polymorph_it_iternext(mp_obj_t self_in) {\n    mp_obj_polymorph_iter_t *self = MP_OBJ_TO_PTR(self_in);\n    // Redirect call to object instance's iternext method\n    return self->iternext(self_in);\n}\n\nconst mp_obj_type_t mp_type_polymorph_iter = {\n    { &mp_type_type },\n    .name = MP_QSTR_iterator,\n    .getiter = mp_identity_getiter,\n    .iternext = polymorph_it_iternext,\n};\n"
  },
  {
    "path": "py/objproperty.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_PROPERTY\n\ntypedef struct _mp_obj_property_t {\n    mp_obj_base_t base;\n    mp_obj_t proxy[3]; // getter, setter, deleter\n} mp_obj_property_t;\n\nSTATIC 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) {\n    enum { ARG_fget, ARG_fset, ARG_fdel, ARG_doc };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n        { MP_QSTR_doc, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },\n    };\n    mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);\n\n    mp_obj_property_t *o = m_new_obj(mp_obj_property_t);\n    o->base.type = type;\n    o->proxy[0] = vals[ARG_fget].u_obj;\n    o->proxy[1] = vals[ARG_fset].u_obj;\n    o->proxy[2] = vals[ARG_fdel].u_obj;\n    // vals[ARG_doc] is silently discarded\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t property_getter(mp_obj_t self_in, mp_obj_t getter) {\n    mp_obj_property_t *p2 = m_new_obj(mp_obj_property_t);\n    *p2 = *(mp_obj_property_t *)MP_OBJ_TO_PTR(self_in);\n    p2->proxy[0] = getter;\n    return MP_OBJ_FROM_PTR(p2);\n}\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(property_getter_obj, property_getter);\n\nSTATIC mp_obj_t property_setter(mp_obj_t self_in, mp_obj_t setter) {\n    mp_obj_property_t *p2 = m_new_obj(mp_obj_property_t);\n    *p2 = *(mp_obj_property_t *)MP_OBJ_TO_PTR(self_in);\n    p2->proxy[1] = setter;\n    return MP_OBJ_FROM_PTR(p2);\n}\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(property_setter_obj, property_setter);\n\nSTATIC mp_obj_t property_deleter(mp_obj_t self_in, mp_obj_t deleter) {\n    mp_obj_property_t *p2 = m_new_obj(mp_obj_property_t);\n    *p2 = *(mp_obj_property_t *)MP_OBJ_TO_PTR(self_in);\n    p2->proxy[2] = deleter;\n    return MP_OBJ_FROM_PTR(p2);\n}\n\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(property_deleter_obj, property_deleter);\n\nSTATIC const mp_rom_map_elem_t property_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_getter), MP_ROM_PTR(&property_getter_obj) },\n    { MP_ROM_QSTR(MP_QSTR_setter), MP_ROM_PTR(&property_setter_obj) },\n    { MP_ROM_QSTR(MP_QSTR_deleter), MP_ROM_PTR(&property_deleter_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(property_locals_dict, property_locals_dict_table);\n\nconst mp_obj_type_t mp_type_property = {\n    { &mp_type_type },\n    .name = MP_QSTR_property,\n    .make_new = property_make_new,\n    .locals_dict = (mp_obj_dict_t *)&property_locals_dict,\n};\n\nconst mp_obj_t *mp_obj_property_get(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_property));\n    mp_obj_property_t *self = MP_OBJ_TO_PTR(self_in);\n    return self->proxy;\n}\n\n#endif // MICROPY_PY_BUILTINS_PROPERTY\n"
  },
  {
    "path": "py/objrange.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n\n#include \"py/runtime.h\"\n\n/******************************************************************************/\n/* range iterator                                                             */\n\ntypedef struct _mp_obj_range_it_t {\n    mp_obj_base_t base;\n    // TODO make these values generic objects or something\n    mp_int_t cur;\n    mp_int_t stop;\n    mp_int_t step;\n} mp_obj_range_it_t;\n\nSTATIC mp_obj_t range_it_iternext(mp_obj_t o_in) {\n    mp_obj_range_it_t *o = MP_OBJ_TO_PTR(o_in);\n    if ((o->step > 0 && o->cur < o->stop) || (o->step < 0 && o->cur > o->stop)) {\n        mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(o->cur);\n        o->cur += o->step;\n        return o_out;\n    } else {\n        return MP_OBJ_STOP_ITERATION;\n    }\n}\n\nSTATIC const mp_obj_type_t range_it_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_iterator,\n    .getiter = mp_identity_getiter,\n    .iternext = range_it_iternext,\n};\n\nSTATIC 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) {\n    assert(sizeof(mp_obj_range_it_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_obj_range_it_t *o = (mp_obj_range_it_t *)iter_buf;\n    o->base.type = &range_it_type;\n    o->cur = cur;\n    o->stop = stop;\n    o->step = step;\n    return MP_OBJ_FROM_PTR(o);\n}\n\n/******************************************************************************/\n/* range                                                                      */\n\ntypedef struct _mp_obj_range_t {\n    mp_obj_base_t base;\n    // TODO make these values generic objects or something\n    mp_int_t start;\n    mp_int_t stop;\n    mp_int_t step;\n} mp_obj_range_t;\n\nSTATIC void range_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"range(\" INT_FMT \", \" INT_FMT \"\", self->start, self->stop);\n    if (self->step == 1) {\n        mp_print_str(print, \")\");\n    } else {\n        mp_printf(print, \", \" INT_FMT \")\", self->step);\n    }\n}\n\nSTATIC 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) {\n    mp_arg_check_num(n_args, n_kw, 1, 3, false);\n\n    mp_obj_range_t *o = m_new_obj(mp_obj_range_t);\n    o->base.type = type;\n    o->start = 0;\n    o->step = 1;\n\n    if (n_args == 1) {\n        o->stop = mp_obj_get_int(args[0]);\n    } else {\n        o->start = mp_obj_get_int(args[0]);\n        o->stop = mp_obj_get_int(args[1]);\n        if (n_args == 3) {\n            o->step = mp_obj_get_int(args[2]);\n            if (o->step == 0) {\n                mp_raise_ValueError(MP_ERROR_TEXT(\"zero step\"));\n            }\n        }\n    }\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_int_t range_len(mp_obj_range_t *self) {\n    // When computing length, need to take into account step!=1 and step<0.\n    mp_int_t len = self->stop - self->start + self->step;\n    if (self->step > 0) {\n        len -= 1;\n    } else {\n        len += 1;\n    }\n    len = len / self->step;\n    if (len < 0) {\n        len = 0;\n    }\n    return len;\n}\n\nSTATIC mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n    mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_int_t len = range_len(self);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(len > 0);\n        case MP_UNARY_OP_LEN:\n            return MP_OBJ_NEW_SMALL_INT(len);\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n\n#if MICROPY_PY_BUILTINS_RANGE_BINOP\nSTATIC mp_obj_t range_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    if (!mp_obj_is_type(rhs_in, &mp_type_range) || op != MP_BINARY_OP_EQUAL) {\n        return MP_OBJ_NULL; // op not supported\n    }\n    mp_obj_range_t *lhs = MP_OBJ_TO_PTR(lhs_in);\n    mp_obj_range_t *rhs = MP_OBJ_TO_PTR(rhs_in);\n    mp_int_t lhs_len = range_len(lhs);\n    mp_int_t rhs_len = range_len(rhs);\n    return mp_obj_new_bool(\n        lhs_len == rhs_len\n        && (lhs_len == 0\n            || (lhs->start == rhs->start\n                && (lhs_len == 1 || lhs->step == rhs->step)))\n        );\n}\n#endif\n\nSTATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {\n    if (value == MP_OBJ_SENTINEL) {\n        // load\n        mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);\n        mp_int_t len = range_len(self);\n        #if MICROPY_PY_BUILTINS_SLICE\n        if (mp_obj_is_type(index, &mp_type_slice)) {\n            mp_bound_slice_t slice;\n            mp_seq_get_fast_slice_indexes(len, index, &slice);\n            mp_obj_range_t *o = m_new_obj(mp_obj_range_t);\n            o->base.type = &mp_type_range;\n            o->start = self->start + slice.start * self->step;\n            o->stop = self->start + slice.stop * self->step;\n            o->step = slice.step * self->step;\n            if (slice.step < 0) {\n                // Negative slice steps have inclusive stop, so adjust for exclusive\n                o->stop -= self->step;\n            }\n            return MP_OBJ_FROM_PTR(o);\n        }\n        #endif\n        size_t index_val = mp_get_index(self->base.type, len, index, false);\n        return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step);\n    } else {\n        return MP_OBJ_NULL; // op not supported\n    }\n}\n\nSTATIC mp_obj_t range_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {\n    mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in);\n    return mp_obj_new_range_iterator(o->start, o->stop, o->step, iter_buf);\n}\n\n\n#if MICROPY_PY_BUILTINS_RANGE_ATTRS\nSTATIC void range_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] != MP_OBJ_NULL) {\n        // not load attribute\n        return;\n    }\n    mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in);\n    if (attr == MP_QSTR_start) {\n        dest[0] = mp_obj_new_int(o->start);\n    } else if (attr == MP_QSTR_stop) {\n        dest[0] = mp_obj_new_int(o->stop);\n    } else if (attr == MP_QSTR_step) {\n        dest[0] = mp_obj_new_int(o->step);\n    }\n}\n#endif\n\nconst mp_obj_type_t mp_type_range = {\n    { &mp_type_type },\n    .name = MP_QSTR_range,\n    .print = range_print,\n    .make_new = range_make_new,\n    .unary_op = range_unary_op,\n    #if MICROPY_PY_BUILTINS_RANGE_BINOP\n    .binary_op = range_binary_op,\n    #endif\n    .subscr = range_subscr,\n    .getiter = range_getiter,\n    #if MICROPY_PY_BUILTINS_RANGE_ATTRS\n    .attr = range_attr,\n    #endif\n};\n"
  },
  {
    "path": "py/objreversed.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_REVERSED\n\ntypedef struct _mp_obj_reversed_t {\n    mp_obj_base_t base;\n    mp_obj_t seq;           // sequence object that we are reversing\n    mp_uint_t cur_index;    // current index, plus 1; 0=no more, 1=last one (index 0)\n} mp_obj_reversed_t;\n\nSTATIC 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) {\n    mp_arg_check_num(n_args, n_kw, 1, 1, false);\n\n    // check if __reversed__ exists, and if so delegate to it\n    mp_obj_t dest[2];\n    mp_load_method_maybe(args[0], MP_QSTR___reversed__, dest);\n    if (dest[0] != MP_OBJ_NULL) {\n        return mp_call_method_n_kw(0, 0, dest);\n    }\n\n    mp_obj_reversed_t *o = m_new_obj(mp_obj_reversed_t);\n    o->base.type = type;\n    o->seq = args[0];\n    o->cur_index = mp_obj_get_int(mp_obj_len(args[0])); // start at the end of the sequence\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t reversed_iternext(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_reversed));\n    mp_obj_reversed_t *self = MP_OBJ_TO_PTR(self_in);\n\n    // \"raise\" stop iteration if we are at the end (the start) of the sequence\n    if (self->cur_index == 0) {\n        return MP_OBJ_STOP_ITERATION;\n    }\n\n    // pre-decrement and index sequence\n    self->cur_index -= 1;\n    return mp_obj_subscr(self->seq, MP_OBJ_NEW_SMALL_INT(self->cur_index), MP_OBJ_SENTINEL);\n}\n\nconst mp_obj_type_t mp_type_reversed = {\n    { &mp_type_type },\n    .name = MP_QSTR_reversed,\n    .make_new = reversed_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = reversed_iternext,\n};\n\n#endif // MICROPY_PY_BUILTINS_REVERSED\n"
  },
  {
    "path": "py/objset.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdbool.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n#include \"py/builtin.h\"\n\n#if MICROPY_PY_BUILTINS_SET\n\ntypedef struct _mp_obj_set_t {\n    mp_obj_base_t base;\n    mp_set_t set;\n} mp_obj_set_t;\n\ntypedef struct _mp_obj_set_it_t {\n    mp_obj_base_t base;\n    mp_fun_1_t iternext;\n    mp_obj_set_t *set;\n    size_t cur;\n} mp_obj_set_it_t;\n\nSTATIC bool is_set_or_frozenset(mp_obj_t o) {\n    return mp_obj_is_type(o, &mp_type_set)\n           #if MICROPY_PY_BUILTINS_FROZENSET\n           || mp_obj_is_type(o, &mp_type_frozenset)\n           #endif\n    ;\n}\n\n// This macro is shorthand for mp_check_self to verify the argument is a set.\n#define check_set(o) mp_check_self(mp_obj_is_type(o, &mp_type_set))\n\n// This macro is shorthand for mp_check_self to verify the argument is a\n// set or frozenset for methods that operate on both of these types.\n#define check_set_or_frozenset(o) mp_check_self(is_set_or_frozenset(o))\n\nSTATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    #if MICROPY_PY_BUILTINS_FROZENSET\n    bool is_frozen = mp_obj_is_type(self_in, &mp_type_frozenset);\n    #endif\n    if (self->set.used == 0) {\n        #if MICROPY_PY_BUILTINS_FROZENSET\n        if (is_frozen) {\n            mp_print_str(print, \"frozen\");\n        }\n        #endif\n        mp_print_str(print, \"set()\");\n        return;\n    }\n    bool first = true;\n    #if MICROPY_PY_BUILTINS_FROZENSET\n    if (is_frozen) {\n        mp_print_str(print, \"frozenset(\");\n    }\n    #endif\n    mp_print_str(print, \"{\");\n    for (size_t i = 0; i < self->set.alloc; i++) {\n        if (mp_set_slot_is_filled(&self->set, i)) {\n            if (!first) {\n                mp_print_str(print, \", \");\n            }\n            first = false;\n            mp_obj_print_helper(print, self->set.table[i], PRINT_REPR);\n        }\n    }\n    mp_print_str(print, \"}\");\n    #if MICROPY_PY_BUILTINS_FROZENSET\n    if (is_frozen) {\n        mp_print_str(print, \")\");\n    }\n    #endif\n}\n\nSTATIC 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) {\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n\n    switch (n_args) {\n        case 0: {\n            // create a new, empty set\n            mp_obj_set_t *set = MP_OBJ_TO_PTR(mp_obj_new_set(0, NULL));\n            // set actual set/frozenset type\n            set->base.type = type;\n            return MP_OBJ_FROM_PTR(set);\n        }\n\n        case 1:\n        default: { // can only be 0 or 1 arg\n            // 1 argument, an iterable from which we make a new set\n            mp_obj_t set = mp_obj_new_set(0, NULL);\n            mp_obj_t iterable = mp_getiter(args[0], NULL);\n            mp_obj_t item;\n            while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n                mp_obj_set_store(set, item);\n            }\n            // Set actual set/frozenset type\n            ((mp_obj_set_t *)MP_OBJ_TO_PTR(set))->base.type = type;\n            return set;\n        }\n    }\n}\n\nSTATIC mp_obj_t set_it_iternext(mp_obj_t self_in) {\n    mp_obj_set_it_t *self = MP_OBJ_TO_PTR(self_in);\n    size_t max = self->set->set.alloc;\n    mp_set_t *set = &self->set->set;\n\n    for (size_t i = self->cur; i < max; i++) {\n        if (mp_set_slot_is_filled(set, i)) {\n            self->cur = i + 1;\n            return set->table[i];\n        }\n    }\n\n    return MP_OBJ_STOP_ITERATION;\n}\n\nSTATIC mp_obj_t set_getiter(mp_obj_t set_in, mp_obj_iter_buf_t *iter_buf) {\n    assert(sizeof(mp_obj_set_it_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_obj_set_it_t *o = (mp_obj_set_it_t *)iter_buf;\n    o->base.type = &mp_type_polymorph_iter;\n    o->iternext = set_it_iternext;\n    o->set = (mp_obj_set_t *)MP_OBJ_TO_PTR(set_in);\n    o->cur = 0;\n    return MP_OBJ_FROM_PTR(o);\n}\n\n/******************************************************************************/\n/* set methods                                                                */\n\nSTATIC mp_obj_t set_add(mp_obj_t self_in, mp_obj_t item) {\n    check_set(self_in);\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_add_obj, set_add);\n\nSTATIC mp_obj_t set_clear(mp_obj_t self_in) {\n    check_set(self_in);\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_set_clear(&self->set);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(set_clear_obj, set_clear);\n\nSTATIC mp_obj_t set_copy(mp_obj_t self_in) {\n    check_set_or_frozenset(self_in);\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_set_t *other = m_new_obj(mp_obj_set_t);\n    other->base.type = self->base.type;\n    mp_set_init(&other->set, self->set.alloc);\n    other->set.used = self->set.used;\n    memcpy(other->set.table, self->set.table, self->set.alloc * sizeof(mp_obj_t));\n    return MP_OBJ_FROM_PTR(other);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(set_copy_obj, set_copy);\n\nSTATIC mp_obj_t set_discard(mp_obj_t self_in, mp_obj_t item) {\n    check_set(self_in);\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_discard_obj, set_discard);\n\nSTATIC mp_obj_t set_diff_int(size_t n_args, const mp_obj_t *args, bool update) {\n    mp_obj_t self;\n    if (update) {\n        check_set(args[0]);\n        self = args[0];\n    } else {\n        self = set_copy(args[0]);\n    }\n\n    for (size_t i = 1; i < n_args; i++) {\n        mp_obj_t other = args[i];\n        if (self == other) {\n            set_clear(self);\n        } else {\n            mp_set_t *self_set = &((mp_obj_set_t *)MP_OBJ_TO_PTR(self))->set;\n            mp_obj_t iter = mp_getiter(other, NULL);\n            mp_obj_t next;\n            while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n                mp_set_lookup(self_set, next, MP_MAP_LOOKUP_REMOVE_IF_FOUND);\n            }\n        }\n    }\n\n    return self;\n}\n\nSTATIC mp_obj_t set_diff(size_t n_args, const mp_obj_t *args) {\n    return set_diff_int(n_args, args, false);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_obj, 1, set_diff);\n\nSTATIC mp_obj_t set_diff_update(size_t n_args, const mp_obj_t *args) {\n    set_diff_int(n_args, args, true);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_update_obj, 1, set_diff_update);\n\nSTATIC mp_obj_t set_intersect_int(mp_obj_t self_in, mp_obj_t other, bool update) {\n    if (update) {\n        check_set(self_in);\n    } else {\n        check_set_or_frozenset(self_in);\n    }\n\n    if (self_in == other) {\n        return update ? mp_const_none : set_copy(self_in);\n    }\n\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_set_t *out = MP_OBJ_TO_PTR(mp_obj_new_set(0, NULL));\n\n    mp_obj_t iter = mp_getiter(other, NULL);\n    mp_obj_t next;\n    while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n        if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) {\n            set_add(MP_OBJ_FROM_PTR(out), next);\n        }\n    }\n\n    if (update) {\n        m_del(mp_obj_t, self->set.table, self->set.alloc);\n        self->set.alloc = out->set.alloc;\n        self->set.used = out->set.used;\n        self->set.table = out->set.table;\n    }\n\n    return update ? mp_const_none : MP_OBJ_FROM_PTR(out);\n}\n\nSTATIC mp_obj_t set_intersect(mp_obj_t self_in, mp_obj_t other) {\n    return set_intersect_int(self_in, other, false);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_obj, set_intersect);\n\nSTATIC mp_obj_t set_intersect_update(mp_obj_t self_in, mp_obj_t other) {\n    return set_intersect_int(self_in, other, true);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_update_obj, set_intersect_update);\n\nSTATIC mp_obj_t set_isdisjoint(mp_obj_t self_in, mp_obj_t other) {\n    check_set_or_frozenset(self_in);\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n\n    mp_obj_iter_buf_t iter_buf;\n    mp_obj_t iter = mp_getiter(other, &iter_buf);\n    mp_obj_t next;\n    while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n        if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) {\n            return mp_const_false;\n        }\n    }\n    return mp_const_true;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_isdisjoint_obj, set_isdisjoint);\n\nSTATIC mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool proper) {\n    mp_obj_set_t *self;\n    bool cleanup_self = false;\n    if (is_set_or_frozenset(self_in)) {\n        self = MP_OBJ_TO_PTR(self_in);\n    } else {\n        self = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, 0, &self_in));\n        cleanup_self = true;\n    }\n\n    mp_obj_set_t *other;\n    bool cleanup_other = false;\n    if (is_set_or_frozenset(other_in)) {\n        other = MP_OBJ_TO_PTR(other_in);\n    } else {\n        other = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, 0, &other_in));\n        cleanup_other = true;\n    }\n    mp_obj_t out = mp_const_true;\n    if (proper && self->set.used == other->set.used) {\n        out = mp_const_false;\n    } else {\n        mp_obj_iter_buf_t iter_buf;\n        mp_obj_t iter = set_getiter(MP_OBJ_FROM_PTR(self), &iter_buf);\n        mp_obj_t next;\n        while ((next = set_it_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n            if (!mp_set_lookup(&other->set, next, MP_MAP_LOOKUP)) {\n                out = mp_const_false;\n                break;\n            }\n        }\n    }\n    // TODO: Should free objects altogether\n    if (cleanup_self) {\n        set_clear(MP_OBJ_FROM_PTR(self));\n    }\n    if (cleanup_other) {\n        set_clear(MP_OBJ_FROM_PTR(other));\n    }\n    return out;\n}\n\nSTATIC mp_obj_t set_issubset(mp_obj_t self_in, mp_obj_t other_in) {\n    return set_issubset_internal(self_in, other_in, false);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_issubset_obj, set_issubset);\n\nSTATIC mp_obj_t set_issubset_proper(mp_obj_t self_in, mp_obj_t other_in) {\n    return set_issubset_internal(self_in, other_in, true);\n}\n\nSTATIC mp_obj_t set_issuperset(mp_obj_t self_in, mp_obj_t other_in) {\n    return set_issubset_internal(other_in, self_in, false);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_issuperset_obj, set_issuperset);\n\nSTATIC mp_obj_t set_issuperset_proper(mp_obj_t self_in, mp_obj_t other_in) {\n    return set_issubset_internal(other_in, self_in, true);\n}\n\nSTATIC mp_obj_t set_equal(mp_obj_t self_in, mp_obj_t other_in) {\n    assert(is_set_or_frozenset(other_in));\n    check_set_or_frozenset(self_in);\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_set_t *other = MP_OBJ_TO_PTR(other_in);\n    if (self->set.used != other->set.used) {\n        return mp_const_false;\n    }\n    return set_issubset(self_in, other_in);\n}\n\nSTATIC mp_obj_t set_pop(mp_obj_t self_in) {\n    check_set(self_in);\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t obj = mp_set_remove_first(&self->set);\n    if (obj == MP_OBJ_NULL) {\n        mp_raise_msg(&mp_type_KeyError, MP_ERROR_TEXT(\"pop from an empty set\"));\n    }\n    return obj;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(set_pop_obj, set_pop);\n\nSTATIC mp_obj_t set_remove(mp_obj_t self_in, mp_obj_t item) {\n    check_set(self_in);\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    if (mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == MP_OBJ_NULL) {\n        nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, item));\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_remove_obj, set_remove);\n\nSTATIC mp_obj_t set_symmetric_difference_update(mp_obj_t self_in, mp_obj_t other_in) {\n    check_set_or_frozenset(self_in); // can be frozenset due to call from set_symmetric_difference\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t iter = mp_getiter(other_in, NULL);\n    mp_obj_t next;\n    while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n        mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND);\n    }\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_update_obj, set_symmetric_difference_update);\n\nSTATIC mp_obj_t set_symmetric_difference(mp_obj_t self_in, mp_obj_t other_in) {\n    mp_obj_t self_out = set_copy(self_in);\n    set_symmetric_difference_update(self_out, other_in);\n    return self_out;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_obj, set_symmetric_difference);\n\nSTATIC void set_update_int(mp_obj_set_t *self, mp_obj_t other_in) {\n    mp_obj_t iter = mp_getiter(other_in, NULL);\n    mp_obj_t next;\n    while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n        mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);\n    }\n}\n\nSTATIC mp_obj_t set_update(size_t n_args, const mp_obj_t *args) {\n    check_set(args[0]);\n    for (size_t i = 1; i < n_args; i++) {\n        set_update_int(MP_OBJ_TO_PTR(args[0]), args[i]);\n    }\n\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_update_obj, 1, set_update);\n\nSTATIC mp_obj_t set_union(mp_obj_t self_in, mp_obj_t other_in) {\n    check_set_or_frozenset(self_in);\n    mp_obj_t self = set_copy(self_in);\n    set_update_int(MP_OBJ_TO_PTR(self), other_in);\n    return self;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(set_union_obj, set_union);\n\nSTATIC mp_obj_t set_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(self->set.used != 0);\n        case MP_UNARY_OP_LEN:\n            return MP_OBJ_NEW_SMALL_INT(self->set.used);\n        #if MICROPY_PY_BUILTINS_FROZENSET\n        case MP_UNARY_OP_HASH:\n            if (mp_obj_is_type(self_in, &mp_type_frozenset)) {\n                // start hash with unique value\n                mp_int_t hash = (mp_int_t)(uintptr_t)&mp_type_frozenset;\n                size_t max = self->set.alloc;\n                mp_set_t *set = &self->set;\n\n                for (size_t i = 0; i < max; i++) {\n                    if (mp_set_slot_is_filled(set, i)) {\n                        hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, set->table[i]));\n                    }\n                }\n                return MP_OBJ_NEW_SMALL_INT(hash);\n            }\n            MP_FALLTHROUGH\n        #endif\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n\nSTATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {\n    mp_obj_t args[] = {lhs, rhs};\n    #if MICROPY_PY_BUILTINS_FROZENSET\n    bool update = mp_obj_is_type(lhs, &mp_type_set);\n    #else\n    bool update = true;\n    #endif\n    if (op != MP_BINARY_OP_CONTAINS && !is_set_or_frozenset(rhs)) {\n        // For all ops except containment the RHS must be a set/frozenset\n        return MP_OBJ_NULL;\n    }\n    switch (op) {\n        case MP_BINARY_OP_OR:\n            return set_union(lhs, rhs);\n        case MP_BINARY_OP_XOR:\n            return set_symmetric_difference(lhs, rhs);\n        case MP_BINARY_OP_AND:\n            return set_intersect(lhs, rhs);\n        case MP_BINARY_OP_SUBTRACT:\n            return set_diff(2, args);\n        case MP_BINARY_OP_INPLACE_OR:\n            if (update) {\n                set_update(2, args);\n                return lhs;\n            } else {\n                return set_union(lhs, rhs);\n            }\n        case MP_BINARY_OP_INPLACE_XOR:\n            if (update) {\n                set_symmetric_difference_update(lhs, rhs);\n                return lhs;\n            } else {\n                return set_symmetric_difference(lhs, rhs);\n            }\n        case MP_BINARY_OP_INPLACE_AND:\n            rhs = set_intersect_int(lhs, rhs, update);\n            if (update) {\n                return lhs;\n            } else {\n                return rhs;\n            }\n        case MP_BINARY_OP_INPLACE_SUBTRACT:\n            return set_diff_int(2, args, update);\n        case MP_BINARY_OP_LESS:\n            return set_issubset_proper(lhs, rhs);\n        case MP_BINARY_OP_MORE:\n            return set_issuperset_proper(lhs, rhs);\n        case MP_BINARY_OP_EQUAL:\n            return set_equal(lhs, rhs);\n        case MP_BINARY_OP_LESS_EQUAL:\n            return set_issubset(lhs, rhs);\n        case MP_BINARY_OP_MORE_EQUAL:\n            return set_issuperset(lhs, rhs);\n        case MP_BINARY_OP_CONTAINS: {\n            mp_obj_set_t *o = MP_OBJ_TO_PTR(lhs);\n            mp_obj_t elem = mp_set_lookup(&o->set, rhs, MP_MAP_LOOKUP);\n            return mp_obj_new_bool(elem != MP_OBJ_NULL);\n        }\n        default:\n            return MP_OBJ_NULL; // op not supported\n    }\n}\n\n/******************************************************************************/\n/* set constructors & public C API                                            */\n\nSTATIC const mp_rom_map_elem_t set_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&set_add_obj) },\n    { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&set_clear_obj) },\n    { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&set_copy_obj) },\n    { MP_ROM_QSTR(MP_QSTR_discard), MP_ROM_PTR(&set_discard_obj) },\n    { MP_ROM_QSTR(MP_QSTR_difference), MP_ROM_PTR(&set_diff_obj) },\n    { MP_ROM_QSTR(MP_QSTR_difference_update), MP_ROM_PTR(&set_diff_update_obj) },\n    { MP_ROM_QSTR(MP_QSTR_intersection), MP_ROM_PTR(&set_intersect_obj) },\n    { MP_ROM_QSTR(MP_QSTR_intersection_update), MP_ROM_PTR(&set_intersect_update_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isdisjoint), MP_ROM_PTR(&set_isdisjoint_obj) },\n    { MP_ROM_QSTR(MP_QSTR_issubset), MP_ROM_PTR(&set_issubset_obj) },\n    { MP_ROM_QSTR(MP_QSTR_issuperset), MP_ROM_PTR(&set_issuperset_obj) },\n    { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&set_pop_obj) },\n    { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&set_remove_obj) },\n    { MP_ROM_QSTR(MP_QSTR_symmetric_difference), MP_ROM_PTR(&set_symmetric_difference_obj) },\n    { MP_ROM_QSTR(MP_QSTR_symmetric_difference_update), MP_ROM_PTR(&set_symmetric_difference_update_obj) },\n    { MP_ROM_QSTR(MP_QSTR_union), MP_ROM_PTR(&set_union_obj) },\n    { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&set_update_obj) },\n    { MP_ROM_QSTR(MP_QSTR___contains__), MP_ROM_PTR(&mp_op_contains_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(set_locals_dict, set_locals_dict_table);\n\nconst mp_obj_type_t mp_type_set = {\n    { &mp_type_type },\n    .name = MP_QSTR_set,\n    .print = set_print,\n    .make_new = set_make_new,\n    .unary_op = set_unary_op,\n    .binary_op = set_binary_op,\n    .getiter = set_getiter,\n    .locals_dict = (mp_obj_dict_t *)&set_locals_dict,\n};\n\n#if MICROPY_PY_BUILTINS_FROZENSET\nSTATIC const mp_rom_map_elem_t frozenset_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&set_copy_obj) },\n    { MP_ROM_QSTR(MP_QSTR_difference), MP_ROM_PTR(&set_diff_obj) },\n    { MP_ROM_QSTR(MP_QSTR_intersection), MP_ROM_PTR(&set_intersect_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isdisjoint), MP_ROM_PTR(&set_isdisjoint_obj) },\n    { MP_ROM_QSTR(MP_QSTR_issubset), MP_ROM_PTR(&set_issubset_obj) },\n    { MP_ROM_QSTR(MP_QSTR_issuperset), MP_ROM_PTR(&set_issuperset_obj) },\n    { MP_ROM_QSTR(MP_QSTR_symmetric_difference), MP_ROM_PTR(&set_symmetric_difference_obj) },\n    { MP_ROM_QSTR(MP_QSTR_union), MP_ROM_PTR(&set_union_obj) },\n    { MP_ROM_QSTR(MP_QSTR___contains__), MP_ROM_PTR(&mp_op_contains_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(frozenset_locals_dict, frozenset_locals_dict_table);\n\nconst mp_obj_type_t mp_type_frozenset = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,\n    .name = MP_QSTR_frozenset,\n    .print = set_print,\n    .make_new = set_make_new,\n    .unary_op = set_unary_op,\n    .binary_op = set_binary_op,\n    .getiter = set_getiter,\n    .locals_dict = (mp_obj_dict_t *)&frozenset_locals_dict,\n};\n#endif\n\nmp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) {\n    mp_obj_set_t *o = m_new_obj(mp_obj_set_t);\n    o->base.type = &mp_type_set;\n    mp_set_init(&o->set, n_args);\n    for (size_t i = 0; i < n_args; i++) {\n        mp_set_lookup(&o->set, items[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nvoid mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_set));\n    mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);\n}\n\n#endif // MICROPY_PY_BUILTINS_SET\n"
  },
  {
    "path": "py/objsingleton.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"py/obj.h\"\n\n/******************************************************************************/\n/* singleton objects defined by Python                                        */\n\ntypedef struct _mp_obj_singleton_t {\n    mp_obj_base_t base;\n    qstr name;\n} mp_obj_singleton_t;\n\nSTATIC void singleton_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_singleton_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"%q\", self->name);\n}\n\nconst mp_obj_type_t mp_type_singleton = {\n    { &mp_type_type },\n    .name = MP_QSTR_,\n    .print = singleton_print,\n    .unary_op = mp_generic_unary_op,\n};\n\nconst mp_obj_singleton_t mp_const_ellipsis_obj = {{&mp_type_singleton}, MP_QSTR_Ellipsis};\n#if MICROPY_PY_BUILTINS_NOTIMPLEMENTED\nconst mp_obj_singleton_t mp_const_notimplemented_obj = {{&mp_type_singleton}, MP_QSTR_NotImplemented};\n#endif\n"
  },
  {
    "path": "py/objslice.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"py/runtime.h\"\n\n/******************************************************************************/\n/* slice object                                                               */\n\n#if MICROPY_PY_BUILTINS_SLICE\n\nSTATIC void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_slice_t *o = MP_OBJ_TO_PTR(o_in);\n    mp_print_str(print, \"slice(\");\n    mp_obj_print_helper(print, o->start, PRINT_REPR);\n    mp_print_str(print, \", \");\n    mp_obj_print_helper(print, o->stop, PRINT_REPR);\n    mp_print_str(print, \", \");\n    mp_obj_print_helper(print, o->step, PRINT_REPR);\n    mp_print_str(print, \")\");\n}\n\n#if MICROPY_PY_BUILTINS_SLICE_INDICES\nSTATIC mp_obj_t slice_indices(mp_obj_t self_in, mp_obj_t length_obj) {\n    mp_int_t length = mp_obj_int_get_checked(length_obj);\n    mp_bound_slice_t bound_indices;\n    mp_obj_slice_indices(self_in, length, &bound_indices);\n\n    mp_obj_t results[3] = {\n        MP_OBJ_NEW_SMALL_INT(bound_indices.start),\n        MP_OBJ_NEW_SMALL_INT(bound_indices.stop),\n        MP_OBJ_NEW_SMALL_INT(bound_indices.step),\n    };\n    return mp_obj_new_tuple(3, results);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(slice_indices_obj, slice_indices);\n#endif\n\n#if MICROPY_PY_BUILTINS_SLICE_ATTRS\nSTATIC void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] != MP_OBJ_NULL) {\n        // not load attribute\n        return;\n    }\n    mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (attr == MP_QSTR_start) {\n        dest[0] = self->start;\n    } else if (attr == MP_QSTR_stop) {\n        dest[0] = self->stop;\n    } else if (attr == MP_QSTR_step) {\n        dest[0] = self->step;\n    #if MICROPY_PY_BUILTINS_SLICE_INDICES\n    } else if (attr == MP_QSTR_indices) {\n        dest[0] = MP_OBJ_FROM_PTR(&slice_indices_obj);\n        dest[1] = self_in;\n    #endif\n    }\n}\n#endif\n\n#if MICROPY_PY_BUILTINS_SLICE_INDICES && !MICROPY_PY_BUILTINS_SLICE_ATTRS\nSTATIC const mp_rom_map_elem_t slice_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_indices), MP_ROM_PTR(&slice_indices_obj) },\n};\nSTATIC MP_DEFINE_CONST_DICT(slice_locals_dict, slice_locals_dict_table);\n#endif\n\nconst mp_obj_type_t mp_type_slice = {\n    { &mp_type_type },\n    .name = MP_QSTR_slice,\n    .print = slice_print,\n    #if MICROPY_PY_BUILTINS_SLICE_ATTRS\n    .attr = slice_attr,\n    #elif MICROPY_PY_BUILTINS_SLICE_INDICES\n    .locals_dict = (mp_obj_dict_t *)&slice_locals_dict,\n    #endif\n};\n\nmp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) {\n    mp_obj_slice_t *o = m_new_obj(mp_obj_slice_t);\n    o->base.type = &mp_type_slice;\n    o->start = ostart;\n    o->stop = ostop;\n    o->step = ostep;\n    return MP_OBJ_FROM_PTR(o);\n}\n\n// Return the real index and step values for a slice when applied to a sequence of\n// the given length, resolving missing components, negative values and values off\n// the end of the sequence.\nvoid mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result) {\n    mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_int_t start, stop, step;\n\n    if (self->step == mp_const_none) {\n        step = 1;\n    } else {\n        step = mp_obj_get_int(self->step);\n        if (step == 0) {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"slice step can't be zero\"));\n        }\n    }\n\n    if (step > 0) {\n        // Positive step\n        if (self->start == mp_const_none) {\n            start = 0;\n        } else {\n            start = mp_obj_get_int(self->start);\n            if (start < 0) {\n                start += length;\n            }\n            start = MIN(length, MAX(start, 0));\n        }\n\n        if (self->stop == mp_const_none) {\n            stop = length;\n        } else {\n            stop = mp_obj_get_int(self->stop);\n            if (stop < 0) {\n                stop += length;\n            }\n            stop = MIN(length, MAX(stop, 0));\n        }\n    } else {\n        // Negative step\n        if (self->start == mp_const_none) {\n            start = length - 1;\n        } else {\n            start = mp_obj_get_int(self->start);\n            if (start < 0) {\n                start += length;\n            }\n            start = MIN(length - 1, MAX(start, -1));\n        }\n\n        if (self->stop == mp_const_none) {\n            stop = -1;\n        } else {\n            stop = mp_obj_get_int(self->stop);\n            if (stop < 0) {\n                stop += length;\n            }\n            stop = MIN(length - 1, MAX(stop, -1));\n        }\n    }\n\n    result->start = start;\n    result->stop = stop;\n    result->step = step;\n}\n\n#endif\n"
  },
  {
    "path": "py/objstr.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014-2018 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <assert.h>\n\n#include \"py/unicode.h\"\n#include \"py/objstr.h\"\n#include \"py/objlist.h\"\n#include \"py/runtime.h\"\n#include \"py/stackctrl.h\"\n\n#if MICROPY_PY_BUILTINS_STR_OP_MODULO\nSTATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict);\n#endif\n\nSTATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);\nSTATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in);\n\n/******************************************************************************/\n/* str                                                                        */\n\nvoid mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes) {\n    // this escapes characters, but it will be very slow to print (calling print many times)\n    bool has_single_quote = false;\n    bool has_double_quote = false;\n    for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) {\n        if (*s == '\\'') {\n            has_single_quote = true;\n        } else if (*s == '\"') {\n            has_double_quote = true;\n        }\n    }\n    int quote_char = '\\'';\n    if (has_single_quote && !has_double_quote) {\n        quote_char = '\"';\n    }\n    mp_printf(print, \"%c\", quote_char);\n    for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {\n        if (*s == quote_char) {\n            mp_printf(print, \"\\\\%c\", quote_char);\n        } else if (*s == '\\\\') {\n            mp_print_str(print, \"\\\\\\\\\");\n        } else if (*s >= 0x20 && *s != 0x7f && (!is_bytes || *s < 0x80)) {\n            // In strings, anything which is not ascii control character\n            // is printed as is, this includes characters in range 0x80-0xff\n            // (which can be non-Latin letters, etc.)\n            mp_printf(print, \"%c\", *s);\n        } else if (*s == '\\n') {\n            mp_print_str(print, \"\\\\n\");\n        } else if (*s == '\\r') {\n            mp_print_str(print, \"\\\\r\");\n        } else if (*s == '\\t') {\n            mp_print_str(print, \"\\\\t\");\n        } else {\n            mp_printf(print, \"\\\\x%02x\", *s);\n        }\n    }\n    mp_printf(print, \"%c\", quote_char);\n}\n\n#if MICROPY_PY_UJSON\nvoid mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len) {\n    // for JSON spec, see http://www.ietf.org/rfc/rfc4627.txt\n    // if we are given a valid utf8-encoded string, we will print it in a JSON-conforming way\n    mp_print_str(print, \"\\\"\");\n    for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {\n        if (*s == '\"' || *s == '\\\\') {\n            mp_printf(print, \"\\\\%c\", *s);\n        } else if (*s >= 32) {\n            // this will handle normal and utf-8 encoded chars\n            mp_printf(print, \"%c\", *s);\n        } else if (*s == '\\n') {\n            mp_print_str(print, \"\\\\n\");\n        } else if (*s == '\\r') {\n            mp_print_str(print, \"\\\\r\");\n        } else if (*s == '\\t') {\n            mp_print_str(print, \"\\\\t\");\n        } else {\n            // this will handle control chars\n            mp_printf(print, \"\\\\u%04x\", *s);\n        }\n    }\n    mp_print_str(print, \"\\\"\");\n}\n#endif\n\nSTATIC void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    GET_STR_DATA_LEN(self_in, str_data, str_len);\n    #if MICROPY_PY_UJSON\n    if (kind == PRINT_JSON) {\n        mp_str_print_json(print, str_data, str_len);\n        return;\n    }\n    #endif\n    #if !MICROPY_PY_BUILTINS_STR_UNICODE\n    bool is_bytes = mp_obj_is_type(self_in, &mp_type_bytes);\n    #else\n    bool is_bytes = true;\n    #endif\n    if (kind == PRINT_RAW || (!MICROPY_PY_BUILTINS_STR_UNICODE && kind == PRINT_STR && !is_bytes)) {\n        mp_printf(print, \"%.*s\", str_len, str_data);\n    } else {\n        if (is_bytes) {\n            mp_print_str(print, \"b\");\n        }\n        mp_str_print_quoted(print, str_data, str_len, is_bytes);\n    }\n}\n\nmp_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) {\n    #if MICROPY_CPYTHON_COMPAT\n    if (n_kw != 0) {\n        mp_arg_error_unimpl_kw();\n    }\n    #endif\n\n    mp_arg_check_num(n_args, n_kw, 0, 3, false);\n\n    switch (n_args) {\n        case 0:\n            return MP_OBJ_NEW_QSTR(MP_QSTR_);\n\n        case 1: {\n            vstr_t vstr;\n            mp_print_t print;\n            vstr_init_print(&vstr, 16, &print);\n            mp_obj_print_helper(&print, args[0], PRINT_STR);\n            return mp_obj_new_str_from_vstr(type, &vstr);\n        }\n\n        default: // 2 or 3 args\n            // TODO: validate 2nd/3rd args\n            if (mp_obj_is_type(args[0], &mp_type_bytes)) {\n                GET_STR_DATA_LEN(args[0], str_data, str_len);\n                GET_STR_HASH(args[0], str_hash);\n                if (str_hash == 0) {\n                    str_hash = qstr_compute_hash(str_data, str_len);\n                }\n                #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK\n                if (!utf8_check(str_data, str_len)) {\n                    mp_raise_msg(&mp_type_UnicodeError, NULL);\n                }\n                #endif\n\n                // Check if a qstr with this data already exists\n                qstr q = qstr_find_strn((const char *)str_data, str_len);\n                if (q != MP_QSTRnull) {\n                    return MP_OBJ_NEW_QSTR(q);\n                }\n\n                mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len));\n                o->data = str_data;\n                o->hash = str_hash;\n                return MP_OBJ_FROM_PTR(o);\n            } else {\n                mp_buffer_info_t bufinfo;\n                mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);\n                #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK\n                if (!utf8_check(bufinfo.buf, bufinfo.len)) {\n                    mp_raise_msg(&mp_type_UnicodeError, NULL);\n                }\n                #endif\n                return mp_obj_new_str(bufinfo.buf, bufinfo.len);\n            }\n    }\n}\n\nSTATIC 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) {\n    (void)type_in;\n\n    #if MICROPY_CPYTHON_COMPAT\n    if (n_kw != 0) {\n        mp_arg_error_unimpl_kw();\n    }\n    #else\n    (void)n_kw;\n    #endif\n\n    if (n_args == 0) {\n        return mp_const_empty_bytes;\n    }\n\n    if (mp_obj_is_type(args[0], &mp_type_bytes)) {\n        return args[0];\n    }\n\n    if (mp_obj_is_str(args[0])) {\n        if (n_args < 2 || n_args > 3) {\n            goto wrong_args;\n        }\n        GET_STR_DATA_LEN(args[0], str_data, str_len);\n        GET_STR_HASH(args[0], str_hash);\n        if (str_hash == 0) {\n            str_hash = qstr_compute_hash(str_data, str_len);\n        }\n        mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(&mp_type_bytes, NULL, str_len));\n        o->data = str_data;\n        o->hash = str_hash;\n        return MP_OBJ_FROM_PTR(o);\n    }\n\n    if (n_args > 1) {\n        goto wrong_args;\n    }\n\n    if (mp_obj_is_small_int(args[0])) {\n        mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]);\n        if (len < 0) {\n            mp_raise_ValueError(NULL);\n        }\n        vstr_t vstr;\n        vstr_init_len(&vstr, len);\n        memset(vstr.buf, 0, len);\n        return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n    }\n\n    // check if argument has the buffer protocol\n    mp_buffer_info_t bufinfo;\n    if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) {\n        return mp_obj_new_bytes(bufinfo.buf, bufinfo.len);\n    }\n\n    vstr_t vstr;\n    // Try to create array of exact len if initializer len is known\n    mp_obj_t len_in = mp_obj_len_maybe(args[0]);\n    if (len_in == MP_OBJ_NULL) {\n        vstr_init(&vstr, 16);\n    } else {\n        mp_int_t len = MP_OBJ_SMALL_INT_VALUE(len_in);\n        vstr_init(&vstr, len);\n    }\n\n    mp_obj_iter_buf_t iter_buf;\n    mp_obj_t iterable = mp_getiter(args[0], &iter_buf);\n    mp_obj_t item;\n    while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n        mp_int_t val = mp_obj_get_int(item);\n        #if MICROPY_FULL_CHECKS\n        if (val < 0 || val > 255) {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"bytes value out of range\"));\n        }\n        #endif\n        vstr_add_byte(&vstr, val);\n    }\n\n    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);\n\nwrong_args:\n    mp_raise_TypeError(MP_ERROR_TEXT(\"wrong number of arguments\"));\n}\n\n// like strstr but with specified length and allows \\0 bytes\n// TODO replace with something more efficient/standard\nconst byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction) {\n    if (hlen >= nlen) {\n        size_t str_index, str_index_end;\n        if (direction > 0) {\n            str_index = 0;\n            str_index_end = hlen - nlen;\n        } else {\n            str_index = hlen - nlen;\n            str_index_end = 0;\n        }\n        for (;;) {\n            if (memcmp(&haystack[str_index], needle, nlen) == 0) {\n                // found\n                return haystack + str_index;\n            }\n            if (str_index == str_index_end) {\n                // not found\n                break;\n            }\n            str_index += direction;\n        }\n    }\n    return NULL;\n}\n\n// Note: this function is used to check if an object is a str or bytes, which\n// works because both those types use it as their binary_op method.  Revisit\n// mp_obj_is_str_or_bytes if this fact changes.\nmp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    // check for modulo\n    if (op == MP_BINARY_OP_MODULO) {\n        #if MICROPY_PY_BUILTINS_STR_OP_MODULO\n        mp_obj_t *args = &rhs_in;\n        size_t n_args = 1;\n        mp_obj_t dict = MP_OBJ_NULL;\n        if (mp_obj_is_type(rhs_in, &mp_type_tuple)) {\n            // TODO: Support tuple subclasses?\n            mp_obj_tuple_get(rhs_in, &n_args, &args);\n        } else if (mp_obj_is_type(rhs_in, &mp_type_dict)) {\n            dict = rhs_in;\n        }\n        return str_modulo_format(lhs_in, n_args, args, dict);\n        #else\n        return MP_OBJ_NULL;\n        #endif\n    }\n\n    // from now on we need lhs type and data, so extract them\n    const mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in);\n    GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len);\n\n    // check for multiply\n    if (op == MP_BINARY_OP_MULTIPLY) {\n        mp_int_t n;\n        if (!mp_obj_get_int_maybe(rhs_in, &n)) {\n            return MP_OBJ_NULL; // op not supported\n        }\n        if (n <= 0) {\n            if (lhs_type == &mp_type_str) {\n                return MP_OBJ_NEW_QSTR(MP_QSTR_); // empty str\n            } else {\n                return mp_const_empty_bytes;\n            }\n        }\n        vstr_t vstr;\n        vstr_init_len(&vstr, lhs_len * n);\n        mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, vstr.buf);\n        return mp_obj_new_str_from_vstr(lhs_type, &vstr);\n    }\n\n    // From now on all operations allow:\n    //    - str with str\n    //    - bytes with bytes\n    //    - bytes with bytearray\n    //    - bytes with array.array\n    // To do this efficiently we use the buffer protocol to extract the raw\n    // data for the rhs, but only if the lhs is a bytes object.\n    //\n    // NOTE: CPython does not allow comparison between bytes ard array.array\n    // (even if the array is of type 'b'), even though it allows addition of\n    // such types.  We are not compatible with this (we do allow comparison\n    // of bytes with anything that has the buffer protocol).  It would be\n    // easy to \"fix\" this with a bit of extra logic below, but it costs code\n    // size and execution time so we don't.\n\n    const byte *rhs_data;\n    size_t rhs_len;\n    if (lhs_type == mp_obj_get_type(rhs_in)) {\n        GET_STR_DATA_LEN(rhs_in, rhs_data_, rhs_len_);\n        rhs_data = rhs_data_;\n        rhs_len = rhs_len_;\n    } else if (lhs_type == &mp_type_bytes) {\n        mp_buffer_info_t bufinfo;\n        if (!mp_get_buffer(rhs_in, &bufinfo, MP_BUFFER_READ)) {\n            return MP_OBJ_NULL; // op not supported\n        }\n        rhs_data = bufinfo.buf;\n        rhs_len = bufinfo.len;\n    } else {\n        // LHS is str and RHS has an incompatible type\n        // (except if operation is EQUAL, but that's handled by mp_obj_equal)\n        bad_implicit_conversion(rhs_in);\n    }\n\n    switch (op) {\n        case MP_BINARY_OP_ADD:\n        case MP_BINARY_OP_INPLACE_ADD: {\n            if (lhs_len == 0 && mp_obj_get_type(rhs_in) == lhs_type) {\n                return rhs_in;\n            }\n            if (rhs_len == 0) {\n                return lhs_in;\n            }\n\n            vstr_t vstr;\n            vstr_init_len(&vstr, lhs_len + rhs_len);\n            memcpy(vstr.buf, lhs_data, lhs_len);\n            memcpy(vstr.buf + lhs_len, rhs_data, rhs_len);\n            return mp_obj_new_str_from_vstr(lhs_type, &vstr);\n        }\n\n        case MP_BINARY_OP_CONTAINS:\n            return mp_obj_new_bool(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL);\n\n        // case MP_BINARY_OP_NOT_EQUAL: // This is never passed here\n        case MP_BINARY_OP_EQUAL: // This will be passed only for bytes, str is dealt with in mp_obj_equal()\n        case MP_BINARY_OP_LESS:\n        case MP_BINARY_OP_LESS_EQUAL:\n        case MP_BINARY_OP_MORE:\n        case MP_BINARY_OP_MORE_EQUAL:\n            return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len));\n\n        default:\n            return MP_OBJ_NULL; // op not supported\n    }\n}\n\n#if !MICROPY_PY_BUILTINS_STR_UNICODE\n// objstrunicode defines own version\nconst byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len,\n    mp_obj_t index, bool is_slice) {\n    size_t index_val = mp_get_index(type, self_len, index, is_slice);\n    return self_data + index_val;\n}\n#endif\n\n// This is used for both bytes and 8-bit strings. This is not used for unicode strings.\nSTATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {\n    const mp_obj_type_t *type = mp_obj_get_type(self_in);\n    GET_STR_DATA_LEN(self_in, self_data, self_len);\n    if (value == MP_OBJ_SENTINEL) {\n        // load\n        #if MICROPY_PY_BUILTINS_SLICE\n        if (mp_obj_is_type(index, &mp_type_slice)) {\n            mp_bound_slice_t slice;\n            if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) {\n                mp_raise_NotImplementedError(MP_ERROR_TEXT(\"only slices with step=1 (aka None) are supported\"));\n            }\n            return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start);\n        }\n        #endif\n        size_t index_val = mp_get_index(type, self_len, index, false);\n        // If we have unicode enabled the type will always be bytes, so take the short cut.\n        if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) {\n            return MP_OBJ_NEW_SMALL_INT(self_data[index_val]);\n        } else {\n            return mp_obj_new_str_via_qstr((char *)&self_data[index_val], 1);\n        }\n    } else {\n        return MP_OBJ_NULL; // op not supported\n    }\n}\n\nSTATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {\n    mp_check_self(mp_obj_is_str_or_bytes(self_in));\n    const mp_obj_type_t *self_type = mp_obj_get_type(self_in);\n\n    // get separation string\n    GET_STR_DATA_LEN(self_in, sep_str, sep_len);\n\n    // process args\n    size_t seq_len;\n    mp_obj_t *seq_items;\n\n    if (!mp_obj_is_type(arg, &mp_type_list) && !mp_obj_is_type(arg, &mp_type_tuple)) {\n        // arg is not a list nor a tuple, try to convert it to a list\n        // TODO: Try to optimize?\n        arg = mp_type_list.make_new(&mp_type_list, 1, 0, &arg);\n    }\n    mp_obj_get_array(arg, &seq_len, &seq_items);\n\n    // count required length\n    size_t required_len = 0;\n    for (size_t i = 0; i < seq_len; i++) {\n        if (mp_obj_get_type(seq_items[i]) != self_type) {\n            mp_raise_TypeError(\n                MP_ERROR_TEXT(\"join expects a list of str/bytes objects consistent with self object\"));\n        }\n        if (i > 0) {\n            required_len += sep_len;\n        }\n        GET_STR_LEN(seq_items[i], l);\n        required_len += l;\n    }\n\n    // make joined string\n    vstr_t vstr;\n    vstr_init_len(&vstr, required_len);\n    byte *data = (byte *)vstr.buf;\n    for (size_t i = 0; i < seq_len; i++) {\n        if (i > 0) {\n            memcpy(data, sep_str, sep_len);\n            data += sep_len;\n        }\n        GET_STR_DATA_LEN(seq_items[i], s, l);\n        memcpy(data, s, l);\n        data += l;\n    }\n\n    // return joined string\n    return mp_obj_new_str_from_vstr(self_type, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);\n\nmp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) {\n    const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);\n    mp_int_t splits = -1;\n    mp_obj_t sep = mp_const_none;\n    if (n_args > 1) {\n        sep = args[1];\n        if (n_args > 2) {\n            splits = mp_obj_get_int(args[2]);\n        }\n    }\n\n    mp_obj_t res = mp_obj_new_list(0, NULL);\n    GET_STR_DATA_LEN(args[0], s, len);\n    const byte *top = s + len;\n\n    if (sep == mp_const_none) {\n        // sep not given, so separate on whitespace\n\n        // Initial whitespace is not counted as split, so we pre-do it\n        while (s < top && unichar_isspace(*s)) {\n            s++;\n        }\n        while (s < top && splits != 0) {\n            const byte *start = s;\n            while (s < top && !unichar_isspace(*s)) {\n                s++;\n            }\n            mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start));\n            if (s >= top) {\n                break;\n            }\n            while (s < top && unichar_isspace(*s)) {\n                s++;\n            }\n            if (splits > 0) {\n                splits--;\n            }\n        }\n\n        if (s < top) {\n            mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, s, top - s));\n        }\n\n    } else {\n        // sep given\n        if (mp_obj_get_type(sep) != self_type) {\n            bad_implicit_conversion(sep);\n        }\n\n        size_t sep_len;\n        const char *sep_str = mp_obj_str_get_data(sep, &sep_len);\n\n        if (sep_len == 0) {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"empty separator\"));\n        }\n\n        for (;;) {\n            const byte *start = s;\n            for (;;) {\n                if (splits == 0 || s + sep_len > top) {\n                    s = top;\n                    break;\n                } else if (memcmp(s, sep_str, sep_len) == 0) {\n                    break;\n                }\n                s++;\n            }\n            mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start));\n            if (s >= top) {\n                break;\n            }\n            s += sep_len;\n            if (splits > 0) {\n                splits--;\n            }\n        }\n    }\n\n    return res;\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, mp_obj_str_split);\n\n#if MICROPY_PY_BUILTINS_STR_SPLITLINES\nSTATIC mp_obj_t str_splitlines(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n    enum { ARG_keepends };\n    static const mp_arg_t allowed_args[] = {\n        { MP_QSTR_keepends, MP_ARG_BOOL, {.u_bool = false} },\n    };\n\n    // parse args\n    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n\n    const mp_obj_type_t *self_type = mp_obj_get_type(pos_args[0]);\n    mp_obj_t res = mp_obj_new_list(0, NULL);\n\n    GET_STR_DATA_LEN(pos_args[0], s, len);\n    const byte *top = s + len;\n\n    while (s < top) {\n        const byte *start = s;\n        size_t match = 0;\n        while (s < top) {\n            if (*s == '\\n') {\n                match = 1;\n                break;\n            } else if (*s == '\\r') {\n                if (s[1] == '\\n') {\n                    match = 2;\n                } else {\n                    match = 1;\n                }\n                break;\n            }\n            s++;\n        }\n        size_t sub_len = s - start;\n        if (args[ARG_keepends].u_bool) {\n            sub_len += match;\n        }\n        mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, sub_len));\n        s += match;\n    }\n\n    return res;\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(str_splitlines_obj, 1, str_splitlines);\n#endif\n\nSTATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) {\n    if (n_args < 3) {\n        // If we don't have split limit, it doesn't matter from which side\n        // we split.\n        return mp_obj_str_split(n_args, args);\n    }\n    const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);\n    mp_obj_t sep = args[1];\n    GET_STR_DATA_LEN(args[0], s, len);\n\n    mp_int_t splits = mp_obj_get_int(args[2]);\n    if (splits < 0) {\n        // Negative limit means no limit, so delegate to split().\n        return mp_obj_str_split(n_args, args);\n    }\n\n    mp_int_t org_splits = splits;\n    // Preallocate list to the max expected # of elements, as we\n    // will fill it from the end.\n    mp_obj_list_t *res = MP_OBJ_TO_PTR(mp_obj_new_list(splits + 1, NULL));\n    mp_int_t idx = splits;\n\n    if (sep == mp_const_none) {\n        mp_raise_NotImplementedError(MP_ERROR_TEXT(\"rsplit(None,n)\"));\n    } else {\n        size_t sep_len;\n        const char *sep_str = mp_obj_str_get_data(sep, &sep_len);\n\n        if (sep_len == 0) {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"empty separator\"));\n        }\n\n        const byte *beg = s;\n        const byte *last = s + len;\n        for (;;) {\n            s = last - sep_len;\n            for (;;) {\n                if (splits == 0 || s < beg) {\n                    break;\n                } else if (memcmp(s, sep_str, sep_len) == 0) {\n                    break;\n                }\n                s--;\n            }\n            if (s < beg || splits == 0) {\n                res->items[idx] = mp_obj_new_str_of_type(self_type, beg, last - beg);\n                break;\n            }\n            res->items[idx--] = mp_obj_new_str_of_type(self_type, s + sep_len, last - s - sep_len);\n            last = s;\n            splits--;\n        }\n        if (idx != 0) {\n            // We split less parts than split limit, now go cleanup surplus\n            size_t used = org_splits + 1 - idx;\n            memmove(res->items, &res->items[idx], used * sizeof(mp_obj_t));\n            mp_seq_clear(res->items, used, res->alloc, sizeof(*res->items));\n            res->len = used;\n        }\n    }\n\n    return MP_OBJ_FROM_PTR(res);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit);\n\nSTATIC mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, bool is_index) {\n    const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);\n    mp_check_self(mp_obj_is_str_or_bytes(args[0]));\n\n    // check argument type\n    if (mp_obj_get_type(args[1]) != self_type) {\n        bad_implicit_conversion(args[1]);\n    }\n\n    GET_STR_DATA_LEN(args[0], haystack, haystack_len);\n    GET_STR_DATA_LEN(args[1], needle, needle_len);\n\n    const byte *start = haystack;\n    const byte *end = haystack + haystack_len;\n    if (n_args >= 3 && args[2] != mp_const_none) {\n        start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true);\n    }\n    if (n_args >= 4 && args[3] != mp_const_none) {\n        end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true);\n    }\n\n    if (end < start) {\n        goto out_error;\n    }\n\n    const byte *p = find_subbytes(start, end - start, needle, needle_len, direction);\n    if (p == NULL) {\n    out_error:\n        // not found\n        if (is_index) {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"substring not found\"));\n        } else {\n            return MP_OBJ_NEW_SMALL_INT(-1);\n        }\n    } else {\n        // found\n        #if MICROPY_PY_BUILTINS_STR_UNICODE\n        if (self_type == &mp_type_str) {\n            return MP_OBJ_NEW_SMALL_INT(utf8_ptr_to_index(haystack, p));\n        }\n        #endif\n        return MP_OBJ_NEW_SMALL_INT(p - haystack);\n    }\n}\n\nSTATIC mp_obj_t str_find(size_t n_args, const mp_obj_t *args) {\n    return str_finder(n_args, args, 1, false);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find);\n\nSTATIC mp_obj_t str_rfind(size_t n_args, const mp_obj_t *args) {\n    return str_finder(n_args, args, -1, false);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind);\n\nSTATIC mp_obj_t str_index(size_t n_args, const mp_obj_t *args) {\n    return str_finder(n_args, args, 1, true);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index);\n\nSTATIC mp_obj_t str_rindex(size_t n_args, const mp_obj_t *args) {\n    return str_finder(n_args, args, -1, true);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex);\n\n// TODO: (Much) more variety in args\nSTATIC mp_obj_t str_startswith(size_t n_args, const mp_obj_t *args) {\n    const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);\n    GET_STR_DATA_LEN(args[0], str, str_len);\n    size_t prefix_len;\n    const char *prefix = mp_obj_str_get_data(args[1], &prefix_len);\n    const byte *start = str;\n    if (n_args > 2) {\n        start = str_index_to_ptr(self_type, str, str_len, args[2], true);\n    }\n    if (prefix_len + (start - str) > str_len) {\n        return mp_const_false;\n    }\n    return mp_obj_new_bool(memcmp(start, prefix, prefix_len) == 0);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith);\n\nSTATIC mp_obj_t str_endswith(size_t n_args, const mp_obj_t *args) {\n    GET_STR_DATA_LEN(args[0], str, str_len);\n    size_t suffix_len;\n    const char *suffix = mp_obj_str_get_data(args[1], &suffix_len);\n    if (n_args > 2) {\n        mp_raise_NotImplementedError(MP_ERROR_TEXT(\"start/end indices\"));\n    }\n\n    if (suffix_len > str_len) {\n        return mp_const_false;\n    }\n    return mp_obj_new_bool(memcmp(str + (str_len - suffix_len), suffix, suffix_len) == 0);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith);\n\nenum { LSTRIP, RSTRIP, STRIP };\n\nSTATIC mp_obj_t str_uni_strip(int type, size_t n_args, const mp_obj_t *args) {\n    mp_check_self(mp_obj_is_str_or_bytes(args[0]));\n    const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);\n\n    const byte *chars_to_del;\n    uint chars_to_del_len;\n    static const byte whitespace[] = \" \\t\\n\\r\\v\\f\";\n\n    if (n_args == 1) {\n        chars_to_del = whitespace;\n        chars_to_del_len = sizeof(whitespace) - 1;\n    } else {\n        if (mp_obj_get_type(args[1]) != self_type) {\n            bad_implicit_conversion(args[1]);\n        }\n        GET_STR_DATA_LEN(args[1], s, l);\n        chars_to_del = s;\n        chars_to_del_len = l;\n    }\n\n    GET_STR_DATA_LEN(args[0], orig_str, orig_str_len);\n\n    size_t first_good_char_pos = 0;\n    bool first_good_char_pos_set = false;\n    size_t last_good_char_pos = 0;\n    size_t i = 0;\n    int delta = 1;\n    if (type == RSTRIP) {\n        i = orig_str_len - 1;\n        delta = -1;\n    }\n    for (size_t len = orig_str_len; len > 0; len--) {\n        if (find_subbytes(chars_to_del, chars_to_del_len, &orig_str[i], 1, 1) == NULL) {\n            if (!first_good_char_pos_set) {\n                first_good_char_pos_set = true;\n                first_good_char_pos = i;\n                if (type == LSTRIP) {\n                    last_good_char_pos = orig_str_len - 1;\n                    break;\n                } else if (type == RSTRIP) {\n                    first_good_char_pos = 0;\n                    last_good_char_pos = i;\n                    break;\n                }\n            }\n            last_good_char_pos = i;\n        }\n        i += delta;\n    }\n\n    if (!first_good_char_pos_set) {\n        // string is all whitespace, return ''\n        if (self_type == &mp_type_str) {\n            return MP_OBJ_NEW_QSTR(MP_QSTR_);\n        } else {\n            return mp_const_empty_bytes;\n        }\n    }\n\n    assert(last_good_char_pos >= first_good_char_pos);\n    // +1 to accommodate the last character\n    size_t stripped_len = last_good_char_pos - first_good_char_pos + 1;\n    if (stripped_len == orig_str_len) {\n        // If nothing was stripped, don't bother to dup original string\n        // TODO: watch out for this case when we'll get to bytearray.strip()\n        assert(first_good_char_pos == 0);\n        return args[0];\n    }\n    return mp_obj_new_str_of_type(self_type, orig_str + first_good_char_pos, stripped_len);\n}\n\nSTATIC mp_obj_t str_strip(size_t n_args, const mp_obj_t *args) {\n    return str_uni_strip(STRIP, n_args, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);\n\nSTATIC mp_obj_t str_lstrip(size_t n_args, const mp_obj_t *args) {\n    return str_uni_strip(LSTRIP, n_args, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip);\n\nSTATIC mp_obj_t str_rstrip(size_t n_args, const mp_obj_t *args) {\n    return str_uni_strip(RSTRIP, n_args, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip);\n\n#if MICROPY_PY_BUILTINS_STR_CENTER\nSTATIC mp_obj_t str_center(mp_obj_t str_in, mp_obj_t width_in) {\n    GET_STR_DATA_LEN(str_in, str, str_len);\n    mp_uint_t width = mp_obj_get_int(width_in);\n    if (str_len >= width) {\n        return str_in;\n    }\n\n    vstr_t vstr;\n    vstr_init_len(&vstr, width);\n    memset(vstr.buf, ' ', width);\n    int left = (width - str_len) / 2;\n    memcpy(vstr.buf + left, str, str_len);\n    return mp_obj_new_str_from_vstr(mp_obj_get_type(str_in), &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(str_center_obj, str_center);\n#endif\n\n// Takes an int arg, but only parses unsigned numbers, and only changes\n// *num if at least one digit was parsed.\nSTATIC const char *str_to_int(const char *str, const char *top, int *num) {\n    if (str < top && '0' <= *str && *str <= '9') {\n        *num = 0;\n        do {\n            *num = *num * 10 + (*str - '0');\n            str++;\n        }\n        while (str < top && '0' <= *str && *str <= '9');\n    }\n    return str;\n}\n\nSTATIC bool isalignment(char ch) {\n    return ch && strchr(\"<>=^\", ch) != NULL;\n}\n\nSTATIC bool istype(char ch) {\n    return ch && strchr(\"bcdeEfFgGnosxX%\", ch) != NULL;\n}\n\nSTATIC bool arg_looks_integer(mp_obj_t arg) {\n    return mp_obj_is_bool(arg) || mp_obj_is_int(arg);\n}\n\nSTATIC bool arg_looks_numeric(mp_obj_t arg) {\n    return arg_looks_integer(arg)\n           #if MICROPY_PY_BUILTINS_FLOAT\n           || mp_obj_is_float(arg)\n           #endif\n    ;\n}\n\n#if MICROPY_PY_BUILTINS_STR_OP_MODULO\nSTATIC mp_obj_t arg_as_int(mp_obj_t arg) {\n    #if MICROPY_PY_BUILTINS_FLOAT\n    if (mp_obj_is_float(arg)) {\n        return mp_obj_new_int_from_float(mp_obj_float_get(arg));\n    }\n    #endif\n    return arg;\n}\n#endif\n\n#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\nSTATIC NORETURN void terse_str_format_value_error(void) {\n    mp_raise_ValueError(MP_ERROR_TEXT(\"bad format string\"));\n}\n#else\n// define to nothing to improve coverage\n#define terse_str_format_value_error()\n#endif\n\nSTATIC 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) {\n    vstr_t vstr;\n    mp_print_t print;\n    vstr_init_print(&vstr, 16, &print);\n\n    for (; str < top; str++) {\n        if (*str == '}') {\n            str++;\n            if (str < top && *str == '}') {\n                vstr_add_byte(&vstr, '}');\n                continue;\n            }\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            terse_str_format_value_error();\n            #else\n            mp_raise_ValueError(MP_ERROR_TEXT(\"single '}' encountered in format string\"));\n            #endif\n        }\n        if (*str != '{') {\n            vstr_add_byte(&vstr, *str);\n            continue;\n        }\n\n        str++;\n        if (str < top && *str == '{') {\n            vstr_add_byte(&vstr, '{');\n            continue;\n        }\n\n        // replacement_field ::=  \"{\" [field_name] [\"!\" conversion] [\":\" format_spec] \"}\"\n\n        const char *field_name = NULL;\n        const char *field_name_top = NULL;\n        char conversion = '\\0';\n        const char *format_spec = NULL;\n\n        if (str < top && *str != '}' && *str != '!' && *str != ':') {\n            field_name = (const char *)str;\n            while (str < top && *str != '}' && *str != '!' && *str != ':') {\n                ++str;\n            }\n            field_name_top = (const char *)str;\n        }\n\n        // conversion ::=  \"r\" | \"s\"\n\n        if (str < top && *str == '!') {\n            str++;\n            if (str < top && (*str == 'r' || *str == 's')) {\n                conversion = *str++;\n            } else {\n                #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                terse_str_format_value_error();\n                #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL\n                mp_raise_ValueError(MP_ERROR_TEXT(\"bad conversion specifier\"));\n                #else\n                if (str >= top) {\n                    mp_raise_ValueError(\n                        MP_ERROR_TEXT(\"end of format while looking for conversion specifier\"));\n                } else {\n                    mp_raise_msg_varg(&mp_type_ValueError,\n                        MP_ERROR_TEXT(\"unknown conversion specifier %c\"), *str);\n                }\n                #endif\n            }\n        }\n\n        if (str < top && *str == ':') {\n            str++;\n            // {:} is the same as {}, which is the same as {!s}\n            // This makes a difference when passing in a True or False\n            // '{}'.format(True) returns 'True'\n            // '{:d}'.format(True) returns '1'\n            // So we treat {:} as {} and this later gets treated to be {!s}\n            if (*str != '}') {\n                format_spec = str;\n                for (int nest = 1; str < top;) {\n                    if (*str == '{') {\n                        ++nest;\n                    } else if (*str == '}') {\n                        if (--nest == 0) {\n                            break;\n                        }\n                    }\n                    ++str;\n                }\n            }\n        }\n        if (str >= top) {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            terse_str_format_value_error();\n            #else\n            mp_raise_ValueError(MP_ERROR_TEXT(\"unmatched '{' in format\"));\n            #endif\n        }\n        if (*str != '}') {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            terse_str_format_value_error();\n            #else\n            mp_raise_ValueError(MP_ERROR_TEXT(\"expected ':' after format specifier\"));\n            #endif\n        }\n\n        mp_obj_t arg = mp_const_none;\n\n        if (field_name) {\n            int index = 0;\n            if (MP_LIKELY(unichar_isdigit(*field_name))) {\n                if (*arg_i > 0) {\n                    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                    terse_str_format_value_error();\n                    #else\n                    mp_raise_ValueError(\n                        MP_ERROR_TEXT(\"can't switch from automatic field numbering to manual field specification\"));\n                    #endif\n                }\n                field_name = str_to_int(field_name, field_name_top, &index);\n                if ((uint)index >= n_args - 1) {\n                    mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT(\"tuple index out of range\"));\n                }\n                arg = args[index + 1];\n                *arg_i = -1;\n            } else {\n                const char *lookup;\n                for (lookup = field_name; lookup < field_name_top && *lookup != '.' && *lookup != '['; lookup++) {;\n                }\n                mp_obj_t field_q = mp_obj_new_str_via_qstr(field_name, lookup - field_name); // should it be via qstr?\n                field_name = lookup;\n                mp_map_elem_t *key_elem = mp_map_lookup(kwargs, field_q, MP_MAP_LOOKUP);\n                if (key_elem == NULL) {\n                    nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, field_q));\n                }\n                arg = key_elem->value;\n            }\n            if (field_name < field_name_top) {\n                mp_raise_NotImplementedError(MP_ERROR_TEXT(\"attributes not supported yet\"));\n            }\n        } else {\n            if (*arg_i < 0) {\n                #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                terse_str_format_value_error();\n                #else\n                mp_raise_ValueError(\n                    MP_ERROR_TEXT(\"can't switch from manual field specification to automatic field numbering\"));\n                #endif\n            }\n            if ((uint)*arg_i >= n_args - 1) {\n                mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT(\"tuple index out of range\"));\n            }\n            arg = args[(*arg_i) + 1];\n            (*arg_i)++;\n        }\n        if (!format_spec && !conversion) {\n            conversion = 's';\n        }\n        if (conversion) {\n            mp_print_kind_t print_kind;\n            if (conversion == 's') {\n                print_kind = PRINT_STR;\n            } else {\n                assert(conversion == 'r');\n                print_kind = PRINT_REPR;\n            }\n            vstr_t arg_vstr;\n            mp_print_t arg_print;\n            vstr_init_print(&arg_vstr, 16, &arg_print);\n            mp_obj_print_helper(&arg_print, arg, print_kind);\n            arg = mp_obj_new_str_from_vstr(&mp_type_str, &arg_vstr);\n        }\n\n        char fill = '\\0';\n        char align = '\\0';\n        int width = -1;\n        int precision = -1;\n        char type = '\\0';\n        int flags = 0;\n\n        if (format_spec) {\n            // The format specifier (from http://docs.python.org/2/library/string.html#formatspec)\n            //\n            // [[fill]align][sign][#][0][width][,][.precision][type]\n            // fill        ::=  <any character>\n            // align       ::=  \"<\" | \">\" | \"=\" | \"^\"\n            // sign        ::=  \"+\" | \"-\" | \" \"\n            // width       ::=  integer\n            // precision   ::=  integer\n            // type        ::=  \"b\" | \"c\" | \"d\" | \"e\" | \"E\" | \"f\" | \"F\" | \"g\" | \"G\" | \"n\" | \"o\" | \"s\" | \"x\" | \"X\" | \"%\"\n\n            // recursively call the formatter to format any nested specifiers\n            MP_STACK_CHECK();\n            vstr_t format_spec_vstr = mp_obj_str_format_helper(format_spec, str, arg_i, n_args, args, kwargs);\n            const char *s = vstr_null_terminated_str(&format_spec_vstr);\n            const char *stop = s + format_spec_vstr.len;\n            if (isalignment(*s)) {\n                align = *s++;\n            } else if (*s && isalignment(s[1])) {\n                fill = *s++;\n                align = *s++;\n            }\n            if (*s == '+' || *s == '-' || *s == ' ') {\n                if (*s == '+') {\n                    flags |= PF_FLAG_SHOW_SIGN;\n                } else if (*s == ' ') {\n                    flags |= PF_FLAG_SPACE_SIGN;\n                }\n                s++;\n            }\n            if (*s == '#') {\n                flags |= PF_FLAG_SHOW_PREFIX;\n                s++;\n            }\n            if (*s == '0') {\n                if (!align) {\n                    align = '=';\n                }\n                if (!fill) {\n                    fill = '0';\n                }\n            }\n            s = str_to_int(s, stop, &width);\n            if (*s == ',') {\n                flags |= PF_FLAG_SHOW_COMMA;\n                s++;\n            }\n            if (*s == '.') {\n                s++;\n                s = str_to_int(s, stop, &precision);\n            }\n            if (istype(*s)) {\n                type = *s++;\n            }\n            if (*s) {\n                #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                terse_str_format_value_error();\n                #else\n                mp_raise_ValueError(MP_ERROR_TEXT(\"invalid format specifier\"));\n                #endif\n            }\n            vstr_clear(&format_spec_vstr);\n        }\n        if (!align) {\n            if (arg_looks_numeric(arg)) {\n                align = '>';\n            } else {\n                align = '<';\n            }\n        }\n        if (!fill) {\n            fill = ' ';\n        }\n\n        if (flags & (PF_FLAG_SHOW_SIGN | PF_FLAG_SPACE_SIGN)) {\n            if (type == 's') {\n                #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                terse_str_format_value_error();\n                #else\n                mp_raise_ValueError(MP_ERROR_TEXT(\"sign not allowed in string format specifier\"));\n                #endif\n            }\n            if (type == 'c') {\n                #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                terse_str_format_value_error();\n                #else\n                mp_raise_ValueError(\n                    MP_ERROR_TEXT(\"sign not allowed with integer format specifier 'c'\"));\n                #endif\n            }\n        }\n\n        switch (align) {\n            case '<':\n                flags |= PF_FLAG_LEFT_ADJUST;\n                break;\n            case '=':\n                flags |= PF_FLAG_PAD_AFTER_SIGN;\n                break;\n            case '^':\n                flags |= PF_FLAG_CENTER_ADJUST;\n                break;\n        }\n\n        if (arg_looks_integer(arg)) {\n            switch (type) {\n                case 'b':\n                    mp_print_mp_int(&print, arg, 2, 'a', flags, fill, width, 0);\n                    continue;\n\n                case 'c': {\n                    char ch = mp_obj_get_int(arg);\n                    mp_print_strn(&print, &ch, 1, flags, fill, width);\n                    continue;\n                }\n\n                case '\\0':  // No explicit format type implies 'd'\n                case 'n':   // I don't think we support locales in uPy so use 'd'\n                case 'd':\n                    mp_print_mp_int(&print, arg, 10, 'a', flags, fill, width, 0);\n                    continue;\n\n                case 'o':\n                    if (flags & PF_FLAG_SHOW_PREFIX) {\n                        flags |= PF_FLAG_SHOW_OCTAL_LETTER;\n                    }\n\n                    mp_print_mp_int(&print, arg, 8, 'a', flags, fill, width, 0);\n                    continue;\n\n                case 'X':\n                case 'x':\n                    mp_print_mp_int(&print, arg, 16, type - ('X' - 'A'), flags, fill, width, 0);\n                    continue;\n\n                case 'e':\n                case 'E':\n                case 'f':\n                case 'F':\n                case 'g':\n                case 'G':\n                case '%':\n                    // The floating point formatters all work with anything that\n                    // looks like an integer\n                    break;\n\n                default:\n                    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                    terse_str_format_value_error();\n                    #else\n                    mp_raise_msg_varg(&mp_type_ValueError,\n                        MP_ERROR_TEXT(\"unknown format code '%c' for object of type '%s'\"),\n                        type, mp_obj_get_type_str(arg));\n                    #endif\n            }\n        }\n\n        // NOTE: no else here. We need the e, f, g etc formats for integer\n        //       arguments (from above if) to take this if.\n        if (arg_looks_numeric(arg)) {\n            if (!type) {\n\n                // Even though the docs say that an unspecified type is the same\n                // as 'g', there is one subtle difference, when the exponent\n                // is one less than the precision.\n                //\n                // '{:10.1}'.format(0.0) ==> '0e+00'\n                // '{:10.1g}'.format(0.0) ==> '0'\n                //\n                // TODO: Figure out how to deal with this.\n                //\n                // A proper solution would involve adding a special flag\n                // or something to format_float, and create a format_double\n                // to deal with doubles. In order to fix this when using\n                // sprintf, we'd need to use the e format and tweak the\n                // returned result to strip trailing zeros like the g format\n                // does.\n                //\n                // {:10.3} and {:10.2e} with 1.23e2 both produce 1.23e+02\n                // but with 1.e2 you get 1e+02 and 1.00e+02\n                //\n                // Stripping the trailing 0's (like g) does would make the\n                // e format give us the right format.\n                //\n                // CPython sources say:\n                //   Omitted type specifier.  Behaves in the same way as repr(x)\n                //   and str(x) if no precision is given, else like 'g', but with\n                //   at least one digit after the decimal point. */\n\n                type = 'g';\n            }\n            if (type == 'n') {\n                type = 'g';\n            }\n\n            switch (type) {\n                #if MICROPY_PY_BUILTINS_FLOAT\n                case 'e':\n                case 'E':\n                case 'f':\n                case 'F':\n                case 'g':\n                case 'G':\n                    mp_print_float(&print, mp_obj_get_float(arg), type, flags, fill, width, precision);\n                    break;\n\n                case '%':\n                    flags |= PF_FLAG_ADD_PERCENT;\n                    #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n                    #define F100 100.0F\n                    #else\n                    #define F100 100.0\n                    #endif\n                    mp_print_float(&print, mp_obj_get_float(arg) * F100, 'f', flags, fill, width, precision);\n#undef F100\n                    break;\n                #endif\n\n                default:\n                    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                    terse_str_format_value_error();\n                    #else\n                    mp_raise_msg_varg(&mp_type_ValueError,\n                        MP_ERROR_TEXT(\"unknown format code '%c' for object of type '%s'\"),\n                        type, mp_obj_get_type_str(arg));\n                    #endif\n            }\n        } else {\n            // arg doesn't look like a number\n\n            if (align == '=') {\n                #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                terse_str_format_value_error();\n                #else\n                mp_raise_ValueError(\n                    MP_ERROR_TEXT(\"'=' alignment not allowed in string format specifier\"));\n                #endif\n            }\n\n            switch (type) {\n                case '\\0': // no explicit format type implies 's'\n                case 's': {\n                    size_t slen;\n                    const char *s = mp_obj_str_get_data(arg, &slen);\n                    if (precision < 0) {\n                        precision = slen;\n                    }\n                    if (slen > (size_t)precision) {\n                        slen = precision;\n                    }\n                    mp_print_strn(&print, s, slen, flags, fill, width);\n                    break;\n                }\n\n                default:\n                    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                    terse_str_format_value_error();\n                    #else\n                    mp_raise_msg_varg(&mp_type_ValueError,\n                        MP_ERROR_TEXT(\"unknown format code '%c' for object of type '%s'\"),\n                        type, mp_obj_get_type_str(arg));\n                    #endif\n            }\n        }\n    }\n\n    return vstr;\n}\n\nmp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {\n    mp_check_self(mp_obj_is_str_or_bytes(args[0]));\n\n    GET_STR_DATA_LEN(args[0], str, len);\n    int arg_i = 0;\n    vstr_t vstr = mp_obj_str_format_helper((const char *)str, (const char *)str + len, &arg_i, n_args, args, kwargs);\n    return mp_obj_new_str_from_vstr(mp_obj_get_type(args[0]), &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_KW(str_format_obj, 1, mp_obj_str_format);\n\n#if MICROPY_PY_BUILTINS_STR_OP_MODULO\nSTATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict) {\n    mp_check_self(mp_obj_is_str_or_bytes(pattern));\n\n    GET_STR_DATA_LEN(pattern, str, len);\n    #if MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_TERSE\n    const byte *start_str = str;\n    #endif\n    bool is_bytes = mp_obj_is_type(pattern, &mp_type_bytes);\n    size_t arg_i = 0;\n    vstr_t vstr;\n    mp_print_t print;\n    vstr_init_print(&vstr, 16, &print);\n\n    for (const byte *top = str + len; str < top; str++) {\n        mp_obj_t arg = MP_OBJ_NULL;\n        if (*str != '%') {\n            vstr_add_byte(&vstr, *str);\n            continue;\n        }\n        if (++str >= top) {\n            goto incomplete_format;\n        }\n        if (*str == '%') {\n            vstr_add_byte(&vstr, '%');\n            continue;\n        }\n\n        // Dictionary value lookup\n        if (*str == '(') {\n            if (dict == MP_OBJ_NULL) {\n                mp_raise_TypeError(MP_ERROR_TEXT(\"format needs a dict\"));\n            }\n            arg_i = 1; // we used up the single dict argument\n            const byte *key = ++str;\n            while (*str != ')') {\n                if (str >= top) {\n                    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                    terse_str_format_value_error();\n                    #else\n                    mp_raise_ValueError(MP_ERROR_TEXT(\"incomplete format key\"));\n                    #endif\n                }\n                ++str;\n            }\n            mp_obj_t k_obj = mp_obj_new_str_via_qstr((const char *)key, str - key);\n            arg = mp_obj_dict_get(dict, k_obj);\n            str++;\n        }\n\n        int flags = 0;\n        char fill = ' ';\n        int alt = 0;\n        while (str < top) {\n            if (*str == '-') {\n                flags |= PF_FLAG_LEFT_ADJUST;\n            } else if (*str == '+') {\n                flags |= PF_FLAG_SHOW_SIGN;\n            } else if (*str == ' ') {\n                flags |= PF_FLAG_SPACE_SIGN;\n            } else if (*str == '#') {\n                alt = PF_FLAG_SHOW_PREFIX;\n            } else if (*str == '0') {\n                flags |= PF_FLAG_PAD_AFTER_SIGN;\n                fill = '0';\n            } else {\n                break;\n            }\n            str++;\n        }\n        // parse width, if it exists\n        int width = 0;\n        if (str < top) {\n            if (*str == '*') {\n                if (arg_i >= n_args) {\n                    goto not_enough_args;\n                }\n                width = mp_obj_get_int(args[arg_i++]);\n                str++;\n            } else {\n                str = (const byte *)str_to_int((const char *)str, (const char *)top, &width);\n            }\n        }\n        int prec = -1;\n        if (str < top && *str == '.') {\n            if (++str < top) {\n                if (*str == '*') {\n                    if (arg_i >= n_args) {\n                        goto not_enough_args;\n                    }\n                    prec = mp_obj_get_int(args[arg_i++]);\n                    str++;\n                } else {\n                    prec = 0;\n                    str = (const byte *)str_to_int((const char *)str, (const char *)top, &prec);\n                }\n            }\n        }\n\n        if (str >= top) {\n        incomplete_format:\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            terse_str_format_value_error();\n            #else\n            mp_raise_ValueError(MP_ERROR_TEXT(\"incomplete format\"));\n            #endif\n        }\n\n        // Tuple value lookup\n        if (arg == MP_OBJ_NULL) {\n            if (arg_i >= n_args) {\n            not_enough_args:\n                mp_raise_TypeError(MP_ERROR_TEXT(\"format string needs more arguments\"));\n            }\n            arg = args[arg_i++];\n        }\n        switch (*str) {\n            case 'c':\n                if (mp_obj_is_str(arg)) {\n                    size_t slen;\n                    const char *s = mp_obj_str_get_data(arg, &slen);\n                    if (slen != 1) {\n                        mp_raise_TypeError(MP_ERROR_TEXT(\"%c needs int or char\"));\n                    }\n                    mp_print_strn(&print, s, 1, flags, ' ', width);\n                } else if (arg_looks_integer(arg)) {\n                    char ch = mp_obj_get_int(arg);\n                    mp_print_strn(&print, &ch, 1, flags, ' ', width);\n                } else {\n                    mp_raise_TypeError(MP_ERROR_TEXT(\"integer needed\"));\n                }\n                break;\n\n            case 'd':\n            case 'i':\n            case 'u':\n                mp_print_mp_int(&print, arg_as_int(arg), 10, 'a', flags, fill, width, prec);\n                break;\n\n            #if MICROPY_PY_BUILTINS_FLOAT\n            case 'e':\n            case 'E':\n            case 'f':\n            case 'F':\n            case 'g':\n            case 'G':\n                mp_print_float(&print, mp_obj_get_float(arg), *str, flags, fill, width, prec);\n                break;\n            #endif\n\n            case 'o':\n                if (alt) {\n                    flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER);\n                }\n                mp_print_mp_int(&print, arg, 8, 'a', flags, fill, width, prec);\n                break;\n\n            case 'r':\n            case 's': {\n                vstr_t arg_vstr;\n                mp_print_t arg_print;\n                vstr_init_print(&arg_vstr, 16, &arg_print);\n                mp_print_kind_t print_kind = (*str == 'r' ? PRINT_REPR : PRINT_STR);\n                if (print_kind == PRINT_STR && is_bytes && mp_obj_is_type(arg, &mp_type_bytes)) {\n                    // If we have something like b\"%s\" % b\"1\", bytes arg should be\n                    // printed undecorated.\n                    print_kind = PRINT_RAW;\n                }\n                mp_obj_print_helper(&arg_print, arg, print_kind);\n                uint vlen = arg_vstr.len;\n                if (prec < 0) {\n                    prec = vlen;\n                }\n                if (vlen > (uint)prec) {\n                    vlen = prec;\n                }\n                mp_print_strn(&print, arg_vstr.buf, vlen, flags, ' ', width);\n                vstr_clear(&arg_vstr);\n                break;\n            }\n\n            case 'X':\n            case 'x':\n                mp_print_mp_int(&print, arg, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec);\n                break;\n\n            default:\n                #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n                terse_str_format_value_error();\n                #else\n                mp_raise_msg_varg(&mp_type_ValueError,\n                    MP_ERROR_TEXT(\"unsupported format character '%c' (0x%x) at index %d\"),\n                    *str, *str, str - start_str);\n                #endif\n        }\n    }\n\n    if (arg_i != n_args) {\n        mp_raise_TypeError(MP_ERROR_TEXT(\"format string didn't convert all arguments\"));\n    }\n\n    return mp_obj_new_str_from_vstr(is_bytes ? &mp_type_bytes : &mp_type_str, &vstr);\n}\n#endif\n\n// The implementation is optimized, returning the original string if there's\n// nothing to replace.\nSTATIC mp_obj_t str_replace(size_t n_args, const mp_obj_t *args) {\n    mp_check_self(mp_obj_is_str_or_bytes(args[0]));\n\n    mp_int_t max_rep = -1;\n    if (n_args == 4) {\n        max_rep = mp_obj_get_int(args[3]);\n        if (max_rep == 0) {\n            return args[0];\n        } else if (max_rep < 0) {\n            max_rep = -1;\n        }\n    }\n\n    // if max_rep is still -1 by this point we will need to do all possible replacements\n\n    // check argument types\n\n    const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);\n\n    if (mp_obj_get_type(args[1]) != self_type) {\n        bad_implicit_conversion(args[1]);\n    }\n\n    if (mp_obj_get_type(args[2]) != self_type) {\n        bad_implicit_conversion(args[2]);\n    }\n\n    // extract string data\n\n    GET_STR_DATA_LEN(args[0], str, str_len);\n    GET_STR_DATA_LEN(args[1], old, old_len);\n    GET_STR_DATA_LEN(args[2], new, new_len);\n\n    // old won't exist in str if it's longer, so nothing to replace\n    if (old_len > str_len) {\n        return args[0];\n    }\n\n    // data for the replaced string\n    byte *data = NULL;\n    vstr_t vstr;\n\n    // do 2 passes over the string:\n    //   first pass computes the required length of the replaced string\n    //   second pass does the replacements\n    for (;;) {\n        size_t replaced_str_index = 0;\n        size_t num_replacements_done = 0;\n        const byte *old_occurrence;\n        const byte *offset_ptr = str;\n        size_t str_len_remain = str_len;\n        if (old_len == 0) {\n            // if old_str is empty, copy new_str to start of replaced string\n            // copy the replacement string\n            if (data != NULL) {\n                memcpy(data, new, new_len);\n            }\n            replaced_str_index += new_len;\n            num_replacements_done++;\n        }\n        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) {\n            if (old_len == 0) {\n                old_occurrence += 1;\n            }\n            // copy from just after end of last occurrence of to-be-replaced string to right before start of next occurrence\n            if (data != NULL) {\n                memcpy(data + replaced_str_index, offset_ptr, old_occurrence - offset_ptr);\n            }\n            replaced_str_index += old_occurrence - offset_ptr;\n            // copy the replacement string\n            if (data != NULL) {\n                memcpy(data + replaced_str_index, new, new_len);\n            }\n            replaced_str_index += new_len;\n            offset_ptr = old_occurrence + old_len;\n            str_len_remain = str + str_len - offset_ptr;\n            num_replacements_done++;\n        }\n\n        // copy from just after end of last occurrence of to-be-replaced string to end of old string\n        if (data != NULL) {\n            memcpy(data + replaced_str_index, offset_ptr, str_len_remain);\n        }\n        replaced_str_index += str_len_remain;\n\n        if (data == NULL) {\n            // first pass\n            if (num_replacements_done == 0) {\n                // no substr found, return original string\n                return args[0];\n            } else {\n                // substr found, allocate new string\n                vstr_init_len(&vstr, replaced_str_index);\n                data = (byte *)vstr.buf;\n                assert(data != NULL);\n            }\n        } else {\n            // second pass, we are done\n            break;\n        }\n    }\n\n    return mp_obj_new_str_from_vstr(self_type, &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace);\n\n#if MICROPY_PY_BUILTINS_STR_COUNT\nSTATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) {\n    const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);\n    mp_check_self(mp_obj_is_str_or_bytes(args[0]));\n\n    // check argument type\n    if (mp_obj_get_type(args[1]) != self_type) {\n        bad_implicit_conversion(args[1]);\n    }\n\n    GET_STR_DATA_LEN(args[0], haystack, haystack_len);\n    GET_STR_DATA_LEN(args[1], needle, needle_len);\n\n    const byte *start = haystack;\n    const byte *end = haystack + haystack_len;\n    if (n_args >= 3 && args[2] != mp_const_none) {\n        start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true);\n    }\n    if (n_args >= 4 && args[3] != mp_const_none) {\n        end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true);\n    }\n\n    // if needle_len is zero then we count each gap between characters as an occurrence\n    if (needle_len == 0) {\n        return MP_OBJ_NEW_SMALL_INT(utf8_charlen(start, end - start) + 1);\n    }\n\n    // count the occurrences\n    mp_int_t num_occurrences = 0;\n    for (const byte *haystack_ptr = start; haystack_ptr + needle_len <= end;) {\n        if (memcmp(haystack_ptr, needle, needle_len) == 0) {\n            num_occurrences++;\n            haystack_ptr += needle_len;\n        } else {\n            haystack_ptr = utf8_next_char(haystack_ptr);\n        }\n    }\n\n    return MP_OBJ_NEW_SMALL_INT(num_occurrences);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count);\n#endif\n\n#if MICROPY_PY_BUILTINS_STR_PARTITION\nSTATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, int direction) {\n    mp_check_self(mp_obj_is_str_or_bytes(self_in));\n    const mp_obj_type_t *self_type = mp_obj_get_type(self_in);\n    if (self_type != mp_obj_get_type(arg)) {\n        bad_implicit_conversion(arg);\n    }\n\n    GET_STR_DATA_LEN(self_in, str, str_len);\n    GET_STR_DATA_LEN(arg, sep, sep_len);\n\n    if (sep_len == 0) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"empty separator\"));\n    }\n\n    mp_obj_t result[3];\n    if (self_type == &mp_type_str) {\n        result[0] = MP_OBJ_NEW_QSTR(MP_QSTR_);\n        result[1] = MP_OBJ_NEW_QSTR(MP_QSTR_);\n        result[2] = MP_OBJ_NEW_QSTR(MP_QSTR_);\n    } else {\n        result[0] = mp_const_empty_bytes;\n        result[1] = mp_const_empty_bytes;\n        result[2] = mp_const_empty_bytes;\n    }\n\n    if (direction > 0) {\n        result[0] = self_in;\n    } else {\n        result[2] = self_in;\n    }\n\n    const byte *position_ptr = find_subbytes(str, str_len, sep, sep_len, direction);\n    if (position_ptr != NULL) {\n        size_t position = position_ptr - str;\n        result[0] = mp_obj_new_str_of_type(self_type, str, position);\n        result[1] = arg;\n        result[2] = mp_obj_new_str_of_type(self_type, str + position + sep_len, str_len - position - sep_len);\n    }\n\n    return mp_obj_new_tuple(3, result);\n}\n\nSTATIC mp_obj_t str_partition(mp_obj_t self_in, mp_obj_t arg) {\n    return str_partitioner(self_in, arg, 1);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);\n\nSTATIC mp_obj_t str_rpartition(mp_obj_t self_in, mp_obj_t arg) {\n    return str_partitioner(self_in, arg, -1);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);\n#endif\n\n// Supposedly not too critical operations, so optimize for code size\nSTATIC mp_obj_t str_caseconv(unichar (*op)(unichar), mp_obj_t self_in) {\n    GET_STR_DATA_LEN(self_in, self_data, self_len);\n    vstr_t vstr;\n    vstr_init_len(&vstr, self_len);\n    byte *data = (byte *)vstr.buf;\n    for (size_t i = 0; i < self_len; i++) {\n        *data++ = op(*self_data++);\n    }\n    return mp_obj_new_str_from_vstr(mp_obj_get_type(self_in), &vstr);\n}\n\nSTATIC mp_obj_t str_lower(mp_obj_t self_in) {\n    return str_caseconv(unichar_tolower, self_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower);\n\nSTATIC mp_obj_t str_upper(mp_obj_t self_in) {\n    return str_caseconv(unichar_toupper, self_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper);\n\nSTATIC mp_obj_t str_uni_istype(bool (*f)(unichar), mp_obj_t self_in) {\n    GET_STR_DATA_LEN(self_in, self_data, self_len);\n\n    if (self_len == 0) {\n        return mp_const_false; // default to False for empty str\n    }\n\n    if (f != unichar_isupper && f != unichar_islower) {\n        for (size_t i = 0; i < self_len; i++) {\n            if (!f(*self_data++)) {\n                return mp_const_false;\n            }\n        }\n    } else {\n        bool contains_alpha = false;\n\n        for (size_t i = 0; i < self_len; i++) { // only check alphanumeric characters\n            if (unichar_isalpha(*self_data++)) {\n                contains_alpha = true;\n                if (!f(*(self_data - 1))) { // -1 because we already incremented above\n                    return mp_const_false;\n                }\n            }\n        }\n\n        if (!contains_alpha) {\n            return mp_const_false;\n        }\n    }\n\n    return mp_const_true;\n}\n\nSTATIC mp_obj_t str_isspace(mp_obj_t self_in) {\n    return str_uni_istype(unichar_isspace, self_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace);\n\nSTATIC mp_obj_t str_isalpha(mp_obj_t self_in) {\n    return str_uni_istype(unichar_isalpha, self_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha);\n\nSTATIC mp_obj_t str_isdigit(mp_obj_t self_in) {\n    return str_uni_istype(unichar_isdigit, self_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit);\n\nSTATIC mp_obj_t str_isupper(mp_obj_t self_in) {\n    return str_uni_istype(unichar_isupper, self_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper);\n\nSTATIC mp_obj_t str_islower(mp_obj_t self_in) {\n    return str_uni_istype(unichar_islower, self_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower);\n\n#if MICROPY_CPYTHON_COMPAT\n// These methods are superfluous in the presence of str() and bytes()\n// constructors.\n// TODO: should accept kwargs too\nSTATIC mp_obj_t bytes_decode(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t new_args[2];\n    if (n_args == 1) {\n        new_args[0] = args[0];\n        new_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_utf_hyphen_8);\n        args = new_args;\n        n_args++;\n    }\n    return mp_obj_str_make_new(&mp_type_str, n_args, 0, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode);\n\n// TODO: should accept kwargs too\nSTATIC mp_obj_t str_encode(size_t n_args, const mp_obj_t *args) {\n    mp_obj_t new_args[2];\n    if (n_args == 1) {\n        new_args[0] = args[0];\n        new_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_utf_hyphen_8);\n        args = new_args;\n        n_args++;\n    }\n    return bytes_make_new(NULL, n_args, 0, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode);\n#endif\n\nmp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {\n    if (flags == MP_BUFFER_READ) {\n        GET_STR_DATA_LEN(self_in, str_data, str_len);\n        bufinfo->buf = (void *)str_data;\n        bufinfo->len = str_len;\n        bufinfo->typecode = 'B'; // bytes should be unsigned, so should unicode byte-access\n        return 0;\n    } else {\n        // can't write to a string\n        return 1;\n    }\n}\n\nSTATIC const mp_rom_map_elem_t str8_locals_dict_table[] = {\n    #if MICROPY_CPYTHON_COMPAT\n    { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&bytes_decode_obj) },\n    #if !MICROPY_PY_BUILTINS_STR_UNICODE\n    // If we have separate unicode type, then here we have methods only\n    // for bytes type, and it should not have encode() methods. Otherwise,\n    // we have non-compliant-but-practical bytestring type, which shares\n    // method table with bytes, so they both have encode() and decode()\n    // methods (which should do type checking at runtime).\n    { MP_ROM_QSTR(MP_QSTR_encode), MP_ROM_PTR(&str_encode_obj) },\n    #endif\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&str_find_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rfind), MP_ROM_PTR(&str_rfind_obj) },\n    { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&str_index_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rindex), MP_ROM_PTR(&str_rindex_obj) },\n    { MP_ROM_QSTR(MP_QSTR_join), MP_ROM_PTR(&str_join_obj) },\n    { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&str_split_obj) },\n    #if MICROPY_PY_BUILTINS_STR_SPLITLINES\n    { MP_ROM_QSTR(MP_QSTR_splitlines), MP_ROM_PTR(&str_splitlines_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_rsplit), MP_ROM_PTR(&str_rsplit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_startswith), MP_ROM_PTR(&str_startswith_obj) },\n    { MP_ROM_QSTR(MP_QSTR_endswith), MP_ROM_PTR(&str_endswith_obj) },\n    { MP_ROM_QSTR(MP_QSTR_strip), MP_ROM_PTR(&str_strip_obj) },\n    { MP_ROM_QSTR(MP_QSTR_lstrip), MP_ROM_PTR(&str_lstrip_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rstrip), MP_ROM_PTR(&str_rstrip_obj) },\n    { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&str_format_obj) },\n    { MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&str_replace_obj) },\n    #if MICROPY_PY_BUILTINS_STR_COUNT\n    { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) },\n    #endif\n    #if MICROPY_PY_BUILTINS_STR_PARTITION\n    { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) },\n    #endif\n    #if MICROPY_PY_BUILTINS_STR_CENTER\n    { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) },\n    { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isalpha), MP_ROM_PTR(&str_isalpha_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isdigit), MP_ROM_PTR(&str_isdigit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isupper), MP_ROM_PTR(&str_isupper_obj) },\n    { MP_ROM_QSTR(MP_QSTR_islower), MP_ROM_PTR(&str_islower_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(str8_locals_dict, str8_locals_dict_table);\n\n#if !MICROPY_PY_BUILTINS_STR_UNICODE\nSTATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);\n\nconst mp_obj_type_t mp_type_str = {\n    { &mp_type_type },\n    .name = MP_QSTR_str,\n    .print = str_print,\n    .make_new = mp_obj_str_make_new,\n    .binary_op = mp_obj_str_binary_op,\n    .subscr = bytes_subscr,\n    .getiter = mp_obj_new_str_iterator,\n    .buffer_p = { .get_buffer = mp_obj_str_get_buffer },\n    .locals_dict = (mp_obj_dict_t *)&str8_locals_dict,\n};\n#endif\n\n// Reuses most of methods from str\nconst mp_obj_type_t mp_type_bytes = {\n    { &mp_type_type },\n    .name = MP_QSTR_bytes,\n    .print = str_print,\n    .make_new = bytes_make_new,\n    .binary_op = mp_obj_str_binary_op,\n    .subscr = bytes_subscr,\n    .getiter = mp_obj_new_bytes_iterator,\n    .buffer_p = { .get_buffer = mp_obj_str_get_buffer },\n    .locals_dict = (mp_obj_dict_t *)&str8_locals_dict,\n};\n\n// The zero-length bytes object, with data that includes a null-terminating byte\nconst mp_obj_str_t mp_const_empty_bytes_obj = {{&mp_type_bytes}, 0, 0, (const byte *)\"\"};\n\n// Create a str/bytes object using the given data.  New memory is allocated and\n// the data is copied across.  This function should only be used if the type is bytes,\n// or if the type is str and the string data is known to be not interned.\nmp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte *data, size_t len) {\n    mp_obj_str_t *o = m_new_obj(mp_obj_str_t);\n    o->base.type = type;\n    o->len = len;\n    if (data) {\n        o->hash = qstr_compute_hash(data, len);\n        byte *p = m_new(byte, len + 1);\n        o->data = p;\n        memcpy(p, data, len * sizeof(byte));\n        p[len] = '\\0'; // for now we add null for compatibility with C ASCIIZ strings\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\n// Create a str/bytes object using the given data.  If the type is str and the string\n// data is already interned, then a qstr object is returned.  Otherwise new memory is\n// allocated for the object and the data is copied across.\nmp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte *data, size_t len) {\n    if (type == &mp_type_str) {\n        return mp_obj_new_str((const char *)data, len);\n    } else {\n        return mp_obj_new_bytes(data, len);\n    }\n}\n\n// Create a str using a qstr to store the data; may use existing or new qstr.\nmp_obj_t mp_obj_new_str_via_qstr(const char *data, size_t len) {\n    return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len));\n}\n\n// Create a str/bytes object from the given vstr.  The vstr buffer is resized to\n// the exact length required and then reused for the str/bytes object.  The vstr\n// is cleared and can safely be passed to vstr_free if it was heap allocated.\nmp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) {\n    // if not a bytes object, look if a qstr with this data already exists\n    if (type == &mp_type_str) {\n        qstr q = qstr_find_strn(vstr->buf, vstr->len);\n        if (q != MP_QSTRnull) {\n            vstr_clear(vstr);\n            vstr->alloc = 0;\n            return MP_OBJ_NEW_QSTR(q);\n        }\n    }\n\n    // make a new str/bytes object\n    mp_obj_str_t *o = m_new_obj(mp_obj_str_t);\n    o->base.type = type;\n    o->len = vstr->len;\n    o->hash = qstr_compute_hash((byte *)vstr->buf, vstr->len);\n    if (vstr->len + 1 == vstr->alloc) {\n        o->data = (byte *)vstr->buf;\n    } else {\n        o->data = (byte *)m_renew(char, vstr->buf, vstr->alloc, vstr->len + 1);\n    }\n    ((byte *)o->data)[o->len] = '\\0'; // add null byte\n    vstr->buf = NULL;\n    vstr->alloc = 0;\n    return MP_OBJ_FROM_PTR(o);\n}\n\nmp_obj_t mp_obj_new_str(const char *data, size_t len) {\n    qstr q = qstr_find_strn(data, len);\n    if (q != MP_QSTRnull) {\n        // qstr with this data already exists\n        return MP_OBJ_NEW_QSTR(q);\n    } else {\n        // no existing qstr, don't make one\n        return mp_obj_new_str_copy(&mp_type_str, (const byte *)data, len);\n    }\n}\n\nmp_obj_t mp_obj_str_intern(mp_obj_t str) {\n    GET_STR_DATA_LEN(str, data, len);\n    return mp_obj_new_str_via_qstr((const char *)data, len);\n}\n\nmp_obj_t mp_obj_str_intern_checked(mp_obj_t obj) {\n    size_t len;\n    const char *data = mp_obj_str_get_data(obj, &len);\n    return mp_obj_new_str_via_qstr((const char *)data, len);\n}\n\nmp_obj_t mp_obj_new_bytes(const byte *data, size_t len) {\n    return mp_obj_new_str_copy(&mp_type_bytes, data, len);\n}\n\nbool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {\n    if (mp_obj_is_qstr(s1) && mp_obj_is_qstr(s2)) {\n        return s1 == s2;\n    } else {\n        GET_STR_HASH(s1, h1);\n        GET_STR_HASH(s2, h2);\n        // If any of hashes is 0, it means it's not valid\n        if (h1 != 0 && h2 != 0 && h1 != h2) {\n            return false;\n        }\n        GET_STR_DATA_LEN(s1, d1, l1);\n        GET_STR_DATA_LEN(s2, d2, l2);\n        if (l1 != l2) {\n            return false;\n        }\n        return memcmp(d1, d2, l1) == 0;\n    }\n}\n\nSTATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) {\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    mp_raise_TypeError(MP_ERROR_TEXT(\"can't convert to str implicitly\"));\n    #else\n    const qstr src_name = mp_obj_get_type(self_in)->name;\n    mp_raise_msg_varg(&mp_type_TypeError,\n        MP_ERROR_TEXT(\"can't convert '%q' object to %q implicitly\"),\n        src_name, src_name == MP_QSTR_str ? MP_QSTR_bytes : MP_QSTR_str);\n    #endif\n}\n\n// use this if you will anyway convert the string to a qstr\n// will be more efficient for the case where it's already a qstr\nqstr mp_obj_str_get_qstr(mp_obj_t self_in) {\n    if (mp_obj_is_qstr(self_in)) {\n        return MP_OBJ_QSTR_VALUE(self_in);\n    } else if (mp_obj_is_type(self_in, &mp_type_str)) {\n        mp_obj_str_t *self = MP_OBJ_TO_PTR(self_in);\n        return qstr_from_strn((char *)self->data, self->len);\n    } else {\n        bad_implicit_conversion(self_in);\n    }\n}\n\n// only use this function if you need the str data to be zero terminated\n// at the moment all strings are zero terminated to help with C ASCIIZ compatibility\nconst char *mp_obj_str_get_str(mp_obj_t self_in) {\n    if (mp_obj_is_str_or_bytes(self_in)) {\n        GET_STR_DATA_LEN(self_in, s, l);\n        (void)l; // len unused\n        return (const char *)s;\n    } else {\n        bad_implicit_conversion(self_in);\n    }\n}\n\nconst char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) {\n    if (mp_obj_is_str_or_bytes(self_in)) {\n        GET_STR_DATA_LEN(self_in, s, l);\n        *len = l;\n        return (const char *)s;\n    } else {\n        bad_implicit_conversion(self_in);\n    }\n}\n\n#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D\nconst byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len) {\n    if (mp_obj_is_qstr(self_in)) {\n        return qstr_data(MP_OBJ_QSTR_VALUE(self_in), len);\n    } else {\n        *len = ((mp_obj_str_t *)MP_OBJ_TO_PTR(self_in))->len;\n        return ((mp_obj_str_t *)MP_OBJ_TO_PTR(self_in))->data;\n    }\n}\n#endif\n\n/******************************************************************************/\n/* str iterator                                                               */\n\ntypedef struct _mp_obj_str8_it_t {\n    mp_obj_base_t base;\n    mp_fun_1_t iternext;\n    mp_obj_t str;\n    size_t cur;\n} mp_obj_str8_it_t;\n\n#if !MICROPY_PY_BUILTINS_STR_UNICODE\nSTATIC mp_obj_t str_it_iternext(mp_obj_t self_in) {\n    mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in);\n    GET_STR_DATA_LEN(self->str, str, len);\n    if (self->cur < len) {\n        mp_obj_t o_out = mp_obj_new_str_via_qstr((const char *)str + self->cur, 1);\n        self->cur += 1;\n        return o_out;\n    } else {\n        return MP_OBJ_STOP_ITERATION;\n    }\n}\n\nSTATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) {\n    assert(sizeof(mp_obj_str8_it_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_obj_str8_it_t *o = (mp_obj_str8_it_t *)iter_buf;\n    o->base.type = &mp_type_polymorph_iter;\n    o->iternext = str_it_iternext;\n    o->str = str;\n    o->cur = 0;\n    return MP_OBJ_FROM_PTR(o);\n}\n#endif\n\nSTATIC mp_obj_t bytes_it_iternext(mp_obj_t self_in) {\n    mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in);\n    GET_STR_DATA_LEN(self->str, str, len);\n    if (self->cur < len) {\n        mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(str[self->cur]);\n        self->cur += 1;\n        return o_out;\n    } else {\n        return MP_OBJ_STOP_ITERATION;\n    }\n}\n\nmp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) {\n    assert(sizeof(mp_obj_str8_it_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_obj_str8_it_t *o = (mp_obj_str8_it_t *)iter_buf;\n    o->base.type = &mp_type_polymorph_iter;\n    o->iternext = bytes_it_iternext;\n    o->str = str;\n    o->cur = 0;\n    return MP_OBJ_FROM_PTR(o);\n}\n"
  },
  {
    "path": "py/objstr.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJSTR_H\n#define MICROPY_INCLUDED_PY_OBJSTR_H\n\n#include \"py/obj.h\"\n\ntypedef struct _mp_obj_str_t {\n    mp_obj_base_t base;\n    mp_uint_t hash;\n    // len == number of bytes used in data, alloc = len + 1 because (at the moment) we also append a null byte\n    size_t len;\n    const byte *data;\n} mp_obj_str_t;\n\n#define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte *)str}\n\n// use this macro to extract the string hash\n// warning: the hash can be 0, meaning invalid, and must then be explicitly computed from the data\n#define GET_STR_HASH(str_obj_in, str_hash) \\\n    mp_uint_t str_hash; if (mp_obj_is_qstr(str_obj_in)) \\\n    { 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; }\n\n// use this macro to extract the string length\n#define GET_STR_LEN(str_obj_in, str_len) \\\n    size_t str_len; if (mp_obj_is_qstr(str_obj_in)) \\\n    { 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; }\n\n// use this macro to extract the string data and length\n#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D\nconst byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len);\n#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \\\n    size_t str_len; const byte *str_data = mp_obj_str_get_data_no_check(str_obj_in, &str_len);\n#else\n#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \\\n    const byte *str_data; size_t str_len; if (mp_obj_is_qstr(str_obj_in)) \\\n    { str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } \\\n    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; }\n#endif\n\nmp_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);\nvoid mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len);\nmp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);\nmp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args);\nmp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte *data, size_t len);\nmp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte *data, size_t len);\n\nmp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in);\nmp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);\n\nconst byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len,\n    mp_obj_t index, bool is_slice);\nconst byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction);\n\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(str_join_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj);\nMP_DECLARE_CONST_FUN_OBJ_KW(str_splitlines_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj);\nMP_DECLARE_CONST_FUN_OBJ_KW(str_format_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(str_partition_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(str_rpartition_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(str_center_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(str_lower_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(str_upper_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(str_isspace_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(str_isalpha_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(str_isdigit_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(str_isupper_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(str_islower_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj);\n\n#endif // MICROPY_INCLUDED_PY_OBJSTR_H\n"
  },
  {
    "path": "py/objstringio.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014-2017 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"py/objstr.h\"\n#include \"py/objstringio.h\"\n#include \"py/runtime.h\"\n#include \"py/stream.h\"\n\n#if MICROPY_PY_IO\n\n#if MICROPY_CPYTHON_COMPAT\nSTATIC void check_stringio_is_open(const mp_obj_stringio_t *o) {\n    if (o->vstr == NULL) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"I/O operation on closed file\"));\n    }\n}\n#else\n#define check_stringio_is_open(o)\n#endif\n\nSTATIC void stringio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, self->base.type == &mp_type_stringio ? \"<io.StringIO 0x%x>\" : \"<io.BytesIO 0x%x>\", self);\n}\n\nSTATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {\n    (void)errcode;\n    mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);\n    check_stringio_is_open(o);\n    if (o->vstr->len <= o->pos) {  // read to EOF, or seeked to EOF or beyond\n        return 0;\n    }\n    mp_uint_t remaining = o->vstr->len - o->pos;\n    if (size > remaining) {\n        size = remaining;\n    }\n    memcpy(buf, o->vstr->buf + o->pos, size);\n    o->pos += size;\n    return size;\n}\n\nSTATIC void stringio_copy_on_write(mp_obj_stringio_t *o) {\n    const void *buf = o->vstr->buf;\n    o->vstr->buf = m_new(char, o->vstr->len);\n    o->vstr->fixed_buf = false;\n    o->ref_obj = MP_OBJ_NULL;\n    memcpy(o->vstr->buf, buf, o->vstr->len);\n}\n\nSTATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {\n    (void)errcode;\n    mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);\n    check_stringio_is_open(o);\n\n    if (o->vstr->fixed_buf) {\n        stringio_copy_on_write(o);\n    }\n\n    mp_uint_t new_pos = o->pos + size;\n    if (new_pos < size) {\n        // Writing <size> bytes will overflow o->pos beyond limit of mp_uint_t.\n        *errcode = MP_EFBIG;\n        return MP_STREAM_ERROR;\n    }\n    mp_uint_t org_len = o->vstr->len;\n    if (new_pos > o->vstr->alloc) {\n        // Take all what's already allocated...\n        o->vstr->len = o->vstr->alloc;\n        // ... and add more\n        vstr_add_len(o->vstr, new_pos - o->vstr->alloc);\n    }\n    // If there was a seek past EOF, clear the hole\n    if (o->pos > org_len) {\n        memset(o->vstr->buf + org_len, 0, o->pos - org_len);\n    }\n    memcpy(o->vstr->buf + o->pos, buf, size);\n    o->pos = new_pos;\n    if (new_pos > o->vstr->len) {\n        o->vstr->len = new_pos;\n    }\n    return size;\n}\n\nSTATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {\n    (void)errcode;\n    mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);\n    switch (request) {\n        case MP_STREAM_SEEK: {\n            struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg;\n            mp_uint_t ref = 0;\n            switch (s->whence) {\n                case MP_SEEK_CUR:\n                    ref = o->pos;\n                    break;\n                case MP_SEEK_END:\n                    ref = o->vstr->len;\n                    break;\n            }\n            mp_uint_t new_pos = ref + s->offset;\n\n            // For MP_SEEK_SET, offset is unsigned\n            if (s->whence != MP_SEEK_SET && s->offset < 0) {\n                if (new_pos > ref) {\n                    // Negative offset from SEEK_CUR or SEEK_END went past 0.\n                    // CPython sets position to 0, POSIX returns an EINVAL error\n                    new_pos = 0;\n                }\n            } else if (new_pos < ref) {\n                // positive offset went beyond the limit of mp_uint_t\n                *errcode = MP_EINVAL;  // replace with MP_EOVERFLOW when defined\n                return MP_STREAM_ERROR;\n            }\n            s->offset = o->pos = new_pos;\n            return 0;\n        }\n        case MP_STREAM_FLUSH:\n            return 0;\n        case MP_STREAM_CLOSE:\n            #if MICROPY_CPYTHON_COMPAT\n            vstr_free(o->vstr);\n            o->vstr = NULL;\n            #else\n            vstr_clear(o->vstr);\n            o->vstr->alloc = 0;\n            o->vstr->len = 0;\n            o->pos = 0;\n            #endif\n            return 0;\n        default:\n            *errcode = MP_EINVAL;\n            return MP_STREAM_ERROR;\n    }\n}\n\n#define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes)\n\nSTATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) {\n    mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in);\n    check_stringio_is_open(self);\n    // TODO: Try to avoid copying string\n    return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte *)self->vstr->buf, self->vstr->len);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue);\n\nSTATIC mp_obj_t stringio___exit__(size_t n_args, const mp_obj_t *args) {\n    (void)n_args;\n    return mp_stream_close(args[0]);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__);\n\nSTATIC mp_obj_stringio_t *stringio_new(const mp_obj_type_t *type) {\n    mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);\n    o->base.type = type;\n    o->pos = 0;\n    o->ref_obj = MP_OBJ_NULL;\n    return o;\n}\n\nSTATIC 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) {\n    (void)n_kw; // TODO check n_kw==0\n\n    mp_uint_t sz = 16;\n    bool initdata = false;\n    mp_buffer_info_t bufinfo;\n\n    mp_obj_stringio_t *o = stringio_new(type_in);\n\n    if (n_args > 0) {\n        if (mp_obj_is_int(args[0])) {\n            sz = mp_obj_get_int(args[0]);\n        } else {\n            mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);\n\n            if (mp_obj_is_str_or_bytes(args[0])) {\n                o->vstr = m_new_obj(vstr_t);\n                vstr_init_fixed_buf(o->vstr, bufinfo.len, bufinfo.buf);\n                o->vstr->len = bufinfo.len;\n                o->ref_obj = args[0];\n                return MP_OBJ_FROM_PTR(o);\n            }\n\n            sz = bufinfo.len;\n            initdata = true;\n        }\n    }\n\n    o->vstr = vstr_new(sz);\n\n    if (initdata) {\n        stringio_write(MP_OBJ_FROM_PTR(o), bufinfo.buf, bufinfo.len, NULL);\n        // Cur ptr is always at the beginning of buffer at the construction\n        o->pos = 0;\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },\n    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },\n    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },\n    { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },\n    { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },\n    { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },\n    { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },\n    { MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) },\n    { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },\n    { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stringio___exit___obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table);\n\nSTATIC const mp_stream_p_t stringio_stream_p = {\n    .read = stringio_read,\n    .write = stringio_write,\n    .ioctl = stringio_ioctl,\n    .is_text = true,\n};\n\nconst mp_obj_type_t mp_type_stringio = {\n    { &mp_type_type },\n    .name = MP_QSTR_StringIO,\n    .print = stringio_print,\n    .make_new = stringio_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &stringio_stream_p,\n    .locals_dict = (mp_obj_dict_t *)&stringio_locals_dict,\n};\n\n#if MICROPY_PY_IO_BYTESIO\nSTATIC const mp_stream_p_t bytesio_stream_p = {\n    .read = stringio_read,\n    .write = stringio_write,\n    .ioctl = stringio_ioctl,\n};\n\nconst mp_obj_type_t mp_type_bytesio = {\n    { &mp_type_type },\n    .name = MP_QSTR_BytesIO,\n    .print = stringio_print,\n    .make_new = stringio_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = mp_stream_unbuffered_iter,\n    .protocol = &bytesio_stream_p,\n    .locals_dict = (mp_obj_dict_t *)&stringio_locals_dict,\n};\n#endif\n\n#endif\n"
  },
  {
    "path": "py/objstringio.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJSTRINGIO_H\n#define MICROPY_INCLUDED_PY_OBJSTRINGIO_H\n\n#include \"py/obj.h\"\n\ntypedef struct _mp_obj_stringio_t {\n    mp_obj_base_t base;\n    vstr_t *vstr;\n    // StringIO has single pointer used for both reading and writing\n    mp_uint_t pos;\n    // Underlying object buffered by this StringIO\n    mp_obj_t ref_obj;\n} mp_obj_stringio_t;\n\n#endif // MICROPY_INCLUDED_PY_OBJSTRINGIO_H\n"
  },
  {
    "path": "py/objstrunicode.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014-2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <assert.h>\n\n#include \"py/objstr.h\"\n#include \"py/objlist.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_PY_BUILTINS_STR_UNICODE\n\nSTATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);\n\n/******************************************************************************/\n/* str                                                                        */\n\nSTATIC void uni_print_quoted(const mp_print_t *print, const byte *str_data, uint str_len) {\n    // this escapes characters, but it will be very slow to print (calling print many times)\n    bool has_single_quote = false;\n    bool has_double_quote = false;\n    for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) {\n        if (*s == '\\'') {\n            has_single_quote = true;\n        } else if (*s == '\"') {\n            has_double_quote = true;\n        }\n    }\n    unichar quote_char = '\\'';\n    if (has_single_quote && !has_double_quote) {\n        quote_char = '\"';\n    }\n    mp_printf(print, \"%c\", quote_char);\n    const byte *s = str_data, *top = str_data + str_len;\n    while (s < top) {\n        unichar ch;\n        ch = utf8_get_char(s);\n        s = utf8_next_char(s);\n        if (ch == quote_char) {\n            mp_printf(print, \"\\\\%c\", quote_char);\n        } else if (ch == '\\\\') {\n            mp_print_str(print, \"\\\\\\\\\");\n        } else if (32 <= ch && ch <= 126) {\n            mp_printf(print, \"%c\", ch);\n        } else if (ch == '\\n') {\n            mp_print_str(print, \"\\\\n\");\n        } else if (ch == '\\r') {\n            mp_print_str(print, \"\\\\r\");\n        } else if (ch == '\\t') {\n            mp_print_str(print, \"\\\\t\");\n        } else if (ch < 0x100) {\n            mp_printf(print, \"\\\\x%02x\", ch);\n        } else if (ch < 0x10000) {\n            mp_printf(print, \"\\\\u%04x\", ch);\n        } else {\n            mp_printf(print, \"\\\\U%08x\", ch);\n        }\n    }\n    mp_printf(print, \"%c\", quote_char);\n}\n\nSTATIC void uni_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    GET_STR_DATA_LEN(self_in, str_data, str_len);\n    #if MICROPY_PY_UJSON\n    if (kind == PRINT_JSON) {\n        mp_str_print_json(print, str_data, str_len);\n        return;\n    }\n    #endif\n    if (kind == PRINT_STR) {\n        mp_printf(print, \"%.*s\", str_len, str_data);\n    } else {\n        uni_print_quoted(print, str_data, str_len);\n    }\n}\n\nSTATIC mp_obj_t uni_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n    GET_STR_DATA_LEN(self_in, str_data, str_len);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(str_len != 0);\n        case MP_UNARY_OP_LEN:\n            return MP_OBJ_NEW_SMALL_INT(utf8_charlen(str_data, str_len));\n        default:\n            return MP_OBJ_NULL; // op not supported\n    }\n}\n\n// Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or\n// be capped to the first/last character of the string, depending on is_slice.\nconst byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len,\n    mp_obj_t index, bool is_slice) {\n    // All str functions also handle bytes objects, and they call str_index_to_ptr(),\n    // so it must handle bytes.\n    if (type == &mp_type_bytes) {\n        // Taken from objstr.c:str_index_to_ptr()\n        size_t index_val = mp_get_index(type, self_len, index, is_slice);\n        return self_data + index_val;\n    }\n\n    mp_int_t i;\n    // Copied from mp_get_index; I don't want bounds checking, just give me\n    // the integer as-is. (I can't bounds-check without scanning the whole\n    // string; an out-of-bounds index will be caught in the loops below.)\n    if (mp_obj_is_small_int(index)) {\n        i = MP_OBJ_SMALL_INT_VALUE(index);\n    } else if (!mp_obj_get_int_maybe(index, &i)) {\n        mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT(\"string indices must be integers, not %s\"), mp_obj_get_type_str(index));\n    }\n    const byte *s, *top = self_data + self_len;\n    if (i < 0) {\n        // Negative indexing is performed by counting from the end of the string.\n        for (s = top - 1; i; --s) {\n            if (s < self_data) {\n                if (is_slice) {\n                    return self_data;\n                }\n                mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT(\"string index out of range\"));\n            }\n            if (!UTF8_IS_CONT(*s)) {\n                ++i;\n            }\n        }\n        ++s;\n    } else {\n        // Positive indexing, correspondingly, counts from the start of the string.\n        // It's assumed that negative indexing will generally be used with small\n        // absolute values (eg str[-1], not str[-1000000]), which means it'll be\n        // more efficient this way.\n        s = self_data;\n        while (1) {\n            // First check out-of-bounds\n            if (s >= top) {\n                if (is_slice) {\n                    return top;\n                }\n                mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT(\"string index out of range\"));\n            }\n            // Then check completion\n            if (i-- == 0) {\n                break;\n            }\n            // Then skip UTF-8 char\n            ++s;\n            while (UTF8_IS_CONT(*s)) {\n                ++s;\n            }\n        }\n    }\n    return s;\n}\n\nSTATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {\n    const mp_obj_type_t *type = mp_obj_get_type(self_in);\n    assert(type == &mp_type_str);\n    GET_STR_DATA_LEN(self_in, self_data, self_len);\n    if (value == MP_OBJ_SENTINEL) {\n        // load\n        #if MICROPY_PY_BUILTINS_SLICE\n        if (mp_obj_is_type(index, &mp_type_slice)) {\n            mp_obj_t ostart, ostop, ostep;\n            mp_obj_slice_t *slice = MP_OBJ_TO_PTR(index);\n            ostart = slice->start;\n            ostop = slice->stop;\n            ostep = slice->step;\n\n            if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {\n                mp_raise_NotImplementedError(MP_ERROR_TEXT(\"only slices with step=1 (aka None) are supported\"));\n            }\n\n            const byte *pstart, *pstop;\n            if (ostart != mp_const_none) {\n                pstart = str_index_to_ptr(type, self_data, self_len, ostart, true);\n            } else {\n                pstart = self_data;\n            }\n            if (ostop != mp_const_none) {\n                // pstop will point just after the stop character. This depends on\n                // the \\0 at the end of the string.\n                pstop = str_index_to_ptr(type, self_data, self_len, ostop, true);\n            } else {\n                pstop = self_data + self_len;\n            }\n            if (pstop < pstart) {\n                return MP_OBJ_NEW_QSTR(MP_QSTR_);\n            }\n            return mp_obj_new_str_of_type(type, (const byte *)pstart, pstop - pstart);\n        }\n        #endif\n        const byte *s = str_index_to_ptr(type, self_data, self_len, index, false);\n        int len = 1;\n        if (UTF8_IS_NONASCII(*s)) {\n            // Count the number of 1 bits (after the first)\n            for (char mask = 0x40; *s & mask; mask >>= 1) {\n                ++len;\n            }\n        }\n        return mp_obj_new_str_via_qstr((const char *)s, len); // This will create a one-character string\n    } else {\n        return MP_OBJ_NULL; // op not supported\n    }\n}\n\nSTATIC const mp_rom_map_elem_t struni_locals_dict_table[] = {\n    #if MICROPY_CPYTHON_COMPAT\n    { MP_ROM_QSTR(MP_QSTR_encode), MP_ROM_PTR(&str_encode_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&str_find_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rfind), MP_ROM_PTR(&str_rfind_obj) },\n    { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&str_index_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rindex), MP_ROM_PTR(&str_rindex_obj) },\n    { MP_ROM_QSTR(MP_QSTR_join), MP_ROM_PTR(&str_join_obj) },\n    { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&str_split_obj) },\n    #if MICROPY_PY_BUILTINS_STR_SPLITLINES\n    { MP_ROM_QSTR(MP_QSTR_splitlines), MP_ROM_PTR(&str_splitlines_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_rsplit), MP_ROM_PTR(&str_rsplit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_startswith), MP_ROM_PTR(&str_startswith_obj) },\n    { MP_ROM_QSTR(MP_QSTR_endswith), MP_ROM_PTR(&str_endswith_obj) },\n    { MP_ROM_QSTR(MP_QSTR_strip), MP_ROM_PTR(&str_strip_obj) },\n    { MP_ROM_QSTR(MP_QSTR_lstrip), MP_ROM_PTR(&str_lstrip_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rstrip), MP_ROM_PTR(&str_rstrip_obj) },\n    { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&str_format_obj) },\n    { MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&str_replace_obj) },\n    #if MICROPY_PY_BUILTINS_STR_COUNT\n    { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) },\n    #endif\n    #if MICROPY_PY_BUILTINS_STR_PARTITION\n    { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) },\n    { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) },\n    #endif\n    #if MICROPY_PY_BUILTINS_STR_CENTER\n    { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) },\n    #endif\n    { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) },\n    { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isalpha), MP_ROM_PTR(&str_isalpha_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isdigit), MP_ROM_PTR(&str_isdigit_obj) },\n    { MP_ROM_QSTR(MP_QSTR_isupper), MP_ROM_PTR(&str_isupper_obj) },\n    { MP_ROM_QSTR(MP_QSTR_islower), MP_ROM_PTR(&str_islower_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(struni_locals_dict, struni_locals_dict_table);\n\nconst mp_obj_type_t mp_type_str = {\n    { &mp_type_type },\n    .name = MP_QSTR_str,\n    .print = uni_print,\n    .make_new = mp_obj_str_make_new,\n    .unary_op = uni_unary_op,\n    .binary_op = mp_obj_str_binary_op,\n    .subscr = str_subscr,\n    .getiter = mp_obj_new_str_iterator,\n    .buffer_p = { .get_buffer = mp_obj_str_get_buffer },\n    .locals_dict = (mp_obj_dict_t *)&struni_locals_dict,\n};\n\n/******************************************************************************/\n/* str iterator                                                               */\n\ntypedef struct _mp_obj_str_it_t {\n    mp_obj_base_t base;\n    mp_fun_1_t iternext;\n    mp_obj_t str;\n    size_t cur;\n} mp_obj_str_it_t;\n\nSTATIC mp_obj_t str_it_iternext(mp_obj_t self_in) {\n    mp_obj_str_it_t *self = MP_OBJ_TO_PTR(self_in);\n    GET_STR_DATA_LEN(self->str, str, len);\n    if (self->cur < len) {\n        const byte *cur = str + self->cur;\n        const byte *end = utf8_next_char(str + self->cur);\n        mp_obj_t o_out = mp_obj_new_str_via_qstr((const char *)cur, end - cur);\n        self->cur += end - cur;\n        return o_out;\n    } else {\n        return MP_OBJ_STOP_ITERATION;\n    }\n}\n\nSTATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) {\n    assert(sizeof(mp_obj_str_it_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_obj_str_it_t *o = (mp_obj_str_it_t *)iter_buf;\n    o->base.type = &mp_type_polymorph_iter;\n    o->iternext = str_it_iternext;\n    o->str = str;\n    o->cur = 0;\n    return MP_OBJ_FROM_PTR(o);\n}\n\n#endif // MICROPY_PY_BUILTINS_STR_UNICODE\n"
  },
  {
    "path": "py/objtuple.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014-2017 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <assert.h>\n\n#include \"py/objtuple.h\"\n#include \"py/runtime.h\"\n\n// type check is done on getiter method to allow tuple, namedtuple, attrtuple\n#define mp_obj_is_tuple_compatible(o) (mp_obj_get_type(o)->getiter == mp_obj_tuple_getiter)\n\n/******************************************************************************/\n/* tuple                                                                      */\n\nvoid mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    mp_obj_tuple_t *o = MP_OBJ_TO_PTR(o_in);\n    if (MICROPY_PY_UJSON && kind == PRINT_JSON) {\n        mp_print_str(print, \"[\");\n    } else {\n        mp_print_str(print, \"(\");\n        kind = PRINT_REPR;\n    }\n    for (size_t i = 0; i < o->len; i++) {\n        if (i > 0) {\n            mp_print_str(print, \", \");\n        }\n        mp_obj_print_helper(print, o->items[i], kind);\n    }\n    if (MICROPY_PY_UJSON && kind == PRINT_JSON) {\n        mp_print_str(print, \"]\");\n    } else {\n        if (o->len == 1) {\n            mp_print_str(print, \",\");\n        }\n        mp_print_str(print, \")\");\n    }\n}\n\nSTATIC 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) {\n    (void)type_in;\n\n    mp_arg_check_num(n_args, n_kw, 0, 1, false);\n\n    switch (n_args) {\n        case 0:\n            // return a empty tuple\n            return mp_const_empty_tuple;\n\n        case 1:\n        default: {\n            // 1 argument, an iterable from which we make a new tuple\n            if (mp_obj_is_type(args[0], &mp_type_tuple)) {\n                return args[0];\n            }\n\n            // TODO optimise for cases where we know the length of the iterator\n\n            size_t alloc = 4;\n            size_t len = 0;\n            mp_obj_t *items = m_new(mp_obj_t, alloc);\n\n            mp_obj_t iterable = mp_getiter(args[0], NULL);\n            mp_obj_t item;\n            while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n                if (len >= alloc) {\n                    items = m_renew(mp_obj_t, items, alloc, alloc * 2);\n                    alloc *= 2;\n                }\n                items[len++] = item;\n            }\n\n            mp_obj_t tuple = mp_obj_new_tuple(len, items);\n            m_del(mp_obj_t, items, alloc);\n\n            return tuple;\n        }\n    }\n}\n\n// Don't pass MP_BINARY_OP_NOT_EQUAL here\nSTATIC mp_obj_t tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) {\n    mp_check_self(mp_obj_is_tuple_compatible(self_in));\n    const mp_obj_type_t *another_type = mp_obj_get_type(another_in);\n    mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);\n    if (another_type->getiter != mp_obj_tuple_getiter) {\n        // Slow path for user subclasses\n        another_in = mp_obj_cast_to_native_base(another_in, MP_OBJ_FROM_PTR(&mp_type_tuple));\n        if (another_in == MP_OBJ_NULL) {\n            return MP_OBJ_NULL;\n        }\n    }\n    mp_obj_tuple_t *another = MP_OBJ_TO_PTR(another_in);\n\n    return mp_obj_new_bool(mp_seq_cmp_objs(op, self->items, self->len, another->items, another->len));\n}\n\nmp_obj_t mp_obj_tuple_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n    mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);\n    switch (op) {\n        case MP_UNARY_OP_BOOL:\n            return mp_obj_new_bool(self->len != 0);\n        case MP_UNARY_OP_HASH: {\n            // start hash with pointer to empty tuple, to make it fairly unique\n            mp_int_t hash = (mp_int_t)mp_const_empty_tuple;\n            for (size_t i = 0; i < self->len; i++) {\n                hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, self->items[i]));\n            }\n            return MP_OBJ_NEW_SMALL_INT(hash);\n        }\n        case MP_UNARY_OP_LEN:\n            return MP_OBJ_NEW_SMALL_INT(self->len);\n        default:\n            return MP_OBJ_NULL;      // op not supported\n    }\n}\n\nmp_obj_t mp_obj_tuple_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {\n    mp_obj_tuple_t *o = MP_OBJ_TO_PTR(lhs);\n    switch (op) {\n        case MP_BINARY_OP_ADD:\n        case MP_BINARY_OP_INPLACE_ADD: {\n            if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(rhs)), MP_OBJ_FROM_PTR(&mp_type_tuple))) {\n                return MP_OBJ_NULL; // op not supported\n            }\n            mp_obj_tuple_t *p = MP_OBJ_TO_PTR(rhs);\n            mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len + p->len, NULL));\n            mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t);\n            return MP_OBJ_FROM_PTR(s);\n        }\n        case MP_BINARY_OP_MULTIPLY:\n        case MP_BINARY_OP_INPLACE_MULTIPLY: {\n            mp_int_t n;\n            if (!mp_obj_get_int_maybe(rhs, &n)) {\n                return MP_OBJ_NULL; // op not supported\n            }\n            if (n <= 0) {\n                return mp_const_empty_tuple;\n            }\n            mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len * n, NULL));\n            mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);\n            return MP_OBJ_FROM_PTR(s);\n        }\n        case MP_BINARY_OP_EQUAL:\n        case MP_BINARY_OP_LESS:\n        case MP_BINARY_OP_LESS_EQUAL:\n        case MP_BINARY_OP_MORE:\n        case MP_BINARY_OP_MORE_EQUAL:\n            return tuple_cmp_helper(op, lhs, rhs);\n\n        default:\n            return MP_OBJ_NULL; // op not supported\n    }\n}\n\nmp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {\n    if (value == MP_OBJ_SENTINEL) {\n        // load\n        mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);\n        #if MICROPY_PY_BUILTINS_SLICE\n        if (mp_obj_is_type(index, &mp_type_slice)) {\n            mp_bound_slice_t slice;\n            if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {\n                mp_raise_NotImplementedError(MP_ERROR_TEXT(\"only slices with step=1 (aka None) are supported\"));\n            }\n            mp_obj_tuple_t *res = MP_OBJ_TO_PTR(mp_obj_new_tuple(slice.stop - slice.start, NULL));\n            mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t);\n            return MP_OBJ_FROM_PTR(res);\n        }\n        #endif\n        size_t index_value = mp_get_index(self->base.type, self->len, index, false);\n        return self->items[index_value];\n    } else {\n        return MP_OBJ_NULL; // op not supported\n    }\n}\n\nSTATIC mp_obj_t tuple_count(mp_obj_t self_in, mp_obj_t value) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_tuple));\n    mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);\n    return mp_seq_count_obj(self->items, self->len, value);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_2(tuple_count_obj, tuple_count);\n\nSTATIC mp_obj_t tuple_index(size_t n_args, const mp_obj_t *args) {\n    mp_check_self(mp_obj_is_type(args[0], &mp_type_tuple));\n    mp_obj_tuple_t *self = MP_OBJ_TO_PTR(args[0]);\n    return mp_seq_index_obj(self->items, self->len, n_args, args);\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(tuple_index_obj, 2, 4, tuple_index);\n\nSTATIC const mp_rom_map_elem_t tuple_locals_dict_table[] = {\n    { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&tuple_count_obj) },\n    { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&tuple_index_obj) },\n};\n\nSTATIC MP_DEFINE_CONST_DICT(tuple_locals_dict, tuple_locals_dict_table);\n\nconst mp_obj_type_t mp_type_tuple = {\n    { &mp_type_type },\n    .name = MP_QSTR_tuple,\n    .print = mp_obj_tuple_print,\n    .make_new = mp_obj_tuple_make_new,\n    .unary_op = mp_obj_tuple_unary_op,\n    .binary_op = mp_obj_tuple_binary_op,\n    .subscr = mp_obj_tuple_subscr,\n    .getiter = mp_obj_tuple_getiter,\n    .locals_dict = (mp_obj_dict_t *)&tuple_locals_dict,\n};\n\n// the zero-length tuple\nconst mp_obj_tuple_t mp_const_empty_tuple_obj = {{&mp_type_tuple}, 0};\n\nmp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) {\n    if (n == 0) {\n        return mp_const_empty_tuple;\n    }\n    mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n);\n    o->base.type = &mp_type_tuple;\n    o->len = n;\n    if (items) {\n        for (size_t i = 0; i < n; i++) {\n            o->items[i] = items[i];\n        }\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nvoid mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) {\n    assert(mp_obj_is_tuple_compatible(self_in));\n    mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);\n    *len = self->len;\n    *items = &self->items[0];\n}\n\nvoid mp_obj_tuple_del(mp_obj_t self_in) {\n    assert(mp_obj_is_type(self_in, &mp_type_tuple));\n    mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);\n    m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self);\n}\n\n/******************************************************************************/\n/* tuple iterator                                                             */\n\ntypedef struct _mp_obj_tuple_it_t {\n    mp_obj_base_t base;\n    mp_fun_1_t iternext;\n    mp_obj_tuple_t *tuple;\n    size_t cur;\n} mp_obj_tuple_it_t;\n\nSTATIC mp_obj_t tuple_it_iternext(mp_obj_t self_in) {\n    mp_obj_tuple_it_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->cur < self->tuple->len) {\n        mp_obj_t o_out = self->tuple->items[self->cur];\n        self->cur += 1;\n        return o_out;\n    } else {\n        return MP_OBJ_STOP_ITERATION;\n    }\n}\n\nmp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {\n    assert(sizeof(mp_obj_tuple_it_t) <= sizeof(mp_obj_iter_buf_t));\n    mp_obj_tuple_it_t *o = (mp_obj_tuple_it_t *)iter_buf;\n    o->base.type = &mp_type_polymorph_iter;\n    o->iternext = tuple_it_iternext;\n    o->tuple = MP_OBJ_TO_PTR(o_in);\n    o->cur = 0;\n    return MP_OBJ_FROM_PTR(o);\n}\n"
  },
  {
    "path": "py/objtuple.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJTUPLE_H\n#define MICROPY_INCLUDED_PY_OBJTUPLE_H\n\n#include \"py/obj.h\"\n\ntypedef struct _mp_obj_tuple_t {\n    mp_obj_base_t base;\n    size_t len;\n    mp_obj_t items[];\n} mp_obj_tuple_t;\n\ntypedef struct _mp_rom_obj_tuple_t {\n    mp_obj_base_t base;\n    size_t len;\n    mp_rom_obj_t items[];\n} mp_rom_obj_tuple_t;\n\nvoid mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);\nmp_obj_t mp_obj_tuple_unary_op(mp_unary_op_t op, mp_obj_t self_in);\nmp_obj_t mp_obj_tuple_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs);\nmp_obj_t mp_obj_tuple_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value);\nmp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf);\n\nextern const mp_obj_type_t mp_type_attrtuple;\n\n#define MP_DEFINE_ATTRTUPLE(tuple_obj_name, fields, nitems, ...) \\\n    const mp_rom_obj_tuple_t tuple_obj_name = { \\\n        .base = {&mp_type_attrtuple}, \\\n        .len = nitems, \\\n        .items = { __VA_ARGS__, MP_ROM_PTR((void *)fields) } \\\n    }\n\n#if MICROPY_PY_COLLECTIONS\nvoid mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields, mp_obj_tuple_t *o);\n#endif\n\nmp_obj_t mp_obj_new_attrtuple(const qstr *fields, size_t n, const mp_obj_t *items);\n\n#endif // MICROPY_INCLUDED_PY_OBJTUPLE_H\n"
  },
  {
    "path": "py/objtype.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2018 Damien P. George\n * Copyright (c) 2014-2018 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stddef.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/objtype.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_PRINT (1)\n#define DEBUG_printf DEBUG_printf\n#else // don't print debugging info\n#define DEBUG_PRINT (0)\n#define DEBUG_printf(...) (void)0\n#endif\n\n#define ENABLE_SPECIAL_ACCESSORS \\\n    (MICROPY_PY_DESCRIPTORS || MICROPY_PY_DELATTR_SETATTR || MICROPY_PY_BUILTINS_PROPERTY)\n\nSTATIC 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);\n\n/******************************************************************************/\n// instance object\n\nSTATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) {\n    int count = 0;\n    for (;;) {\n        if (type == &mp_type_object) {\n            // Not a \"real\" type, end search here.\n            return count;\n        } else if (mp_obj_is_native_type(type)) {\n            // Native types don't have parents (at least not from our perspective) so end.\n            *last_native_base = type;\n            return count + 1;\n        } else if (type->parent == NULL) {\n            // No parents so end search here.\n            return count;\n        #if MICROPY_MULTIPLE_INHERITANCE\n        } else if (((mp_obj_base_t *)type->parent)->type == &mp_type_tuple) {\n            // Multiple parents, search through them all recursively.\n            const mp_obj_tuple_t *parent_tuple = type->parent;\n            const mp_obj_t *item = parent_tuple->items;\n            const mp_obj_t *top = item + parent_tuple->len;\n            for (; item < top; ++item) {\n                assert(mp_obj_is_type(*item, &mp_type_type));\n                const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(*item);\n                count += instance_count_native_bases(bt, last_native_base);\n            }\n            return count;\n        #endif\n        } else {\n            // A single parent, use iteration to continue the search.\n            type = type->parent;\n        }\n    }\n}\n\n// This wrapper function is allows a subclass of a native type to call the\n// __init__() method (corresponding to type->make_new) of the native type.\nSTATIC mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) {\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(args[0]);\n    const mp_obj_type_t *native_base = NULL;\n    instance_count_native_bases(self->base.type, &native_base);\n    self->subobj[0] = native_base->make_new(native_base, n_args - 1, 0, args + 1);\n    return mp_const_none;\n}\nSTATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(native_base_init_wrapper_obj, 1, MP_OBJ_FUN_ARGS_MAX, native_base_init_wrapper);\n\n#if !MICROPY_CPYTHON_COMPAT\nSTATIC\n#endif\nmp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_type_t **native_base) {\n    size_t num_native_bases = instance_count_native_bases(class, native_base);\n    assert(num_native_bases < 2);\n    mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, num_native_bases);\n    o->base.type = class;\n    mp_map_init(&o->members, 0);\n    // Initialise the native base-class slot (should be 1 at most) with a valid\n    // object.  It doesn't matter which object, so long as it can be uniquely\n    // distinguished from a native class that is initialised.\n    if (num_native_bases != 0) {\n        o->subobj[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj);\n    }\n    return o;\n}\n\n// TODO\n// This implements depth-first left-to-right MRO, which is not compliant with Python3 MRO\n// http://python-history.blogspot.com/2010/06/method-resolution-order.html\n// https://www.python.org/download/releases/2.3/mro/\n//\n// will keep lookup->dest[0]'s value (should be MP_OBJ_NULL on invocation) if attribute\n// is not found\n// will set lookup->dest[0] to MP_OBJ_SENTINEL if special method was found in a native\n// type base via slot id (as specified by lookup->meth_offset). As there can be only one\n// native base, it's known that it applies to instance->subobj[0]. In most cases, we also\n// don't need to know which type it was - because instance->subobj[0] is of that type.\n// The only exception is when object is not yet constructed, then we need to know base\n// native type to construct its instance->subobj[0] from. But this case is handled via\n// instance_count_native_bases(), which returns a native base which it saw.\nstruct class_lookup_data {\n    mp_obj_instance_t *obj;\n    qstr attr;\n    size_t meth_offset;\n    mp_obj_t *dest;\n    bool is_type;\n};\n\nSTATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_type_t *type) {\n    assert(lookup->dest[0] == MP_OBJ_NULL);\n    assert(lookup->dest[1] == MP_OBJ_NULL);\n    for (;;) {\n        DEBUG_printf(\"mp_obj_class_lookup: Looking up %s in %s\\n\", qstr_str(lookup->attr), qstr_str(type->name));\n        // Optimize special method lookup for native types\n        // This avoids extra method_name => slot lookup. On the other hand,\n        // this should not be applied to class types, as will result in extra\n        // lookup either.\n        if (lookup->meth_offset != 0 && mp_obj_is_native_type(type)) {\n            if (*(void **)((char *)type + lookup->meth_offset) != NULL) {\n                DEBUG_printf(\"mp_obj_class_lookup: Matched special meth slot (off=%d) for %s\\n\",\n                    lookup->meth_offset, qstr_str(lookup->attr));\n                lookup->dest[0] = MP_OBJ_SENTINEL;\n                return;\n            }\n        }\n\n        if (type->locals_dict != NULL) {\n            // search locals_dict (the set of methods/attributes)\n            assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(type->locals_dict))); // MicroPython restriction, for now\n            mp_map_t *locals_map = &type->locals_dict->map;\n            mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(lookup->attr), MP_MAP_LOOKUP);\n            if (elem != NULL) {\n                if (lookup->is_type) {\n                    // If we look up a class method, we need to return original type for which we\n                    // do a lookup, not a (base) type in which we found the class method.\n                    const mp_obj_type_t *org_type = (const mp_obj_type_t *)lookup->obj;\n                    mp_convert_member_lookup(MP_OBJ_NULL, org_type, elem->value, lookup->dest);\n                } else {\n                    mp_obj_instance_t *obj = lookup->obj;\n                    mp_obj_t obj_obj;\n                    if (obj != NULL && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) {\n                        // If we're dealing with native base class, then it applies to native sub-object\n                        obj_obj = obj->subobj[0];\n                    } else {\n                        obj_obj = MP_OBJ_FROM_PTR(obj);\n                    }\n                    mp_convert_member_lookup(obj_obj, type, elem->value, lookup->dest);\n                }\n                #if DEBUG_PRINT\n                DEBUG_printf(\"mp_obj_class_lookup: Returning: \");\n                mp_obj_print_helper(MICROPY_DEBUG_PRINTER, lookup->dest[0], PRINT_REPR);\n                if (lookup->dest[1] != MP_OBJ_NULL) {\n                    // Don't try to repr() lookup->dest[1], as we can be called recursively\n                    DEBUG_printf(\" <%s @%p>\", mp_obj_get_type_str(lookup->dest[1]), MP_OBJ_TO_PTR(lookup->dest[1]));\n                }\n                DEBUG_printf(\"\\n\");\n                #endif\n                return;\n            }\n        }\n\n        // Previous code block takes care about attributes defined in .locals_dict,\n        // but some attributes of native types may be handled using .load_attr method,\n        // so make sure we try to lookup those too.\n        if (lookup->obj != NULL && !lookup->is_type && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) {\n            mp_load_method_maybe(lookup->obj->subobj[0], lookup->attr, lookup->dest);\n            if (lookup->dest[0] != MP_OBJ_NULL) {\n                return;\n            }\n        }\n\n        // attribute not found, keep searching base classes\n\n        if (type->parent == NULL) {\n            DEBUG_printf(\"mp_obj_class_lookup: No more parents\\n\");\n            return;\n        #if MICROPY_MULTIPLE_INHERITANCE\n        } else if (((mp_obj_base_t *)type->parent)->type == &mp_type_tuple) {\n            const mp_obj_tuple_t *parent_tuple = type->parent;\n            const mp_obj_t *item = parent_tuple->items;\n            const mp_obj_t *top = item + parent_tuple->len - 1;\n            for (; item < top; ++item) {\n                assert(mp_obj_is_type(*item, &mp_type_type));\n                mp_obj_type_t *bt = (mp_obj_type_t *)MP_OBJ_TO_PTR(*item);\n                if (bt == &mp_type_object) {\n                    // Not a \"real\" type\n                    continue;\n                }\n                mp_obj_class_lookup(lookup, bt);\n                if (lookup->dest[0] != MP_OBJ_NULL) {\n                    return;\n                }\n            }\n\n            // search last base (simple tail recursion elimination)\n            assert(mp_obj_is_type(*item, &mp_type_type));\n            type = (mp_obj_type_t *)MP_OBJ_TO_PTR(*item);\n        #endif\n        } else {\n            type = type->parent;\n        }\n        if (type == &mp_type_object) {\n            // Not a \"real\" type\n            return;\n        }\n    }\n}\n\nSTATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__;\n    mp_obj_t member[2] = {MP_OBJ_NULL};\n    struct class_lookup_data lookup = {\n        .obj = self,\n        .attr = meth,\n        .meth_offset = offsetof(mp_obj_type_t, print),\n        .dest = member,\n        .is_type = false,\n    };\n    mp_obj_class_lookup(&lookup, self->base.type);\n    if (member[0] == MP_OBJ_NULL && kind == PRINT_STR) {\n        // If there's no __str__, fall back to __repr__\n        lookup.attr = MP_QSTR___repr__;\n        lookup.meth_offset = 0;\n        mp_obj_class_lookup(&lookup, self->base.type);\n    }\n\n    if (member[0] == MP_OBJ_SENTINEL) {\n        // Handle Exception subclasses specially\n        if (mp_obj_is_native_exception_instance(self->subobj[0])) {\n            if (kind != PRINT_STR) {\n                mp_print_str(print, qstr_str(self->base.type->name));\n            }\n            mp_obj_print_helper(print, self->subobj[0], kind | PRINT_EXC_SUBCLASS);\n        } else {\n            mp_obj_print_helper(print, self->subobj[0], kind);\n        }\n        return;\n    }\n\n    if (member[0] != MP_OBJ_NULL) {\n        mp_obj_t r = mp_call_function_1(member[0], self_in);\n        mp_obj_print_helper(print, r, PRINT_STR);\n        return;\n    }\n\n    // TODO: CPython prints fully-qualified type name\n    mp_printf(print, \"<%s object at %p>\", mp_obj_get_type_str(self_in), self);\n}\n\nmp_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) {\n    assert(mp_obj_is_instance_type(self));\n\n    // look for __new__ function\n    mp_obj_t init_fn[2] = {MP_OBJ_NULL};\n    struct class_lookup_data lookup = {\n        .obj = NULL,\n        .attr = MP_QSTR___new__,\n        .meth_offset = offsetof(mp_obj_type_t, make_new),\n        .dest = init_fn,\n        .is_type = false,\n    };\n    mp_obj_class_lookup(&lookup, self);\n\n    const mp_obj_type_t *native_base = NULL;\n    mp_obj_instance_t *o;\n    if (init_fn[0] == MP_OBJ_NULL || init_fn[0] == MP_OBJ_SENTINEL) {\n        // Either there is no __new__() method defined or there is a native\n        // constructor.  In both cases create a blank instance.\n        o = mp_obj_new_instance(self, &native_base);\n\n        // Since type->make_new() implements both __new__() and __init__() in\n        // one go, of which the latter may be overridden by the Python subclass,\n        // we defer (see the end of this function) the call of the native\n        // constructor to give a chance for the Python __init__() method to call\n        // said native constructor.\n\n    } else {\n        // Call Python class __new__ function with all args to create an instance\n        mp_obj_t new_ret;\n        if (n_args == 0 && n_kw == 0) {\n            mp_obj_t args2[1] = {MP_OBJ_FROM_PTR(self)};\n            new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, args2);\n        } else {\n            mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw);\n            args2[0] = MP_OBJ_FROM_PTR(self);\n            memcpy(args2 + 1, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));\n            new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2);\n            m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw);\n        }\n\n        // https://docs.python.org/3.4/reference/datamodel.html#object.__new__\n        // \"If __new__() does not return an instance of cls, then the new\n        // instance's __init__() method will not be invoked.\"\n        if (mp_obj_get_type(new_ret) != self) {\n            return new_ret;\n        }\n\n        // The instance returned by __new__() becomes the new object\n        o = MP_OBJ_TO_PTR(new_ret);\n    }\n\n    // now call Python class __init__ function with all args\n    // This method has a chance to call super().__init__() to construct a\n    // possible native base class.\n    init_fn[0] = init_fn[1] = MP_OBJ_NULL;\n    lookup.obj = o;\n    lookup.attr = MP_QSTR___init__;\n    lookup.meth_offset = 0;\n    mp_obj_class_lookup(&lookup, self);\n    if (init_fn[0] != MP_OBJ_NULL) {\n        mp_obj_t init_ret;\n        if (n_args == 0 && n_kw == 0) {\n            init_ret = mp_call_method_n_kw(0, 0, init_fn);\n        } else {\n            mp_obj_t *args2 = m_new(mp_obj_t, 2 + n_args + 2 * n_kw);\n            args2[0] = init_fn[0];\n            args2[1] = init_fn[1];\n            memcpy(args2 + 2, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));\n            init_ret = mp_call_method_n_kw(n_args, n_kw, args2);\n            m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw);\n        }\n        if (init_ret != mp_const_none) {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_raise_TypeError(MP_ERROR_TEXT(\"__init__() should return None\"));\n            #else\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"__init__() should return None, not '%s'\"), mp_obj_get_type_str(init_ret));\n            #endif\n        }\n    }\n\n    // If the type had a native base that was not explicitly initialised\n    // (constructed) by the Python __init__() method then construct it now.\n    if (native_base != NULL && o->subobj[0] == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) {\n        o->subobj[0] = native_base->make_new(native_base, n_args, n_kw, args);\n    }\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\n// Qstrs for special methods are guaranteed to have a small value, so we use byte\n// type to represent them.\nconst byte mp_unary_op_method_name[MP_UNARY_OP_NUM_RUNTIME] = {\n    [MP_UNARY_OP_BOOL] = MP_QSTR___bool__,\n    [MP_UNARY_OP_LEN] = MP_QSTR___len__,\n    [MP_UNARY_OP_HASH] = MP_QSTR___hash__,\n    [MP_UNARY_OP_INT] = MP_QSTR___int__,\n    #if MICROPY_PY_ALL_SPECIAL_METHODS\n    [MP_UNARY_OP_POSITIVE] = MP_QSTR___pos__,\n    [MP_UNARY_OP_NEGATIVE] = MP_QSTR___neg__,\n    [MP_UNARY_OP_INVERT] = MP_QSTR___invert__,\n    [MP_UNARY_OP_ABS] = MP_QSTR___abs__,\n    #endif\n    #if MICROPY_PY_SYS_GETSIZEOF\n    [MP_UNARY_OP_SIZEOF] = MP_QSTR___sizeof__,\n    #endif\n};\n\nSTATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n\n    #if MICROPY_PY_SYS_GETSIZEOF\n    if (MP_UNLIKELY(op == MP_UNARY_OP_SIZEOF)) {\n        // TODO: This doesn't count inherited objects (self->subobj)\n        const mp_obj_type_t *native_base;\n        size_t num_native_bases = instance_count_native_bases(mp_obj_get_type(self_in), &native_base);\n\n        size_t sz = sizeof(*self) + sizeof(*self->subobj) * num_native_bases\n            + sizeof(*self->members.table) * self->members.alloc;\n        return MP_OBJ_NEW_SMALL_INT(sz);\n    }\n    #endif\n\n    qstr op_name = mp_unary_op_method_name[op];\n    /* Still try to lookup native slot\n    if (op_name == 0) {\n        return MP_OBJ_NULL;\n    }\n    */\n    mp_obj_t member[2] = {MP_OBJ_NULL};\n    struct class_lookup_data lookup = {\n        .obj = self,\n        .attr = op_name,\n        .meth_offset = offsetof(mp_obj_type_t, unary_op),\n        .dest = member,\n        .is_type = false,\n    };\n    mp_obj_class_lookup(&lookup, self->base.type);\n    if (member[0] == MP_OBJ_SENTINEL) {\n        return mp_unary_op(op, self->subobj[0]);\n    } else if (member[0] != MP_OBJ_NULL) {\n        mp_obj_t val = mp_call_function_1(member[0], self_in);\n\n        switch (op) {\n            case MP_UNARY_OP_HASH:\n                // __hash__ must return a small int\n                val = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int_truncated(val));\n                break;\n            case MP_UNARY_OP_INT:\n                // Must return int\n                if (!mp_obj_is_int(val)) {\n                    mp_raise_TypeError(NULL);\n                }\n                break;\n            default:\n                // No need to do anything\n                ;\n        }\n        return val;\n    } else {\n        if (op == MP_UNARY_OP_HASH) {\n            lookup.attr = MP_QSTR___eq__;\n            mp_obj_class_lookup(&lookup, self->base.type);\n            if (member[0] == MP_OBJ_NULL) {\n                // https://docs.python.org/3/reference/datamodel.html#object.__hash__\n                // \"User-defined classes have __eq__() and __hash__() methods by default;\n                // with them, all objects compare unequal (except with themselves) and\n                // x.__hash__() returns an appropriate value such that x == y implies\n                // both that x is y and hash(x) == hash(y).\"\n                return MP_OBJ_NEW_SMALL_INT((mp_uint_t)self_in);\n            }\n            // \"A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None.\n            // When the __hash__() method of a class is None, instances of the class will raise an appropriate TypeError\"\n        }\n\n        return MP_OBJ_NULL; // op not supported\n    }\n}\n\n// Binary-op enum values not listed here will have the default value of 0 in the\n// table, corresponding to MP_QSTRnull, and are therefore unsupported (a lookup will\n// fail).  They can be added at the expense of code size for the qstr.\n// Qstrs for special methods are guaranteed to have a small value, so we use byte\n// type to represent them.\nconst byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = {\n    [MP_BINARY_OP_LESS] = MP_QSTR___lt__,\n    [MP_BINARY_OP_MORE] = MP_QSTR___gt__,\n    [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__,\n    [MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__,\n    [MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__,\n    [MP_BINARY_OP_NOT_EQUAL] = MP_QSTR___ne__,\n    [MP_BINARY_OP_CONTAINS] = MP_QSTR___contains__,\n\n    // If an inplace method is not found a normal method will be used as a fallback\n    [MP_BINARY_OP_INPLACE_ADD] = MP_QSTR___iadd__,\n    [MP_BINARY_OP_INPLACE_SUBTRACT] = MP_QSTR___isub__,\n    #if MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS\n    [MP_BINARY_OP_INPLACE_MULTIPLY] = MP_QSTR___imul__,\n    [MP_BINARY_OP_INPLACE_MAT_MULTIPLY] = MP_QSTR___imatmul__,\n    [MP_BINARY_OP_INPLACE_FLOOR_DIVIDE] = MP_QSTR___ifloordiv__,\n    [MP_BINARY_OP_INPLACE_TRUE_DIVIDE] = MP_QSTR___itruediv__,\n    [MP_BINARY_OP_INPLACE_MODULO] = MP_QSTR___imod__,\n    [MP_BINARY_OP_INPLACE_POWER] = MP_QSTR___ipow__,\n    [MP_BINARY_OP_INPLACE_OR] = MP_QSTR___ior__,\n    [MP_BINARY_OP_INPLACE_XOR] = MP_QSTR___ixor__,\n    [MP_BINARY_OP_INPLACE_AND] = MP_QSTR___iand__,\n    [MP_BINARY_OP_INPLACE_LSHIFT] = MP_QSTR___ilshift__,\n    [MP_BINARY_OP_INPLACE_RSHIFT] = MP_QSTR___irshift__,\n    #endif\n\n    [MP_BINARY_OP_ADD] = MP_QSTR___add__,\n    [MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__,\n    #if MICROPY_PY_ALL_SPECIAL_METHODS\n    [MP_BINARY_OP_MULTIPLY] = MP_QSTR___mul__,\n    [MP_BINARY_OP_MAT_MULTIPLY] = MP_QSTR___matmul__,\n    [MP_BINARY_OP_FLOOR_DIVIDE] = MP_QSTR___floordiv__,\n    [MP_BINARY_OP_TRUE_DIVIDE] = MP_QSTR___truediv__,\n    [MP_BINARY_OP_MODULO] = MP_QSTR___mod__,\n    [MP_BINARY_OP_DIVMOD] = MP_QSTR___divmod__,\n    [MP_BINARY_OP_POWER] = MP_QSTR___pow__,\n    [MP_BINARY_OP_OR] = MP_QSTR___or__,\n    [MP_BINARY_OP_XOR] = MP_QSTR___xor__,\n    [MP_BINARY_OP_AND] = MP_QSTR___and__,\n    [MP_BINARY_OP_LSHIFT] = MP_QSTR___lshift__,\n    [MP_BINARY_OP_RSHIFT] = MP_QSTR___rshift__,\n    #endif\n\n    #if MICROPY_PY_REVERSE_SPECIAL_METHODS\n    [MP_BINARY_OP_REVERSE_ADD] = MP_QSTR___radd__,\n    [MP_BINARY_OP_REVERSE_SUBTRACT] = MP_QSTR___rsub__,\n    #if MICROPY_PY_ALL_SPECIAL_METHODS\n    [MP_BINARY_OP_REVERSE_MULTIPLY] = MP_QSTR___rmul__,\n    [MP_BINARY_OP_REVERSE_MAT_MULTIPLY] = MP_QSTR___rmatmul__,\n    [MP_BINARY_OP_REVERSE_FLOOR_DIVIDE] = MP_QSTR___rfloordiv__,\n    [MP_BINARY_OP_REVERSE_TRUE_DIVIDE] = MP_QSTR___rtruediv__,\n    [MP_BINARY_OP_REVERSE_MODULO] = MP_QSTR___rmod__,\n    [MP_BINARY_OP_REVERSE_POWER] = MP_QSTR___rpow__,\n    [MP_BINARY_OP_REVERSE_OR] = MP_QSTR___ror__,\n    [MP_BINARY_OP_REVERSE_XOR] = MP_QSTR___rxor__,\n    [MP_BINARY_OP_REVERSE_AND] = MP_QSTR___rand__,\n    [MP_BINARY_OP_REVERSE_LSHIFT] = MP_QSTR___rlshift__,\n    [MP_BINARY_OP_REVERSE_RSHIFT] = MP_QSTR___rrshift__,\n    #endif\n    #endif\n};\n\nSTATIC mp_obj_t instance_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    // Note: For ducktyping, CPython does not look in the instance members or use\n    // __getattr__ or __getattribute__.  It only looks in the class dictionary.\n    mp_obj_instance_t *lhs = MP_OBJ_TO_PTR(lhs_in);\nretry:;\n    qstr op_name = mp_binary_op_method_name[op];\n    /* Still try to lookup native slot\n    if (op_name == 0) {\n        return MP_OBJ_NULL;\n    }\n    */\n    mp_obj_t dest[3] = {MP_OBJ_NULL};\n    struct class_lookup_data lookup = {\n        .obj = lhs,\n        .attr = op_name,\n        .meth_offset = offsetof(mp_obj_type_t, binary_op),\n        .dest = dest,\n        .is_type = false,\n    };\n    mp_obj_class_lookup(&lookup, lhs->base.type);\n\n    mp_obj_t res;\n    if (dest[0] == MP_OBJ_SENTINEL) {\n        res = mp_binary_op(op, lhs->subobj[0], rhs_in);\n    } else if (dest[0] != MP_OBJ_NULL) {\n        dest[2] = rhs_in;\n        res = mp_call_method_n_kw(1, 0, dest);\n    } else {\n        // If this was an inplace method, fallback to normal method\n        // https://docs.python.org/3/reference/datamodel.html#object.__iadd__ :\n        // \"If a specific method is not defined, the augmented assignment\n        // falls back to the normal methods.\"\n        if (op >= MP_BINARY_OP_INPLACE_OR && op <= MP_BINARY_OP_INPLACE_POWER) {\n            op -= MP_BINARY_OP_INPLACE_OR - MP_BINARY_OP_OR;\n            goto retry;\n        }\n        return MP_OBJ_NULL; // op not supported\n    }\n\n    #if MICROPY_PY_BUILTINS_NOTIMPLEMENTED\n    // NotImplemented means \"try other fallbacks (like calling __rop__\n    // instead of __op__) and if nothing works, raise TypeError\". As\n    // MicroPython doesn't implement any fallbacks, signal to raise\n    // TypeError right away.\n    if (res == mp_const_notimplemented) {\n        return MP_OBJ_NULL; // op not supported\n    }\n    #endif\n\n    return res;\n}\n\nSTATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    // logic: look in instance members then class locals\n    assert(mp_obj_is_instance_type(mp_obj_get_type(self_in)));\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n\n    mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);\n    if (elem != NULL) {\n        // object member, always treated as a value\n        dest[0] = elem->value;\n        return;\n    }\n    #if MICROPY_CPYTHON_COMPAT\n    if (attr == MP_QSTR___dict__) {\n        // Create a new dict with a copy of the instance's map items.\n        // This creates, unlike CPython, a read-only __dict__ that can't be modified.\n        mp_obj_dict_t dict;\n        dict.base.type = &mp_type_dict;\n        dict.map = self->members;\n        dest[0] = mp_obj_dict_copy(MP_OBJ_FROM_PTR(&dict));\n        mp_obj_dict_t *dest_dict = MP_OBJ_TO_PTR(dest[0]);\n        dest_dict->map.is_fixed = 1;\n        return;\n    }\n    #endif\n    struct class_lookup_data lookup = {\n        .obj = self,\n        .attr = attr,\n        .meth_offset = 0,\n        .dest = dest,\n        .is_type = false,\n    };\n    mp_obj_class_lookup(&lookup, self->base.type);\n    mp_obj_t member = dest[0];\n    if (member != MP_OBJ_NULL) {\n        if (!(self->base.type->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {\n            // Class doesn't have any special accessors to check so return straightaway\n            return;\n        }\n\n        #if MICROPY_PY_BUILTINS_PROPERTY\n        if (mp_obj_is_type(member, &mp_type_property)) {\n            // object member is a property; delegate the load to the property\n            // Note: This is an optimisation for code size and execution time.\n            // The proper way to do it is have the functionality just below\n            // in a __get__ method of the property object, and then it would\n            // be called by the descriptor code down below.  But that way\n            // requires overhead for the nested mp_call's and overhead for\n            // the code.\n            const mp_obj_t *proxy = mp_obj_property_get(member);\n            if (proxy[0] == mp_const_none) {\n                mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT(\"unreadable attribute\"));\n            } else {\n                dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in);\n            }\n            return;\n        }\n        #endif\n\n        #if MICROPY_PY_DESCRIPTORS\n        // found a class attribute; if it has a __get__ method then call it with the\n        // class instance and class as arguments and return the result\n        // Note that this is functionally correct but very slow: each load_attr\n        // requires an extra mp_load_method_maybe to check for the __get__.\n        mp_obj_t attr_get_method[4];\n        mp_load_method_maybe(member, MP_QSTR___get__, attr_get_method);\n        if (attr_get_method[0] != MP_OBJ_NULL) {\n            attr_get_method[2] = self_in;\n            attr_get_method[3] = MP_OBJ_FROM_PTR(mp_obj_get_type(self_in));\n            dest[0] = mp_call_method_n_kw(2, 0, attr_get_method);\n        }\n        #endif\n        return;\n    }\n\n    // try __getattr__\n    if (attr != MP_QSTR___getattr__) {\n        #if MICROPY_PY_DELATTR_SETATTR\n        // If the requested attr is __setattr__/__delattr__ then don't delegate the lookup\n        // to __getattr__.  If we followed CPython's behaviour then __setattr__/__delattr__\n        // would have already been found in the \"object\" base class.\n        if (attr == MP_QSTR___setattr__ || attr == MP_QSTR___delattr__) {\n            return;\n        }\n        #endif\n\n        mp_obj_t dest2[3];\n        mp_load_method_maybe(self_in, MP_QSTR___getattr__, dest2);\n        if (dest2[0] != MP_OBJ_NULL) {\n            // __getattr__ exists, call it and return its result\n            dest2[2] = MP_OBJ_NEW_QSTR(attr);\n            dest[0] = mp_call_method_n_kw(1, 0, dest2);\n            return;\n        }\n    }\n}\n\nSTATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (!(self->base.type->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {\n        // Class doesn't have any special accessors so skip their checks\n        goto skip_special_accessors;\n    }\n\n    #if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS\n    // With property and/or descriptors enabled we need to do a lookup\n    // first in the class dict for the attribute to see if the store should\n    // be delegated.\n    mp_obj_t member[2] = {MP_OBJ_NULL};\n    struct class_lookup_data lookup = {\n        .obj = self,\n        .attr = attr,\n        .meth_offset = 0,\n        .dest = member,\n        .is_type = false,\n    };\n    mp_obj_class_lookup(&lookup, self->base.type);\n\n    if (member[0] != MP_OBJ_NULL) {\n        #if MICROPY_PY_BUILTINS_PROPERTY\n        if (mp_obj_is_type(member[0], &mp_type_property)) {\n            // attribute exists and is a property; delegate the store/delete\n            // Note: This is an optimisation for code size and execution time.\n            // The proper way to do it is have the functionality just below in\n            // a __set__/__delete__ method of the property object, and then it\n            // would be called by the descriptor code down below.  But that way\n            // requires overhead for the nested mp_call's and overhead for\n            // the code.\n            const mp_obj_t *proxy = mp_obj_property_get(member[0]);\n            mp_obj_t dest[2] = {self_in, value};\n            if (value == MP_OBJ_NULL) {\n                // delete attribute\n                if (proxy[2] == mp_const_none) {\n                    // TODO better error message?\n                    return false;\n                } else {\n                    mp_call_function_n_kw(proxy[2], 1, 0, dest);\n                    return true;\n                }\n            } else {\n                // store attribute\n                if (proxy[1] == mp_const_none) {\n                    // TODO better error message?\n                    return false;\n                } else {\n                    mp_call_function_n_kw(proxy[1], 2, 0, dest);\n                    return true;\n                }\n            }\n        }\n        #endif\n\n        #if MICROPY_PY_DESCRIPTORS\n        // found a class attribute; if it has a __set__/__delete__ method then\n        // call it with the class instance (and value) as arguments\n        if (value == MP_OBJ_NULL) {\n            // delete attribute\n            mp_obj_t attr_delete_method[3];\n            mp_load_method_maybe(member[0], MP_QSTR___delete__, attr_delete_method);\n            if (attr_delete_method[0] != MP_OBJ_NULL) {\n                attr_delete_method[2] = self_in;\n                mp_call_method_n_kw(1, 0, attr_delete_method);\n                return true;\n            }\n        } else {\n            // store attribute\n            mp_obj_t attr_set_method[4];\n            mp_load_method_maybe(member[0], MP_QSTR___set__, attr_set_method);\n            if (attr_set_method[0] != MP_OBJ_NULL) {\n                attr_set_method[2] = self_in;\n                attr_set_method[3] = value;\n                mp_call_method_n_kw(2, 0, attr_set_method);\n                return true;\n            }\n        }\n        #endif\n    }\n    #endif\n\n    #if MICROPY_PY_DELATTR_SETATTR\n    if (value == MP_OBJ_NULL) {\n        // delete attribute\n        // try __delattr__ first\n        mp_obj_t attr_delattr_method[3];\n        mp_load_method_maybe(self_in, MP_QSTR___delattr__, attr_delattr_method);\n        if (attr_delattr_method[0] != MP_OBJ_NULL) {\n            // __delattr__ exists, so call it\n            attr_delattr_method[2] = MP_OBJ_NEW_QSTR(attr);\n            mp_call_method_n_kw(1, 0, attr_delattr_method);\n            return true;\n        }\n    } else {\n        // store attribute\n        // try __setattr__ first\n        mp_obj_t attr_setattr_method[4];\n        mp_load_method_maybe(self_in, MP_QSTR___setattr__, attr_setattr_method);\n        if (attr_setattr_method[0] != MP_OBJ_NULL) {\n            // __setattr__ exists, so call it\n            attr_setattr_method[2] = MP_OBJ_NEW_QSTR(attr);\n            attr_setattr_method[3] = value;\n            mp_call_method_n_kw(2, 0, attr_setattr_method);\n            return true;\n        }\n    }\n    #endif\n\nskip_special_accessors:\n\n    if (value == MP_OBJ_NULL) {\n        // delete attribute\n        mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);\n        return elem != NULL;\n    } else {\n        // store attribute\n        mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;\n        return true;\n    }\n}\n\nSTATIC void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] == MP_OBJ_NULL) {\n        mp_obj_instance_load_attr(self_in, attr, dest);\n    } else {\n        if (mp_obj_instance_store_attr(self_in, attr, dest[1])) {\n            dest[0] = MP_OBJ_NULL; // indicate success\n        }\n    }\n}\n\nSTATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t member[4] = {MP_OBJ_NULL, MP_OBJ_NULL, index, value};\n    struct class_lookup_data lookup = {\n        .obj = self,\n        .meth_offset = offsetof(mp_obj_type_t, subscr),\n        .dest = member,\n        .is_type = false,\n    };\n    if (value == MP_OBJ_NULL) {\n        // delete item\n        lookup.attr = MP_QSTR___delitem__;\n    } else if (value == MP_OBJ_SENTINEL) {\n        // load item\n        lookup.attr = MP_QSTR___getitem__;\n    } else {\n        // store item\n        lookup.attr = MP_QSTR___setitem__;\n    }\n    mp_obj_class_lookup(&lookup, self->base.type);\n    if (member[0] == MP_OBJ_SENTINEL) {\n        return mp_obj_subscr(self->subobj[0], index, value);\n    } else if (member[0] != MP_OBJ_NULL) {\n        size_t n_args = value == MP_OBJ_NULL || value == MP_OBJ_SENTINEL ? 1 : 2;\n        mp_obj_t ret = mp_call_method_n_kw(n_args, 0, member);\n        if (value == MP_OBJ_SENTINEL) {\n            return ret;\n        } else {\n            return mp_const_none;\n        }\n    } else {\n        return MP_OBJ_NULL; // op not supported\n    }\n}\n\nSTATIC mp_obj_t mp_obj_instance_get_call(mp_obj_t self_in, mp_obj_t *member) {\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    struct class_lookup_data lookup = {\n        .obj = self,\n        .attr = MP_QSTR___call__,\n        .meth_offset = offsetof(mp_obj_type_t, call),\n        .dest = member,\n        .is_type = false,\n    };\n    mp_obj_class_lookup(&lookup, self->base.type);\n    return member[0];\n}\n\nbool mp_obj_instance_is_callable(mp_obj_t self_in) {\n    mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL};\n    return mp_obj_instance_get_call(self_in, member) != MP_OBJ_NULL;\n}\n\nmp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL};\n    mp_obj_t call = mp_obj_instance_get_call(self_in, member);\n    if (call == MP_OBJ_NULL) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_TypeError(MP_ERROR_TEXT(\"object not callable\"));\n        #else\n        mp_raise_msg_varg(&mp_type_TypeError,\n            MP_ERROR_TEXT(\"'%s' object isn't callable\"), mp_obj_get_type_str(self_in));\n        #endif\n    }\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    if (call == MP_OBJ_SENTINEL) {\n        return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args);\n    }\n\n    return mp_call_method_self_n_kw(member[0], member[1], n_args, n_kw, args);\n}\n\n// Note that iter_buf may be NULL, and needs to be allocated if needed\nmp_obj_t mp_obj_instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t member[2] = {MP_OBJ_NULL};\n    struct class_lookup_data lookup = {\n        .obj = self,\n        .attr = MP_QSTR___iter__,\n        .meth_offset = offsetof(mp_obj_type_t, getiter),\n        .dest = member,\n        .is_type = false,\n    };\n    mp_obj_class_lookup(&lookup, self->base.type);\n    if (member[0] == MP_OBJ_NULL) {\n        return MP_OBJ_NULL;\n    } else if (member[0] == MP_OBJ_SENTINEL) {\n        const mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]);\n        if (iter_buf == NULL) {\n            iter_buf = m_new_obj(mp_obj_iter_buf_t);\n        }\n        return type->getiter(self->subobj[0], iter_buf);\n    } else {\n        return mp_call_method_n_kw(0, 0, member);\n    }\n}\n\nSTATIC mp_int_t instance_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {\n    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_obj_t member[2] = {MP_OBJ_NULL};\n    struct class_lookup_data lookup = {\n        .obj = self,\n        .attr = MP_QSTR_, // don't actually look for a method\n        .meth_offset = offsetof(mp_obj_type_t, buffer_p.get_buffer),\n        .dest = member,\n        .is_type = false,\n    };\n    mp_obj_class_lookup(&lookup, self->base.type);\n    if (member[0] == MP_OBJ_SENTINEL) {\n        const mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]);\n        return type->buffer_p.get_buffer(self->subobj[0], bufinfo, flags);\n    } else {\n        return 1; // object does not support buffer protocol\n    }\n}\n\n/******************************************************************************/\n// type object\n//  - the struct is mp_obj_type_t and is defined in obj.h so const types can be made\n//  - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object\n//  - creating a new class (a new type) creates a new mp_obj_type_t\n\n#if ENABLE_SPECIAL_ACCESSORS\nSTATIC bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) {\n    #if MICROPY_PY_DELATTR_SETATTR\n    if (key == MP_OBJ_NEW_QSTR(MP_QSTR___setattr__) || key == MP_OBJ_NEW_QSTR(MP_QSTR___delattr__)) {\n        return true;\n    }\n    #endif\n    #if MICROPY_PY_BUILTINS_PROPERTY\n    if (mp_obj_is_type(value, &mp_type_property)) {\n        return true;\n    }\n    #endif\n    #if MICROPY_PY_DESCRIPTORS\n    static const uint8_t to_check[] = {\n        MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__,\n    };\n    for (size_t i = 0; i < MP_ARRAY_SIZE(to_check); ++i) {\n        mp_obj_t dest_temp[2];\n        mp_load_method_protected(value, to_check[i], dest_temp, true);\n        if (dest_temp[0] != MP_OBJ_NULL) {\n            return true;\n        }\n    }\n    #endif\n    return false;\n}\n#endif\n\nSTATIC void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_printf(print, \"<class '%q'>\", self->name);\n}\n\nSTATIC 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) {\n    (void)type_in;\n\n    mp_arg_check_num(n_args, n_kw, 1, 3, false);\n\n    switch (n_args) {\n        case 1:\n            return MP_OBJ_FROM_PTR(mp_obj_get_type(args[0]));\n\n        case 3:\n            // args[0] = name\n            // args[1] = bases tuple\n            // args[2] = locals dict\n            return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]);\n\n        default:\n            mp_raise_TypeError(MP_ERROR_TEXT(\"type takes 1 or 3 arguments\"));\n    }\n}\n\nSTATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    // instantiate an instance of a class\n\n    mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (self->make_new == NULL) {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_TypeError(MP_ERROR_TEXT(\"can't create instance\"));\n        #else\n        mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT(\"can't create '%q' instances\"), self->name);\n        #endif\n    }\n\n    // make new instance\n    mp_obj_t o = self->make_new(self, n_args, n_kw, args);\n\n    // return new instance\n    return o;\n}\n\nSTATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    assert(mp_obj_is_type(self_in, &mp_type_type));\n    mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);\n\n    if (dest[0] == MP_OBJ_NULL) {\n        // load attribute\n        #if MICROPY_CPYTHON_COMPAT\n        if (attr == MP_QSTR___name__) {\n            dest[0] = MP_OBJ_NEW_QSTR(self->name);\n            return;\n        }\n        #if MICROPY_CPYTHON_COMPAT\n        if (attr == MP_QSTR___dict__) {\n            // Returns a read-only dict of the class attributes.\n            // If the internal locals is not fixed, a copy will be created.\n            const mp_obj_dict_t *dict = self->locals_dict;\n            if (!dict) {\n                dict = &mp_const_empty_dict_obj;\n            }\n            if (dict->map.is_fixed) {\n                dest[0] = MP_OBJ_FROM_PTR(dict);\n            } else {\n                dest[0] = mp_obj_dict_copy(MP_OBJ_FROM_PTR(dict));\n                mp_obj_dict_t *dict_copy = MP_OBJ_TO_PTR(dest[0]);\n                dict_copy->map.is_fixed = 1;\n            }\n            return;\n        }\n        #endif\n        if (attr == MP_QSTR___bases__) {\n            if (self == &mp_type_object) {\n                dest[0] = mp_const_empty_tuple;\n                return;\n            }\n            mp_obj_t parent_obj = self->parent ? MP_OBJ_FROM_PTR(self->parent) : MP_OBJ_FROM_PTR(&mp_type_object);\n            #if MICROPY_MULTIPLE_INHERITANCE\n            if (mp_obj_is_type(parent_obj, &mp_type_tuple)) {\n                dest[0] = parent_obj;\n                return;\n            }\n            #endif\n            dest[0] = mp_obj_new_tuple(1, &parent_obj);\n            return;\n        }\n        #endif\n        struct class_lookup_data lookup = {\n            .obj = (mp_obj_instance_t *)self,\n            .attr = attr,\n            .meth_offset = 0,\n            .dest = dest,\n            .is_type = true,\n        };\n        mp_obj_class_lookup(&lookup, self);\n    } else {\n        // delete/store attribute\n\n        if (self->locals_dict != NULL) {\n            assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(self->locals_dict))); // MicroPython restriction, for now\n            mp_map_t *locals_map = &self->locals_dict->map;\n            if (locals_map->is_fixed) {\n                // can't apply delete/store to a fixed map\n                return;\n            }\n            if (dest[1] == MP_OBJ_NULL) {\n                // delete attribute\n                mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);\n                if (elem != NULL) {\n                    dest[0] = MP_OBJ_NULL; // indicate success\n                }\n            } else {\n                #if ENABLE_SPECIAL_ACCESSORS\n                // Check if we add any special accessor methods with this store\n                if (!(self->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {\n                    if (check_for_special_accessors(MP_OBJ_NEW_QSTR(attr), dest[1])) {\n                        if (self->flags & MP_TYPE_FLAG_IS_SUBCLASSED) {\n                            // This class is already subclassed so can't have special accessors added\n                            mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT(\"can't add special method to already-subclassed class\"));\n                        }\n                        self->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS;\n                    }\n                }\n                #endif\n\n                // store attribute\n                mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);\n                elem->value = dest[1];\n                dest[0] = MP_OBJ_NULL; // indicate success\n            }\n        }\n    }\n}\n\nconst mp_obj_type_t mp_type_type = {\n    { &mp_type_type },\n    .name = MP_QSTR_type,\n    .print = type_print,\n    .make_new = type_make_new,\n    .call = type_call,\n    .unary_op = mp_generic_unary_op,\n    .attr = type_attr,\n};\n\nmp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) {\n    // Verify input objects have expected type\n    if (!mp_obj_is_type(bases_tuple, &mp_type_tuple)) {\n        mp_raise_TypeError(NULL);\n    }\n    if (!mp_obj_is_dict_or_ordereddict(locals_dict)) {\n        mp_raise_TypeError(NULL);\n    }\n\n    // TODO might need to make a copy of locals_dict; at least that's how CPython does it\n\n    // Basic validation of base classes\n    uint16_t base_flags = MP_TYPE_FLAG_EQ_NOT_REFLEXIVE\n        | MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_EQ_HAS_NEQ_TEST;\n    size_t bases_len;\n    mp_obj_t *bases_items;\n    mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items);\n    for (size_t i = 0; i < bases_len; i++) {\n        if (!mp_obj_is_type(bases_items[i], &mp_type_type)) {\n            mp_raise_TypeError(NULL);\n        }\n        mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]);\n        // TODO: Verify with CPy, tested on function type\n        if (t->make_new == NULL) {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_raise_TypeError(MP_ERROR_TEXT(\"type isn't an acceptable base type\"));\n            #else\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"type '%q' isn't an acceptable base type\"), t->name);\n            #endif\n        }\n        #if ENABLE_SPECIAL_ACCESSORS\n        if (mp_obj_is_instance_type(t)) {\n            t->flags |= MP_TYPE_FLAG_IS_SUBCLASSED;\n            base_flags |= t->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS;\n        }\n        #endif\n    }\n\n    mp_obj_type_t *o = m_new0(mp_obj_type_t, 1);\n    o->base.type = &mp_type_type;\n    o->flags = base_flags;\n    o->name = name;\n    o->print = instance_print;\n    o->make_new = mp_obj_instance_make_new;\n    o->call = mp_obj_instance_call;\n    o->unary_op = instance_unary_op;\n    o->binary_op = instance_binary_op;\n    o->attr = mp_obj_instance_attr;\n    o->subscr = instance_subscr;\n    o->getiter = mp_obj_instance_getiter;\n    // o->iternext = ; not implemented\n    o->buffer_p.get_buffer = instance_get_buffer;\n\n    if (bases_len > 0) {\n        // Inherit protocol from a base class. This allows to define an\n        // abstract base class which would translate C-level protocol to\n        // Python method calls, and any subclass inheriting from it will\n        // support this feature.\n        o->protocol = ((mp_obj_type_t *)MP_OBJ_TO_PTR(bases_items[0]))->protocol;\n\n        if (bases_len >= 2) {\n            #if MICROPY_MULTIPLE_INHERITANCE\n            o->parent = MP_OBJ_TO_PTR(bases_tuple);\n            #else\n            mp_raise_NotImplementedError(MP_ERROR_TEXT(\"multiple inheritance not supported\"));\n            #endif\n        } else {\n            o->parent = MP_OBJ_TO_PTR(bases_items[0]);\n        }\n    }\n\n    o->locals_dict = MP_OBJ_TO_PTR(locals_dict);\n\n    #if ENABLE_SPECIAL_ACCESSORS\n    // Check if the class has any special accessor methods\n    if (!(o->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {\n        for (size_t i = 0; i < o->locals_dict->map.alloc; i++) {\n            if (mp_map_slot_is_filled(&o->locals_dict->map, i)) {\n                const mp_map_elem_t *elem = &o->locals_dict->map.table[i];\n                if (check_for_special_accessors(elem->key, elem->value)) {\n                    o->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS;\n                    break;\n                }\n            }\n        }\n    }\n    #endif\n\n    const mp_obj_type_t *native_base;\n    size_t num_native_bases = instance_count_native_bases(o, &native_base);\n    if (num_native_bases > 1) {\n        mp_raise_TypeError(MP_ERROR_TEXT(\"multiple bases have instance lay-out conflict\"));\n    }\n\n    mp_map_t *locals_map = &o->locals_dict->map;\n    mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP);\n    if (elem != NULL) {\n        // __new__ slot exists; check if it is a function\n        if (mp_obj_is_fun(elem->value)) {\n            // __new__ is a function, wrap it in a staticmethod decorator\n            elem->value = static_class_method_make_new(&mp_type_staticmethod, 1, 0, &elem->value);\n        }\n    }\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\n/******************************************************************************/\n// super object\n\ntypedef struct _mp_obj_super_t {\n    mp_obj_base_t base;\n    mp_obj_t type;\n    mp_obj_t obj;\n} mp_obj_super_t;\n\nSTATIC void super_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in);\n    mp_print_str(print, \"<super: \");\n    mp_obj_print_helper(print, self->type, PRINT_STR);\n    mp_print_str(print, \", \");\n    mp_obj_print_helper(print, self->obj, PRINT_STR);\n    mp_print_str(print, \">\");\n}\n\nSTATIC 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) {\n    (void)type_in;\n    // 0 arguments are turned into 2 in the compiler\n    // 1 argument is not yet implemented\n    mp_arg_check_num(n_args, n_kw, 2, 2, false);\n    if (!mp_obj_is_type(args[0], &mp_type_type)) {\n        mp_raise_TypeError(NULL);\n    }\n    mp_obj_super_t *o = m_new_obj(mp_obj_super_t);\n    *o = (mp_obj_super_t) {{type_in}, args[0], args[1]};\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] != MP_OBJ_NULL) {\n        // not load attribute\n        return;\n    }\n\n    assert(mp_obj_is_type(self_in, &mp_type_super));\n    mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in);\n\n    assert(mp_obj_is_type(self->type, &mp_type_type));\n\n    mp_obj_type_t *type = MP_OBJ_TO_PTR(self->type);\n\n    struct class_lookup_data lookup = {\n        .obj = MP_OBJ_TO_PTR(self->obj),\n        .attr = attr,\n        .meth_offset = 0,\n        .dest = dest,\n        .is_type = false,\n    };\n\n    // Allow a call super().__init__() to reach any native base classes\n    if (attr == MP_QSTR___init__) {\n        lookup.meth_offset = offsetof(mp_obj_type_t, make_new);\n    }\n\n    if (type->parent == NULL) {\n        // no parents, do nothing\n    #if MICROPY_MULTIPLE_INHERITANCE\n    } else if (((mp_obj_base_t *)type->parent)->type == &mp_type_tuple) {\n        const mp_obj_tuple_t *parent_tuple = type->parent;\n        size_t len = parent_tuple->len;\n        const mp_obj_t *items = parent_tuple->items;\n        for (size_t i = 0; i < len; i++) {\n            assert(mp_obj_is_type(items[i], &mp_type_type));\n            if (MP_OBJ_TO_PTR(items[i]) == &mp_type_object) {\n                // The \"object\" type will be searched at the end of this function,\n                // and we don't want to lookup native methods in object.\n                continue;\n            }\n            mp_obj_class_lookup(&lookup, (mp_obj_type_t *)MP_OBJ_TO_PTR(items[i]));\n            if (dest[0] != MP_OBJ_NULL) {\n                break;\n            }\n        }\n    #endif\n    } else if (type->parent != &mp_type_object) {\n        mp_obj_class_lookup(&lookup, type->parent);\n    }\n\n    if (dest[0] != MP_OBJ_NULL) {\n        if (dest[0] == MP_OBJ_SENTINEL) {\n            // Looked up native __init__ so defer to it\n            dest[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj);\n            dest[1] = self->obj;\n        }\n        return;\n    }\n\n    // Reset meth_offset so we don't look up any native methods in object,\n    // because object never takes up the native base-class slot.\n    lookup.meth_offset = 0;\n\n    mp_obj_class_lookup(&lookup, &mp_type_object);\n}\n\nconst mp_obj_type_t mp_type_super = {\n    { &mp_type_type },\n    .name = MP_QSTR_super,\n    .print = super_print,\n    .make_new = super_make_new,\n    .attr = super_attr,\n};\n\nvoid mp_load_super_method(qstr attr, mp_obj_t *dest) {\n    mp_obj_super_t super = {{&mp_type_super}, dest[1], dest[2]};\n    mp_load_method(MP_OBJ_FROM_PTR(&super), attr, dest);\n}\n\n/******************************************************************************/\n// subclassing and built-ins specific to types\n\n// object and classinfo should be type objects\n// (but the function will fail gracefully if they are not)\nbool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {\n    for (;;) {\n        if (object == classinfo) {\n            return true;\n        }\n\n        // not equivalent classes, keep searching base classes\n\n        // object should always be a type object, but just return false if it's not\n        if (!mp_obj_is_type(object, &mp_type_type)) {\n            return false;\n        }\n\n        const mp_obj_type_t *self = MP_OBJ_TO_PTR(object);\n\n        if (self->parent == NULL) {\n            // type has no parents\n            return false;\n        #if MICROPY_MULTIPLE_INHERITANCE\n        } else if (((mp_obj_base_t *)self->parent)->type == &mp_type_tuple) {\n            // get the base objects (they should be type objects)\n            const mp_obj_tuple_t *parent_tuple = self->parent;\n            const mp_obj_t *item = parent_tuple->items;\n            const mp_obj_t *top = item + parent_tuple->len - 1;\n\n            // iterate through the base objects\n            for (; item < top; ++item) {\n                if (mp_obj_is_subclass_fast(*item, classinfo)) {\n                    return true;\n                }\n            }\n\n            // search last base (simple tail recursion elimination)\n            object = *item;\n        #endif\n        } else {\n            // type has 1 parent\n            object = MP_OBJ_FROM_PTR(self->parent);\n        }\n    }\n}\n\nSTATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) {\n    size_t len;\n    mp_obj_t *items;\n    if (mp_obj_is_type(classinfo, &mp_type_type)) {\n        len = 1;\n        items = &classinfo;\n    } else if (mp_obj_is_type(classinfo, &mp_type_tuple)) {\n        mp_obj_tuple_get(classinfo, &len, &items);\n    } else {\n        mp_raise_TypeError(MP_ERROR_TEXT(\"issubclass() arg 2 must be a class or a tuple of classes\"));\n    }\n\n    for (size_t i = 0; i < len; i++) {\n        // We explicitly check for 'object' here since no-one explicitly derives from it\n        if (items[i] == MP_OBJ_FROM_PTR(&mp_type_object) || mp_obj_is_subclass_fast(object, items[i])) {\n            return mp_const_true;\n        }\n    }\n    return mp_const_false;\n}\n\nSTATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) {\n    if (!mp_obj_is_type(object, &mp_type_type)) {\n        mp_raise_TypeError(MP_ERROR_TEXT(\"issubclass() arg 1 must be a class\"));\n    }\n    return mp_obj_is_subclass(object, classinfo);\n}\n\nMP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj, mp_builtin_issubclass);\n\nSTATIC mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) {\n    return mp_obj_is_subclass(MP_OBJ_FROM_PTR(mp_obj_get_type(object)), classinfo);\n}\n\nMP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance);\n\nmp_obj_t mp_obj_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type) {\n    const mp_obj_type_t *self_type = mp_obj_get_type(self_in);\n\n    if (MP_OBJ_FROM_PTR(self_type) == native_type) {\n        return self_in;\n    } else if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self_type), native_type)) {\n        return MP_OBJ_NULL;\n    } else {\n        mp_obj_instance_t *self = (mp_obj_instance_t *)MP_OBJ_TO_PTR(self_in);\n        return self->subobj[0];\n    }\n}\n\n/******************************************************************************/\n// staticmethod and classmethod types (probably should go in a different file)\n\nSTATIC 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) {\n    assert(self == &mp_type_staticmethod || self == &mp_type_classmethod);\n\n    mp_arg_check_num(n_args, n_kw, 1, 1, false);\n\n    mp_obj_static_class_method_t *o = m_new_obj(mp_obj_static_class_method_t);\n    *o = (mp_obj_static_class_method_t) {{self}, args[0]};\n    return MP_OBJ_FROM_PTR(o);\n}\n\nconst mp_obj_type_t mp_type_staticmethod = {\n    { &mp_type_type },\n    .name = MP_QSTR_staticmethod,\n    .make_new = static_class_method_make_new,\n};\n\nconst mp_obj_type_t mp_type_classmethod = {\n    { &mp_type_type },\n    .name = MP_QSTR_classmethod,\n    .make_new = static_class_method_make_new,\n};\n"
  },
  {
    "path": "py/objtype.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_OBJTYPE_H\n#define MICROPY_INCLUDED_PY_OBJTYPE_H\n\n#include \"py/obj.h\"\n\n// instance object\n// creating an instance of a class makes one of these objects\ntypedef struct _mp_obj_instance_t {\n    mp_obj_base_t base;\n    mp_map_t members;\n    mp_obj_t subobj[];\n    // TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them\n} mp_obj_instance_t;\n\n#if MICROPY_CPYTHON_COMPAT\n// this is needed for object.__new__\nmp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *cls, const mp_obj_type_t **native_base);\n#endif\n\n// these need to be exposed so mp_obj_is_callable can work correctly\nbool mp_obj_instance_is_callable(mp_obj_t self_in);\nmp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args);\n\n#define mp_obj_is_instance_type(type) ((type)->make_new == mp_obj_instance_make_new)\n#define mp_obj_is_native_type(type) ((type)->make_new != mp_obj_instance_make_new)\n// this needs to be exposed for the above macros to work correctly\nmp_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);\n\n// this needs to be exposed for mp_getiter\nmp_obj_t mp_obj_instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf);\n\n#endif // MICROPY_INCLUDED_PY_OBJTYPE_H\n"
  },
  {
    "path": "py/objzip.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"py/objtuple.h\"\n#include \"py/runtime.h\"\n\ntypedef struct _mp_obj_zip_t {\n    mp_obj_base_t base;\n    size_t n_iters;\n    mp_obj_t iters[];\n} mp_obj_zip_t;\n\nSTATIC 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) {\n    mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false);\n\n    mp_obj_zip_t *o = m_new_obj_var(mp_obj_zip_t, mp_obj_t, n_args);\n    o->base.type = type;\n    o->n_iters = n_args;\n    for (size_t i = 0; i < n_args; i++) {\n        o->iters[i] = mp_getiter(args[i], NULL);\n    }\n    return MP_OBJ_FROM_PTR(o);\n}\n\nSTATIC mp_obj_t zip_iternext(mp_obj_t self_in) {\n    mp_check_self(mp_obj_is_type(self_in, &mp_type_zip));\n    mp_obj_zip_t *self = MP_OBJ_TO_PTR(self_in);\n    if (self->n_iters == 0) {\n        return MP_OBJ_STOP_ITERATION;\n    }\n    mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->n_iters, NULL));\n\n    for (size_t i = 0; i < self->n_iters; i++) {\n        mp_obj_t next = mp_iternext(self->iters[i]);\n        if (next == MP_OBJ_STOP_ITERATION) {\n            mp_obj_tuple_del(MP_OBJ_FROM_PTR(tuple));\n            return MP_OBJ_STOP_ITERATION;\n        }\n        tuple->items[i] = next;\n    }\n    return MP_OBJ_FROM_PTR(tuple);\n}\n\nconst mp_obj_type_t mp_type_zip = {\n    { &mp_type_type },\n    .name = MP_QSTR_zip,\n    .make_new = zip_make_new,\n    .getiter = mp_identity_getiter,\n    .iternext = zip_iternext,\n};\n"
  },
  {
    "path": "py/opmethods.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/obj.h\"\n#include \"py/builtin.h\"\n\nSTATIC mp_obj_t op_getitem(mp_obj_t self_in, mp_obj_t key_in) {\n    const mp_obj_type_t *type = mp_obj_get_type(self_in);\n    return type->subscr(self_in, key_in, MP_OBJ_SENTINEL);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_op_getitem_obj, op_getitem);\n\nSTATIC mp_obj_t op_setitem(mp_obj_t self_in, mp_obj_t key_in, mp_obj_t value_in) {\n    const mp_obj_type_t *type = mp_obj_get_type(self_in);\n    return type->subscr(self_in, key_in, value_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_3(mp_op_setitem_obj, op_setitem);\n\nSTATIC mp_obj_t op_delitem(mp_obj_t self_in, mp_obj_t key_in) {\n    const mp_obj_type_t *type = mp_obj_get_type(self_in);\n    return type->subscr(self_in, key_in, MP_OBJ_NULL);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_op_delitem_obj, op_delitem);\n\nSTATIC mp_obj_t op_contains(mp_obj_t lhs_in, mp_obj_t rhs_in) {\n    const mp_obj_type_t *type = mp_obj_get_type(lhs_in);\n    return type->binary_op(MP_BINARY_OP_CONTAINS, lhs_in, rhs_in);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_op_contains_obj, op_contains);\n"
  },
  {
    "path": "py/pairheap.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2020 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/pairheap.h\"\n\n// The mp_pairheap_t.next pointer can take one of the following values:\n//   - NULL: the node is the top of the heap\n//   - LSB set: the node is the last of the children and points to its parent node\n//   - other: the node is a child and not the last child\n// The macros below help manage this pointer.\n#define NEXT_MAKE_RIGHTMOST_PARENT(parent) ((void *)((uintptr_t)(parent) | 1))\n#define NEXT_IS_RIGHTMOST_PARENT(next) ((uintptr_t)(next) & 1)\n#define NEXT_GET_RIGHTMOST_PARENT(next) ((void *)((uintptr_t)(next) & ~1))\n\n// O(1), stable\nmp_pairheap_t *mp_pairheap_meld(mp_pairheap_lt_t lt, mp_pairheap_t *heap1, mp_pairheap_t *heap2) {\n    if (heap1 == NULL) {\n        return heap2;\n    }\n    if (heap2 == NULL) {\n        return heap1;\n    }\n    if (lt(heap1, heap2)) {\n        if (heap1->child == NULL) {\n            heap1->child = heap2;\n        } else {\n            heap1->child_last->next = heap2;\n        }\n        heap1->child_last = heap2;\n        heap2->next = NEXT_MAKE_RIGHTMOST_PARENT(heap1);\n        return heap1;\n    } else {\n        heap1->next = heap2->child;\n        heap2->child = heap1;\n        if (heap1->next == NULL) {\n            heap2->child_last = heap1;\n            heap1->next = NEXT_MAKE_RIGHTMOST_PARENT(heap2);\n        }\n        return heap2;\n    }\n}\n\n// amortised O(log N), stable\nmp_pairheap_t *mp_pairheap_pairing(mp_pairheap_lt_t lt, mp_pairheap_t *child) {\n    if (child == NULL) {\n        return NULL;\n    }\n    mp_pairheap_t *heap = NULL;\n    while (!NEXT_IS_RIGHTMOST_PARENT(child)) {\n        mp_pairheap_t *n1 = child;\n        child = child->next;\n        n1->next = NULL;\n        if (!NEXT_IS_RIGHTMOST_PARENT(child)) {\n            mp_pairheap_t *n2 = child;\n            child = child->next;\n            n2->next = NULL;\n            n1 = mp_pairheap_meld(lt, n1, n2);\n        }\n        heap = mp_pairheap_meld(lt, heap, n1);\n    }\n    heap->next = NULL;\n    return heap;\n}\n\n// amortised O(log N), stable\nmp_pairheap_t *mp_pairheap_delete(mp_pairheap_lt_t lt, mp_pairheap_t *heap, mp_pairheap_t *node) {\n    // Simple case of the top being the node to delete\n    if (node == heap) {\n        mp_pairheap_t *child = heap->child;\n        node->child = NULL;\n        return mp_pairheap_pairing(lt, child);\n    }\n\n    // Case where node is not in the heap\n    if (node->next == NULL) {\n        return heap;\n    }\n\n    // Find parent of node\n    mp_pairheap_t *parent = node;\n    while (!NEXT_IS_RIGHTMOST_PARENT(parent->next)) {\n        parent = parent->next;\n    }\n    parent = NEXT_GET_RIGHTMOST_PARENT(parent->next);\n\n    // Replace node with pairing of its children\n    mp_pairheap_t *next;\n    if (node == parent->child && node->child == NULL) {\n        if (NEXT_IS_RIGHTMOST_PARENT(node->next)) {\n            parent->child = NULL;\n        } else {\n            parent->child = node->next;\n        }\n        node->next = NULL;\n        return heap;\n    } else if (node == parent->child) {\n        mp_pairheap_t *child = node->child;\n        next = node->next;\n        node->child = NULL;\n        node->next = NULL;\n        node = mp_pairheap_pairing(lt, child);\n        parent->child = node;\n    } else {\n        mp_pairheap_t *n = parent->child;\n        while (node != n->next) {\n            n = n->next;\n        }\n        mp_pairheap_t *child = node->child;\n        next = node->next;\n        node->child = NULL;\n        node->next = NULL;\n        node = mp_pairheap_pairing(lt, child);\n        if (node == NULL) {\n            node = n;\n        } else {\n            n->next = node;\n        }\n    }\n    node->next = next;\n    if (NEXT_IS_RIGHTMOST_PARENT(next)) {\n        parent->child_last = node;\n    }\n    return heap;\n}\n"
  },
  {
    "path": "py/pairheap.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2020 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_PAIRHEAP_H\n#define MICROPY_INCLUDED_PY_PAIRHEAP_H\n\n// This is an implementation of a pairing heap.  It is stable and has deletion\n// support.  Only the less-than operation needs to be defined on elements.\n//\n// See original paper for details:\n// Michael L. Fredman, Robert Sedjewick, Daniel D. Sleator, and Robert E. Tarjan.\n// The Pairing Heap: A New Form of Self-Adjusting Heap.\n// Algorithmica 1:111-129, 1986.\n// https://www.cs.cmu.edu/~sleator/papers/pairing-heaps.pdf\n\n#include <assert.h>\n#include \"py/obj.h\"\n\n// This struct forms the nodes of the heap and is intended to be extended, by\n// placing it first in another struct, to include additional information for the\n// element stored in the heap.  It includes \"base\" so it can be a MicroPython\n// object allocated on the heap and the GC can automatically trace all nodes by\n// following the tree structure.\ntypedef struct _mp_pairheap_t {\n    mp_obj_base_t base;\n    struct _mp_pairheap_t *child;\n    struct _mp_pairheap_t *child_last;\n    struct _mp_pairheap_t *next;\n} mp_pairheap_t;\n\n// This is the function for the less-than operation on nodes/elements.\ntypedef int (*mp_pairheap_lt_t)(mp_pairheap_t *, mp_pairheap_t *);\n\n// Core functions.\nmp_pairheap_t *mp_pairheap_meld(mp_pairheap_lt_t lt, mp_pairheap_t *heap1, mp_pairheap_t *heap2);\nmp_pairheap_t *mp_pairheap_pairing(mp_pairheap_lt_t lt, mp_pairheap_t *child);\nmp_pairheap_t *mp_pairheap_delete(mp_pairheap_lt_t lt, mp_pairheap_t *heap, mp_pairheap_t *node);\n\n// Create a new heap.\nstatic inline mp_pairheap_t *mp_pairheap_new(mp_pairheap_lt_t lt) {\n    (void)lt;\n    return NULL;\n}\n\n// Initialise a single pairing-heap node so it is ready to push on to a heap.\nstatic inline void mp_pairheap_init_node(mp_pairheap_lt_t lt, mp_pairheap_t *node) {\n    (void)lt;\n    node->child = NULL;\n    node->next = NULL;\n}\n\n// Test if the heap is empty.\nstatic inline bool mp_pairheap_is_empty(mp_pairheap_lt_t lt, mp_pairheap_t *heap) {\n    (void)lt;\n    return heap == NULL;\n}\n\n// Peek at the top of the heap.  Will return NULL if empty.\nstatic inline mp_pairheap_t *mp_pairheap_peek(mp_pairheap_lt_t lt, mp_pairheap_t *heap) {\n    (void)lt;\n    return heap;\n}\n\n// Push new node onto existing heap.  Returns the new heap.\nstatic inline mp_pairheap_t *mp_pairheap_push(mp_pairheap_lt_t lt, mp_pairheap_t *heap, mp_pairheap_t *node) {\n    assert(node->child == NULL && node->next == NULL);\n    return mp_pairheap_meld(lt, node, heap); // node is first to be stable\n}\n\n// Pop the top off the heap, which must not be empty.  Returns the new heap.\nstatic inline mp_pairheap_t *mp_pairheap_pop(mp_pairheap_lt_t lt, mp_pairheap_t *heap) {\n    assert(heap->next == NULL);\n    mp_pairheap_t *child = heap->child;\n    heap->child = NULL;\n    return mp_pairheap_pairing(lt, child);\n}\n\n#endif // MICROPY_INCLUDED_PY_PAIRHEAP_H\n"
  },
  {
    "path": "py/parse.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <unistd.h> // for ssize_t\n#include <assert.h>\n#include <string.h>\n\n#include \"py/lexer.h\"\n#include \"py/parse.h\"\n#include \"py/parsenum.h\"\n#include \"py/runtime.h\"\n#include \"py/objint.h\"\n#include \"py/objstr.h\"\n#include \"py/builtin.h\"\n\n#if MICROPY_ENABLE_COMPILER\n\n#define RULE_ACT_ARG_MASK       (0x0f)\n#define RULE_ACT_KIND_MASK      (0x30)\n#define RULE_ACT_ALLOW_IDENT    (0x40)\n#define RULE_ACT_ADD_BLANK      (0x80)\n#define RULE_ACT_OR             (0x10)\n#define RULE_ACT_AND            (0x20)\n#define RULE_ACT_LIST           (0x30)\n\n#define RULE_ARG_KIND_MASK      (0xf000)\n#define RULE_ARG_ARG_MASK       (0x0fff)\n#define RULE_ARG_TOK            (0x1000)\n#define RULE_ARG_RULE           (0x2000)\n#define RULE_ARG_OPT_RULE       (0x3000)\n\n// *FORMAT-OFF*\n\nenum {\n// define rules with a compile function\n#define DEF_RULE(rule, comp, kind, ...) RULE_##rule,\n#define DEF_RULE_NC(rule, kind, ...)\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n    RULE_const_object, // special node for a constant, generic Python object\n\n// define rules without a compile function\n#define DEF_RULE(rule, comp, kind, ...)\n#define DEF_RULE_NC(rule, kind, ...) RULE_##rule,\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n};\n\n// Define an array of actions corresponding to each rule\nSTATIC const uint8_t rule_act_table[] = {\n#define or(n)                   (RULE_ACT_OR | n)\n#define and(n)                  (RULE_ACT_AND | n)\n#define and_ident(n)            (RULE_ACT_AND | n | RULE_ACT_ALLOW_IDENT)\n#define and_blank(n)            (RULE_ACT_AND | n | RULE_ACT_ADD_BLANK)\n#define one_or_more             (RULE_ACT_LIST | 2)\n#define list                    (RULE_ACT_LIST | 1)\n#define list_with_end           (RULE_ACT_LIST | 3)\n\n#define DEF_RULE(rule, comp, kind, ...) kind,\n#define DEF_RULE_NC(rule, kind, ...)\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n\n    0, // RULE_const_object\n\n#define DEF_RULE(rule, comp, kind, ...)\n#define DEF_RULE_NC(rule, kind, ...) kind,\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n\n#undef or\n#undef and\n#undef and_ident\n#undef and_blank\n#undef one_or_more\n#undef list\n#undef list_with_end\n};\n\n// Define the argument data for each rule, as a combined array\nSTATIC const uint16_t rule_arg_combined_table[] = {\n#define tok(t)                  (RULE_ARG_TOK | MP_TOKEN_##t)\n#define rule(r)                 (RULE_ARG_RULE | RULE_##r)\n#define opt_rule(r)             (RULE_ARG_OPT_RULE | RULE_##r)\n\n#define DEF_RULE(rule, comp, kind, ...) __VA_ARGS__,\n#define DEF_RULE_NC(rule, kind, ...)\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n\n#define DEF_RULE(rule, comp, kind, ...)\n#define DEF_RULE_NC(rule, kind, ...)  __VA_ARGS__,\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n\n#undef tok\n#undef rule\n#undef opt_rule\n};\n\n// Macro to create a list of N identifiers where N is the number of variable arguments to the macro\n#define RULE_EXPAND(x) x\n#define RULE_PADDING(rule, ...) RULE_PADDING2(rule, __VA_ARGS__, RULE_PADDING_IDS(rule))\n#define RULE_PADDING2(rule, ...) RULE_EXPAND(RULE_PADDING3(rule, __VA_ARGS__))\n#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) __VA_ARGS__\n#define RULE_PADDING_IDS(r) PAD13_##r, PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r,\n\n// Use an enum to create constants specifying how much room a rule takes in rule_arg_combined_table\nenum {\n#define DEF_RULE(rule, comp, kind, ...) RULE_PADDING(rule, __VA_ARGS__)\n#define DEF_RULE_NC(rule, kind, ...)\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n#define DEF_RULE(rule, comp, kind, ...)\n#define DEF_RULE_NC(rule, kind, ...) RULE_PADDING(rule, __VA_ARGS__)\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n};\n\n// Macro to compute the start of a rule in rule_arg_combined_table\n#define RULE_ARG_OFFSET(rule, ...) RULE_ARG_OFFSET2(rule, __VA_ARGS__, RULE_ARG_OFFSET_IDS(rule))\n#define RULE_ARG_OFFSET2(rule, ...) RULE_EXPAND(RULE_ARG_OFFSET3(rule, __VA_ARGS__))\n#define RULE_ARG_OFFSET3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) _14\n#define RULE_ARG_OFFSET_IDS(r) PAD13_##r, PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, PAD0_##r,\n\n// Use the above enum values to create a table of offsets for each rule's arg\n// data, which indexes rule_arg_combined_table.  The offsets require 9 bits of\n// storage but only the lower 8 bits are stored here.  The 9th bit is computed\n// in get_rule_arg using the FIRST_RULE_WITH_OFFSET_ABOVE_255 constant.\nSTATIC const uint8_t rule_arg_offset_table[] = {\n#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff,\n#define DEF_RULE_NC(rule, kind, ...)\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n    0, // RULE_const_object\n#define DEF_RULE(rule, comp, kind, ...)\n#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff,\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n};\n\n// Define a constant that's used to determine the 9th bit of the values in rule_arg_offset_table\nstatic const size_t FIRST_RULE_WITH_OFFSET_ABOVE_255 =\n#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule :\n#define DEF_RULE_NC(rule, kind, ...)\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n#define DEF_RULE(rule, comp, kind, ...)\n#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule :\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n0;\n\n#if MICROPY_DEBUG_PARSE_RULE_NAME\n// Define an array of rule names corresponding to each rule\nSTATIC const char *const rule_name_table[] = {\n#define DEF_RULE(rule, comp, kind, ...) #rule,\n#define DEF_RULE_NC(rule, kind, ...)\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n    \"\", // RULE_const_object\n#define DEF_RULE(rule, comp, kind, ...)\n#define DEF_RULE_NC(rule, kind, ...) #rule,\n#include \"py/grammar.h\"\n#undef DEF_RULE\n#undef DEF_RULE_NC\n};\n#endif\n\n// *FORMAT-ON*\n\ntypedef struct _rule_stack_t {\n    size_t src_line : (8 * sizeof(size_t) - 8); // maximum bits storing source line number\n    size_t rule_id : 8; // this must be large enough to fit largest rule number\n    size_t arg_i; // this dictates the maximum nodes in a \"list\" of things\n} rule_stack_t;\n\ntypedef struct _mp_parse_chunk_t {\n    size_t alloc;\n    union {\n        size_t used;\n        struct _mp_parse_chunk_t *next;\n    } union_;\n    byte data[];\n} mp_parse_chunk_t;\n\ntypedef struct _parser_t {\n    size_t rule_stack_alloc;\n    size_t rule_stack_top;\n    rule_stack_t *rule_stack;\n\n    size_t result_stack_alloc;\n    size_t result_stack_top;\n    mp_parse_node_t *result_stack;\n\n    mp_lexer_t *lexer;\n\n    mp_parse_tree_t tree;\n    mp_parse_chunk_t *cur_chunk;\n\n    #if MICROPY_COMP_CONST\n    mp_map_t consts;\n    #endif\n} parser_t;\n\nSTATIC const uint16_t *get_rule_arg(uint8_t r_id) {\n    size_t off = rule_arg_offset_table[r_id];\n    if (r_id >= FIRST_RULE_WITH_OFFSET_ABOVE_255) {\n        off |= 0x100;\n    }\n    return &rule_arg_combined_table[off];\n}\n\nSTATIC void *parser_alloc(parser_t *parser, size_t num_bytes) {\n    // use a custom memory allocator to store parse nodes sequentially in large chunks\n\n    mp_parse_chunk_t *chunk = parser->cur_chunk;\n\n    if (chunk != NULL && chunk->union_.used + num_bytes > chunk->alloc) {\n        // not enough room at end of previously allocated chunk so try to grow\n        mp_parse_chunk_t *new_data = (mp_parse_chunk_t *)m_renew_maybe(byte, chunk,\n            sizeof(mp_parse_chunk_t) + chunk->alloc,\n            sizeof(mp_parse_chunk_t) + chunk->alloc + num_bytes, false);\n        if (new_data == NULL) {\n            // could not grow existing memory; shrink it to fit previous\n            (void)m_renew_maybe(byte, chunk, sizeof(mp_parse_chunk_t) + chunk->alloc,\n                sizeof(mp_parse_chunk_t) + chunk->union_.used, false);\n            chunk->alloc = chunk->union_.used;\n            chunk->union_.next = parser->tree.chunk;\n            parser->tree.chunk = chunk;\n            chunk = NULL;\n        } else {\n            // could grow existing memory\n            chunk->alloc += num_bytes;\n        }\n    }\n\n    if (chunk == NULL) {\n        // no previous chunk, allocate a new chunk\n        size_t alloc = MICROPY_ALLOC_PARSE_CHUNK_INIT;\n        if (alloc < num_bytes) {\n            alloc = num_bytes;\n        }\n        chunk = (mp_parse_chunk_t *)m_new(byte, sizeof(mp_parse_chunk_t) + alloc);\n        chunk->alloc = alloc;\n        chunk->union_.used = 0;\n        parser->cur_chunk = chunk;\n    }\n\n    byte *ret = chunk->data + chunk->union_.used;\n    chunk->union_.used += num_bytes;\n    return ret;\n}\n\nSTATIC void push_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t arg_i) {\n    if (parser->rule_stack_top >= parser->rule_stack_alloc) {\n        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);\n        parser->rule_stack = rs;\n        parser->rule_stack_alloc += MICROPY_ALLOC_PARSE_RULE_INC;\n    }\n    rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++];\n    rs->src_line = src_line;\n    rs->rule_id = rule_id;\n    rs->arg_i = arg_i;\n}\n\nSTATIC void push_rule_from_arg(parser_t *parser, size_t arg) {\n    assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE);\n    size_t rule_id = arg & RULE_ARG_ARG_MASK;\n    push_rule(parser, parser->lexer->tok_line, rule_id, 0);\n}\n\nSTATIC uint8_t pop_rule(parser_t *parser, size_t *arg_i, size_t *src_line) {\n    parser->rule_stack_top -= 1;\n    uint8_t rule_id = parser->rule_stack[parser->rule_stack_top].rule_id;\n    *arg_i = parser->rule_stack[parser->rule_stack_top].arg_i;\n    *src_line = parser->rule_stack[parser->rule_stack_top].src_line;\n    return rule_id;\n}\n\nbool mp_parse_node_is_const_false(mp_parse_node_t pn) {\n    return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE)\n           || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0);\n}\n\nbool mp_parse_node_is_const_true(mp_parse_node_t pn) {\n    return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE)\n           || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) != 0);\n}\n\nbool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) {\n    if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {\n        *o = MP_OBJ_NEW_SMALL_INT(MP_PARSE_NODE_LEAF_SMALL_INT(pn));\n        return true;\n    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_const_object)) {\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n        #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D\n        // nodes are 32-bit pointers, but need to extract 64-bit object\n        *o = (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32);\n        #else\n        *o = (mp_obj_t)pns->nodes[0];\n        #endif\n        return mp_obj_is_int(*o);\n    } else {\n        return false;\n    }\n}\n\nsize_t mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes) {\n    if (MP_PARSE_NODE_IS_NULL(*pn)) {\n        *nodes = NULL;\n        return 0;\n    } else if (MP_PARSE_NODE_IS_LEAF(*pn)) {\n        *nodes = pn;\n        return 1;\n    } else {\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)(*pn);\n        if (MP_PARSE_NODE_STRUCT_KIND(pns) != pn_kind) {\n            *nodes = pn;\n            return 1;\n        } else {\n            *nodes = pns->nodes;\n            return MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n        }\n    }\n}\n\n#if MICROPY_DEBUG_PRINTERS\nvoid mp_parse_node_print(const mp_print_t *print, mp_parse_node_t pn, size_t indent) {\n    if (MP_PARSE_NODE_IS_STRUCT(pn)) {\n        mp_printf(print, \"[% 4d] \", (int)((mp_parse_node_struct_t *)pn)->source_line);\n    } else {\n        mp_printf(print, \"       \");\n    }\n    for (size_t i = 0; i < indent; i++) {\n        mp_printf(print, \" \");\n    }\n    if (MP_PARSE_NODE_IS_NULL(pn)) {\n        mp_printf(print, \"NULL\\n\");\n    } else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {\n        mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);\n        mp_printf(print, \"int(\" INT_FMT \")\\n\", arg);\n    } else if (MP_PARSE_NODE_IS_LEAF(pn)) {\n        uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn);\n        switch (MP_PARSE_NODE_LEAF_KIND(pn)) {\n            case MP_PARSE_NODE_ID:\n                mp_printf(print, \"id(%s)\\n\", qstr_str(arg));\n                break;\n            case MP_PARSE_NODE_STRING:\n                mp_printf(print, \"str(%s)\\n\", qstr_str(arg));\n                break;\n            case MP_PARSE_NODE_BYTES:\n                mp_printf(print, \"bytes(%s)\\n\", qstr_str(arg));\n                break;\n            default:\n                assert(MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN);\n                mp_printf(print, \"tok(%u)\\n\", (uint)arg);\n                break;\n        }\n    } else {\n        // node must be a mp_parse_node_struct_t\n        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;\n        if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_const_object) {\n            #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D\n            mp_printf(print, \"literal const(%016llx)\\n\", (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32));\n            #else\n            mp_printf(print, \"literal const(%p)\\n\", (mp_obj_t)pns->nodes[0]);\n            #endif\n        } else {\n            size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);\n            #if MICROPY_DEBUG_PARSE_RULE_NAME\n            mp_printf(print, \"%s(%u) (n=%u)\\n\", rule_name_table[MP_PARSE_NODE_STRUCT_KIND(pns)], (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n);\n            #else\n            mp_printf(print, \"rule(%u) (n=%u)\\n\", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n);\n            #endif\n            for (size_t i = 0; i < n; i++) {\n                mp_parse_node_print(print, pns->nodes[i], indent + 2);\n            }\n        }\n    }\n}\n#endif // MICROPY_DEBUG_PRINTERS\n\n/*\nSTATIC void result_stack_show(const mp_print_t *print, parser_t *parser) {\n    mp_printf(print, \"result stack, most recent first\\n\");\n    for (ssize_t i = parser->result_stack_top - 1; i >= 0; i--) {\n        mp_parse_node_print(print, parser->result_stack[i], 0);\n    }\n}\n*/\n\nSTATIC mp_parse_node_t pop_result(parser_t *parser) {\n    assert(parser->result_stack_top > 0);\n    return parser->result_stack[--parser->result_stack_top];\n}\n\nSTATIC mp_parse_node_t peek_result(parser_t *parser, size_t pos) {\n    assert(parser->result_stack_top > pos);\n    return parser->result_stack[parser->result_stack_top - 1 - pos];\n}\n\nSTATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) {\n    if (parser->result_stack_top >= parser->result_stack_alloc) {\n        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);\n        parser->result_stack = stack;\n        parser->result_stack_alloc += MICROPY_ALLOC_PARSE_RESULT_INC;\n    }\n    parser->result_stack[parser->result_stack_top++] = pn;\n}\n\nSTATIC mp_parse_node_t make_node_const_object(parser_t *parser, size_t src_line, mp_obj_t obj) {\n    mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_obj_t));\n    pn->source_line = src_line;\n    #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D\n    // nodes are 32-bit pointers, but need to store 64-bit object\n    pn->kind_num_nodes = RULE_const_object | (2 << 8);\n    pn->nodes[0] = (uint64_t)obj;\n    pn->nodes[1] = (uint64_t)obj >> 32;\n    #else\n    pn->kind_num_nodes = RULE_const_object | (1 << 8);\n    pn->nodes[0] = (uintptr_t)obj;\n    #endif\n    return (mp_parse_node_t)pn;\n}\n\nSTATIC mp_parse_node_t mp_parse_node_new_small_int_checked(parser_t *parser, mp_obj_t o_val) {\n    (void)parser;\n    mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_val);\n    #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D\n    // A parse node is only 32-bits and the small-int value must fit in 31-bits\n    if (((val ^ (val << 1)) & 0xffffffff80000000) != 0) {\n        return make_node_const_object(parser, 0, o_val);\n    }\n    #endif\n    return mp_parse_node_new_small_int(val);\n}\n\nSTATIC void push_result_token(parser_t *parser, uint8_t rule_id) {\n    mp_parse_node_t pn;\n    mp_lexer_t *lex = parser->lexer;\n    if (lex->tok_kind == MP_TOKEN_NAME) {\n        qstr id = qstr_from_strn(lex->vstr.buf, lex->vstr.len);\n        #if MICROPY_COMP_CONST\n        // if name is a standalone identifier, look it up in the table of dynamic constants\n        mp_map_elem_t *elem;\n        if (rule_id == RULE_atom\n            && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) {\n            if (mp_obj_is_small_int(elem->value)) {\n                pn = mp_parse_node_new_small_int_checked(parser, elem->value);\n            } else {\n                pn = make_node_const_object(parser, lex->tok_line, elem->value);\n            }\n        } else {\n            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id);\n        }\n        #else\n        (void)rule_id;\n        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id);\n        #endif\n    } else if (lex->tok_kind == MP_TOKEN_INTEGER) {\n        mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex);\n        if (mp_obj_is_small_int(o)) {\n            pn = mp_parse_node_new_small_int_checked(parser, o);\n        } else {\n            pn = make_node_const_object(parser, lex->tok_line, o);\n        }\n    } else if (lex->tok_kind == MP_TOKEN_FLOAT_OR_IMAG) {\n        mp_obj_t o = mp_parse_num_decimal(lex->vstr.buf, lex->vstr.len, true, false, lex);\n        pn = make_node_const_object(parser, lex->tok_line, o);\n    } else if (lex->tok_kind == MP_TOKEN_STRING || lex->tok_kind == MP_TOKEN_BYTES) {\n        // Don't automatically intern all strings/bytes.  doc strings (which are usually large)\n        // will be discarded by the compiler, and so we shouldn't intern them.\n        qstr qst = MP_QSTRnull;\n        if (lex->vstr.len <= MICROPY_ALLOC_PARSE_INTERN_STRING_LEN) {\n            // intern short strings\n            qst = qstr_from_strn(lex->vstr.buf, lex->vstr.len);\n        } else {\n            // check if this string is already interned\n            qst = qstr_find_strn(lex->vstr.buf, lex->vstr.len);\n        }\n        if (qst != MP_QSTRnull) {\n            // qstr exists, make a leaf node\n            pn = mp_parse_node_new_leaf(lex->tok_kind == MP_TOKEN_STRING ? MP_PARSE_NODE_STRING : MP_PARSE_NODE_BYTES, qst);\n        } else {\n            // not interned, make a node holding a pointer to the string/bytes object\n            mp_obj_t o = mp_obj_new_str_copy(\n                lex->tok_kind == MP_TOKEN_STRING ? &mp_type_str : &mp_type_bytes,\n                (const byte *)lex->vstr.buf, lex->vstr.len);\n            pn = make_node_const_object(parser, lex->tok_line, o);\n        }\n    } else {\n        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, lex->tok_kind);\n    }\n    push_result_node(parser, pn);\n}\n\n#if MICROPY_COMP_MODULE_CONST\nSTATIC const mp_rom_map_elem_t mp_constants_table[] = {\n    #if MICROPY_PY_UERRNO\n    { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) },\n    #endif\n    #if MICROPY_PY_UCTYPES\n    { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) },\n    #endif\n    // Extra constants as defined by a port\n    MICROPY_PORT_CONSTANTS\n};\nSTATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table);\n#endif\n\nSTATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args);\n\n#if MICROPY_COMP_CONST_FOLDING\nSTATIC bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *num_args) {\n    if (rule_id == RULE_or_test\n        || rule_id == RULE_and_test) {\n        // folding for binary logical ops: or and\n        size_t copy_to = *num_args;\n        for (size_t i = copy_to; i > 0;) {\n            mp_parse_node_t pn = peek_result(parser, --i);\n            parser->result_stack[parser->result_stack_top - copy_to] = pn;\n            if (i == 0) {\n                // always need to keep the last value\n                break;\n            }\n            if (rule_id == RULE_or_test) {\n                if (mp_parse_node_is_const_true(pn)) {\n                    //\n                    break;\n                } else if (!mp_parse_node_is_const_false(pn)) {\n                    copy_to -= 1;\n                }\n            } else {\n                // RULE_and_test\n                if (mp_parse_node_is_const_false(pn)) {\n                    break;\n                } else if (!mp_parse_node_is_const_true(pn)) {\n                    copy_to -= 1;\n                }\n            }\n        }\n        copy_to -= 1; // copy_to now contains number of args to pop\n\n        // pop and discard all the short-circuited expressions\n        for (size_t i = 0; i < copy_to; ++i) {\n            pop_result(parser);\n        }\n        *num_args -= copy_to;\n\n        // we did a complete folding if there's only 1 arg left\n        return *num_args == 1;\n\n    } else if (rule_id == RULE_not_test_2) {\n        // folding for unary logical op: not\n        mp_parse_node_t pn = peek_result(parser, 0);\n        if (mp_parse_node_is_const_false(pn)) {\n            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, MP_TOKEN_KW_TRUE);\n        } else if (mp_parse_node_is_const_true(pn)) {\n            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, MP_TOKEN_KW_FALSE);\n        } else {\n            return false;\n        }\n        pop_result(parser);\n        push_result_node(parser, pn);\n        return true;\n    }\n\n    return false;\n}\n\nSTATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {\n    // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4\n    // it does not do partial folding, eg 1 + 2 + x -> 3 + x\n\n    mp_obj_t arg0;\n    if (rule_id == RULE_expr\n        || rule_id == RULE_xor_expr\n        || rule_id == RULE_and_expr\n        || rule_id == RULE_power) {\n        // folding for binary ops: | ^ & **\n        mp_parse_node_t pn = peek_result(parser, num_args - 1);\n        if (!mp_parse_node_get_int_maybe(pn, &arg0)) {\n            return false;\n        }\n        mp_binary_op_t op;\n        if (rule_id == RULE_expr) {\n            op = MP_BINARY_OP_OR;\n        } else if (rule_id == RULE_xor_expr) {\n            op = MP_BINARY_OP_XOR;\n        } else if (rule_id == RULE_and_expr) {\n            op = MP_BINARY_OP_AND;\n        } else {\n            op = MP_BINARY_OP_POWER;\n        }\n        for (ssize_t i = num_args - 2; i >= 0; --i) {\n            pn = peek_result(parser, i);\n            mp_obj_t arg1;\n            if (!mp_parse_node_get_int_maybe(pn, &arg1)) {\n                return false;\n            }\n            if (op == MP_BINARY_OP_POWER && mp_obj_int_sign(arg1) < 0) {\n                // ** can't have negative rhs\n                return false;\n            }\n            arg0 = mp_binary_op(op, arg0, arg1);\n        }\n    } else if (rule_id == RULE_shift_expr\n               || rule_id == RULE_arith_expr\n               || rule_id == RULE_term) {\n        // folding for binary ops: << >> + - * @ / % //\n        mp_parse_node_t pn = peek_result(parser, num_args - 1);\n        if (!mp_parse_node_get_int_maybe(pn, &arg0)) {\n            return false;\n        }\n        for (ssize_t i = num_args - 2; i >= 1; i -= 2) {\n            pn = peek_result(parser, i - 1);\n            mp_obj_t arg1;\n            if (!mp_parse_node_get_int_maybe(pn, &arg1)) {\n                return false;\n            }\n            mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, i));\n            if (tok == MP_TOKEN_OP_AT || tok == MP_TOKEN_OP_SLASH) {\n                // Can't fold @ or /\n                return false;\n            }\n            mp_binary_op_t op = MP_BINARY_OP_LSHIFT + (tok - MP_TOKEN_OP_DBL_LESS);\n            int rhs_sign = mp_obj_int_sign(arg1);\n            if (op <= MP_BINARY_OP_RSHIFT) {\n                // << and >> can't have negative rhs\n                if (rhs_sign < 0) {\n                    return false;\n                }\n            } else if (op >= MP_BINARY_OP_FLOOR_DIVIDE) {\n                // % and // can't have zero rhs\n                if (rhs_sign == 0) {\n                    return false;\n                }\n            }\n            arg0 = mp_binary_op(op, arg0, arg1);\n        }\n    } else if (rule_id == RULE_factor_2) {\n        // folding for unary ops: + - ~\n        mp_parse_node_t pn = peek_result(parser, 0);\n        if (!mp_parse_node_get_int_maybe(pn, &arg0)) {\n            return false;\n        }\n        mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, 1));\n        mp_unary_op_t op;\n        if (tok == MP_TOKEN_OP_TILDE) {\n            op = MP_UNARY_OP_INVERT;\n        } else {\n            assert(tok == MP_TOKEN_OP_PLUS || tok == MP_TOKEN_OP_MINUS); // should be\n            op = MP_UNARY_OP_POSITIVE + (tok - MP_TOKEN_OP_PLUS);\n        }\n        arg0 = mp_unary_op(op, arg0);\n\n    #if MICROPY_COMP_CONST\n    } else if (rule_id == RULE_expr_stmt) {\n        mp_parse_node_t pn1 = peek_result(parser, 0);\n        if (!MP_PARSE_NODE_IS_NULL(pn1)\n            && !(MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_augassign)\n                 || MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_assign_list))) {\n            // this node is of the form <x> = <y>\n            mp_parse_node_t pn0 = peek_result(parser, 1);\n            if (MP_PARSE_NODE_IS_ID(pn0)\n                && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_atom_expr_normal)\n                && MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t *)pn1)->nodes[0])\n                && MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t *)pn1)->nodes[0]) == MP_QSTR_const\n                && MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t *)pn1)->nodes[1], RULE_trailer_paren)\n                ) {\n                // code to assign dynamic constants: id = const(value)\n\n                // get the id\n                qstr id = MP_PARSE_NODE_LEAF_ARG(pn0);\n\n                // get the value\n                mp_parse_node_t pn_value = ((mp_parse_node_struct_t *)((mp_parse_node_struct_t *)pn1)->nodes[1])->nodes[0];\n                mp_obj_t value;\n                if (!mp_parse_node_get_int_maybe(pn_value, &value)) {\n                    mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,\n                        MP_ERROR_TEXT(\"constant must be an integer\"));\n                    mp_obj_exception_add_traceback(exc, parser->lexer->source_name,\n                        ((mp_parse_node_struct_t *)pn1)->source_line, MP_QSTRnull);\n                    nlr_raise(exc);\n                }\n\n                // store the value in the table of dynamic constants\n                mp_map_elem_t *elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);\n                assert(elem->value == MP_OBJ_NULL);\n                elem->value = value;\n\n                // If the constant starts with an underscore then treat it as a private\n                // variable and don't emit any code to store the value to the id.\n                if (qstr_str(id)[0] == '_') {\n                    pop_result(parser); // pop const(value)\n                    pop_result(parser); // pop id\n                    push_result_rule(parser, 0, RULE_pass_stmt, 0); // replace with \"pass\"\n                    return true;\n                }\n\n                // replace const(value) with value\n                pop_result(parser);\n                push_result_node(parser, pn_value);\n\n                // finished folding this assignment, but we still want it to be part of the tree\n                return false;\n            }\n        }\n        return false;\n    #endif\n\n    #if MICROPY_COMP_MODULE_CONST\n    } else if (rule_id == RULE_atom_expr_normal) {\n        mp_parse_node_t pn0 = peek_result(parser, 1);\n        mp_parse_node_t pn1 = peek_result(parser, 0);\n        if (!(MP_PARSE_NODE_IS_ID(pn0)\n              && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_trailer_period))) {\n            return false;\n        }\n        // id1.id2\n        // look it up in constant table, see if it can be replaced with an integer\n        mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pn1;\n        assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));\n        qstr q_base = MP_PARSE_NODE_LEAF_ARG(pn0);\n        qstr q_attr = MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]);\n        mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&mp_constants_map, MP_OBJ_NEW_QSTR(q_base), MP_MAP_LOOKUP);\n        if (elem == NULL) {\n            return false;\n        }\n        mp_obj_t dest[2];\n        mp_load_method_maybe(elem->value, q_attr, dest);\n        if (!(dest[0] != MP_OBJ_NULL && mp_obj_is_int(dest[0]) && dest[1] == MP_OBJ_NULL)) {\n            return false;\n        }\n        arg0 = dest[0];\n    #endif\n\n    } else {\n        return false;\n    }\n\n    // success folding this rule\n\n    for (size_t i = num_args; i > 0; i--) {\n        pop_result(parser);\n    }\n    if (mp_obj_is_small_int(arg0)) {\n        push_result_node(parser, mp_parse_node_new_small_int_checked(parser, arg0));\n    } else {\n        // TODO reuse memory for parse node struct?\n        push_result_node(parser, make_node_const_object(parser, 0, arg0));\n    }\n\n    return true;\n}\n#endif\n\nSTATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) {\n    // optimise away parenthesis around an expression if possible\n    if (rule_id == RULE_atom_paren) {\n        // there should be just 1 arg for this rule\n        mp_parse_node_t pn = peek_result(parser, 0);\n        if (MP_PARSE_NODE_IS_NULL(pn)) {\n            // need to keep parenthesis for ()\n        } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_testlist_comp)) {\n            // need to keep parenthesis for (a, b, ...)\n        } else {\n            // parenthesis around a single expression, so it's just the expression\n            return;\n        }\n    }\n\n    #if MICROPY_COMP_CONST_FOLDING\n    if (fold_logical_constants(parser, rule_id, &num_args)) {\n        // we folded this rule so return straight away\n        return;\n    }\n    if (fold_constants(parser, rule_id, num_args)) {\n        // we folded this rule so return straight away\n        return;\n    }\n    #endif\n\n    mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * num_args);\n    pn->source_line = src_line;\n    pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8);\n    for (size_t i = num_args; i > 0; i--) {\n        pn->nodes[i - 1] = pop_result(parser);\n    }\n    push_result_node(parser, (mp_parse_node_t)pn);\n}\n\nmp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {\n\n    // initialise parser and allocate memory for its stacks\n\n    parser_t parser;\n\n    parser.rule_stack_alloc = MICROPY_ALLOC_PARSE_RULE_INIT;\n    parser.rule_stack_top = 0;\n    parser.rule_stack = m_new(rule_stack_t, parser.rule_stack_alloc);\n\n    parser.result_stack_alloc = MICROPY_ALLOC_PARSE_RESULT_INIT;\n    parser.result_stack_top = 0;\n    parser.result_stack = m_new(mp_parse_node_t, parser.result_stack_alloc);\n\n    parser.lexer = lex;\n\n    parser.tree.chunk = NULL;\n    parser.cur_chunk = NULL;\n\n    #if MICROPY_COMP_CONST\n    mp_map_init(&parser.consts, 0);\n    #endif\n\n    // work out the top-level rule to use, and push it on the stack\n    size_t top_level_rule;\n    switch (input_kind) {\n        case MP_PARSE_SINGLE_INPUT:\n            top_level_rule = RULE_single_input;\n            break;\n        case MP_PARSE_EVAL_INPUT:\n            top_level_rule = RULE_eval_input;\n            break;\n        default:\n            top_level_rule = RULE_file_input;\n    }\n    push_rule(&parser, lex->tok_line, top_level_rule, 0);\n\n    // parse!\n\n    bool backtrack = false;\n\n    for (;;) {\n    next_rule:\n        if (parser.rule_stack_top == 0) {\n            break;\n        }\n\n        // Pop the next rule to process it\n        size_t i; // state for the current rule\n        size_t rule_src_line; // source line for the first token matched by the current rule\n        uint8_t rule_id = pop_rule(&parser, &i, &rule_src_line);\n        uint8_t rule_act = rule_act_table[rule_id];\n        const uint16_t *rule_arg = get_rule_arg(rule_id);\n        size_t n = rule_act & RULE_ACT_ARG_MASK;\n\n        #if 0\n        // debugging\n        printf(\"depth=\" UINT_FMT \" \", parser.rule_stack_top);\n        for (int j = 0; j < parser.rule_stack_top; ++j) {\n            printf(\" \");\n        }\n        printf(\"%s n=\" UINT_FMT \" i=\" UINT_FMT \" bt=%d\\n\", rule_name_table[rule_id], n, i, backtrack);\n        #endif\n\n        switch (rule_act & RULE_ACT_KIND_MASK) {\n            case RULE_ACT_OR:\n                if (i > 0 && !backtrack) {\n                    goto next_rule;\n                } else {\n                    backtrack = false;\n                }\n                for (; i < n; ++i) {\n                    uint16_t kind = rule_arg[i] & RULE_ARG_KIND_MASK;\n                    if (kind == RULE_ARG_TOK) {\n                        if (lex->tok_kind == (rule_arg[i] & RULE_ARG_ARG_MASK)) {\n                            push_result_token(&parser, rule_id);\n                            mp_lexer_to_next(lex);\n                            goto next_rule;\n                        }\n                    } else {\n                        assert(kind == RULE_ARG_RULE);\n                        if (i + 1 < n) {\n                            push_rule(&parser, rule_src_line, rule_id, i + 1); // save this or-rule\n                        }\n                        push_rule_from_arg(&parser, rule_arg[i]); // push child of or-rule\n                        goto next_rule;\n                    }\n                }\n                backtrack = true;\n                break;\n\n            case RULE_ACT_AND: {\n\n                // failed, backtrack if we can, else syntax error\n                if (backtrack) {\n                    assert(i > 0);\n                    if ((rule_arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) {\n                        // an optional rule that failed, so continue with next arg\n                        push_result_node(&parser, MP_PARSE_NODE_NULL);\n                        backtrack = false;\n                    } else {\n                        // a mandatory rule that failed, so propagate backtrack\n                        if (i > 1) {\n                            // already eaten tokens so can't backtrack\n                            goto syntax_error;\n                        } else {\n                            goto next_rule;\n                        }\n                    }\n                }\n\n                // progress through the rule\n                for (; i < n; ++i) {\n                    if ((rule_arg[i] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {\n                        // need to match a token\n                        mp_token_kind_t tok_kind = rule_arg[i] & RULE_ARG_ARG_MASK;\n                        if (lex->tok_kind == tok_kind) {\n                            // matched token\n                            if (tok_kind == MP_TOKEN_NAME) {\n                                push_result_token(&parser, rule_id);\n                            }\n                            mp_lexer_to_next(lex);\n                        } else {\n                            // failed to match token\n                            if (i > 0) {\n                                // already eaten tokens so can't backtrack\n                                goto syntax_error;\n                            } else {\n                                // this rule failed, so backtrack\n                                backtrack = true;\n                                goto next_rule;\n                            }\n                        }\n                    } else {\n                        push_rule(&parser, rule_src_line, rule_id, i + 1); // save this and-rule\n                        push_rule_from_arg(&parser, rule_arg[i]); // push child of and-rule\n                        goto next_rule;\n                    }\n                }\n\n                assert(i == n);\n\n                // matched the rule, so now build the corresponding parse_node\n\n                #if !MICROPY_ENABLE_DOC_STRING\n                // this code discards lonely statements, such as doc strings\n                if (input_kind != MP_PARSE_SINGLE_INPUT && rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) {\n                    mp_parse_node_t p = peek_result(&parser, 1);\n                    if ((MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p))\n                        || MP_PARSE_NODE_IS_STRUCT_KIND(p, RULE_const_object)) {\n                        pop_result(&parser); // MP_PARSE_NODE_NULL\n                        pop_result(&parser); // const expression (leaf or RULE_const_object)\n                        // Pushing the \"pass\" rule here will overwrite any RULE_const_object\n                        // entry that was on the result stack, allowing the GC to reclaim\n                        // the memory from the const object when needed.\n                        push_result_rule(&parser, rule_src_line, RULE_pass_stmt, 0);\n                        break;\n                    }\n                }\n                #endif\n\n                // count number of arguments for the parse node\n                i = 0;\n                size_t num_not_nil = 0;\n                for (size_t x = n; x > 0;) {\n                    --x;\n                    if ((rule_arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {\n                        mp_token_kind_t tok_kind = rule_arg[x] & RULE_ARG_ARG_MASK;\n                        if (tok_kind == MP_TOKEN_NAME) {\n                            // only tokens which were names are pushed to stack\n                            i += 1;\n                            num_not_nil += 1;\n                        }\n                    } else {\n                        // rules are always pushed\n                        if (peek_result(&parser, i) != MP_PARSE_NODE_NULL) {\n                            num_not_nil += 1;\n                        }\n                        i += 1;\n                    }\n                }\n\n                if (num_not_nil == 1 && (rule_act & RULE_ACT_ALLOW_IDENT)) {\n                    // this rule has only 1 argument and should not be emitted\n                    mp_parse_node_t pn = MP_PARSE_NODE_NULL;\n                    for (size_t x = 0; x < i; ++x) {\n                        mp_parse_node_t pn2 = pop_result(&parser);\n                        if (pn2 != MP_PARSE_NODE_NULL) {\n                            pn = pn2;\n                        }\n                    }\n                    push_result_node(&parser, pn);\n                } else {\n                    // this rule must be emitted\n\n                    if (rule_act & RULE_ACT_ADD_BLANK) {\n                        // and add an extra blank node at the end (used by the compiler to store data)\n                        push_result_node(&parser, MP_PARSE_NODE_NULL);\n                        i += 1;\n                    }\n\n                    push_result_rule(&parser, rule_src_line, rule_id, i);\n                }\n                break;\n            }\n\n            default: {\n                assert((rule_act & RULE_ACT_KIND_MASK) == RULE_ACT_LIST);\n\n                // n=2 is: item item*\n                // n=1 is: item (sep item)*\n                // n=3 is: item (sep item)* [sep]\n                bool had_trailing_sep;\n                if (backtrack) {\n                list_backtrack:\n                    had_trailing_sep = false;\n                    if (n == 2) {\n                        if (i == 1) {\n                            // fail on item, first time round; propagate backtrack\n                            goto next_rule;\n                        } else {\n                            // fail on item, in later rounds; finish with this rule\n                            backtrack = false;\n                        }\n                    } else {\n                        if (i == 1) {\n                            // fail on item, first time round; propagate backtrack\n                            goto next_rule;\n                        } else if ((i & 1) == 1) {\n                            // fail on item, in later rounds; have eaten tokens so can't backtrack\n                            if (n == 3) {\n                                // list allows trailing separator; finish parsing list\n                                had_trailing_sep = true;\n                                backtrack = false;\n                            } else {\n                                // list doesn't allowing trailing separator; fail\n                                goto syntax_error;\n                            }\n                        } else {\n                            // fail on separator; finish parsing list\n                            backtrack = false;\n                        }\n                    }\n                } else {\n                    for (;;) {\n                        size_t arg = rule_arg[i & 1 & n];\n                        if ((arg & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {\n                            if (lex->tok_kind == (arg & RULE_ARG_ARG_MASK)) {\n                                if (i & 1 & n) {\n                                    // separators which are tokens are not pushed to result stack\n                                } else {\n                                    push_result_token(&parser, rule_id);\n                                }\n                                mp_lexer_to_next(lex);\n                                // got element of list, so continue parsing list\n                                i += 1;\n                            } else {\n                                // couldn't get element of list\n                                i += 1;\n                                backtrack = true;\n                                goto list_backtrack;\n                            }\n                        } else {\n                            assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE);\n                            push_rule(&parser, rule_src_line, rule_id, i + 1); // save this list-rule\n                            push_rule_from_arg(&parser, arg); // push child of list-rule\n                            goto next_rule;\n                        }\n                    }\n                }\n                assert(i >= 1);\n\n                // compute number of elements in list, result in i\n                i -= 1;\n                if ((n & 1) && (rule_arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {\n                    // don't count separators when they are tokens\n                    i = (i + 1) / 2;\n                }\n\n                if (i == 1) {\n                    // list matched single item\n                    if (had_trailing_sep) {\n                        // if there was a trailing separator, make a list of a single item\n                        push_result_rule(&parser, rule_src_line, rule_id, i);\n                    } else {\n                        // just leave single item on stack (ie don't wrap in a list)\n                    }\n                } else {\n                    push_result_rule(&parser, rule_src_line, rule_id, i);\n                }\n                break;\n            }\n        }\n    }\n\n    #if MICROPY_COMP_CONST\n    mp_map_deinit(&parser.consts);\n    #endif\n\n    // truncate final chunk and link into chain of chunks\n    if (parser.cur_chunk != NULL) {\n        (void)m_renew_maybe(byte, parser.cur_chunk,\n            sizeof(mp_parse_chunk_t) + parser.cur_chunk->alloc,\n            sizeof(mp_parse_chunk_t) + parser.cur_chunk->union_.used,\n            false);\n        parser.cur_chunk->alloc = parser.cur_chunk->union_.used;\n        parser.cur_chunk->union_.next = parser.tree.chunk;\n        parser.tree.chunk = parser.cur_chunk;\n    }\n\n    if (\n        lex->tok_kind != MP_TOKEN_END // check we are at the end of the token stream\n        || parser.result_stack_top == 0 // check that we got a node (can fail on empty input)\n        ) {\n    syntax_error:;\n        mp_obj_t exc;\n        if (lex->tok_kind == MP_TOKEN_INDENT) {\n            exc = mp_obj_new_exception_msg(&mp_type_IndentationError,\n                MP_ERROR_TEXT(\"unexpected indent\"));\n        } else if (lex->tok_kind == MP_TOKEN_DEDENT_MISMATCH) {\n            exc = mp_obj_new_exception_msg(&mp_type_IndentationError,\n                MP_ERROR_TEXT(\"unindent doesn't match any outer indent level\"));\n        } else {\n            exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,\n                MP_ERROR_TEXT(\"invalid syntax\"));\n        }\n        // add traceback to give info about file name and location\n        // we don't have a 'block' name, so just pass the NULL qstr to indicate this\n        mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTRnull);\n        nlr_raise(exc);\n    }\n\n    // get the root parse node that we created\n    assert(parser.result_stack_top == 1);\n    parser.tree.root = parser.result_stack[0];\n\n    // free the memory that we don't need anymore\n    m_del(rule_stack_t, parser.rule_stack, parser.rule_stack_alloc);\n    m_del(mp_parse_node_t, parser.result_stack, parser.result_stack_alloc);\n\n    // we also free the lexer on behalf of the caller\n    mp_lexer_free(lex);\n\n    return parser.tree;\n}\n\nvoid mp_parse_tree_clear(mp_parse_tree_t *tree) {\n    mp_parse_chunk_t *chunk = tree->chunk;\n    while (chunk != NULL) {\n        mp_parse_chunk_t *next = chunk->union_.next;\n        m_del(byte, chunk, sizeof(mp_parse_chunk_t) + chunk->alloc);\n        chunk = next;\n    }\n}\n\n#endif // MICROPY_ENABLE_COMPILER\n"
  },
  {
    "path": "py/parse.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_PARSE_H\n#define MICROPY_INCLUDED_PY_PARSE_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"py/obj.h\"\n\nstruct _mp_lexer_t;\n\n// a mp_parse_node_t is:\n//  - 0000...0000: no node\n//  - xxxx...xxx1: a small integer; bits 1 and above are the signed value, 2's complement\n//  - xxxx...xx00: pointer to mp_parse_node_struct_t\n//  - xx...xx0010: an identifier; bits 4 and above are the qstr\n//  - xx...xx0110: a string; bits 4 and above are the qstr holding the value\n//  - xx...xx1010: a string of bytes; bits 4 and above are the qstr holding the value\n//  - xx...xx1110: a token; bits 4 and above are mp_token_kind_t\n\n#define MP_PARSE_NODE_NULL      (0)\n#define MP_PARSE_NODE_SMALL_INT (0x1)\n#define MP_PARSE_NODE_ID        (0x02)\n#define MP_PARSE_NODE_STRING    (0x06)\n#define MP_PARSE_NODE_BYTES     (0x0a)\n#define MP_PARSE_NODE_TOKEN     (0x0e)\n\ntypedef uintptr_t mp_parse_node_t; // must be pointer size\n\ntypedef struct _mp_parse_node_struct_t {\n    uint32_t source_line;       // line number in source file\n    uint32_t kind_num_nodes;    // parse node kind, and number of nodes\n    mp_parse_node_t nodes[];    // nodes\n} mp_parse_node_struct_t;\n\n// macros for mp_parse_node_t usage\n// some of these evaluate their argument more than once\n\n#define MP_PARSE_NODE_IS_NULL(pn) ((pn) == MP_PARSE_NODE_NULL)\n#define MP_PARSE_NODE_IS_LEAF(pn) ((pn) & 3)\n#define MP_PARSE_NODE_IS_STRUCT(pn) ((pn) != MP_PARSE_NODE_NULL && ((pn) & 3) == 0)\n#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))\n\n#define MP_PARSE_NODE_IS_SMALL_INT(pn) (((pn) & 0x1) == MP_PARSE_NODE_SMALL_INT)\n#define MP_PARSE_NODE_IS_ID(pn) (((pn) & 0x0f) == MP_PARSE_NODE_ID)\n#define MP_PARSE_NODE_IS_TOKEN(pn) (((pn) & 0x0f) == MP_PARSE_NODE_TOKEN)\n#define MP_PARSE_NODE_IS_TOKEN_KIND(pn, k) ((pn) == (MP_PARSE_NODE_TOKEN | ((k) << 4)))\n\n#define MP_PARSE_NODE_LEAF_KIND(pn) ((pn) & 0x0f)\n#define MP_PARSE_NODE_LEAF_ARG(pn) (((uintptr_t)(pn)) >> 4)\n#define MP_PARSE_NODE_LEAF_SMALL_INT(pn) (((mp_int_t)(intptr_t)(pn)) >> 1)\n#define MP_PARSE_NODE_STRUCT_KIND(pns) ((pns)->kind_num_nodes & 0xff)\n#define MP_PARSE_NODE_STRUCT_NUM_NODES(pns) ((pns)->kind_num_nodes >> 8)\n\nstatic inline mp_parse_node_t mp_parse_node_new_small_int(mp_int_t val) {\n    return (mp_parse_node_t)(MP_PARSE_NODE_SMALL_INT | ((mp_uint_t)val << 1));\n}\nstatic inline mp_parse_node_t mp_parse_node_new_leaf(size_t kind, mp_int_t arg) {\n    return (mp_parse_node_t)(kind | ((mp_uint_t)arg << 4));\n}\nbool mp_parse_node_is_const_false(mp_parse_node_t pn);\nbool mp_parse_node_is_const_true(mp_parse_node_t pn);\nbool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o);\nsize_t mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes);\nvoid mp_parse_node_print(const mp_print_t *print, mp_parse_node_t pn, size_t indent);\n\ntypedef enum {\n    MP_PARSE_SINGLE_INPUT,\n    MP_PARSE_FILE_INPUT,\n    MP_PARSE_EVAL_INPUT,\n} mp_parse_input_kind_t;\n\ntypedef struct _mp_parse_t {\n    mp_parse_node_t root;\n    struct _mp_parse_chunk_t *chunk;\n} mp_parse_tree_t;\n\n// the parser will raise an exception if an error occurred\n// the parser will free the lexer before it returns\nmp_parse_tree_t mp_parse(struct _mp_lexer_t *lex, mp_parse_input_kind_t input_kind);\nvoid mp_parse_tree_clear(mp_parse_tree_t *tree);\n\n#endif // MICROPY_INCLUDED_PY_PARSE_H\n"
  },
  {
    "path": "py/parsenum.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdbool.h>\n#include <stdlib.h>\n\n#include \"py/runtime.h\"\n#include \"py/parsenumbase.h\"\n#include \"py/parsenum.h\"\n#include \"py/smallint.h\"\n\n#if MICROPY_PY_BUILTINS_FLOAT\n#include <math.h>\n#endif\n\nSTATIC NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) {\n    // if lex!=NULL then the parser called us and we need to convert the\n    // exception's type from ValueError to SyntaxError and add traceback info\n    if (lex != NULL) {\n        ((mp_obj_base_t *)MP_OBJ_TO_PTR(exc))->type = &mp_type_SyntaxError;\n        mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTRnull);\n    }\n    nlr_raise(exc);\n}\n\nmp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, mp_lexer_t *lex) {\n    const byte *restrict str = (const byte *)str_;\n    const byte *restrict top = str + len;\n    bool neg = false;\n    mp_obj_t ret_val;\n\n    // check radix base\n    if ((base != 0 && base < 2) || base > 36) {\n        // this won't be reached if lex!=NULL\n        mp_raise_ValueError(MP_ERROR_TEXT(\"int() arg 2 must be >= 2 and <= 36\"));\n    }\n\n    // skip leading space\n    for (; str < top && unichar_isspace(*str); str++) {\n    }\n\n    // parse optional sign\n    if (str < top) {\n        if (*str == '+') {\n            str++;\n        } else if (*str == '-') {\n            str++;\n            neg = true;\n        }\n    }\n\n    // parse optional base prefix\n    str += mp_parse_num_base((const char *)str, top - str, &base);\n\n    // string should be an integer number\n    mp_int_t int_val = 0;\n    const byte *restrict str_val_start = str;\n    for (; str < top; str++) {\n        // get next digit as a value\n        mp_uint_t dig = *str;\n        if ('0' <= dig && dig <= '9') {\n            dig -= '0';\n        } else if (dig == '_') {\n            continue;\n        } else {\n            dig |= 0x20; // make digit lower-case\n            if ('a' <= dig && dig <= 'z') {\n                dig -= 'a' - 10;\n            } else {\n                // unknown character\n                break;\n            }\n        }\n        if (dig >= (mp_uint_t)base) {\n            break;\n        }\n\n        // add next digi and check for overflow\n        if (mp_small_int_mul_overflow(int_val, base)) {\n            goto overflow;\n        }\n        int_val = int_val * base + dig;\n        if (!MP_SMALL_INT_FITS(int_val)) {\n            goto overflow;\n        }\n    }\n\n    // negate value if needed\n    if (neg) {\n        int_val = -int_val;\n    }\n\n    // create the small int\n    ret_val = MP_OBJ_NEW_SMALL_INT(int_val);\n\nhave_ret_val:\n    // check we parsed something\n    if (str == str_val_start) {\n        goto value_error;\n    }\n\n    // skip trailing space\n    for (; str < top && unichar_isspace(*str); str++) {\n    }\n\n    // check we reached the end of the string\n    if (str != top) {\n        goto value_error;\n    }\n\n    // return the object\n    return ret_val;\n\noverflow:\n    // reparse using long int\n    {\n        const char *s2 = (const char *)str_val_start;\n        ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base);\n        str = (const byte *)s2;\n        goto have_ret_val;\n    }\n\nvalue_error:\n    {\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_ValueError,\n            MP_ERROR_TEXT(\"invalid syntax for integer\"));\n        raise_exc(exc, lex);\n        #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL\n        mp_obj_t exc = mp_obj_new_exception_msg_varg(&mp_type_ValueError,\n            MP_ERROR_TEXT(\"invalid syntax for integer with base %d\"), base);\n        raise_exc(exc, lex);\n        #else\n        vstr_t vstr;\n        mp_print_t print;\n        vstr_init_print(&vstr, 50, &print);\n        mp_printf(&print, \"invalid syntax for integer with base %d: \", base);\n        mp_str_print_quoted(&print, str_val_start, top - str_val_start, true);\n        mp_obj_t exc = mp_obj_new_exception_arg1(&mp_type_ValueError,\n            mp_obj_new_str_from_vstr(&mp_type_str, &vstr));\n        raise_exc(exc, lex);\n        #endif\n    }\n}\n\ntypedef enum {\n    PARSE_DEC_IN_INTG,\n    PARSE_DEC_IN_FRAC,\n    PARSE_DEC_IN_EXP,\n} parse_dec_in_t;\n\nmp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex) {\n    #if MICROPY_PY_BUILTINS_FLOAT\n\n// DEC_VAL_MAX only needs to be rough and is used to retain precision while not overflowing\n// SMALL_NORMAL_VAL is the smallest power of 10 that is still a normal float\n// EXACT_POWER_OF_10 is the largest value of x so that 10^x can be stored exactly in a float\n//   Note: EXACT_POWER_OF_10 is at least floor(log_5(2^mantissa_length)). Indeed, 10^n = 2^n * 5^n\n//   so we only have to store the 5^n part in the mantissa (the 2^n part will go into the float's\n//   exponent).\n    #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT\n#define DEC_VAL_MAX 1e20F\n#define SMALL_NORMAL_VAL (1e-37F)\n#define SMALL_NORMAL_EXP (-37)\n#define EXACT_POWER_OF_10 (9)\n    #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE\n#define DEC_VAL_MAX 1e200\n#define SMALL_NORMAL_VAL (1e-307)\n#define SMALL_NORMAL_EXP (-307)\n#define EXACT_POWER_OF_10 (22)\n    #endif\n\n    const char *top = str + len;\n    mp_float_t dec_val = 0;\n    bool dec_neg = false;\n    bool imag = false;\n\n    // skip leading space\n    for (; str < top && unichar_isspace(*str); str++) {\n    }\n\n    // parse optional sign\n    if (str < top) {\n        if (*str == '+') {\n            str++;\n        } else if (*str == '-') {\n            str++;\n            dec_neg = true;\n        }\n    }\n\n    const char *str_val_start = str;\n\n    // determine what the string is\n    if (str < top && (str[0] | 0x20) == 'i') {\n        // string starts with 'i', should be 'inf' or 'infinity' (case insensitive)\n        if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') {\n            // inf\n            str += 3;\n            dec_val = (mp_float_t)INFINITY;\n            if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') {\n                // infinity\n                str += 5;\n            }\n        }\n    } else if (str < top && (str[0] | 0x20) == 'n') {\n        // string starts with 'n', should be 'nan' (case insensitive)\n        if (str + 2 < top && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') {\n            // NaN\n            str += 3;\n            dec_val = MICROPY_FLOAT_C_FUN(nan)(\"\");\n        }\n    } else {\n        // string should be a decimal number\n        parse_dec_in_t in = PARSE_DEC_IN_INTG;\n        bool exp_neg = false;\n        int exp_val = 0;\n        int exp_extra = 0;\n        while (str < top) {\n            unsigned int dig = *str++;\n            if ('0' <= dig && dig <= '9') {\n                dig -= '0';\n                if (in == PARSE_DEC_IN_EXP) {\n                    // don't overflow exp_val when adding next digit, instead just truncate\n                    // it and the resulting float will still be correct, either inf or 0.0\n                    // (use INT_MAX/2 to allow adding exp_extra at the end without overflow)\n                    if (exp_val < (INT_MAX / 2 - 9) / 10) {\n                        exp_val = 10 * exp_val + dig;\n                    }\n                } else {\n                    if (dec_val < DEC_VAL_MAX) {\n                        // dec_val won't overflow so keep accumulating\n                        dec_val = 10 * dec_val + dig;\n                        if (in == PARSE_DEC_IN_FRAC) {\n                            --exp_extra;\n                        }\n                    } else {\n                        // dec_val might overflow and we anyway can't represent more digits\n                        // of precision, so ignore the digit and just adjust the exponent\n                        if (in == PARSE_DEC_IN_INTG) {\n                            ++exp_extra;\n                        }\n                    }\n                }\n            } else if (in == PARSE_DEC_IN_INTG && dig == '.') {\n                in = PARSE_DEC_IN_FRAC;\n            } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) {\n                in = PARSE_DEC_IN_EXP;\n                if (str < top) {\n                    if (str[0] == '+') {\n                        str++;\n                    } else if (str[0] == '-') {\n                        str++;\n                        exp_neg = true;\n                    }\n                }\n                if (str == top) {\n                    goto value_error;\n                }\n            } else if (allow_imag && (dig | 0x20) == 'j') {\n                imag = true;\n                break;\n            } else if (dig == '_') {\n                continue;\n            } else {\n                // unknown character\n                str--;\n                break;\n            }\n        }\n\n        // work out the exponent\n        if (exp_neg) {\n            exp_val = -exp_val;\n        }\n\n        // apply the exponent, making sure it's not a subnormal value\n        exp_val += exp_extra;\n        if (exp_val < SMALL_NORMAL_EXP) {\n            exp_val -= SMALL_NORMAL_EXP;\n            dec_val *= SMALL_NORMAL_VAL;\n        }\n\n        // At this point, we need to multiply the mantissa by its base 10 exponent. If possible,\n        // we would rather manipulate numbers that have an exact representation in IEEE754. It\n        // turns out small positive powers of 10 do, whereas small negative powers of 10 don't.\n        // So in that case, we'll yield a division of exact values rather than a multiplication\n        // of slightly erroneous values.\n        if (exp_val < 0 && exp_val >= -EXACT_POWER_OF_10) {\n            dec_val /= MICROPY_FLOAT_C_FUN(pow)(10, -exp_val);\n        } else {\n            dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val);\n        }\n    }\n\n    // negate value if needed\n    if (dec_neg) {\n        dec_val = -dec_val;\n    }\n\n    // check we parsed something\n    if (str == str_val_start) {\n        goto value_error;\n    }\n\n    // skip trailing space\n    for (; str < top && unichar_isspace(*str); str++) {\n    }\n\n    // check we reached the end of the string\n    if (str != top) {\n        goto value_error;\n    }\n\n    // return the object\n    #if MICROPY_PY_BUILTINS_COMPLEX\n    if (imag) {\n        return mp_obj_new_complex(0, dec_val);\n    } else if (force_complex) {\n        return mp_obj_new_complex(dec_val, 0);\n    }\n    #else\n    if (imag || force_complex) {\n        raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, MP_ERROR_TEXT(\"complex values not supported\")), lex);\n    }\n    #endif\n    else {\n        return mp_obj_new_float(dec_val);\n    }\n\nvalue_error:\n    raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, MP_ERROR_TEXT(\"invalid syntax for number\")), lex);\n\n    #else\n    raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, MP_ERROR_TEXT(\"decimal numbers not supported\")), lex);\n    #endif\n}\n"
  },
  {
    "path": "py/parsenum.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_PARSENUM_H\n#define MICROPY_INCLUDED_PY_PARSENUM_H\n\n#include \"py/mpconfig.h\"\n#include \"py/lexer.h\"\n#include \"py/obj.h\"\n\n// these functions raise a SyntaxError if lex!=NULL, else a ValueError\nmp_obj_t mp_parse_num_integer(const char *restrict str, size_t len, int base, mp_lexer_t *lex);\nmp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex);\n\n#endif // MICROPY_INCLUDED_PY_PARSENUM_H\n"
  },
  {
    "path": "py/parsenumbase.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n#include \"py/parsenumbase.h\"\n\n// find real radix base, and strip preceding '0x', '0o' and '0b'\n// puts base in *base, and returns number of bytes to skip the prefix\nsize_t mp_parse_num_base(const char *str, size_t len, int *base) {\n    const byte *p = (const byte *)str;\n    if (len <= 1) {\n        goto no_prefix;\n    }\n    unichar c = *(p++);\n    if ((*base == 0 || *base == 16) && c == '0') {\n        c = *(p++);\n        if ((c | 32) == 'x') {\n            *base = 16;\n        } else if (*base == 0 && (c | 32) == 'o') {\n            *base = 8;\n        } else if (*base == 0 && (c | 32) == 'b') {\n            *base = 2;\n        } else {\n            if (*base == 0) {\n                *base = 10;\n            }\n            p -= 2;\n        }\n    } else if (*base == 8 && c == '0') {\n        c = *(p++);\n        if ((c | 32) != 'o') {\n            p -= 2;\n        }\n    } else if (*base == 2 && c == '0') {\n        c = *(p++);\n        if ((c | 32) != 'b') {\n            p -= 2;\n        }\n    } else {\n        p--;\n    no_prefix:\n        if (*base == 0) {\n            *base = 10;\n        }\n    }\n    return p - (const byte *)str;\n}\n"
  },
  {
    "path": "py/parsenumbase.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_PARSENUMBASE_H\n#define MICROPY_INCLUDED_PY_PARSENUMBASE_H\n\n#include \"py/mpconfig.h\"\n\nsize_t mp_parse_num_base(const char *str, size_t len, int *base);\n\n#endif // MICROPY_INCLUDED_PY_PARSENUMBASE_H\n"
  },
  {
    "path": "py/persistentcode.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2020 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/reader.h\"\n#include \"py/nativeglue.h\"\n#include \"py/persistentcode.h\"\n#include \"py/bc0.h\"\n#include \"py/objstr.h\"\n#include \"py/mpthread.h\"\n\n#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE\n\n#include \"py/smallint.h\"\n\n#define QSTR_LAST_STATIC MP_QSTR_zip\n\n#if MICROPY_DYNAMIC_COMPILER\n#define MPY_FEATURE_ARCH_DYNAMIC mp_dynamic_compiler.native_arch\n#else\n#define MPY_FEATURE_ARCH_DYNAMIC MPY_FEATURE_ARCH\n#endif\n\n#if MICROPY_PERSISTENT_CODE_LOAD || (MICROPY_PERSISTENT_CODE_SAVE && !MICROPY_DYNAMIC_COMPILER)\n// The bytecode will depend on the number of bits in a small-int, and\n// this function computes that (could make it a fixed constant, but it\n// would need to be defined in mpconfigport.h).\nSTATIC int mp_small_int_bits(void) {\n    mp_int_t i = MP_SMALL_INT_MAX;\n    int n = 1;\n    while (i != 0) {\n        i >>= 1;\n        ++n;\n    }\n    return n;\n}\n#endif\n\n#define QSTR_WINDOW_SIZE (32)\n\ntypedef struct _qstr_window_t {\n    uint16_t idx; // indexes the head of the window\n    uint16_t window[QSTR_WINDOW_SIZE];\n} qstr_window_t;\n\n// Push a qstr to the head of the window, and the tail qstr is overwritten\nSTATIC void qstr_window_push(qstr_window_t *qw, qstr qst) {\n    qw->idx = (qw->idx + 1) % QSTR_WINDOW_SIZE;\n    qw->window[qw->idx] = qst;\n}\n\n// Pull an existing qstr from within the window to the head of the window\nSTATIC qstr qstr_window_pull(qstr_window_t *qw, size_t idx) {\n    qstr qst = qw->window[idx];\n    if (idx > qw->idx) {\n        memmove(&qw->window[idx], &qw->window[idx + 1], (QSTR_WINDOW_SIZE - idx - 1) * sizeof(uint16_t));\n        qw->window[QSTR_WINDOW_SIZE - 1] = qw->window[0];\n        idx = 0;\n    }\n    memmove(&qw->window[idx], &qw->window[idx + 1], (qw->idx - idx) * sizeof(uint16_t));\n    qw->window[qw->idx] = qst;\n    return qst;\n}\n\n#if MICROPY_PERSISTENT_CODE_LOAD\n\n// Access a qstr at the given index, relative to the head of the window (0=head)\nSTATIC qstr qstr_window_access(qstr_window_t *qw, size_t idx) {\n    return qstr_window_pull(qw, (qw->idx + QSTR_WINDOW_SIZE - idx) % QSTR_WINDOW_SIZE);\n}\n\n#endif\n\n#if MICROPY_PERSISTENT_CODE_SAVE\n\n// Insert a qstr at the head of the window, either by pulling an existing one or pushing a new one\nSTATIC size_t qstr_window_insert(qstr_window_t *qw, qstr qst) {\n    for (size_t idx = 0; idx < QSTR_WINDOW_SIZE; ++idx) {\n        if (qw->window[idx] == qst) {\n            qstr_window_pull(qw, idx);\n            return (qw->idx + QSTR_WINDOW_SIZE - idx) % QSTR_WINDOW_SIZE;\n        }\n    }\n    qstr_window_push(qw, qst);\n    return QSTR_WINDOW_SIZE;\n}\n\n#endif\n\ntypedef struct _bytecode_prelude_t {\n    uint n_state;\n    uint n_exc_stack;\n    uint scope_flags;\n    uint n_pos_args;\n    uint n_kwonly_args;\n    uint n_def_pos_args;\n    uint code_info_size;\n} bytecode_prelude_t;\n\n// ip will point to start of opcodes\n// return value will point to simple_name, source_file qstrs\nSTATIC byte *extract_prelude(const byte **ip, bytecode_prelude_t *prelude) {\n    MP_BC_PRELUDE_SIG_DECODE(*ip);\n    prelude->n_state = n_state;\n    prelude->n_exc_stack = n_exc_stack;\n    prelude->scope_flags = scope_flags;\n    prelude->n_pos_args = n_pos_args;\n    prelude->n_kwonly_args = n_kwonly_args;\n    prelude->n_def_pos_args = n_def_pos_args;\n    MP_BC_PRELUDE_SIZE_DECODE(*ip);\n    byte *ip_info = (byte *)*ip;\n    *ip += n_info;\n    *ip += n_cell;\n    return ip_info;\n}\n\n#endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE\n\n#if MICROPY_PERSISTENT_CODE_LOAD\n\n#include \"py/parsenum.h\"\n\nSTATIC int read_byte(mp_reader_t *reader);\nSTATIC size_t read_uint(mp_reader_t *reader, byte **out);\n\n#if MICROPY_EMIT_MACHINE_CODE\n\ntypedef struct _reloc_info_t {\n    mp_reader_t *reader;\n    mp_uint_t *const_table;\n} reloc_info_t;\n\n#if MICROPY_EMIT_THUMB\nSTATIC void asm_thumb_rewrite_mov(uint8_t *pc, uint16_t val) {\n    // high part\n    *(uint16_t *)pc = (*(uint16_t *)pc & 0xfbf0) | (val >> 1 & 0x0400) | (val >> 12);\n    // low part\n    *(uint16_t *)(pc + 2) = (*(uint16_t *)(pc + 2) & 0x0f00) | (val << 4 & 0x7000) | (val & 0x00ff);\n\n}\n#endif\n\nSTATIC void arch_link_qstr(uint8_t *pc, bool is_obj, qstr qst) {\n    mp_uint_t val = qst;\n    if (is_obj) {\n        val = (mp_uint_t)MP_OBJ_NEW_QSTR(qst);\n    }\n    #if MICROPY_EMIT_X86 || MICROPY_EMIT_X64 || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA || MICROPY_EMIT_XTENSAWIN\n    pc[0] = val & 0xff;\n    pc[1] = (val >> 8) & 0xff;\n    pc[2] = (val >> 16) & 0xff;\n    pc[3] = (val >> 24) & 0xff;\n    #elif MICROPY_EMIT_THUMB\n    if (is_obj) {\n        // qstr object, movw and movt\n        asm_thumb_rewrite_mov(pc, val); // movw\n        asm_thumb_rewrite_mov(pc + 4, val >> 16); // movt\n    } else {\n        // qstr number, movw instruction\n        asm_thumb_rewrite_mov(pc, val); // movw\n    }\n    #endif\n}\n\nvoid mp_native_relocate(void *ri_in, uint8_t *text, uintptr_t reloc_text) {\n    // Relocate native code\n    reloc_info_t *ri = ri_in;\n    uint8_t op;\n    uintptr_t *addr_to_adjust = NULL;\n    while ((op = read_byte(ri->reader)) != 0xff) {\n        if (op & 1) {\n            // Point to new location to make adjustments\n            size_t addr = read_uint(ri->reader, NULL);\n            if ((addr & 1) == 0) {\n                // Point to somewhere in text\n                addr_to_adjust = &((uintptr_t *)text)[addr >> 1];\n            } else {\n                // Point to somewhere in rodata\n                addr_to_adjust = &((uintptr_t *)ri->const_table[1])[addr >> 1];\n            }\n        }\n        op >>= 1;\n        uintptr_t dest;\n        size_t n = 1;\n        if (op <= 5) {\n            if (op & 1) {\n                // Read in number of adjustments to make\n                n = read_uint(ri->reader, NULL);\n            }\n            op >>= 1;\n            if (op == 0) {\n                // Destination is text\n                dest = reloc_text;\n            } else {\n                // Destination is rodata (op=1) or bss (op=1 if no rodata, else op=2)\n                dest = ri->const_table[op];\n            }\n        } else if (op == 6) {\n            // Destination is mp_fun_table itself\n            dest = (uintptr_t)&mp_fun_table;\n        } else {\n            // Destination is an entry in mp_fun_table\n            dest = ((uintptr_t *)&mp_fun_table)[op - 7];\n        }\n        while (n--) {\n            *addr_to_adjust++ += dest;\n        }\n    }\n}\n\n#endif\n\nSTATIC int read_byte(mp_reader_t *reader) {\n    return reader->readbyte(reader->data);\n}\n\nSTATIC void read_bytes(mp_reader_t *reader, byte *buf, size_t len) {\n    while (len-- > 0) {\n        *buf++ = reader->readbyte(reader->data);\n    }\n}\n\nSTATIC size_t read_uint(mp_reader_t *reader, byte **out) {\n    size_t unum = 0;\n    for (;;) {\n        byte b = reader->readbyte(reader->data);\n        if (out != NULL) {\n            **out = b;\n            ++*out;\n        }\n        unum = (unum << 7) | (b & 0x7f);\n        if ((b & 0x80) == 0) {\n            break;\n        }\n    }\n    return unum;\n}\n\nSTATIC qstr load_qstr(mp_reader_t *reader, qstr_window_t *qw) {\n    size_t len = read_uint(reader, NULL);\n    if (len == 0) {\n        // static qstr\n        return read_byte(reader);\n    }\n    if (len & 1) {\n        // qstr in window\n        return qstr_window_access(qw, len >> 1);\n    }\n    len >>= 1;\n    char *str = m_new(char, len);\n    read_bytes(reader, (byte *)str, len);\n    qstr qst = qstr_from_strn(str, len);\n    m_del(char, str, len);\n    qstr_window_push(qw, qst);\n    return qst;\n}\n\nSTATIC mp_obj_t load_obj(mp_reader_t *reader) {\n    byte obj_type = read_byte(reader);\n    if (obj_type == 'e') {\n        return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj);\n    } else {\n        size_t len = read_uint(reader, NULL);\n        vstr_t vstr;\n        vstr_init_len(&vstr, len);\n        read_bytes(reader, (byte *)vstr.buf, len);\n        if (obj_type == 's' || obj_type == 'b') {\n            return mp_obj_new_str_from_vstr(obj_type == 's' ? &mp_type_str : &mp_type_bytes, &vstr);\n        } else if (obj_type == 'i') {\n            return mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL);\n        } else {\n            assert(obj_type == 'f' || obj_type == 'c');\n            return mp_parse_num_decimal(vstr.buf, vstr.len, obj_type == 'c', false, NULL);\n        }\n    }\n}\n\nSTATIC void load_prelude_qstrs(mp_reader_t *reader, qstr_window_t *qw, byte *ip) {\n    qstr simple_name = load_qstr(reader, qw);\n    ip[0] = simple_name;\n    ip[1] = simple_name >> 8;\n    qstr source_file = load_qstr(reader, qw);\n    ip[2] = source_file;\n    ip[3] = source_file >> 8;\n}\n\nSTATIC void load_prelude(mp_reader_t *reader, qstr_window_t *qw, byte **ip, bytecode_prelude_t *prelude) {\n    // Read in the prelude header\n    byte *ip_read = *ip;\n    read_uint(reader, &ip_read);                    // read in n_state/etc (is effectively a var-uint)\n    read_uint(reader, &ip_read);                    // read in n_info/n_cell (is effectively a var-uint)\n\n    // Prelude header has been read into *ip, now decode and extract values from it\n    extract_prelude((const byte **)ip, prelude);\n\n    // Load qstrs in prelude\n    load_prelude_qstrs(reader, qw, ip_read);\n    ip_read += 4;\n\n    // Read remaining code info\n    read_bytes(reader, ip_read, *ip - ip_read);\n}\n\nSTATIC void load_bytecode(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte *ip_top) {\n    while (ip < ip_top) {\n        *ip = read_byte(reader);\n        size_t sz;\n        uint f = mp_opcode_format(ip, &sz, false);\n        ++ip;\n        --sz;\n        if (f == MP_BC_FORMAT_QSTR) {\n            qstr qst = load_qstr(reader, qw);\n            *ip++ = qst;\n            *ip++ = qst >> 8;\n            sz -= 2;\n        } else if (f == MP_BC_FORMAT_VAR_UINT) {\n            while ((*ip++ = read_byte(reader)) & 0x80) {\n            }\n        }\n        read_bytes(reader, ip, sz);\n        ip += sz;\n    }\n}\n\nSTATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) {\n    // Load function kind and data length\n    size_t kind_len = read_uint(reader, NULL);\n    int kind = (kind_len & 3) + MP_CODE_BYTECODE;\n    size_t fun_data_len = kind_len >> 2;\n\n    #if !MICROPY_EMIT_MACHINE_CODE\n    if (kind != MP_CODE_BYTECODE) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"incompatible .mpy file\"));\n    }\n    #endif\n\n    uint8_t *fun_data = NULL;\n    bytecode_prelude_t prelude = {0};\n    #if MICROPY_EMIT_MACHINE_CODE\n    size_t prelude_offset = 0;\n    mp_uint_t type_sig = 0;\n    size_t n_qstr_link = 0;\n    #endif\n\n    if (kind == MP_CODE_BYTECODE) {\n        // Allocate memory for the bytecode\n        fun_data = m_new(uint8_t, fun_data_len);\n\n        // Load prelude\n        byte *ip = fun_data;\n        load_prelude(reader, qw, &ip, &prelude);\n\n        // Load bytecode\n        load_bytecode(reader, qw, ip, fun_data + fun_data_len);\n\n    #if MICROPY_EMIT_MACHINE_CODE\n    } else {\n        // Allocate memory for native data and load it\n        size_t fun_alloc;\n        MP_PLAT_ALLOC_EXEC(fun_data_len, (void **)&fun_data, &fun_alloc);\n        read_bytes(reader, fun_data, fun_data_len);\n\n        if (kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER) {\n            // Parse qstr link table and link native code\n            n_qstr_link = read_uint(reader, NULL);\n            for (size_t i = 0; i < n_qstr_link; ++i) {\n                size_t off = read_uint(reader, NULL);\n                qstr qst = load_qstr(reader, qw);\n                uint8_t *dest = fun_data + (off >> 2);\n                if ((off & 3) == 0) {\n                    // Generic 16-bit link\n                    dest[0] = qst & 0xff;\n                    dest[1] = (qst >> 8) & 0xff;\n                } else if ((off & 3) == 3) {\n                    // Generic, aligned qstr-object link\n                    *(mp_obj_t *)dest = MP_OBJ_NEW_QSTR(qst);\n                } else {\n                    // Architecture-specific link\n                    arch_link_qstr(dest, (off & 3) == 2, qst);\n                }\n            }\n        }\n\n        if (kind == MP_CODE_NATIVE_PY) {\n            // Extract prelude for later use\n            prelude_offset = read_uint(reader, NULL);\n            const byte *ip = fun_data + prelude_offset;\n            byte *ip_info = extract_prelude(&ip, &prelude);\n            // Load qstrs in prelude\n            load_prelude_qstrs(reader, qw, ip_info);\n        } else {\n            // Load basic scope info for viper and asm\n            prelude.scope_flags = read_uint(reader, NULL);\n            prelude.n_pos_args = 0;\n            prelude.n_kwonly_args = 0;\n            if (kind == MP_CODE_NATIVE_ASM) {\n                prelude.n_pos_args = read_uint(reader, NULL);\n                type_sig = read_uint(reader, NULL);\n            }\n        }\n    #endif\n    }\n\n    size_t n_obj = 0;\n    size_t n_raw_code = 0;\n    mp_uint_t *const_table = NULL;\n\n    if (kind != MP_CODE_NATIVE_ASM) {\n        // Load constant table for bytecode, native and viper\n\n        // Number of entries in constant table\n        n_obj = read_uint(reader, NULL);\n        n_raw_code = read_uint(reader, NULL);\n\n        // Allocate constant table\n        size_t n_alloc = prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code;\n        #if MICROPY_EMIT_MACHINE_CODE\n        if (kind != MP_CODE_BYTECODE) {\n            ++n_alloc; // additional entry for mp_fun_table\n            if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) {\n                ++n_alloc; // additional entry for rodata\n            }\n            if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) {\n                ++n_alloc; // additional entry for BSS\n            }\n        }\n        #endif\n\n        const_table = m_new(mp_uint_t, n_alloc);\n        mp_uint_t *ct = const_table;\n\n        // Load function argument names (initial entries in const_table)\n        // (viper has n_pos_args=n_kwonly_args=0 so doesn't load any qstrs here)\n        for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) {\n            *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader, qw));\n        }\n\n        #if MICROPY_EMIT_MACHINE_CODE\n        if (kind != MP_CODE_BYTECODE) {\n            // Populate mp_fun_table entry\n            *ct++ = (mp_uint_t)(uintptr_t)&mp_fun_table;\n\n            // Allocate and load rodata if needed\n            if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) {\n                size_t size = read_uint(reader, NULL);\n                uint8_t *rodata = m_new(uint8_t, size);\n                read_bytes(reader, rodata, size);\n                *ct++ = (uintptr_t)rodata;\n            }\n\n            // Allocate BSS if needed\n            if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) {\n                size_t size = read_uint(reader, NULL);\n                uint8_t *bss = m_new0(uint8_t, size);\n                *ct++ = (uintptr_t)bss;\n            }\n        }\n        #endif\n\n        // Load constant objects and raw code children\n        for (size_t i = 0; i < n_obj; ++i) {\n            *ct++ = (mp_uint_t)load_obj(reader);\n        }\n        for (size_t i = 0; i < n_raw_code; ++i) {\n            *ct++ = (mp_uint_t)(uintptr_t)load_raw_code(reader, qw);\n        }\n    }\n\n    // Create raw_code and return it\n    mp_raw_code_t *rc = mp_emit_glue_new_raw_code();\n    if (kind == MP_CODE_BYTECODE) {\n        // Assign bytecode to raw code object\n        mp_emit_glue_assign_bytecode(rc, fun_data,\n            #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS\n            fun_data_len,\n            #endif\n            const_table,\n            #if MICROPY_PERSISTENT_CODE_SAVE\n            n_obj, n_raw_code,\n            #endif\n            prelude.scope_flags);\n\n    #if MICROPY_EMIT_MACHINE_CODE\n    } else {\n        // Relocate and commit code to executable address space\n        reloc_info_t ri = {reader, const_table};\n        #if defined(MP_PLAT_COMMIT_EXEC)\n        void *opt_ri = (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) ? &ri : NULL;\n        fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len, opt_ri);\n        #else\n        if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) {\n            #if MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE\n            // If native code needs relocations then it's not guaranteed that a pointer to\n            // the head of `buf` (containing the machine code) will be retained for the GC\n            // to trace.  This is because native functions can start inside `buf` and so\n            // it's possible that the only GC-reachable pointers are pointers inside `buf`.\n            // So put this `buf` on a list of reachable root pointers.\n            if (MP_STATE_PORT(track_reloc_code_list) == MP_OBJ_NULL) {\n                MP_STATE_PORT(track_reloc_code_list) = mp_obj_new_list(0, NULL);\n            }\n            mp_obj_list_append(MP_STATE_PORT(track_reloc_code_list), MP_OBJ_FROM_PTR(fun_data));\n            #endif\n            // Do the relocations.\n            mp_native_relocate(&ri, fun_data, (uintptr_t)fun_data);\n        }\n        #endif\n\n        // Assign native code to raw code object\n        mp_emit_glue_assign_native(rc, kind,\n            fun_data, fun_data_len, const_table,\n            #if MICROPY_PERSISTENT_CODE_SAVE\n            prelude_offset,\n            n_obj, n_raw_code,\n            n_qstr_link, NULL,\n            #endif\n            prelude.n_pos_args, prelude.scope_flags, type_sig);\n    #endif\n    }\n    return rc;\n}\n\nmp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) {\n    byte header[4];\n    read_bytes(reader, header, sizeof(header));\n    if (header[0] != 'M'\n        || header[1] != MPY_VERSION\n        || MPY_FEATURE_DECODE_FLAGS(header[2]) != MPY_FEATURE_FLAGS\n        || header[3] > mp_small_int_bits()\n        || read_uint(reader, NULL) > QSTR_WINDOW_SIZE) {\n        mp_raise_ValueError(MP_ERROR_TEXT(\"incompatible .mpy file\"));\n    }\n    if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE) {\n        byte arch = MPY_FEATURE_DECODE_ARCH(header[2]);\n        if (!MPY_FEATURE_ARCH_TEST(arch)) {\n            mp_raise_ValueError(MP_ERROR_TEXT(\"incompatible .mpy arch\"));\n        }\n    }\n    qstr_window_t qw;\n    qw.idx = 0;\n    mp_raw_code_t *rc = load_raw_code(reader, &qw);\n    reader->close(reader->data);\n    return rc;\n}\n\nmp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len) {\n    mp_reader_t reader;\n    mp_reader_new_mem(&reader, buf, len, 0);\n    return mp_raw_code_load(&reader);\n}\n\n#if MICROPY_HAS_FILE_READER\n\nmp_raw_code_t *mp_raw_code_load_file(const char *filename) {\n    mp_reader_t reader;\n    mp_reader_new_file(&reader, filename);\n    return mp_raw_code_load(&reader);\n}\n\n#endif // MICROPY_HAS_FILE_READER\n\n#endif // MICROPY_PERSISTENT_CODE_LOAD\n\n#if MICROPY_PERSISTENT_CODE_SAVE\n\n#include \"py/objstr.h\"\n\nSTATIC void mp_print_bytes(mp_print_t *print, const byte *data, size_t len) {\n    print->print_strn(print->data, (const char *)data, len);\n}\n\n#define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7)\nSTATIC void mp_print_uint(mp_print_t *print, size_t n) {\n    byte buf[BYTES_FOR_INT];\n    byte *p = buf + sizeof(buf);\n    *--p = n & 0x7f;\n    n >>= 7;\n    for (; n != 0; n >>= 7) {\n        *--p = 0x80 | (n & 0x7f);\n    }\n    print->print_strn(print->data, (char *)p, buf + sizeof(buf) - p);\n}\n\nSTATIC void save_qstr(mp_print_t *print, qstr_window_t *qw, qstr qst) {\n    if (qst <= QSTR_LAST_STATIC) {\n        // encode static qstr\n        byte buf[2] = {0, qst & 0xff};\n        mp_print_bytes(print, buf, 2);\n        return;\n    }\n    size_t idx = qstr_window_insert(qw, qst);\n    if (idx < QSTR_WINDOW_SIZE) {\n        // qstr found in window, encode index to it\n        mp_print_uint(print, idx << 1 | 1);\n        return;\n    }\n    size_t len;\n    const byte *str = qstr_data(qst, &len);\n    mp_print_uint(print, len << 1);\n    mp_print_bytes(print, str, len);\n}\n\nSTATIC void save_obj(mp_print_t *print, mp_obj_t o) {\n    if (mp_obj_is_str_or_bytes(o)) {\n        byte obj_type;\n        if (mp_obj_is_str(o)) {\n            obj_type = 's';\n        } else {\n            obj_type = 'b';\n        }\n        size_t len;\n        const char *str = mp_obj_str_get_data(o, &len);\n        mp_print_bytes(print, &obj_type, 1);\n        mp_print_uint(print, len);\n        mp_print_bytes(print, (const byte *)str, len);\n    } else if (MP_OBJ_TO_PTR(o) == &mp_const_ellipsis_obj) {\n        byte obj_type = 'e';\n        mp_print_bytes(print, &obj_type, 1);\n    } else {\n        // we save numbers using a simplistic text representation\n        // TODO could be improved\n        byte obj_type;\n        if (mp_obj_is_type(o, &mp_type_int)) {\n            obj_type = 'i';\n        #if MICROPY_PY_BUILTINS_COMPLEX\n        } else if (mp_obj_is_type(o, &mp_type_complex)) {\n            obj_type = 'c';\n        #endif\n        } else {\n            assert(mp_obj_is_float(o));\n            obj_type = 'f';\n        }\n        vstr_t vstr;\n        mp_print_t pr;\n        vstr_init_print(&vstr, 10, &pr);\n        mp_obj_print_helper(&pr, o, PRINT_REPR);\n        mp_print_bytes(print, &obj_type, 1);\n        mp_print_uint(print, vstr.len);\n        mp_print_bytes(print, (const byte *)vstr.buf, vstr.len);\n        vstr_clear(&vstr);\n    }\n}\n\nSTATIC void save_prelude_qstrs(mp_print_t *print, qstr_window_t *qw, const byte *ip) {\n    save_qstr(print, qw, ip[0] | (ip[1] << 8)); // simple_name\n    save_qstr(print, qw, ip[2] | (ip[3] << 8)); // source_file\n}\n\nSTATIC void save_bytecode(mp_print_t *print, qstr_window_t *qw, const byte *ip, const byte *ip_top) {\n    while (ip < ip_top) {\n        size_t sz;\n        uint f = mp_opcode_format(ip, &sz, true);\n        if (f == MP_BC_FORMAT_QSTR) {\n            mp_print_bytes(print, ip, 1);\n            qstr qst = ip[1] | (ip[2] << 8);\n            save_qstr(print, qw, qst);\n            ip += 3;\n            sz -= 3;\n        }\n        mp_print_bytes(print, ip, sz);\n        ip += sz;\n    }\n}\n\nSTATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *qstr_window) {\n    // Save function kind and data length\n    mp_print_uint(print, (rc->fun_data_len << 2) | (rc->kind - MP_CODE_BYTECODE));\n\n    bytecode_prelude_t prelude;\n\n    if (rc->kind == MP_CODE_BYTECODE) {\n        // Extract prelude\n        const byte *ip = rc->fun_data;\n        const byte *ip_info = extract_prelude(&ip, &prelude);\n\n        // Save prelude\n        mp_print_bytes(print, rc->fun_data, ip_info - (const byte *)rc->fun_data);\n        save_prelude_qstrs(print, qstr_window, ip_info);\n        ip_info += 4;\n        mp_print_bytes(print, ip_info, ip - ip_info);\n\n        // Save bytecode\n        const byte *ip_top = (const byte *)rc->fun_data + rc->fun_data_len;\n        save_bytecode(print, qstr_window, ip, ip_top);\n    #if MICROPY_EMIT_MACHINE_CODE\n    } else {\n        // Save native code\n        mp_print_bytes(print, rc->fun_data, rc->fun_data_len);\n\n        if (rc->kind == MP_CODE_NATIVE_PY || rc->kind == MP_CODE_NATIVE_VIPER) {\n            // Save qstr link table for native code\n            mp_print_uint(print, rc->n_qstr);\n            for (size_t i = 0; i < rc->n_qstr; ++i) {\n                mp_print_uint(print, rc->qstr_link[i].off);\n                save_qstr(print, qstr_window, rc->qstr_link[i].qst);\n            }\n        }\n\n        if (rc->kind == MP_CODE_NATIVE_PY) {\n            // Save prelude size\n            mp_print_uint(print, rc->prelude_offset);\n\n            // Extract prelude and save qstrs in prelude\n            const byte *ip = (const byte *)rc->fun_data + rc->prelude_offset;\n            const byte *ip_info = extract_prelude(&ip, &prelude);\n            save_prelude_qstrs(print, qstr_window, ip_info);\n        } else {\n            // Save basic scope info for viper and asm\n            mp_print_uint(print, rc->scope_flags & MP_SCOPE_FLAG_ALL_SIG);\n            prelude.n_pos_args = 0;\n            prelude.n_kwonly_args = 0;\n            if (rc->kind == MP_CODE_NATIVE_ASM) {\n                mp_print_uint(print, rc->n_pos_args);\n                mp_print_uint(print, rc->type_sig);\n            }\n        }\n    #endif\n    }\n\n    if (rc->kind != MP_CODE_NATIVE_ASM) {\n        // Save constant table for bytecode, native and viper\n\n        // Number of entries in constant table\n        mp_print_uint(print, rc->n_obj);\n        mp_print_uint(print, rc->n_raw_code);\n\n        const mp_uint_t *const_table = rc->const_table;\n\n        // Save function argument names (initial entries in const_table)\n        // (viper has n_pos_args=n_kwonly_args=0 so doesn't save any qstrs here)\n        for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) {\n            mp_obj_t o = (mp_obj_t)*const_table++;\n            save_qstr(print, qstr_window, MP_OBJ_QSTR_VALUE(o));\n        }\n\n        if (rc->kind != MP_CODE_BYTECODE) {\n            // Skip saving mp_fun_table entry\n            ++const_table;\n        }\n\n        // Save constant objects and raw code children\n        for (size_t i = 0; i < rc->n_obj; ++i) {\n            save_obj(print, (mp_obj_t)*const_table++);\n        }\n        for (size_t i = 0; i < rc->n_raw_code; ++i) {\n            save_raw_code(print, (mp_raw_code_t *)(uintptr_t)*const_table++, qstr_window);\n        }\n    }\n}\n\nSTATIC bool mp_raw_code_has_native(mp_raw_code_t *rc) {\n    if (rc->kind != MP_CODE_BYTECODE) {\n        return true;\n    }\n\n    const byte *ip = rc->fun_data;\n    bytecode_prelude_t prelude;\n    extract_prelude(&ip, &prelude);\n\n    const mp_uint_t *const_table = rc->const_table\n        + prelude.n_pos_args + prelude.n_kwonly_args\n        + rc->n_obj;\n\n    for (size_t i = 0; i < rc->n_raw_code; ++i) {\n        if (mp_raw_code_has_native((mp_raw_code_t *)(uintptr_t)*const_table++)) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) {\n    // header contains:\n    //  byte  'M'\n    //  byte  version\n    //  byte  feature flags\n    //  byte  number of bits in a small int\n    //  uint  size of qstr window\n    byte header[4] = {\n        'M',\n        MPY_VERSION,\n        MPY_FEATURE_ENCODE_FLAGS(MPY_FEATURE_FLAGS_DYNAMIC),\n        #if MICROPY_DYNAMIC_COMPILER\n        mp_dynamic_compiler.small_int_bits,\n        #else\n        mp_small_int_bits(),\n        #endif\n    };\n    if (mp_raw_code_has_native(rc)) {\n        header[2] |= MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC);\n    }\n    mp_print_bytes(print, header, sizeof(header));\n    mp_print_uint(print, QSTR_WINDOW_SIZE);\n\n    qstr_window_t qw;\n    qw.idx = 0;\n    memset(qw.window, 0, sizeof(qw.window));\n    save_raw_code(print, rc, &qw);\n}\n\n// here we define mp_raw_code_save_file depending on the port\n// TODO abstract this away properly\n\n#if defined(__i386__) || defined(__x86_64__) || defined(_WIN32) || defined(__unix__)\n\n#include <unistd.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n\nSTATIC void fd_print_strn(void *env, const char *str, size_t len) {\n    int fd = (intptr_t)env;\n    MP_THREAD_GIL_EXIT();\n    ssize_t ret = write(fd, str, len);\n    MP_THREAD_GIL_ENTER();\n    (void)ret;\n}\n\nvoid mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename) {\n    MP_THREAD_GIL_EXIT();\n    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);\n    MP_THREAD_GIL_ENTER();\n    mp_print_t fd_print = {(void *)(intptr_t)fd, fd_print_strn};\n    mp_raw_code_save(rc, &fd_print);\n    MP_THREAD_GIL_EXIT();\n    close(fd);\n    MP_THREAD_GIL_ENTER();\n}\n\n#else\n#error mp_raw_code_save_file not implemented for this platform\n#endif\n\n#endif // MICROPY_PERSISTENT_CODE_SAVE\n"
  },
  {
    "path": "py/persistentcode.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_PERSISTENTCODE_H\n#define MICROPY_INCLUDED_PY_PERSISTENTCODE_H\n\n#include \"py/mpprint.h\"\n#include \"py/reader.h\"\n#include \"py/emitglue.h\"\n\n// The current version of .mpy files\n#define MPY_VERSION 5\n\n// Macros to encode/decode flags to/from the feature byte\n#define MPY_FEATURE_ENCODE_FLAGS(flags) (flags)\n#define MPY_FEATURE_DECODE_FLAGS(feat) ((feat) & 3)\n\n// Macros to encode/decode native architecture to/from the feature byte\n#define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2)\n#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2)\n\n// The feature flag bits encode the compile-time config options that\n// affect the generate bytecode.\n#define MPY_FEATURE_FLAGS ( \\\n    ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \\\n    | ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \\\n    )\n// This is a version of the flags that can be configured at runtime.\n#define MPY_FEATURE_FLAGS_DYNAMIC ( \\\n    ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) << 0) \\\n    | ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \\\n    )\n\n// Define the host architecture\n#if MICROPY_EMIT_X86\n    #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86)\n#elif MICROPY_EMIT_X64\n    #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64)\n#elif MICROPY_EMIT_THUMB\n    #if defined(__thumb2__)\n        #if defined(__ARM_FP) && (__ARM_FP & 8) == 8\n            #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMDP)\n        #elif defined(__ARM_FP) && (__ARM_FP & 4) == 4\n            #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMSP)\n        #else\n            #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EM)\n        #endif\n    #else\n        #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7M)\n    #endif\n    #define MPY_FEATURE_ARCH_TEST(x) (MP_NATIVE_ARCH_ARMV6M <= (x) && (x) <= MPY_FEATURE_ARCH)\n#elif MICROPY_EMIT_ARM\n    #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6)\n#elif MICROPY_EMIT_XTENSA\n    #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA)\n#elif MICROPY_EMIT_XTENSAWIN\n    #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN)\n#else\n    #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE)\n#endif\n\n#ifndef MPY_FEATURE_ARCH_TEST\n#define MPY_FEATURE_ARCH_TEST(x) ((x) == MPY_FEATURE_ARCH)\n#endif\n\n// 16-bit little-endian integer with the second and third bytes of supported .mpy files\n#define MPY_FILE_HEADER_INT (MPY_VERSION \\\n    | (MPY_FEATURE_ENCODE_FLAGS(MPY_FEATURE_FLAGS) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH)) << 8)\n\nenum {\n    MP_NATIVE_ARCH_NONE = 0,\n    MP_NATIVE_ARCH_X86,\n    MP_NATIVE_ARCH_X64,\n    MP_NATIVE_ARCH_ARMV6,\n    MP_NATIVE_ARCH_ARMV6M,\n    MP_NATIVE_ARCH_ARMV7M,\n    MP_NATIVE_ARCH_ARMV7EM,\n    MP_NATIVE_ARCH_ARMV7EMSP,\n    MP_NATIVE_ARCH_ARMV7EMDP,\n    MP_NATIVE_ARCH_XTENSA,\n    MP_NATIVE_ARCH_XTENSAWIN,\n};\n\nmp_raw_code_t *mp_raw_code_load(mp_reader_t *reader);\nmp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len);\nmp_raw_code_t *mp_raw_code_load_file(const char *filename);\n\nvoid mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print);\nvoid mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename);\n\nvoid mp_native_relocate(void *reloc, uint8_t *text, uintptr_t reloc_text);\n\n#endif // MICROPY_INCLUDED_PY_PERSISTENTCODE_H\n"
  },
  {
    "path": "py/profile.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) SatoshiLabs\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/profile.h\"\n#include \"py/bc0.h\"\n#include \"py/gc.h\"\n\n#if MICROPY_PY_SYS_SETTRACE\n\n#define prof_trace_cb MP_STATE_THREAD(prof_trace_callback)\n\nSTATIC uint mp_prof_bytecode_lineno(const mp_raw_code_t *rc, size_t bc) {\n    const mp_bytecode_prelude_t *prelude = &rc->prelude;\n    return mp_bytecode_get_source_line(prelude->line_info, bc);\n}\n\nvoid mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude) {\n    const byte *ip = bytecode;\n\n    MP_BC_PRELUDE_SIG_DECODE(ip);\n    prelude->n_state = n_state;\n    prelude->n_exc_stack = n_exc_stack;\n    prelude->scope_flags = scope_flags;\n    prelude->n_pos_args = n_pos_args;\n    prelude->n_kwonly_args = n_kwonly_args;\n    prelude->n_def_pos_args = n_def_pos_args;\n\n    MP_BC_PRELUDE_SIZE_DECODE(ip);\n\n    prelude->line_info = ip + 4;\n    prelude->opcodes = ip + n_info + n_cell;\n\n    qstr block_name = ip[0] | (ip[1] << 8);\n    qstr source_file = ip[2] | (ip[3] << 8);\n    prelude->qstr_block_name = block_name;\n    prelude->qstr_source_file = source_file;\n}\n\n/******************************************************************************/\n// code object\n\nSTATIC void code_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_code_t *o = MP_OBJ_TO_PTR(o_in);\n    const mp_raw_code_t *rc = o->rc;\n    const mp_bytecode_prelude_t *prelude = &rc->prelude;\n    mp_printf(print,\n        \"<code object %q at 0x%p, file \\\"%q\\\", line %d>\",\n        prelude->qstr_block_name,\n        o,\n        prelude->qstr_source_file,\n        rc->line_of_definition\n        );\n}\n\nSTATIC mp_obj_tuple_t *code_consts(const mp_raw_code_t *rc) {\n    const mp_bytecode_prelude_t *prelude = &rc->prelude;\n    int start = prelude->n_pos_args + prelude->n_kwonly_args + rc->n_obj;\n    int stop = prelude->n_pos_args + prelude->n_kwonly_args + rc->n_obj + rc->n_raw_code;\n    mp_obj_tuple_t *consts = MP_OBJ_TO_PTR(mp_obj_new_tuple(stop - start + 1, NULL));\n\n    size_t const_no = 0;\n    for (int i = start; i < stop; ++i) {\n        mp_obj_t code = mp_obj_new_code((const mp_raw_code_t *)MP_OBJ_TO_PTR(rc->const_table[i]));\n        if (code == MP_OBJ_NULL) {\n            m_malloc_fail(sizeof(mp_obj_code_t));\n        }\n        consts->items[const_no++] = code;\n    }\n    consts->items[const_no++] = mp_const_none;\n\n    return consts;\n}\n\nSTATIC mp_obj_t raw_code_lnotab(const mp_raw_code_t *rc) {\n    // const mp_bytecode_prelude_t *prelude = &rc->prelude;\n    uint start = 0;\n    uint stop = rc->fun_data_len - start;\n\n    uint last_lineno = mp_prof_bytecode_lineno(rc, start);\n    uint lasti = 0;\n\n    const uint buffer_chunk_size = (stop - start) >> 2; // heuristic magic\n    uint buffer_size = buffer_chunk_size;\n    byte *buffer = m_new(byte, buffer_size);\n    uint buffer_index = 0;\n\n    for (uint i = start; i < stop; ++i) {\n        uint lineno = mp_prof_bytecode_lineno(rc, i);\n        size_t line_diff = lineno - last_lineno;\n        if (line_diff > 0) {\n            uint instr_diff = (i - start) - lasti;\n\n            assert(instr_diff < 256);\n            assert(line_diff < 256);\n\n            if (buffer_index + 2 > buffer_size) {\n                buffer = m_renew(byte, buffer, buffer_size, buffer_size + buffer_chunk_size);\n                buffer_size = buffer_size + buffer_chunk_size;\n            }\n            last_lineno = lineno;\n            lasti = i - start;\n            buffer[buffer_index++] = instr_diff;\n            buffer[buffer_index++] = line_diff;\n        }\n    }\n\n    mp_obj_t o = mp_obj_new_bytes(buffer, buffer_index);\n    m_del(byte, buffer, buffer_size);\n    return o;\n}\n\nSTATIC void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] != MP_OBJ_NULL) {\n        // not load attribute\n        return;\n    }\n    mp_obj_code_t *o = MP_OBJ_TO_PTR(self_in);\n    const mp_raw_code_t *rc = o->rc;\n    const mp_bytecode_prelude_t *prelude = &rc->prelude;\n    switch (attr) {\n        case MP_QSTR_co_code:\n            dest[0] = mp_obj_new_bytes(\n                (void *)prelude->opcodes,\n                rc->fun_data_len - (prelude->opcodes - (const byte *)rc->fun_data)\n                );\n            break;\n        case MP_QSTR_co_consts:\n            dest[0] = MP_OBJ_FROM_PTR(code_consts(rc));\n            break;\n        case MP_QSTR_co_filename:\n            dest[0] = MP_OBJ_NEW_QSTR(prelude->qstr_source_file);\n            break;\n        case MP_QSTR_co_firstlineno:\n            dest[0] = MP_OBJ_NEW_SMALL_INT(mp_prof_bytecode_lineno(rc, 0));\n            break;\n        case MP_QSTR_co_name:\n            dest[0] = MP_OBJ_NEW_QSTR(prelude->qstr_block_name);\n            break;\n        case MP_QSTR_co_names:\n            dest[0] = MP_OBJ_FROM_PTR(o->dict_locals);\n            break;\n        case MP_QSTR_co_lnotab:\n            if (!o->lnotab) {\n                o->lnotab = raw_code_lnotab(rc);\n            }\n            dest[0] = o->lnotab;\n            break;\n    }\n}\n\nconst mp_obj_type_t mp_type_code = {\n    { &mp_type_type },\n    .name = MP_QSTR_code,\n    .print = code_print,\n    .unary_op = mp_generic_unary_op,\n    .attr = code_attr,\n};\n\nmp_obj_t mp_obj_new_code(const mp_raw_code_t *rc) {\n    mp_obj_code_t *o = m_new_obj_maybe(mp_obj_code_t);\n    if (o == NULL) {\n        return MP_OBJ_NULL;\n    }\n    o->base.type = &mp_type_code;\n    o->rc = rc;\n    o->dict_locals = mp_locals_get(); // this is a wrong! how to do this properly?\n    o->lnotab = MP_OBJ_NULL;\n    return MP_OBJ_FROM_PTR(o);\n}\n\n/******************************************************************************/\n// frame object\n\nSTATIC void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {\n    (void)kind;\n    mp_obj_frame_t *frame = MP_OBJ_TO_PTR(o_in);\n    mp_obj_code_t *code = frame->code;\n    const mp_raw_code_t *rc = code->rc;\n    const mp_bytecode_prelude_t *prelude = &rc->prelude;\n    mp_printf(print,\n        \"<frame at 0x%p, file '%q', line %d, code %q>\",\n        frame,\n        prelude->qstr_source_file,\n        frame->lineno,\n        prelude->qstr_block_name\n        );\n}\n\nSTATIC void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {\n    if (dest[0] != MP_OBJ_NULL) {\n        // not load attribute\n        return;\n    }\n\n    mp_obj_frame_t *o = MP_OBJ_TO_PTR(self_in);\n\n    switch (attr) {\n        case MP_QSTR_f_back:\n            dest[0] = mp_const_none;\n            if (o->code_state->prev_state) {\n                dest[0] = MP_OBJ_FROM_PTR(o->code_state->prev_state->frame);\n            }\n            break;\n        case MP_QSTR_f_code:\n            dest[0] = MP_OBJ_FROM_PTR(o->code);\n            break;\n        case MP_QSTR_f_globals:\n            dest[0] = MP_OBJ_FROM_PTR(o->code_state->fun_bc->globals);\n            break;\n        case MP_QSTR_f_lasti:\n            dest[0] = MP_OBJ_NEW_SMALL_INT(o->lasti);\n            break;\n        case MP_QSTR_f_lineno:\n            dest[0] = MP_OBJ_NEW_SMALL_INT(o->lineno);\n            break;\n    }\n}\n\nconst mp_obj_type_t mp_type_frame = {\n    { &mp_type_type },\n    .name = MP_QSTR_frame,\n    .print = frame_print,\n    .unary_op = mp_generic_unary_op,\n    .attr = frame_attr,\n};\n\nmp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state) {\n    if (gc_is_locked()) {\n        return MP_OBJ_NULL;\n    }\n\n    mp_obj_frame_t *o = m_new_obj_maybe(mp_obj_frame_t);\n    if (o == NULL) {\n        return MP_OBJ_NULL;\n    }\n\n    mp_obj_code_t *code = o->code = MP_OBJ_TO_PTR(mp_obj_new_code(code_state->fun_bc->rc));\n    if (code == NULL) {\n        return MP_OBJ_NULL;\n    }\n\n    const mp_raw_code_t *rc = code->rc;\n    const mp_bytecode_prelude_t *prelude = &rc->prelude;\n    o->code_state = code_state;\n    o->base.type = &mp_type_frame;\n    o->back = NULL;\n    o->code = code;\n    o->lasti = code_state->ip - prelude->opcodes;\n    o->lineno = mp_prof_bytecode_lineno(rc, o->lasti);\n    o->trace_opcodes = false;\n    o->callback = MP_OBJ_NULL;\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\n\n/******************************************************************************/\n// Trace logic\n\ntypedef struct {\n    struct _mp_obj_frame_t *frame;\n    mp_obj_t event;\n    mp_obj_t arg;\n} prof_callback_args_t;\n\nSTATIC mp_obj_t mp_prof_callback_invoke(mp_obj_t callback, prof_callback_args_t *args) {\n    assert(mp_obj_is_callable(callback));\n\n    mp_prof_is_executing = true;\n\n    mp_obj_t a[3] = {MP_OBJ_FROM_PTR(args->frame), args->event, args->arg};\n    mp_obj_t top = mp_call_function_n_kw(callback, 3, 0, a);\n\n    mp_prof_is_executing = false;\n\n    if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {\n        mp_obj_t obj = MP_STATE_VM(mp_pending_exception);\n        MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;\n        nlr_raise(obj);\n    }\n    return top;\n}\n\nmp_obj_t mp_prof_settrace(mp_obj_t callback) {\n    if (mp_obj_is_callable(callback)) {\n        prof_trace_cb = callback;\n    } else {\n        prof_trace_cb = MP_OBJ_NULL;\n    }\n    return mp_const_none;\n}\n\nmp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state) {\n    assert(!mp_prof_is_executing);\n\n    mp_obj_frame_t *frame = MP_OBJ_TO_PTR(mp_obj_new_frame(code_state));\n    if (frame == NULL) {\n        // Couldn't allocate a frame object\n        return MP_OBJ_NULL;\n    }\n\n    if (code_state->prev_state && code_state->frame == NULL) {\n        // We are entering not-yet-traced frame\n        // which means it's a CALL event (not a GENERATOR)\n        // so set the function definition line.\n        const mp_raw_code_t *rc = code_state->fun_bc->rc;\n        frame->lineno = rc->line_of_definition;\n        if (!rc->line_of_definition) {\n            frame->lineno = mp_prof_bytecode_lineno(rc, 0);\n        }\n    }\n    code_state->frame = frame;\n\n    if (!prof_trace_cb) {\n        return MP_OBJ_NULL;\n    }\n\n    mp_obj_t top;\n    prof_callback_args_t _args, *args = &_args;\n    args->frame = code_state->frame;\n\n    // SETTRACE event CALL\n    args->event = MP_OBJ_NEW_QSTR(MP_QSTR_call);\n    args->arg = mp_const_none;\n    top = mp_prof_callback_invoke(prof_trace_cb, args);\n\n    code_state->frame->callback = mp_obj_is_callable(top) ? top : MP_OBJ_NULL;\n\n    // Invalidate the last executed line number so the LINE trace can trigger after this CALL.\n    frame->lineno = 0;\n\n    return top;\n}\n\nmp_obj_t mp_prof_frame_update(const mp_code_state_t *code_state) {\n    mp_obj_frame_t *frame = code_state->frame;\n    if (frame == NULL) {\n        // Frame was not allocated (eg because there was no memory available)\n        return MP_OBJ_NULL;\n    }\n\n    mp_obj_frame_t *o = frame;\n    mp_obj_code_t *code = o->code;\n    const mp_raw_code_t *rc = code->rc;\n    const mp_bytecode_prelude_t *prelude = &rc->prelude;\n\n    assert(o->code_state == code_state);\n\n    o->lasti = code_state->ip - prelude->opcodes;\n    o->lineno = mp_prof_bytecode_lineno(rc, o->lasti);\n\n    return MP_OBJ_FROM_PTR(o);\n}\n\nmp_obj_t mp_prof_instr_tick(mp_code_state_t *code_state, bool is_exception) {\n    // Detect execution recursion\n    assert(!mp_prof_is_executing);\n    assert(code_state->frame);\n    assert(mp_obj_get_type(code_state->frame) == &mp_type_frame);\n\n    // Detect data recursion\n    assert(code_state != code_state->prev_state);\n\n    mp_obj_t top = mp_const_none;\n    mp_obj_t callback = code_state->frame->callback;\n\n    prof_callback_args_t _args, *args = &_args;\n    args->frame = code_state->frame;\n    args->event = mp_const_none;\n    args->arg = mp_const_none;\n\n    // Call event's are handled inside mp_prof_frame_enter\n\n    // SETTRACE event EXCEPTION\n    if (is_exception) {\n        args->event = MP_OBJ_NEW_QSTR(MP_QSTR_exception);\n        top = mp_prof_callback_invoke(callback, args);\n        return top;\n    }\n\n    // SETTRACE event LINE\n    const mp_raw_code_t *rc = code_state->fun_bc->rc;\n    const mp_bytecode_prelude_t *prelude = &rc->prelude;\n    size_t prev_line_no = args->frame->lineno;\n    size_t current_line_no = mp_prof_bytecode_lineno(rc, code_state->ip - prelude->opcodes);\n    if (prev_line_no != current_line_no) {\n        args->frame->lineno = current_line_no;\n        args->event = MP_OBJ_NEW_QSTR(MP_QSTR_line);\n        top = mp_prof_callback_invoke(callback, args);\n    }\n\n    // SETTRACE event RETURN\n    const byte *ip = code_state->ip;\n    if (*ip == MP_BC_RETURN_VALUE || *ip == MP_BC_YIELD_VALUE) {\n        args->event = MP_OBJ_NEW_QSTR(MP_QSTR_return);\n        top = mp_prof_callback_invoke(callback, args);\n        if (code_state->prev_state && *ip == MP_BC_RETURN_VALUE) {\n            code_state->frame->callback = MP_OBJ_NULL;\n        }\n    }\n\n    // SETTRACE event OPCODE\n    // TODO: frame.f_trace_opcodes=True\n    if (false) {\n        args->event = MP_OBJ_NEW_QSTR(MP_QSTR_opcode);\n    }\n\n    return top;\n}\n\n/******************************************************************************/\n// DEBUG\n\n// This section is for debugging the settrace feature itself, and is not intended\n// to be included in production/release builds.  The code structure for this block\n// was taken from py/showbc.c and should not be used as a reference.  To enable\n// this debug feature enable MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE in py/profile.h.\n#if MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE\n\n#include \"runtime0.h\"\n\n#define DECODE_UINT { \\\n        unum = 0; \\\n        do { \\\n            unum = (unum << 7) + (*ip & 0x7f); \\\n        } while ((*ip++ & 0x80) != 0); \\\n}\n#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0)\n#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0)\n\n#define DECODE_QSTR \\\n    qst = ip[0] | ip[1] << 8; \\\n    ip += 2;\n#define DECODE_PTR \\\n    DECODE_UINT; \\\n    ptr = (const byte *)const_table[unum]\n#define DECODE_OBJ \\\n    DECODE_UINT; \\\n    obj = (mp_obj_t)const_table[unum]\n\ntypedef struct _mp_dis_instruction_t {\n    mp_uint_t qstr_opname;\n    mp_uint_t arg;\n    mp_obj_t argobj;\n    mp_obj_t argobjex_cache;\n} mp_dis_instruction_t;\n\nSTATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_table, mp_dis_instruction_t *instruction) {\n    mp_uint_t unum;\n    const byte *ptr;\n    mp_obj_t obj;\n    qstr qst;\n\n    instruction->qstr_opname = MP_QSTR_;\n    instruction->arg = 0;\n    instruction->argobj = mp_const_none;\n    instruction->argobjex_cache = mp_const_none;\n\n    switch (*ip++) {\n        case MP_BC_LOAD_CONST_FALSE:\n            instruction->qstr_opname = MP_QSTR_LOAD_CONST_FALSE;\n            break;\n\n        case MP_BC_LOAD_CONST_NONE:\n            instruction->qstr_opname = MP_QSTR_LOAD_CONST_NONE;\n            break;\n\n        case MP_BC_LOAD_CONST_TRUE:\n            instruction->qstr_opname = MP_QSTR_LOAD_CONST_TRUE;\n            break;\n\n        case MP_BC_LOAD_CONST_SMALL_INT: {\n            mp_int_t num = 0;\n            if ((ip[0] & 0x40) != 0) {\n                // Number is negative\n                num--;\n            }\n            do {\n                num = (num << 7) | (*ip & 0x7f);\n            } while ((*ip++ & 0x80) != 0);\n            instruction->qstr_opname = MP_QSTR_LOAD_CONST_SMALL_INT;\n            instruction->arg = num;\n            break;\n        }\n\n        case MP_BC_LOAD_CONST_STRING:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_LOAD_CONST_STRING;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            break;\n\n        case MP_BC_LOAD_CONST_OBJ:\n            DECODE_OBJ;\n            instruction->qstr_opname = MP_QSTR_LOAD_CONST_OBJ;\n            instruction->arg = unum;\n            instruction->argobj = obj;\n            break;\n\n        case MP_BC_LOAD_NULL:\n            instruction->qstr_opname = MP_QSTR_LOAD_NULL;\n            break;\n\n        case MP_BC_LOAD_FAST_N:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_LOAD_FAST_N;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_LOAD_DEREF:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_LOAD_DEREF;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_LOAD_NAME:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_LOAD_NAME;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {\n                instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);\n            }\n            break;\n\n        case MP_BC_LOAD_GLOBAL:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_LOAD_GLOBAL;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {\n                instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);\n            }\n            break;\n\n        case MP_BC_LOAD_ATTR:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_LOAD_ATTR;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {\n                instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);\n            }\n            break;\n\n        case MP_BC_LOAD_METHOD:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_LOAD_METHOD;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            break;\n\n        case MP_BC_LOAD_SUPER_METHOD:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_LOAD_SUPER_METHOD;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            break;\n\n        case MP_BC_LOAD_BUILD_CLASS:\n            instruction->qstr_opname = MP_QSTR_LOAD_BUILD_CLASS;\n            break;\n\n        case MP_BC_LOAD_SUBSCR:\n            instruction->qstr_opname = MP_QSTR_LOAD_SUBSCR;\n            break;\n\n        case MP_BC_STORE_FAST_N:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_STORE_FAST_N;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_STORE_DEREF:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_STORE_DEREF;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_STORE_NAME:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_STORE_NAME;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            break;\n\n        case MP_BC_STORE_GLOBAL:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_STORE_GLOBAL;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            break;\n\n        case MP_BC_STORE_ATTR:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_STORE_ATTR;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {\n                instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);\n            }\n            break;\n\n        case MP_BC_STORE_SUBSCR:\n            instruction->qstr_opname = MP_QSTR_STORE_SUBSCR;\n            break;\n\n        case MP_BC_DELETE_FAST:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_DELETE_FAST;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_DELETE_DEREF:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_DELETE_DEREF;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_DELETE_NAME:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_DELETE_NAME;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            break;\n\n        case MP_BC_DELETE_GLOBAL:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_DELETE_GLOBAL;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            break;\n\n        case MP_BC_DUP_TOP:\n            instruction->qstr_opname = MP_QSTR_DUP_TOP;\n            break;\n\n        case MP_BC_DUP_TOP_TWO:\n            instruction->qstr_opname = MP_QSTR_DUP_TOP_TWO;\n            break;\n\n        case MP_BC_POP_TOP:\n            instruction->qstr_opname = MP_QSTR_POP_TOP;\n            break;\n\n        case MP_BC_ROT_TWO:\n            instruction->qstr_opname = MP_QSTR_ROT_TWO;\n            break;\n\n        case MP_BC_ROT_THREE:\n            instruction->qstr_opname = MP_QSTR_ROT_THREE;\n            break;\n\n        case MP_BC_JUMP:\n            DECODE_SLABEL;\n            instruction->qstr_opname = MP_QSTR_JUMP;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_POP_JUMP_IF_TRUE:\n            DECODE_SLABEL;\n            instruction->qstr_opname = MP_QSTR_POP_JUMP_IF_TRUE;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_POP_JUMP_IF_FALSE:\n            DECODE_SLABEL;\n            instruction->qstr_opname = MP_QSTR_POP_JUMP_IF_FALSE;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_JUMP_IF_TRUE_OR_POP:\n            DECODE_SLABEL;\n            instruction->qstr_opname = MP_QSTR_JUMP_IF_TRUE_OR_POP;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_JUMP_IF_FALSE_OR_POP:\n            DECODE_SLABEL;\n            instruction->qstr_opname = MP_QSTR_JUMP_IF_FALSE_OR_POP;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_SETUP_WITH:\n            DECODE_ULABEL; // loop-like labels are always forward\n            instruction->qstr_opname = MP_QSTR_SETUP_WITH;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_WITH_CLEANUP:\n            instruction->qstr_opname = MP_QSTR_WITH_CLEANUP;\n            break;\n\n        case MP_BC_UNWIND_JUMP:\n            DECODE_SLABEL;\n            instruction->qstr_opname = MP_QSTR_UNWIND_JUMP;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_SETUP_EXCEPT:\n            DECODE_ULABEL; // except labels are always forward\n            instruction->qstr_opname = MP_QSTR_SETUP_EXCEPT;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_SETUP_FINALLY:\n            DECODE_ULABEL; // except labels are always forward\n            instruction->qstr_opname = MP_QSTR_SETUP_FINALLY;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_END_FINALLY:\n            // if TOS is an exception, reraises the exception (3 values on TOS)\n            // if TOS is an integer, does something else\n            // if TOS is None, just pops it and continues\n            // else error\n            instruction->qstr_opname = MP_QSTR_END_FINALLY;\n            break;\n\n        case MP_BC_GET_ITER:\n            instruction->qstr_opname = MP_QSTR_GET_ITER;\n            break;\n\n        case MP_BC_GET_ITER_STACK:\n            instruction->qstr_opname = MP_QSTR_GET_ITER_STACK;\n            break;\n\n        case MP_BC_FOR_ITER:\n            DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward\n            instruction->qstr_opname = MP_QSTR_FOR_ITER;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_BUILD_TUPLE:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_BUILD_TUPLE;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_BUILD_LIST:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_BUILD_LIST;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_BUILD_MAP:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_BUILD_MAP;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_STORE_MAP:\n            instruction->qstr_opname = MP_QSTR_STORE_MAP;\n            break;\n\n        case MP_BC_BUILD_SET:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_BUILD_SET;\n            instruction->arg = unum;\n            break;\n\n        #if MICROPY_PY_BUILTINS_SLICE\n        case MP_BC_BUILD_SLICE:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_BUILD_SLICE;\n            instruction->arg = unum;\n            break;\n        #endif\n\n        case MP_BC_STORE_COMP:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_STORE_COMP;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_UNPACK_SEQUENCE:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_UNPACK_SEQUENCE;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_UNPACK_EX:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_UNPACK_EX;\n            instruction->arg = unum;\n            break;\n\n        case MP_BC_MAKE_FUNCTION:\n            DECODE_PTR;\n            instruction->qstr_opname = MP_QSTR_MAKE_FUNCTION;\n            instruction->arg = unum;\n            instruction->argobj = mp_obj_new_int_from_ull((uint64_t)ptr);\n            break;\n\n        case MP_BC_MAKE_FUNCTION_DEFARGS:\n            DECODE_PTR;\n            instruction->qstr_opname = MP_QSTR_MAKE_FUNCTION_DEFARGS;\n            instruction->arg = unum;\n            instruction->argobj = mp_obj_new_int_from_ull((uint64_t)ptr);\n            break;\n\n        case MP_BC_MAKE_CLOSURE: {\n            DECODE_PTR;\n            mp_uint_t n_closed_over = *ip++;\n            instruction->qstr_opname = MP_QSTR_MAKE_CLOSURE;\n            instruction->arg = unum;\n            instruction->argobj = mp_obj_new_int_from_ull((uint64_t)ptr);\n            instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(n_closed_over);\n            break;\n        }\n\n        case MP_BC_MAKE_CLOSURE_DEFARGS: {\n            DECODE_PTR;\n            mp_uint_t n_closed_over = *ip++;\n            instruction->qstr_opname = MP_QSTR_MAKE_CLOSURE_DEFARGS;\n            instruction->arg = unum;\n            instruction->argobj = mp_obj_new_int_from_ull((uint64_t)ptr);\n            instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(n_closed_over);\n            break;\n        }\n\n        case MP_BC_CALL_FUNCTION:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_CALL_FUNCTION;\n            instruction->arg = unum & 0xff;\n            instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff);\n            break;\n\n        case MP_BC_CALL_FUNCTION_VAR_KW:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_CALL_FUNCTION_VAR_KW;\n            instruction->arg = unum & 0xff;\n            instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff);\n            break;\n\n        case MP_BC_CALL_METHOD:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_CALL_METHOD;\n            instruction->arg = unum & 0xff;\n            instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff);\n            break;\n\n        case MP_BC_CALL_METHOD_VAR_KW:\n            DECODE_UINT;\n            instruction->qstr_opname = MP_QSTR_CALL_METHOD_VAR_KW;\n            instruction->arg = unum & 0xff;\n            instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff);\n            break;\n\n        case MP_BC_RETURN_VALUE:\n            instruction->qstr_opname = MP_QSTR_RETURN_VALUE;\n            break;\n\n        case MP_BC_RAISE_LAST:\n            instruction->qstr_opname = MP_QSTR_RAISE_LAST;\n            break;\n\n        case MP_BC_RAISE_OBJ:\n            instruction->qstr_opname = MP_QSTR_RAISE_OBJ;\n            break;\n\n        case MP_BC_RAISE_FROM:\n            instruction->qstr_opname = MP_QSTR_RAISE_FROM;\n            break;\n\n        case MP_BC_YIELD_VALUE:\n            instruction->qstr_opname = MP_QSTR_YIELD_VALUE;\n            break;\n\n        case MP_BC_YIELD_FROM:\n            instruction->qstr_opname = MP_QSTR_YIELD_FROM;\n            break;\n\n        case MP_BC_IMPORT_NAME:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_IMPORT_NAME;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            break;\n\n        case MP_BC_IMPORT_FROM:\n            DECODE_QSTR;\n            instruction->qstr_opname = MP_QSTR_IMPORT_FROM;\n            instruction->arg = qst;\n            instruction->argobj = MP_OBJ_NEW_QSTR(qst);\n            break;\n\n        case MP_BC_IMPORT_STAR:\n            instruction->qstr_opname = MP_QSTR_IMPORT_STAR;\n            break;\n\n        default:\n            if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) {\n                instruction->qstr_opname = MP_QSTR_LOAD_CONST_SMALL_INT;\n                instruction->arg = (mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16;\n            } else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) {\n                instruction->qstr_opname = MP_QSTR_LOAD_FAST;\n                instruction->arg = (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI;\n            } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {\n                instruction->qstr_opname = MP_QSTR_STORE_FAST;\n                instruction->arg = (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI;\n            } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) {\n                instruction->qstr_opname = MP_QSTR_UNARY_OP;\n                instruction->arg = (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI;\n            } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) {\n                mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI;\n                instruction->qstr_opname = MP_QSTR_BINARY_OP;\n                instruction->arg = op;\n            } else {\n                mp_printf(&mp_plat_print, \"code %p, opcode 0x%02x not implemented\\n\", ip - 1, ip[-1]);\n                assert(0);\n                return ip;\n            }\n            break;\n    }\n\n    return ip;\n}\n\nvoid mp_prof_print_instr(const byte *ip, mp_code_state_t *code_state) {\n    mp_dis_instruction_t _instruction, *instruction = &_instruction;\n    mp_prof_opcode_decode(ip, code_state->fun_bc->rc->const_table, instruction);\n    const mp_raw_code_t *rc = code_state->fun_bc->rc;\n    const mp_bytecode_prelude_t *prelude = &rc->prelude;\n\n    mp_uint_t offset = ip - prelude->opcodes;\n    mp_printf(&mp_plat_print, \"instr\");\n\n    /* long path */ if (1) {\n        mp_printf(&mp_plat_print,\n            \"@0x%p:%q:%q+0x%04x:%d\",\n            ip,\n            prelude->qstr_source_file,\n            prelude->qstr_block_name,\n            offset,\n            mp_prof_bytecode_lineno(rc, offset)\n            );\n    }\n\n    /* bytecode */ if (0) {\n        mp_printf(&mp_plat_print, \" %02x %02x %02x %02x\", ip[0], ip[1], ip[2], ip[3]);\n    }\n\n    mp_printf(&mp_plat_print, \" 0x%02x %q [%d]\", *ip, instruction->qstr_opname, instruction->arg);\n\n    if (instruction->argobj != mp_const_none) {\n        mp_printf(&mp_plat_print, \" $\");\n        mp_obj_print_helper(&mp_plat_print, instruction->argobj, PRINT_REPR);\n    }\n    if (instruction->argobjex_cache != mp_const_none) {\n        mp_printf(&mp_plat_print, \" #\");\n        mp_obj_print_helper(&mp_plat_print, instruction->argobjex_cache, PRINT_REPR);\n    }\n\n    mp_printf(&mp_plat_print, \"\\n\");\n}\n\n#endif // MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE\n\n#endif // MICROPY_PY_SYS_SETTRACE\n"
  },
  {
    "path": "py/profile.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) SatoshiLabs\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef MICROPY_INCLUDED_PY_PROFILING_H\n#define MICROPY_INCLUDED_PY_PROFILING_H\n\n#include \"py/emitglue.h\"\n\n#if MICROPY_PY_SYS_SETTRACE\n\n#define mp_prof_is_executing MP_STATE_THREAD(prof_callback_is_executing)\n\ntypedef struct _mp_obj_code_t {\n    mp_obj_base_t base;\n    const mp_raw_code_t *rc;\n    mp_obj_dict_t *dict_locals;\n    mp_obj_t lnotab;\n} mp_obj_code_t;\n\ntypedef struct _mp_obj_frame_t {\n    mp_obj_base_t base;\n    const mp_code_state_t *code_state;\n    struct _mp_obj_frame_t *back;\n    mp_obj_t callback;\n    mp_obj_code_t *code;\n    mp_uint_t lasti;\n    mp_uint_t lineno;\n    bool trace_opcodes;\n} mp_obj_frame_t;\n\nvoid mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude);\n\nmp_obj_t mp_obj_new_code(const mp_raw_code_t *rc);\nmp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state);\n\n// This is the implementation for the sys.settrace\nmp_obj_t mp_prof_settrace(mp_obj_t callback);\n\nmp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state);\nmp_obj_t mp_prof_frame_update(const mp_code_state_t *code_state);\n\n// For every VM instruction tick this function deduces events from the state\nmp_obj_t mp_prof_instr_tick(mp_code_state_t *code_state, bool is_exception);\n\n// This section is for debugging the settrace feature itself, and is not intended\n// to be included in production/release builds.\n#define MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE 0\n#if MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE\nvoid mp_prof_print_instr(const byte *ip, mp_code_state_t *code_state);\n#define MP_PROF_INSTR_DEBUG_PRINT(current_ip) mp_prof_print_instr((current_ip), code_state)\n#else\n#define MP_PROF_INSTR_DEBUG_PRINT(current_ip)\n#endif\n\n#endif // MICROPY_PY_SYS_SETTRACE\n#endif // MICROPY_INCLUDED_PY_PROFILING_H\n"
  },
  {
    "path": "py/py.mk",
    "content": "# where py object files go (they have a name prefix to prevent filename clashes)\nPY_BUILD = $(BUILD)/py\n\n# where autogenerated header files go\nHEADER_BUILD = $(BUILD)/genhdr\n\n# file containing qstr defs for the core Python bit\nPY_QSTR_DEFS = $(PY_SRC)/qstrdefs.h\n\n# If qstr autogeneration is not disabled we specify the output header\n# for all collected qstrings.\nifneq ($(QSTR_AUTOGEN_DISABLE),1)\nQSTR_DEFS_COLLECTED = $(HEADER_BUILD)/qstrdefs.collected.h\nendif\n\n# Any files listed by these variables will cause a full regeneration of qstrs\n# DEPENDENCIES: included in qstr processing; REQUIREMENTS: not included\nQSTR_GLOBAL_DEPENDENCIES += $(PY_SRC)/mpconfig.h mpconfigport.h\nQSTR_GLOBAL_REQUIREMENTS += $(HEADER_BUILD)/mpversion.h\n\n# some code is performance bottleneck and compiled with other optimization options\nCSUPEROPT = -O3\n\n# Enable building 32-bit code on 64-bit host.\nifeq ($(MICROPY_FORCE_32BIT),1)\nCC += -m32\nCXX += -m32\nLD += -m32\nendif\n\n# External modules written in C.\nifneq ($(USER_C_MODULES),)\n# pre-define USERMOD variables as expanded so that variables are immediate\n# expanded as they're added to them\nSRC_USERMOD :=\nSRC_USERMOD_CXX :=\nCFLAGS_USERMOD :=\nCXXFLAGS_USERMOD :=\nLDFLAGS_USERMOD :=\n$(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \\\n    $(eval USERMOD_DIR = $(patsubst %/,%,$(dir $(module))))\\\n    $(info Including User C Module from $(USERMOD_DIR))\\\n\t$(eval include $(module))\\\n)\n\nSRC_MOD += $(patsubst $(USER_C_MODULES)/%.c,%.c,$(SRC_USERMOD))\nSRC_MOD_CXX += $(patsubst $(USER_C_MODULES)/%.cpp,%.cpp,$(SRC_USERMOD_CXX))\nCFLAGS_MOD += $(CFLAGS_USERMOD)\nCXXFLAGS_MOD += $(CXXFLAGS_USERMOD)\nLDFLAGS_MOD += $(LDFLAGS_USERMOD)\nendif\n\n# py object files\nPY_CORE_O_BASENAME = $(addprefix py/,\\\n\tmpstate.o \\\n\tnlr.o \\\n\tnlrx86.o \\\n\tnlrx64.o \\\n\tnlrthumb.o \\\n\tnlrpowerpc.o \\\n\tnlrxtensa.o \\\n\tnlrsetjmp.o \\\n\tmalloc.o \\\n\tgc.o \\\n\tpystack.o \\\n\tqstr.o \\\n\tvstr.o \\\n\tmpprint.o \\\n\tunicode.o \\\n\tmpz.o \\\n\treader.o \\\n\tlexer.o \\\n\tparse.o \\\n\tscope.o \\\n\tcompile.o \\\n\temitcommon.o \\\n\temitbc.o \\\n\tasmbase.o \\\n\tasmx64.o \\\n\temitnx64.o \\\n\tasmx86.o \\\n\temitnx86.o \\\n\tasmthumb.o \\\n\temitnthumb.o \\\n\temitinlinethumb.o \\\n\tasmarm.o \\\n\temitnarm.o \\\n\tasmxtensa.o \\\n\temitnxtensa.o \\\n\temitinlinextensa.o \\\n\temitnxtensawin.o \\\n\tformatfloat.o \\\n\tparsenumbase.o \\\n\tparsenum.o \\\n\temitglue.o \\\n\tpersistentcode.o \\\n\truntime.o \\\n\truntime_utils.o \\\n\tscheduler.o \\\n\tnativeglue.o \\\n\tpairheap.o \\\n\tringbuf.o \\\n\tstackctrl.o \\\n\targcheck.o \\\n\twarning.o \\\n\tprofile.o \\\n\tmap.o \\\n\tobj.o \\\n\tobjarray.o \\\n\tobjattrtuple.o \\\n\tobjbool.o \\\n\tobjboundmeth.o \\\n\tobjcell.o \\\n\tobjclosure.o \\\n\tobjcomplex.o \\\n\tobjdeque.o \\\n\tobjdict.o \\\n\tobjenumerate.o \\\n\tobjexcept.o \\\n\tobjfilter.o \\\n\tobjfloat.o \\\n\tobjfun.o \\\n\tobjgenerator.o \\\n\tobjgetitemiter.o \\\n\tobjint.o \\\n\tobjint_longlong.o \\\n\tobjint_mpz.o \\\n\tobjlist.o \\\n\tobjmap.o \\\n\tobjmodule.o \\\n\tobjobject.o \\\n\tobjpolyiter.o \\\n\tobjproperty.o \\\n\tobjnone.o \\\n\tobjnamedtuple.o \\\n\tobjrange.o \\\n\tobjreversed.o \\\n\tobjset.o \\\n\tobjsingleton.o \\\n\tobjslice.o \\\n\tobjstr.o \\\n\tobjstrunicode.o \\\n\tobjstringio.o \\\n\tobjtuple.o \\\n\tobjtype.o \\\n\tobjzip.o \\\n\topmethods.o \\\n\tsequence.o \\\n\tstream.o \\\n\tbinary.o \\\n\tbuiltinimport.o \\\n\tbuiltinevex.o \\\n\tbuiltinhelp.o \\\n\tmodarray.o \\\n\tmodbuiltins.o \\\n\tmodcollections.o \\\n\tmodgc.o \\\n\tmodio.o \\\n\tmodmath.o \\\n\tmodcmath.o \\\n\tmodmicropython.o \\\n\tmodstruct.o \\\n\tmodsys.o \\\n\tmoduerrno.o \\\n\tmodthread.o \\\n\tvm.o \\\n\tbc.o \\\n\tshowbc.o \\\n\trepl.o \\\n\tsmallint.o \\\n\tfrozenmod.o \\\n\t)\n\nPY_EXTMOD_O_BASENAME = \\\n\textmod/moduasyncio.o \\\n\textmod/moductypes.o \\\n\textmod/modujson.o \\\n\textmod/modure.o \\\n\textmod/moduzlib.o \\\n\textmod/moduheapq.o \\\n\textmod/modutimeq.o \\\n\textmod/moduhashlib.o \\\n\textmod/moducryptolib.o \\\n\textmod/modubinascii.o \\\n\textmod/virtpin.o \\\n\textmod/machine_mem.o \\\n\textmod/machine_pinbase.o \\\n\textmod/machine_signal.o \\\n\textmod/machine_pulse.o \\\n\textmod/machine_i2c.o \\\n\textmod/machine_spi.o \\\n\textmod/modbluetooth.o \\\n\textmod/modussl_axtls.o \\\n\textmod/modussl_mbedtls.o \\\n\textmod/modurandom.o \\\n\textmod/moduselect.o \\\n\textmod/moduwebsocket.o \\\n\textmod/modwebrepl.o \\\n\textmod/modframebuf.o \\\n\textmod/vfs.o \\\n\textmod/vfs_blockdev.o \\\n\textmod/vfs_reader.o \\\n\textmod/vfs_posix.o \\\n\textmod/vfs_posix_file.o \\\n\textmod/vfs_fat.o \\\n\textmod/vfs_fat_diskio.o \\\n\textmod/vfs_fat_file.o \\\n\textmod/vfs_lfs.o \\\n\textmod/utime_mphal.o \\\n\textmod/uos_dupterm.o \\\n\tlib/embed/abort_.o \\\n\tlib/utils/printf.o \\\n\n# prepend the build destination prefix to the py object files\nPY_CORE_O = $(addprefix $(BUILD)/, $(PY_CORE_O_BASENAME))\nPY_EXTMOD_O = $(addprefix $(BUILD)/, $(PY_EXTMOD_O_BASENAME))\n\n# this is a convenience variable for ports that want core, extmod and frozen code\nPY_O = $(PY_CORE_O) $(PY_EXTMOD_O)\n\n# object file for frozen code specified via a manifest\nifneq ($(FROZEN_MANIFEST),)\nPY_O += $(BUILD)/$(BUILD)/frozen_content.o\nendif\n\n# object file for frozen files\nifneq ($(FROZEN_DIR),)\nPY_O += $(BUILD)/$(BUILD)/frozen.o\nendif\n\n# object file for frozen bytecode (frozen .mpy files)\nifneq ($(FROZEN_MPY_DIR),)\nPY_O += $(BUILD)/$(BUILD)/frozen_mpy.o\nendif\n\n# Sources that may contain qstrings\nSRC_QSTR_IGNORE = py/nlr%\nSRC_QSTR += $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) $(PY_EXTMOD_O_BASENAME:.o=.c)\n\n# Anything that depends on FORCE will be considered out-of-date\nFORCE:\n.PHONY: FORCE\n\n$(HEADER_BUILD)/mpversion.h: FORCE | $(HEADER_BUILD)\n\t$(Q)$(PYTHON) $(PY_SRC)/makeversionhdr.py $@\n\n# mpconfigport.mk is optional, but changes to it may drastically change\n# overall config, so they need to be caught\nMPCONFIGPORT_MK = $(wildcard mpconfigport.mk)\n\n# qstr data\n# Adding an order only dependency on $(HEADER_BUILD) causes $(HEADER_BUILD) to get\n# created before we run the script to generate the .h\n# Note: we need to protect the qstr names from the preprocessor, so we wrap\n# the lines in \"\" and then unwrap after the preprocessor is finished.\n# See more information about this process in docs/develop/qstr.rst.\n$(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) $(PY_SRC)/makeqstrdata.py mpconfigport.h $(MPCONFIGPORT_MK) $(PY_SRC)/mpconfig.h | $(HEADER_BUILD)\n\t$(ECHO) \"GEN $@\"\n\t$(Q)$(CAT) $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) | $(SED) 's/^Q(.*)/\"&\"/' | $(CPP) $(CFLAGS) - | $(SED) 's/^\\\"\\(Q(.*)\\)\\\"/\\1/' > $(HEADER_BUILD)/qstrdefs.preprocessed.h\n\t$(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@\n\n$(HEADER_BUILD)/compressed.data.h: $(HEADER_BUILD)/compressed.collected\n\t$(ECHO) \"GEN $@\"\n\t$(Q)$(PYTHON) $(PY_SRC)/makecompresseddata.py $< > $@\n\n# build a list of registered modules for py/objmodule.c.\n$(HEADER_BUILD)/moduledefs.h: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h\n\t@$(ECHO) \"GEN $@\"\n\t$(Q)$(PYTHON) $(PY_SRC)/makemoduledefs.py --vpath=\"., $(TOP), $(USER_C_MODULES)\" $(SRC_QSTR) > $@\n\nSRC_QSTR += $(HEADER_BUILD)/moduledefs.h\n\n# Standard C functions like memset need to be compiled with special flags so\n# the compiler does not optimise these functions in terms of themselves.\nCFLAGS_BUILTIN ?= -ffreestanding -fno-builtin -fno-lto\n$(BUILD)/lib/libc/string0.o: CFLAGS += $(CFLAGS_BUILTIN)\n\n# Force nlr code to always be compiled with space-saving optimisation so\n# that the function preludes are of a minimal and predictable form.\n$(PY_BUILD)/nlr%.o: CFLAGS += -Os\n\n# optimising gc for speed; 5ms down to 4ms on pybv2\n$(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT)\n\n# optimising vm for speed, adds only a small amount to code size but makes a huge difference to speed (20% faster)\n$(PY_BUILD)/vm.o: CFLAGS += $(CSUPEROPT)\n# Optimizing vm.o for modern deeply pipelined CPUs with branch predictors\n# may require disabling tail jump optimization. This will make sure that\n# each opcode has its own dispatching jump which will improve branch\n# branch predictor efficiency.\n# https://marc.info/?l=lua-l&m=129778596120851\n# http://hg.python.org/cpython/file/b127046831e2/Python/ceval.c#l828\n# http://www.emulators.com/docs/nx25_nostradamus.htm\n#-fno-crossjumping\n\n# Include rules for extmod related code\ninclude $(TOP)/extmod/extmod.mk\n"
  },
  {
    "path": "py/pystack.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n\n#include \"py/runtime.h\"\n\n#if MICROPY_ENABLE_PYSTACK\n\nvoid mp_pystack_init(void *start, void *end) {\n    MP_STATE_THREAD(pystack_start) = start;\n    MP_STATE_THREAD(pystack_end) = end;\n    MP_STATE_THREAD(pystack_cur) = start;\n}\n\nvoid *mp_pystack_alloc(size_t n_bytes) {\n    n_bytes = (n_bytes + (MICROPY_PYSTACK_ALIGN - 1)) & ~(MICROPY_PYSTACK_ALIGN - 1);\n    #if MP_PYSTACK_DEBUG\n    n_bytes += MICROPY_PYSTACK_ALIGN;\n    #endif\n    if (MP_STATE_THREAD(pystack_cur) + n_bytes > MP_STATE_THREAD(pystack_end)) {\n        // out of memory in the pystack\n        nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError,\n            MP_OBJ_NEW_QSTR(MP_QSTR_pystack_space_exhausted)));\n    }\n    void *ptr = MP_STATE_THREAD(pystack_cur);\n    MP_STATE_THREAD(pystack_cur) += n_bytes;\n    #if MP_PYSTACK_DEBUG\n    *(size_t *)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN) = n_bytes;\n    #endif\n    return ptr;\n}\n\n#endif\n"
  },
  {
    "path": "py/pystack.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_PYSTACK_H\n#define MICROPY_INCLUDED_PY_PYSTACK_H\n\n#include \"py/mpstate.h\"\n\n// Enable this debugging option to check that the amount of memory freed is\n// consistent with amounts that were previously allocated.\n#define MP_PYSTACK_DEBUG (0)\n\n#if MICROPY_ENABLE_PYSTACK\n\nvoid mp_pystack_init(void *start, void *end);\nvoid *mp_pystack_alloc(size_t n_bytes);\n\n// This function can free multiple continuous blocks at once: just pass the\n// pointer to the block that was allocated first and it and all subsequently\n// allocated blocks will be freed.\nstatic inline void mp_pystack_free(void *ptr) {\n    assert((uint8_t *)ptr >= MP_STATE_THREAD(pystack_start));\n    assert((uint8_t *)ptr <= MP_STATE_THREAD(pystack_cur));\n    #if MP_PYSTACK_DEBUG\n    size_t n_bytes_to_free = MP_STATE_THREAD(pystack_cur) - (uint8_t *)ptr;\n    size_t n_bytes = *(size_t *)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN);\n    while (n_bytes < n_bytes_to_free) {\n        n_bytes += *(size_t *)(MP_STATE_THREAD(pystack_cur) - n_bytes - MICROPY_PYSTACK_ALIGN);\n    }\n    if (n_bytes != n_bytes_to_free) {\n        mp_printf(&mp_plat_print, \"mp_pystack_free() failed: %u != %u\\n\", (uint)n_bytes_to_free,\n            (uint)*(size_t *)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN));\n        assert(0);\n    }\n    #endif\n    MP_STATE_THREAD(pystack_cur) = (uint8_t *)ptr;\n}\n\nstatic inline void mp_pystack_realloc(void *ptr, size_t n_bytes) {\n    mp_pystack_free(ptr);\n    mp_pystack_alloc(n_bytes);\n}\n\nstatic inline size_t mp_pystack_usage(void) {\n    return MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start);\n}\n\nstatic inline size_t mp_pystack_limit(void) {\n    return MP_STATE_THREAD(pystack_end) - MP_STATE_THREAD(pystack_start);\n}\n\n#endif\n\n#if !MICROPY_ENABLE_PYSTACK\n\n#define mp_local_alloc(n_bytes) alloca(n_bytes)\n\nstatic inline void mp_local_free(void *ptr) {\n    (void)ptr;\n}\n\nstatic inline void *mp_nonlocal_alloc(size_t n_bytes) {\n    return m_new(uint8_t, n_bytes);\n}\n\nstatic inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) {\n    return m_renew(uint8_t, ptr, old_n_bytes, new_n_bytes);\n}\n\nstatic inline void mp_nonlocal_free(void *ptr, size_t n_bytes) {\n    m_del(uint8_t, ptr, n_bytes);\n}\n\n#else\n\nstatic inline void *mp_local_alloc(size_t n_bytes) {\n    return mp_pystack_alloc(n_bytes);\n}\n\nstatic inline void mp_local_free(void *ptr) {\n    mp_pystack_free(ptr);\n}\n\nstatic inline void *mp_nonlocal_alloc(size_t n_bytes) {\n    return mp_pystack_alloc(n_bytes);\n}\n\nstatic inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) {\n    (void)old_n_bytes;\n    mp_pystack_realloc(ptr, new_n_bytes);\n    return ptr;\n}\n\nstatic inline void mp_nonlocal_free(void *ptr, size_t n_bytes) {\n    (void)n_bytes;\n    mp_pystack_free(ptr);\n}\n\n#endif\n\n#endif // MICROPY_INCLUDED_PY_PYSTACK_H\n"
  },
  {
    "path": "py/qstr.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <string.h>\n#include <stdio.h>\n\n#include \"py/mpstate.h\"\n#include \"py/qstr.h\"\n#include \"py/gc.h\"\n#include \"py/runtime.h\"\n\n// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)\n// ultimately we will replace this with a static hash table of some kind\n// also probably need to include the length in the string data, to allow null bytes in the string\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_printf DEBUG_printf\n#else // don't print debugging info\n#define DEBUG_printf(...) (void)0\n#endif\n\n// A qstr is an index into the qstr pool.\n// The data for a qstr contains (hash, length, data):\n//  - hash (configurable number of bytes)\n//  - length (configurable number of bytes)\n//  - data (\"length\" number of bytes)\n//  - \\0 terminated (so they can be printed using printf)\n\n#if MICROPY_QSTR_BYTES_IN_HASH == 1\n    #define Q_HASH_MASK (0xff)\n    #define Q_GET_HASH(q) ((mp_uint_t)(q)[0])\n    #define Q_SET_HASH(q, hash) do { (q)[0] = (hash); } while (0)\n#elif MICROPY_QSTR_BYTES_IN_HASH == 2\n    #define Q_HASH_MASK (0xffff)\n    #define Q_GET_HASH(q) ((mp_uint_t)(q)[0] | ((mp_uint_t)(q)[1] << 8))\n    #define Q_SET_HASH(q, hash) do { (q)[0] = (hash); (q)[1] = (hash) >> 8; } while (0)\n#else\n    #error unimplemented qstr hash decoding\n#endif\n#define Q_GET_ALLOC(q)  (MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + Q_GET_LENGTH(q) + 1)\n#define Q_GET_DATA(q)   ((q) + MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN)\n#if MICROPY_QSTR_BYTES_IN_LEN == 1\n    #define Q_GET_LENGTH(q) ((q)[MICROPY_QSTR_BYTES_IN_HASH])\n    #define Q_SET_LENGTH(q, len) do { (q)[MICROPY_QSTR_BYTES_IN_HASH] = (len); } while (0)\n#elif MICROPY_QSTR_BYTES_IN_LEN == 2\n    #define Q_GET_LENGTH(q) ((q)[MICROPY_QSTR_BYTES_IN_HASH] | ((q)[MICROPY_QSTR_BYTES_IN_HASH + 1] << 8))\n    #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)\n#else\n    #error unimplemented qstr length decoding\n#endif\n\n#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL\n#define QSTR_ENTER() mp_thread_mutex_lock(&MP_STATE_VM(qstr_mutex), 1)\n#define QSTR_EXIT() mp_thread_mutex_unlock(&MP_STATE_VM(qstr_mutex))\n#else\n#define QSTR_ENTER()\n#define QSTR_EXIT()\n#endif\n\n// Initial number of entries for qstr pool, set so that the first dynamically\n// allocated pool is twice this size.  The value here must be <= MP_QSTRnumber_of.\n#define MICROPY_ALLOC_QSTR_ENTRIES_INIT (10)\n\n// this must match the equivalent function in makeqstrdata.py\nmp_uint_t qstr_compute_hash(const byte *data, size_t len) {\n    // djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html\n    mp_uint_t hash = 5381;\n    for (const byte *top = data + len; data < top; data++) {\n        hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data\n    }\n    hash &= Q_HASH_MASK;\n    // Make sure that valid hash is never zero, zero means \"hash not computed\"\n    if (hash == 0) {\n        hash++;\n    }\n    return hash;\n}\n\nconst qstr_pool_t mp_qstr_const_pool = {\n    NULL,               // no previous pool\n    0,                  // no previous pool\n    MICROPY_ALLOC_QSTR_ENTRIES_INIT,\n    MP_QSTRnumber_of,   // corresponds to number of strings in array just below\n    {\n        #ifndef NO_QSTR\n#define QDEF(id, str) str,\n        #include \"genhdr/qstrdefs.generated.h\"\n#undef QDEF\n        #endif\n    },\n};\n\n#ifdef MICROPY_QSTR_EXTRA_POOL\nextern const qstr_pool_t MICROPY_QSTR_EXTRA_POOL;\n#define CONST_POOL MICROPY_QSTR_EXTRA_POOL\n#else\n#define CONST_POOL mp_qstr_const_pool\n#endif\n\nvoid qstr_init(void) {\n    MP_STATE_VM(last_pool) = (qstr_pool_t *)&CONST_POOL; // we won't modify the const_pool since it has no allocated room left\n    MP_STATE_VM(qstr_last_chunk) = NULL;\n\n    #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL\n    mp_thread_mutex_init(&MP_STATE_VM(qstr_mutex));\n    #endif\n}\n\nSTATIC const byte *find_qstr(qstr q) {\n    // search pool for this qstr\n    // total_prev_len==0 in the final pool, so the loop will always terminate\n    qstr_pool_t *pool = MP_STATE_VM(last_pool);\n    while (q < pool->total_prev_len) {\n        pool = pool->prev;\n    }\n    return pool->qstrs[q - pool->total_prev_len];\n}\n\n// qstr_mutex must be taken while in this function\nSTATIC qstr qstr_add(const byte *q_ptr) {\n    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));\n\n    // make sure we have room in the pool for a new qstr\n    if (MP_STATE_VM(last_pool)->len >= MP_STATE_VM(last_pool)->alloc) {\n        size_t new_alloc = MP_STATE_VM(last_pool)->alloc * 2;\n        #ifdef MICROPY_QSTR_EXTRA_POOL\n        // Put a lower bound on the allocation size in case the extra qstr pool has few entries\n        new_alloc = MAX(MICROPY_ALLOC_QSTR_ENTRIES_INIT, new_alloc);\n        #endif\n        qstr_pool_t *pool = m_new_obj_var_maybe(qstr_pool_t, const char *, new_alloc);\n        if (pool == NULL) {\n            QSTR_EXIT();\n            m_malloc_fail(new_alloc);\n        }\n        pool->prev = MP_STATE_VM(last_pool);\n        pool->total_prev_len = MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len;\n        pool->alloc = new_alloc;\n        pool->len = 0;\n        MP_STATE_VM(last_pool) = pool;\n        DEBUG_printf(\"QSTR: allocate new pool of size %d\\n\", MP_STATE_VM(last_pool)->alloc);\n    }\n\n    // add the new qstr\n    MP_STATE_VM(last_pool)->qstrs[MP_STATE_VM(last_pool)->len++] = q_ptr;\n\n    // return id for the newly-added qstr\n    return MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len - 1;\n}\n\nqstr qstr_find_strn(const char *str, size_t str_len) {\n    // work out hash of str\n    mp_uint_t str_hash = qstr_compute_hash((const byte *)str, str_len);\n\n    // search pools for the data\n    for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL; pool = pool->prev) {\n        for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {\n            if (Q_GET_HASH(*q) == str_hash && Q_GET_LENGTH(*q) == str_len && memcmp(Q_GET_DATA(*q), str, str_len) == 0) {\n                return pool->total_prev_len + (q - pool->qstrs);\n            }\n        }\n    }\n\n    // not found; return null qstr\n    return 0;\n}\n\nqstr qstr_from_str(const char *str) {\n    return qstr_from_strn(str, strlen(str));\n}\n\nqstr qstr_from_strn(const char *str, size_t len) {\n    QSTR_ENTER();\n    qstr q = qstr_find_strn(str, len);\n    if (q == 0) {\n        // qstr does not exist in interned pool so need to add it\n\n        // check that len is not too big\n        if (len >= (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))) {\n            QSTR_EXIT();\n            mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"name too long\"));\n        }\n\n        // compute number of bytes needed to intern this string\n        size_t n_bytes = MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1;\n\n        if (MP_STATE_VM(qstr_last_chunk) != NULL && MP_STATE_VM(qstr_last_used) + n_bytes > MP_STATE_VM(qstr_last_alloc)) {\n            // not enough room at end of previously interned string so try to grow\n            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);\n            if (new_p == NULL) {\n                // could not grow existing memory; shrink it to fit previous\n                (void)m_renew_maybe(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_used), false);\n                MP_STATE_VM(qstr_last_chunk) = NULL;\n            } else {\n                // could grow existing memory\n                MP_STATE_VM(qstr_last_alloc) += n_bytes;\n            }\n        }\n\n        if (MP_STATE_VM(qstr_last_chunk) == NULL) {\n            // no existing memory for the interned string so allocate a new chunk\n            size_t al = n_bytes;\n            if (al < MICROPY_ALLOC_QSTR_CHUNK_INIT) {\n                al = MICROPY_ALLOC_QSTR_CHUNK_INIT;\n            }\n            MP_STATE_VM(qstr_last_chunk) = m_new_maybe(byte, al);\n            if (MP_STATE_VM(qstr_last_chunk) == NULL) {\n                // failed to allocate a large chunk so try with exact size\n                MP_STATE_VM(qstr_last_chunk) = m_new_maybe(byte, n_bytes);\n                if (MP_STATE_VM(qstr_last_chunk) == NULL) {\n                    QSTR_EXIT();\n                    m_malloc_fail(n_bytes);\n                }\n                al = n_bytes;\n            }\n            MP_STATE_VM(qstr_last_alloc) = al;\n            MP_STATE_VM(qstr_last_used) = 0;\n        }\n\n        // allocate memory from the chunk for this new interned string's data\n        byte *q_ptr = MP_STATE_VM(qstr_last_chunk) + MP_STATE_VM(qstr_last_used);\n        MP_STATE_VM(qstr_last_used) += n_bytes;\n\n        // store the interned strings' data\n        mp_uint_t hash = qstr_compute_hash((const byte *)str, len);\n        Q_SET_HASH(q_ptr, hash);\n        Q_SET_LENGTH(q_ptr, len);\n        memcpy(q_ptr + MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN, str, len);\n        q_ptr[MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len] = '\\0';\n        q = qstr_add(q_ptr);\n    }\n    QSTR_EXIT();\n    return q;\n}\n\nmp_uint_t qstr_hash(qstr q) {\n    const byte *qd = find_qstr(q);\n    return Q_GET_HASH(qd);\n}\n\nsize_t qstr_len(qstr q) {\n    const byte *qd = find_qstr(q);\n    return Q_GET_LENGTH(qd);\n}\n\nconst char *qstr_str(qstr q) {\n    const byte *qd = find_qstr(q);\n    return (const char *)Q_GET_DATA(qd);\n}\n\nconst byte *qstr_data(qstr q, size_t *len) {\n    const byte *qd = find_qstr(q);\n    *len = Q_GET_LENGTH(qd);\n    return Q_GET_DATA(qd);\n}\n\nvoid qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, size_t *n_total_bytes) {\n    QSTR_ENTER();\n    *n_pool = 0;\n    *n_qstr = 0;\n    *n_str_data_bytes = 0;\n    *n_total_bytes = 0;\n    for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &CONST_POOL; pool = pool->prev) {\n        *n_pool += 1;\n        *n_qstr += pool->len;\n        for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {\n            *n_str_data_bytes += Q_GET_ALLOC(*q);\n        }\n        #if MICROPY_ENABLE_GC\n        *n_total_bytes += gc_nbytes(pool); // this counts actual bytes used in heap\n        #else\n        *n_total_bytes += sizeof(qstr_pool_t) + sizeof(qstr) * pool->alloc;\n        #endif\n    }\n    *n_total_bytes += *n_str_data_bytes;\n    QSTR_EXIT();\n}\n\n#if MICROPY_PY_MICROPYTHON_MEM_INFO\nvoid qstr_dump_data(void) {\n    QSTR_ENTER();\n    for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &CONST_POOL; pool = pool->prev) {\n        for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {\n            mp_printf(&mp_plat_print, \"Q(%s)\\n\", Q_GET_DATA(*q));\n        }\n    }\n    QSTR_EXIT();\n}\n#endif\n\n#if MICROPY_ROM_TEXT_COMPRESSION\n\n#ifdef NO_QSTR\n\n// If NO_QSTR is set, it means we're doing QSTR extraction.\n// So we won't yet have \"genhdr/compressed.data.h\"\n\n#else\n\n// Emit the compressed_string_data string.\n#define MP_COMPRESSED_DATA(x) STATIC const char *compressed_string_data = x;\n#define MP_MATCH_COMPRESSED(a, b)\n#include \"genhdr/compressed.data.h\"\n#undef MP_COMPRESSED_DATA\n#undef MP_MATCH_COMPRESSED\n\n#endif // NO_QSTR\n\n// This implements the \"common word\" compression scheme (see makecompresseddata.py) where the most\n// common 128 words in error messages are replaced by their index into the list of common words.\n\n// The compressed string data is delimited by setting high bit in the final char of each word.\n// e.g. aaaa<0x80|a>bbbbbb<0x80|b>....\n// This method finds the n'th string.\nSTATIC const byte *find_uncompressed_string(uint8_t n) {\n    const byte *c = (byte *)compressed_string_data;\n    while (n > 0) {\n        while ((*c & 0x80) == 0) {\n            ++c;\n        }\n        ++c;\n        --n;\n    }\n    return c;\n}\n\n// Given a compressed string in src, decompresses it into dst.\n// dst must be large enough (use MP_MAX_UNCOMPRESSED_TEXT_LEN+1).\nvoid mp_decompress_rom_string(byte *dst, const mp_rom_error_text_t src_chr) {\n    // Skip past the 0xff marker.\n    const byte *src = (byte *)src_chr + 1;\n    // Need to add spaces around compressed words, except for the first (i.e. transition from 1<->2).\n    // 0 = start, 1 = compressed, 2 = regular.\n    int state = 0;\n    while (*src) {\n        if ((byte) * src >= 128) {\n            if (state != 0) {\n                *dst++ = ' ';\n            }\n            state = 1;\n\n            // High bit set, replace with common word.\n            const byte *word = find_uncompressed_string(*src & 0x7f);\n            // The word is terminated by the final char having its high bit set.\n            while ((*word & 0x80) == 0) {\n                *dst++ = *word++;\n            }\n            *dst++ = (*word & 0x7f);\n        } else {\n            // Otherwise just copy one char.\n            if (state == 1) {\n                *dst++ = ' ';\n            }\n            state = 2;\n\n            *dst++ = *src;\n        }\n        ++src;\n    }\n    // Add null-terminator.\n    *dst = 0;\n}\n\n#endif // MICROPY_ROM_TEXT_COMPRESSION\n"
  },
  {
    "path": "py/qstr.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_QSTR_H\n#define MICROPY_INCLUDED_PY_QSTR_H\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n\n// See qstrdefs.h for a list of qstr's that are available as constants.\n// Reference them as MP_QSTR_xxxx.\n//\n// Note: it would be possible to define MP_QSTR_xxx as qstr_from_str_static(\"xxx\")\n// for qstrs that are referenced this way, but you don't want to have them in ROM.\n\n// first entry in enum will be MP_QSTRnull=0, which indicates invalid/no qstr\nenum {\n    #ifndef NO_QSTR\n#define QDEF(id, str) id,\n    #include \"genhdr/qstrdefs.generated.h\"\n#undef QDEF\n    #endif\n    MP_QSTRnumber_of, // no underscore so it can't clash with any of the above\n};\n\ntypedef size_t qstr;\n\ntypedef struct _qstr_pool_t {\n    struct _qstr_pool_t *prev;\n    size_t total_prev_len;\n    size_t alloc;\n    size_t len;\n    const byte *qstrs[];\n} qstr_pool_t;\n\n#define QSTR_FROM_STR_STATIC(s) (qstr_from_strn((s), strlen(s)))\n#define QSTR_TOTAL() (MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len)\n\nvoid qstr_init(void);\n\nmp_uint_t qstr_compute_hash(const byte *data, size_t len);\nqstr qstr_find_strn(const char *str, size_t str_len); // returns MP_QSTRnull if not found\n\nqstr qstr_from_str(const char *str);\nqstr qstr_from_strn(const char *str, size_t len);\n\nmp_uint_t qstr_hash(qstr q);\nconst char *qstr_str(qstr q);\nsize_t qstr_len(qstr q);\nconst byte *qstr_data(qstr q, size_t *len);\n\nvoid qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, size_t *n_total_bytes);\nvoid qstr_dump_data(void);\n\n#if MICROPY_ROM_TEXT_COMPRESSION\nvoid mp_decompress_rom_string(byte *dst, mp_rom_error_text_t src);\n#define MP_IS_COMPRESSED_ROM_STRING(s) (*(byte *)(s) == 0xff)\n#endif\n\n#endif // MICROPY_INCLUDED_PY_QSTR_H\n"
  },
  {
    "path": "py/qstrdefs.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n// *FORMAT-OFF*\n\n#include \"py/mpconfig.h\"\n\n// All the qstr definitions in this file are available as constants.\n// That is, they are in ROM and you can reference them simply as MP_QSTR_xxxx.\n\n// qstr configuration passed to makeqstrdata.py of the form QCFG(key, value)\nQCFG(BYTES_IN_LEN, MICROPY_QSTR_BYTES_IN_LEN)\nQCFG(BYTES_IN_HASH, MICROPY_QSTR_BYTES_IN_HASH)\n\nQ()\nQ(*)\nQ(_)\nQ(/)\n#if MICROPY_PY_BUILTINS_STR_OP_MODULO\nQ(%#o)\nQ(%#x)\n#else\nQ({:#o})\nQ({:#x})\n#endif\nQ({:#b})\nQ( )\nQ(\\n)\nQ(maximum recursion depth exceeded)\nQ(<module>)\nQ(<lambda>)\nQ(<listcomp>)\nQ(<dictcomp>)\nQ(<setcomp>)\nQ(<genexpr>)\nQ(<string>)\nQ(<stdin>)\nQ(utf-8)\n\n#if MICROPY_ENABLE_PYSTACK\nQ(pystack exhausted)\n#endif\n"
  },
  {
    "path": "py/reader.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <assert.h>\n#include <sys/errno.h>\n\n#include \"py/runtime.h\"\n#include \"py/mperrno.h\"\n#include \"py/mpthread.h\"\n#include \"py/reader.h\"\n\ntypedef struct _mp_reader_mem_t {\n    size_t free_len; // if >0 mem is freed on close by: m_free(beg, free_len)\n    const byte *beg;\n    const byte *cur;\n    const byte *end;\n} mp_reader_mem_t;\n\nSTATIC mp_uint_t mp_reader_mem_readbyte(void *data) {\n    mp_reader_mem_t *reader = (mp_reader_mem_t *)data;\n    if (reader->cur < reader->end) {\n        return *reader->cur++;\n    } else {\n        return MP_READER_EOF;\n    }\n}\n\nSTATIC void mp_reader_mem_close(void *data) {\n    mp_reader_mem_t *reader = (mp_reader_mem_t *)data;\n    if (reader->free_len > 0) {\n        m_del(char, (char *)reader->beg, reader->free_len);\n    }\n    m_del_obj(mp_reader_mem_t, reader);\n}\n\nvoid mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len) {\n    mp_reader_mem_t *rm = m_new_obj(mp_reader_mem_t);\n    rm->free_len = free_len;\n    rm->beg = buf;\n    rm->cur = buf;\n    rm->end = buf + len;\n    reader->data = rm;\n    reader->readbyte = mp_reader_mem_readbyte;\n    reader->close = mp_reader_mem_close;\n}\n\n#if MICROPY_READER_POSIX\n\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <unistd.h>\n\ntypedef struct _mp_reader_posix_t {\n    bool close_fd;\n    int fd;\n    size_t len;\n    size_t pos;\n    byte buf[20];\n} mp_reader_posix_t;\n\nSTATIC mp_uint_t mp_reader_posix_readbyte(void *data) {\n    mp_reader_posix_t *reader = (mp_reader_posix_t *)data;\n    if (reader->pos >= reader->len) {\n        if (reader->len == 0) {\n            return MP_READER_EOF;\n        } else {\n            MP_THREAD_GIL_EXIT();\n            int n = read(reader->fd, reader->buf, sizeof(reader->buf));\n            MP_THREAD_GIL_ENTER();\n            if (n <= 0) {\n                reader->len = 0;\n                return MP_READER_EOF;\n            }\n            reader->len = n;\n            reader->pos = 0;\n        }\n    }\n    return reader->buf[reader->pos++];\n}\n\nSTATIC void mp_reader_posix_close(void *data) {\n    mp_reader_posix_t *reader = (mp_reader_posix_t *)data;\n    if (reader->close_fd) {\n        MP_THREAD_GIL_EXIT();\n        close(reader->fd);\n        MP_THREAD_GIL_ENTER();\n    }\n    m_del_obj(mp_reader_posix_t, reader);\n}\n\nvoid mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) {\n    mp_reader_posix_t *rp = m_new_obj(mp_reader_posix_t);\n    rp->close_fd = close_fd;\n    rp->fd = fd;\n    MP_THREAD_GIL_EXIT();\n    int n = read(rp->fd, rp->buf, sizeof(rp->buf));\n    if (n == -1) {\n        if (close_fd) {\n            close(fd);\n        }\n        MP_THREAD_GIL_ENTER();\n        mp_raise_OSError(errno);\n    }\n    MP_THREAD_GIL_ENTER();\n    rp->len = n;\n    rp->pos = 0;\n    reader->data = rp;\n    reader->readbyte = mp_reader_posix_readbyte;\n    reader->close = mp_reader_posix_close;\n}\n\n#if !MICROPY_VFS_POSIX\n// If MICROPY_VFS_POSIX is defined then this function is provided by the VFS layer\nvoid mp_reader_new_file(mp_reader_t *reader, const char *filename) {\n    MP_THREAD_GIL_EXIT();\n    int fd = open(filename, O_RDONLY, 0644);\n    MP_THREAD_GIL_ENTER();\n    if (fd < 0) {\n        mp_raise_OSError(errno);\n    }\n    mp_reader_new_file_from_fd(reader, fd, true);\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "py/reader.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2016 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_READER_H\n#define MICROPY_INCLUDED_PY_READER_H\n\n#include \"py/obj.h\"\n\n// the readbyte function must return the next byte in the input stream\n// it must return MP_READER_EOF if end of stream\n// it can be called again after returning MP_READER_EOF, and in that case must return MP_READER_EOF\n#define MP_READER_EOF ((mp_uint_t)(-1))\n\ntypedef struct _mp_reader_t {\n    void *data;\n    mp_uint_t (*readbyte)(void *data);\n    void (*close)(void *data);\n} mp_reader_t;\n\nvoid mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len);\nvoid mp_reader_new_file(mp_reader_t *reader, const char *filename);\nvoid mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd);\n\n#endif // MICROPY_INCLUDED_PY_READER_H\n"
  },
  {
    "path": "py/repl.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2015 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include \"py/obj.h\"\n#include \"py/runtime.h\"\n#include \"py/builtin.h\"\n#include \"py/repl.h\"\n\n#if MICROPY_HELPER_REPL\n\nSTATIC bool str_startswith_word(const char *str, const char *head) {\n    size_t i;\n    for (i = 0; str[i] && head[i]; i++) {\n        if (str[i] != head[i]) {\n            return false;\n        }\n    }\n    return head[i] == '\\0' && (str[i] == '\\0' || !unichar_isident(str[i]));\n}\n\nbool mp_repl_continue_with_input(const char *input) {\n    // check for blank input\n    if (input[0] == '\\0') {\n        return false;\n    }\n\n    // check if input starts with a certain keyword\n    bool starts_with_compound_keyword =\n        input[0] == '@'\n        || str_startswith_word(input, \"if\")\n        || str_startswith_word(input, \"while\")\n        || str_startswith_word(input, \"for\")\n        || str_startswith_word(input, \"try\")\n        || str_startswith_word(input, \"with\")\n        || str_startswith_word(input, \"def\")\n        || str_startswith_word(input, \"class\")\n        #if MICROPY_PY_ASYNC_AWAIT\n        || str_startswith_word(input, \"async\")\n        #endif\n    ;\n\n    // check for unmatched open bracket, quote or escape quote\n    #define Q_NONE (0)\n    #define Q_1_SINGLE (1)\n    #define Q_1_DOUBLE (2)\n    #define Q_3_SINGLE (3)\n    #define Q_3_DOUBLE (4)\n    int n_paren = 0;\n    int n_brack = 0;\n    int n_brace = 0;\n    int in_quote = Q_NONE;\n    const char *i;\n    for (i = input; *i; i++) {\n        if (*i == '\\'') {\n            if ((in_quote == Q_NONE || in_quote == Q_3_SINGLE) && i[1] == '\\'' && i[2] == '\\'') {\n                i += 2;\n                in_quote = Q_3_SINGLE - in_quote;\n            } else if (in_quote == Q_NONE || in_quote == Q_1_SINGLE) {\n                in_quote = Q_1_SINGLE - in_quote;\n            }\n        } else if (*i == '\"') {\n            if ((in_quote == Q_NONE || in_quote == Q_3_DOUBLE) && i[1] == '\"' && i[2] == '\"') {\n                i += 2;\n                in_quote = Q_3_DOUBLE - in_quote;\n            } else if (in_quote == Q_NONE || in_quote == Q_1_DOUBLE) {\n                in_quote = Q_1_DOUBLE - in_quote;\n            }\n        } else if (*i == '\\\\' && (i[1] == '\\'' || i[1] == '\"' || i[1] == '\\\\')) {\n            if (in_quote != Q_NONE) {\n                i++;\n            }\n        } else if (in_quote == Q_NONE) {\n            switch (*i) {\n                case '(':\n                    n_paren += 1;\n                    break;\n                case ')':\n                    n_paren -= 1;\n                    break;\n                case '[':\n                    n_brack += 1;\n                    break;\n                case ']':\n                    n_brack -= 1;\n                    break;\n                case '{':\n                    n_brace += 1;\n                    break;\n                case '}':\n                    n_brace -= 1;\n                    break;\n                default:\n                    break;\n            }\n        }\n    }\n\n    // continue if unmatched 3-quotes\n    if (in_quote == Q_3_SINGLE || in_quote == Q_3_DOUBLE) {\n        return true;\n    }\n\n    // continue if unmatched brackets, but only if not in a 1-quote\n    if ((n_paren > 0 || n_brack > 0 || n_brace > 0) && in_quote == Q_NONE) {\n        return true;\n    }\n\n    // continue if last character was backslash (for line continuation)\n    if (i[-1] == '\\\\') {\n        return true;\n    }\n\n    // continue if compound keyword and last line was not empty\n    if (starts_with_compound_keyword && i[-1] != '\\n') {\n        return true;\n    }\n\n    // otherwise, don't continue\n    return false;\n}\n\nsize_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print, const char **compl_str) {\n    // scan backwards to find start of \"a.b.c\" chain\n    const char *org_str = str;\n    const char *top = str + len;\n    for (const char *s = top; --s >= str;) {\n        if (!(unichar_isalpha(*s) || unichar_isdigit(*s) || *s == '_' || *s == '.')) {\n            ++s;\n            str = s;\n            break;\n        }\n    }\n\n    size_t nqstr = QSTR_TOTAL();\n\n    // begin search in outer global dict which is accessed from __main__\n    mp_obj_t obj = MP_OBJ_FROM_PTR(&mp_module___main__);\n    mp_obj_t dest[2];\n\n    for (;;) {\n        // get next word in string to complete\n        const char *s_start = str;\n        while (str < top && *str != '.') {\n            ++str;\n        }\n        size_t s_len = str - s_start;\n\n        if (str < top) {\n            // a complete word, lookup in current object\n            qstr q = qstr_find_strn(s_start, s_len);\n            if (q == MP_QSTRnull) {\n                // lookup will fail\n                return 0;\n            }\n            mp_load_method_protected(obj, q, dest, true);\n            obj = dest[0]; // attribute, method, or MP_OBJ_NULL if nothing found\n\n            if (obj == MP_OBJ_NULL) {\n                // lookup failed\n                return 0;\n            }\n\n            // skip '.' to move to next word\n            ++str;\n\n        } else {\n            // end of string, do completion on this partial name\n\n            // look for matches\n            const char *match_str = NULL;\n            size_t match_len = 0;\n            qstr q_first = 0, q_last = 0;\n            for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) {\n                size_t d_len;\n                const char *d_str = (const char *)qstr_data(q, &d_len);\n                if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {\n                    mp_load_method_protected(obj, q, dest, true);\n                    if (dest[0] != MP_OBJ_NULL) {\n                        if (match_str == NULL) {\n                            match_str = d_str;\n                            match_len = d_len;\n                        } else {\n                            // search for longest common prefix of match_str and d_str\n                            // (assumes these strings are null-terminated)\n                            for (size_t j = s_len; j <= match_len && j <= d_len; ++j) {\n                                if (match_str[j] != d_str[j]) {\n                                    match_len = j;\n                                    break;\n                                }\n                            }\n                        }\n                        if (q_first == 0) {\n                            q_first = q;\n                        }\n                        q_last = q;\n                    }\n                }\n            }\n\n            // nothing found\n            if (q_first == 0) {\n                // If there're no better alternatives, and if it's first word\n                // in the line, try to complete \"import\".\n                if (s_start == org_str) {\n                    static const char import_str[] = \"import \";\n                    if (memcmp(s_start, import_str, s_len) == 0) {\n                        *compl_str = import_str + s_len;\n                        return sizeof(import_str) - 1 - s_len;\n                    }\n                }\n\n                return 0;\n            }\n\n            // 1 match found, or multiple matches with a common prefix\n            if (q_first == q_last || match_len > s_len) {\n                *compl_str = match_str + s_len;\n                return match_len - s_len;\n            }\n\n            // multiple matches found, print them out\n\n            #define WORD_SLOT_LEN (16)\n            #define MAX_LINE_LEN  (4 * WORD_SLOT_LEN)\n\n            int line_len = MAX_LINE_LEN; // force a newline for first word\n            for (qstr q = q_first; q <= q_last; ++q) {\n                size_t d_len;\n                const char *d_str = (const char *)qstr_data(q, &d_len);\n                if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {\n                    mp_load_method_protected(obj, q, dest, true);\n                    if (dest[0] != MP_OBJ_NULL) {\n                        int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len;\n                        if (gap < 2) {\n                            gap += WORD_SLOT_LEN;\n                        }\n                        if (line_len + gap + d_len <= MAX_LINE_LEN) {\n                            // TODO optimise printing of gap?\n                            for (int j = 0; j < gap; ++j) {\n                                mp_print_str(print, \" \");\n                            }\n                            mp_print_str(print, d_str);\n                            line_len += gap + d_len;\n                        } else {\n                            mp_printf(print, \"\\n%s\", d_str);\n                            line_len = d_len;\n                        }\n                    }\n                }\n            }\n            mp_print_str(print, \"\\n\");\n\n            return (size_t)(-1); // indicate many matches\n        }\n    }\n}\n\n#endif // MICROPY_HELPER_REPL\n"
  },
  {
    "path": "py/repl.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_REPL_H\n#define MICROPY_INCLUDED_PY_REPL_H\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n#include \"py/mpprint.h\"\n\n#if MICROPY_HELPER_REPL\nbool mp_repl_continue_with_input(const char *input);\nsize_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print, const char **compl_str);\n#endif\n\n#endif // MICROPY_INCLUDED_PY_REPL_H\n"
  },
  {
    "path": "py/ringbuf.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Jim Mussared\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include \"ringbuf.h\"\n\nint ringbuf_get16(ringbuf_t *r) {\n    int v = ringbuf_peek16(r);\n    if (v == -1) {\n        return v;\n    }\n    r->iget += 2;\n    if (r->iget >= r->size) {\n        r->iget -= r->size;\n    }\n    return v;\n}\n\nint ringbuf_peek16(ringbuf_t *r) {\n    if (r->iget == r->iput) {\n        return -1;\n    }\n    uint32_t iget_a = r->iget + 1;\n    if (iget_a == r->size) {\n        iget_a = 0;\n    }\n    if (iget_a == r->iput) {\n        return -1;\n    }\n    return (r->buf[r->iget] << 8) | (r->buf[iget_a]);\n}\n\nint ringbuf_put16(ringbuf_t *r, uint16_t v) {\n    uint32_t iput_a = r->iput + 1;\n    if (iput_a == r->size) {\n        iput_a = 0;\n    }\n    if (iput_a == r->iget) {\n        return -1;\n    }\n    uint32_t iput_b = iput_a + 1;\n    if (iput_b == r->size) {\n        iput_b = 0;\n    }\n    if (iput_b == r->iget) {\n        return -1;\n    }\n    r->buf[r->iput] = (v >> 8) & 0xff;\n    r->buf[iput_a] = v & 0xff;\n    r->iput = iput_b;\n    return 0;\n}\n"
  },
  {
    "path": "py/ringbuf.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_RINGBUF_H\n#define MICROPY_INCLUDED_PY_RINGBUF_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#ifdef _MSC_VER\n#include \"py/mpconfig.h\" // For inline.\n#endif\n\ntypedef struct _ringbuf_t {\n    uint8_t *buf;\n    uint16_t size;\n    uint16_t iget;\n    uint16_t iput;\n} ringbuf_t;\n\n// Static initialization:\n// byte buf_array[N];\n// ringbuf_t buf = {buf_array, sizeof(buf_array)};\n\n// Dynamic initialization. This needs to become findable as a root pointer!\n#define ringbuf_alloc(r, sz) \\\n    { \\\n        (r)->buf = m_new(uint8_t, sz); \\\n        (r)->size = sz; \\\n        (r)->iget = (r)->iput = 0; \\\n    }\n\nstatic inline int ringbuf_get(ringbuf_t *r) {\n    if (r->iget == r->iput) {\n        return -1;\n    }\n    uint8_t v = r->buf[r->iget++];\n    if (r->iget >= r->size) {\n        r->iget = 0;\n    }\n    return v;\n}\n\nstatic inline int ringbuf_peek(ringbuf_t *r) {\n    if (r->iget == r->iput) {\n        return -1;\n    }\n    return r->buf[r->iget];\n}\n\nstatic inline int ringbuf_put(ringbuf_t *r, uint8_t v) {\n    uint32_t iput_new = r->iput + 1;\n    if (iput_new >= r->size) {\n        iput_new = 0;\n    }\n    if (iput_new == r->iget) {\n        return -1;\n    }\n    r->buf[r->iput] = v;\n    r->iput = iput_new;\n    return 0;\n}\n\nstatic inline size_t ringbuf_free(ringbuf_t *r) {\n    return (r->size + r->iget - r->iput - 1) % r->size;\n}\n\nstatic inline size_t ringbuf_avail(ringbuf_t *r) {\n    return (r->size + r->iput - r->iget) % r->size;\n}\n\n// Note: big-endian. No-op if not enough room available for both bytes.\nint ringbuf_get16(ringbuf_t *r);\nint ringbuf_peek16(ringbuf_t *r);\nint ringbuf_put16(ringbuf_t *r, uint16_t v);\n\n#endif // MICROPY_INCLUDED_PY_RINGBUF_H\n"
  },
  {
    "path": "py/runtime.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014-2018 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdarg.h>\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/parsenum.h\"\n#include \"py/compile.h\"\n#include \"py/objstr.h\"\n#include \"py/objtuple.h\"\n#include \"py/objlist.h\"\n#include \"py/objtype.h\"\n#include \"py/objmodule.h\"\n#include \"py/objgenerator.h\"\n#include \"py/smallint.h\"\n#include \"py/runtime.h\"\n#include \"py/builtin.h\"\n#include \"py/stackctrl.h\"\n#include \"py/gc.h\"\n\n#if MICROPY_DEBUG_VERBOSE // print debugging info\n#define DEBUG_PRINT (1)\n#define DEBUG_printf DEBUG_printf\n#define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__)\n#else // don't print debugging info\n#define DEBUG_printf(...) (void)0\n#define DEBUG_OP_printf(...) (void)0\n#endif\n\nconst mp_obj_module_t mp_module___main__ = {\n    .base = { &mp_type_module },\n    .globals = (mp_obj_dict_t *)&MP_STATE_VM(dict_main),\n};\n\nvoid mp_init(void) {\n    qstr_init();\n\n    // no pending exceptions to start with\n    MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;\n    #if MICROPY_ENABLE_SCHEDULER\n    MP_STATE_VM(sched_state) = MP_SCHED_IDLE;\n    MP_STATE_VM(sched_idx) = 0;\n    MP_STATE_VM(sched_len) = 0;\n    #endif\n\n    #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF\n    mp_init_emergency_exception_buf();\n    #endif\n\n    #if MICROPY_KBD_EXCEPTION\n    // initialise the exception object for raising KeyboardInterrupt\n    MP_STATE_VM(mp_kbd_exception).base.type = &mp_type_KeyboardInterrupt;\n    MP_STATE_VM(mp_kbd_exception).traceback_alloc = 0;\n    MP_STATE_VM(mp_kbd_exception).traceback_len = 0;\n    MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;\n    MP_STATE_VM(mp_kbd_exception).args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;\n    #endif\n\n    #if MICROPY_ENABLE_COMPILER\n    // optimization disabled by default\n    MP_STATE_VM(mp_optimise_value) = 0;\n    #if MICROPY_EMIT_NATIVE\n    MP_STATE_VM(default_emit_opt) = MP_EMIT_OPT_NONE;\n    #endif\n    #endif\n\n    // init global module dict\n    mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), 3);\n\n    // initialise the __main__ module\n    mp_obj_dict_init(&MP_STATE_VM(dict_main), 1);\n    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__));\n\n    // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New())\n    mp_locals_set(&MP_STATE_VM(dict_main));\n    mp_globals_set(&MP_STATE_VM(dict_main));\n\n    #if MICROPY_CAN_OVERRIDE_BUILTINS\n    // start with no extensions to builtins\n    MP_STATE_VM(mp_module_builtins_override_dict) = NULL;\n    #endif\n\n    #if MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE\n    MP_STATE_VM(track_reloc_code_list) = MP_OBJ_NULL;\n    #endif\n\n    #if MICROPY_PY_OS_DUPTERM\n    for (size_t i = 0; i < MICROPY_PY_OS_DUPTERM; ++i) {\n        MP_STATE_VM(dupterm_objs[i]) = MP_OBJ_NULL;\n    }\n    #endif\n\n    #if MICROPY_VFS\n    // initialise the VFS sub-system\n    MP_STATE_VM(vfs_cur) = NULL;\n    MP_STATE_VM(vfs_mount_table) = NULL;\n    #endif\n\n    #if MICROPY_PY_SYS_ATEXIT\n    MP_STATE_VM(sys_exitfunc) = mp_const_none;\n    #endif\n\n    #if MICROPY_PY_SYS_SETTRACE\n    MP_STATE_THREAD(prof_trace_callback) = MP_OBJ_NULL;\n    MP_STATE_THREAD(prof_callback_is_executing) = false;\n    MP_STATE_THREAD(current_code_state) = NULL;\n    #endif\n\n    #if MICROPY_PY_BLUETOOTH\n    MP_STATE_VM(bluetooth) = MP_OBJ_NULL;\n    #endif\n\n    #if MICROPY_PY_THREAD_GIL\n    mp_thread_mutex_init(&MP_STATE_VM(gil_mutex));\n    #endif\n\n    // call port specific initialization if any\n    #ifdef MICROPY_PORT_INIT_FUNC\n    MICROPY_PORT_INIT_FUNC;\n    #endif\n\n    MP_THREAD_GIL_ENTER();\n}\n\nvoid mp_deinit(void) {\n    MP_THREAD_GIL_EXIT();\n\n    // call port specific deinitialization if any\n    #ifdef MICROPY_PORT_DEINIT_FUNC\n    MICROPY_PORT_DEINIT_FUNC;\n    #endif\n\n    // mp_obj_dict_free(&dict_main);\n    // mp_map_deinit(&MP_STATE_VM(mp_loaded_modules_map));\n}\n\nmp_obj_t mp_load_name(qstr qst) {\n    // logic: search locals, globals, builtins\n    DEBUG_OP_printf(\"load name %s\\n\", qstr_str(qst));\n    // If we're at the outer scope (locals == globals), dispatch to load_global right away\n    if (mp_locals_get() != mp_globals_get()) {\n        mp_map_elem_t *elem = mp_map_lookup(&mp_locals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);\n        if (elem != NULL) {\n            return elem->value;\n        }\n    }\n    return mp_load_global(qst);\n}\n\nmp_obj_t mp_load_global(qstr qst) {\n    // logic: search globals, builtins\n    DEBUG_OP_printf(\"load global %s\\n\", qstr_str(qst));\n    mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);\n    if (elem == NULL) {\n        #if MICROPY_CAN_OVERRIDE_BUILTINS\n        if (MP_STATE_VM(mp_module_builtins_override_dict) != NULL) {\n            // lookup in additional dynamic table of builtins first\n            elem = mp_map_lookup(&MP_STATE_VM(mp_module_builtins_override_dict)->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);\n            if (elem != NULL) {\n                return elem->value;\n            }\n        }\n        #endif\n        elem = mp_map_lookup((mp_map_t *)&mp_module_builtins_globals.map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);\n        if (elem == NULL) {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_raise_msg(&mp_type_NameError, MP_ERROR_TEXT(\"name not defined\"));\n            #else\n            mp_raise_msg_varg(&mp_type_NameError, MP_ERROR_TEXT(\"name '%q' isn't defined\"), qst);\n            #endif\n        }\n    }\n    return elem->value;\n}\n\nmp_obj_t mp_load_build_class(void) {\n    DEBUG_OP_printf(\"load_build_class\\n\");\n    #if MICROPY_CAN_OVERRIDE_BUILTINS\n    if (MP_STATE_VM(mp_module_builtins_override_dict) != NULL) {\n        // lookup in additional dynamic table of builtins first\n        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);\n        if (elem != NULL) {\n            return elem->value;\n        }\n    }\n    #endif\n    return MP_OBJ_FROM_PTR(&mp_builtin___build_class___obj);\n}\n\nvoid mp_store_name(qstr qst, mp_obj_t obj) {\n    DEBUG_OP_printf(\"store name %s <- %p\\n\", qstr_str(qst), obj);\n    mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst), obj);\n}\n\nvoid mp_delete_name(qstr qst) {\n    DEBUG_OP_printf(\"delete name %s\\n\", qstr_str(qst));\n    // TODO convert KeyError to NameError if qst not found\n    mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst));\n}\n\nvoid mp_store_global(qstr qst, mp_obj_t obj) {\n    DEBUG_OP_printf(\"store global %s <- %p\\n\", qstr_str(qst), obj);\n    mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst), obj);\n}\n\nvoid mp_delete_global(qstr qst) {\n    DEBUG_OP_printf(\"delete global %s\\n\", qstr_str(qst));\n    // TODO convert KeyError to NameError if qst not found\n    mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst));\n}\n\nmp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {\n    DEBUG_OP_printf(\"unary \" UINT_FMT \" %q %p\\n\", op, mp_unary_op_method_name[op], arg);\n\n    if (op == MP_UNARY_OP_NOT) {\n        // \"not x\" is the negative of whether \"x\" is true per Python semantics\n        return mp_obj_new_bool(mp_obj_is_true(arg) == 0);\n    } else if (mp_obj_is_small_int(arg)) {\n        mp_int_t val = MP_OBJ_SMALL_INT_VALUE(arg);\n        switch (op) {\n            case MP_UNARY_OP_BOOL:\n                return mp_obj_new_bool(val != 0);\n            case MP_UNARY_OP_HASH:\n                return arg;\n            case MP_UNARY_OP_POSITIVE:\n            case MP_UNARY_OP_INT:\n                return arg;\n            case MP_UNARY_OP_NEGATIVE:\n                // check for overflow\n                if (val == MP_SMALL_INT_MIN) {\n                    return mp_obj_new_int(-val);\n                } else {\n                    return MP_OBJ_NEW_SMALL_INT(-val);\n                }\n            case MP_UNARY_OP_ABS:\n                if (val >= 0) {\n                    return arg;\n                } else if (val == MP_SMALL_INT_MIN) {\n                    // check for overflow\n                    return mp_obj_new_int(-val);\n                } else {\n                    return MP_OBJ_NEW_SMALL_INT(-val);\n                }\n            default:\n                assert(op == MP_UNARY_OP_INVERT);\n                return MP_OBJ_NEW_SMALL_INT(~val);\n        }\n    } else if (op == MP_UNARY_OP_HASH && mp_obj_is_str_or_bytes(arg)) {\n        // fast path for hashing str/bytes\n        GET_STR_HASH(arg, h);\n        if (h == 0) {\n            GET_STR_DATA_LEN(arg, data, len);\n            h = qstr_compute_hash(data, len);\n        }\n        return MP_OBJ_NEW_SMALL_INT(h);\n    } else {\n        const mp_obj_type_t *type = mp_obj_get_type(arg);\n        if (type->unary_op != NULL) {\n            mp_obj_t result = type->unary_op(op, arg);\n            if (result != MP_OBJ_NULL) {\n                return result;\n            }\n        }\n        // With MP_UNARY_OP_INT, mp_unary_op() becomes a fallback for mp_obj_get_int().\n        // In this case provide a more focused error message to not confuse, e.g. chr(1.0)\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        if (op == MP_UNARY_OP_INT) {\n            mp_raise_TypeError(MP_ERROR_TEXT(\"can't convert to int\"));\n        } else {\n            mp_raise_TypeError(MP_ERROR_TEXT(\"unsupported type for operator\"));\n        }\n        #else\n        if (op == MP_UNARY_OP_INT) {\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"can't convert %s to int\"), mp_obj_get_type_str(arg));\n        } else {\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"unsupported type for %q: '%s'\"),\n                mp_unary_op_method_name[op], mp_obj_get_type_str(arg));\n        }\n        #endif\n    }\n}\n\nmp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {\n    DEBUG_OP_printf(\"binary \" UINT_FMT \" %q %p %p\\n\", op, mp_binary_op_method_name[op], lhs, rhs);\n\n    // TODO correctly distinguish inplace operators for mutable objects\n    // lookup logic that CPython uses for +=:\n    //   check for implemented +=\n    //   then check for implemented +\n    //   then check for implemented seq.inplace_concat\n    //   then check for implemented seq.concat\n    //   then fail\n    // note that list does not implement + or +=, so that inplace_concat is reached first for +=\n\n    // deal with is\n    if (op == MP_BINARY_OP_IS) {\n        return mp_obj_new_bool(lhs == rhs);\n    }\n\n    // deal with == and != for all types\n    if (op == MP_BINARY_OP_EQUAL || op == MP_BINARY_OP_NOT_EQUAL) {\n        // mp_obj_equal_not_equal supports a bunch of shortcuts\n        return mp_obj_equal_not_equal(op, lhs, rhs);\n    }\n\n    // deal with exception_match for all types\n    if (op == MP_BINARY_OP_EXCEPTION_MATCH) {\n        // rhs must be issubclass(rhs, BaseException)\n        if (mp_obj_is_exception_type(rhs)) {\n            if (mp_obj_exception_match(lhs, rhs)) {\n                return mp_const_true;\n            } else {\n                return mp_const_false;\n            }\n        } else if (mp_obj_is_type(rhs, &mp_type_tuple)) {\n            mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(rhs);\n            for (size_t i = 0; i < tuple->len; i++) {\n                rhs = tuple->items[i];\n                if (!mp_obj_is_exception_type(rhs)) {\n                    goto unsupported_op;\n                }\n                if (mp_obj_exception_match(lhs, rhs)) {\n                    return mp_const_true;\n                }\n            }\n            return mp_const_false;\n        }\n        goto unsupported_op;\n    }\n\n    if (mp_obj_is_small_int(lhs)) {\n        mp_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs);\n        if (mp_obj_is_small_int(rhs)) {\n            mp_int_t rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs);\n            // This is a binary operation: lhs_val op rhs_val\n            // We need to be careful to handle overflow; see CERT INT32-C\n            // Operations that can overflow:\n            //      +       result always fits in mp_int_t, then handled by SMALL_INT check\n            //      -       result always fits in mp_int_t, then handled by SMALL_INT check\n            //      *       checked explicitly\n            //      /       if lhs=MIN and rhs=-1; result always fits in mp_int_t, then handled by SMALL_INT check\n            //      %       if lhs=MIN and rhs=-1; result always fits in mp_int_t, then handled by SMALL_INT check\n            //      <<      checked explicitly\n            switch (op) {\n                case MP_BINARY_OP_OR:\n                case MP_BINARY_OP_INPLACE_OR:\n                    lhs_val |= rhs_val;\n                    break;\n                case MP_BINARY_OP_XOR:\n                case MP_BINARY_OP_INPLACE_XOR:\n                    lhs_val ^= rhs_val;\n                    break;\n                case MP_BINARY_OP_AND:\n                case MP_BINARY_OP_INPLACE_AND:\n                    lhs_val &= rhs_val;\n                    break;\n                case MP_BINARY_OP_LSHIFT:\n                case MP_BINARY_OP_INPLACE_LSHIFT: {\n                    if (rhs_val < 0) {\n                        // negative shift not allowed\n                        mp_raise_ValueError(MP_ERROR_TEXT(\"negative shift count\"));\n                    } 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)) {\n                        // left-shift will overflow, so use higher precision integer\n                        lhs = mp_obj_new_int_from_ll(lhs_val);\n                        goto generic_binary_op;\n                    } else {\n                        // use standard precision\n                        lhs_val <<= rhs_val;\n                    }\n                    break;\n                }\n                case MP_BINARY_OP_RSHIFT:\n                case MP_BINARY_OP_INPLACE_RSHIFT:\n                    if (rhs_val < 0) {\n                        // negative shift not allowed\n                        mp_raise_ValueError(MP_ERROR_TEXT(\"negative shift count\"));\n                    } else {\n                        // standard precision is enough for right-shift\n                        if (rhs_val >= (mp_int_t)BITS_PER_WORD) {\n                            // Shifting to big amounts is underfined behavior\n                            // in C and is CPU-dependent; propagate sign bit.\n                            rhs_val = BITS_PER_WORD - 1;\n                        }\n                        lhs_val >>= rhs_val;\n                    }\n                    break;\n                case MP_BINARY_OP_ADD:\n                case MP_BINARY_OP_INPLACE_ADD:\n                    lhs_val += rhs_val;\n                    break;\n                case MP_BINARY_OP_SUBTRACT:\n                case MP_BINARY_OP_INPLACE_SUBTRACT:\n                    lhs_val -= rhs_val;\n                    break;\n                case MP_BINARY_OP_MULTIPLY:\n                case MP_BINARY_OP_INPLACE_MULTIPLY: {\n\n                    // If long long type exists and is larger than mp_int_t, then\n                    // we can use the following code to perform overflow-checked multiplication.\n                    // Otherwise (eg in x64 case) we must use mp_small_int_mul_overflow.\n                    #if 0\n                    // compute result using long long precision\n                    long long res = (long long)lhs_val * (long long)rhs_val;\n                    if (res > MP_SMALL_INT_MAX || res < MP_SMALL_INT_MIN) {\n                        // result overflowed SMALL_INT, so return higher precision integer\n                        return mp_obj_new_int_from_ll(res);\n                    } else {\n                        // use standard precision\n                        lhs_val = (mp_int_t)res;\n                    }\n                    #endif\n\n                    if (mp_small_int_mul_overflow(lhs_val, rhs_val)) {\n                        // use higher precision\n                        lhs = mp_obj_new_int_from_ll(lhs_val);\n                        goto generic_binary_op;\n                    } else {\n                        // use standard precision\n                        return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val);\n                    }\n                }\n                case MP_BINARY_OP_FLOOR_DIVIDE:\n                case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:\n                    if (rhs_val == 0) {\n                        goto zero_division;\n                    }\n                    lhs_val = mp_small_int_floor_divide(lhs_val, rhs_val);\n                    break;\n\n                #if MICROPY_PY_BUILTINS_FLOAT\n                case MP_BINARY_OP_TRUE_DIVIDE:\n                case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:\n                    if (rhs_val == 0) {\n                        goto zero_division;\n                    }\n                    return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val);\n                #endif\n\n                case MP_BINARY_OP_MODULO:\n                case MP_BINARY_OP_INPLACE_MODULO: {\n                    if (rhs_val == 0) {\n                        goto zero_division;\n                    }\n                    lhs_val = mp_small_int_modulo(lhs_val, rhs_val);\n                    break;\n                }\n\n                case MP_BINARY_OP_POWER:\n                case MP_BINARY_OP_INPLACE_POWER:\n                    if (rhs_val < 0) {\n                        #if MICROPY_PY_BUILTINS_FLOAT\n                        return mp_obj_float_binary_op(op, (mp_float_t)lhs_val, rhs);\n                        #else\n                        mp_raise_ValueError(MP_ERROR_TEXT(\"negative power with no float support\"));\n                        #endif\n                    } else {\n                        mp_int_t ans = 1;\n                        while (rhs_val > 0) {\n                            if (rhs_val & 1) {\n                                if (mp_small_int_mul_overflow(ans, lhs_val)) {\n                                    goto power_overflow;\n                                }\n                                ans *= lhs_val;\n                            }\n                            if (rhs_val == 1) {\n                                break;\n                            }\n                            rhs_val /= 2;\n                            if (mp_small_int_mul_overflow(lhs_val, lhs_val)) {\n                                goto power_overflow;\n                            }\n                            lhs_val *= lhs_val;\n                        }\n                        lhs_val = ans;\n                    }\n                    break;\n\n                power_overflow:\n                    // use higher precision\n                    lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs));\n                    goto generic_binary_op;\n\n                case MP_BINARY_OP_DIVMOD: {\n                    if (rhs_val == 0) {\n                        goto zero_division;\n                    }\n                    // to reduce stack usage we don't pass a temp array of the 2 items\n                    mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));\n                    tuple->items[0] = MP_OBJ_NEW_SMALL_INT(mp_small_int_floor_divide(lhs_val, rhs_val));\n                    tuple->items[1] = MP_OBJ_NEW_SMALL_INT(mp_small_int_modulo(lhs_val, rhs_val));\n                    return MP_OBJ_FROM_PTR(tuple);\n                }\n\n                case MP_BINARY_OP_LESS:\n                    return mp_obj_new_bool(lhs_val < rhs_val);\n                case MP_BINARY_OP_MORE:\n                    return mp_obj_new_bool(lhs_val > rhs_val);\n                case MP_BINARY_OP_LESS_EQUAL:\n                    return mp_obj_new_bool(lhs_val <= rhs_val);\n                case MP_BINARY_OP_MORE_EQUAL:\n                    return mp_obj_new_bool(lhs_val >= rhs_val);\n\n                default:\n                    goto unsupported_op;\n            }\n            // This is an inlined version of mp_obj_new_int, for speed\n            if (MP_SMALL_INT_FITS(lhs_val)) {\n                return MP_OBJ_NEW_SMALL_INT(lhs_val);\n            } else {\n                return mp_obj_new_int_from_ll(lhs_val);\n            }\n        #if MICROPY_PY_BUILTINS_FLOAT\n        } else if (mp_obj_is_float(rhs)) {\n            mp_obj_t res = mp_obj_float_binary_op(op, (mp_float_t)lhs_val, rhs);\n            if (res == MP_OBJ_NULL) {\n                goto unsupported_op;\n            } else {\n                return res;\n            }\n        #endif\n        #if MICROPY_PY_BUILTINS_COMPLEX\n        } else if (mp_obj_is_type(rhs, &mp_type_complex)) {\n            mp_obj_t res = mp_obj_complex_binary_op(op, (mp_float_t)lhs_val, 0, rhs);\n            if (res == MP_OBJ_NULL) {\n                goto unsupported_op;\n            } else {\n                return res;\n            }\n        #endif\n        }\n    }\n\n    // Convert MP_BINARY_OP_IN to MP_BINARY_OP_CONTAINS with swapped args.\n    if (op == MP_BINARY_OP_IN) {\n        op = MP_BINARY_OP_CONTAINS;\n        mp_obj_t temp = lhs;\n        lhs = rhs;\n        rhs = temp;\n    }\n\n    // generic binary_op supplied by type\n    const mp_obj_type_t *type;\ngeneric_binary_op:\n    type = mp_obj_get_type(lhs);\n    if (type->binary_op != NULL) {\n        mp_obj_t result = type->binary_op(op, lhs, rhs);\n        if (result != MP_OBJ_NULL) {\n            return result;\n        }\n    }\n\n    #if MICROPY_PY_REVERSE_SPECIAL_METHODS\n    if (op >= MP_BINARY_OP_OR && op <= MP_BINARY_OP_POWER) {\n        mp_obj_t t = rhs;\n        rhs = lhs;\n        lhs = t;\n        op += MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR;\n        goto generic_binary_op;\n    } else if (op >= MP_BINARY_OP_REVERSE_OR) {\n        // Convert __rop__ back to __op__ for error message\n        mp_obj_t t = rhs;\n        rhs = lhs;\n        lhs = t;\n        op -= MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR;\n    }\n    #endif\n\n    if (op == MP_BINARY_OP_CONTAINS) {\n        // If type didn't support containment then explicitly walk the iterator.\n        // mp_getiter will raise the appropriate exception if lhs is not iterable.\n        mp_obj_iter_buf_t iter_buf;\n        mp_obj_t iter = mp_getiter(lhs, &iter_buf);\n        mp_obj_t next;\n        while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {\n            if (mp_obj_equal(next, rhs)) {\n                return mp_const_true;\n            }\n        }\n        return mp_const_false;\n    }\n\nunsupported_op:\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    mp_raise_TypeError(MP_ERROR_TEXT(\"unsupported type for operator\"));\n    #else\n    mp_raise_msg_varg(&mp_type_TypeError,\n        MP_ERROR_TEXT(\"unsupported types for %q: '%s', '%s'\"),\n        mp_binary_op_method_name[op], mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs));\n    #endif\n\nzero_division:\n    mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT(\"divide by zero\"));\n}\n\nmp_obj_t mp_call_function_0(mp_obj_t fun) {\n    return mp_call_function_n_kw(fun, 0, 0, NULL);\n}\n\nmp_obj_t mp_call_function_1(mp_obj_t fun, mp_obj_t arg) {\n    return mp_call_function_n_kw(fun, 1, 0, &arg);\n}\n\nmp_obj_t mp_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) {\n    mp_obj_t args[2];\n    args[0] = arg1;\n    args[1] = arg2;\n    return mp_call_function_n_kw(fun, 2, 0, args);\n}\n\n// args contains, eg: arg0  arg1  key0  value0  key1  value1\nmp_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) {\n    // TODO improve this: fun object can specify its type and we parse here the arguments,\n    // passing to the function arrays of fixed and keyword arguments\n\n    DEBUG_OP_printf(\"calling function %p(n_args=\" UINT_FMT \", n_kw=\" UINT_FMT \", args=%p)\\n\", fun_in, n_args, n_kw, args);\n\n    // get the type\n    const mp_obj_type_t *type = mp_obj_get_type(fun_in);\n\n    // do the call\n    if (type->call != NULL) {\n        return type->call(fun_in, n_args, n_kw, args);\n    }\n\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    mp_raise_TypeError(MP_ERROR_TEXT(\"object not callable\"));\n    #else\n    mp_raise_msg_varg(&mp_type_TypeError,\n        MP_ERROR_TEXT(\"'%s' object isn't callable\"), mp_obj_get_type_str(fun_in));\n    #endif\n}\n\n// 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)\n// if n_args==0 and n_kw==0 then there are only fun and self/NULL\nmp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    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);\n    int adjust = (args[1] == MP_OBJ_NULL) ? 0 : 1;\n    return mp_call_function_n_kw(args[0], n_args + adjust, n_kw, args + 2 - adjust);\n}\n\n// This function only needs to be exposed externally when in stackless mode.\n#if !MICROPY_STACKLESS\nSTATIC\n#endif\nvoid 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) {\n    mp_obj_t fun = *args++;\n    mp_obj_t self = MP_OBJ_NULL;\n    if (have_self) {\n        self = *args++; // may be MP_OBJ_NULL\n    }\n    uint n_args = n_args_n_kw & 0xff;\n    uint n_kw = (n_args_n_kw >> 8) & 0xff;\n    mp_obj_t pos_seq = args[n_args + 2 * n_kw]; // may be MP_OBJ_NULL\n    mp_obj_t kw_dict = args[n_args + 2 * n_kw + 1]; // may be MP_OBJ_NULL\n\n    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);\n\n    // We need to create the following array of objects:\n    //     args[0 .. n_args]  unpacked(pos_seq)  args[n_args .. n_args + 2 * n_kw]  unpacked(kw_dict)\n    // TODO: optimize one day to avoid constructing new arg array? Will be hard.\n\n    // The new args array\n    mp_obj_t *args2;\n    uint args2_alloc;\n    uint args2_len = 0;\n\n    // Try to get a hint for the size of the kw_dict\n    uint kw_dict_len = 0;\n    if (kw_dict != MP_OBJ_NULL && mp_obj_is_type(kw_dict, &mp_type_dict)) {\n        kw_dict_len = mp_obj_dict_len(kw_dict);\n    }\n\n    // Extract the pos_seq sequence to the new args array.\n    // Note that it can be arbitrary iterator.\n    if (pos_seq == MP_OBJ_NULL) {\n        // no sequence\n\n        // allocate memory for the new array of args\n        args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len);\n        args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t));\n\n        // copy the self\n        if (self != MP_OBJ_NULL) {\n            args2[args2_len++] = self;\n        }\n\n        // copy the fixed pos args\n        mp_seq_copy(args2 + args2_len, args, n_args, mp_obj_t);\n        args2_len += n_args;\n\n    } else if (mp_obj_is_type(pos_seq, &mp_type_tuple) || mp_obj_is_type(pos_seq, &mp_type_list)) {\n        // optimise the case of a tuple and list\n\n        // get the items\n        size_t len;\n        mp_obj_t *items;\n        mp_obj_get_array(pos_seq, &len, &items);\n\n        // allocate memory for the new array of args\n        args2_alloc = 1 + n_args + len + 2 * (n_kw + kw_dict_len);\n        args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t));\n\n        // copy the self\n        if (self != MP_OBJ_NULL) {\n            args2[args2_len++] = self;\n        }\n\n        // copy the fixed and variable position args\n        mp_seq_cat(args2 + args2_len, args, n_args, items, len, mp_obj_t);\n        args2_len += n_args + len;\n\n    } else {\n        // generic iterator\n\n        // allocate memory for the new array of args\n        args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len) + 3;\n        args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t));\n\n        // copy the self\n        if (self != MP_OBJ_NULL) {\n            args2[args2_len++] = self;\n        }\n\n        // copy the fixed position args\n        mp_seq_copy(args2 + args2_len, args, n_args, mp_obj_t);\n        args2_len += n_args;\n\n        // extract the variable position args from the iterator\n        mp_obj_iter_buf_t iter_buf;\n        mp_obj_t iterable = mp_getiter(pos_seq, &iter_buf);\n        mp_obj_t item;\n        while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n            if (args2_len >= args2_alloc) {\n                args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), args2_alloc * 2 * sizeof(mp_obj_t));\n                args2_alloc *= 2;\n            }\n            args2[args2_len++] = item;\n        }\n    }\n\n    // The size of the args2 array now is the number of positional args.\n    uint pos_args_len = args2_len;\n\n    // Copy the fixed kw args.\n    mp_seq_copy(args2 + args2_len, args + n_args, 2 * n_kw, mp_obj_t);\n    args2_len += 2 * n_kw;\n\n    // Extract (key,value) pairs from kw_dict dictionary and append to args2.\n    // Note that it can be arbitrary iterator.\n    if (kw_dict == MP_OBJ_NULL) {\n        // pass\n    } else if (mp_obj_is_type(kw_dict, &mp_type_dict)) {\n        // dictionary\n        mp_map_t *map = mp_obj_dict_get_map(kw_dict);\n        assert(args2_len + 2 * map->used <= args2_alloc); // should have enough, since kw_dict_len is in this case hinted correctly above\n        for (size_t i = 0; i < map->alloc; i++) {\n            if (mp_map_slot_is_filled(map, i)) {\n                // the key must be a qstr, so intern it if it's a string\n                mp_obj_t key = map->table[i].key;\n                if (!mp_obj_is_qstr(key)) {\n                    key = mp_obj_str_intern_checked(key);\n                }\n                args2[args2_len++] = key;\n                args2[args2_len++] = map->table[i].value;\n            }\n        }\n    } else {\n        // generic mapping:\n        // - call keys() to get an iterable of all keys in the mapping\n        // - call __getitem__ for each key to get the corresponding value\n\n        // get the keys iterable\n        mp_obj_t dest[3];\n        mp_load_method(kw_dict, MP_QSTR_keys, dest);\n        mp_obj_t iterable = mp_getiter(mp_call_method_n_kw(0, 0, dest), NULL);\n\n        mp_obj_t key;\n        while ((key = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n            // expand size of args array if needed\n            if (args2_len + 1 >= args2_alloc) {\n                uint new_alloc = args2_alloc * 2;\n                if (new_alloc < 4) {\n                    new_alloc = 4;\n                }\n                args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), new_alloc * sizeof(mp_obj_t));\n                args2_alloc = new_alloc;\n            }\n\n            // the key must be a qstr, so intern it if it's a string\n            if (!mp_obj_is_qstr(key)) {\n                key = mp_obj_str_intern_checked(key);\n            }\n\n            // get the value corresponding to the key\n            mp_load_method(kw_dict, MP_QSTR___getitem__, dest);\n            dest[2] = key;\n            mp_obj_t value = mp_call_method_n_kw(1, 0, dest);\n\n            // store the key/value pair in the argument array\n            args2[args2_len++] = key;\n            args2[args2_len++] = value;\n        }\n    }\n\n    out_args->fun = fun;\n    out_args->args = args2;\n    out_args->n_args = pos_args_len;\n    out_args->n_kw = (args2_len - pos_args_len) / 2;\n    out_args->n_alloc = args2_alloc;\n}\n\nmp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args) {\n    mp_call_args_t out_args;\n    mp_call_prepare_args_n_kw_var(have_self, n_args_n_kw, args, &out_args);\n\n    mp_obj_t res = mp_call_function_n_kw(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args);\n    mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t));\n\n    return res;\n}\n\n// unpacked items are stored in reverse order into the array pointed to by items\nvoid mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) {\n    size_t seq_len;\n    if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) {\n        mp_obj_t *seq_items;\n        mp_obj_get_array(seq_in, &seq_len, &seq_items);\n        if (seq_len < num) {\n            goto too_short;\n        } else if (seq_len > num) {\n            goto too_long;\n        }\n        for (size_t i = 0; i < num; i++) {\n            items[i] = seq_items[num - 1 - i];\n        }\n    } else {\n        mp_obj_iter_buf_t iter_buf;\n        mp_obj_t iterable = mp_getiter(seq_in, &iter_buf);\n\n        for (seq_len = 0; seq_len < num; seq_len++) {\n            mp_obj_t el = mp_iternext(iterable);\n            if (el == MP_OBJ_STOP_ITERATION) {\n                goto too_short;\n            }\n            items[num - 1 - seq_len] = el;\n        }\n        if (mp_iternext(iterable) != MP_OBJ_STOP_ITERATION) {\n            goto too_long;\n        }\n    }\n    return;\n\ntoo_short:\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    mp_raise_ValueError(MP_ERROR_TEXT(\"wrong number of values to unpack\"));\n    #else\n    mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT(\"need more than %d values to unpack\"), (int)seq_len);\n    #endif\ntoo_long:\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    mp_raise_ValueError(MP_ERROR_TEXT(\"wrong number of values to unpack\"));\n    #else\n    mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT(\"too many values to unpack (expected %d)\"), (int)num);\n    #endif\n}\n\n// unpacked items are stored in reverse order into the array pointed to by items\nvoid mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) {\n    size_t num_left = num_in & 0xff;\n    size_t num_right = (num_in >> 8) & 0xff;\n    DEBUG_OP_printf(\"unpack ex \" UINT_FMT \" \" UINT_FMT \"\\n\", num_left, num_right);\n    size_t seq_len;\n    if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) {\n        // Make the seq variable volatile so the compiler keeps a reference to it,\n        // since if it's a tuple then seq_items points to the interior of the GC cell\n        // and mp_obj_new_list may trigger a GC which doesn't trace this and reclaims seq.\n        volatile mp_obj_t seq = seq_in;\n        mp_obj_t *seq_items;\n        mp_obj_get_array(seq, &seq_len, &seq_items);\n        if (seq_len < num_left + num_right) {\n            goto too_short;\n        }\n        for (size_t i = 0; i < num_right; i++) {\n            items[i] = seq_items[seq_len - 1 - i];\n        }\n        items[num_right] = mp_obj_new_list(seq_len - num_left - num_right, seq_items + num_left);\n        for (size_t i = 0; i < num_left; i++) {\n            items[num_right + 1 + i] = seq_items[num_left - 1 - i];\n        }\n        seq = MP_OBJ_NULL;\n    } else {\n        // Generic iterable; this gets a bit messy: we unpack known left length to the\n        // items destination array, then the rest to a dynamically created list.  Once the\n        // iterable is exhausted, we take from this list for the right part of the items.\n        // TODO Improve to waste less memory in the dynamically created list.\n        mp_obj_t iterable = mp_getiter(seq_in, NULL);\n        mp_obj_t item;\n        for (seq_len = 0; seq_len < num_left; seq_len++) {\n            item = mp_iternext(iterable);\n            if (item == MP_OBJ_STOP_ITERATION) {\n                goto too_short;\n            }\n            items[num_left + num_right + 1 - 1 - seq_len] = item;\n        }\n        mp_obj_list_t *rest = MP_OBJ_TO_PTR(mp_obj_new_list(0, NULL));\n        while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n            mp_obj_list_append(MP_OBJ_FROM_PTR(rest), item);\n        }\n        if (rest->len < num_right) {\n            goto too_short;\n        }\n        items[num_right] = MP_OBJ_FROM_PTR(rest);\n        for (size_t i = 0; i < num_right; i++) {\n            items[num_right - 1 - i] = rest->items[rest->len - num_right + i];\n        }\n        mp_obj_list_set_len(MP_OBJ_FROM_PTR(rest), rest->len - num_right);\n    }\n    return;\n\ntoo_short:\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    mp_raise_ValueError(MP_ERROR_TEXT(\"wrong number of values to unpack\"));\n    #else\n    mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT(\"need more than %d values to unpack\"), (int)seq_len);\n    #endif\n}\n\nmp_obj_t mp_load_attr(mp_obj_t base, qstr attr) {\n    DEBUG_OP_printf(\"load attr %p.%s\\n\", base, qstr_str(attr));\n    // use load_method\n    mp_obj_t dest[2];\n    mp_load_method(base, attr, dest);\n    if (dest[1] == MP_OBJ_NULL) {\n        // load_method returned just a normal attribute\n        return dest[0];\n    } else {\n        // load_method returned a method, so build a bound method object\n        return mp_obj_new_bound_meth(dest[0], dest[1]);\n    }\n}\n\n#if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG\n\n// The following \"checked fun\" type is local to the mp_convert_member_lookup\n// function, and serves to check that the first argument to a builtin function\n// has the correct type.\n\ntypedef struct _mp_obj_checked_fun_t {\n    mp_obj_base_t base;\n    const mp_obj_type_t *type;\n    mp_obj_t fun;\n} mp_obj_checked_fun_t;\n\nSTATIC mp_obj_t checked_fun_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n    mp_obj_checked_fun_t *self = MP_OBJ_TO_PTR(self_in);\n    if (n_args > 0) {\n        const mp_obj_type_t *arg0_type = mp_obj_get_type(args[0]);\n        if (arg0_type != self->type) {\n            #if MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_DETAILED\n            mp_raise_TypeError(MP_ERROR_TEXT(\"argument has wrong type\"));\n            #else\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"argument should be a '%q' not a '%q'\"), self->type->name, arg0_type->name);\n            #endif\n        }\n    }\n    return mp_call_function_n_kw(self->fun, n_args, n_kw, args);\n}\n\nSTATIC const mp_obj_type_t mp_type_checked_fun = {\n    { &mp_type_type },\n    .flags = MP_TYPE_FLAG_BINDS_SELF,\n    .name = MP_QSTR_function,\n    .call = checked_fun_call,\n};\n\nSTATIC mp_obj_t mp_obj_new_checked_fun(const mp_obj_type_t *type, mp_obj_t fun) {\n    mp_obj_checked_fun_t *o = m_new_obj(mp_obj_checked_fun_t);\n    o->base.type = &mp_type_checked_fun;\n    o->type = type;\n    o->fun = fun;\n    return MP_OBJ_FROM_PTR(o);\n}\n\n#endif // MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG\n\n// Given a member that was extracted from an instance, convert it correctly\n// and put the result in the dest[] array for a possible method call.\n// Conversion means dealing with static/class methods, callables, and values.\n// see http://docs.python.org/3/howto/descriptor.html\n// and also https://mail.python.org/pipermail/python-dev/2015-March/138950.html\nvoid mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) {\n    if (mp_obj_is_obj(member)) {\n        const mp_obj_type_t *m_type = ((mp_obj_base_t *)MP_OBJ_TO_PTR(member))->type;\n        if (m_type->flags & MP_TYPE_FLAG_BINDS_SELF) {\n            // `member` is a function that binds self as its first argument.\n            if (m_type->flags & MP_TYPE_FLAG_BUILTIN_FUN) {\n                // `member` is a built-in function, which has special behaviour.\n                if (mp_obj_is_instance_type(type)) {\n                    // Built-in functions on user types always behave like a staticmethod.\n                    dest[0] = member;\n                }\n                #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG\n                else if (self == MP_OBJ_NULL && type != &mp_type_object) {\n                    // `member` is a built-in method without a first argument, so wrap\n                    // it in a type checker that will check self when it's supplied.\n                    // Note that object will do its own checking so shouldn't be wrapped.\n                    dest[0] = mp_obj_new_checked_fun(type, member);\n                }\n                #endif\n                else {\n                    // Return a (built-in) bound method, with self being this object.\n                    dest[0] = member;\n                    dest[1] = self;\n                }\n            } else {\n                // Return a bound method, with self being this object.\n                dest[0] = member;\n                dest[1] = self;\n            }\n        } else if (m_type == &mp_type_staticmethod) {\n            // `member` is a staticmethod, return the function that it wraps.\n            dest[0] = ((mp_obj_static_class_method_t *)MP_OBJ_TO_PTR(member))->fun;\n        } else if (m_type == &mp_type_classmethod) {\n            // `member` is a classmethod, return a bound method with self being the type of\n            // this object.  This type should be the type of the original instance, not the\n            // base type (which is what is passed in the `type` argument to this function).\n            if (self != MP_OBJ_NULL) {\n                type = mp_obj_get_type(self);\n            }\n            dest[0] = ((mp_obj_static_class_method_t *)MP_OBJ_TO_PTR(member))->fun;\n            dest[1] = MP_OBJ_FROM_PTR(type);\n        } else {\n            // `member` is a value, so just return that value.\n            dest[0] = member;\n        }\n    } else {\n        // `member` is a value, so just return that value.\n        dest[0] = member;\n    }\n}\n\n// no attribute found, returns:     dest[0] == MP_OBJ_NULL, dest[1] == MP_OBJ_NULL\n// normal attribute found, returns: dest[0] == <attribute>, dest[1] == MP_OBJ_NULL\n// method attribute found, returns: dest[0] == <method>,    dest[1] == <self>\nvoid mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {\n    // clear output to indicate no attribute/method found yet\n    dest[0] = MP_OBJ_NULL;\n    dest[1] = MP_OBJ_NULL;\n\n    // get the type\n    const mp_obj_type_t *type = mp_obj_get_type(obj);\n\n    // look for built-in names\n    #if MICROPY_CPYTHON_COMPAT\n    if (attr == MP_QSTR___class__) {\n        // a.__class__ is equivalent to type(a)\n        dest[0] = MP_OBJ_FROM_PTR(type);\n        return;\n    }\n    #endif\n\n    if (attr == MP_QSTR___next__ && type->iternext != NULL) {\n        dest[0] = MP_OBJ_FROM_PTR(&mp_builtin_next_obj);\n        dest[1] = obj;\n\n    } else if (type->attr != NULL) {\n        // this type can do its own load, so call it\n        type->attr(obj, attr, dest);\n\n    } else if (type->locals_dict != NULL) {\n        // generic method lookup\n        // this is a lookup in the object (ie not class or type)\n        assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now\n        mp_map_t *locals_map = &type->locals_dict->map;\n        mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);\n        if (elem != NULL) {\n            mp_convert_member_lookup(obj, type, elem->value, dest);\n        }\n    }\n}\n\nvoid mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {\n    DEBUG_OP_printf(\"load method %p.%s\\n\", base, qstr_str(attr));\n\n    mp_load_method_maybe(base, attr, dest);\n\n    if (dest[0] == MP_OBJ_NULL) {\n        // no attribute/method called attr\n        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n        mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT(\"no such attribute\"));\n        #else\n        // following CPython, we give a more detailed error message for type objects\n        if (mp_obj_is_type(base, &mp_type_type)) {\n            mp_raise_msg_varg(&mp_type_AttributeError,\n                MP_ERROR_TEXT(\"type object '%q' has no attribute '%q'\"),\n                ((mp_obj_type_t *)MP_OBJ_TO_PTR(base))->name, attr);\n        } else {\n            mp_raise_msg_varg(&mp_type_AttributeError,\n                MP_ERROR_TEXT(\"'%s' object has no attribute '%q'\"),\n                mp_obj_get_type_str(base), attr);\n        }\n        #endif\n    }\n}\n\n// Acts like mp_load_method_maybe but catches AttributeError, and all other exceptions if requested\nvoid mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc) {\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        mp_load_method_maybe(obj, attr, dest);\n        nlr_pop();\n    } else {\n        if (!catch_all_exc\n            && !mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type),\n                MP_OBJ_FROM_PTR(&mp_type_AttributeError))) {\n            // Re-raise the exception\n            nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val));\n        }\n    }\n}\n\nvoid mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {\n    DEBUG_OP_printf(\"store attr %p.%s <- %p\\n\", base, qstr_str(attr), value);\n    const mp_obj_type_t *type = mp_obj_get_type(base);\n    if (type->attr != NULL) {\n        mp_obj_t dest[2] = {MP_OBJ_SENTINEL, value};\n        type->attr(base, attr, dest);\n        if (dest[0] == MP_OBJ_NULL) {\n            // success\n            return;\n        }\n    }\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT(\"no such attribute\"));\n    #else\n    mp_raise_msg_varg(&mp_type_AttributeError,\n        MP_ERROR_TEXT(\"'%s' object has no attribute '%q'\"),\n        mp_obj_get_type_str(base), attr);\n    #endif\n}\n\nmp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {\n    assert(o_in);\n    const mp_obj_type_t *type = mp_obj_get_type(o_in);\n\n    // Check for native getiter which is the identity.  We handle this case explicitly\n    // so we don't unnecessarily allocate any RAM for the iter_buf, which won't be used.\n    if (type->getiter == mp_identity_getiter) {\n        return o_in;\n    }\n\n    // check for native getiter (corresponds to __iter__)\n    if (type->getiter != NULL) {\n        if (iter_buf == NULL && type->getiter != mp_obj_instance_getiter) {\n            // if caller did not provide a buffer then allocate one on the heap\n            // mp_obj_instance_getiter is special, it will allocate only if needed\n            iter_buf = m_new_obj(mp_obj_iter_buf_t);\n        }\n        mp_obj_t iter = type->getiter(o_in, iter_buf);\n        if (iter != MP_OBJ_NULL) {\n            return iter;\n        }\n    }\n\n    // check for __getitem__\n    mp_obj_t dest[2];\n    mp_load_method_maybe(o_in, MP_QSTR___getitem__, dest);\n    if (dest[0] != MP_OBJ_NULL) {\n        // __getitem__ exists, create and return an iterator\n        if (iter_buf == NULL) {\n            // if caller did not provide a buffer then allocate one on the heap\n            iter_buf = m_new_obj(mp_obj_iter_buf_t);\n        }\n        return mp_obj_new_getitem_iter(dest, iter_buf);\n    }\n\n    // object not iterable\n    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n    mp_raise_TypeError(MP_ERROR_TEXT(\"object not iterable\"));\n    #else\n    mp_raise_msg_varg(&mp_type_TypeError,\n        MP_ERROR_TEXT(\"'%s' object isn't iterable\"), mp_obj_get_type_str(o_in));\n    #endif\n\n}\n\n// may return MP_OBJ_STOP_ITERATION as an optimisation instead of raise StopIteration()\n// may also raise StopIteration()\nmp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) {\n    const mp_obj_type_t *type = mp_obj_get_type(o_in);\n    if (type->iternext != NULL) {\n        return type->iternext(o_in);\n    } else {\n        // check for __next__ method\n        mp_obj_t dest[2];\n        mp_load_method_maybe(o_in, MP_QSTR___next__, dest);\n        if (dest[0] != MP_OBJ_NULL) {\n            // __next__ exists, call it and return its result\n            return mp_call_method_n_kw(0, 0, dest);\n        } else {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_raise_TypeError(MP_ERROR_TEXT(\"object not an iterator\"));\n            #else\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"'%s' object isn't an iterator\"), mp_obj_get_type_str(o_in));\n            #endif\n        }\n    }\n}\n\n// will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration() (or any subclass thereof)\n// may raise other exceptions\nmp_obj_t mp_iternext(mp_obj_t o_in) {\n    MP_STACK_CHECK(); // enumerate, filter, map and zip can recursively call mp_iternext\n    const mp_obj_type_t *type = mp_obj_get_type(o_in);\n    if (type->iternext != NULL) {\n        return type->iternext(o_in);\n    } else {\n        // check for __next__ method\n        mp_obj_t dest[2];\n        mp_load_method_maybe(o_in, MP_QSTR___next__, dest);\n        if (dest[0] != MP_OBJ_NULL) {\n            // __next__ exists, call it and return its result\n            nlr_buf_t nlr;\n            if (nlr_push(&nlr) == 0) {\n                mp_obj_t ret = mp_call_method_n_kw(0, 0, dest);\n                nlr_pop();\n                return ret;\n            } else {\n                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))) {\n                    return MP_OBJ_STOP_ITERATION;\n                } else {\n                    nlr_jump(nlr.ret_val);\n                }\n            }\n        } else {\n            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE\n            mp_raise_TypeError(MP_ERROR_TEXT(\"object not an iterator\"));\n            #else\n            mp_raise_msg_varg(&mp_type_TypeError,\n                MP_ERROR_TEXT(\"'%s' object isn't an iterator\"), mp_obj_get_type_str(o_in));\n            #endif\n        }\n    }\n}\n\n// TODO: Unclear what to do with StopIterarion exception here.\nmp_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) {\n    assert((send_value != MP_OBJ_NULL) ^ (throw_value != MP_OBJ_NULL));\n    const mp_obj_type_t *type = mp_obj_get_type(self_in);\n\n    if (type == &mp_type_gen_instance) {\n        return mp_obj_gen_resume(self_in, send_value, throw_value, ret_val);\n    }\n\n    if (type->iternext != NULL && send_value == mp_const_none) {\n        mp_obj_t ret = type->iternext(self_in);\n        *ret_val = ret;\n        if (ret != MP_OBJ_STOP_ITERATION) {\n            return MP_VM_RETURN_YIELD;\n        } else {\n            // Emulate raise StopIteration()\n            // Special case, handled in vm.c\n            return MP_VM_RETURN_NORMAL;\n        }\n    }\n\n    mp_obj_t dest[3]; // Reserve slot for send() arg\n\n    // Python instance iterator protocol\n    if (send_value == mp_const_none) {\n        mp_load_method_maybe(self_in, MP_QSTR___next__, dest);\n        if (dest[0] != MP_OBJ_NULL) {\n            *ret_val = mp_call_method_n_kw(0, 0, dest);\n            return MP_VM_RETURN_YIELD;\n        }\n    }\n\n    // Either python instance generator protocol, or native object\n    // generator protocol.\n    if (send_value != MP_OBJ_NULL) {\n        mp_load_method(self_in, MP_QSTR_send, dest);\n        dest[2] = send_value;\n        *ret_val = mp_call_method_n_kw(1, 0, dest);\n        return MP_VM_RETURN_YIELD;\n    }\n\n    assert(throw_value != MP_OBJ_NULL);\n    {\n        if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(throw_value)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) {\n            mp_load_method_maybe(self_in, MP_QSTR_close, dest);\n            if (dest[0] != MP_OBJ_NULL) {\n                // TODO: Exceptions raised in close() are not propagated,\n                // printed to sys.stderr\n                *ret_val = mp_call_method_n_kw(0, 0, dest);\n                // We assume one can't \"yield\" from close()\n                return MP_VM_RETURN_NORMAL;\n            }\n        } else {\n            mp_load_method_maybe(self_in, MP_QSTR_throw, dest);\n            if (dest[0] != MP_OBJ_NULL) {\n                dest[2] = throw_value;\n                *ret_val = mp_call_method_n_kw(1, 0, dest);\n                // If .throw() method returned, we assume it's value to yield\n                // - any exception would be thrown with nlr_raise().\n                return MP_VM_RETURN_YIELD;\n            }\n        }\n        // If there's nowhere to throw exception into, then we assume that object\n        // is just incapable to handle it, so any exception thrown into it\n        // will be propagated up. This behavior is approved by test_pep380.py\n        // test_delegation_of_close_to_non_generator(),\n        //  test_delegating_throw_to_non_generator()\n        if (mp_obj_exception_match(throw_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) {\n            // PEP479: if StopIteration is raised inside a generator it is replaced with RuntimeError\n            *ret_val = mp_obj_new_exception_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"generator raised StopIteration\"));\n        } else {\n            *ret_val = mp_make_raise_obj(throw_value);\n        }\n        return MP_VM_RETURN_EXCEPTION;\n    }\n}\n\nmp_obj_t mp_make_raise_obj(mp_obj_t o) {\n    DEBUG_printf(\"raise %p\\n\", o);\n    if (mp_obj_is_exception_type(o)) {\n        // o is an exception type (it is derived from BaseException (or is BaseException))\n        // create and return a new exception instance by calling o\n        // TODO could have an option to disable traceback, then builtin exceptions (eg TypeError)\n        // could have const instances in ROM which we return here instead\n        return mp_call_function_n_kw(o, 0, 0, NULL);\n    } else if (mp_obj_is_exception_instance(o)) {\n        // o is an instance of an exception, so use it as the exception\n        return o;\n    } else {\n        // o cannot be used as an exception, so return a type error (which will be raised by the caller)\n        return mp_obj_new_exception_msg(&mp_type_TypeError, MP_ERROR_TEXT(\"exceptions must derive from BaseException\"));\n    }\n}\n\nmp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) {\n    DEBUG_printf(\"import name '%s' level=%d\\n\", qstr_str(name), MP_OBJ_SMALL_INT_VALUE(level));\n\n    // build args array\n    mp_obj_t args[5];\n    args[0] = MP_OBJ_NEW_QSTR(name);\n    args[1] = mp_const_none; // TODO should be globals\n    args[2] = mp_const_none; // TODO should be locals\n    args[3] = fromlist;\n    args[4] = level;\n\n    #if MICROPY_CAN_OVERRIDE_BUILTINS\n    // Lookup __import__ and call that if it exists\n    mp_obj_dict_t *bo_dict = MP_STATE_VM(mp_module_builtins_override_dict);\n    if (bo_dict != NULL) {\n        mp_map_elem_t *import = mp_map_lookup(&bo_dict->map, MP_OBJ_NEW_QSTR(MP_QSTR___import__), MP_MAP_LOOKUP);\n        if (import != NULL) {\n            return mp_call_function_n_kw(import->value, 5, 0, args);\n        }\n    }\n    #endif\n\n    return mp_builtin___import__(5, args);\n}\n\nmp_obj_t mp_import_from(mp_obj_t module, qstr name) {\n    DEBUG_printf(\"import from %p %s\\n\", module, qstr_str(name));\n\n    mp_obj_t dest[2];\n\n    mp_load_method_maybe(module, name, dest);\n\n    if (dest[1] != MP_OBJ_NULL) {\n        // Hopefully we can't import bound method from an object\n    import_error:\n        mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT(\"can't import name %q\"), name);\n    }\n\n    if (dest[0] != MP_OBJ_NULL) {\n        return dest[0];\n    }\n\n    #if MICROPY_ENABLE_EXTERNAL_IMPORT\n\n    // See if it's a package, then can try FS import\n    if (!mp_obj_is_package(module)) {\n        goto import_error;\n    }\n\n    mp_load_method_maybe(module, MP_QSTR___name__, dest);\n    size_t pkg_name_len;\n    const char *pkg_name = mp_obj_str_get_data(dest[0], &pkg_name_len);\n\n    const uint dot_name_len = pkg_name_len + 1 + qstr_len(name);\n    char *dot_name = mp_local_alloc(dot_name_len);\n    memcpy(dot_name, pkg_name, pkg_name_len);\n    dot_name[pkg_name_len] = '.';\n    memcpy(dot_name + pkg_name_len + 1, qstr_str(name), qstr_len(name));\n    qstr dot_name_q = qstr_from_strn(dot_name, dot_name_len);\n    mp_local_free(dot_name);\n\n    // For fromlist, pass sentinel \"non empty\" value to force returning of leaf module\n    return mp_import_name(dot_name_q, mp_const_true, MP_OBJ_NEW_SMALL_INT(0));\n\n    #else\n\n    // Package import not supported with external imports disabled\n    goto import_error;\n\n    #endif\n}\n\nvoid mp_import_all(mp_obj_t module) {\n    DEBUG_printf(\"import all %p\\n\", module);\n\n    // TODO: Support __all__\n    mp_map_t *map = &mp_obj_module_get_globals(module)->map;\n    for (size_t i = 0; i < map->alloc; i++) {\n        if (mp_map_slot_is_filled(map, i)) {\n            // Entry in module global scope may be generated programmatically\n            // (and thus be not a qstr for longer names). Avoid turning it in\n            // qstr if it has '_' and was used exactly to save memory.\n            const char *name = mp_obj_str_get_str(map->table[i].key);\n            if (*name != '_') {\n                qstr qname = mp_obj_str_get_qstr(map->table[i].key);\n                mp_store_name(qname, map->table[i].value);\n            }\n        }\n    }\n}\n\n#if MICROPY_ENABLE_COMPILER\n\nmp_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) {\n    // save context\n    mp_obj_dict_t *volatile old_globals = mp_globals_get();\n    mp_obj_dict_t *volatile old_locals = mp_locals_get();\n\n    // set new context\n    mp_globals_set(globals);\n    mp_locals_set(locals);\n\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        qstr source_name = lex->source_name;\n        mp_parse_tree_t parse_tree = mp_parse(lex, parse_input_kind);\n        mp_obj_t module_fun = mp_compile(&parse_tree, source_name, parse_input_kind == MP_PARSE_SINGLE_INPUT);\n\n        mp_obj_t ret;\n        if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) {\n            // for compile only, return value is the module function\n            ret = module_fun;\n        } else {\n            // execute module function and get return value\n            ret = mp_call_function_0(module_fun);\n        }\n\n        // finish nlr block, restore context and return value\n        nlr_pop();\n        mp_globals_set(old_globals);\n        mp_locals_set(old_locals);\n        return ret;\n    } else {\n        // exception; restore context and re-raise same exception\n        mp_globals_set(old_globals);\n        mp_locals_set(old_locals);\n        nlr_jump(nlr.ret_val);\n    }\n}\n\n#endif // MICROPY_ENABLE_COMPILER\n\nNORETURN void m_malloc_fail(size_t num_bytes) {\n    DEBUG_printf(\"memory allocation failed, allocating %u bytes\\n\", (uint)num_bytes);\n    #if MICROPY_ENABLE_GC\n    if (gc_is_locked()) {\n        mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT(\"memory allocation failed, heap is locked\"));\n    }\n    #endif\n    mp_raise_msg_varg(&mp_type_MemoryError,\n        MP_ERROR_TEXT(\"memory allocation failed, allocating %u bytes\"), (uint)num_bytes);\n}\n\nNORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg) {\n    if (msg == NULL) {\n        nlr_raise(mp_obj_new_exception(exc_type));\n    } else {\n        nlr_raise(mp_obj_new_exception_msg(exc_type, msg));\n    }\n}\n\nNORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...) {\n    va_list args;\n    va_start(args, fmt);\n    mp_obj_t exc = mp_obj_new_exception_msg_vlist(exc_type, fmt, args);\n    va_end(args);\n    nlr_raise(exc);\n}\n\nNORETURN void mp_raise_ValueError(mp_rom_error_text_t msg) {\n    mp_raise_msg(&mp_type_ValueError, msg);\n}\n\nNORETURN void mp_raise_TypeError(mp_rom_error_text_t msg) {\n    mp_raise_msg(&mp_type_TypeError, msg);\n}\n\nNORETURN void mp_raise_OSError(int errno_) {\n    nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_)));\n}\n\nNORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg) {\n    mp_raise_msg(&mp_type_NotImplementedError, msg);\n}\n\n#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK\nNORETURN void mp_raise_recursion_depth(void) {\n    nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError,\n        MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded)));\n}\n#endif\n"
  },
  {
    "path": "py/runtime.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_RUNTIME_H\n#define MICROPY_INCLUDED_PY_RUNTIME_H\n\n#include \"py/mpstate.h\"\n#include \"py/pystack.h\"\n\ntypedef enum {\n    MP_VM_RETURN_NORMAL,\n    MP_VM_RETURN_YIELD,\n    MP_VM_RETURN_EXCEPTION,\n} mp_vm_return_kind_t;\n\ntypedef enum {\n    MP_ARG_BOOL      = 0x001,\n    MP_ARG_INT       = 0x002,\n    MP_ARG_OBJ       = 0x003,\n    MP_ARG_KIND_MASK = 0x0ff,\n    MP_ARG_REQUIRED  = 0x100,\n    MP_ARG_KW_ONLY   = 0x200,\n} mp_arg_flag_t;\n\ntypedef union _mp_arg_val_t {\n    bool u_bool;\n    mp_int_t u_int;\n    mp_obj_t u_obj;\n    mp_rom_obj_t u_rom_obj;\n} mp_arg_val_t;\n\ntypedef struct _mp_arg_t {\n    uint16_t qst;\n    uint16_t flags;\n    mp_arg_val_t defval;\n} mp_arg_t;\n\n// Tables mapping operator enums to qstrs, defined in objtype.c\nextern const byte mp_unary_op_method_name[];\nextern const byte mp_binary_op_method_name[];\n\nvoid mp_init(void);\nvoid mp_deinit(void);\n\nvoid mp_keyboard_interrupt(void);\nvoid mp_handle_pending(bool raise_exc);\nvoid mp_handle_pending_tail(mp_uint_t atomic_state);\n\n#if MICROPY_ENABLE_SCHEDULER\nvoid mp_sched_lock(void);\nvoid mp_sched_unlock(void);\n#define mp_sched_num_pending() (MP_STATE_VM(sched_len))\nbool mp_sched_schedule(mp_obj_t function, mp_obj_t arg);\n#endif\n\n// extra printing method specifically for mp_obj_t's which are integral type\nint 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);\n\nvoid mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig);\nstatic inline 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) {\n    mp_arg_check_num_sig(n_args, n_kw, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, takes_kw));\n}\nvoid 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);\nvoid 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);\nNORETURN void mp_arg_error_terse_mismatch(void);\nNORETURN void mp_arg_error_unimpl_kw(void);\n\nstatic inline mp_obj_dict_t *mp_locals_get(void) {\n    return MP_STATE_THREAD(dict_locals);\n}\nstatic inline void mp_locals_set(mp_obj_dict_t *d) {\n    MP_STATE_THREAD(dict_locals) = d;\n}\nstatic inline mp_obj_dict_t *mp_globals_get(void) {\n    return MP_STATE_THREAD(dict_globals);\n}\nstatic inline void mp_globals_set(mp_obj_dict_t *d) {\n    MP_STATE_THREAD(dict_globals) = d;\n}\n\nmp_obj_t mp_load_name(qstr qst);\nmp_obj_t mp_load_global(qstr qst);\nmp_obj_t mp_load_build_class(void);\nvoid mp_store_name(qstr qst, mp_obj_t obj);\nvoid mp_store_global(qstr qst, mp_obj_t obj);\nvoid mp_delete_name(qstr qst);\nvoid mp_delete_global(qstr qst);\n\nmp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg);\nmp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs);\n\nmp_obj_t mp_call_function_0(mp_obj_t fun);\nmp_obj_t mp_call_function_1(mp_obj_t fun, mp_obj_t arg);\nmp_obj_t mp_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);\nmp_obj_t mp_call_function_n_kw(mp_obj_t fun, size_t n_args, size_t n_kw, const mp_obj_t *args);\nmp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args);\nmp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args);\nmp_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);\n// Call function and catch/dump exception - for Python callbacks from C code\n// (return MP_OBJ_NULL in case of exception).\nmp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg);\nmp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);\n\ntypedef struct _mp_call_args_t {\n    mp_obj_t fun;\n    size_t n_args, n_kw, n_alloc;\n    mp_obj_t *args;\n} mp_call_args_t;\n\n#if MICROPY_STACKLESS\n// Takes arguments which are the most general mix of Python arg types, and\n// prepares argument array suitable for passing to ->call() method of a\n// function object (and mp_call_function_n_kw()).\n// (Only needed in stackless mode.)\nvoid 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);\n#endif\n\nvoid mp_unpack_sequence(mp_obj_t seq, size_t num, mp_obj_t *items);\nvoid mp_unpack_ex(mp_obj_t seq, size_t num, mp_obj_t *items);\nmp_obj_t mp_store_map(mp_obj_t map, mp_obj_t key, mp_obj_t value);\nmp_obj_t mp_load_attr(mp_obj_t base, qstr attr);\nvoid mp_convert_member_lookup(mp_obj_t obj, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest);\nvoid mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest);\nvoid mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest);\nvoid mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc);\nvoid mp_load_super_method(qstr attr, mp_obj_t *dest);\nvoid mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val);\n\nmp_obj_t mp_getiter(mp_obj_t o, mp_obj_iter_buf_t *iter_buf);\nmp_obj_t mp_iternext_allow_raise(mp_obj_t o); // may return MP_OBJ_STOP_ITERATION instead of raising StopIteration()\nmp_obj_t mp_iternext(mp_obj_t o); // will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration(...)\nmp_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);\n\nmp_obj_t mp_make_raise_obj(mp_obj_t o);\n\nmp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level);\nmp_obj_t mp_import_from(mp_obj_t module, qstr name);\nvoid mp_import_all(mp_obj_t module);\n\n#define mp_raise_type(exc_type) mp_raise_msg(exc_type, NULL)\nNORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg);\nNORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...);\nNORETURN void mp_raise_ValueError(mp_rom_error_text_t msg);\nNORETURN void mp_raise_TypeError(mp_rom_error_text_t msg);\nNORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg);\nNORETURN void mp_raise_OSError(int errno_);\nNORETURN void mp_raise_recursion_depth(void);\n\n#if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG\n#undef mp_check_self\n#define mp_check_self(pred)\n#else\n// A port may define to raise TypeError for example\n#ifndef mp_check_self\n#define mp_check_self(pred) assert(pred)\n#endif\n#endif\n\n// helper functions for native/viper code\nint mp_native_type_from_qstr(qstr qst);\nmp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type);\nmp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type);\n\n#define mp_sys_path (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_path_obj)))\n#define mp_sys_argv (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_argv_obj)))\n\n#if MICROPY_WARNINGS\n#ifndef mp_warning\nvoid mp_warning(const char *category, const char *msg, ...);\n#endif\n#else\n#define mp_warning(...)\n#endif\n\n#endif // MICROPY_INCLUDED_PY_RUNTIME_H\n"
  },
  {
    "path": "py/runtime0.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_RUNTIME0_H\n#define MICROPY_INCLUDED_PY_RUNTIME0_H\n\n// The first four must fit in 8 bits, see emitbc.c\n// The remaining must fit in 16 bits, see scope.h\n#define MP_SCOPE_FLAG_ALL_SIG      (0x0f)\n#define MP_SCOPE_FLAG_GENERATOR    (0x01)\n#define MP_SCOPE_FLAG_VARKEYWORDS  (0x02)\n#define MP_SCOPE_FLAG_VARARGS      (0x04)\n#define MP_SCOPE_FLAG_DEFKWARGS    (0x08)\n#define MP_SCOPE_FLAG_REFGLOBALS   (0x10) // used only if native emitter enabled\n#define MP_SCOPE_FLAG_HASCONSTS    (0x20) // used only if native emitter enabled\n#define MP_SCOPE_FLAG_VIPERRET_POS    (6) // 3 bits used for viper return type, to pass from compiler to native emitter\n#define MP_SCOPE_FLAG_VIPERRELOC   (0x10) // used only when loading viper from .mpy\n#define MP_SCOPE_FLAG_VIPERRODATA  (0x20) // used only when loading viper from .mpy\n#define MP_SCOPE_FLAG_VIPERBSS     (0x40) // used only when loading viper from .mpy\n\n// types for native (viper) function signature\n#define MP_NATIVE_TYPE_OBJ  (0x00)\n#define MP_NATIVE_TYPE_BOOL (0x01)\n#define MP_NATIVE_TYPE_INT  (0x02)\n#define MP_NATIVE_TYPE_UINT (0x03)\n#define MP_NATIVE_TYPE_PTR  (0x04)\n#define MP_NATIVE_TYPE_PTR8 (0x05)\n#define MP_NATIVE_TYPE_PTR16 (0x06)\n#define MP_NATIVE_TYPE_PTR32 (0x07)\n\n// Bytecode and runtime boundaries for unary ops\n#define MP_UNARY_OP_NUM_BYTECODE    (MP_UNARY_OP_NOT + 1)\n#define MP_UNARY_OP_NUM_RUNTIME     (MP_UNARY_OP_SIZEOF + 1)\n\n// Bytecode and runtime boundaries for binary ops\n#define MP_BINARY_OP_NUM_BYTECODE   (MP_BINARY_OP_POWER + 1)\n#if MICROPY_PY_REVERSE_SPECIAL_METHODS\n#define MP_BINARY_OP_NUM_RUNTIME    (MP_BINARY_OP_REVERSE_POWER + 1)\n#else\n#define MP_BINARY_OP_NUM_RUNTIME    (MP_BINARY_OP_CONTAINS + 1)\n#endif\n\ntypedef enum {\n    // These ops may appear in the bytecode. Changing this group\n    // in any way requires changing the bytecode version.\n    MP_UNARY_OP_POSITIVE,\n    MP_UNARY_OP_NEGATIVE,\n    MP_UNARY_OP_INVERT,\n    MP_UNARY_OP_NOT,\n\n    // Following ops cannot appear in the bytecode\n    MP_UNARY_OP_BOOL, // __bool__\n    MP_UNARY_OP_LEN, // __len__\n    MP_UNARY_OP_HASH, // __hash__; must return a small int\n    MP_UNARY_OP_ABS, // __abs__\n    MP_UNARY_OP_INT, // __int__\n    MP_UNARY_OP_SIZEOF, // for sys.getsizeof()\n} mp_unary_op_t;\n\ntypedef enum {\n    // The following 9+13+13 ops are used in bytecode and changing\n    // them requires changing the bytecode version.\n\n    // 9 relational operations, should return a bool; order of first 6 matches corresponding mp_token_kind_t\n    MP_BINARY_OP_LESS,\n    MP_BINARY_OP_MORE,\n    MP_BINARY_OP_EQUAL,\n    MP_BINARY_OP_LESS_EQUAL,\n    MP_BINARY_OP_MORE_EQUAL,\n    MP_BINARY_OP_NOT_EQUAL,\n    MP_BINARY_OP_IN,\n    MP_BINARY_OP_IS,\n    MP_BINARY_OP_EXCEPTION_MATCH,\n\n    // 13 inplace arithmetic operations; order matches corresponding mp_token_kind_t\n    MP_BINARY_OP_INPLACE_OR,\n    MP_BINARY_OP_INPLACE_XOR,\n    MP_BINARY_OP_INPLACE_AND,\n    MP_BINARY_OP_INPLACE_LSHIFT,\n    MP_BINARY_OP_INPLACE_RSHIFT,\n    MP_BINARY_OP_INPLACE_ADD,\n    MP_BINARY_OP_INPLACE_SUBTRACT,\n    MP_BINARY_OP_INPLACE_MULTIPLY,\n    MP_BINARY_OP_INPLACE_MAT_MULTIPLY,\n    MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,\n    MP_BINARY_OP_INPLACE_TRUE_DIVIDE,\n    MP_BINARY_OP_INPLACE_MODULO,\n    MP_BINARY_OP_INPLACE_POWER,\n\n    // 13 normal arithmetic operations; order matches corresponding mp_token_kind_t\n    MP_BINARY_OP_OR,\n    MP_BINARY_OP_XOR,\n    MP_BINARY_OP_AND,\n    MP_BINARY_OP_LSHIFT,\n    MP_BINARY_OP_RSHIFT,\n    MP_BINARY_OP_ADD,\n    MP_BINARY_OP_SUBTRACT,\n    MP_BINARY_OP_MULTIPLY,\n    MP_BINARY_OP_MAT_MULTIPLY,\n    MP_BINARY_OP_FLOOR_DIVIDE,\n    MP_BINARY_OP_TRUE_DIVIDE,\n    MP_BINARY_OP_MODULO,\n    MP_BINARY_OP_POWER,\n\n    // Operations below this line don't appear in bytecode, they\n    // just identify special methods.\n\n    // This is not emitted by the compiler but is supported by the runtime.\n    // It must follow immediately after MP_BINARY_OP_POWER.\n    MP_BINARY_OP_DIVMOD,\n\n    // The runtime will convert MP_BINARY_OP_IN to this operator with swapped args.\n    // A type should implement this containment operator instead of MP_BINARY_OP_IN.\n    MP_BINARY_OP_CONTAINS,\n\n    // 13 MP_BINARY_OP_REVERSE_* operations must be in the same order as MP_BINARY_OP_*,\n    // and be the last ones supported by the runtime.\n    MP_BINARY_OP_REVERSE_OR,\n    MP_BINARY_OP_REVERSE_XOR,\n    MP_BINARY_OP_REVERSE_AND,\n    MP_BINARY_OP_REVERSE_LSHIFT,\n    MP_BINARY_OP_REVERSE_RSHIFT,\n    MP_BINARY_OP_REVERSE_ADD,\n    MP_BINARY_OP_REVERSE_SUBTRACT,\n    MP_BINARY_OP_REVERSE_MULTIPLY,\n    MP_BINARY_OP_REVERSE_MAT_MULTIPLY,\n    MP_BINARY_OP_REVERSE_FLOOR_DIVIDE,\n    MP_BINARY_OP_REVERSE_TRUE_DIVIDE,\n    MP_BINARY_OP_REVERSE_MODULO,\n    MP_BINARY_OP_REVERSE_POWER,\n\n    // These 2 are not supported by the runtime and must be synthesised by the emitter\n    MP_BINARY_OP_NOT_IN,\n    MP_BINARY_OP_IS_NOT,\n} mp_binary_op_t;\n\n#endif // MICROPY_INCLUDED_PY_RUNTIME0_H\n"
  },
  {
    "path": "py/runtime_utils.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 Josef Gajdusek\n * Copyright (c) 2015 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/runtime.h\"\n\nmp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) {\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        mp_obj_t ret = mp_call_function_1(fun, arg);\n        nlr_pop();\n        return ret;\n    } else {\n        mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));\n        return MP_OBJ_NULL;\n    }\n}\n\nmp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) {\n    nlr_buf_t nlr;\n    if (nlr_push(&nlr) == 0) {\n        mp_obj_t ret = mp_call_function_2(fun, arg1, arg2);\n        nlr_pop();\n        return ret;\n    } else {\n        mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));\n        return MP_OBJ_NULL;\n    }\n}\n"
  },
  {
    "path": "py/scheduler.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2017 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n\n#include \"py/runtime.h\"\n\n#if MICROPY_KBD_EXCEPTION\n// This function may be called asynchronously at any time so only do the bare minimum.\nvoid MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(mp_keyboard_interrupt)(void) {\n    MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;\n    MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));\n    #if MICROPY_ENABLE_SCHEDULER\n    if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {\n        MP_STATE_VM(sched_state) = MP_SCHED_PENDING;\n    }\n    #endif\n}\n#endif\n\n#if MICROPY_ENABLE_SCHEDULER\n\n#define IDX_MASK(i) ((i) & (MICROPY_SCHEDULER_DEPTH - 1))\n\n// This is a macro so it is guaranteed to be inlined in functions like\n// mp_sched_schedule that may be located in a special memory region.\n#define mp_sched_full() (mp_sched_num_pending() == MICROPY_SCHEDULER_DEPTH)\n\nstatic inline bool mp_sched_empty(void) {\n    MP_STATIC_ASSERT(MICROPY_SCHEDULER_DEPTH <= 255); // MICROPY_SCHEDULER_DEPTH must fit in 8 bits\n    MP_STATIC_ASSERT((IDX_MASK(MICROPY_SCHEDULER_DEPTH) == 0)); // MICROPY_SCHEDULER_DEPTH must be a power of 2\n\n    return mp_sched_num_pending() == 0;\n}\n\n// A variant of this is inlined in the VM at the pending exception check\nvoid mp_handle_pending(bool raise_exc) {\n    if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) {\n        mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();\n        // Re-check state is still pending now that we're in the atomic section.\n        if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) {\n            mp_obj_t obj = MP_STATE_VM(mp_pending_exception);\n            if (obj != MP_OBJ_NULL) {\n                MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;\n                if (!mp_sched_num_pending()) {\n                    MP_STATE_VM(sched_state) = MP_SCHED_IDLE;\n                }\n                if (raise_exc) {\n                    MICROPY_END_ATOMIC_SECTION(atomic_state);\n                    nlr_raise(obj);\n                }\n            }\n            mp_handle_pending_tail(atomic_state);\n        } else {\n            MICROPY_END_ATOMIC_SECTION(atomic_state);\n        }\n    }\n}\n\n// This function should only be called by mp_handle_pending,\n// or by the VM's inlined version of that function.\nvoid mp_handle_pending_tail(mp_uint_t atomic_state) {\n    MP_STATE_VM(sched_state) = MP_SCHED_LOCKED;\n    if (!mp_sched_empty()) {\n        mp_sched_item_t item = MP_STATE_VM(sched_queue)[MP_STATE_VM(sched_idx)];\n        MP_STATE_VM(sched_idx) = IDX_MASK(MP_STATE_VM(sched_idx) + 1);\n        --MP_STATE_VM(sched_len);\n        MICROPY_END_ATOMIC_SECTION(atomic_state);\n        mp_call_function_1_protected(item.func, item.arg);\n    } else {\n        MICROPY_END_ATOMIC_SECTION(atomic_state);\n    }\n    mp_sched_unlock();\n}\n\nvoid mp_sched_lock(void) {\n    mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();\n    if (MP_STATE_VM(sched_state) < 0) {\n        --MP_STATE_VM(sched_state);\n    } else {\n        MP_STATE_VM(sched_state) = MP_SCHED_LOCKED;\n    }\n    MICROPY_END_ATOMIC_SECTION(atomic_state);\n}\n\nvoid mp_sched_unlock(void) {\n    mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();\n    assert(MP_STATE_VM(sched_state) < 0);\n    if (++MP_STATE_VM(sched_state) == 0) {\n        // vm became unlocked\n        if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL || mp_sched_num_pending()) {\n            MP_STATE_VM(sched_state) = MP_SCHED_PENDING;\n        } else {\n            MP_STATE_VM(sched_state) = MP_SCHED_IDLE;\n        }\n    }\n    MICROPY_END_ATOMIC_SECTION(atomic_state);\n}\n\nbool MICROPY_WRAP_MP_SCHED_SCHEDULE(mp_sched_schedule)(mp_obj_t function, mp_obj_t arg) {\n    mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();\n    bool ret;\n    if (!mp_sched_full()) {\n        if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {\n            MP_STATE_VM(sched_state) = MP_SCHED_PENDING;\n        }\n        uint8_t iput = IDX_MASK(MP_STATE_VM(sched_idx) + MP_STATE_VM(sched_len)++);\n        MP_STATE_VM(sched_queue)[iput].func = function;\n        MP_STATE_VM(sched_queue)[iput].arg = arg;\n        ret = true;\n    } else {\n        // schedule queue is full\n        ret = false;\n    }\n    MICROPY_END_ATOMIC_SECTION(atomic_state);\n    return ret;\n}\n\n#else // MICROPY_ENABLE_SCHEDULER\n\n// A variant of this is inlined in the VM at the pending exception check\nvoid mp_handle_pending(bool raise_exc) {\n    if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {\n        mp_obj_t obj = MP_STATE_VM(mp_pending_exception);\n        MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;\n        if (raise_exc) {\n            nlr_raise(obj);\n        }\n    }\n}\n\n#endif // MICROPY_ENABLE_SCHEDULER\n"
  },
  {
    "path": "py/scope.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <assert.h>\n\n#include \"py/scope.h\"\n\n#if MICROPY_ENABLE_COMPILER\n\n// These low numbered qstrs should fit in 8 bits.  See assertions below.\nSTATIC const uint8_t scope_simple_name_table[] = {\n    [SCOPE_MODULE] = MP_QSTR__lt_module_gt_,\n    [SCOPE_LAMBDA] = MP_QSTR__lt_lambda_gt_,\n    [SCOPE_LIST_COMP] = MP_QSTR__lt_listcomp_gt_,\n    [SCOPE_DICT_COMP] = MP_QSTR__lt_dictcomp_gt_,\n    [SCOPE_SET_COMP] = MP_QSTR__lt_setcomp_gt_,\n    [SCOPE_GEN_EXPR] = MP_QSTR__lt_genexpr_gt_,\n};\n\nscope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options) {\n    // Make sure those qstrs indeed fit in an uint8_t.\n    MP_STATIC_ASSERT(MP_QSTR__lt_module_gt_ <= UINT8_MAX);\n    MP_STATIC_ASSERT(MP_QSTR__lt_lambda_gt_ <= UINT8_MAX);\n    MP_STATIC_ASSERT(MP_QSTR__lt_listcomp_gt_ <= UINT8_MAX);\n    MP_STATIC_ASSERT(MP_QSTR__lt_dictcomp_gt_ <= UINT8_MAX);\n    MP_STATIC_ASSERT(MP_QSTR__lt_setcomp_gt_ <= UINT8_MAX);\n    MP_STATIC_ASSERT(MP_QSTR__lt_genexpr_gt_ <= UINT8_MAX);\n\n    scope_t *scope = m_new0(scope_t, 1);\n    scope->kind = kind;\n    scope->pn = pn;\n    scope->source_file = source_file;\n    if (kind == SCOPE_FUNCTION || kind == SCOPE_CLASS) {\n        assert(MP_PARSE_NODE_IS_STRUCT(pn));\n        scope->simple_name = MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t *)pn)->nodes[0]);\n    } else {\n        scope->simple_name = scope_simple_name_table[kind];\n    }\n    scope->raw_code = mp_emit_glue_new_raw_code();\n    scope->emit_options = emit_options;\n    scope->id_info_alloc = MICROPY_ALLOC_SCOPE_ID_INIT;\n    scope->id_info = m_new(id_info_t, scope->id_info_alloc);\n\n    return scope;\n}\n\nvoid scope_free(scope_t *scope) {\n    m_del(id_info_t, scope->id_info, scope->id_info_alloc);\n    m_del(scope_t, scope, 1);\n}\n\nid_info_t *scope_find_or_add_id(scope_t *scope, qstr qst, id_info_kind_t kind) {\n    id_info_t *id_info = scope_find(scope, qst);\n    if (id_info != NULL) {\n        return id_info;\n    }\n\n    // make sure we have enough memory\n    if (scope->id_info_len >= scope->id_info_alloc) {\n        scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc + MICROPY_ALLOC_SCOPE_ID_INC);\n        scope->id_info_alloc += MICROPY_ALLOC_SCOPE_ID_INC;\n    }\n\n    // add new id to end of array of all ids; this seems to match CPython\n    // important thing is that function arguments are first, but that is\n    // handled by the compiler because it adds arguments before compiling the body\n    id_info = &scope->id_info[scope->id_info_len++];\n\n    id_info->kind = kind;\n    id_info->flags = 0;\n    id_info->local_num = 0;\n    id_info->qst = qst;\n    return id_info;\n}\n\nid_info_t *scope_find(scope_t *scope, qstr qst) {\n    for (mp_uint_t i = 0; i < scope->id_info_len; i++) {\n        if (scope->id_info[i].qst == qst) {\n            return &scope->id_info[i];\n        }\n    }\n    return NULL;\n}\n\nid_info_t *scope_find_global(scope_t *scope, qstr qst) {\n    while (scope->parent != NULL) {\n        scope = scope->parent;\n    }\n    return scope_find(scope, qst);\n}\n\nSTATIC void scope_close_over_in_parents(scope_t *scope, qstr qst) {\n    assert(scope->parent != NULL); // we should have at least 1 parent\n    for (scope_t *s = scope->parent;; s = s->parent) {\n        assert(s->parent != NULL); // we should not get to the outer scope\n        id_info_t *id = scope_find_or_add_id(s, qst, ID_INFO_KIND_UNDECIDED);\n        if (id->kind == ID_INFO_KIND_UNDECIDED) {\n            // variable not previously declared in this scope, so declare it as free and keep searching parents\n            id->kind = ID_INFO_KIND_FREE;\n        } else {\n            // variable is declared in this scope, so finish\n            if (id->kind == ID_INFO_KIND_LOCAL) {\n                // variable local to this scope, close it over\n                id->kind = ID_INFO_KIND_CELL;\n            } else {\n                // ID_INFO_KIND_FREE: variable already closed over in a parent scope\n                // ID_INFO_KIND_CELL: variable already closed over in this scope\n                assert(id->kind == ID_INFO_KIND_FREE || id->kind == ID_INFO_KIND_CELL);\n            }\n            return;\n        }\n    }\n}\n\nvoid scope_check_to_close_over(scope_t *scope, id_info_t *id) {\n    if (scope->parent != NULL) {\n        for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {\n            id_info_t *id2 = scope_find(s, id->qst);\n            if (id2 != NULL) {\n                if (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE) {\n                    id->kind = ID_INFO_KIND_FREE;\n                    scope_close_over_in_parents(scope, id->qst);\n                }\n                break;\n            }\n        }\n    }\n}\n\n#endif // MICROPY_ENABLE_COMPILER\n"
  },
  {
    "path": "py/scope.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_SCOPE_H\n#define MICROPY_INCLUDED_PY_SCOPE_H\n\n#include \"py/parse.h\"\n#include \"py/emitglue.h\"\n\ntypedef enum {\n    ID_INFO_KIND_UNDECIDED,\n    ID_INFO_KIND_GLOBAL_IMPLICIT,\n    ID_INFO_KIND_GLOBAL_EXPLICIT,\n    ID_INFO_KIND_LOCAL, // in a function f, written and only referenced by f\n    ID_INFO_KIND_CELL,  // in a function f, read/written by children of f\n    ID_INFO_KIND_FREE,  // in a function f, belongs to the parent of f\n} id_info_kind_t;\n\nenum {\n    ID_FLAG_IS_PARAM = 0x01,\n    ID_FLAG_IS_STAR_PARAM = 0x02,\n    ID_FLAG_IS_DBL_STAR_PARAM = 0x04,\n    ID_FLAG_VIPER_TYPE_POS = 4,\n};\n\ntypedef struct _id_info_t {\n    uint8_t kind;\n    uint8_t flags;\n    // when it's an ID_INFO_KIND_LOCAL this is the unique number of the local\n    // whet it's an ID_INFO_KIND_CELL/FREE this is the unique number of the closed over variable\n    uint16_t local_num;\n    qstr qst;\n} id_info_t;\n\n#define SCOPE_IS_FUNC_LIKE(s) ((s) >= SCOPE_LAMBDA)\n#define SCOPE_IS_COMP_LIKE(s) (SCOPE_LIST_COMP <= (s) && (s) <= SCOPE_GEN_EXPR)\n\n// scope is a \"block\" in Python parlance\ntypedef enum {\n    SCOPE_MODULE,\n    SCOPE_CLASS,\n    SCOPE_LAMBDA,\n    SCOPE_LIST_COMP,\n    SCOPE_DICT_COMP,\n    SCOPE_SET_COMP,\n    SCOPE_GEN_EXPR,\n    SCOPE_FUNCTION,\n} scope_kind_t;\n\ntypedef struct _scope_t {\n    scope_kind_t kind;\n    struct _scope_t *parent;\n    struct _scope_t *next;\n    mp_parse_node_t pn;\n    mp_raw_code_t *raw_code;\n    uint16_t source_file; // a qstr\n    uint16_t simple_name; // a qstr\n    uint16_t scope_flags;  // see runtime0.h\n    uint16_t emit_options; // see emitglue.h\n    uint16_t num_pos_args;\n    uint16_t num_kwonly_args;\n    uint16_t num_def_pos_args;\n    uint16_t num_locals;\n    uint16_t stack_size;     // maximum size of the locals stack\n    uint16_t exc_stack_size; // maximum size of the exception stack\n    uint16_t id_info_alloc;\n    uint16_t id_info_len;\n    id_info_t *id_info;\n} scope_t;\n\nscope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options);\nvoid scope_free(scope_t *scope);\nid_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, id_info_kind_t kind);\nid_info_t *scope_find(scope_t *scope, qstr qstr);\nid_info_t *scope_find_global(scope_t *scope, qstr qstr);\nvoid scope_check_to_close_over(scope_t *scope, id_info_t *id);\n\n#endif // MICROPY_INCLUDED_PY_SCOPE_H\n"
  },
  {
    "path": "py/sequence.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n\n#include \"py/runtime.h\"\n\n// Helpers for sequence types\n\n#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; }\n\n// Implements backend of sequence * integer operation. Assumes elements are\n// memory-adjacent in sequence.\nvoid mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest) {\n    for (size_t i = 0; i < times; i++) {\n        size_t copy_sz = item_sz * len;\n        memcpy(dest, items, copy_sz);\n        dest = (char *)dest + copy_sz;\n    }\n}\n\n#if MICROPY_PY_BUILTINS_SLICE\n\nbool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes) {\n    mp_obj_slice_indices(slice, len, indexes);\n\n    // If the index is negative then stop points to the last item, not after it\n    if (indexes->step < 0) {\n        indexes->stop++;\n    }\n\n    // CPython returns empty sequence in such case, or point for assignment is at start\n    if (indexes->step > 0 && indexes->start > indexes->stop) {\n        indexes->stop = indexes->start;\n    } else if (indexes->step < 0 && indexes->start < indexes->stop) {\n        indexes->stop = indexes->start + 1;\n    }\n\n    return indexes->step == 1;\n}\n\n#endif\n\nmp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes) {\n    (void)len; // TODO can we remove len from the arg list?\n\n    mp_int_t start = indexes->start, stop = indexes->stop;\n    mp_int_t step = indexes->step;\n\n    mp_obj_t res = mp_obj_new_list(0, NULL);\n\n    if (step < 0) {\n        while (start >= stop) {\n            mp_obj_list_append(res, seq[start]);\n            start += step;\n        }\n    } else {\n        while (start < stop) {\n            mp_obj_list_append(res, seq[start]);\n            start += step;\n        }\n    }\n    return res;\n}\n\n// Special-case comparison function for sequences of bytes\n// Don't pass MP_BINARY_OP_NOT_EQUAL here\nbool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte *data2, size_t len2) {\n    if (op == MP_BINARY_OP_EQUAL && len1 != len2) {\n        return false;\n    }\n\n    // Let's deal only with > & >=\n    if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {\n        SWAP(const byte *, data1, data2);\n        SWAP(size_t, len1, len2);\n        if (op == MP_BINARY_OP_LESS) {\n            op = MP_BINARY_OP_MORE;\n        } else {\n            op = MP_BINARY_OP_MORE_EQUAL;\n        }\n    }\n    size_t min_len = len1 < len2 ? len1 : len2;\n    int res = memcmp(data1, data2, min_len);\n    if (op == MP_BINARY_OP_EQUAL) {\n        // If we are checking for equality, here's the answer\n        return res == 0;\n    }\n    if (res < 0) {\n        return false;\n    }\n    if (res > 0) {\n        return true;\n    }\n\n    // If we had tie in the last element...\n    // ... and we have lists of different lengths...\n    if (len1 != len2) {\n        if (len1 < len2) {\n            // ... then longer list length wins (we deal only with >)\n            return false;\n        }\n    } else if (op == MP_BINARY_OP_MORE) {\n        // Otherwise, if we have strict relation, equality means failure\n        return false;\n    }\n    return true;\n}\n\n// Special-case comparison function for sequences of mp_obj_t\n// Don't pass MP_BINARY_OP_NOT_EQUAL here\nbool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp_obj_t *items2, size_t len2) {\n    if (op == MP_BINARY_OP_EQUAL && len1 != len2) {\n        return false;\n    }\n\n    // Let's deal only with > & >=\n    if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {\n        SWAP(const mp_obj_t *, items1, items2);\n        SWAP(size_t, len1, len2);\n        if (op == MP_BINARY_OP_LESS) {\n            op = MP_BINARY_OP_MORE;\n        } else {\n            op = MP_BINARY_OP_MORE_EQUAL;\n        }\n    }\n\n    size_t len = len1 < len2 ? len1 : len2;\n    for (size_t i = 0; i < len; i++) {\n        // If current elements equal, can't decide anything - go on\n        if (mp_obj_equal(items1[i], items2[i])) {\n            continue;\n        }\n\n        // Othewise, if they are not equal, we can have final decision based on them\n        if (op == MP_BINARY_OP_EQUAL) {\n            // In particular, if we are checking for equality, here're the answer\n            return false;\n        }\n\n        // Otherwise, application of relation op gives the answer\n        return mp_binary_op(op, items1[i], items2[i]) == mp_const_true;\n    }\n\n    // If we had tie in the last element...\n    // ... and we have lists of different lengths...\n    if (len1 != len2) {\n        if (len1 < len2) {\n            // ... then longer list length wins (we deal only with >)\n            return false;\n        }\n    } else if (op == MP_BINARY_OP_MORE) {\n        // Otherwise, if we have strict relation, sequence equality means failure\n        return false;\n    }\n\n    return true;\n}\n\n// Special-case of index() which searches for mp_obj_t\nmp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args) {\n    const mp_obj_type_t *type = mp_obj_get_type(args[0]);\n    mp_obj_t value = args[1];\n    size_t start = 0;\n    size_t stop = len;\n\n    if (n_args >= 3) {\n        start = mp_get_index(type, len, args[2], true);\n        if (n_args >= 4) {\n            stop = mp_get_index(type, len, args[3], true);\n        }\n    }\n\n    for (size_t i = start; i < stop; i++) {\n        if (mp_obj_equal(items[i], value)) {\n            // Common sense says this cannot overflow small int\n            return MP_OBJ_NEW_SMALL_INT(i);\n        }\n    }\n\n    mp_raise_ValueError(MP_ERROR_TEXT(\"object not in sequence\"));\n}\n\nmp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value) {\n    size_t count = 0;\n    for (size_t i = 0; i < len; i++) {\n        if (mp_obj_equal(items[i], value)) {\n            count++;\n        }\n    }\n\n    // Common sense says this cannot overflow small int\n    return MP_OBJ_NEW_SMALL_INT(count);\n}\n"
  },
  {
    "path": "py/showbc.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <assert.h>\n\n#include \"py/bc0.h\"\n#include \"py/bc.h\"\n\n#if MICROPY_DEBUG_PRINTERS\n\n#define DECODE_UINT { \\\n        unum = 0; \\\n        do { \\\n            unum = (unum << 7) + (*ip & 0x7f); \\\n        } while ((*ip++ & 0x80) != 0); \\\n}\n#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0)\n#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0)\n\n#if MICROPY_PERSISTENT_CODE\n\n#define DECODE_QSTR \\\n    qst = ip[0] | ip[1] << 8; \\\n    ip += 2;\n#define DECODE_PTR \\\n    DECODE_UINT; \\\n    unum = mp_showbc_const_table[unum]\n#define DECODE_OBJ \\\n    DECODE_UINT; \\\n    unum = mp_showbc_const_table[unum]\n\n#else\n\n#define DECODE_QSTR { \\\n        qst = 0; \\\n        do { \\\n            qst = (qst << 7) + (*ip & 0x7f); \\\n        } while ((*ip++ & 0x80) != 0); \\\n}\n#define DECODE_PTR do { \\\n        ip = (byte *)MP_ALIGN(ip, sizeof(void *)); \\\n        unum = (uintptr_t)*(void **)ip; \\\n        ip += sizeof(void *); \\\n} while (0)\n#define DECODE_OBJ do { \\\n        ip = (byte *)MP_ALIGN(ip, sizeof(mp_obj_t)); \\\n        unum = (mp_uint_t)*(mp_obj_t *)ip; \\\n        ip += sizeof(mp_obj_t); \\\n} while (0)\n\n#endif\n\nconst byte *mp_showbc_code_start;\nconst mp_uint_t *mp_showbc_const_table;\n\nvoid mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *ip, mp_uint_t len, const mp_uint_t *const_table) {\n    mp_showbc_code_start = ip;\n\n    // Decode prelude\n    MP_BC_PRELUDE_SIG_DECODE(ip);\n    MP_BC_PRELUDE_SIZE_DECODE(ip);\n    const byte *code_info = ip;\n\n    #if MICROPY_PERSISTENT_CODE\n    qstr block_name = code_info[0] | (code_info[1] << 8);\n    qstr source_file = code_info[2] | (code_info[3] << 8);\n    code_info += 4;\n    #else\n    qstr block_name = mp_decode_uint(&code_info);\n    qstr source_file = mp_decode_uint(&code_info);\n    #endif\n    mp_printf(print, \"File %s, code block '%s' (descriptor: %p, bytecode @%p \" UINT_FMT \" bytes)\\n\",\n        qstr_str(source_file), qstr_str(block_name), descr, mp_showbc_code_start, len);\n\n    // raw bytecode dump\n    size_t prelude_size = ip - mp_showbc_code_start + n_info + n_cell;\n    mp_printf(print, \"Raw bytecode (code_info_size=\" UINT_FMT \", bytecode_size=\" UINT_FMT \"):\\n\",\n        prelude_size, len - prelude_size);\n    for (mp_uint_t i = 0; i < len; i++) {\n        if (i > 0 && i % 16 == 0) {\n            mp_printf(print, \"\\n\");\n        }\n        mp_printf(print, \" %02x\", mp_showbc_code_start[i]);\n    }\n    mp_printf(print, \"\\n\");\n\n    // bytecode prelude: arg names (as qstr objects)\n    mp_printf(print, \"arg names:\");\n    for (mp_uint_t i = 0; i < n_pos_args + n_kwonly_args; i++) {\n        mp_printf(print, \" %s\", qstr_str(MP_OBJ_QSTR_VALUE(const_table[i])));\n    }\n    mp_printf(print, \"\\n\");\n\n    mp_printf(print, \"(N_STATE %u)\\n\", (unsigned)n_state);\n    mp_printf(print, \"(N_EXC_STACK %u)\\n\", (unsigned)n_exc_stack);\n\n    // skip over code_info\n    ip += n_info;\n\n    // bytecode prelude: initialise closed over variables\n    for (size_t i = 0; i < n_cell; ++i) {\n        uint local_num = *ip++;\n        mp_printf(print, \"(INIT_CELL %u)\\n\", local_num);\n    }\n\n    // print out line number info\n    {\n        mp_int_t bc = 0;\n        mp_uint_t source_line = 1;\n        mp_printf(print, \"  bc=\" INT_FMT \" line=\" UINT_FMT \"\\n\", bc, source_line);\n        for (const byte *ci = code_info; *ci;) {\n            if ((ci[0] & 0x80) == 0) {\n                // 0b0LLBBBBB encoding\n                bc += ci[0] & 0x1f;\n                source_line += ci[0] >> 5;\n                ci += 1;\n            } else {\n                // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte)\n                bc += ci[0] & 0xf;\n                source_line += ((ci[0] << 4) & 0x700) | ci[1];\n                ci += 2;\n            }\n            mp_printf(print, \"  bc=\" INT_FMT \" line=\" UINT_FMT \"\\n\", bc, source_line);\n        }\n    }\n    mp_bytecode_print2(print, ip, len - prelude_size, const_table);\n}\n\nconst byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {\n    mp_uint_t unum;\n    qstr qst;\n\n    switch (*ip++) {\n        case MP_BC_LOAD_CONST_FALSE:\n            mp_printf(print, \"LOAD_CONST_FALSE\");\n            break;\n\n        case MP_BC_LOAD_CONST_NONE:\n            mp_printf(print, \"LOAD_CONST_NONE\");\n            break;\n\n        case MP_BC_LOAD_CONST_TRUE:\n            mp_printf(print, \"LOAD_CONST_TRUE\");\n            break;\n\n        case MP_BC_LOAD_CONST_SMALL_INT: {\n            mp_int_t num = 0;\n            if ((ip[0] & 0x40) != 0) {\n                // Number is negative\n                num--;\n            }\n            do {\n                num = (num << 7) | (*ip & 0x7f);\n            } while ((*ip++ & 0x80) != 0);\n            mp_printf(print, \"LOAD_CONST_SMALL_INT \" INT_FMT, num);\n            break;\n        }\n\n        case MP_BC_LOAD_CONST_STRING:\n            DECODE_QSTR;\n            mp_printf(print, \"LOAD_CONST_STRING '%s'\", qstr_str(qst));\n            break;\n\n        case MP_BC_LOAD_CONST_OBJ:\n            DECODE_OBJ;\n            mp_printf(print, \"LOAD_CONST_OBJ %p=\", MP_OBJ_TO_PTR(unum));\n            mp_obj_print_helper(print, (mp_obj_t)unum, PRINT_REPR);\n            break;\n\n        case MP_BC_LOAD_NULL:\n            mp_printf(print, \"LOAD_NULL\");\n            break;\n\n        case MP_BC_LOAD_FAST_N:\n            DECODE_UINT;\n            mp_printf(print, \"LOAD_FAST_N \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_LOAD_DEREF:\n            DECODE_UINT;\n            mp_printf(print, \"LOAD_DEREF \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_LOAD_NAME:\n            DECODE_QSTR;\n            mp_printf(print, \"LOAD_NAME %s\", qstr_str(qst));\n            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {\n                mp_printf(print, \" (cache=%u)\", *ip++);\n            }\n            break;\n\n        case MP_BC_LOAD_GLOBAL:\n            DECODE_QSTR;\n            mp_printf(print, \"LOAD_GLOBAL %s\", qstr_str(qst));\n            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {\n                mp_printf(print, \" (cache=%u)\", *ip++);\n            }\n            break;\n\n        case MP_BC_LOAD_ATTR:\n            DECODE_QSTR;\n            mp_printf(print, \"LOAD_ATTR %s\", qstr_str(qst));\n            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {\n                mp_printf(print, \" (cache=%u)\", *ip++);\n            }\n            break;\n\n        case MP_BC_LOAD_METHOD:\n            DECODE_QSTR;\n            mp_printf(print, \"LOAD_METHOD %s\", qstr_str(qst));\n            break;\n\n        case MP_BC_LOAD_SUPER_METHOD:\n            DECODE_QSTR;\n            mp_printf(print, \"LOAD_SUPER_METHOD %s\", qstr_str(qst));\n            break;\n\n        case MP_BC_LOAD_BUILD_CLASS:\n            mp_printf(print, \"LOAD_BUILD_CLASS\");\n            break;\n\n        case MP_BC_LOAD_SUBSCR:\n            mp_printf(print, \"LOAD_SUBSCR\");\n            break;\n\n        case MP_BC_STORE_FAST_N:\n            DECODE_UINT;\n            mp_printf(print, \"STORE_FAST_N \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_STORE_DEREF:\n            DECODE_UINT;\n            mp_printf(print, \"STORE_DEREF \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_STORE_NAME:\n            DECODE_QSTR;\n            mp_printf(print, \"STORE_NAME %s\", qstr_str(qst));\n            break;\n\n        case MP_BC_STORE_GLOBAL:\n            DECODE_QSTR;\n            mp_printf(print, \"STORE_GLOBAL %s\", qstr_str(qst));\n            break;\n\n        case MP_BC_STORE_ATTR:\n            DECODE_QSTR;\n            mp_printf(print, \"STORE_ATTR %s\", qstr_str(qst));\n            if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {\n                mp_printf(print, \" (cache=%u)\", *ip++);\n            }\n            break;\n\n        case MP_BC_STORE_SUBSCR:\n            mp_printf(print, \"STORE_SUBSCR\");\n            break;\n\n        case MP_BC_DELETE_FAST:\n            DECODE_UINT;\n            mp_printf(print, \"DELETE_FAST \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_DELETE_DEREF:\n            DECODE_UINT;\n            mp_printf(print, \"DELETE_DEREF \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_DELETE_NAME:\n            DECODE_QSTR;\n            mp_printf(print, \"DELETE_NAME %s\", qstr_str(qst));\n            break;\n\n        case MP_BC_DELETE_GLOBAL:\n            DECODE_QSTR;\n            mp_printf(print, \"DELETE_GLOBAL %s\", qstr_str(qst));\n            break;\n\n        case MP_BC_DUP_TOP:\n            mp_printf(print, \"DUP_TOP\");\n            break;\n\n        case MP_BC_DUP_TOP_TWO:\n            mp_printf(print, \"DUP_TOP_TWO\");\n            break;\n\n        case MP_BC_POP_TOP:\n            mp_printf(print, \"POP_TOP\");\n            break;\n\n        case MP_BC_ROT_TWO:\n            mp_printf(print, \"ROT_TWO\");\n            break;\n\n        case MP_BC_ROT_THREE:\n            mp_printf(print, \"ROT_THREE\");\n            break;\n\n        case MP_BC_JUMP:\n            DECODE_SLABEL;\n            mp_printf(print, \"JUMP \" UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));\n            break;\n\n        case MP_BC_POP_JUMP_IF_TRUE:\n            DECODE_SLABEL;\n            mp_printf(print, \"POP_JUMP_IF_TRUE \" UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));\n            break;\n\n        case MP_BC_POP_JUMP_IF_FALSE:\n            DECODE_SLABEL;\n            mp_printf(print, \"POP_JUMP_IF_FALSE \" UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));\n            break;\n\n        case MP_BC_JUMP_IF_TRUE_OR_POP:\n            DECODE_SLABEL;\n            mp_printf(print, \"JUMP_IF_TRUE_OR_POP \" UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));\n            break;\n\n        case MP_BC_JUMP_IF_FALSE_OR_POP:\n            DECODE_SLABEL;\n            mp_printf(print, \"JUMP_IF_FALSE_OR_POP \" UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));\n            break;\n\n        case MP_BC_SETUP_WITH:\n            DECODE_ULABEL; // loop-like labels are always forward\n            mp_printf(print, \"SETUP_WITH \" UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));\n            break;\n\n        case MP_BC_WITH_CLEANUP:\n            mp_printf(print, \"WITH_CLEANUP\");\n            break;\n\n        case MP_BC_UNWIND_JUMP:\n            DECODE_SLABEL;\n            mp_printf(print, \"UNWIND_JUMP \" UINT_FMT \" %d\", (mp_uint_t)(ip + unum - mp_showbc_code_start), *ip);\n            ip += 1;\n            break;\n\n        case MP_BC_SETUP_EXCEPT:\n            DECODE_ULABEL; // except labels are always forward\n            mp_printf(print, \"SETUP_EXCEPT \" UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));\n            break;\n\n        case MP_BC_SETUP_FINALLY:\n            DECODE_ULABEL; // except labels are always forward\n            mp_printf(print, \"SETUP_FINALLY \" UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));\n            break;\n\n        case MP_BC_END_FINALLY:\n            // if TOS is an exception, reraises the exception (3 values on TOS)\n            // if TOS is an integer, does something else\n            // if TOS is None, just pops it and continues\n            // else error\n            mp_printf(print, \"END_FINALLY\");\n            break;\n\n        case MP_BC_GET_ITER:\n            mp_printf(print, \"GET_ITER\");\n            break;\n\n        case MP_BC_GET_ITER_STACK:\n            mp_printf(print, \"GET_ITER_STACK\");\n            break;\n\n        case MP_BC_FOR_ITER:\n            DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward\n            mp_printf(print, \"FOR_ITER \" UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));\n            break;\n\n        case MP_BC_POP_EXCEPT_JUMP:\n            DECODE_ULABEL; // these labels are always forward\n            mp_printf(print, \"POP_EXCEPT_JUMP \" UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));\n            break;\n\n        case MP_BC_BUILD_TUPLE:\n            DECODE_UINT;\n            mp_printf(print, \"BUILD_TUPLE \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_BUILD_LIST:\n            DECODE_UINT;\n            mp_printf(print, \"BUILD_LIST \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_BUILD_MAP:\n            DECODE_UINT;\n            mp_printf(print, \"BUILD_MAP \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_STORE_MAP:\n            mp_printf(print, \"STORE_MAP\");\n            break;\n\n        case MP_BC_BUILD_SET:\n            DECODE_UINT;\n            mp_printf(print, \"BUILD_SET \" UINT_FMT, unum);\n            break;\n\n        #if MICROPY_PY_BUILTINS_SLICE\n        case MP_BC_BUILD_SLICE:\n            DECODE_UINT;\n            mp_printf(print, \"BUILD_SLICE \" UINT_FMT, unum);\n            break;\n        #endif\n\n        case MP_BC_STORE_COMP:\n            DECODE_UINT;\n            mp_printf(print, \"STORE_COMP \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_UNPACK_SEQUENCE:\n            DECODE_UINT;\n            mp_printf(print, \"UNPACK_SEQUENCE \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_UNPACK_EX:\n            DECODE_UINT;\n            mp_printf(print, \"UNPACK_EX \" UINT_FMT, unum);\n            break;\n\n        case MP_BC_MAKE_FUNCTION:\n            DECODE_PTR;\n            mp_printf(print, \"MAKE_FUNCTION %p\", (void *)(uintptr_t)unum);\n            break;\n\n        case MP_BC_MAKE_FUNCTION_DEFARGS:\n            DECODE_PTR;\n            mp_printf(print, \"MAKE_FUNCTION_DEFARGS %p\", (void *)(uintptr_t)unum);\n            break;\n\n        case MP_BC_MAKE_CLOSURE: {\n            DECODE_PTR;\n            mp_uint_t n_closed_over = *ip++;\n            mp_printf(print, \"MAKE_CLOSURE %p \" UINT_FMT, (void *)(uintptr_t)unum, n_closed_over);\n            break;\n        }\n\n        case MP_BC_MAKE_CLOSURE_DEFARGS: {\n            DECODE_PTR;\n            mp_uint_t n_closed_over = *ip++;\n            mp_printf(print, \"MAKE_CLOSURE_DEFARGS %p \" UINT_FMT, (void *)(uintptr_t)unum, n_closed_over);\n            break;\n        }\n\n        case MP_BC_CALL_FUNCTION:\n            DECODE_UINT;\n            mp_printf(print, \"CALL_FUNCTION n=\" UINT_FMT \" nkw=\" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff);\n            break;\n\n        case MP_BC_CALL_FUNCTION_VAR_KW:\n            DECODE_UINT;\n            mp_printf(print, \"CALL_FUNCTION_VAR_KW n=\" UINT_FMT \" nkw=\" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff);\n            break;\n\n        case MP_BC_CALL_METHOD:\n            DECODE_UINT;\n            mp_printf(print, \"CALL_METHOD n=\" UINT_FMT \" nkw=\" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff);\n            break;\n\n        case MP_BC_CALL_METHOD_VAR_KW:\n            DECODE_UINT;\n            mp_printf(print, \"CALL_METHOD_VAR_KW n=\" UINT_FMT \" nkw=\" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff);\n            break;\n\n        case MP_BC_RETURN_VALUE:\n            mp_printf(print, \"RETURN_VALUE\");\n            break;\n\n        case MP_BC_RAISE_LAST:\n            mp_printf(print, \"RAISE_LAST\");\n            break;\n\n        case MP_BC_RAISE_OBJ:\n            mp_printf(print, \"RAISE_OBJ\");\n            break;\n\n        case MP_BC_RAISE_FROM:\n            mp_printf(print, \"RAISE_FROM\");\n            break;\n\n        case MP_BC_YIELD_VALUE:\n            mp_printf(print, \"YIELD_VALUE\");\n            break;\n\n        case MP_BC_YIELD_FROM:\n            mp_printf(print, \"YIELD_FROM\");\n            break;\n\n        case MP_BC_IMPORT_NAME:\n            DECODE_QSTR;\n            mp_printf(print, \"IMPORT_NAME '%s'\", qstr_str(qst));\n            break;\n\n        case MP_BC_IMPORT_FROM:\n            DECODE_QSTR;\n            mp_printf(print, \"IMPORT_FROM '%s'\", qstr_str(qst));\n            break;\n\n        case MP_BC_IMPORT_STAR:\n            mp_printf(print, \"IMPORT_STAR\");\n            break;\n\n        default:\n            if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) {\n                mp_printf(print, \"LOAD_CONST_SMALL_INT \" INT_FMT, (mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16);\n            } else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) {\n                mp_printf(print, \"LOAD_FAST \" UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI);\n            } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {\n                mp_printf(print, \"STORE_FAST \" UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI);\n            } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) {\n                mp_printf(print, \"UNARY_OP \" UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI);\n            } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) {\n                mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI;\n                mp_printf(print, \"BINARY_OP \" UINT_FMT \" %s\", op, qstr_str(mp_binary_op_method_name[op]));\n            } else {\n                mp_printf(print, \"code %p, byte code 0x%02x not implemented\\n\", ip - 1, ip[-1]);\n                assert(0);\n                return ip;\n            }\n            break;\n    }\n\n    return ip;\n}\n\nvoid mp_bytecode_print2(const mp_print_t *print, const byte *ip, size_t len, const mp_uint_t *const_table) {\n    mp_showbc_code_start = ip;\n    mp_showbc_const_table = const_table;\n    while (ip < len + mp_showbc_code_start) {\n        mp_printf(print, \"%02u \", (uint)(ip - mp_showbc_code_start));\n        ip = mp_bytecode_print_str(print, ip);\n        mp_printf(print, \"\\n\");\n    }\n}\n\n#endif // MICROPY_DEBUG_PRINTERS\n"
  },
  {
    "path": "py/smallint.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/smallint.h\"\n\nbool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y) {\n    // Check for multiply overflow; see CERT INT32-C\n    if (x > 0) { // x is positive\n        if (y > 0) { // x and y are positive\n            if (x > (MP_SMALL_INT_MAX / y)) {\n                return true;\n            }\n        } else { // x positive, y nonpositive\n            if (y < (MP_SMALL_INT_MIN / x)) {\n                return true;\n            }\n        } // x positive, y nonpositive\n    } else { // x is nonpositive\n        if (y > 0) { // x is nonpositive, y is positive\n            if (x < (MP_SMALL_INT_MIN / y)) {\n                return true;\n            }\n        } else { // x and y are nonpositive\n            if (x != 0 && y < (MP_SMALL_INT_MAX / x)) {\n                return true;\n            }\n        } // End if x and y are nonpositive\n    } // End if x is nonpositive\n    return false;\n}\n\nmp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor) {\n    // Python specs require that mod has same sign as second operand\n    dividend %= divisor;\n    if ((dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0)) {\n        dividend += divisor;\n    }\n    return dividend;\n}\n\nmp_int_t mp_small_int_floor_divide(mp_int_t num, mp_int_t denom) {\n    if (num >= 0) {\n        if (denom < 0) {\n            num += -denom - 1;\n        }\n    } else {\n        if (denom >= 0) {\n            num += -denom + 1;\n        }\n    }\n    return num / denom;\n}\n"
  },
  {
    "path": "py/smallint.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_SMALLINT_H\n#define MICROPY_INCLUDED_PY_SMALLINT_H\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n\n// Functions for small integer arithmetic\n\n#ifndef MP_SMALL_INT_MIN\n\n// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range\n#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C\n\n#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)WORD_MSBIT_HIGH) >> 1))\n#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0)\n// Mask to truncate mp_int_t to positive value\n#define MP_SMALL_INT_POSITIVE_MASK ~(WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))\n\n#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B\n\n#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)WORD_MSBIT_HIGH) >> 2))\n#define MP_SMALL_INT_FITS(n) ((((n) & MP_SMALL_INT_MIN) == 0) || (((n) & MP_SMALL_INT_MIN) == MP_SMALL_INT_MIN))\n// Mask to truncate mp_int_t to positive value\n#define MP_SMALL_INT_POSITIVE_MASK ~(WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1) | (WORD_MSBIT_HIGH >> 2))\n\n#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D\n\n#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffff800000000000) >> 1))\n#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffff800000000000) == 0)\n// Mask to truncate mp_int_t to positive value\n#define MP_SMALL_INT_POSITIVE_MASK ~(0xffff800000000000 | (0xffff800000000000 >> 1))\n\n#endif\n\n#endif\n\n#define MP_SMALL_INT_MAX ((mp_int_t)(~(MP_SMALL_INT_MIN)))\n\nbool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y);\nmp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor);\nmp_int_t mp_small_int_floor_divide(mp_int_t num, mp_int_t denom);\n\n#endif // MICROPY_INCLUDED_PY_SMALLINT_H\n"
  },
  {
    "path": "py/stackctrl.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include \"py/runtime.h\"\n#include \"py/stackctrl.h\"\n\nvoid mp_stack_ctrl_init(void) {\n    volatile int stack_dummy;\n    MP_STATE_THREAD(stack_top) = (char *)&stack_dummy;\n}\n\nvoid mp_stack_set_top(void *top) {\n    MP_STATE_THREAD(stack_top) = top;\n}\n\nmp_uint_t mp_stack_usage(void) {\n    // Assumes descending stack\n    volatile int stack_dummy;\n    return MP_STATE_THREAD(stack_top) - (char *)&stack_dummy;\n}\n\n#if MICROPY_STACK_CHECK\n\nvoid mp_stack_set_limit(mp_uint_t limit) {\n    MP_STATE_THREAD(stack_limit) = limit;\n}\n\nvoid mp_stack_check(void) {\n    if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) {\n        mp_raise_recursion_depth();\n    }\n}\n\n#endif // MICROPY_STACK_CHECK\n"
  },
  {
    "path": "py/stackctrl.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_STACKCTRL_H\n#define MICROPY_INCLUDED_PY_STACKCTRL_H\n\n#include \"py/mpconfig.h\"\n\nvoid mp_stack_ctrl_init(void);\nvoid mp_stack_set_top(void *top);\nmp_uint_t mp_stack_usage(void);\n\n#if MICROPY_STACK_CHECK\n\nvoid mp_stack_set_limit(mp_uint_t limit);\nvoid mp_stack_check(void);\n#define MP_STACK_CHECK() mp_stack_check()\n\n#else\n\n#define mp_stack_set_limit(limit)\n#define MP_STACK_CHECK()\n\n#endif\n\n#endif // MICROPY_INCLUDED_PY_STACKCTRL_H\n"
  },
  {
    "path": "py/stream.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n * Copyright (c) 2014-2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <string.h>\n#include <unistd.h>\n\n#include \"py/objstr.h\"\n#include \"py/stream.h\"\n#include \"py/runtime.h\"\n\n// This file defines generic Python stream read/write methods which\n// dispatch to the underlying stream interface of an object.\n\n// TODO: should be in mpconfig.h\n#define DEFAULT_BUFFER_SIZE 256\n\nSTATIC mp_obj_t stream_readall(mp_obj_t self_in);\n\n#define STREAM_CONTENT_TYPE(stream) (((stream)->is_text) ? &mp_type_str : &mp_type_bytes)\n\n// Returns error condition in *errcode, if non-zero, return value is number of bytes written\n// before error condition occurred. If *errcode == 0, returns total bytes written (which will\n// be equal to input size).\nmp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode, byte flags) {\n    byte *buf = buf_;\n    typedef mp_uint_t (*io_func_t)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);\n    io_func_t io_func;\n    const mp_stream_p_t *stream_p = mp_get_stream(stream);\n    if (flags & MP_STREAM_RW_WRITE) {\n        io_func = (io_func_t)stream_p->write;\n    } else {\n        io_func = stream_p->read;\n    }\n\n    *errcode = 0;\n    mp_uint_t done = 0;\n    while (size > 0) {\n        mp_uint_t out_sz = io_func(stream, buf, size, errcode);\n        // For read, out_sz == 0 means EOF. For write, it's unspecified\n        // what it means, but we don't make any progress, so returning\n        // is still the best option.\n        if (out_sz == 0) {\n            return done;\n        }\n        if (out_sz == MP_STREAM_ERROR) {\n            // If we read something before getting EAGAIN, don't leak it\n            if (mp_is_nonblocking_error(*errcode) && done != 0) {\n                *errcode = 0;\n            }\n            return done;\n        }\n        if (flags & MP_STREAM_RW_ONCE) {\n            return out_sz;\n        }\n\n        buf += out_sz;\n        size -= out_sz;\n        done += out_sz;\n    }\n    return done;\n}\n\nconst mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) {\n    const mp_obj_type_t *type = mp_obj_get_type(self_in);\n    const mp_stream_p_t *stream_p = type->protocol;\n    if (stream_p == NULL\n        || ((flags & MP_STREAM_OP_READ) && stream_p->read == NULL)\n        || ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL)\n        || ((flags & MP_STREAM_OP_IOCTL) && stream_p->ioctl == NULL)) {\n        // CPython: io.UnsupportedOperation, OSError subclass\n        mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT(\"stream operation not supported\"));\n    }\n    return stream_p;\n}\n\nSTATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) {\n    // What to do if sz < -1?  Python docs don't specify this case.\n    // CPython does a readall, but here we silently let negatives through,\n    // and they will cause a MemoryError.\n    mp_int_t sz;\n    if (n_args == 1 || ((sz = mp_obj_get_int(args[1])) == -1)) {\n        return stream_readall(args[0]);\n    }\n\n    const mp_stream_p_t *stream_p = mp_get_stream(args[0]);\n\n    #if MICROPY_PY_BUILTINS_STR_UNICODE\n    if (stream_p->is_text) {\n        // We need to read sz number of unicode characters.  Because we don't have any\n        // buffering, and because the stream API can only read bytes, we must read here\n        // in units of bytes and must never over read.  If we want sz chars, then reading\n        // sz bytes will never over-read, so we follow this approach, in a loop to keep\n        // reading until we have exactly enough chars.  This will be 1 read for text\n        // with ASCII-only chars, and about 2 reads for text with a couple of non-ASCII\n        // chars.  For text with lots of non-ASCII chars, it'll be pretty inefficient\n        // in time and memory.\n\n        vstr_t vstr;\n        vstr_init(&vstr, sz);\n        mp_uint_t more_bytes = sz;\n        mp_uint_t last_buf_offset = 0;\n        while (more_bytes > 0) {\n            char *p = vstr_add_len(&vstr, more_bytes);\n            int error;\n            mp_uint_t out_sz = mp_stream_read_exactly(args[0], p, more_bytes, &error);\n            if (error != 0) {\n                vstr_cut_tail_bytes(&vstr, more_bytes);\n                if (mp_is_nonblocking_error(error)) {\n                    // With non-blocking streams, we read as much as we can.\n                    // If we read nothing, return None, just like read().\n                    // Otherwise, return data read so far.\n                    // TODO what if we have read only half a non-ASCII char?\n                    if (vstr.len == 0) {\n                        vstr_clear(&vstr);\n                        return mp_const_none;\n                    }\n                    break;\n                }\n                mp_raise_OSError(error);\n            }\n\n            if (out_sz < more_bytes) {\n                // Finish reading.\n                // TODO what if we have read only half a non-ASCII char?\n                vstr_cut_tail_bytes(&vstr, more_bytes - out_sz);\n                if (out_sz == 0) {\n                    break;\n                }\n            }\n\n            // count chars from bytes just read\n            for (mp_uint_t off = last_buf_offset;;) {\n                byte b = vstr.buf[off];\n                int n;\n                if (!UTF8_IS_NONASCII(b)) {\n                    // 1-byte ASCII char\n                    n = 1;\n                } else if ((b & 0xe0) == 0xc0) {\n                    // 2-byte char\n                    n = 2;\n                } else if ((b & 0xf0) == 0xe0) {\n                    // 3-byte char\n                    n = 3;\n                } else if ((b & 0xf8) == 0xf0) {\n                    // 4-byte char\n                    n = 4;\n                } else {\n                    // TODO\n                    n = 5;\n                }\n                if (off + n <= vstr.len) {\n                    // got a whole char in n bytes\n                    off += n;\n                    sz -= 1;\n                    last_buf_offset = off;\n                    if (off >= vstr.len) {\n                        more_bytes = sz;\n                        break;\n                    }\n                } else {\n                    // didn't get a whole char, so work out how many extra bytes are needed for\n                    // this partial char, plus bytes for additional chars that we want\n                    more_bytes = (off + n - vstr.len) + (sz - 1);\n                    break;\n                }\n            }\n        }\n\n        return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);\n    }\n    #endif\n\n    vstr_t vstr;\n    vstr_init_len(&vstr, sz);\n    int error;\n    mp_uint_t out_sz = mp_stream_rw(args[0], vstr.buf, sz, &error, flags);\n    if (error != 0) {\n        vstr_clear(&vstr);\n        if (mp_is_nonblocking_error(error)) {\n            // https://docs.python.org/3.4/library/io.html#io.RawIOBase.read\n            // \"If the object is in non-blocking mode and no bytes are available,\n            // None is returned.\"\n            // This is actually very weird, as naive truth check will treat\n            // this as EOF.\n            return mp_const_none;\n        }\n        mp_raise_OSError(error);\n    } else {\n        vstr.len = out_sz;\n        return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr);\n    }\n}\n\nSTATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) {\n    return stream_read_generic(n_args, args, MP_STREAM_RW_READ);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj, 1, 2, stream_read);\n\nSTATIC mp_obj_t stream_read1(size_t n_args, const mp_obj_t *args) {\n    return stream_read_generic(n_args, args, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj, 1, 2, stream_read1);\n\nmp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags) {\n    int error;\n    mp_uint_t out_sz = mp_stream_rw(self_in, (void *)buf, len, &error, flags);\n    if (error != 0) {\n        if (mp_is_nonblocking_error(error)) {\n            // http://docs.python.org/3/library/io.html#io.RawIOBase.write\n            // \"None is returned if the raw stream is set not to block and\n            // no single byte could be readily written to it.\"\n            return mp_const_none;\n        }\n        mp_raise_OSError(error);\n    } else {\n        return MP_OBJ_NEW_SMALL_INT(out_sz);\n    }\n}\n\n// This is used to adapt a stream object to an mp_print_t interface\nvoid mp_stream_write_adaptor(void *self, const char *buf, size_t len) {\n    mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE);\n}\n\nSTATIC mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);\n    size_t max_len = (size_t)-1;\n    size_t off = 0;\n    if (n_args == 3) {\n        max_len = mp_obj_get_int_truncated(args[2]);\n    } else if (n_args == 4) {\n        off = mp_obj_get_int_truncated(args[2]);\n        max_len = mp_obj_get_int_truncated(args[3]);\n        if (off > bufinfo.len) {\n            off = bufinfo.len;\n        }\n    }\n    bufinfo.len -= off;\n    return mp_stream_write(args[0], (byte *)bufinfo.buf + off, MIN(bufinfo.len, max_len), MP_STREAM_RW_WRITE);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj, 2, 4, stream_write_method);\n\nSTATIC mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);\n    return mp_stream_write(self_in, bufinfo.buf, bufinfo.len, MP_STREAM_RW_WRITE | MP_STREAM_RW_ONCE);\n}\nMP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write1_obj, stream_write1_method);\n\nSTATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) {\n    mp_buffer_info_t bufinfo;\n    mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);\n\n    // CPython extension: if 2nd arg is provided, that's max len to read,\n    // instead of full buffer. Similar to\n    // https://docs.python.org/3/library/socket.html#socket.socket.recv_into\n    mp_uint_t len = bufinfo.len;\n    if (n_args > 2) {\n        len = mp_obj_get_int(args[2]);\n        if (len > bufinfo.len) {\n            len = bufinfo.len;\n        }\n    }\n\n    int error;\n    mp_uint_t out_sz = mp_stream_read_exactly(args[0], bufinfo.buf, len, &error);\n    if (error != 0) {\n        if (mp_is_nonblocking_error(error)) {\n            return mp_const_none;\n        }\n        mp_raise_OSError(error);\n    } else {\n        return MP_OBJ_NEW_SMALL_INT(out_sz);\n    }\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj, 2, 3, stream_readinto);\n\nSTATIC mp_obj_t stream_readall(mp_obj_t self_in) {\n    const mp_stream_p_t *stream_p = mp_get_stream(self_in);\n\n    mp_uint_t total_size = 0;\n    vstr_t vstr;\n    vstr_init(&vstr, DEFAULT_BUFFER_SIZE);\n    char *p = vstr.buf;\n    mp_uint_t current_read = DEFAULT_BUFFER_SIZE;\n    while (true) {\n        int error;\n        mp_uint_t out_sz = stream_p->read(self_in, p, current_read, &error);\n        if (out_sz == MP_STREAM_ERROR) {\n            if (mp_is_nonblocking_error(error)) {\n                // With non-blocking streams, we read as much as we can.\n                // If we read nothing, return None, just like read().\n                // Otherwise, return data read so far.\n                if (total_size == 0) {\n                    return mp_const_none;\n                }\n                break;\n            }\n            mp_raise_OSError(error);\n        }\n        if (out_sz == 0) {\n            break;\n        }\n        total_size += out_sz;\n        if (out_sz < current_read) {\n            current_read -= out_sz;\n            p += out_sz;\n        } else {\n            p = vstr_extend(&vstr, DEFAULT_BUFFER_SIZE);\n            current_read = DEFAULT_BUFFER_SIZE;\n        }\n    }\n\n    vstr.len = total_size;\n    return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr);\n}\n\n// Unbuffered, inefficient implementation of readline() for raw I/O files.\nSTATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) {\n    const mp_stream_p_t *stream_p = mp_get_stream(args[0]);\n\n    mp_int_t max_size = -1;\n    if (n_args > 1) {\n        max_size = MP_OBJ_SMALL_INT_VALUE(args[1]);\n    }\n\n    vstr_t vstr;\n    if (max_size != -1) {\n        vstr_init(&vstr, max_size);\n    } else {\n        vstr_init(&vstr, 16);\n    }\n\n    while (max_size == -1 || max_size-- != 0) {\n        char *p = vstr_add_len(&vstr, 1);\n        int error;\n        mp_uint_t out_sz = stream_p->read(args[0], p, 1, &error);\n        if (out_sz == MP_STREAM_ERROR) {\n            if (mp_is_nonblocking_error(error)) {\n                if (vstr.len == 1) {\n                    // We just incremented it, but otherwise we read nothing\n                    // and immediately got EAGAIN. This case is not well\n                    // specified in\n                    // https://docs.python.org/3/library/io.html#io.IOBase.readline\n                    // unlike similar case for read(). But we follow the latter's\n                    // behavior - return None.\n                    vstr_clear(&vstr);\n                    return mp_const_none;\n                } else {\n                    goto done;\n                }\n            }\n            mp_raise_OSError(error);\n        }\n        if (out_sz == 0) {\n        done:\n            // Back out previously added byte\n            // Consider, what's better - read a char and get OutOfMemory (so read\n            // char is lost), or allocate first as we do.\n            vstr_cut_tail_bytes(&vstr, 1);\n            break;\n        }\n        if (*p == '\\n') {\n            break;\n        }\n    }\n\n    return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj, 1, 2, stream_unbuffered_readline);\n\n// TODO take an optional extra argument (what does it do exactly?)\nSTATIC mp_obj_t stream_unbuffered_readlines(mp_obj_t self) {\n    mp_obj_t lines = mp_obj_new_list(0, NULL);\n    for (;;) {\n        mp_obj_t line = stream_unbuffered_readline(1, &self);\n        if (!mp_obj_is_true(line)) {\n            break;\n        }\n        mp_obj_list_append(lines, line);\n    }\n    return lines;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj, stream_unbuffered_readlines);\n\nmp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) {\n    mp_obj_t l_in = stream_unbuffered_readline(1, &self);\n    if (mp_obj_is_true(l_in)) {\n        return l_in;\n    }\n    return MP_OBJ_STOP_ITERATION;\n}\n\nmp_obj_t mp_stream_close(mp_obj_t stream) {\n    const mp_stream_p_t *stream_p = mp_get_stream(stream);\n    int error;\n    mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);\n    if (res == MP_STREAM_ERROR) {\n        mp_raise_OSError(error);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close);\n\nSTATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) {\n    struct mp_stream_seek_t seek_s;\n    // TODO: Could be uint64\n    seek_s.offset = mp_obj_get_int(args[1]);\n    seek_s.whence = SEEK_SET;\n    if (n_args == 3) {\n        seek_s.whence = mp_obj_get_int(args[2]);\n    }\n\n    // In POSIX, it's error to seek before end of stream, we enforce it here.\n    if (seek_s.whence == SEEK_SET && seek_s.offset < 0) {\n        mp_raise_OSError(MP_EINVAL);\n    }\n\n    const mp_stream_p_t *stream_p = mp_get_stream(args[0]);\n    int error;\n    mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error);\n    if (res == MP_STREAM_ERROR) {\n        mp_raise_OSError(error);\n    }\n\n    // TODO: Could be uint64\n    return mp_obj_new_int_from_uint(seek_s.offset);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj, 2, 3, stream_seek);\n\nSTATIC mp_obj_t stream_tell(mp_obj_t self) {\n    mp_obj_t offset = MP_OBJ_NEW_SMALL_INT(0);\n    mp_obj_t whence = MP_OBJ_NEW_SMALL_INT(SEEK_CUR);\n    const mp_obj_t args[3] = {self, offset, whence};\n    return stream_seek(3, args);\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_stream_tell_obj, stream_tell);\n\nSTATIC mp_obj_t stream_flush(mp_obj_t self) {\n    const mp_stream_p_t *stream_p = mp_get_stream(self);\n    int error;\n    mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error);\n    if (res == MP_STREAM_ERROR) {\n        mp_raise_OSError(error);\n    }\n    return mp_const_none;\n}\nMP_DEFINE_CONST_FUN_OBJ_1(mp_stream_flush_obj, stream_flush);\n\nSTATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) {\n    mp_buffer_info_t bufinfo;\n    uintptr_t val = 0;\n    if (n_args > 2) {\n        if (mp_get_buffer(args[2], &bufinfo, MP_BUFFER_WRITE)) {\n            val = (uintptr_t)bufinfo.buf;\n        } else {\n            val = mp_obj_get_int_truncated(args[2]);\n        }\n    }\n\n    const mp_stream_p_t *stream_p = mp_get_stream(args[0]);\n    int error;\n    mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error);\n    if (res == MP_STREAM_ERROR) {\n        mp_raise_OSError(error);\n    }\n\n    return mp_obj_new_int(res);\n}\nMP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj, 2, 3, stream_ioctl);\n\n#if MICROPY_STREAMS_POSIX_API\n/*\n * POSIX-like functions\n *\n * These functions have POSIX-compatible signature (except for \"void *stream\"\n * first argument instead of \"int fd\"). They are useful to port existing\n * POSIX-compatible software to work with MicroPython streams.\n */\n\n#include <errno.h>\n\nssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len) {\n    mp_obj_base_t *o = stream;\n    const mp_stream_p_t *stream_p = o->type->protocol;\n    mp_uint_t out_sz = stream_p->write(MP_OBJ_FROM_PTR(stream), buf, len, &errno);\n    if (out_sz == MP_STREAM_ERROR) {\n        return -1;\n    } else {\n        return out_sz;\n    }\n}\n\nssize_t mp_stream_posix_read(void *stream, void *buf, size_t len) {\n    mp_obj_base_t *o = stream;\n    const mp_stream_p_t *stream_p = o->type->protocol;\n    mp_uint_t out_sz = stream_p->read(MP_OBJ_FROM_PTR(stream), buf, len, &errno);\n    if (out_sz == MP_STREAM_ERROR) {\n        return -1;\n    } else {\n        return out_sz;\n    }\n}\n\noff_t mp_stream_posix_lseek(void *stream, off_t offset, int whence) {\n    const mp_obj_base_t *o = stream;\n    const mp_stream_p_t *stream_p = o->type->protocol;\n    struct mp_stream_seek_t seek_s;\n    seek_s.offset = offset;\n    seek_s.whence = whence;\n    mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &errno);\n    if (res == MP_STREAM_ERROR) {\n        return -1;\n    }\n    return seek_s.offset;\n}\n\nint mp_stream_posix_fsync(void *stream) {\n    mp_obj_base_t *o = stream;\n    const mp_stream_p_t *stream_p = o->type->protocol;\n    mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_FLUSH, 0, &errno);\n    if (res == MP_STREAM_ERROR) {\n        return -1;\n    }\n    return res;\n}\n\n#endif\n"
  },
  {
    "path": "py/stream.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014-2016 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_STREAM_H\n#define MICROPY_INCLUDED_PY_STREAM_H\n\n#include \"py/obj.h\"\n#include \"py/mperrno.h\"\n\n#define MP_STREAM_ERROR ((mp_uint_t)-1)\n\n// Stream ioctl request codes\n#define MP_STREAM_FLUSH (1)\n#define MP_STREAM_SEEK  (2)\n#define MP_STREAM_POLL  (3)\n#define MP_STREAM_CLOSE         (4)\n#define MP_STREAM_TIMEOUT       (5)  // Get/set timeout (single op)\n#define MP_STREAM_GET_OPTS      (6)  // Get stream options\n#define MP_STREAM_SET_OPTS      (7)  // Set stream options\n#define MP_STREAM_GET_DATA_OPTS (8)  // Get data/message options\n#define MP_STREAM_SET_DATA_OPTS (9)  // Set data/message options\n#define MP_STREAM_GET_FILENO    (10) // Get fileno of underlying file\n\n// These poll ioctl values are compatible with Linux\n#define MP_STREAM_POLL_RD       (0x0001)\n#define MP_STREAM_POLL_WR       (0x0004)\n#define MP_STREAM_POLL_ERR      (0x0008)\n#define MP_STREAM_POLL_HUP      (0x0010)\n#define MP_STREAM_POLL_NVAL     (0x0020)\n\n// Argument structure for MP_STREAM_SEEK\nstruct mp_stream_seek_t {\n    // If whence == MP_SEEK_SET, offset should be treated as unsigned.\n    // This allows dealing with full-width stream sizes (16, 32, 64,\n    // etc. bits). For other seek types, should be treated as signed.\n    mp_off_t offset;\n    int whence;\n};\n\n// seek ioctl \"whence\" values\n#define MP_SEEK_SET (0)\n#define MP_SEEK_CUR (1)\n#define MP_SEEK_END (2)\n\n// Stream protocol\ntypedef struct _mp_stream_p_t {\n    // On error, functions should return MP_STREAM_ERROR and fill in *errcode (values\n    // are implementation-dependent, but will be exposed to user, e.g. via exception).\n    mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);\n    mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);\n    mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);\n    mp_uint_t is_text : 1; // default is bytes, set this for text stream\n} mp_stream_p_t;\n\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj);\nMP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_stream_close_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_stream_tell_obj);\nMP_DECLARE_CONST_FUN_OBJ_1(mp_stream_flush_obj);\nMP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj);\n\n// these are for mp_get_stream_raise and can be or'd together\n#define MP_STREAM_OP_READ (1)\n#define MP_STREAM_OP_WRITE (2)\n#define MP_STREAM_OP_IOCTL (4)\n\n// Object is assumed to have a non-NULL stream protocol with valid r/w/ioctl methods\nstatic inline const mp_stream_p_t *mp_get_stream(mp_const_obj_t self) {\n    return (const mp_stream_p_t *)((const mp_obj_base_t *)MP_OBJ_TO_PTR(self))->type->protocol;\n}\n\nconst mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags);\nmp_obj_t mp_stream_close(mp_obj_t stream);\n\n// Iterator which uses mp_stream_unbuffered_readline_obj\nmp_obj_t mp_stream_unbuffered_iter(mp_obj_t self);\n\nmp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags);\n\n// C-level helper functions\n#define MP_STREAM_RW_READ  0\n#define MP_STREAM_RW_WRITE 2\n#define MP_STREAM_RW_ONCE  1\nmp_uint_t mp_stream_rw(mp_obj_t stream, void *buf, mp_uint_t size, int *errcode, byte flags);\n#define mp_stream_write_exactly(stream, buf, size, err) mp_stream_rw(stream, (byte *)buf, size, err, MP_STREAM_RW_WRITE)\n#define mp_stream_read_exactly(stream, buf, size, err) mp_stream_rw(stream, buf, size, err, MP_STREAM_RW_READ)\n\nvoid mp_stream_write_adaptor(void *self, const char *buf, size_t len);\n\n#if MICROPY_STREAMS_POSIX_API\n#include <sys/types.h>\n// Functions with POSIX-compatible signatures\n// \"stream\" is assumed to be a pointer to a concrete object with the stream protocol\nssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len);\nssize_t mp_stream_posix_read(void *stream, void *buf, size_t len);\noff_t mp_stream_posix_lseek(void *stream, off_t offset, int whence);\nint mp_stream_posix_fsync(void *stream);\n#endif\n\n#if MICROPY_STREAMS_NON_BLOCK\n#define mp_is_nonblocking_error(errno) ((errno) == MP_EAGAIN || (errno) == MP_EWOULDBLOCK)\n#else\n#define mp_is_nonblocking_error(errno) (0)\n#endif\n\n#endif // MICROPY_INCLUDED_PY_STREAM_H\n"
  },
  {
    "path": "py/unicode.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdint.h>\n\n#include \"py/unicode.h\"\n\n// attribute flags\n#define FL_PRINT (0x01)\n#define FL_SPACE (0x02)\n#define FL_DIGIT (0x04)\n#define FL_ALPHA (0x08)\n#define FL_UPPER (0x10)\n#define FL_LOWER (0x20)\n#define FL_XDIGIT (0x40)\n\n// shorthand character attributes\n#define AT_PR (FL_PRINT)\n#define AT_SP (FL_SPACE | FL_PRINT)\n#define AT_DI (FL_DIGIT | FL_PRINT | FL_XDIGIT)\n#define AT_AL (FL_ALPHA | FL_PRINT)\n#define AT_UP (FL_UPPER | FL_ALPHA | FL_PRINT)\n#define AT_LO (FL_LOWER | FL_ALPHA | FL_PRINT)\n#define AT_UX (FL_UPPER | FL_ALPHA | FL_PRINT | FL_XDIGIT)\n#define AT_LX (FL_LOWER | FL_ALPHA | FL_PRINT | FL_XDIGIT)\n\n// table of attributes for ascii characters\nSTATIC const uint8_t attr[] = {\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, AT_SP, AT_SP, AT_SP, AT_SP, AT_SP, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    AT_SP, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR,\n    AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR,\n    AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI,\n    AT_DI, AT_DI, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR,\n    AT_PR, AT_UX, AT_UX, AT_UX, AT_UX, AT_UX, AT_UX, AT_UP,\n    AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP,\n    AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP,\n    AT_UP, AT_UP, AT_UP, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR,\n    AT_PR, AT_LX, AT_LX, AT_LX, AT_LX, AT_LX, AT_LX, AT_LO,\n    AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO,\n    AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO,\n    AT_LO, AT_LO, AT_LO, AT_PR, AT_PR, AT_PR, AT_PR, 0\n};\n\n#if MICROPY_PY_BUILTINS_STR_UNICODE\n\nunichar utf8_get_char(const byte *s) {\n    unichar ord = *s++;\n    if (!UTF8_IS_NONASCII(ord)) {\n        return ord;\n    }\n    ord &= 0x7F;\n    for (unichar mask = 0x40; ord & mask; mask >>= 1) {\n        ord &= ~mask;\n    }\n    while (UTF8_IS_CONT(*s)) {\n        ord = (ord << 6) | (*s++ & 0x3F);\n    }\n    return ord;\n}\n\nconst byte *utf8_next_char(const byte *s) {\n    ++s;\n    while (UTF8_IS_CONT(*s)) {\n        ++s;\n    }\n    return s;\n}\n\nmp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr) {\n    mp_uint_t i = 0;\n    while (ptr > s) {\n        if (!UTF8_IS_CONT(*--ptr)) {\n            i++;\n        }\n    }\n\n    return i;\n}\n\nsize_t utf8_charlen(const byte *str, size_t len) {\n    size_t charlen = 0;\n    for (const byte *top = str + len; str < top; ++str) {\n        if (!UTF8_IS_CONT(*str)) {\n            ++charlen;\n        }\n    }\n    return charlen;\n}\n\n#endif\n\n// Be aware: These unichar_is* functions are actually ASCII-only!\nbool unichar_isspace(unichar c) {\n    return c < 128 && (attr[c] & FL_SPACE) != 0;\n}\n\nbool unichar_isalpha(unichar c) {\n    return c < 128 && (attr[c] & FL_ALPHA) != 0;\n}\n\n/* unused\nbool unichar_isprint(unichar c) {\n    return c < 128 && (attr[c] & FL_PRINT) != 0;\n}\n*/\n\nbool unichar_isdigit(unichar c) {\n    return c < 128 && (attr[c] & FL_DIGIT) != 0;\n}\n\nbool unichar_isxdigit(unichar c) {\n    return c < 128 && (attr[c] & FL_XDIGIT) != 0;\n}\n\nbool unichar_isident(unichar c) {\n    return c < 128 && ((attr[c] & (FL_ALPHA | FL_DIGIT)) != 0 || c == '_');\n}\n\nbool unichar_isalnum(unichar c) {\n    return c < 128 && ((attr[c] & (FL_ALPHA | FL_DIGIT)) != 0);\n}\n\nbool unichar_isupper(unichar c) {\n    return c < 128 && (attr[c] & FL_UPPER) != 0;\n}\n\nbool unichar_islower(unichar c) {\n    return c < 128 && (attr[c] & FL_LOWER) != 0;\n}\n\nunichar unichar_tolower(unichar c) {\n    if (unichar_isupper(c)) {\n        return c + 0x20;\n    }\n    return c;\n}\n\nunichar unichar_toupper(unichar c) {\n    if (unichar_islower(c)) {\n        return c - 0x20;\n    }\n    return c;\n}\n\nmp_uint_t unichar_xdigit_value(unichar c) {\n    // c is assumed to be hex digit\n    mp_uint_t n = c - '0';\n    if (n > 9) {\n        n &= ~('a' - 'A');\n        n -= ('A' - ('9' + 1));\n    }\n    return n;\n}\n\n#if MICROPY_PY_BUILTINS_STR_UNICODE\n\nbool utf8_check(const byte *p, size_t len) {\n    uint8_t need = 0;\n    const byte *end = p + len;\n    for (; p < end; p++) {\n        byte c = *p;\n        if (need) {\n            if (UTF8_IS_CONT(c)) {\n                need--;\n            } else {\n                // mismatch\n                return 0;\n            }\n        } else {\n            if (c >= 0xc0) {\n                if (c >= 0xf8) {\n                    // mismatch\n                    return 0;\n                }\n                need = (0xe5 >> ((c >> 3) & 0x6)) & 3;\n            } else if (c >= 0x80) {\n                // mismatch\n                return 0;\n            }\n        }\n    }\n    return need == 0; // no pending fragments allowed\n}\n\n#endif\n"
  },
  {
    "path": "py/unicode.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef MICROPY_INCLUDED_PY_UNICODE_H\n#define MICROPY_INCLUDED_PY_UNICODE_H\n\n#include \"py/mpconfig.h\"\n#include \"py/misc.h\"\n\nmp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr);\nbool utf8_check(const byte *p, size_t len);\n\n#endif // MICROPY_INCLUDED_PY_UNICODE_H\n"
  },
  {
    "path": "py/vm.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013-2019 Damien P. George\n * Copyright (c) 2014-2015 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/emitglue.h\"\n#include \"py/objtype.h\"\n#include \"py/runtime.h\"\n#include \"py/bc0.h\"\n#include \"py/bc.h\"\n#include \"py/profile.h\"\n\n// *FORMAT-OFF*\n\n#if 0\n#define TRACE(ip) printf(\"sp=%d \", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(&mp_plat_print, ip, 1, code_state->fun_bc->const_table);\n#else\n#define TRACE(ip)\n#endif\n\n// Value stack grows up (this makes it incompatible with native C stack, but\n// makes sure that arguments to functions are in natural order arg1..argN\n// (Python semantics mandates left-to-right evaluation order, including for\n// function arguments). Stack pointer is pre-incremented and points at the\n// top element.\n// Exception stack also grows up, top element is also pointed at.\n\n#define DECODE_UINT \\\n    mp_uint_t unum = 0; \\\n    do { \\\n        unum = (unum << 7) + (*ip & 0x7f); \\\n    } while ((*ip++ & 0x80) != 0)\n#define DECODE_ULABEL size_t ulab = (ip[0] | (ip[1] << 8)); ip += 2\n#define DECODE_SLABEL size_t slab = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2\n\n#if MICROPY_PERSISTENT_CODE\n\n#define DECODE_QSTR \\\n    qstr qst = ip[0] | ip[1] << 8; \\\n    ip += 2;\n#define DECODE_PTR \\\n    DECODE_UINT; \\\n    void *ptr = (void*)(uintptr_t)code_state->fun_bc->const_table[unum]\n#define DECODE_OBJ \\\n    DECODE_UINT; \\\n    mp_obj_t obj = (mp_obj_t)code_state->fun_bc->const_table[unum]\n\n#else\n\n#define DECODE_QSTR qstr qst = 0; \\\n    do { \\\n        qst = (qst << 7) + (*ip & 0x7f); \\\n    } while ((*ip++ & 0x80) != 0)\n#define DECODE_PTR \\\n    ip = (byte*)MP_ALIGN(ip, sizeof(void*)); \\\n    void *ptr = *(void**)ip; \\\n    ip += sizeof(void*)\n#define DECODE_OBJ \\\n    ip = (byte*)MP_ALIGN(ip, sizeof(mp_obj_t)); \\\n    mp_obj_t obj = *(mp_obj_t*)ip; \\\n    ip += sizeof(mp_obj_t)\n\n#endif\n\n#define PUSH(val) *++sp = (val)\n#define POP() (*sp--)\n#define TOP() (*sp)\n#define SET_TOP(val) *sp = (val)\n\n#if MICROPY_PY_SYS_EXC_INFO\n#define CLEAR_SYS_EXC_INFO() MP_STATE_VM(cur_exception) = NULL;\n#else\n#define CLEAR_SYS_EXC_INFO()\n#endif\n\n#define PUSH_EXC_BLOCK(with_or_finally) do { \\\n    DECODE_ULABEL; /* except labels are always forward */ \\\n    ++exc_sp; \\\n    exc_sp->handler = ip + ulab; \\\n    exc_sp->val_sp = MP_TAGPTR_MAKE(sp, ((with_or_finally) << 1)); \\\n    exc_sp->prev_exc = NULL; \\\n} while (0)\n\n#define POP_EXC_BLOCK() \\\n    exc_sp--; /* pop back to previous exception handler */ \\\n    CLEAR_SYS_EXC_INFO() /* just clear sys.exc_info(), not compliant, but it shouldn't be used in 1st place */\n\n#define CANCEL_ACTIVE_FINALLY(sp) do { \\\n    if (mp_obj_is_small_int(sp[-1])) { \\\n        /* Stack: (..., prev_dest_ip, prev_cause, dest_ip) */ \\\n        /* Cancel the unwind through the previous finally, replace with current one */ \\\n        sp[-2] = sp[0]; \\\n        sp -= 2; \\\n    } else { \\\n        assert(sp[-1] == mp_const_none || mp_obj_is_exception_instance(sp[-1])); \\\n        /* Stack: (..., None/exception, dest_ip) */ \\\n        /* Silence the finally's exception value (may be None or an exception) */ \\\n        sp[-1] = sp[0]; \\\n        --sp; \\\n    } \\\n} while (0)\n\n#if MICROPY_PY_SYS_SETTRACE\n\n#define FRAME_SETUP() do { \\\n    assert(code_state != code_state->prev_state); \\\n    MP_STATE_THREAD(current_code_state) = code_state; \\\n    assert(code_state != code_state->prev_state); \\\n} while(0)\n\n#define FRAME_ENTER() do { \\\n    assert(code_state != code_state->prev_state); \\\n    code_state->prev_state = MP_STATE_THREAD(current_code_state); \\\n    assert(code_state != code_state->prev_state); \\\n    if (!mp_prof_is_executing) { \\\n        mp_prof_frame_enter(code_state); \\\n    } \\\n} while(0)\n\n#define FRAME_LEAVE() do { \\\n    assert(code_state != code_state->prev_state); \\\n    MP_STATE_THREAD(current_code_state) = code_state->prev_state; \\\n    assert(code_state != code_state->prev_state); \\\n} while(0)\n\n#define FRAME_UPDATE() do { \\\n    assert(MP_STATE_THREAD(current_code_state) == code_state); \\\n    if (!mp_prof_is_executing) { \\\n        code_state->frame = MP_OBJ_TO_PTR(mp_prof_frame_update(code_state)); \\\n    } \\\n} while(0)\n\n#define TRACE_TICK(current_ip, current_sp, is_exception) do { \\\n    assert(code_state != code_state->prev_state); \\\n    assert(MP_STATE_THREAD(current_code_state) == code_state); \\\n    if (!mp_prof_is_executing && code_state->frame && MP_STATE_THREAD(prof_trace_callback)) { \\\n        MP_PROF_INSTR_DEBUG_PRINT(code_state->ip); \\\n    } \\\n    if (!mp_prof_is_executing && code_state->frame && code_state->frame->callback) { \\\n        mp_prof_instr_tick(code_state, is_exception); \\\n    } \\\n} while(0)\n\n#else // MICROPY_PY_SYS_SETTRACE\n#define FRAME_SETUP()\n#define FRAME_ENTER()\n#define FRAME_LEAVE()\n#define FRAME_UPDATE()\n#define TRACE_TICK(current_ip, current_sp, is_exception)\n#endif // MICROPY_PY_SYS_SETTRACE\n\n#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE\nstatic inline mp_map_elem_t *mp_map_cached_lookup(mp_map_t *map, qstr qst, uint8_t *idx_cache) {\n    size_t idx = *idx_cache;\n    mp_obj_t key = MP_OBJ_NEW_QSTR(qst);\n    mp_map_elem_t *elem = NULL;\n    if (idx < map->alloc && map->table[idx].key == key) {\n        elem = &map->table[idx];\n    } else {\n        elem = mp_map_lookup(map, key, MP_MAP_LOOKUP);\n        if (elem != NULL) {\n            *idx_cache = (elem - &map->table[0]) & 0xff;\n        }\n    }\n    return elem;\n}\n#endif\n\n// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)\n// sp points to bottom of stack which grows up\n// returns:\n//  MP_VM_RETURN_NORMAL, sp valid, return value in *sp\n//  MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp\n//  MP_VM_RETURN_EXCEPTION, exception in state[0]\nmp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) {\n#define SELECTIVE_EXC_IP (0)\n#if SELECTIVE_EXC_IP\n#define MARK_EXC_IP_SELECTIVE() { code_state->ip = ip; } /* stores ip 1 byte past last opcode */\n#define MARK_EXC_IP_GLOBAL()\n#else\n#define MARK_EXC_IP_SELECTIVE()\n#define MARK_EXC_IP_GLOBAL() { code_state->ip = ip; } /* stores ip pointing to last opcode */\n#endif\n#if MICROPY_OPT_COMPUTED_GOTO\n    #include \"py/vmentrytable.h\"\n    #define DISPATCH() do { \\\n        TRACE(ip); \\\n        MARK_EXC_IP_GLOBAL(); \\\n        TRACE_TICK(ip, sp, false); \\\n        goto *entry_table[*ip++]; \\\n    } while (0)\n    #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check\n    #define ENTRY(op) entry_##op\n    #define ENTRY_DEFAULT entry_default\n#else\n    #define DISPATCH() goto dispatch_loop\n    #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check\n    #define ENTRY(op) case op\n    #define ENTRY_DEFAULT default\n#endif\n\n    // nlr_raise needs to be implemented as a goto, so that the C compiler's flow analyser\n    // sees that it's possible for us to jump from the dispatch loop to the exception\n    // handler.  Without this, the code may have a different stack layout in the dispatch\n    // loop and the exception handler, leading to very obscure bugs.\n    #define RAISE(o) do { nlr_pop(); nlr.ret_val = MP_OBJ_TO_PTR(o); goto exception_handler; } while (0)\n\n#if MICROPY_STACKLESS\nrun_code_state: ;\n#endif\nFRAME_ENTER();\n\n#if MICROPY_STACKLESS\nrun_code_state_from_return: ;\n#endif\nFRAME_SETUP();\n\n    // Pointers which are constant for particular invocation of mp_execute_bytecode()\n    mp_obj_t * /*const*/ fastn;\n    mp_exc_stack_t * /*const*/ exc_stack;\n    {\n        size_t n_state = code_state->n_state;\n        fastn = &code_state->state[n_state - 1];\n        exc_stack = (mp_exc_stack_t*)(code_state->state + n_state);\n    }\n\n    // variables that are visible to the exception handler (declared volatile)\n    mp_exc_stack_t *volatile exc_sp = MP_CODE_STATE_EXC_SP_IDX_TO_PTR(exc_stack, code_state->exc_sp_idx); // stack grows up, exc_sp points to top of stack\n\n    #if MICROPY_PY_THREAD_GIL && MICROPY_PY_THREAD_GIL_VM_DIVISOR\n    // This needs to be volatile and outside the VM loop so it persists across handling\n    // of any exceptions.  Otherwise it's possible that the VM never gives up the GIL.\n    volatile int gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR;\n    #endif\n\n    // outer exception handling loop\n    for (;;) {\n        nlr_buf_t nlr;\nouter_dispatch_loop:\n        if (nlr_push(&nlr) == 0) {\n            // local variables that are not visible to the exception handler\n            const byte *ip = code_state->ip;\n            mp_obj_t *sp = code_state->sp;\n            mp_obj_t obj_shared;\n            MICROPY_VM_HOOK_INIT\n\n            // If we have exception to inject, now that we finish setting up\n            // execution context, raise it. This works as if MP_BC_RAISE_OBJ\n            // bytecode was executed.\n            // Injecting exc into yield from generator is a special case,\n            // handled by MP_BC_YIELD_FROM itself\n            if (inject_exc != MP_OBJ_NULL && *ip != MP_BC_YIELD_FROM) {\n                mp_obj_t exc = inject_exc;\n                inject_exc = MP_OBJ_NULL;\n                exc = mp_make_raise_obj(exc);\n                RAISE(exc);\n            }\n\n            // loop to execute byte code\n            for (;;) {\ndispatch_loop:\n#if MICROPY_OPT_COMPUTED_GOTO\n                DISPATCH();\n#else\n                TRACE(ip);\n                MARK_EXC_IP_GLOBAL();\n                TRACE_TICK(ip, sp, false);\n                switch (*ip++) {\n#endif\n\n                ENTRY(MP_BC_LOAD_CONST_FALSE):\n                    PUSH(mp_const_false);\n                    DISPATCH();\n\n                ENTRY(MP_BC_LOAD_CONST_NONE):\n                    PUSH(mp_const_none);\n                    DISPATCH();\n\n                ENTRY(MP_BC_LOAD_CONST_TRUE):\n                    PUSH(mp_const_true);\n                    DISPATCH();\n\n                ENTRY(MP_BC_LOAD_CONST_SMALL_INT): {\n                    mp_int_t num = 0;\n                    if ((ip[0] & 0x40) != 0) {\n                        // Number is negative\n                        num--;\n                    }\n                    do {\n                        num = (num << 7) | (*ip & 0x7f);\n                    } while ((*ip++ & 0x80) != 0);\n                    PUSH(MP_OBJ_NEW_SMALL_INT(num));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_LOAD_CONST_STRING): {\n                    DECODE_QSTR;\n                    PUSH(MP_OBJ_NEW_QSTR(qst));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_LOAD_CONST_OBJ): {\n                    DECODE_OBJ;\n                    PUSH(obj);\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_LOAD_NULL):\n                    PUSH(MP_OBJ_NULL);\n                    DISPATCH();\n\n                ENTRY(MP_BC_LOAD_FAST_N): {\n                    DECODE_UINT;\n                    obj_shared = fastn[-unum];\n                    load_check:\n                    if (obj_shared == MP_OBJ_NULL) {\n                        local_name_error: {\n                            MARK_EXC_IP_SELECTIVE();\n                            mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NameError, MP_ERROR_TEXT(\"local variable referenced before assignment\"));\n                            RAISE(obj);\n                        }\n                    }\n                    PUSH(obj_shared);\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_LOAD_DEREF): {\n                    DECODE_UINT;\n                    obj_shared = mp_obj_cell_get(fastn[-unum]);\n                    goto load_check;\n                }\n\n                #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE\n                ENTRY(MP_BC_LOAD_NAME): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    PUSH(mp_load_name(qst));\n                    DISPATCH();\n                }\n                #else\n                ENTRY(MP_BC_LOAD_NAME): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_map_elem_t *elem = mp_map_cached_lookup(&mp_locals_get()->map, qst, (uint8_t*)ip);\n                    mp_obj_t obj;\n                    if (elem != NULL) {\n                        obj = elem->value;\n                    } else {\n                        obj = mp_load_name(qst);\n                    }\n                    PUSH(obj);\n                    ip++;\n                    DISPATCH();\n                }\n                #endif\n\n                #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE\n                ENTRY(MP_BC_LOAD_GLOBAL): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    PUSH(mp_load_global(qst));\n                    DISPATCH();\n                }\n                #else\n                ENTRY(MP_BC_LOAD_GLOBAL): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_map_elem_t *elem = mp_map_cached_lookup(&mp_globals_get()->map, qst, (uint8_t*)ip);\n                    mp_obj_t obj;\n                    if (elem != NULL) {\n                        obj = elem->value;\n                    } else {\n                        obj = mp_load_global(qst);\n                    }\n                    PUSH(obj);\n                    ip++;\n                    DISPATCH();\n                }\n                #endif\n\n                #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE\n                ENTRY(MP_BC_LOAD_ATTR): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    SET_TOP(mp_load_attr(TOP(), qst));\n                    DISPATCH();\n                }\n                #else\n                ENTRY(MP_BC_LOAD_ATTR): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_obj_t top = TOP();\n                    mp_map_elem_t *elem = NULL;\n                    if (mp_obj_is_instance_type(mp_obj_get_type(top))) {\n                        mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);\n                        elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip);\n                    }\n                    mp_obj_t obj;\n                    if (elem != NULL) {\n                        obj = elem->value;\n                    } else {\n                        obj = mp_load_attr(top, qst);\n                    }\n                    SET_TOP(obj);\n                    ip++;\n                    DISPATCH();\n                }\n                #endif\n\n                ENTRY(MP_BC_LOAD_METHOD): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_load_method(*sp, qst, sp);\n                    sp += 1;\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_LOAD_SUPER_METHOD): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    sp -= 1;\n                    mp_load_super_method(qst, sp - 1);\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_LOAD_BUILD_CLASS):\n                    MARK_EXC_IP_SELECTIVE();\n                    PUSH(mp_load_build_class());\n                    DISPATCH();\n\n                ENTRY(MP_BC_LOAD_SUBSCR): {\n                    MARK_EXC_IP_SELECTIVE();\n                    mp_obj_t index = POP();\n                    SET_TOP(mp_obj_subscr(TOP(), index, MP_OBJ_SENTINEL));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_STORE_FAST_N): {\n                    DECODE_UINT;\n                    fastn[-unum] = POP();\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_STORE_DEREF): {\n                    DECODE_UINT;\n                    mp_obj_cell_set(fastn[-unum], POP());\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_STORE_NAME): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_store_name(qst, POP());\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_STORE_GLOBAL): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_store_global(qst, POP());\n                    DISPATCH();\n                }\n\n                #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE\n                ENTRY(MP_BC_STORE_ATTR): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_store_attr(sp[0], qst, sp[-1]);\n                    sp -= 2;\n                    DISPATCH();\n                }\n                #else\n                // This caching code works with MICROPY_PY_BUILTINS_PROPERTY and/or\n                // MICROPY_PY_DESCRIPTORS enabled because if the attr exists in\n                // self->members then it can't be a property or have descriptors.  A\n                // consequence of this is that we can't use MP_MAP_LOOKUP_ADD_IF_NOT_FOUND\n                // in the fast-path below, because that store could override a property.\n                ENTRY(MP_BC_STORE_ATTR): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_map_elem_t *elem = NULL;\n                    mp_obj_t top = TOP();\n                    if (mp_obj_is_instance_type(mp_obj_get_type(top)) && sp[-1] != MP_OBJ_NULL) {\n                        mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);\n                        elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip);\n                    }\n                    if (elem != NULL) {\n                        elem->value = sp[-1];\n                    } else {\n                        mp_store_attr(sp[0], qst, sp[-1]);\n                    }\n                    sp -= 2;\n                    ip++;\n                    DISPATCH();\n                }\n                #endif\n\n                ENTRY(MP_BC_STORE_SUBSCR):\n                    MARK_EXC_IP_SELECTIVE();\n                    mp_obj_subscr(sp[-1], sp[0], sp[-2]);\n                    sp -= 3;\n                    DISPATCH();\n\n                ENTRY(MP_BC_DELETE_FAST): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    if (fastn[-unum] == MP_OBJ_NULL) {\n                        goto local_name_error;\n                    }\n                    fastn[-unum] = MP_OBJ_NULL;\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_DELETE_DEREF): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    if (mp_obj_cell_get(fastn[-unum]) == MP_OBJ_NULL) {\n                        goto local_name_error;\n                    }\n                    mp_obj_cell_set(fastn[-unum], MP_OBJ_NULL);\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_DELETE_NAME): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_delete_name(qst);\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_DELETE_GLOBAL): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_delete_global(qst);\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_DUP_TOP): {\n                    mp_obj_t top = TOP();\n                    PUSH(top);\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_DUP_TOP_TWO):\n                    sp += 2;\n                    sp[0] = sp[-2];\n                    sp[-1] = sp[-3];\n                    DISPATCH();\n\n                ENTRY(MP_BC_POP_TOP):\n                    sp -= 1;\n                    DISPATCH();\n\n                ENTRY(MP_BC_ROT_TWO): {\n                    mp_obj_t top = sp[0];\n                    sp[0] = sp[-1];\n                    sp[-1] = top;\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_ROT_THREE): {\n                    mp_obj_t top = sp[0];\n                    sp[0] = sp[-1];\n                    sp[-1] = sp[-2];\n                    sp[-2] = top;\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_JUMP): {\n                    DECODE_SLABEL;\n                    ip += slab;\n                    DISPATCH_WITH_PEND_EXC_CHECK();\n                }\n\n                ENTRY(MP_BC_POP_JUMP_IF_TRUE): {\n                    DECODE_SLABEL;\n                    if (mp_obj_is_true(POP())) {\n                        ip += slab;\n                    }\n                    DISPATCH_WITH_PEND_EXC_CHECK();\n                }\n\n                ENTRY(MP_BC_POP_JUMP_IF_FALSE): {\n                    DECODE_SLABEL;\n                    if (!mp_obj_is_true(POP())) {\n                        ip += slab;\n                    }\n                    DISPATCH_WITH_PEND_EXC_CHECK();\n                }\n\n                ENTRY(MP_BC_JUMP_IF_TRUE_OR_POP): {\n                    DECODE_SLABEL;\n                    if (mp_obj_is_true(TOP())) {\n                        ip += slab;\n                    } else {\n                        sp--;\n                    }\n                    DISPATCH_WITH_PEND_EXC_CHECK();\n                }\n\n                ENTRY(MP_BC_JUMP_IF_FALSE_OR_POP): {\n                    DECODE_SLABEL;\n                    if (mp_obj_is_true(TOP())) {\n                        sp--;\n                    } else {\n                        ip += slab;\n                    }\n                    DISPATCH_WITH_PEND_EXC_CHECK();\n                }\n\n                ENTRY(MP_BC_SETUP_WITH): {\n                    MARK_EXC_IP_SELECTIVE();\n                    // stack: (..., ctx_mgr)\n                    mp_obj_t obj = TOP();\n                    mp_load_method(obj, MP_QSTR___exit__, sp);\n                    mp_load_method(obj, MP_QSTR___enter__, sp + 2);\n                    mp_obj_t ret = mp_call_method_n_kw(0, 0, sp + 2);\n                    sp += 1;\n                    PUSH_EXC_BLOCK(1);\n                    PUSH(ret);\n                    // stack: (..., __exit__, ctx_mgr, as_value)\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_WITH_CLEANUP): {\n                    MARK_EXC_IP_SELECTIVE();\n                    // Arriving here, there's \"exception control block\" on top of stack,\n                    // and __exit__ method (with self) underneath it. Bytecode calls __exit__,\n                    // and \"deletes\" it off stack, shifting \"exception control block\"\n                    // to its place.\n                    // The bytecode emitter ensures that there is enough space on the Python\n                    // value stack to hold the __exit__ method plus an additional 4 entries.\n                    if (TOP() == mp_const_none) {\n                        // stack: (..., __exit__, ctx_mgr, None)\n                        sp[1] = mp_const_none;\n                        sp[2] = mp_const_none;\n                        sp -= 2;\n                        mp_call_method_n_kw(3, 0, sp);\n                        SET_TOP(mp_const_none);\n                    } else if (mp_obj_is_small_int(TOP())) {\n                        // Getting here there are two distinct cases:\n                        //  - unwind return, stack: (..., __exit__, ctx_mgr, ret_val, SMALL_INT(-1))\n                        //  - unwind jump, stack:   (..., __exit__, ctx_mgr, dest_ip, SMALL_INT(num_exc))\n                        // For both cases we do exactly the same thing.\n                        mp_obj_t data = sp[-1];\n                        mp_obj_t cause = sp[0];\n                        sp[-1] = mp_const_none;\n                        sp[0] = mp_const_none;\n                        sp[1] = mp_const_none;\n                        mp_call_method_n_kw(3, 0, sp - 3);\n                        sp[-3] = data;\n                        sp[-2] = cause;\n                        sp -= 2; // we removed (__exit__, ctx_mgr)\n                    } else {\n                        assert(mp_obj_is_exception_instance(TOP()));\n                        // stack: (..., __exit__, ctx_mgr, exc_instance)\n                        // Need to pass (exc_type, exc_instance, None) as arguments to __exit__.\n                        sp[1] = sp[0];\n                        sp[0] = MP_OBJ_FROM_PTR(mp_obj_get_type(sp[0]));\n                        sp[2] = mp_const_none;\n                        sp -= 2;\n                        mp_obj_t ret_value = mp_call_method_n_kw(3, 0, sp);\n                        if (mp_obj_is_true(ret_value)) {\n                            // We need to silence/swallow the exception.  This is done\n                            // by popping the exception and the __exit__ handler and\n                            // replacing it with None, which signals END_FINALLY to just\n                            // execute the finally handler normally.\n                            SET_TOP(mp_const_none);\n                        } else {\n                            // We need to re-raise the exception.  We pop __exit__ handler\n                            // by copying the exception instance down to the new top-of-stack.\n                            sp[0] = sp[3];\n                        }\n                    }\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_UNWIND_JUMP): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_SLABEL;\n                    PUSH((mp_obj_t)(mp_uint_t)(uintptr_t)(ip + slab)); // push destination ip for jump\n                    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)\nunwind_jump:;\n                    mp_uint_t unum = (mp_uint_t)POP(); // get number of exception handlers to unwind\n                    while ((unum & 0x7f) > 0) {\n                        unum -= 1;\n                        assert(exc_sp >= exc_stack);\n\n                        if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {\n                            if (exc_sp->handler > ip) {\n                                // Found a finally handler that isn't active; run it.\n                                // Getting here the stack looks like:\n                                //     (..., X, dest_ip)\n                                // where X is pointed to by exc_sp->val_sp and in the case\n                                // of a \"with\" block contains the context manager info.\n                                assert(&sp[-1] == MP_TAGPTR_PTR(exc_sp->val_sp));\n                                // We're going to run \"finally\" code as a coroutine\n                                // (not calling it recursively). Set up a sentinel\n                                // on the stack so it can return back to us when it is\n                                // done (when WITH_CLEANUP or END_FINALLY reached).\n                                // The sentinel is the number of exception handlers left to\n                                // unwind, which is a non-negative integer.\n                                PUSH(MP_OBJ_NEW_SMALL_INT(unum));\n                                ip = exc_sp->handler;\n                                goto dispatch_loop;\n                            } else {\n                                // Found a finally handler that is already active; cancel it.\n                                CANCEL_ACTIVE_FINALLY(sp);\n                            }\n                        }\n                        POP_EXC_BLOCK();\n                    }\n                    ip = (const byte*)MP_OBJ_TO_PTR(POP()); // pop destination ip for jump\n                    if (unum != 0) {\n                        // pop the exhausted iterator\n                        sp -= MP_OBJ_ITER_BUF_NSLOTS;\n                    }\n                    DISPATCH_WITH_PEND_EXC_CHECK();\n                }\n\n                ENTRY(MP_BC_SETUP_EXCEPT):\n                ENTRY(MP_BC_SETUP_FINALLY): {\n                    MARK_EXC_IP_SELECTIVE();\n                    #if SELECTIVE_EXC_IP\n                    PUSH_EXC_BLOCK((code_state->ip[-1] == MP_BC_SETUP_FINALLY) ? 1 : 0);\n                    #else\n                    PUSH_EXC_BLOCK((code_state->ip[0] == MP_BC_SETUP_FINALLY) ? 1 : 0);\n                    #endif\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_END_FINALLY):\n                    MARK_EXC_IP_SELECTIVE();\n                    // if TOS is None, just pops it and continues\n                    // if TOS is an integer, finishes coroutine and returns control to caller\n                    // if TOS is an exception, reraises the exception\n                    assert(exc_sp >= exc_stack);\n                    POP_EXC_BLOCK();\n                    if (TOP() == mp_const_none) {\n                        sp--;\n                    } else if (mp_obj_is_small_int(TOP())) {\n                        // We finished \"finally\" coroutine and now dispatch back\n                        // to our caller, based on TOS value\n                        mp_int_t cause = MP_OBJ_SMALL_INT_VALUE(POP());\n                        if (cause < 0) {\n                            // A negative cause indicates unwind return\n                            goto unwind_return;\n                        } else {\n                            // Otherwise it's an unwind jump and we must push as a raw\n                            // number the number of exception handlers to unwind\n                            PUSH((mp_obj_t)cause);\n                            goto unwind_jump;\n                        }\n                    } else {\n                        assert(mp_obj_is_exception_instance(TOP()));\n                        RAISE(TOP());\n                    }\n                    DISPATCH();\n\n                ENTRY(MP_BC_GET_ITER):\n                    MARK_EXC_IP_SELECTIVE();\n                    SET_TOP(mp_getiter(TOP(), NULL));\n                    DISPATCH();\n\n                // An iterator for a for-loop takes MP_OBJ_ITER_BUF_NSLOTS slots on\n                // the Python value stack.  These slots are either used to store the\n                // iterator object itself, or the first slot is MP_OBJ_NULL and\n                // the second slot holds a reference to the iterator object.\n                ENTRY(MP_BC_GET_ITER_STACK): {\n                    MARK_EXC_IP_SELECTIVE();\n                    mp_obj_t obj = TOP();\n                    mp_obj_iter_buf_t *iter_buf = (mp_obj_iter_buf_t*)sp;\n                    sp += MP_OBJ_ITER_BUF_NSLOTS - 1;\n                    obj = mp_getiter(obj, iter_buf);\n                    if (obj != MP_OBJ_FROM_PTR(iter_buf)) {\n                        // Iterator didn't use the stack so indicate that with MP_OBJ_NULL.\n                        sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] = MP_OBJ_NULL;\n                        sp[-MP_OBJ_ITER_BUF_NSLOTS + 2] = obj;\n                    }\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_FOR_ITER): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward\n                    code_state->sp = sp;\n                    mp_obj_t obj;\n                    if (sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] == MP_OBJ_NULL) {\n                        obj = sp[-MP_OBJ_ITER_BUF_NSLOTS + 2];\n                    } else {\n                        obj = MP_OBJ_FROM_PTR(&sp[-MP_OBJ_ITER_BUF_NSLOTS + 1]);\n                    }\n                    mp_obj_t value = mp_iternext_allow_raise(obj);\n                    if (value == MP_OBJ_STOP_ITERATION) {\n                        sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator\n                        ip += ulab; // jump to after for-block\n                    } else {\n                        PUSH(value); // push the next iteration value\n                        #if MICROPY_PY_SYS_SETTRACE\n                        // LINE event should trigger for every iteration so invalidate last trigger\n                        if (code_state->frame) {\n                            code_state->frame->lineno = 0;\n                        }\n                        #endif\n                    }\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_POP_EXCEPT_JUMP): {\n                    assert(exc_sp >= exc_stack);\n                    POP_EXC_BLOCK();\n                    DECODE_ULABEL;\n                    ip += ulab;\n                    DISPATCH_WITH_PEND_EXC_CHECK();\n                }\n\n                ENTRY(MP_BC_BUILD_TUPLE): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    sp -= unum - 1;\n                    SET_TOP(mp_obj_new_tuple(unum, sp));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_BUILD_LIST): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    sp -= unum - 1;\n                    SET_TOP(mp_obj_new_list(unum, sp));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_BUILD_MAP): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    PUSH(mp_obj_new_dict(unum));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_STORE_MAP):\n                    MARK_EXC_IP_SELECTIVE();\n                    sp -= 2;\n                    mp_obj_dict_store(sp[0], sp[2], sp[1]);\n                    DISPATCH();\n\n#if MICROPY_PY_BUILTINS_SET\n                ENTRY(MP_BC_BUILD_SET): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    sp -= unum - 1;\n                    SET_TOP(mp_obj_new_set(unum, sp));\n                    DISPATCH();\n                }\n#endif\n\n#if MICROPY_PY_BUILTINS_SLICE\n                ENTRY(MP_BC_BUILD_SLICE): {\n                    MARK_EXC_IP_SELECTIVE();\n                    mp_obj_t step = mp_const_none;\n                    if (*ip++ == 3) {\n                        // 3-argument slice includes step\n                        step = POP();\n                    }\n                    mp_obj_t stop = POP();\n                    mp_obj_t start = TOP();\n                    SET_TOP(mp_obj_new_slice(start, stop, step));\n                    DISPATCH();\n                }\n#endif\n\n                ENTRY(MP_BC_STORE_COMP): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    mp_obj_t obj = sp[-(unum >> 2)];\n                    if ((unum & 3) == 0) {\n                        mp_obj_list_append(obj, sp[0]);\n                        sp--;\n                    } else if (!MICROPY_PY_BUILTINS_SET || (unum & 3) == 1) {\n                        mp_obj_dict_store(obj, sp[0], sp[-1]);\n                        sp -= 2;\n                    #if MICROPY_PY_BUILTINS_SET\n                    } else {\n                        mp_obj_set_store(obj, sp[0]);\n                        sp--;\n                    #endif\n                    }\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_UNPACK_SEQUENCE): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    mp_unpack_sequence(sp[0], unum, sp);\n                    sp += unum - 1;\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_UNPACK_EX): {\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    mp_unpack_ex(sp[0], unum, sp);\n                    sp += (unum & 0xff) + ((unum >> 8) & 0xff);\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_MAKE_FUNCTION): {\n                    DECODE_PTR;\n                    PUSH(mp_make_function_from_raw_code(ptr, MP_OBJ_NULL, MP_OBJ_NULL));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_MAKE_FUNCTION_DEFARGS): {\n                    DECODE_PTR;\n                    // Stack layout: def_tuple def_dict <- TOS\n                    mp_obj_t def_dict = POP();\n                    SET_TOP(mp_make_function_from_raw_code(ptr, TOP(), def_dict));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_MAKE_CLOSURE): {\n                    DECODE_PTR;\n                    size_t n_closed_over = *ip++;\n                    // Stack layout: closed_overs <- TOS\n                    sp -= n_closed_over - 1;\n                    SET_TOP(mp_make_closure_from_raw_code(ptr, n_closed_over, sp));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_MAKE_CLOSURE_DEFARGS): {\n                    DECODE_PTR;\n                    size_t n_closed_over = *ip++;\n                    // Stack layout: def_tuple def_dict closed_overs <- TOS\n                    sp -= 2 + n_closed_over - 1;\n                    SET_TOP(mp_make_closure_from_raw_code(ptr, 0x100 | n_closed_over, sp));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_CALL_FUNCTION): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    // unum & 0xff == n_positional\n                    // (unum >> 8) & 0xff == n_keyword\n                    sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe);\n                    #if MICROPY_STACKLESS\n                    if (mp_obj_get_type(*sp) == &mp_type_fun_bc) {\n                        code_state->ip = ip;\n                        code_state->sp = sp;\n                        code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp);\n                        mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1);\n                        #if !MICROPY_ENABLE_PYSTACK\n                        if (new_state == NULL) {\n                            // Couldn't allocate codestate on heap: in the strict case raise\n                            // an exception, otherwise just fall through to stack allocation.\n                            #if MICROPY_STACKLESS_STRICT\n                        deep_recursion_error:\n                            mp_raise_recursion_depth();\n                            #endif\n                        } else\n                        #endif\n                        {\n                            new_state->prev = code_state;\n                            code_state = new_state;\n                            nlr_pop();\n                            goto run_code_state;\n                        }\n                    }\n                    #endif\n                    SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_CALL_FUNCTION_VAR_KW): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    // unum & 0xff == n_positional\n                    // (unum >> 8) & 0xff == n_keyword\n                    // We have following stack layout here:\n                    // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS\n                    sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 2;\n                    #if MICROPY_STACKLESS\n                    if (mp_obj_get_type(*sp) == &mp_type_fun_bc) {\n                        code_state->ip = ip;\n                        code_state->sp = sp;\n                        code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp);\n\n                        mp_call_args_t out_args;\n                        mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args);\n\n                        mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun,\n                            out_args.n_args, out_args.n_kw, out_args.args);\n                        #if !MICROPY_ENABLE_PYSTACK\n                        // Freeing args at this point does not follow a LIFO order so only do it if\n                        // pystack is not enabled.  For pystack, they are freed when code_state is.\n                        mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t));\n                        #endif\n                        #if !MICROPY_ENABLE_PYSTACK\n                        if (new_state == NULL) {\n                            // Couldn't allocate codestate on heap: in the strict case raise\n                            // an exception, otherwise just fall through to stack allocation.\n                            #if MICROPY_STACKLESS_STRICT\n                            goto deep_recursion_error;\n                            #endif\n                        } else\n                        #endif\n                        {\n                            new_state->prev = code_state;\n                            code_state = new_state;\n                            nlr_pop();\n                            goto run_code_state;\n                        }\n                    }\n                    #endif\n                    SET_TOP(mp_call_method_n_kw_var(false, unum, sp));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_CALL_METHOD): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    // unum & 0xff == n_positional\n                    // (unum >> 8) & 0xff == n_keyword\n                    sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1;\n                    #if MICROPY_STACKLESS\n                    if (mp_obj_get_type(*sp) == &mp_type_fun_bc) {\n                        code_state->ip = ip;\n                        code_state->sp = sp;\n                        code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp);\n\n                        size_t n_args = unum & 0xff;\n                        size_t n_kw = (unum >> 8) & 0xff;\n                        int adjust = (sp[1] == MP_OBJ_NULL) ? 0 : 1;\n\n                        mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust);\n                        #if !MICROPY_ENABLE_PYSTACK\n                        if (new_state == NULL) {\n                            // Couldn't allocate codestate on heap: in the strict case raise\n                            // an exception, otherwise just fall through to stack allocation.\n                            #if MICROPY_STACKLESS_STRICT\n                            goto deep_recursion_error;\n                            #endif\n                        } else\n                        #endif\n                        {\n                            new_state->prev = code_state;\n                            code_state = new_state;\n                            nlr_pop();\n                            goto run_code_state;\n                        }\n                    }\n                    #endif\n                    SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_CALL_METHOD_VAR_KW): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_UINT;\n                    // unum & 0xff == n_positional\n                    // (unum >> 8) & 0xff == n_keyword\n                    // We have following stack layout here:\n                    // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS\n                    sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 3;\n                    #if MICROPY_STACKLESS\n                    if (mp_obj_get_type(*sp) == &mp_type_fun_bc) {\n                        code_state->ip = ip;\n                        code_state->sp = sp;\n                        code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp);\n\n                        mp_call_args_t out_args;\n                        mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args);\n\n                        mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun,\n                            out_args.n_args, out_args.n_kw, out_args.args);\n                        #if !MICROPY_ENABLE_PYSTACK\n                        // Freeing args at this point does not follow a LIFO order so only do it if\n                        // pystack is not enabled.  For pystack, they are freed when code_state is.\n                        mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t));\n                        #endif\n                        #if !MICROPY_ENABLE_PYSTACK\n                        if (new_state == NULL) {\n                            // Couldn't allocate codestate on heap: in the strict case raise\n                            // an exception, otherwise just fall through to stack allocation.\n                            #if MICROPY_STACKLESS_STRICT\n                            goto deep_recursion_error;\n                            #endif\n                        } else\n                        #endif\n                        {\n                            new_state->prev = code_state;\n                            code_state = new_state;\n                            nlr_pop();\n                            goto run_code_state;\n                        }\n                    }\n                    #endif\n                    SET_TOP(mp_call_method_n_kw_var(true, unum, sp));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_RETURN_VALUE):\n                    MARK_EXC_IP_SELECTIVE();\nunwind_return:\n                    // Search for and execute finally handlers that aren't already active\n                    while (exc_sp >= exc_stack) {\n                        if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {\n                            if (exc_sp->handler > ip) {\n                                // Found a finally handler that isn't active; run it.\n                                // Getting here the stack looks like:\n                                //     (..., X, [iter0, iter1, ...,] ret_val)\n                                // where X is pointed to by exc_sp->val_sp and in the case\n                                // of a \"with\" block contains the context manager info.\n                                // There may be 0 or more for-iterators between X and the\n                                // return value, and these must be removed before control can\n                                // pass to the finally code.  We simply copy the ret_value down\n                                // over these iterators, if they exist.  If they don't then the\n                                // following is a null operation.\n                                mp_obj_t *finally_sp = MP_TAGPTR_PTR(exc_sp->val_sp);\n                                finally_sp[1] = sp[0];\n                                sp = &finally_sp[1];\n                                // We're going to run \"finally\" code as a coroutine\n                                // (not calling it recursively). Set up a sentinel\n                                // on a stack so it can return back to us when it is\n                                // done (when WITH_CLEANUP or END_FINALLY reached).\n                                PUSH(MP_OBJ_NEW_SMALL_INT(-1));\n                                ip = exc_sp->handler;\n                                goto dispatch_loop;\n                            } else {\n                                // Found a finally handler that is already active; cancel it.\n                                CANCEL_ACTIVE_FINALLY(sp);\n                            }\n                        }\n                        POP_EXC_BLOCK();\n                    }\n                    nlr_pop();\n                    code_state->sp = sp;\n                    assert(exc_sp == exc_stack - 1);\n                    MICROPY_VM_HOOK_RETURN\n                    #if MICROPY_STACKLESS\n                    if (code_state->prev != NULL) {\n                        mp_obj_t res = *sp;\n                        mp_globals_set(code_state->old_globals);\n                        mp_code_state_t *new_code_state = code_state->prev;\n                        #if MICROPY_ENABLE_PYSTACK\n                        // Free code_state, and args allocated by mp_call_prepare_args_n_kw_var\n                        // (The latter is implicitly freed when using pystack due to its LIFO nature.)\n                        // The sizeof in the following statement does not include the size of the variable\n                        // part of the struct.  This arg is anyway not used if pystack is enabled.\n                        mp_nonlocal_free(code_state, sizeof(mp_code_state_t));\n                        #endif\n                        code_state = new_code_state;\n                        *code_state->sp = res;\n                        goto run_code_state_from_return;\n                    }\n                    #endif\n                    FRAME_LEAVE();\n                    return MP_VM_RETURN_NORMAL;\n\n                ENTRY(MP_BC_RAISE_LAST): {\n                    MARK_EXC_IP_SELECTIVE();\n                    // search for the inner-most previous exception, to reraise it\n                    mp_obj_t obj = MP_OBJ_NULL;\n                    for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; --e) {\n                        if (e->prev_exc != NULL) {\n                            obj = MP_OBJ_FROM_PTR(e->prev_exc);\n                            break;\n                        }\n                    }\n                    if (obj == MP_OBJ_NULL) {\n                        obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, MP_ERROR_TEXT(\"no active exception to reraise\"));\n                    }\n                    RAISE(obj);\n                }\n\n                ENTRY(MP_BC_RAISE_OBJ): {\n                    MARK_EXC_IP_SELECTIVE();\n                    mp_obj_t obj = mp_make_raise_obj(TOP());\n                    RAISE(obj);\n                }\n\n                ENTRY(MP_BC_RAISE_FROM): {\n                    MARK_EXC_IP_SELECTIVE();\n                    mp_warning(NULL, \"exception chaining not supported\");\n                    sp--; // ignore (pop) \"from\" argument\n                    mp_obj_t obj = mp_make_raise_obj(TOP());\n                    RAISE(obj);\n                }\n\n                ENTRY(MP_BC_YIELD_VALUE):\nyield:\n                    nlr_pop();\n                    code_state->ip = ip;\n                    code_state->sp = sp;\n                    code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp);\n                    FRAME_LEAVE();\n                    return MP_VM_RETURN_YIELD;\n\n                ENTRY(MP_BC_YIELD_FROM): {\n                    MARK_EXC_IP_SELECTIVE();\n//#define EXC_MATCH(exc, type) mp_obj_is_type(exc, type)\n#define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type)\n#define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { mp_obj_t raise_t = mp_make_raise_obj(t); RAISE(raise_t); }\n                    mp_vm_return_kind_t ret_kind;\n                    mp_obj_t send_value = POP();\n                    mp_obj_t t_exc = MP_OBJ_NULL;\n                    mp_obj_t ret_value;\n                    code_state->sp = sp; // Save sp because it's needed if mp_resume raises StopIteration\n                    if (inject_exc != MP_OBJ_NULL) {\n                        t_exc = inject_exc;\n                        inject_exc = MP_OBJ_NULL;\n                        ret_kind = mp_resume(TOP(), MP_OBJ_NULL, t_exc, &ret_value);\n                    } else {\n                        ret_kind = mp_resume(TOP(), send_value, MP_OBJ_NULL, &ret_value);\n                    }\n\n                    if (ret_kind == MP_VM_RETURN_YIELD) {\n                        ip--;\n                        PUSH(ret_value);\n                        goto yield;\n                    } else if (ret_kind == MP_VM_RETURN_NORMAL) {\n                        // Pop exhausted gen\n                        sp--;\n                        if (ret_value == MP_OBJ_STOP_ITERATION) {\n                            // Optimize StopIteration\n                            // TODO: get StopIteration's value\n                            PUSH(mp_const_none);\n                        } else {\n                            PUSH(ret_value);\n                        }\n\n                        // If we injected GeneratorExit downstream, then even\n                        // if it was swallowed, we re-raise GeneratorExit\n                        GENERATOR_EXIT_IF_NEEDED(t_exc);\n                        DISPATCH();\n                    } else {\n                        assert(ret_kind == MP_VM_RETURN_EXCEPTION);\n                        assert(!EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration)));\n                        // Pop exhausted gen\n                        sp--;\n                        RAISE(ret_value);\n                    }\n                }\n\n                ENTRY(MP_BC_IMPORT_NAME): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_obj_t obj = POP();\n                    SET_TOP(mp_import_name(qst, obj, TOP()));\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_IMPORT_FROM): {\n                    FRAME_UPDATE();\n                    MARK_EXC_IP_SELECTIVE();\n                    DECODE_QSTR;\n                    mp_obj_t obj = mp_import_from(TOP(), qst);\n                    PUSH(obj);\n                    DISPATCH();\n                }\n\n                ENTRY(MP_BC_IMPORT_STAR):\n                    MARK_EXC_IP_SELECTIVE();\n                    mp_import_all(POP());\n                    DISPATCH();\n\n#if MICROPY_OPT_COMPUTED_GOTO\n                ENTRY(MP_BC_LOAD_CONST_SMALL_INT_MULTI):\n                    PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS));\n                    DISPATCH();\n\n                ENTRY(MP_BC_LOAD_FAST_MULTI):\n                    obj_shared = fastn[MP_BC_LOAD_FAST_MULTI - (mp_int_t)ip[-1]];\n                    goto load_check;\n\n                ENTRY(MP_BC_STORE_FAST_MULTI):\n                    fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP();\n                    DISPATCH();\n\n                ENTRY(MP_BC_UNARY_OP_MULTI):\n                    MARK_EXC_IP_SELECTIVE();\n                    SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP()));\n                    DISPATCH();\n\n                ENTRY(MP_BC_BINARY_OP_MULTI): {\n                    MARK_EXC_IP_SELECTIVE();\n                    mp_obj_t rhs = POP();\n                    mp_obj_t lhs = TOP();\n                    SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs));\n                    DISPATCH();\n                }\n\n                ENTRY_DEFAULT:\n                    MARK_EXC_IP_SELECTIVE();\n#else\n                ENTRY_DEFAULT:\n                    if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + MP_BC_LOAD_CONST_SMALL_INT_MULTI_NUM) {\n                        PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS));\n                        DISPATCH();\n                    } else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + MP_BC_LOAD_FAST_MULTI_NUM) {\n                        obj_shared = fastn[MP_BC_LOAD_FAST_MULTI - (mp_int_t)ip[-1]];\n                        goto load_check;\n                    } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + MP_BC_STORE_FAST_MULTI_NUM) {\n                        fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP();\n                        DISPATCH();\n                    } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_BC_UNARY_OP_MULTI_NUM) {\n                        SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP()));\n                        DISPATCH();\n                    } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BC_BINARY_OP_MULTI_NUM) {\n                        mp_obj_t rhs = POP();\n                        mp_obj_t lhs = TOP();\n                        SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs));\n                        DISPATCH();\n                    } else\n#endif\n                {\n\n                    mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, MP_ERROR_TEXT(\"opcode\"));\n                    nlr_pop();\n                    code_state->state[0] = obj;\n                    FRAME_LEAVE();\n                    return MP_VM_RETURN_EXCEPTION;\n                }\n\n#if !MICROPY_OPT_COMPUTED_GOTO\n                } // switch\n#endif\n\npending_exception_check:\n                MICROPY_VM_HOOK_LOOP\n\n                #if MICROPY_ENABLE_SCHEDULER\n                // This is an inlined variant of mp_handle_pending\n                if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) {\n                    mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();\n                    // Re-check state is still pending now that we're in the atomic section.\n                    if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) {\n                        MARK_EXC_IP_SELECTIVE();\n                        mp_obj_t obj = MP_STATE_VM(mp_pending_exception);\n                        if (obj != MP_OBJ_NULL) {\n                            MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;\n                            if (!mp_sched_num_pending()) {\n                                MP_STATE_VM(sched_state) = MP_SCHED_IDLE;\n                            }\n                            MICROPY_END_ATOMIC_SECTION(atomic_state);\n                            RAISE(obj);\n                        }\n                        mp_handle_pending_tail(atomic_state);\n                    } else {\n                        MICROPY_END_ATOMIC_SECTION(atomic_state);\n                    }\n                }\n                #else\n                // This is an inlined variant of mp_handle_pending\n                if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {\n                    MARK_EXC_IP_SELECTIVE();\n                    mp_obj_t obj = MP_STATE_VM(mp_pending_exception);\n                    MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;\n                    RAISE(obj);\n                }\n                #endif\n\n                #if MICROPY_PY_THREAD_GIL\n                #if MICROPY_PY_THREAD_GIL_VM_DIVISOR\n                if (--gil_divisor == 0)\n                #endif\n                {\n                    #if MICROPY_PY_THREAD_GIL_VM_DIVISOR\n                    gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR;\n                    #endif\n                    #if MICROPY_ENABLE_SCHEDULER\n                    // can only switch threads if the scheduler is unlocked\n                    if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE)\n                    #endif\n                    {\n                    MP_THREAD_GIL_EXIT();\n                    MP_THREAD_GIL_ENTER();\n                    }\n                }\n                #endif\n\n            } // for loop\n\n        } else {\nexception_handler:\n            // exception occurred\n\n            #if MICROPY_PY_SYS_EXC_INFO\n            MP_STATE_VM(cur_exception) = nlr.ret_val;\n            #endif\n\n            #if SELECTIVE_EXC_IP\n            // with selective ip, we store the ip 1 byte past the opcode, so move ptr back\n            code_state->ip -= 1;\n            #endif\n\n            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))) {\n                if (code_state->ip) {\n                    // check if it's a StopIteration within a for block\n                    if (*code_state->ip == MP_BC_FOR_ITER) {\n                        const byte *ip = code_state->ip + 1;\n                        DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward\n                        code_state->ip = ip + ulab; // jump to after for-block\n                        code_state->sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator\n                        goto outer_dispatch_loop; // continue with dispatch loop\n                    } else if (*code_state->ip == MP_BC_YIELD_FROM) {\n                        // StopIteration inside yield from call means return a value of\n                        // yield from, so inject exception's value as yield from's result\n                        // (Instead of stack pop then push we just replace exhausted gen with value)\n                        *code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val));\n                        code_state->ip++; // yield from is over, move to next instruction\n                        goto outer_dispatch_loop; // continue with dispatch loop\n                    }\n                }\n            }\n\n            #if MICROPY_PY_SYS_SETTRACE\n            // Exceptions are traced here\n            if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_Exception))) {\n                TRACE_TICK(code_state->ip, code_state->sp, true /* yes, it's an exception */);\n            }\n            #endif\n\n#if MICROPY_STACKLESS\nunwind_loop:\n#endif\n            // Set traceback info (file and line number) where the exception occurred, but not for:\n            // - constant GeneratorExit object, because it's const\n            // - exceptions re-raised by END_FINALLY\n            // - exceptions re-raised explicitly by \"raise\"\n            if (nlr.ret_val != &mp_const_GeneratorExit_obj\n                && *code_state->ip != MP_BC_END_FINALLY\n                && *code_state->ip != MP_BC_RAISE_LAST) {\n                const byte *ip = code_state->fun_bc->bytecode;\n                MP_BC_PRELUDE_SIG_DECODE(ip);\n                MP_BC_PRELUDE_SIZE_DECODE(ip);\n                const byte *bytecode_start = ip + n_info + n_cell;\n                #if !MICROPY_PERSISTENT_CODE\n                // so bytecode is aligned\n                bytecode_start = MP_ALIGN(bytecode_start, sizeof(mp_uint_t));\n                #endif\n                size_t bc = code_state->ip - bytecode_start;\n                #if MICROPY_PERSISTENT_CODE\n                qstr block_name = ip[0] | (ip[1] << 8);\n                qstr source_file = ip[2] | (ip[3] << 8);\n                ip += 4;\n                #else\n                qstr block_name = mp_decode_uint_value(ip);\n                ip = mp_decode_uint_skip(ip);\n                qstr source_file = mp_decode_uint_value(ip);\n                ip = mp_decode_uint_skip(ip);\n                #endif\n                size_t source_line = mp_bytecode_get_source_line(ip, bc);\n                mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(nlr.ret_val), source_file, source_line, block_name);\n            }\n\n            while (exc_sp >= exc_stack && exc_sp->handler <= code_state->ip) {\n\n                // nested exception\n\n                assert(exc_sp >= exc_stack);\n\n                // TODO make a proper message for nested exception\n                // at the moment we are just raising the very last exception (the one that caused the nested exception)\n\n                // move up to previous exception handler\n                POP_EXC_BLOCK();\n            }\n\n            if (exc_sp >= exc_stack) {\n                // catch exception and pass to byte code\n                code_state->ip = exc_sp->handler;\n                mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp);\n                // save this exception in the stack so it can be used in a reraise, if needed\n                exc_sp->prev_exc = nlr.ret_val;\n                // push exception object so it can be handled by bytecode\n                PUSH(MP_OBJ_FROM_PTR(nlr.ret_val));\n                code_state->sp = sp;\n\n            #if MICROPY_STACKLESS\n            } else if (code_state->prev != NULL) {\n                mp_globals_set(code_state->old_globals);\n                mp_code_state_t *new_code_state = code_state->prev;\n                #if MICROPY_ENABLE_PYSTACK\n                // Free code_state, and args allocated by mp_call_prepare_args_n_kw_var\n                // (The latter is implicitly freed when using pystack due to its LIFO nature.)\n                // The sizeof in the following statement does not include the size of the variable\n                // part of the struct.  This arg is anyway not used if pystack is enabled.\n                mp_nonlocal_free(code_state, sizeof(mp_code_state_t));\n                #endif\n                code_state = new_code_state;\n                size_t n_state = code_state->n_state;\n                fastn = &code_state->state[n_state - 1];\n                exc_stack = (mp_exc_stack_t*)(code_state->state + n_state);\n                // variables that are visible to the exception handler (declared volatile)\n                exc_sp = MP_CODE_STATE_EXC_SP_IDX_TO_PTR(exc_stack, code_state->exc_sp_idx); // stack grows up, exc_sp points to top of stack\n                goto unwind_loop;\n\n            #endif\n            } else {\n                // propagate exception to higher level\n                // Note: ip and sp don't have usable values at this point\n                code_state->state[0] = MP_OBJ_FROM_PTR(nlr.ret_val); // put exception here because sp is invalid\n                FRAME_LEAVE();\n                return MP_VM_RETURN_EXCEPTION;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "py/vmentrytable.h",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n// *FORMAT-OFF*\n\n#if __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Winitializer-overrides\"\n#endif // __clang__\n#if __GNUC__ >= 5\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Woverride-init\"\n#endif // __GNUC__ >= 5\n\nstatic const void *const entry_table[256] = {\n    [0 ... 255] = &&entry_default,\n    [MP_BC_LOAD_CONST_FALSE] = &&entry_MP_BC_LOAD_CONST_FALSE,\n    [MP_BC_LOAD_CONST_NONE] = &&entry_MP_BC_LOAD_CONST_NONE,\n    [MP_BC_LOAD_CONST_TRUE] = &&entry_MP_BC_LOAD_CONST_TRUE,\n    [MP_BC_LOAD_CONST_SMALL_INT] = &&entry_MP_BC_LOAD_CONST_SMALL_INT,\n    [MP_BC_LOAD_CONST_STRING] = &&entry_MP_BC_LOAD_CONST_STRING,\n    [MP_BC_LOAD_CONST_OBJ] = &&entry_MP_BC_LOAD_CONST_OBJ,\n    [MP_BC_LOAD_NULL] = &&entry_MP_BC_LOAD_NULL,\n    [MP_BC_LOAD_FAST_N] = &&entry_MP_BC_LOAD_FAST_N,\n    [MP_BC_LOAD_DEREF] = &&entry_MP_BC_LOAD_DEREF,\n    [MP_BC_LOAD_NAME] = &&entry_MP_BC_LOAD_NAME,\n    [MP_BC_LOAD_GLOBAL] = &&entry_MP_BC_LOAD_GLOBAL,\n    [MP_BC_LOAD_ATTR] = &&entry_MP_BC_LOAD_ATTR,\n    [MP_BC_LOAD_METHOD] = &&entry_MP_BC_LOAD_METHOD,\n    [MP_BC_LOAD_SUPER_METHOD] = &&entry_MP_BC_LOAD_SUPER_METHOD,\n    [MP_BC_LOAD_BUILD_CLASS] = &&entry_MP_BC_LOAD_BUILD_CLASS,\n    [MP_BC_LOAD_SUBSCR] = &&entry_MP_BC_LOAD_SUBSCR,\n    [MP_BC_STORE_FAST_N] = &&entry_MP_BC_STORE_FAST_N,\n    [MP_BC_STORE_DEREF] = &&entry_MP_BC_STORE_DEREF,\n    [MP_BC_STORE_NAME] = &&entry_MP_BC_STORE_NAME,\n    [MP_BC_STORE_GLOBAL] = &&entry_MP_BC_STORE_GLOBAL,\n    [MP_BC_STORE_ATTR] = &&entry_MP_BC_STORE_ATTR,\n    [MP_BC_STORE_SUBSCR] = &&entry_MP_BC_STORE_SUBSCR,\n    [MP_BC_DELETE_FAST] = &&entry_MP_BC_DELETE_FAST,\n    [MP_BC_DELETE_DEREF] = &&entry_MP_BC_DELETE_DEREF,\n    [MP_BC_DELETE_NAME] = &&entry_MP_BC_DELETE_NAME,\n    [MP_BC_DELETE_GLOBAL] = &&entry_MP_BC_DELETE_GLOBAL,\n    [MP_BC_DUP_TOP] = &&entry_MP_BC_DUP_TOP,\n    [MP_BC_DUP_TOP_TWO] = &&entry_MP_BC_DUP_TOP_TWO,\n    [MP_BC_POP_TOP] = &&entry_MP_BC_POP_TOP,\n    [MP_BC_ROT_TWO] = &&entry_MP_BC_ROT_TWO,\n    [MP_BC_ROT_THREE] = &&entry_MP_BC_ROT_THREE,\n    [MP_BC_JUMP] = &&entry_MP_BC_JUMP,\n    [MP_BC_POP_JUMP_IF_TRUE] = &&entry_MP_BC_POP_JUMP_IF_TRUE,\n    [MP_BC_POP_JUMP_IF_FALSE] = &&entry_MP_BC_POP_JUMP_IF_FALSE,\n    [MP_BC_JUMP_IF_TRUE_OR_POP] = &&entry_MP_BC_JUMP_IF_TRUE_OR_POP,\n    [MP_BC_JUMP_IF_FALSE_OR_POP] = &&entry_MP_BC_JUMP_IF_FALSE_OR_POP,\n    [MP_BC_SETUP_WITH] = &&entry_MP_BC_SETUP_WITH,\n    [MP_BC_WITH_CLEANUP] = &&entry_MP_BC_WITH_CLEANUP,\n    [MP_BC_UNWIND_JUMP] = &&entry_MP_BC_UNWIND_JUMP,\n    [MP_BC_SETUP_EXCEPT] = &&entry_MP_BC_SETUP_EXCEPT,\n    [MP_BC_SETUP_FINALLY] = &&entry_MP_BC_SETUP_FINALLY,\n    [MP_BC_END_FINALLY] = &&entry_MP_BC_END_FINALLY,\n    [MP_BC_GET_ITER] = &&entry_MP_BC_GET_ITER,\n    [MP_BC_GET_ITER_STACK] = &&entry_MP_BC_GET_ITER_STACK,\n    [MP_BC_FOR_ITER] = &&entry_MP_BC_FOR_ITER,\n    [MP_BC_POP_EXCEPT_JUMP] = &&entry_MP_BC_POP_EXCEPT_JUMP,\n    [MP_BC_BUILD_TUPLE] = &&entry_MP_BC_BUILD_TUPLE,\n    [MP_BC_BUILD_LIST] = &&entry_MP_BC_BUILD_LIST,\n    [MP_BC_BUILD_MAP] = &&entry_MP_BC_BUILD_MAP,\n    [MP_BC_STORE_MAP] = &&entry_MP_BC_STORE_MAP,\n    #if MICROPY_PY_BUILTINS_SET\n    [MP_BC_BUILD_SET] = &&entry_MP_BC_BUILD_SET,\n    #endif\n    #if MICROPY_PY_BUILTINS_SLICE\n    [MP_BC_BUILD_SLICE] = &&entry_MP_BC_BUILD_SLICE,\n    #endif\n    [MP_BC_STORE_COMP] = &&entry_MP_BC_STORE_COMP,\n    [MP_BC_UNPACK_SEQUENCE] = &&entry_MP_BC_UNPACK_SEQUENCE,\n    [MP_BC_UNPACK_EX] = &&entry_MP_BC_UNPACK_EX,\n    [MP_BC_MAKE_FUNCTION] = &&entry_MP_BC_MAKE_FUNCTION,\n    [MP_BC_MAKE_FUNCTION_DEFARGS] = &&entry_MP_BC_MAKE_FUNCTION_DEFARGS,\n    [MP_BC_MAKE_CLOSURE] = &&entry_MP_BC_MAKE_CLOSURE,\n    [MP_BC_MAKE_CLOSURE_DEFARGS] = &&entry_MP_BC_MAKE_CLOSURE_DEFARGS,\n    [MP_BC_CALL_FUNCTION] = &&entry_MP_BC_CALL_FUNCTION,\n    [MP_BC_CALL_FUNCTION_VAR_KW] = &&entry_MP_BC_CALL_FUNCTION_VAR_KW,\n    [MP_BC_CALL_METHOD] = &&entry_MP_BC_CALL_METHOD,\n    [MP_BC_CALL_METHOD_VAR_KW] = &&entry_MP_BC_CALL_METHOD_VAR_KW,\n    [MP_BC_RETURN_VALUE] = &&entry_MP_BC_RETURN_VALUE,\n    [MP_BC_RAISE_LAST] = &&entry_MP_BC_RAISE_LAST,\n    [MP_BC_RAISE_OBJ] = &&entry_MP_BC_RAISE_OBJ,\n    [MP_BC_RAISE_FROM] = &&entry_MP_BC_RAISE_FROM,\n    [MP_BC_YIELD_VALUE] = &&entry_MP_BC_YIELD_VALUE,\n    [MP_BC_YIELD_FROM] = &&entry_MP_BC_YIELD_FROM,\n    [MP_BC_IMPORT_NAME] = &&entry_MP_BC_IMPORT_NAME,\n    [MP_BC_IMPORT_FROM] = &&entry_MP_BC_IMPORT_FROM,\n    [MP_BC_IMPORT_STAR] = &&entry_MP_BC_IMPORT_STAR,\n    [MP_BC_LOAD_CONST_SMALL_INT_MULTI ... MP_BC_LOAD_CONST_SMALL_INT_MULTI + MP_BC_LOAD_CONST_SMALL_INT_MULTI_NUM - 1] = &&entry_MP_BC_LOAD_CONST_SMALL_INT_MULTI,\n    [MP_BC_LOAD_FAST_MULTI ... MP_BC_LOAD_FAST_MULTI + MP_BC_LOAD_FAST_MULTI_NUM - 1] = &&entry_MP_BC_LOAD_FAST_MULTI,\n    [MP_BC_STORE_FAST_MULTI ... MP_BC_STORE_FAST_MULTI + MP_BC_STORE_FAST_MULTI_NUM - 1] = &&entry_MP_BC_STORE_FAST_MULTI,\n    [MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + MP_BC_UNARY_OP_MULTI_NUM - 1] = &&entry_MP_BC_UNARY_OP_MULTI,\n    [MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + MP_BC_BINARY_OP_MULTI_NUM - 1] = &&entry_MP_BC_BINARY_OP_MULTI,\n};\n\n#if __clang__\n#pragma clang diagnostic pop\n#endif // __clang__\n#if __GNUC__ >= 5\n#pragma GCC diagnostic pop\n#endif // __GNUC__ >= 5\n"
  },
  {
    "path": "py/vstr.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2013, 2014 Damien P. George\n * Copyright (c) 2014 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdarg.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"py/mpconfig.h\"\n#include \"py/runtime.h\"\n#include \"py/mpprint.h\"\n\n// returned value is always at least 1 greater than argument\n#define ROUND_ALLOC(a) (((a) & ((~0U) - 7)) + 8)\n\n// Init the vstr so it allocs exactly given number of bytes.  Set length to zero.\nvoid vstr_init(vstr_t *vstr, size_t alloc) {\n    if (alloc < 1) {\n        alloc = 1;\n    }\n    vstr->alloc = alloc;\n    vstr->len = 0;\n    vstr->buf = m_new(char, vstr->alloc);\n    vstr->fixed_buf = false;\n}\n\n// Init the vstr so it allocs exactly enough ram to hold a null-terminated\n// string of the given length, and set the length.\nvoid vstr_init_len(vstr_t *vstr, size_t len) {\n    vstr_init(vstr, len + 1);\n    vstr->len = len;\n}\n\nvoid vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf) {\n    vstr->alloc = alloc;\n    vstr->len = 0;\n    vstr->buf = buf;\n    vstr->fixed_buf = true;\n}\n\nvoid vstr_init_print(vstr_t *vstr, size_t alloc, mp_print_t *print) {\n    vstr_init(vstr, alloc);\n    print->data = vstr;\n    print->print_strn = (mp_print_strn_t)vstr_add_strn;\n}\n\nvoid vstr_clear(vstr_t *vstr) {\n    if (!vstr->fixed_buf) {\n        m_del(char, vstr->buf, vstr->alloc);\n    }\n    vstr->buf = NULL;\n}\n\nvstr_t *vstr_new(size_t alloc) {\n    vstr_t *vstr = m_new_obj(vstr_t);\n    vstr_init(vstr, alloc);\n    return vstr;\n}\n\nvoid vstr_free(vstr_t *vstr) {\n    if (vstr != NULL) {\n        if (!vstr->fixed_buf) {\n            m_del(char, vstr->buf, vstr->alloc);\n        }\n        m_del_obj(vstr_t, vstr);\n    }\n}\n\n// Extend vstr strictly by requested size, return pointer to newly added chunk.\nchar *vstr_extend(vstr_t *vstr, size_t size) {\n    if (vstr->fixed_buf) {\n        // We can't reallocate, and the caller is expecting the space to\n        // be there, so the only safe option is to raise an exception.\n        mp_raise_msg(&mp_type_RuntimeError, NULL);\n    }\n    char *new_buf = m_renew(char, vstr->buf, vstr->alloc, vstr->alloc + size);\n    char *p = new_buf + vstr->alloc;\n    vstr->alloc += size;\n    vstr->buf = new_buf;\n    return p;\n}\n\nSTATIC void vstr_ensure_extra(vstr_t *vstr, size_t size) {\n    if (vstr->len + size > vstr->alloc) {\n        if (vstr->fixed_buf) {\n            // We can't reallocate, and the caller is expecting the space to\n            // be there, so the only safe option is to raise an exception.\n            mp_raise_msg(&mp_type_RuntimeError, NULL);\n        }\n        size_t new_alloc = ROUND_ALLOC((vstr->len + size) + 16);\n        char *new_buf = m_renew(char, vstr->buf, vstr->alloc, new_alloc);\n        vstr->alloc = new_alloc;\n        vstr->buf = new_buf;\n    }\n}\n\nvoid vstr_hint_size(vstr_t *vstr, size_t size) {\n    vstr_ensure_extra(vstr, size);\n}\n\nchar *vstr_add_len(vstr_t *vstr, size_t len) {\n    vstr_ensure_extra(vstr, len);\n    char *buf = vstr->buf + vstr->len;\n    vstr->len += len;\n    return buf;\n}\n\n// Doesn't increase len, just makes sure there is a null byte at the end\nchar *vstr_null_terminated_str(vstr_t *vstr) {\n    // If there's no more room, add single byte\n    if (vstr->alloc == vstr->len) {\n        vstr_extend(vstr, 1);\n    }\n    vstr->buf[vstr->len] = '\\0';\n    return vstr->buf;\n}\n\nvoid vstr_add_byte(vstr_t *vstr, byte b) {\n    byte *buf = (byte *)vstr_add_len(vstr, 1);\n    buf[0] = b;\n}\n\nvoid vstr_add_char(vstr_t *vstr, unichar c) {\n    #if MICROPY_PY_BUILTINS_STR_UNICODE\n    // TODO: Can this be simplified and deduplicated?\n    // Is it worth just calling vstr_add_len(vstr, 4)?\n    if (c < 0x80) {\n        byte *buf = (byte *)vstr_add_len(vstr, 1);\n        *buf = (byte)c;\n    } else if (c < 0x800) {\n        byte *buf = (byte *)vstr_add_len(vstr, 2);\n        buf[0] = (c >> 6) | 0xC0;\n        buf[1] = (c & 0x3F) | 0x80;\n    } else if (c < 0x10000) {\n        byte *buf = (byte *)vstr_add_len(vstr, 3);\n        buf[0] = (c >> 12) | 0xE0;\n        buf[1] = ((c >> 6) & 0x3F) | 0x80;\n        buf[2] = (c & 0x3F) | 0x80;\n    } else {\n        assert(c < 0x110000);\n        byte *buf = (byte *)vstr_add_len(vstr, 4);\n        buf[0] = (c >> 18) | 0xF0;\n        buf[1] = ((c >> 12) & 0x3F) | 0x80;\n        buf[2] = ((c >> 6) & 0x3F) | 0x80;\n        buf[3] = (c & 0x3F) | 0x80;\n    }\n    #else\n    vstr_add_byte(vstr, c);\n    #endif\n}\n\nvoid vstr_add_str(vstr_t *vstr, const char *str) {\n    vstr_add_strn(vstr, str, strlen(str));\n}\n\nvoid vstr_add_strn(vstr_t *vstr, const char *str, size_t len) {\n    vstr_ensure_extra(vstr, len);\n    memmove(vstr->buf + vstr->len, str, len);\n    vstr->len += len;\n}\n\nSTATIC char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len) {\n    size_t l = vstr->len;\n    if (byte_pos > l) {\n        byte_pos = l;\n    }\n    if (byte_len > 0) {\n        // ensure room for the new bytes\n        vstr_ensure_extra(vstr, byte_len);\n        // copy up the string to make room for the new bytes\n        memmove(vstr->buf + byte_pos + byte_len, vstr->buf + byte_pos, l - byte_pos);\n        // increase the length\n        vstr->len += byte_len;\n    }\n    return vstr->buf + byte_pos;\n}\n\nvoid vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b) {\n    char *s = vstr_ins_blank_bytes(vstr, byte_pos, 1);\n    *s = b;\n}\n\nvoid vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr) {\n    // TODO UNICODE\n    char *s = vstr_ins_blank_bytes(vstr, char_pos, 1);\n    *s = chr;\n}\n\nvoid vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut) {\n    vstr_cut_out_bytes(vstr, 0, bytes_to_cut);\n}\n\nvoid vstr_cut_tail_bytes(vstr_t *vstr, size_t len) {\n    if (len > vstr->len) {\n        vstr->len = 0;\n    } else {\n        vstr->len -= len;\n    }\n}\n\nvoid vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut) {\n    if (byte_pos >= vstr->len) {\n        return;\n    } else if (byte_pos + bytes_to_cut >= vstr->len) {\n        vstr->len = byte_pos;\n    } else {\n        memmove(vstr->buf + byte_pos, vstr->buf + byte_pos + bytes_to_cut, vstr->len - byte_pos - bytes_to_cut);\n        vstr->len -= bytes_to_cut;\n    }\n}\n\nvoid vstr_printf(vstr_t *vstr, const char *fmt, ...) {\n    va_list ap;\n    va_start(ap, fmt);\n    vstr_vprintf(vstr, fmt, ap);\n    va_end(ap);\n}\n\nvoid vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap) {\n    mp_print_t print = {vstr, (mp_print_strn_t)vstr_add_strn};\n    mp_vprintf(&print, fmt, ap);\n}\n"
  },
  {
    "path": "py/warning.c",
    "content": "/*\n * This file is part of the MicroPython project, http://micropython.org/\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Damien P. George\n * Copyright (c) 2015-2018 Paul Sokolovsky\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#include <stdarg.h>\n#include <stdio.h>\n\n#include \"py/emit.h\"\n#include \"py/runtime.h\"\n\n#if MICROPY_WARNINGS\n\nvoid mp_warning(const char *category, const char *msg, ...) {\n    if (category == NULL) {\n        category = \"Warning\";\n    }\n    mp_print_str(MICROPY_ERROR_PRINTER, category);\n    mp_print_str(MICROPY_ERROR_PRINTER, \": \");\n\n    va_list args;\n    va_start(args, msg);\n    mp_vprintf(MICROPY_ERROR_PRINTER, msg, args);\n    mp_print_str(MICROPY_ERROR_PRINTER, \"\\n\");\n    va_end(args);\n}\n\nvoid mp_emitter_warning(pass_kind_t pass, const char *msg) {\n    if (pass == MP_PASS_CODE_SIZE) {\n        mp_warning(NULL, msg);\n    }\n}\n\n#endif // MICROPY_WARNINGS\n"
  },
  {
    "path": "tools/mpy-cross/hellortt.py",
    "content": "# import os\nclass HelloRtt:\n\n    def __repr__(self):\n        self.__call__()\n        return \"\"\n    \n    def __call__(self):\n        print(\"hello world!!\")\n        print(\"hello RTT\")\n\nhello = HelloRtt()\n"
  }
]