├── .github └── workflows │ └── check.yaml ├── .gitignore ├── LICENSE ├── README.md ├── bool.mbt ├── build.js ├── callable.mbt ├── cpython ├── abstract.mbt ├── cell.mbt ├── ceval.mbt ├── class.mbt ├── code.mbt ├── codecs.mbt ├── context.mbt ├── core.mbt ├── cpython.mbti ├── dict.mbt ├── error.mbt ├── file.mbt ├── func.mbt ├── import.mbt ├── iter.mbt ├── lifecycle.mbt ├── list.mbt ├── module.mbt ├── moon.pkg.json ├── number.mbt ├── object.mbt ├── odict.mbt ├── set.mbt ├── tuple.mbt ├── unicode.mbt ├── utils.mbt └── wrap.c ├── dict.mbt ├── enums.mbt ├── errors.mbt ├── float.mbt ├── integer.mbt ├── list.mbt ├── main ├── main.mbt ├── main.mbti └── moon.pkg.json ├── module.mbt ├── moon.mod.json ├── moon.pkg.json ├── obj.mbt ├── python.mbti ├── set.mbt ├── str.mbt ├── test ├── module_test.mbt ├── moon.pkg.json ├── object_test.mbt └── test.mbti ├── time ├── lib.mbt ├── moon.pkg.json └── time.mbti ├── tkinter ├── moon.pkg.json ├── tkinter.mbt └── tkinter.mbti ├── traits.mbt ├── tuple.mbt ├── turtle ├── color.mbt ├── double_pendulum.mbt.md ├── lib.mbt ├── moon.pkg.json ├── pen.mbt ├── pen2.mbt ├── screen.mbt ├── shape.mbt ├── speed.mbt └── turtle.mbti └── utils.mbt /.github/workflows/check.yaml: -------------------------------------------------------------------------------- 1 | name: check 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | merge_group: 9 | 10 | jobs: 11 | python-check: 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest, macos-latest] 15 | fail-fast: false 16 | runs-on: ${{ matrix.os }} 17 | continue-on-error: false 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Setup Python 3.13 22 | uses: actions/setup-python@v4 23 | with: 24 | python-version: '3.13' 25 | 26 | - name: Verify Python installation 27 | run: | 28 | python3 --version 29 | python3 -c "import sys; print(f'Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}')" 30 | 31 | # TODO: remove bleeding 32 | - name: Install Moonbit 33 | run: | 34 | curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash -s bleeding 35 | echo "$HOME/.moon/bin" >> $GITHUB_PATH 36 | 37 | - name: Moon version 38 | run: | 39 | moon version --all 40 | moonrun --version 41 | 42 | - name: Moon check 43 | run: moon check --deny-warn 44 | 45 | - name: Moon info 46 | run: | 47 | moon info --target native 48 | git diff --exit-code 49 | 50 | - name: Format diff 51 | run: | 52 | moon fmt 53 | git diff --exit-code 54 | 55 | - name: Set ulimit and run moon test 56 | run: | 57 | ulimit -s 8176 58 | moon test --target native 59 | moon test --target native --release 60 | 61 | - name: Moon test --target native --doc 62 | run: | 63 | moon test --target native --doc 64 | 65 | typo-check: 66 | runs-on: ubuntu-latest 67 | timeout-minutes: 10 68 | env: 69 | FORCE_COLOR: 1 70 | TYPOS_VERSION: v1.19.0 71 | steps: 72 | - name: Download typos 73 | run: curl -LsSf https://github.com/crate-ci/typos/releases/download/$TYPOS_VERSION/typos-$TYPOS_VERSION-x86_64-unknown-linux-musl.tar.gz | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin 74 | 75 | - name: Checkout repository 76 | uses: actions/checkout@v4 77 | with: 78 | ref: ${{ github.event.pull_request.head.sha }} 79 | 80 | - name: Check typos 81 | run: typos 82 | 83 | license-header-check: 84 | runs-on: ubuntu-latest 85 | env: 86 | HAWKEYE_VERSION: v5.8.1 87 | steps: 88 | - uses: actions/checkout@v4 89 | with: 90 | fetch-depth: 0 91 | - name: Download HawkEye 92 | run: curl --proto '=https' --tlsv1.2 -LsSf https://github.com/korandoru/hawkeye/releases/download/$HAWKEYE_VERSION/hawkeye-installer.sh | sh 93 | - name: Check License Header 94 | run: | 95 | hawkeye check 96 | 97 | moon-json-format-check: 98 | runs-on: ubuntu-latest 99 | steps: 100 | - uses: actions/checkout@v4 101 | 102 | - name: Check `moon.*.json` format 103 | shell: bash 104 | run: | 105 | _passed=0; 106 | for f in $(find . -type f -name "moon.*.json"); do 107 | if ! jq '.' $f > /dev/null; then 108 | echo $f; 109 | _passed=1; 110 | fi 111 | done 112 | (exit $_passed) 113 | 114 | bleeding-check: 115 | continue-on-error: true 116 | strategy: 117 | matrix: 118 | os: [ubuntu-latest, macos-latest] 119 | runs-on: ${{ matrix.os }} 120 | steps: 121 | - uses: actions/checkout@v4 122 | 123 | - name: Setup Python 3.13 124 | uses: actions/setup-python@v4 125 | with: 126 | python-version: '3.13' 127 | 128 | - name: Install Moonbit (bleeding) 129 | run: | 130 | curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash -s bleeding 131 | echo "$HOME/.moon/bin" >> $GITHUB_PATH 132 | 133 | - name: Moon version 134 | run: | 135 | moon version --all 136 | moonrun --version 137 | 138 | - name: Set ulimit and run moon test 139 | run: | 140 | ulimit -s 8176 141 | moon test --target native 142 | moon test --target native --release 143 | 144 | - name: Moon test --target native --doc 145 | run: | 146 | moon test --target native --doc 147 | 148 | - name: Moon check --target native 149 | run: moon check --target native 150 | 151 | - name: Moon info 152 | run: | 153 | moon info --target native 154 | git diff 155 | 156 | - name: Format diff 157 | run: | 158 | moon fmt 159 | git diff 160 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .mooncakes/ 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🐍 Python.mbt 2 | 3 | [🇨🇳简体中文](#-pythonmbt-1) 4 | 5 | ⚠️ **Project Status Notice** 6 | This project is currently in early development. API changes may occur without backward compatibility. Not recommended for production use. Contributors and testers welcome! 7 | 8 | ## ✨ Key Features 9 | 10 | Moonbit-Python is the first CPython-based bridge for Moonbit language, offering: 11 | 12 | * **Python Ecosystem Integration** - Directly interoperate with top Python libraries like Numpy, Matplotlib, and PyTorch 13 | * **Type-Safe Interactions** - Strongly-typed interfaces ensuring safe object handling 14 | 15 | ## 📦 Environment Setup 16 | 17 | ### Python Installation 18 | 19 | Requires Python 3.9+. Recommended installation methods: 20 | 21 | **Linux (Debian/Ubuntu)** 22 | 23 | ```bash 24 | sudo apt-get update && sudo apt-get install python3.13 python3.13-dev 25 | ``` 26 | 27 | **macOS (Homebrew)** 28 | 29 | ```bash 30 | brew install python@3.13 31 | ``` 32 | 33 | **Windows** 34 | 35 | 1. Visit [Python Official Download Page](https://www.python.org/downloads/windows/) 36 | 2. Download latest 3.x installer 37 | 3. Enable "Add Python to PATH" during installation 38 | 39 | ### Environment Verification 40 | 41 | ```bash 42 | # Verify Python version 43 | python3 --version 44 | ``` 45 | 46 | ## 🔧 Project Configuration 47 | 48 | ### Add Dependency 49 | 50 | Update package index and install core library: 51 | 52 | ```bash 53 | moon update 54 | moon add Kaida-Amethyst/python 55 | ``` 56 | 57 | 💡 **Note**: Current package manager has known issues with native-only libraries. Ignore related error messages. Track official fixes at [Moonbitlang](https://www.moonbitlang.cn/) 58 | 59 | ### Build Configuration 60 | 61 | Add to your project's `moon.pkg.json`: 62 | 63 | ```json 64 | { 65 | "import": [ 66 | "Kaida-Amethyst/python" 67 | ] 68 | } 69 | ``` 70 | 71 | ## 🚀 Quick Start 72 | 73 | ### Example: Using collections.Counter 74 | 75 | ```moonbit 76 | typealias @python.(PyInteger, PyList, PyTuple) 77 | 78 | fn main { 79 | // It's equivalent to `nums = [1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4]` 80 | let nums = [1L, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4] 81 | let py_nums = nums.map(PyInteger::from) |> PyList::from 82 | println(py_nums) // Output: [1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4] 83 | 84 | // It's equivalent to `import collections` 85 | guard @python.pyimport("collections") is Some(collections) 86 | 87 | // It's equivalent to `from collections import Counter` 88 | guard collections.get_attr("Counter") is Some(PyCallable(counter)) 89 | 90 | let args = PyTuple::new(1) 91 | args.. set(0, py_nums) 92 | 93 | // It's equivalent to `cnt = Counter(nums)` 94 | guard counter.invoke?(args~) is Ok(Some(cnt)) 95 | guard cnt is PyDict(cnt) 96 | 97 | // `print(cnt)` 98 | println(cnt) // Output: Counter({4: 4, 3: 3, 1: 2, 2: 2}) 99 | } 100 | ``` 101 | 102 | ### Running the Example 103 | 104 | ```bash 105 | moon run main --target native 106 | ``` 107 | 108 | Equivalent Python implementation: 109 | 110 | ```python 111 | from collections import Counter 112 | 113 | l = [1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4] 114 | print(Counter(l)) # Counter({4: 4, 3: 3, 1: 2, 2: 2}) 115 | ``` 116 | 117 | ## 🤝 Contributing 118 | 119 | We welcome contributions through: 120 | 121 | 1. Issue reporting 122 | 2. Pull requests 123 | 3. Ecosystem documentation improvements 124 | 125 | --- 126 | 127 | 📜 **License**: Apache-2.0 License (See LICENSE file) 128 | 129 | 130 | # 🐍 Python.mbt 131 | 132 | ⚠️ **项目状态提示** 133 | 本项目目前处于早期开发阶段,API可能发生不兼容变更,暂不建议用于生产环境。欢迎开发者参与测试和功能建议! 134 | 135 | 136 | ## 🌟项目亮点 137 | 138 | Moonbit-Python 是首个基于CPython的Moonbit语言桥接工具,具有以下核心优势: 139 | 140 | * **无缝调用Python生态** - 直接操作Numpy、Matplotlib、PyTorch等顶级Python库 141 | * **类型安全交互** - 提供强类型接口保障与Python对象的安全交互 142 | 143 | ## 📦 环境准备 144 | 145 | ### Python安装指南 146 | 147 | 要求Python 3.9+版本,推荐使用最新稳定版: 148 | 149 | **Linux (Debian/Ubuntu)** 150 | 151 | ```bash 152 | sudo apt-get update && sudo apt-get install python3.13 python3.13-dev 153 | ``` 154 | 155 | **macOS (Homebrew)** 156 | 157 | ```bash 158 | brew install python@3.13 159 | ``` 160 | 161 | **Windows** 162 | 163 | 1. 访问[Python官方网站](https://www.python.org/downloads/windows/) 164 | 2. 下载最新3.x版本安装包 165 | 3. 安装时勾选 "Add Python to PATH" 166 | 167 | ### 环境验证 168 | 169 | ```bash 170 | # 验证Python版本 171 | python3 --version 172 | ``` 173 | 174 | ## 🔧 项目配置 175 | 176 | ### 添加依赖 177 | 178 | 更新包索引并安装核心库: 179 | 180 | ```bash 181 | moon update 182 | moon add Kaida-Amethyst/python 183 | ``` 184 | 185 | 💡 **注意**:当前包管理器对纯Native库的支持存在已知问题,可忽略相关错误提示。官方修复进度请关注[Moonbitlang](https://www.moonbitlang.cn/) 186 | 187 | ### 构建配置 188 | 189 | 在项目根目录的 `moon.pkg.json` 中添加: 190 | 191 | ```json 192 | { 193 | "import": [ 194 | "Kaida-Amethyst/python" 195 | ] 196 | } 197 | ``` 198 | 199 | ## 🚀 快速入门 200 | 201 | 一个使用python 中Counter的例子 202 | 203 | ```moonbit 204 | typealias @python.(PyInteger, PyList, PyTuple) 205 | 206 | fn main { 207 | // It's equivalent to `nums = [1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4]` 208 | let nums = [1L, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4] 209 | let py_nums = nums.map(PyInteger::from) |> PyList::from 210 | println(py_nums) // Output: [1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4] 211 | 212 | // It's equivalent to `import collections` 213 | guard @python.pyimport("collections") is Some(collections) 214 | 215 | // It's equivalent to `from collections import Counter` 216 | guard collections.get_attr("Counter") is Some(PyCallable(counter)) 217 | 218 | let args = PyTuple::new(1) 219 | args.. set(0, py_nums) 220 | 221 | // It's equivalent to `cnt = Counter(nums)` 222 | guard counter.invoke?(args~) is Ok(Some(cnt)) 223 | guard cnt is PyDict(cnt) 224 | 225 | // `print(cnt)` 226 | println(cnt) // Output: Counter({4: 4, 3: 3, 1: 2, 2: 2}) 227 | } 228 | ``` 229 | 230 | ### 运行示例 231 | 232 | ```bash 233 | moon run main --target native 234 | ``` 235 | 236 | 等效Python代码: 237 | 238 | ```python 239 | from collections import Counter 240 | 241 | l = [1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4] 242 | print(Counter(l)) # Counter({4: 4, 3: 3, 1: 2, 2: 2}) 243 | ``` 244 | 245 | ## 🤝 参与贡献 246 | 247 | 我们欢迎任何形式的贡献,包括但不限于: 248 | 249 | 1. 提交Issue报告问题 250 | 2. 发起Pull Request改进代码 251 | 3. 编写生态库扩展文档 252 | 253 | --- 254 | 255 | 📜 **许可证**:Apache-2.0 License(详见LICENSE文件) 256 | -------------------------------------------------------------------------------- /bool.mbt: -------------------------------------------------------------------------------- 1 | // ======================================== 2 | // PyBool 3 | // ======================================== 4 | ///| 5 | pub struct PyBool { 6 | priv obj : PyObject 7 | } 8 | 9 | ///| Create a python boolean object from a python object. 10 | /// If the object is not a boolean, it will raise a TypeMisMatchError. 11 | pub fn PyBool::create(obj : PyObject) -> PyBool!PyRuntimeError { 12 | guard obj.is_bool() else { raise TypeMisMatchError } 13 | PyBool::{ obj, } 14 | } 15 | 16 | ///| 17 | fn PyBool::create_unchecked(obj : PyObject) -> PyBool { 18 | PyBool::{ obj, } 19 | } 20 | 21 | ///| Create a python boolean object from a python object reference. 22 | /// If the object is not a boolean, it will raise a TypeMisMatchError. 23 | pub fn PyBool::create_by_ref( 24 | obj_ref : @cpython.PyObjectRef 25 | ) -> PyBool!PyRuntimeError { 26 | guard @cpython.py_bool_check(obj_ref) else { raise TypeMisMatchError } 27 | PyBool::{ obj: PyObject::create(obj_ref) } 28 | } 29 | 30 | ///| 31 | fn PyBool::create_by_ref_unchecked(obj_ref : @cpython.PyObjectRef) -> PyBool { 32 | PyBool::{ obj: PyObject::create(obj_ref) } 33 | } 34 | 35 | ///| 36 | pub fn PyBool::dump(self : PyBool) -> Unit { 37 | self.obj.dump() 38 | } 39 | 40 | ///| Create a python boolean object from moonbit bool. 41 | /// 42 | /// ## Example 43 | /// 44 | /// ```moonbit 45 | /// test "PyBool::from" { 46 | /// let t = PyBool::from(true); 47 | /// 48 | /// inspect!(t, content="True") 49 | /// } 50 | /// ``` 51 | /// 52 | /// The above code is equivalent to: 53 | /// 54 | /// ```python 55 | /// t = True 56 | /// 57 | /// print(t) # Output: True 58 | /// ``` 59 | pub fn PyBool::from(value : Bool) -> PyBool { 60 | let value = value.to_int64() 61 | let obj_ref = @cpython.py_bool_from_long(value) 62 | PyBool::create_by_ref_unchecked(obj_ref) 63 | } 64 | 65 | ///| Return `true` if it is true, using python interpreter. 66 | /// 67 | /// ## Example 68 | /// 69 | /// ```moonbit 70 | /// test "PyBool::is_true" { 71 | /// let t = PyBool::from(true); 72 | /// let f = PyBool::from(false); 73 | /// 74 | /// assert_true!(t.is_true()); 75 | /// assert_false!(f.is_true()); 76 | /// } 77 | /// ``` 78 | pub fn PyBool::is_true(self : PyBool) -> Bool { 79 | let obj = self.obj_ref() 80 | @cpython.py_object_is_true(obj) 81 | } 82 | 83 | ///| 84 | pub fn PyBool::to_bool(self : PyBool) -> Bool { 85 | self.is_true() 86 | } 87 | 88 | ///| Return `true` if it is false, using python interpreter. 89 | /// 90 | /// ## Example 91 | /// 92 | /// ```moonbit 93 | /// test "PyBool::is_false" { 94 | /// let t = PyBool::from(true); 95 | /// let f = PyBool::from(false); 96 | /// 97 | /// assert_false!(t.is_false()); 98 | /// assert_true!(f.is_false()); 99 | /// } 100 | /// ``` 101 | pub fn PyBool::is_false(self : PyBool) -> Bool { 102 | self.is_true() |> not 103 | } 104 | 105 | ///| Return the reverse of the boolean value. 106 | /// 107 | /// ## Example 108 | /// 109 | /// ```moonbit 110 | /// test "PyBool::not" { 111 | /// let t = PyBool::from(true); 112 | /// let f = t.not(); 113 | /// 114 | /// assert_true!(f.is_false()); 115 | /// } 116 | /// ``` 117 | pub fn PyBool::not(self : PyBool) -> PyBool { 118 | if self.is_true() { 119 | return PyBool::from(false) 120 | } else { 121 | return PyBool::from(true) 122 | } 123 | } 124 | 125 | ///| 126 | pub impl IsPyObject for PyBool with obj(self) { 127 | self.obj 128 | } 129 | 130 | ///| 131 | pub impl Show for PyBool with to_string(self) { 132 | self.obj.to_string() 133 | } 134 | 135 | ///| 136 | pub impl Show for PyBool with output(self, logger) { 137 | logger.write_string(self.to_string()) 138 | } 139 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | const { execSync } = require('child_process') 2 | const path = require('path') 3 | 4 | try { 5 | // Helper function to execute shell commands and trim output 6 | const runCommand = (command) => { 7 | try { 8 | return execSync(command, { encoding: 'utf8' }).trim() 9 | } catch (error) { 10 | console.error(`Error executing command: ${command}`) 11 | console.error(error.stderr || error.message) 12 | process.exit(1) 13 | } 14 | } 15 | 16 | // 1. Get PY_VERSION 17 | const pyVersionCmd = 18 | 'python3 -c "import sys; print(f\'{sys.version_info.major}.{sys.version_info.minor}\')"' 19 | const pyVersion = runCommand(pyVersionCmd) 20 | 21 | // 2. Set CC 22 | const cc = process.env.CC || 'gcc' // Use environment CC if set, otherwise default to gcc 23 | 24 | // 3. Get Python prefix and include directory 25 | const pyPrefixCmd = 'python3-config --prefix' 26 | const pyPrefix = runCommand(pyPrefixCmd) 27 | const pyIncludeDir = path.join(pyPrefix, 'include', `python${pyVersion}`) 28 | 29 | // 4. Construct CC_FLAGS 30 | const stubCCFlags = `-I${pyIncludeDir} -DNDEBUG` 31 | const ccFlags = stubCCFlags 32 | 33 | // 5. Get Python ldflags 34 | const pyLdflagsCmd = 'python3-config --ldflags' 35 | const pyLdflags = runCommand(pyLdflagsCmd) 36 | 37 | // 6. Construct CC_LINK_FLAGS 38 | // Sometimes ldflags already includes the -lpython part, remove it if present before adding ours 39 | const baseLdflags = pyLdflags.replace(/-lpython[\d.]+\w*/, '').trim() 40 | const ccLinkFlags = `${baseLdflags} -lpython${pyVersion}` 41 | 42 | // 7. Construct C_INCLUDE_PATH 43 | const existingCIncludePath = process.env.C_INCLUDE_PATH || '' 44 | const cIncludePath = existingCIncludePath 45 | ? `${pyIncludeDir}${path.delimiter}${existingCIncludePath}` 46 | : pyIncludeDir 47 | 48 | // 8. Assemble the variables 49 | const output = { 50 | vars: { 51 | PY_VERSION: pyVersion, 52 | CC: cc, 53 | CC_FLAGS: ccFlags, 54 | STUB_CC_FLAGS: stubCCFlags, 55 | CC_LINK_FLAGS: ccLinkFlags, 56 | C_INCLUDE_PATH: cIncludePath, 57 | }, 58 | link_configs: [ 59 | { 60 | package: 'Kaida-Amethyst/python/cpython', 61 | link_flags: ccLinkFlags, 62 | }, 63 | ], 64 | } 65 | 66 | console.log(JSON.stringify(output, null, 2)) 67 | } catch (error) { 68 | // Catch any unexpected errors during setup or JSON stringification 69 | console.error('An unexpected error occurred:', error.message) 70 | process.exit(1) 71 | } 72 | -------------------------------------------------------------------------------- /callable.mbt: -------------------------------------------------------------------------------- 1 | // ======================================== 2 | // Function 3 | // ======================================== 4 | ///| 5 | pub struct PyCallable { 6 | priv obj : PyObject 7 | } 8 | 9 | ///| Create a python callable object from a PyObject. 10 | /// If the object is not callable, a TypeMisMatchError is raised. 11 | pub fn PyCallable::create(obj : PyObject) -> PyCallable!PyRuntimeError { 12 | guard obj.is_callable() else { raise TypeMisMatchError } 13 | PyCallable::{ obj, } 14 | } 15 | 16 | ///| 17 | fn PyCallable::create_unchecked(obj : PyObject) -> PyCallable { 18 | PyCallable::{ obj, } 19 | } 20 | 21 | ///| Create a python callable object from a PyObjectRef. 22 | /// If the object is not callable, a TypeMisMatchError is raised. 23 | pub fn PyCallable::create_by_ref( 24 | obj : @cpython.PyObjectRef 25 | ) -> PyCallable!PyRuntimeError { 26 | guard @cpython.py_callable_check(obj) else { raise TypeMisMatchError } 27 | PyCallable::{ obj: PyObject::create(obj) } 28 | } 29 | 30 | ///| 31 | fn PyCallable::create_by_ref_unchecked( 32 | obj : @cpython.PyObjectRef 33 | ) -> PyCallable { 34 | PyCallable::{ obj: PyObject::create(obj) } 35 | } 36 | 37 | ///| 38 | pub fn PyCallable::dump(self : PyCallable) -> Unit { 39 | self.obj.dump() 40 | } 41 | 42 | ///| 43 | pub fn PyCallable::invoke( 44 | self : PyCallable, 45 | args~ : PyTuple = PyTuple::new(0), 46 | kwargs~ : PyDict = PyDict::new(), 47 | print_err~ : Bool = false 48 | ) -> PyObjectEnum?!PyRuntimeError { 49 | let obj_ref = if kwargs.len() > 0 { 50 | @cpython.py_object_call(self.obj_ref(), args.obj_ref(), kwargs.obj_ref()) 51 | } else { 52 | @cpython.py_object_call_object(self.obj_ref(), args.obj_ref()) 53 | } 54 | if obj_ref.is_null() { 55 | let e = @cpython.py_err_occurred() 56 | if not(e.is_null()) { 57 | if print_err { 58 | @cpython.py_err_print() 59 | } 60 | @cpython.py_err_clear() 61 | raise InVokeError 62 | } 63 | } 64 | @option.unless(@cpython.py_none_check(obj_ref), fn() { 65 | let obj = PyObject::create(obj_ref) 66 | PyObjectEnum::create(obj) 67 | }) 68 | } 69 | 70 | ///| 71 | pub impl IsPyObject for PyCallable with obj(self) -> PyObject { 72 | self.obj 73 | } 74 | 75 | ///| 76 | pub impl Show for PyCallable with to_string(self) { 77 | self.obj.to_string() 78 | } 79 | 80 | ///| 81 | pub impl Show for PyCallable with output(self, logger) { 82 | logger.write_string(self.to_string()) 83 | } 84 | -------------------------------------------------------------------------------- /cpython/abstract.mbt: -------------------------------------------------------------------------------- 1 | // Abstract 2 | ///| Call a callable Python object 'callable' with arguments given by the 3 | /// tuple 'args' and keywords arguments given by the dictionary 'kwargs'. 4 | /// 5 | /// 'args' must not be NULL, use an empty tuple if no arguments are 6 | /// needed. If no named arguments are needed, 'kwargs' can be NULL. 7 | /// 8 | /// This is the equivalent of the Python expression: 9 | /// callable(*args, **kwargs). 10 | pub extern "C" fn py_object_call( 11 | callable : PyObjectRef, 12 | args : PyObjectRef, 13 | kwargs : PyObjectRef 14 | ) -> PyObjectRef = "PyObject_Call" 15 | 16 | ///| Call a callable Python object 'callable', with arguments given by the 17 | /// tuple 'args'. If no arguments are needed, then 'args' can be NULL. 18 | /// 19 | /// Returns the result of the call on success, or NULL on failure. 20 | /// 21 | /// This is the equivalent of the Python expression: 22 | /// callable(*args). 23 | pub extern "C" fn py_object_call_object( 24 | callable : PyObjectRef, 25 | args : PyObjectRef 26 | ) -> PyObjectRef = "PyObject_CallObject" 27 | 28 | ///| Get the type of an object. 29 | /// 30 | /// On success, returns a type object corresponding to the object type of object 31 | /// 'o'. On failure, returns NULL. 32 | /// 33 | /// This is equivalent to the Python expression: type(o) 34 | pub extern "C" fn py_object_type(obj : PyObjectRef) -> PyObjectRef = "PyObject_Type" 35 | 36 | ///| Return the size of object 'o'. If the object 'o' provides both sequence and 37 | /// mapping protocols, the sequence size is returned. 38 | /// 39 | /// On error, -1 is returned. 40 | /// 41 | /// This is the equivalent to the Python expression: len(o) */ 42 | pub extern "C" fn py_object_size(obj : PyObjectRef) -> UInt64 = "PyObject_Size" 43 | 44 | ///| Return element of 'o' corresponding to the object 'key'. Return NULL 45 | /// on failure. 46 | /// 47 | /// This is the equivalent of the Python expression: o[key] */ 48 | pub extern "C" fn py_object_get_item( 49 | obj : PyObjectRef, 50 | key : PyObjectRef 51 | ) -> PyObjectRef = "PyObject_GetItem" 52 | 53 | ///| Map the object 'key' to the value 'v' into 'o'. 54 | /// 55 | /// Raise an exception and return -1 on failure; return 0 on success. 56 | /// 57 | /// This is the equivalent of the Python statement: o[key]=v. */ 58 | pub extern "C" fn py_object_set_item( 59 | obj : PyObjectRef, 60 | key : PyObjectRef, 61 | value : PyObjectRef 62 | ) -> Int = "py_object_SetItem" 63 | 64 | ///| Remove the mapping for the string 'key' from the object 'o'. 65 | /// Returns -1 on failure. 66 | /// 67 | /// This is equivalent to the Python statement: del o[key]. 68 | pub extern "C" fn py_object_del_item_string( 69 | obj : PyObjectRef, 70 | key : CStr 71 | ) -> Int = "PyObject_DelItemString" 72 | 73 | ///| Delete the mapping for the object 'key' from the object 'o'. 74 | /// Returns -1 on failure. 75 | /// 76 | /// This is the equivalent of the Python statement: del o[key]. 77 | pub extern "C" fn py_object_del_item( 78 | obj : PyObjectRef, 79 | key : PyObjectRef 80 | ) -> Int = "PyObject_DelItem" 81 | 82 | ///| Takes an arbitrary object and returns the result of calling 83 | /// obj.__format__(format_spec). 84 | pub extern "C" fn pyobkect_format( 85 | obj : PyObjectRef, 86 | format_spec : PyObjectRef 87 | ) -> PyObjectRef = "PyObject_Format" 88 | 89 | ///| Takes an object and returns an iterator for it. 90 | /// This is typically a new iterator but if the argument is an iterator, this 91 | /// returns itself. */ 92 | pub extern "C" fn py_object_get_iter(obj : PyObjectRef) -> PyObjectRef = "PyObject_GetIter" 93 | 94 | ///| Returns 1 if the object 'obj' provides iterator protocols, and 0 otherwise. 95 | /// 96 | /// This function always succeeds. */ 97 | pub extern "C" fn pyiter_check(obj : PyObjectRef) -> Int = "PyIter_Check" 98 | 99 | ///| Takes an iterator object and calls its tp_iternext slot, 100 | /// returning the next value. 101 | /// 102 | /// If the iterator is exhausted, this returns NULL without setting an 103 | /// exception. 104 | /// 105 | /// NULL with an exception means an error occurred. */ 106 | pub extern "C" fn pyiter_next(iter : PyObjectRef) -> PyObjectRef = "PyIter_Next" 107 | 108 | ///| Returns 1 if the object 'o' provides numeric protocols, and 0 otherwise. 109 | /// 110 | /// This function always succeeds. */ 111 | pub extern "C" fn pynumber_check(obj : PyObjectRef) -> Int = "PyNumber_Check" 112 | 113 | ///| Returns the result of adding o1 and o2, or NULL on failure. 114 | /// 115 | /// This is the equivalent of the Python expression: o1 + o2. */ 116 | pub extern "C" fn pynumber_add( 117 | obj1 : PyObjectRef, 118 | obj2 : PyObjectRef 119 | ) -> PyObjectRef = "PyNumber_Add" 120 | 121 | ///| Returns the result of subtracting o2 from o1, or NULL on failure. 122 | /// 123 | /// This is the equivalent of the Python expression: o1 - o2. */ 124 | pub extern "C" fn pynumber_subtract( 125 | obj1 : PyObjectRef, 126 | obj2 : PyObjectRef 127 | ) -> PyObjectRef = "PyNumber_Subtract" 128 | 129 | ///| Returns the result of multiplying o1 and o2, or NULL on failure. 130 | /// 131 | /// This is the equivalent of the Python expression: o1 * o2. */ 132 | pub extern "C" fn pynumber_multiply( 133 | obj1 : PyObjectRef, 134 | obj2 : PyObjectRef 135 | ) -> PyObjectRef = "PyNumber_Multiply" 136 | 137 | ///| Returns the result of dividing o1 by o2 giving an integral result, 138 | /// or NULL on failure. 139 | /// 140 | /// This is the equivalent of the Python expression: o1 // o2. */ 141 | pub extern "C" fn pynumber_floor_divide( 142 | obj1 : PyObjectRef, 143 | obj2 : PyObjectRef 144 | ) -> PyObjectRef = "PyNumber_FloorDivide" 145 | 146 | ///| Returns the result of dividing o1 by o2 giving a float result, or NULL on 147 | /// failure. 148 | /// 149 | /// This is the equivalent of the Python expression: o1 / o2. 150 | pub extern "C" fn pynumber_true_divide( 151 | obj1 : PyObjectRef, 152 | obj2 : PyObjectRef 153 | ) -> PyObjectRef = "PyNumber_TrueDivide" 154 | 155 | ///| Returns the remainder of dividing o1 by o2, or NULL on failure. 156 | /// 157 | /// This is the equivalent of the Python expression: o1 % o2. 158 | pub extern "C" fn pynumber_remainder( 159 | obj1 : PyObjectRef, 160 | obj2 : PyObjectRef 161 | ) -> PyObjectRef = "PyNumber_Remainder" 162 | 163 | ///| See the built-in function divmod. 164 | /// 165 | /// Returns NULL on failure. 166 | /// 167 | /// This is the equivalent of the Python expression: divmod(o1, o2). 168 | pub extern "C" fn pynumber_divmod( 169 | obj1 : PyObjectRef, 170 | obj2 : PyObjectRef 171 | ) -> PyObjectRef = "PyNumber_Divmod" 172 | 173 | ///| See the built-in function pow. Returns NULL on failure. 174 | /// 175 | /// This is the equivalent of the Python expression: pow(o1, o2, o3), 176 | /// where o3 is optional. 177 | pub extern "C" fn pynumber_power( 178 | obj1 : PyObjectRef, 179 | obj2 : PyObjectRef, 180 | obj3 : PyObjectRef 181 | ) -> PyObjectRef = "PyNumber_Power" 182 | 183 | ///| Returns the negation of o on success, or NULL on failure. 184 | /// 185 | /// This is the equivalent of the Python expression: -o. 186 | pub extern "C" fn pynumber_negative(obj : PyObjectRef) -> PyObjectRef = "PyNumber_Negative" 187 | 188 | ///| Returns the positive of o on success, or NULL on failure. 189 | /// 190 | /// This is the equivalent of the Python expression: +o. 191 | pub extern "C" fn pynumber_positive(obj : PyObjectRef) -> PyObjectRef = "PyNumber_Positive" 192 | 193 | ///| Returns the absolute value of 'o', or NULL on failure. 194 | /// 195 | /// This is the equivalent of the Python expression: abs(o). 196 | pub extern "C" fn pynumber_absolute(obj : PyObjectRef) -> PyObjectRef = "PyNumber_Absolute" 197 | 198 | ///| Returns the bitwise negation of 'o' on success, or NULL on failure. 199 | /// 200 | /// This is the equivalent of the Python expression: ~o. 201 | pub extern "C" fn pynumber_invert(obj : PyObjectRef) -> PyObjectRef = "PyNumber_Invert" 202 | 203 | ///| Returns the result of left shifting o1 by o2 on success, or NULL on failure. 204 | /// 205 | /// This is the equivalent of the Python expression: o1 << o2. 206 | pub extern "C" fn pynumber_lshift( 207 | obj1 : PyObjectRef, 208 | obj2 : PyObjectRef 209 | ) -> PyObjectRef = "PyNumber_Lshift" 210 | 211 | ///| Returns the result of right shifting o1 by o2 on success, or NULL on 212 | /// failure. 213 | /// 214 | /// This is the equivalent of the Python expression: o1 >> o2. 215 | pub extern "C" fn pynumber_rshift( 216 | obj1 : PyObjectRef, 217 | obj2 : PyObjectRef 218 | ) -> PyObjectRef = "PyNumber_Rshift" 219 | 220 | ///| Returns the result of bitwise and of o1 and o2 on success, or NULL on 221 | /// failure. 222 | /// 223 | /// This is the equivalent of the Python expression: o1 & o2. 224 | pub extern "C" fn pynumber_and( 225 | obj1 : PyObjectRef, 226 | obj2 : PyObjectRef 227 | ) -> PyObjectRef = "PyNumber_And" 228 | 229 | ///| Returns the bitwise exclusive or of o1 by o2 on success, or NULL on failure. 230 | /// 231 | /// This is the equivalent of the Python expression: o1 ^ o2. 232 | pub extern "C" fn pynumber_xor( 233 | obj1 : PyObjectRef, 234 | obj2 : PyObjectRef 235 | ) -> PyObjectRef = "PyNumber_Xor" 236 | 237 | ///| Returns the result of bitwise or on o1 and o2 on success, or NULL on 238 | /// failure. 239 | /// 240 | /// This is the equivalent of the Python expression: o1 | o2. 241 | pub extern "C" fn pynumber_or( 242 | obj1 : PyObjectRef, 243 | obj2 : PyObjectRef 244 | ) -> PyObjectRef = "PyNumber_Or" 245 | 246 | ///| Returns 1 if obj is an index integer (has the nb_index slot of the 247 | /// tp_as_number structure filled in), and 0 otherwise. 248 | pub extern "C" fn pyindex_check(obj : PyObjectRef) -> Int = "PyIndex_Check" 249 | 250 | ///| Returns the object 'o' converted to a Python int, or NULL with an exception 251 | /// raised on failure. 252 | pub extern "C" fn pynumber_index(obj : PyObjectRef) -> PyObjectRef = "PyNumber_Index" 253 | 254 | ///| Returns the object 'o' converted to Py_ssize_t by going through 255 | /// PyNumber_Index() first. 256 | /// 257 | /// If an overflow error occurs while converting the int to Py_ssize_t, then the 258 | /// second argument 'exc' is the error-type to return. If it is NULL, then the 259 | /// overflow error is cleared and the value is clipped. 260 | pub extern "C" fn pynumber_as_ssize_t( 261 | obj : PyObjectRef, 262 | exc : PyObjectRef 263 | ) -> Int = "PyNumber_AsSsize_t" 264 | 265 | ///| Returns the object 'o' converted to an integer object on success, or NULL 266 | /// on failure. 267 | /// 268 | /// This is the equivalent of the Python expression: int(o). 269 | pub extern "C" fn pynumber_long(obj : PyObjectRef) -> PyObjectRef = "PyNumber_Long" 270 | 271 | ///| Returns the object 'o' converted to a float object on success, or NULL 272 | /// on failure. 273 | /// 274 | /// This is the equivalent of the Python expression: float(o). 275 | pub extern "C" fn pynumber_float(obj : PyObjectRef) -> PyObjectRef = "PyNumber_Float" 276 | 277 | ///| Returns the result of adding o2 to o1, possibly in-place, or NULL 278 | /// on failure. 279 | /// 280 | /// This is the equivalent of the Python expression: o1 += o2. 281 | pub extern "C" fn pynumber_inplace_add( 282 | obj1 : PyObjectRef, 283 | obj2 : PyObjectRef 284 | ) -> PyObjectRef = "PyNumber_InPlaceAdd" 285 | 286 | ///| Returns the result of subtracting o2 from o1, possibly in-place or 287 | /// NULL on failure. 288 | /// 289 | /// This is the equivalent of the Python expression: o1 -= o2. 290 | pub extern "C" fn pynumber_inplace_subtract( 291 | obj1 : PyObjectRef, 292 | obj2 : PyObjectRef 293 | ) -> PyObjectRef = "PyNumber_InPlaceSubtract" 294 | 295 | ///| Returns the result of multiplying o1 by o2, possibly in-place, or NULL on 296 | /// failure. 297 | /// 298 | /// This is the equivalent of the Python expression: o1 *= o2. 299 | pub extern "C" fn pynumber_inplace_multiply( 300 | obj1 : PyObjectRef, 301 | obj2 : PyObjectRef 302 | ) -> PyObjectRef = "PyNumber_InPlaceMultiply" 303 | 304 | ///| 305 | pub extern "C" fn pynumber_inplace_floor_divide( 306 | obj1 : PyObjectRef, 307 | obj2 : PyObjectRef 308 | ) -> PyObjectRef = "PyNumber_InPlaceFloorDivide" 309 | 310 | ///| Returns the result of dividing o1 by o2 giving a float result, possibly 311 | /// in-place, or null on failure. 312 | /// 313 | /// This is the equivalent of the Python expression: o1 /= o2. 314 | pub extern "C" fn pynumber_inplace_true_divide( 315 | obj1 : PyObjectRef, 316 | obj2 : PyObjectRef 317 | ) -> PyObjectRef = "PyNumber_InPlaceTrueDivide" 318 | 319 | ///| Returns the remainder of dividing o1 by o2, possibly in-place, or NULL on 320 | /// failure. 321 | /// 322 | /// This is the equivalent of the Python expression: o1 %= o2. 323 | pub extern "C" fn pynumber_inplace_remainder( 324 | obj1 : PyObjectRef, 325 | obj2 : PyObjectRef 326 | ) -> PyObjectRef = "PyNumber_InPlaceRemainder" 327 | 328 | ///| Returns the result of raising o1 to the power of o2, possibly in-place, 329 | /// or NULL on failure. 330 | /// 331 | /// This is the equivalent of the Python expression: o1 **= o2, 332 | /// or o1 = pow(o1, o2, o3) if o3 is present. 333 | pub extern "C" fn pynumber_inplace_power( 334 | obj1 : PyObjectRef, 335 | obj2 : PyObjectRef, 336 | obj3 : PyObjectRef 337 | ) -> PyObjectRef = "PyNumber_InPlacePower" 338 | 339 | ///| Returns the result of left shifting o1 by o2, possibly in-place, or NULL 340 | /// on failure. 341 | /// 342 | /// This is the equivalent of the Python expression: o1 <<= o2. 343 | pub extern "C" fn pynumber_inplace_lshift( 344 | obj1 : PyObjectRef, 345 | obj2 : PyObjectRef 346 | ) -> PyObjectRef = "PyNumber_InPlaceLshift" 347 | 348 | ///| Returns the result of right shifting o1 by o2, possibly in-place or NULL 349 | /// on failure. 350 | /// 351 | /// This is the equivalent of the Python expression: o1 >>= o2. 352 | pub extern "C" fn pynumber_inplace_rshift( 353 | obj1 : PyObjectRef, 354 | obj2 : PyObjectRef 355 | ) -> PyObjectRef = "PyNumber_InPlaceRshift" 356 | 357 | ///| Returns the result of bitwise and of o1 and o2, possibly in-place, or NULL 358 | /// on failure. 359 | /// 360 | /// This is the equivalent of the Python expression: o1 &= o2. 361 | pub extern "C" fn pynumber_inplace_and( 362 | obj1 : PyObjectRef, 363 | obj2 : PyObjectRef 364 | ) -> PyObjectRef = "PyNumber_InPlaceAnd" 365 | 366 | ///| Returns the bitwise exclusive or of o1 by o2, possibly in-place, or NULL 367 | /// on failure. 368 | /// 369 | /// This is the equivalent of the Python expression: o1 ^= o2. 370 | pub extern "C" fn pynumber_inplace_xor( 371 | obj1 : PyObjectRef, 372 | obj2 : PyObjectRef 373 | ) -> PyObjectRef = "PyNumber_InPlaceXor" 374 | 375 | ///| Returns the result of bitwise or of o1 and o2, possibly in-place, 376 | /// or NULL on failure. 377 | /// 378 | /// This is the equivalent of the Python expression: o1 |= o2. 379 | pub extern "C" fn pynumber_inplace_or( 380 | obj1 : PyObjectRef, 381 | obj2 : PyObjectRef 382 | ) -> PyObjectRef = "PyNumber_InPlaceOr" 383 | 384 | ///| Returns the integer n converted to a string with a base, with a base 385 | /// marker of 0b, 0o or 0x prefixed if applicable. 386 | /// 387 | /// If n is not an int object, it is converted with PyNumber_Index first. */ 388 | pub extern "C" fn pynumber_to_base( 389 | obj : PyObjectRef, 390 | base : Int 391 | ) -> PyObjectRef = "PyNumber_ToBase" 392 | 393 | ///| Return 1 if the object provides sequence protocol, and zero 394 | /// otherwise. 395 | /// 396 | /// This function always succeeds. 397 | pub extern "C" fn pysequence_check(obj : PyObjectRef) -> Int = "PySequence_Check" 398 | 399 | ///| Return the size of sequence object o, or -1 on failure. */ 400 | pub extern "C" fn pysequence_size(obj : PyObjectRef) -> Int = "PySequence_Size" 401 | 402 | ///| Return the concatenation of o1 and o2 on success, and NULL on failure. 403 | /// 404 | /// This is the equivalent of the Python expression: o1 + o2. */ 405 | pub extern "C" fn pysequence_concat( 406 | obj1 : PyObjectRef, 407 | obj2 : PyObjectRef 408 | ) -> PyObjectRef = "PySequence_Concat" 409 | 410 | ///| Return the result of repeating sequence object 'o' 'count' times, 411 | /// or NULL on failure. 412 | /// 413 | /// This is the equivalent of the Python expression: o * count. */ 414 | pub extern "C" fn pysequence_repeat( 415 | obj : PyObjectRef, 416 | count : Int 417 | ) -> PyObjectRef = "PySequence_Repeat" 418 | 419 | ///| Return the ith element of o, or NULL on failure. 420 | /// 421 | /// This is the equivalent of the Python expression: o[i]. 422 | pub extern "C" fn pysequence_get_item( 423 | obj : PyObjectRef, 424 | idx : UInt64 425 | ) -> PyObjectRef = "PySequence_GetItem" 426 | 427 | ///| Return the slice of sequence object o between i1 and i2, or NULL on failure. 428 | /// 429 | /// This is the equivalent of the Python expression: o[i1:i2]. 430 | pub extern "C" fn pysequence_get_slice( 431 | obj : PyObjectRef, 432 | start : UInt64, 433 | end : UInt64 434 | ) -> PyObjectRef = "PySequence_GetSlice" 435 | 436 | ///| Assign object 'v' to the ith element of the sequence 'o'. Raise an exception 437 | /// and return -1 on failure; return 0 on success. 438 | /// 439 | /// This is the equivalent of the Python statement o[i] = v. */ 440 | pub extern "C" fn pysequence_set_item( 441 | obj : PyObjectRef, 442 | idx : UInt64, 443 | value : PyObjectRef 444 | ) -> Int = "PySequence_SetItem" 445 | 446 | ///| Delete the 'i'-th element of the sequence 'v'. Returns -1 on failure. 447 | /// 448 | /// This is the equivalent of the Python statement: del o[i]. */ 449 | pub extern "C" fn pysequence_del_item(obj : PyObjectRef, idx : UInt64) -> Int = "PySequence_DelItem" 450 | 451 | ///| Assign the sequence object 'v' to the slice in sequence object 'o', 452 | /// from 'i1' to 'i2'. Returns -1 on failure. 453 | /// 454 | /// This is the equivalent of the Python statement: o[i1:i2] = v. */ 455 | pub extern "C" fn pysequence_set_slice( 456 | obj : PyObjectRef, 457 | start : UInt64, 458 | end : UInt64, 459 | new_list : PyObjectRef 460 | ) -> Int = "PySequence_SetSlice" 461 | 462 | ///| Delete the slice in sequence object 'o' from 'i1' to 'i2'. 463 | /// Returns -1 on failure. 464 | /// 465 | /// This is the equivalent of the Python statement: del o[i1:i2]. */ 466 | pub extern "C" fn pysequence_del_slice( 467 | obj : PyObjectRef, 468 | start : UInt64, 469 | end : UInt64 470 | ) -> Int = "PySequence_DelSlice" 471 | 472 | ///| Returns the sequence 'o' as a tuple on success, and NULL on failure. 473 | /// 474 | /// This is equivalent to the Python expression: tuple(o). */ 475 | pub extern "C" fn pysequence_tuple(obj : PyObjectRef) -> PyObjectRef = "PySequence_Tuple" 476 | 477 | ///| Returns the sequence 'o' as a list on success, and NULL on failure. 478 | /// This is equivalent to the Python expression: list(o) */ 479 | pub extern "C" fn pysequence_list(obj : PyObjectRef) -> PyObjectRef = "PySequence_List" 480 | 481 | ///| Return the sequence 'o' as a list, unless it's already a tuple or list. 482 | /// 483 | /// Use PySequence_Fast_GET_ITEM to access the members of this list, and 484 | /// PySequence_Fast_GET_SIZE to get its length. 485 | /// 486 | /// Returns NULL on failure. If the object does not support iteration, raises a 487 | /// TypeError exception with 'm' as the message text. */ 488 | pub extern "C" fn pysequence_fast(obj : PyObjectRef, msg : CStr) -> PyObjectRef = "PySequence_Fast" 489 | 490 | // PyAPI_FUNC(Py_ssize_t) PySequence_Count(py_object *o, PyObject *value); 491 | ///| 492 | pub extern "C" fn pysequence_count( 493 | obj : PyObjectRef, 494 | value : PyObjectRef 495 | ) -> Int = "PySequence_Count" 496 | 497 | ///| Return 1 if 'ob' is in the sequence 'seq'; 0 if 'ob' is not in the sequence 498 | /// 'seq'; -1 on error. 499 | /// 500 | /// Use __contains__ if possible, else _PySequence_IterSearch(). 501 | pub extern "C" fn pysequence_contains( 502 | seq : PyObjectRef, 503 | ob : PyObjectRef 504 | ) -> Int = "PySequence_Contains" 505 | 506 | // PyAPI_FUNC(Py_ssize_t) PySequence_Index(py_object *o, PyObject *value); 507 | ///| 508 | pub extern "C" fn pysequence_index( 509 | obj : PyObjectRef, 510 | value : PyObjectRef 511 | ) -> Int = "PySequence_Index" 512 | 513 | ///| Append sequence 'o2' to sequence 'o1', in-place when possible. Return the 514 | /// resulting object, which could be 'o1', or NULL on failure. 515 | /// 516 | /// This is the equivalent of the Python expression: o1 += o2. */ 517 | pub extern "C" fn pysequence_inplace_concat( 518 | obj1 : PyObjectRef, 519 | obj2 : PyObjectRef 520 | ) -> PyObjectRef = "PySequence_InPlaceConcat" 521 | 522 | ///| Repeat sequence 'o' by 'count', in-place when possible. Return the resulting 523 | /// object, which could be 'o', or NULL on failure. 524 | /// 525 | /// This is the equivalent of the Python expression: o1 *= count. */ 526 | pub extern "C" fn pysequence_inplace_repeat( 527 | obj : PyObjectRef, 528 | count : Int 529 | ) -> PyObjectRef = "PySequence_InPlaceRepeat" 530 | 531 | ///| Return 1 if the object provides mapping protocol, and 0 otherwise. 532 | /// 533 | /// This function always succeeds. 534 | pub extern "C" fn pymapping_check(obj : PyObjectRef) -> Int = "PyMapping_Check" 535 | 536 | ///| Returns the number of keys in mapping object 'o' on success, and -1 on 537 | /// failure. This is equivalent to the Python expression: len(o). */ 538 | pub extern "C" fn pymapping_size(obj : PyObjectRef) -> Int = "PyMapping_Size" 539 | 540 | ///| On success, return 1 if the mapping object 'o' has the key 'key', 541 | /// and 0 otherwise. 542 | /// 543 | /// This is equivalent to the Python expression: key in o. 544 | /// 545 | /// This function always succeeds. */ 546 | pub extern "C" fn pymapping_has_key_string( 547 | obj : PyObjectRef, 548 | key : CStr 549 | ) -> Int = "PyMapping_HasKeyString" 550 | 551 | ///| Return 1 if the mapping object has the key 'key', and 0 otherwise. 552 | /// 553 | /// This is equivalent to the Python expression: key in o. 554 | /// 555 | /// This function always succeeds. 556 | pub extern "C" fn pymapping_has_key( 557 | obj : PyObjectRef, 558 | key : PyObjectRef 559 | ) -> Int = "PyMapping_HasKey" 560 | 561 | ///| On success, return a list or tuple of the keys in mapping object 'o'. 562 | /// On failure, return NULL. */ 563 | pub extern "C" fn pymapping_keys(obj : PyObjectRef) -> PyObjectRef = "PyMapping_Keys" 564 | 565 | ///| On success, return a list or tuple of the values in mapping object 'o'. 566 | /// On failure, return NULL. 567 | pub extern "C" fn pymapping_values(obj : PyObjectRef) -> PyObjectRef = "PyMapping_Values" 568 | 569 | ///| On success, return a list or tuple of the items in mapping object 'o', 570 | /// where each item is a tuple containing a key-value pair. On failure, return 571 | /// NULL. 572 | pub extern "C" fn pymapping_items(obj : PyObjectRef) -> PyObjectRef = "PyMapping_Items" 573 | 574 | ///| 575 | pub extern "C" fn pymapping_get_item_string( 576 | obj : PyObjectRef, 577 | key : CStr 578 | ) -> PyObjectRef = "PyMapping_GetItemString" 579 | 580 | ///| 581 | pub extern "C" fn pymapping_set_item_string( 582 | obj : PyObjectRef, 583 | key : CStr, 584 | value : PyObjectRef 585 | ) -> Int = "PyMapping_SetItemString" 586 | 587 | ///| 588 | pub extern "C" fn py_object_is_instance( 589 | obj : PyObjectRef, 590 | typeorclass : PyObjectRef 591 | ) -> Int = "PyObject_IsInstance" 592 | 593 | ///| 594 | pub extern "C" fn py_object_is_subclass( 595 | obj : PyObjectRef, 596 | typeorclass : PyObjectRef 597 | ) -> Int = "PyObject_IsSubclass" 598 | 599 | ///| PyObject repr to string 600 | pub fn py_object_moonbit_repr(obj : PyObjectRef) -> String { 601 | let repr = py_object_repr(obj) 602 | py_unicode_as_moonbit_string(repr) 603 | } 604 | 605 | ///| PyObject str to string 606 | pub fn py_object_moonbit_str(obj : PyObjectRef) -> String { 607 | let str = py_object_str(obj) 608 | py_unicode_as_moonbit_string(str) 609 | } 610 | -------------------------------------------------------------------------------- /cpython/cell.mbt: -------------------------------------------------------------------------------- 1 | // cell 2 | ///| 3 | pub extern "C" fn py_cell_new(a : PyObjectRef) -> PyObjectRef = "PyCell_New" 4 | 5 | ///| 6 | pub extern "C" fn py_cell_get(a : PyObjectRef) -> PyObjectRef = "PyCell_Get" 7 | 8 | ///| 9 | pub extern "C" fn py_cell_set(a : PyObjectRef, b : PyObjectRef) -> Int = "PyCell_Set" 10 | 11 | // Eval 12 | ///| 13 | pub extern "C" fn py_eval_eval_code( 14 | a : PyObjectRef, 15 | b : PyObjectRef, 16 | c : PyObjectRef 17 | ) -> PyObjectRef = "PyEval_EvalCode" 18 | -------------------------------------------------------------------------------- /cpython/ceval.mbt: -------------------------------------------------------------------------------- 1 | // ceval 2 | ///| 3 | pub extern "C" fn py_eval_call_object_with_keywords( 4 | callable : PyObjectRef, 5 | args : PyObjectRef, 6 | kwargs : PyObjectRef 7 | ) -> PyObjectRef = "PyEval_CallObjectWithKeywords" 8 | 9 | // pub extern "C" fn py_eval_call_function(callable: PyObjectRef, format: CStr, ...) -> PyObjectRef = "PyEval_CallFunction" // 可变参数 ... 10 | // pub extern "C" fn py_eval_call_method(obj: PyObjectRef, name: CStr, format: CStr, ...) -> PyObjectRef = "PyEval_CallMethod" // 可变参数 ... 11 | // pub extern "C" fn py_eval_set_profile(a: Py_tracefunc, b: PyObjectRef) = "PyEval_SetProfile" 12 | // pub extern "C" fn py_eval_set_trace(a: Py_tracefunc, b: PyObjectRef) = "PyEval_SetTrace" 13 | ///| 14 | pub extern "C" fn py_eval_get_builtins() -> PyObjectRef = "PyEval_GetBuiltins" 15 | 16 | ///| 17 | pub extern "C" fn py_eval_get_globals() -> PyObjectRef = "PyEval_GetGlobals" 18 | 19 | ///| 20 | pub extern "C" fn py_eval_get_locals() -> PyObjectRef = "PyEval_GetLocals" 21 | 22 | // pub extern "C" fn py_eval_merge_compiler_flags(cf: *PyCompilerFlags) -> Int = "PyEval_MergeCompilerFlags" // 指针类型 * 23 | // pub extern "C" fn py_add_pending_call(func: *fn(a: *Void) -> Int, arg: *Void) -> Int = "Py_AddPendingCall" // 函数指针, void 指针 24 | ///| 25 | pub extern "C" fn py_make_pending_calls() -> Int = "Py_MakePendingCalls" 26 | 27 | ///| 28 | pub extern "C" fn py_set_recursion_limit(a : Int) = "Py_SetRecursionLimit" 29 | 30 | ///| 31 | pub extern "C" fn py_get_recursion_limit() -> Int = "Py_GetRecursionLimit" 32 | 33 | ///| 34 | pub extern "C" fn py_eval_get_func_name(a : PyObjectRef) -> CStr = "PyEval_GetFuncName" 35 | 36 | ///| 37 | pub extern "C" fn py_eval_get_func_desc(a : PyObjectRef) -> CStr = "PyEval_GetFuncDesc" 38 | 39 | ///| 40 | pub extern "C" fn py_eval_save_thread() -> PyThreadStateRef = "PyEval_SaveThread" 41 | 42 | ///| 43 | pub extern "C" fn py_eval_restore_thread(a : PyThreadStateRef) = "PyEval_RestoreThread" 44 | 45 | ///| 46 | pub extern "C" fn py_eval_threads_initialized() -> Int = "PyEval_ThreadsInitialized" 47 | 48 | ///| 49 | pub extern "C" fn py_eval_init_threads() = "PyEval_InitThreads" 50 | 51 | ///| 52 | pub extern "C" fn py_eval_acquire_thread(tstate : PyThreadStateRef) = "PyEval_AcquireThread" 53 | 54 | ///| 55 | pub extern "C" fn py_eval_release_thread(tstate : PyThreadStateRef) = "PyEval_ReleaseThread" 56 | -------------------------------------------------------------------------------- /cpython/class.mbt: -------------------------------------------------------------------------------- 1 | // class 2 | ///| 3 | pub extern "C" fn py_method_new( 4 | a : PyObjectRef, 5 | b : PyObjectRef 6 | ) -> PyObjectRef = "PyMethod_New" 7 | 8 | ///| 9 | pub extern "C" fn py_method_function(a : PyObjectRef) -> PyObjectRef = "PyMethod_Function" 10 | 11 | ///| 12 | pub extern "C" fn py_method_self(a : PyObjectRef) -> PyObjectRef = "PyMethod_Self" 13 | 14 | ///| 15 | pub extern "C" fn py_method_clear_free_list() -> Int = "PyMethod_ClearFreeList" 16 | 17 | ///| 18 | pub extern "C" fn py_instance_method_new(a : PyObjectRef) -> PyObjectRef = "PyInstanceMethod_New" 19 | 20 | ///| 21 | pub extern "C" fn py_instance_method_function(a : PyObjectRef) -> PyObjectRef = "PyInstanceMethod_Function" 22 | -------------------------------------------------------------------------------- /cpython/code.mbt: -------------------------------------------------------------------------------- 1 | // code 2 | ///| 3 | pub extern "C" fn py_code_new( 4 | a : Int, 5 | b : Int, 6 | c : Int, 7 | d : Int, 8 | e : Int, 9 | f : PyObjectRef, 10 | g : PyObjectRef, 11 | h : PyObjectRef, 12 | i : PyObjectRef, 13 | j : PyObjectRef, 14 | k : PyObjectRef, 15 | l : PyObjectRef, 16 | m : PyObjectRef, 17 | n : Int, 18 | o : PyObjectRef 19 | ) -> PyCodeObjectRef = "PyCode_New" 20 | 21 | ///| 22 | pub extern "C" fn py_code_new_with_pos_only_args( 23 | a : Int, 24 | b : Int, 25 | c : Int, 26 | d : Int, 27 | e : Int, 28 | f : Int, 29 | g : PyObjectRef, 30 | h : PyObjectRef, 31 | i : PyObjectRef, 32 | j : PyObjectRef, 33 | k : PyObjectRef, 34 | l : PyObjectRef, 35 | m : PyObjectRef, 36 | n : PyObjectRef, 37 | o : Int, 38 | p : PyObjectRef 39 | ) -> PyCodeObjectRef = "PyCode_NewWithPosOnlyArgs" 40 | 41 | ///| 42 | pub extern "C" fn py_code_new_empty( 43 | filename : CStr, 44 | funcname : CStr, 45 | firstlineno : Int 46 | ) -> PyCodeObjectRef = "PyCode_NewEmpty" 47 | 48 | ///| 49 | pub extern "C" fn py_code_addr2_line(a : PyCodeObjectRef, b : Int) -> Int = "PyCode_Addr2Line" 50 | -------------------------------------------------------------------------------- /cpython/codecs.mbt: -------------------------------------------------------------------------------- 1 | // code cs 2 | ///| 3 | pub extern "C" fn py_codec_register(search_function : PyObjectRef) -> Int = "PyCodec_Register" 4 | 5 | ///| 6 | pub extern "C" fn py_codec_known_encoding(encoding : CStr) -> Int = "PyCodec_KnownEncoding" 7 | 8 | ///| 9 | pub extern "C" fn py_codec_encode( 10 | object : PyObjectRef, 11 | encoding : CStr, 12 | errors : CStr 13 | ) -> PyObjectRef = "PyCodec_Encode" 14 | 15 | ///| 16 | pub extern "C" fn py_codec_decode( 17 | object : PyObjectRef, 18 | encoding : CStr, 19 | errors : CStr 20 | ) -> PyObjectRef = "PyCodec_Decode" 21 | 22 | ///| 23 | pub extern "C" fn py_codec_encoder(encoding : CStr) -> PyObjectRef = "PyCodec_Encoder" 24 | 25 | ///| 26 | pub extern "C" fn py_codec_decoder(encoding : CStr) -> PyObjectRef = "PyCodec_Decoder" 27 | 28 | ///| 29 | pub extern "C" fn py_codec_incremental_encoder( 30 | encoding : CStr, 31 | errors : CStr 32 | ) -> PyObjectRef = "PyCodec_IncrementalEncoder" 33 | 34 | ///| 35 | pub extern "C" fn py_codec_incremental_decoder( 36 | encoding : CStr, 37 | errors : CStr 38 | ) -> PyObjectRef = "PyCodec_IncrementalDecoder" 39 | 40 | ///| 41 | pub extern "C" fn py_codec_stream_reader( 42 | encoding : CStr, 43 | stream : PyObjectRef, 44 | errors : CStr 45 | ) -> PyObjectRef = "PyCodec_StreamReader" 46 | 47 | ///| 48 | pub extern "C" fn py_codec_stream_writer( 49 | encoding : CStr, 50 | stream : PyObjectRef, 51 | errors : CStr 52 | ) -> PyObjectRef = "PyCodec_StreamWriter" 53 | 54 | ///| 55 | pub extern "C" fn py_codec_register_error( 56 | name : CStr, 57 | error : PyObjectRef 58 | ) -> Int = "PyCodec_RegisterError" 59 | 60 | ///| 61 | pub extern "C" fn py_codec_lookup_error(name : CStr) -> PyObjectRef = "PyCodec_LookupError" 62 | 63 | ///| 64 | pub extern "C" fn py_codec_strict_errors(exc : PyObjectRef) -> PyObjectRef = "PyCodec_StrictErrors" 65 | 66 | ///| 67 | pub extern "C" fn py_codec_ignore_errors(exc : PyObjectRef) -> PyObjectRef = "PyCodec_IgnoreErrors" 68 | 69 | ///| 70 | pub extern "C" fn py_codec_replace_errors(exc : PyObjectRef) -> PyObjectRef = "PyCodec_ReplaceErrors" 71 | 72 | ///| 73 | pub extern "C" fn py_codec_xml_char_ref_replace_errors( 74 | exc : PyObjectRef 75 | ) -> PyObjectRef = "PyCodec_XMLCharRefReplaceErrors" 76 | 77 | ///| 78 | pub extern "C" fn py_codec_backslash_replace_errors( 79 | exc : PyObjectRef 80 | ) -> PyObjectRef = "PyCodec_BackslashReplaceErrors" 81 | 82 | ///| 83 | pub extern "C" fn py_codec_name_replace_errors( 84 | exc : PyObjectRef 85 | ) -> PyObjectRef = "PyCodec_NameReplaceErrors" 86 | -------------------------------------------------------------------------------- /cpython/context.mbt: -------------------------------------------------------------------------------- 1 | // context 2 | ///| 3 | pub extern "C" fn py_context_new() -> PyObjectRef = "PyContext_New" 4 | 5 | ///| 6 | pub extern "C" fn py_context_copy(a : PyObjectRef) -> PyObjectRef = "PyContext_Copy" 7 | 8 | ///| 9 | pub extern "C" fn py_context_copy_current() -> PyObjectRef = "PyContext_CopyCurrent" 10 | 11 | ///| 12 | pub extern "C" fn py_context_enter(a : PyObjectRef) -> Int = "PyContext_Enter" 13 | 14 | ///| 15 | pub extern "C" fn py_context_exit(a : PyObjectRef) -> Int = "PyContext_Exit" 16 | 17 | ///| 18 | pub extern "C" fn py_context_var_new( 19 | name : CStr, 20 | default_value : PyObjectRef 21 | ) -> PyObjectRef = "PyContextVar_New" 22 | 23 | ///| 24 | pub extern "C" fn py_context_var_get( 25 | var : PyObjectRef, 26 | default_value : PyObjectRef, 27 | value : ArrayPyObjectRef 28 | ) -> Int = "PyContextVar_Get" 29 | 30 | ///| 31 | pub extern "C" fn py_context_var_set( 32 | var : PyObjectRef, 33 | value : PyObjectRef 34 | ) -> PyObjectRef = "PyContextVar_Set" 35 | 36 | ///| 37 | pub extern "C" fn py_context_var_reset( 38 | var : PyObjectRef, 39 | token : PyObjectRef 40 | ) -> Int = "PyContextVar_Reset" 41 | 42 | ///| 43 | pub extern "C" fn _py_context_new_hamt_for_tests() -> PyObjectRef = "_PyContext_NewHamtForTests" 44 | 45 | ///| 46 | pub extern "C" fn py_context_clear_free_list() -> Int = "PyContext_ClearFreeList" 47 | -------------------------------------------------------------------------------- /cpython/core.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | type CStr // const char* 3 | 4 | ///| 5 | type CWStr // const wchar_t* 6 | 7 | ///| 8 | type PyObjectRef // PyObject* 9 | 10 | ///| 11 | type PyThreadStateRef // PyThreadState* 12 | 13 | ///| 14 | type PyCodeObjectRef // PyCodeObject* 15 | 16 | ///| 17 | type ArrayPyObjectRef // PyObject*[] 18 | 19 | ///| 20 | type PyTypeObjectRef 21 | 22 | ///| 23 | extern "C" fn moonbit_str_to_c_str(s : String) -> CStr = "moonbit_str_to_c_str" 24 | 25 | ///| 26 | extern "C" fn c_str_to_moonbit_str(s : CStr) -> String = "c_str_to_moonbit_str" 27 | 28 | ///| 29 | extern "C" fn c_str_to_moonbit_str_with_length(s : CStr, len : UInt) -> String = "c_str_to_moonbit_str_with_length" 30 | 31 | ///| 32 | extern "C" fn moonbit_str_to_cw_str(s : String) -> CWStr = "moonbit_str_to_cw_str" 33 | 34 | ///| 35 | extern "C" fn cw_str_to_moonbit_str(s : CWStr) -> String = "cw_str_to_moonbit_str" 36 | 37 | ///| 38 | extern "C" fn cw_str_to_moonbit_str_with_length( 39 | s : CWStr, 40 | len : UInt 41 | ) -> String = "cw_str_to_moonbit_str_with_length" 42 | 43 | ///| 44 | fn CStr::from(s : String) -> CStr { 45 | moonbit_str_to_c_str(s) 46 | } 47 | 48 | ///| 49 | fn CStr::to_string(self : CStr) -> String { 50 | c_str_to_moonbit_str(self) 51 | } 52 | 53 | ///| 54 | fn CStr::to_string_with_length(self : CStr, len : UInt) -> String { 55 | c_str_to_moonbit_str_with_length(self, len) 56 | } 57 | 58 | ///| 59 | fn CWStr::from(s : String) -> CWStr { 60 | moonbit_str_to_cw_str(s) 61 | } 62 | 63 | ///| 64 | fn CWStr::to_string(self : CWStr) -> String { 65 | cw_str_to_moonbit_str(self) 66 | } 67 | 68 | ///| 69 | fn CWStr::to_string_with_length(self : CWStr, len : UInt) -> String { 70 | cw_str_to_moonbit_str_with_length(self, len) 71 | } 72 | 73 | ///| 74 | extern "C" fn py_object_is_null(obj : PyObjectRef) -> Int = "Moonbit_PyObjectRef_is_null" 75 | 76 | ///| 77 | pub fn PyObjectRef::is_null(self : PyObjectRef) -> Bool { 78 | py_object_is_null(self) != 0 79 | } 80 | 81 | ///| 82 | pub extern "C" fn print_pyobject(obj : PyObjectRef) = "print_pyobject" 83 | 84 | ///| 85 | pub fn PyObjectRef::dump(self : PyObjectRef) -> Unit { 86 | print_pyobject(self) 87 | } 88 | 89 | ///| 90 | pub extern "C" fn py_incref(obj : PyObjectRef) = "py_incref" 91 | 92 | ///| 93 | pub extern "C" fn py_decref(obj : PyObjectRef) = "py_decref" 94 | -------------------------------------------------------------------------------- /cpython/cpython.mbti: -------------------------------------------------------------------------------- 1 | package "Kaida-Amethyst/python/cpython" 2 | 3 | // Values 4 | fn __py_callable_check(PyObjectRef) -> Int 5 | 6 | fn __py_dict_contains(PyObjectRef, PyObjectRef) -> Int 7 | 8 | fn _py_context_new_hamt_for_tests() -> PyObjectRef 9 | 10 | fn print_pyobject(PyObjectRef) -> Unit 11 | 12 | fn py_bool_check(PyObjectRef) -> Bool 13 | 14 | fn py_bool_from_long(Int64) -> PyObjectRef 15 | 16 | fn py_call_iter_new(PyObjectRef, PyObjectRef) -> PyObjectRef 17 | 18 | fn py_callable_check(PyObjectRef) -> Bool 19 | 20 | fn py_cell_get(PyObjectRef) -> PyObjectRef 21 | 22 | fn py_cell_new(PyObjectRef) -> PyObjectRef 23 | 24 | fn py_cell_set(PyObjectRef, PyObjectRef) -> Int 25 | 26 | fn py_class_method_new(PyObjectRef) -> PyObjectRef 27 | 28 | fn py_code_addr2_line(PyCodeObjectRef, Int) -> Int 29 | 30 | fn py_code_new(Int, Int, Int, Int, Int, PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, Int, PyObjectRef) -> PyCodeObjectRef 31 | 32 | fn py_code_new_empty(CStr, CStr, Int) -> PyCodeObjectRef 33 | 34 | fn py_code_new_with_pos_only_args(Int, Int, Int, Int, Int, Int, PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, Int, PyObjectRef) -> PyCodeObjectRef 35 | 36 | fn py_codec_backslash_replace_errors(PyObjectRef) -> PyObjectRef 37 | 38 | fn py_codec_decode(PyObjectRef, CStr, CStr) -> PyObjectRef 39 | 40 | fn py_codec_decoder(CStr) -> PyObjectRef 41 | 42 | fn py_codec_encode(PyObjectRef, CStr, CStr) -> PyObjectRef 43 | 44 | fn py_codec_encoder(CStr) -> PyObjectRef 45 | 46 | fn py_codec_ignore_errors(PyObjectRef) -> PyObjectRef 47 | 48 | fn py_codec_incremental_decoder(CStr, CStr) -> PyObjectRef 49 | 50 | fn py_codec_incremental_encoder(CStr, CStr) -> PyObjectRef 51 | 52 | fn py_codec_known_encoding(CStr) -> Int 53 | 54 | fn py_codec_lookup_error(CStr) -> PyObjectRef 55 | 56 | fn py_codec_name_replace_errors(PyObjectRef) -> PyObjectRef 57 | 58 | fn py_codec_register(PyObjectRef) -> Int 59 | 60 | fn py_codec_register_error(CStr, PyObjectRef) -> Int 61 | 62 | fn py_codec_replace_errors(PyObjectRef) -> PyObjectRef 63 | 64 | fn py_codec_stream_reader(CStr, PyObjectRef, CStr) -> PyObjectRef 65 | 66 | fn py_codec_stream_writer(CStr, PyObjectRef, CStr) -> PyObjectRef 67 | 68 | fn py_codec_strict_errors(PyObjectRef) -> PyObjectRef 69 | 70 | fn py_codec_xml_char_ref_replace_errors(PyObjectRef) -> PyObjectRef 71 | 72 | fn py_complex_from_doubles(Double, Double) -> PyObjectRef 73 | 74 | fn py_complex_imag_as_double(PyObjectRef) -> Double 75 | 76 | fn py_complex_real_as_double(PyObjectRef) -> Double 77 | 78 | fn py_context_clear_free_list() -> Int 79 | 80 | fn py_context_copy(PyObjectRef) -> PyObjectRef 81 | 82 | fn py_context_copy_current() -> PyObjectRef 83 | 84 | fn py_context_enter(PyObjectRef) -> Int 85 | 86 | fn py_context_exit(PyObjectRef) -> Int 87 | 88 | fn py_context_new() -> PyObjectRef 89 | 90 | fn py_context_var_get(PyObjectRef, PyObjectRef, ArrayPyObjectRef) -> Int 91 | 92 | fn py_context_var_new(CStr, PyObjectRef) -> PyObjectRef 93 | 94 | fn py_context_var_reset(PyObjectRef, PyObjectRef) -> Int 95 | 96 | fn py_context_var_set(PyObjectRef, PyObjectRef) -> PyObjectRef 97 | 98 | fn py_decref(PyObjectRef) -> Unit 99 | 100 | fn py_dict_check(PyObjectRef) -> Bool 101 | 102 | fn py_dict_clear(PyObjectRef) -> Unit 103 | 104 | fn py_dict_contains(PyObjectRef, PyObjectRef) -> Bool 105 | 106 | fn py_dict_copy(PyObjectRef) -> PyObjectRef 107 | 108 | fn py_dict_del_item(PyObjectRef, PyObjectRef) -> Int 109 | 110 | fn py_dict_del_item_string(PyObjectRef, String) -> Int 111 | 112 | fn py_dict_get_item(PyObjectRef, PyObjectRef) -> PyObjectRef 113 | 114 | fn py_dict_get_item_string(PyObjectRef, String) -> PyObjectRef 115 | 116 | fn py_dict_items(PyObjectRef) -> PyObjectRef 117 | 118 | fn py_dict_keys(PyObjectRef) -> PyObjectRef 119 | 120 | fn py_dict_merge(PyObjectRef, PyObjectRef, Int) -> Int 121 | 122 | fn py_dict_merge_from_seq2(PyObjectRef, PyObjectRef, Int) -> Int 123 | 124 | fn py_dict_new() -> PyObjectRef 125 | 126 | fn py_dict_set_item(PyObjectRef, PyObjectRef, PyObjectRef) -> Int 127 | 128 | fn py_dict_set_item_string(PyObjectRef, String, PyObjectRef) -> Int 129 | 130 | fn py_dict_size(PyObjectRef) -> UInt64 131 | 132 | fn py_dict_update(PyObjectRef, PyObjectRef) -> Int 133 | 134 | fn py_dict_values(PyObjectRef) -> PyObjectRef 135 | 136 | fn py_err_clear() -> Unit 137 | 138 | fn py_err_occurred() -> PyObjectRef 139 | 140 | fn py_err_print() -> Unit 141 | 142 | fn py_eval_acquire_thread(PyThreadStateRef) -> Unit 143 | 144 | fn py_eval_call_object_with_keywords(PyObjectRef, PyObjectRef, PyObjectRef) -> PyObjectRef 145 | 146 | fn py_eval_eval_code(PyObjectRef, PyObjectRef, PyObjectRef) -> PyObjectRef 147 | 148 | fn py_eval_get_builtins() -> PyObjectRef 149 | 150 | fn py_eval_get_func_desc(PyObjectRef) -> CStr 151 | 152 | fn py_eval_get_func_name(PyObjectRef) -> CStr 153 | 154 | fn py_eval_get_globals() -> PyObjectRef 155 | 156 | fn py_eval_get_locals() -> PyObjectRef 157 | 158 | fn py_eval_init_threads() -> Unit 159 | 160 | fn py_eval_release_thread(PyThreadStateRef) -> Unit 161 | 162 | fn py_eval_restore_thread(PyThreadStateRef) -> Unit 163 | 164 | fn py_eval_save_thread() -> PyThreadStateRef 165 | 166 | fn py_eval_threads_initialized() -> Int 167 | 168 | fn py_file_from_fd(Int, CStr, CStr, Int, CStr, CStr, CStr, Int) -> PyObjectRef 169 | 170 | fn py_file_get_line(PyObjectRef, Int) -> PyObjectRef 171 | 172 | fn py_file_new_std_printer(Int) -> PyObjectRef 173 | 174 | fn py_file_open_code(CStr) -> PyObjectRef 175 | 176 | fn py_file_open_code_object(PyObjectRef) -> PyObjectRef 177 | 178 | fn py_file_write_object(PyObjectRef, PyObjectRef, Int) -> Int 179 | 180 | fn py_file_write_string(CStr, PyObjectRef) -> Int 181 | 182 | fn py_finalize() -> Unit 183 | 184 | fn py_float_as_double(PyObjectRef) -> Double 185 | 186 | fn py_float_check(PyObjectRef) -> Bool 187 | 188 | fn py_float_from_double(Double) -> PyObjectRef 189 | 190 | fn py_float_from_string(PyObjectRef) -> PyObjectRef 191 | 192 | fn py_float_get_info() -> PyObjectRef 193 | 194 | fn py_float_get_max() -> Double 195 | 196 | fn py_float_get_min() -> Double 197 | 198 | fn py_frozen_set_new(PyObjectRef) -> PyObjectRef 199 | 200 | fn py_function_check(PyObjectRef) -> Bool 201 | 202 | fn py_function_get_annotations(PyObjectRef) -> PyObjectRef 203 | 204 | fn py_function_get_closure(PyObjectRef) -> PyObjectRef 205 | 206 | fn py_function_get_code(PyObjectRef) -> PyObjectRef 207 | 208 | fn py_function_get_defaults(PyObjectRef) -> PyObjectRef 209 | 210 | fn py_function_get_globals(PyObjectRef) -> PyObjectRef 211 | 212 | fn py_function_get_kw_defaults(PyObjectRef) -> PyObjectRef 213 | 214 | fn py_function_get_module(PyObjectRef) -> PyObjectRef 215 | 216 | fn py_function_new(PyObjectRef, PyObjectRef) -> PyObjectRef 217 | 218 | fn py_function_new_with_qual_name(PyObjectRef, PyObjectRef, PyObjectRef) -> PyObjectRef 219 | 220 | fn py_function_set_annotations(PyObjectRef, PyObjectRef) -> Int 221 | 222 | fn py_function_set_closure(PyObjectRef, PyObjectRef) -> Int 223 | 224 | fn py_function_set_defaults(PyObjectRef, PyObjectRef) -> Int 225 | 226 | fn py_function_set_kw_defaults(PyObjectRef, PyObjectRef) -> Int 227 | 228 | fn py_get_recursion_limit() -> Int 229 | 230 | fn py_import_add_module(CStr) -> PyObjectRef 231 | 232 | fn py_import_add_module_object(PyObjectRef) -> PyObjectRef 233 | 234 | fn py_import_cleanup() -> Unit 235 | 236 | fn py_import_exec_code_module(CStr, PyObjectRef) -> PyObjectRef 237 | 238 | fn py_import_exec_code_module_ex(CStr, PyObjectRef, CStr) -> PyObjectRef 239 | 240 | fn py_import_exec_code_module_object(PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef) -> PyObjectRef 241 | 242 | fn py_import_exec_code_module_with_pathnames(CStr, PyObjectRef, CStr, CStr) -> PyObjectRef 243 | 244 | fn py_import_get_importer(PyObjectRef) -> PyObjectRef 245 | 246 | fn py_import_get_magic_number() -> Int 247 | 248 | fn py_import_get_magic_tag() -> CStr 249 | 250 | fn py_import_get_module(PyObjectRef) -> PyObjectRef 251 | 252 | fn py_import_get_module_dict() -> PyObjectRef 253 | 254 | fn py_import_import(PyObjectRef) -> PyObjectRef 255 | 256 | fn py_import_import_frozen_module(CStr) -> Int 257 | 258 | fn py_import_import_frozen_module_object(PyObjectRef) -> Int 259 | 260 | fn py_import_import_module(String) -> PyObjectRef 261 | 262 | fn py_import_import_module_level(CStr, PyObjectRef, PyObjectRef, PyObjectRef, Int) -> PyObjectRef 263 | 264 | fn py_import_import_module_level_object(PyObjectRef, PyObjectRef, PyObjectRef, PyObjectRef, Int) -> PyObjectRef 265 | 266 | fn py_import_import_module_no_block(CStr) -> PyObjectRef 267 | 268 | fn py_import_reload_module(PyObjectRef) -> PyObjectRef 269 | 270 | fn py_incref(PyObjectRef) -> Unit 271 | 272 | fn py_init() -> Unit 273 | 274 | fn py_instance_method_function(PyObjectRef) -> PyObjectRef 275 | 276 | fn py_instance_method_new(PyObjectRef) -> PyObjectRef 277 | 278 | fn py_int_check(PyObjectRef) -> Bool 279 | 280 | fn py_is_initialized() -> Bool 281 | 282 | fn py_list_append(PyObjectRef, PyObjectRef) -> Int 283 | 284 | fn py_list_as_tuple(PyObjectRef) -> PyObjectRef 285 | 286 | fn py_list_check(PyObjectRef) -> Bool 287 | 288 | fn py_list_get_item(PyObjectRef, Int64) -> PyObjectRef 289 | 290 | fn py_list_get_slice(PyObjectRef, Int64, Int64) -> PyObjectRef 291 | 292 | fn py_list_insert(PyObjectRef, Int64, PyObjectRef) -> Int 293 | 294 | fn py_list_new(Int64) -> PyObjectRef 295 | 296 | fn py_list_reverse(PyObjectRef) -> Int 297 | 298 | fn py_list_set_item(PyObjectRef, Int64, PyObjectRef) -> Int 299 | 300 | fn py_list_set_slice(PyObjectRef, Int64, Int64, PyObjectRef) -> Int 301 | 302 | fn py_list_size(PyObjectRef) -> Int64 303 | 304 | fn py_list_sort(PyObjectRef) -> Int 305 | 306 | fn py_long_as_double(PyObjectRef) -> Double 307 | 308 | fn py_long_as_long(PyObjectRef) -> Int64 309 | 310 | fn py_long_from_long(Int64) -> PyObjectRef 311 | 312 | fn py_make_pending_calls() -> Int 313 | 314 | fn py_method_clear_free_list() -> Int 315 | 316 | fn py_method_function(PyObjectRef) -> PyObjectRef 317 | 318 | fn py_method_new(PyObjectRef, PyObjectRef) -> PyObjectRef 319 | 320 | fn py_method_self(PyObjectRef) -> PyObjectRef 321 | 322 | fn py_module_check(PyObjectRef) -> Bool 323 | 324 | fn py_module_get_dict(PyObjectRef) -> PyObjectRef 325 | 326 | fn py_module_get_filename_object(PyObjectRef) -> PyObjectRef 327 | 328 | fn py_module_get_name(PyObjectRef) -> CStr 329 | 330 | fn py_module_get_name_object(PyObjectRef) -> PyObjectRef 331 | 332 | fn py_module_new(CStr) -> PyObjectRef 333 | 334 | fn py_module_new_object(PyObjectRef) -> PyObjectRef 335 | 336 | fn py_none_check(PyObjectRef) -> Bool 337 | 338 | fn py_object_as_file_descriptor(PyObjectRef) -> Int 339 | 340 | fn py_object_ascii(PyObjectRef) -> PyObjectRef 341 | 342 | fn py_object_bytes(PyObjectRef) -> PyObjectRef 343 | 344 | fn py_object_call(PyObjectRef, PyObjectRef, PyObjectRef) -> PyObjectRef 345 | 346 | fn py_object_call_object(PyObjectRef, PyObjectRef) -> PyObjectRef 347 | 348 | fn py_object_clear_weak_refs(PyObjectRef) -> Unit 349 | 350 | fn py_object_del_item(PyObjectRef, PyObjectRef) -> Int 351 | 352 | fn py_object_del_item_string(PyObjectRef, CStr) -> Int 353 | 354 | fn py_object_dir(PyObjectRef) -> PyObjectRef 355 | 356 | fn py_object_generic_get_attr(PyObjectRef, PyObjectRef) -> PyObjectRef 357 | 358 | fn py_object_generic_set_attr(PyObjectRef, PyObjectRef, PyObjectRef) -> Int 359 | 360 | fn py_object_get_attr(PyObjectRef, PyObjectRef) -> PyObjectRef 361 | 362 | fn py_object_get_attr_string(PyObjectRef, String) -> PyObjectRef 363 | 364 | fn py_object_get_item(PyObjectRef, PyObjectRef) -> PyObjectRef 365 | 366 | fn py_object_get_iter(PyObjectRef) -> PyObjectRef 367 | 368 | fn py_object_has_attr(PyObjectRef, PyObjectRef) -> Int 369 | 370 | fn py_object_has_attr_string(PyObjectRef, String) -> Int 371 | 372 | fn py_object_is_instance(PyObjectRef, PyObjectRef) -> Int 373 | 374 | fn py_object_is_subclass(PyObjectRef, PyObjectRef) -> Int 375 | 376 | fn py_object_is_true(PyObjectRef) -> Bool 377 | 378 | fn py_object_moonbit_repr(PyObjectRef) -> String 379 | 380 | fn py_object_moonbit_str(PyObjectRef) -> String 381 | 382 | fn py_object_not(PyObjectRef) -> Int 383 | 384 | fn py_object_repr(PyObjectRef) -> PyObjectRef 385 | 386 | fn py_object_rich_compare(PyObjectRef, PyObjectRef, Int) -> PyObjectRef 387 | 388 | fn py_object_rich_compare_bool(PyObjectRef, PyObjectRef, Int) -> Int 389 | 390 | fn py_object_self_iter(PyObjectRef) -> PyObjectRef 391 | 392 | fn py_object_set_attr(PyObjectRef, PyObjectRef, PyObjectRef) -> Int 393 | 394 | fn py_object_set_attr_string(PyObjectRef, String, PyObjectRef) -> Int 395 | 396 | fn py_object_set_item(PyObjectRef, PyObjectRef, PyObjectRef) -> Int 397 | 398 | fn py_object_size(PyObjectRef) -> UInt64 399 | 400 | fn py_object_str(PyObjectRef) -> PyObjectRef 401 | 402 | fn py_object_type(PyObjectRef) -> PyObjectRef 403 | 404 | fn py_odict_del_item(PyObjectRef, PyObjectRef) -> Int 405 | 406 | fn py_odict_new() -> PyObjectRef 407 | 408 | fn py_odict_set_item(PyObjectRef, PyObjectRef, PyObjectRef) -> Int 409 | 410 | fn py_repr_enter(PyObjectRef) -> Int 411 | 412 | fn py_repr_leave(PyObjectRef) -> Unit 413 | 414 | fn py_seq_iter_new(PyObjectRef) -> PyObjectRef 415 | 416 | fn py_set_add(PyObjectRef, PyObjectRef) -> Int 417 | 418 | fn py_set_check(PyObjectRef) -> Bool 419 | 420 | fn py_set_clear(PyObjectRef) -> Int 421 | 422 | fn py_set_contains(PyObjectRef, PyObjectRef) -> Int 423 | 424 | fn py_set_discard(PyObjectRef, PyObjectRef) -> Int 425 | 426 | fn py_set_new(PyObjectRef) -> PyObjectRef 427 | 428 | fn py_set_pop(PyObjectRef) -> PyObjectRef 429 | 430 | fn py_set_recursion_limit(Int) -> Unit 431 | 432 | fn py_set_size(PyObjectRef) -> Int64 433 | 434 | fn py_static_method_new(PyObjectRef) -> PyObjectRef 435 | 436 | fn py_string_check(PyObjectRef) -> Bool 437 | 438 | fn py_tuple_check(PyObjectRef) -> Bool 439 | 440 | fn py_type(PyObjectRef) -> PyTypeObjectRef 441 | 442 | fn py_type_name(PyTypeObjectRef) -> String 443 | 444 | fn py_unicode_as_moonbit_string(PyObjectRef) -> String 445 | 446 | fn py_unicode_as_utf16_string(PyObjectRef) -> PyObjectRef 447 | 448 | fn py_unicode_as_utf8(PyObjectRef) -> String 449 | 450 | fn py_unicode_from_moonbit_string(String) -> PyObjectRef 451 | 452 | fn py_unicode_from_string(String) -> PyObjectRef 453 | 454 | fn py_unicode_from_string_and_size(CStr, UInt64) -> PyObjectRef 455 | 456 | fn py_unicode_from_unicode(CWStr, UInt64) -> PyObjectRef 457 | 458 | fn pyindex_check(PyObjectRef) -> Int 459 | 460 | fn pyiter_check(PyObjectRef) -> Int 461 | 462 | fn pyiter_next(PyObjectRef) -> PyObjectRef 463 | 464 | fn pymapping_check(PyObjectRef) -> Int 465 | 466 | fn pymapping_get_item_string(PyObjectRef, CStr) -> PyObjectRef 467 | 468 | fn pymapping_has_key(PyObjectRef, PyObjectRef) -> Int 469 | 470 | fn pymapping_has_key_string(PyObjectRef, CStr) -> Int 471 | 472 | fn pymapping_items(PyObjectRef) -> PyObjectRef 473 | 474 | fn pymapping_keys(PyObjectRef) -> PyObjectRef 475 | 476 | fn pymapping_set_item_string(PyObjectRef, CStr, PyObjectRef) -> Int 477 | 478 | fn pymapping_size(PyObjectRef) -> Int 479 | 480 | fn pymapping_values(PyObjectRef) -> PyObjectRef 481 | 482 | fn pynumber_absolute(PyObjectRef) -> PyObjectRef 483 | 484 | fn pynumber_add(PyObjectRef, PyObjectRef) -> PyObjectRef 485 | 486 | fn pynumber_and(PyObjectRef, PyObjectRef) -> PyObjectRef 487 | 488 | fn pynumber_as_ssize_t(PyObjectRef, PyObjectRef) -> Int 489 | 490 | fn pynumber_check(PyObjectRef) -> Int 491 | 492 | fn pynumber_divmod(PyObjectRef, PyObjectRef) -> PyObjectRef 493 | 494 | fn pynumber_float(PyObjectRef) -> PyObjectRef 495 | 496 | fn pynumber_floor_divide(PyObjectRef, PyObjectRef) -> PyObjectRef 497 | 498 | fn pynumber_index(PyObjectRef) -> PyObjectRef 499 | 500 | fn pynumber_inplace_add(PyObjectRef, PyObjectRef) -> PyObjectRef 501 | 502 | fn pynumber_inplace_and(PyObjectRef, PyObjectRef) -> PyObjectRef 503 | 504 | fn pynumber_inplace_floor_divide(PyObjectRef, PyObjectRef) -> PyObjectRef 505 | 506 | fn pynumber_inplace_lshift(PyObjectRef, PyObjectRef) -> PyObjectRef 507 | 508 | fn pynumber_inplace_multiply(PyObjectRef, PyObjectRef) -> PyObjectRef 509 | 510 | fn pynumber_inplace_or(PyObjectRef, PyObjectRef) -> PyObjectRef 511 | 512 | fn pynumber_inplace_power(PyObjectRef, PyObjectRef, PyObjectRef) -> PyObjectRef 513 | 514 | fn pynumber_inplace_remainder(PyObjectRef, PyObjectRef) -> PyObjectRef 515 | 516 | fn pynumber_inplace_rshift(PyObjectRef, PyObjectRef) -> PyObjectRef 517 | 518 | fn pynumber_inplace_subtract(PyObjectRef, PyObjectRef) -> PyObjectRef 519 | 520 | fn pynumber_inplace_true_divide(PyObjectRef, PyObjectRef) -> PyObjectRef 521 | 522 | fn pynumber_inplace_xor(PyObjectRef, PyObjectRef) -> PyObjectRef 523 | 524 | fn pynumber_invert(PyObjectRef) -> PyObjectRef 525 | 526 | fn pynumber_long(PyObjectRef) -> PyObjectRef 527 | 528 | fn pynumber_lshift(PyObjectRef, PyObjectRef) -> PyObjectRef 529 | 530 | fn pynumber_multiply(PyObjectRef, PyObjectRef) -> PyObjectRef 531 | 532 | fn pynumber_negative(PyObjectRef) -> PyObjectRef 533 | 534 | fn pynumber_or(PyObjectRef, PyObjectRef) -> PyObjectRef 535 | 536 | fn pynumber_positive(PyObjectRef) -> PyObjectRef 537 | 538 | fn pynumber_power(PyObjectRef, PyObjectRef, PyObjectRef) -> PyObjectRef 539 | 540 | fn pynumber_remainder(PyObjectRef, PyObjectRef) -> PyObjectRef 541 | 542 | fn pynumber_rshift(PyObjectRef, PyObjectRef) -> PyObjectRef 543 | 544 | fn pynumber_subtract(PyObjectRef, PyObjectRef) -> PyObjectRef 545 | 546 | fn pynumber_to_base(PyObjectRef, Int) -> PyObjectRef 547 | 548 | fn pynumber_true_divide(PyObjectRef, PyObjectRef) -> PyObjectRef 549 | 550 | fn pynumber_xor(PyObjectRef, PyObjectRef) -> PyObjectRef 551 | 552 | fn pyobkect_format(PyObjectRef, PyObjectRef) -> PyObjectRef 553 | 554 | fn pysequence_check(PyObjectRef) -> Int 555 | 556 | fn pysequence_concat(PyObjectRef, PyObjectRef) -> PyObjectRef 557 | 558 | fn pysequence_contains(PyObjectRef, PyObjectRef) -> Int 559 | 560 | fn pysequence_count(PyObjectRef, PyObjectRef) -> Int 561 | 562 | fn pysequence_del_item(PyObjectRef, UInt64) -> Int 563 | 564 | fn pysequence_del_slice(PyObjectRef, UInt64, UInt64) -> Int 565 | 566 | fn pysequence_fast(PyObjectRef, CStr) -> PyObjectRef 567 | 568 | fn pysequence_get_item(PyObjectRef, UInt64) -> PyObjectRef 569 | 570 | fn pysequence_get_slice(PyObjectRef, UInt64, UInt64) -> PyObjectRef 571 | 572 | fn pysequence_index(PyObjectRef, PyObjectRef) -> Int 573 | 574 | fn pysequence_inplace_concat(PyObjectRef, PyObjectRef) -> PyObjectRef 575 | 576 | fn pysequence_inplace_repeat(PyObjectRef, Int) -> PyObjectRef 577 | 578 | fn pysequence_list(PyObjectRef) -> PyObjectRef 579 | 580 | fn pysequence_repeat(PyObjectRef, Int) -> PyObjectRef 581 | 582 | fn pysequence_set_item(PyObjectRef, UInt64, PyObjectRef) -> Int 583 | 584 | fn pysequence_set_slice(PyObjectRef, UInt64, UInt64, PyObjectRef) -> Int 585 | 586 | fn pysequence_size(PyObjectRef) -> Int 587 | 588 | fn pysequence_tuple(PyObjectRef) -> PyObjectRef 589 | 590 | fn pytuple_get_item(PyObjectRef, UInt64) -> PyObjectRef 591 | 592 | fn pytuple_get_slice(PyObjectRef, UInt64, UInt64) -> PyObjectRef 593 | 594 | fn pytuple_new(UInt64) -> PyObjectRef 595 | 596 | fn pytuple_set_item(PyObjectRef, UInt64, PyObjectRef) -> Int 597 | 598 | fn pytuple_size(PyObjectRef) -> UInt64 599 | 600 | // Types and methods 601 | type ArrayPyObjectRef 602 | 603 | type CStr 604 | 605 | type CWStr 606 | 607 | type PyCodeObjectRef 608 | 609 | type PyObjectRef 610 | fn PyObjectRef::dump(Self) -> Unit 611 | fn PyObjectRef::is_bool(Self) -> Bool 612 | fn PyObjectRef::is_callable(Self) -> Bool 613 | fn PyObjectRef::is_dict(Self) -> Bool 614 | fn PyObjectRef::is_float(Self) -> Bool 615 | fn PyObjectRef::is_function(Self) -> Bool 616 | fn PyObjectRef::is_int(Self) -> Bool 617 | fn PyObjectRef::is_list(Self) -> Bool 618 | fn PyObjectRef::is_module(Self) -> Bool 619 | fn PyObjectRef::is_null(Self) -> Bool 620 | fn PyObjectRef::is_set(Self) -> Bool 621 | fn PyObjectRef::is_string(Self) -> Bool 622 | 623 | type PyThreadStateRef 624 | 625 | type PyTypeObjectRef 626 | 627 | // Type aliases 628 | 629 | // Traits 630 | 631 | -------------------------------------------------------------------------------- /cpython/dict.mbt: -------------------------------------------------------------------------------- 1 | // dict 2 | ///| 3 | pub extern "C" fn py_dict_new() -> PyObjectRef = "PyDict_New" 4 | 5 | ///| 6 | pub extern "C" fn py_dict_get_item( 7 | dict : PyObjectRef, 8 | key : PyObjectRef 9 | ) -> PyObjectRef = "PyDict_GetItem" 10 | 11 | ///| 12 | pub extern "C" fn py_dict_set_item( 13 | dict : PyObjectRef, 14 | key : PyObjectRef, 15 | item : PyObjectRef 16 | ) -> Int = "PyDict_SetItem" 17 | 18 | ///| 19 | pub extern "C" fn py_dict_del_item( 20 | dict : PyObjectRef, 21 | key : PyObjectRef 22 | ) -> Int = "PyDict_DelItem" 23 | 24 | ///| 25 | pub extern "C" fn py_dict_clear(dict : PyObjectRef) = "PyDict_Clear" 26 | 27 | // PyAPI_FUNC(int) py_dict_Next( 28 | // PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value); 29 | 30 | ///| 31 | pub extern "C" fn py_dict_keys(dict : PyObjectRef) -> PyObjectRef = "PyDict_Keys" 32 | 33 | ///| 34 | pub extern "C" fn py_dict_values(dict : PyObjectRef) -> PyObjectRef = "PyDict_Values" 35 | 36 | ///| 37 | pub extern "C" fn py_dict_items(dict : PyObjectRef) -> PyObjectRef = "PyDict_Items" 38 | 39 | ///| 40 | pub extern "C" fn py_dict_size(dict : PyObjectRef) -> UInt64 = "PyDict_Size" 41 | 42 | ///| 43 | pub extern "C" fn py_dict_copy(dict : PyObjectRef) -> PyObjectRef = "PyDict_Copy" 44 | 45 | ///| 46 | pub extern "C" fn __py_dict_contains( 47 | dict : PyObjectRef, 48 | key : PyObjectRef 49 | ) -> Int = "PyDict_Contains" 50 | 51 | ///| 52 | pub fn py_dict_contains(dict : PyObjectRef, key : PyObjectRef) -> Bool { 53 | __py_dict_contains(dict, key) != 0 54 | } 55 | 56 | ///| 57 | pub extern "C" fn py_dict_update( 58 | dict : PyObjectRef, 59 | other : PyObjectRef 60 | ) -> Int = "PyDict_Update" 61 | 62 | ///| 63 | pub extern "C" fn py_dict_merge( 64 | dict : PyObjectRef, 65 | other : PyObjectRef, 66 | _override : Int 67 | ) -> Int = "PyDict_Merge" 68 | 69 | ///| 70 | pub extern "C" fn py_dict_merge_from_seq2( 71 | dict : PyObjectRef, 72 | seq2 : PyObjectRef, 73 | override_ : Int 74 | ) -> Int = "PyDict_MergeFromSeq2" 75 | 76 | ///| 77 | extern "C" fn __py_dict_get_item_string( 78 | dict : PyObjectRef, 79 | key : CStr 80 | ) -> PyObjectRef = "PyDict_GetItemString" 81 | 82 | ///| 83 | pub fn py_dict_get_item_string(dict : PyObjectRef, key : String) -> PyObjectRef { 84 | let key = CStr::from(key) 85 | __py_dict_get_item_string(dict, key) 86 | } 87 | 88 | ///| 89 | extern "C" fn __py_dict_set_item_string( 90 | dict : PyObjectRef, 91 | key : CStr, 92 | item : PyObjectRef 93 | ) -> Int = "PyDict_SetItemString" 94 | 95 | ///| 96 | pub fn py_dict_set_item_string( 97 | dict : PyObjectRef, 98 | key : String, 99 | item : PyObjectRef 100 | ) -> Int { 101 | let key = CStr::from(key) 102 | __py_dict_set_item_string(dict, key, item) 103 | } 104 | 105 | ///| 106 | extern "C" fn __py_dict_del_item_string(dict : PyObjectRef, key : CStr) -> Int = "PyDict_DelItemString" 107 | 108 | ///| 109 | pub fn py_dict_del_item_string(dict : PyObjectRef, key : String) -> Int { 110 | let key = CStr::from(key) 111 | __py_dict_del_item_string(dict, key) 112 | } 113 | -------------------------------------------------------------------------------- /cpython/error.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub extern "C" fn py_err_occurred() -> PyObjectRef = "PyErr_Occurred" 3 | 4 | ///| 5 | pub extern "C" fn py_err_clear() = "PyErr_Clear" 6 | 7 | ///| 8 | pub extern "C" fn py_err_print() = "PyErr_Print" 9 | -------------------------------------------------------------------------------- /cpython/file.mbt: -------------------------------------------------------------------------------- 1 | // File 2 | ///| 3 | pub extern "C" fn py_file_from_fd( 4 | fd : Int, 5 | name : CStr, 6 | mode : CStr, 7 | closefd : Int, 8 | encoding : CStr, 9 | errors : CStr, 10 | newline : CStr, 11 | line_buffering : Int 12 | ) -> PyObjectRef = "PyFile_FromFd" 13 | 14 | ///| 15 | pub extern "C" fn py_file_get_line(a : PyObjectRef, b : Int) -> PyObjectRef = "PyFile_GetLine" 16 | 17 | ///| 18 | pub extern "C" fn py_file_write_object( 19 | a : PyObjectRef, 20 | b : PyObjectRef, 21 | c : Int 22 | ) -> Int = "PyFile_WriteObject" 23 | 24 | ///| 25 | pub extern "C" fn py_file_write_string(s : CStr, a : PyObjectRef) -> Int = "PyFile_WriteString" 26 | 27 | ///| 28 | pub extern "C" fn py_object_as_file_descriptor(a : PyObjectRef) -> Int = "PyObject_AsFileDescriptor" 29 | 30 | ///| 31 | pub extern "C" fn py_file_new_std_printer(a : Int) -> PyObjectRef = "PyFile_NewStdPrinter" 32 | 33 | ///| 34 | pub extern "C" fn py_file_open_code(utf8path : CStr) -> PyObjectRef = "PyFile_OpenCode" 35 | 36 | ///| 37 | pub extern "C" fn py_file_open_code_object(path : PyObjectRef) -> PyObjectRef = "PyFile_OpenCodeObject" 38 | -------------------------------------------------------------------------------- /cpython/func.mbt: -------------------------------------------------------------------------------- 1 | // Func Object 2 | 3 | ///| 4 | pub extern "C" fn py_function_new( 5 | a : PyObjectRef, 6 | b : PyObjectRef 7 | ) -> PyObjectRef = "PyFunction_New" 8 | 9 | ///| 10 | pub extern "C" fn py_function_new_with_qual_name( 11 | a : PyObjectRef, 12 | b : PyObjectRef, 13 | c : PyObjectRef 14 | ) -> PyObjectRef = "PyFunction_NewWithQualName" 15 | 16 | ///| 17 | pub extern "C" fn py_function_get_code(a : PyObjectRef) -> PyObjectRef = "PyFunction_GetCode" 18 | 19 | ///| 20 | pub extern "C" fn py_function_get_globals(a : PyObjectRef) -> PyObjectRef = "PyFunction_GetGlobals" 21 | 22 | ///| 23 | pub extern "C" fn py_function_get_module(a : PyObjectRef) -> PyObjectRef = "PyFunction_GetModule" 24 | 25 | ///| 26 | pub extern "C" fn py_function_get_defaults(a : PyObjectRef) -> PyObjectRef = "PyFunction_GetDefaults" 27 | 28 | ///| 29 | pub extern "C" fn py_function_set_defaults( 30 | a : PyObjectRef, 31 | b : PyObjectRef 32 | ) -> Int = "PyFunction_SetDefaults" 33 | 34 | ///| 35 | pub extern "C" fn py_function_get_kw_defaults(a : PyObjectRef) -> PyObjectRef = "PyFunction_GetKwDefaults" 36 | 37 | ///| 38 | pub extern "C" fn py_function_set_kw_defaults( 39 | a : PyObjectRef, 40 | b : PyObjectRef 41 | ) -> Int = "PyFunction_SetKwDefaults" 42 | 43 | ///| 44 | pub extern "C" fn py_function_get_closure(a : PyObjectRef) -> PyObjectRef = "PyFunction_GetClosure" 45 | 46 | ///| 47 | pub extern "C" fn py_function_set_closure( 48 | a : PyObjectRef, 49 | b : PyObjectRef 50 | ) -> Int = "PyFunction_SetClosure" 51 | 52 | ///| 53 | pub extern "C" fn py_function_get_annotations(a : PyObjectRef) -> PyObjectRef = "PyFunction_GetAnnotations" 54 | 55 | ///| 56 | pub extern "C" fn py_function_set_annotations( 57 | a : PyObjectRef, 58 | b : PyObjectRef 59 | ) -> Int = "PyFunction_SetAnnotations" 60 | 61 | ///| 62 | pub extern "C" fn py_class_method_new(a : PyObjectRef) -> PyObjectRef = "PyClassMethod_New" 63 | 64 | ///| 65 | pub extern "C" fn py_static_method_new(a : PyObjectRef) -> PyObjectRef = "PyStaticMethod_New" 66 | -------------------------------------------------------------------------------- /cpython/import.mbt: -------------------------------------------------------------------------------- 1 | // Import 2 | ///| 3 | pub extern "C" fn py_import_get_magic_number() -> Int = "PyImport_GetMagicNumber" 4 | 5 | ///| 6 | pub extern "C" fn py_import_get_magic_tag() -> CStr = "PyImport_GetMagicTag" 7 | 8 | ///| 9 | pub extern "C" fn py_import_exec_code_module( 10 | name : CStr, 11 | co : PyObjectRef 12 | ) -> PyObjectRef = "PyImport_ExecCodeModule" 13 | 14 | ///| 15 | pub extern "C" fn py_import_exec_code_module_ex( 16 | name : CStr, 17 | co : PyObjectRef, 18 | pathname : CStr 19 | ) -> PyObjectRef = "PyImport_ExecCodeModuleEx" 20 | 21 | ///| 22 | pub extern "C" fn py_import_exec_code_module_with_pathnames( 23 | name : CStr, 24 | co : PyObjectRef, 25 | pathname : CStr, 26 | cpathname : CStr 27 | ) -> PyObjectRef = "PyImport_ExecCodeModuleWithPathnames" 28 | 29 | ///| 30 | pub extern "C" fn py_import_exec_code_module_object( 31 | name : PyObjectRef, 32 | co : PyObjectRef, 33 | pathname : PyObjectRef, 34 | cpathname : PyObjectRef 35 | ) -> PyObjectRef = "PyImport_ExecCodeModuleObject" 36 | 37 | ///| 38 | pub extern "C" fn py_import_get_module_dict() -> PyObjectRef = "PyImport_GetModuleDict" 39 | 40 | ///| 41 | pub extern "C" fn py_import_get_module(name : PyObjectRef) -> PyObjectRef = "PyImport_GetModule" 42 | 43 | ///| 44 | pub extern "C" fn py_import_add_module_object( 45 | name : PyObjectRef 46 | ) -> PyObjectRef = "PyImport_AddModuleObject" 47 | 48 | ///| 49 | pub extern "C" fn py_import_add_module(name : CStr) -> PyObjectRef = "PyImport_AddModule" 50 | 51 | ///| 52 | extern "C" fn __py_import_import_module(name : Bytes) -> PyObjectRef = "PyImport_ImportModule" 53 | 54 | //extern "C" fn __py_import_import_module(name: Bytes) -> PyObjectRef = "py_import_import_module" 55 | ///| 56 | pub fn py_import_import_module(name : String) -> PyObjectRef { 57 | let cstr = ToCStr::to_cstr(name) 58 | __py_import_import_module(cstr) 59 | } 60 | 61 | ///| 62 | pub extern "C" fn py_import_import_module_no_block(name : CStr) -> PyObjectRef = "PyImport_ImportModuleNoBlock" 63 | 64 | ///| 65 | pub extern "C" fn py_import_import_module_level( 66 | name : CStr, 67 | globals : PyObjectRef, 68 | locals : PyObjectRef, 69 | fromlist : PyObjectRef, 70 | level : Int 71 | ) -> PyObjectRef = "PyImport_ImportModuleLevel" 72 | 73 | ///| 74 | pub extern "C" fn py_import_import_module_level_object( 75 | name : PyObjectRef, 76 | globals : PyObjectRef, 77 | locals : PyObjectRef, 78 | fromlist : PyObjectRef, 79 | level : Int 80 | ) -> PyObjectRef = "PyImport_ImportModuleLevelObject" 81 | 82 | ///| 83 | pub extern "C" fn py_import_get_importer(path : PyObjectRef) -> PyObjectRef = "PyImport_GetImporter" 84 | 85 | ///| 86 | pub extern "C" fn py_import_import(name : PyObjectRef) -> PyObjectRef = "PyImport_Import" 87 | 88 | ///| 89 | pub extern "C" fn py_import_reload_module(m : PyObjectRef) -> PyObjectRef = "PyImport_ReloadModule" 90 | 91 | ///| 92 | pub extern "C" fn py_import_cleanup() = "PyImport_Cleanup" 93 | 94 | ///| 95 | pub extern "C" fn py_import_import_frozen_module_object( 96 | name : PyObjectRef 97 | ) -> Int = "PyImport_ImportFrozenModuleObject" 98 | 99 | ///| 100 | pub extern "C" fn py_import_import_frozen_module(name : CStr) -> Int = "PyImport_ImportFrozenModule" 101 | -------------------------------------------------------------------------------- /cpython/iter.mbt: -------------------------------------------------------------------------------- 1 | // Iter 2 | ///| 3 | pub extern "C" fn py_seq_iter_new(a : PyObjectRef) -> PyObjectRef = "PySeqIter_New" 4 | 5 | ///| 6 | pub extern "C" fn py_call_iter_new( 7 | a : PyObjectRef, 8 | b : PyObjectRef 9 | ) -> PyObjectRef = "PyCallIter_New" 10 | -------------------------------------------------------------------------------- /cpython/lifecycle.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub extern "C" fn py_init() = "Py_Initialize" 3 | 4 | ///| 5 | pub extern "C" fn py_finalize() = "Py_Finalize" 6 | 7 | ///| 8 | extern "C" fn __py_is_initialized() -> Int = "Py_IsInitialized" 9 | 10 | ///| 11 | pub fn py_is_initialized() -> Bool { 12 | __py_is_initialized() != 0 13 | } 14 | -------------------------------------------------------------------------------- /cpython/list.mbt: -------------------------------------------------------------------------------- 1 | // List 2 | ///| 3 | pub extern "C" fn py_list_new(sz : Int64) -> PyObjectRef = "PyList_New" 4 | 5 | ///| 6 | pub extern "C" fn py_list_size(list : PyObjectRef) -> Int64 = "PyList_Size" 7 | 8 | ///| 9 | pub extern "C" fn py_list_get_item( 10 | list : PyObjectRef, 11 | idx : Int64 12 | ) -> PyObjectRef = "PyList_GetItem" 13 | 14 | ///| 15 | pub extern "C" fn py_list_set_item( 16 | list : PyObjectRef, 17 | idx : Int64, 18 | item : PyObjectRef 19 | ) -> Int = "PyList_SetItem" 20 | 21 | ///| 22 | pub extern "C" fn py_list_insert( 23 | list : PyObjectRef, 24 | idx : Int64, 25 | item : PyObjectRef 26 | ) -> Int = "PyList_Insert" 27 | 28 | ///| 29 | pub extern "C" fn py_list_append(list : PyObjectRef, item : PyObjectRef) -> Int = "PyList_Append" 30 | 31 | ///| 32 | pub extern "C" fn py_list_get_slice( 33 | list : PyObjectRef, 34 | start : Int64, 35 | end : Int64 36 | ) -> PyObjectRef = "PyList_GetSlice" 37 | 38 | ///| 39 | pub extern "C" fn py_list_set_slice( 40 | list : PyObjectRef, 41 | start : Int64, 42 | end : Int64, 43 | new_list : PyObjectRef 44 | ) -> Int = "PyList_SetSlice" 45 | 46 | ///| 47 | pub extern "C" fn py_list_sort(list : PyObjectRef) -> Int = "PyList_Sort" 48 | 49 | ///| 50 | pub extern "C" fn py_list_reverse(list : PyObjectRef) -> Int = "PyList_Reverse" 51 | 52 | ///| 53 | pub extern "C" fn py_list_as_tuple(list : PyObjectRef) -> PyObjectRef = "PyList_AsTuple" 54 | -------------------------------------------------------------------------------- /cpython/module.mbt: -------------------------------------------------------------------------------- 1 | // Module 2 | 3 | ///| 4 | pub extern "C" fn py_module_new_object(name : PyObjectRef) -> PyObjectRef = "PyModule_NewObject" 5 | 6 | ///| 7 | pub extern "C" fn py_module_new(name : CStr) -> PyObjectRef = "PyModule_New" 8 | 9 | ///| 10 | pub extern "C" fn py_module_get_dict(a : PyObjectRef) -> PyObjectRef = "PyModule_GetDict" 11 | 12 | ///| 13 | pub extern "C" fn py_module_get_name_object(a : PyObjectRef) -> PyObjectRef = "PyModule_GetNameObject" 14 | 15 | ///| 16 | pub extern "C" fn py_module_get_name(a : PyObjectRef) -> CStr = "PyModule_GetName" 17 | 18 | ///| 19 | pub extern "C" fn py_module_get_filename_object(a : PyObjectRef) -> PyObjectRef = "PyModule_GetFilenameObject" 20 | -------------------------------------------------------------------------------- /cpython/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": false, 3 | "supported-targets": ["native"], 4 | "native-stub": ["wrap.c"], 5 | "link": { 6 | "native": { 7 | "stub-cc": "${build.CC}", 8 | "stub-cc-flags": "${build.STUB_CC_FLAGS}" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /cpython/number.mbt: -------------------------------------------------------------------------------- 1 | // PyObjectRef PyBool_FromLong(long); 2 | 3 | ///| 4 | pub extern "C" fn py_long_from_long(value : Int64) -> PyObjectRef = "PyLong_FromLong" 5 | 6 | // As Long 7 | ///| 8 | pub extern "C" fn py_long_as_long(obj : PyObjectRef) -> Int64 = "PyLong_AsLong" 9 | 10 | // As Double 11 | ///| 12 | pub extern "C" fn py_long_as_double(obj : PyObjectRef) -> Double = "PyLong_AsDouble" 13 | 14 | // Float 15 | 16 | ///| 17 | pub extern "C" fn py_float_from_double(value : Double) -> PyObjectRef = "PyFloat_FromDouble" 18 | 19 | ///| 20 | pub extern "C" fn py_float_as_double(obj : PyObjectRef) -> Double = "PyFloat_AsDouble" 21 | 22 | ///| 23 | pub extern "C" fn py_float_get_max() -> Double = "PyFloat_GetMax" 24 | 25 | ///| 26 | pub extern "C" fn py_float_get_min() -> Double = "PyFloat_GetMin" 27 | 28 | ///| 29 | pub extern "C" fn py_float_get_info() -> PyObjectRef = "PyFloat_GetInfo" 30 | 31 | ///| 32 | pub extern "C" fn py_float_from_string(obj : PyObjectRef) -> PyObjectRef = "PyFloat_FromString" 33 | 34 | // Complex 35 | ///| 36 | pub extern "C" fn py_complex_from_doubles( 37 | real : Double, 38 | imag : Double 39 | ) -> PyObjectRef = "PyComplex_FromDoubles" 40 | 41 | ///| 42 | pub extern "C" fn py_complex_real_as_double(op : PyObjectRef) -> Double = "PyComplex_RealAsDouble" 43 | 44 | ///| 45 | pub extern "C" fn py_complex_imag_as_double(op : PyObjectRef) -> Double = "PyComplex_ImagAsDouble" 46 | 47 | // Bool 48 | ///| 49 | pub extern "C" fn py_bool_from_long(value : Int64) -> PyObjectRef = "PyBool_FromLong" 50 | -------------------------------------------------------------------------------- /cpython/object.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub extern "C" fn py_object_repr(a : PyObjectRef) -> PyObjectRef = "PyObject_Repr" 3 | 4 | ///| 5 | pub extern "C" fn py_object_str(a : PyObjectRef) -> PyObjectRef = "PyObject_Str" 6 | 7 | ///| 8 | pub extern "C" fn py_object_ascii(a : PyObjectRef) -> PyObjectRef = "PyObject_ASCII" 9 | 10 | ///| 11 | pub extern "C" fn py_object_bytes(a : PyObjectRef) -> PyObjectRef = "PyObject_Bytes" 12 | 13 | ///| 14 | pub extern "C" fn py_object_rich_compare( 15 | a : PyObjectRef, 16 | b : PyObjectRef, 17 | c : Int 18 | ) -> PyObjectRef = "PyObject_RichCompare" 19 | 20 | ///| 21 | pub extern "C" fn py_object_rich_compare_bool( 22 | a : PyObjectRef, 23 | b : PyObjectRef, 24 | c : Int 25 | ) -> Int = "PyObject_RichCompareBool" 26 | 27 | ///| 28 | extern "C" fn __py_object_get_attr_string( 29 | a : PyObjectRef, 30 | b : Bytes 31 | ) -> PyObjectRef = "PyObject_GetAttrString" 32 | 33 | ///| 34 | pub fn py_object_get_attr_string(a : PyObjectRef, b : String) -> PyObjectRef { 35 | let b = ToCStr::to_cstr(b) 36 | __py_object_get_attr_string(a, b) 37 | } 38 | 39 | ///| 40 | extern "C" fn __py_object_set_attr_string( 41 | a : PyObjectRef, 42 | b : Bytes, 43 | c : PyObjectRef 44 | ) -> Int = "PyObject_SetAttrString" 45 | 46 | ///| 47 | pub fn py_object_set_attr_string( 48 | a : PyObjectRef, 49 | b : String, 50 | c : PyObjectRef 51 | ) -> Int { 52 | let b = ToCStr::to_cstr(b) 53 | __py_object_set_attr_string(a, b, c) 54 | } 55 | 56 | ///| 57 | extern "C" fn __py_object_has_attr_string(a : PyObjectRef, b : Bytes) -> Int = "PyObject_HasAttrString" 58 | 59 | ///| 60 | pub fn py_object_has_attr_string(a : PyObjectRef, b : String) -> Int { 61 | let b = ToCStr::to_cstr(b) 62 | __py_object_has_attr_string(a, b) 63 | } 64 | 65 | ///| 66 | pub extern "C" fn py_object_get_attr( 67 | a : PyObjectRef, 68 | b : PyObjectRef 69 | ) -> PyObjectRef = "PyObject_GetAttr" 70 | 71 | ///| 72 | pub extern "C" fn py_object_set_attr( 73 | a : PyObjectRef, 74 | b : PyObjectRef, 75 | c : PyObjectRef 76 | ) -> Int = "PyObject_SetAttr" 77 | 78 | ///| 79 | pub extern "C" fn py_object_has_attr(a : PyObjectRef, b : PyObjectRef) -> Int = "PyObject_HasAttr" 80 | 81 | ///| 82 | pub extern "C" fn py_object_self_iter(a : PyObjectRef) -> PyObjectRef = "PyObject_SelfIter" 83 | 84 | ///| 85 | pub extern "C" fn py_object_generic_get_attr( 86 | a : PyObjectRef, 87 | b : PyObjectRef 88 | ) -> PyObjectRef = "PyObject_GenericGetAttr" 89 | 90 | ///| 91 | pub extern "C" fn py_object_generic_set_attr( 92 | a : PyObjectRef, 93 | b : PyObjectRef, 94 | c : PyObjectRef 95 | ) -> Int = "PyObject_GenericSetAttr" 96 | 97 | // pub extern "C" fn py_object_hash(a: PyObjectRef) -> Py_hash_t = "PyObject_Hash" 98 | // pub extern "C" fn py_object_hash_not_implemented(a: PyObjectRef) -> Py_hash_t = "PyObject_HashNotImplemented" 99 | ///| 100 | extern "C" fn __py_object_is_true(a : PyObjectRef) -> Int = "PyObject_IsTrue" 101 | 102 | ///| 103 | pub fn py_object_is_true(a : PyObjectRef) -> Bool { 104 | __py_object_is_true(a) != 0 105 | } 106 | 107 | ///| 108 | pub extern "C" fn py_object_not(a : PyObjectRef) -> Int = "PyObject_Not" 109 | 110 | ///| 111 | pub extern "C" fn py_object_clear_weak_refs(a : PyObjectRef) = "PyObject_ClearWeakRefs" 112 | 113 | ///| 114 | pub extern "C" fn py_object_dir(a : PyObjectRef) -> PyObjectRef = "PyObject_Dir" 115 | 116 | ///| 117 | pub extern "C" fn py_repr_enter(a : PyObjectRef) -> Int = "Py_ReprEnter" 118 | 119 | ///| 120 | pub extern "C" fn py_repr_leave(a : PyObjectRef) = "Py_ReprLeave" 121 | 122 | ///| 123 | pub extern "C" fn py_type(obj : PyObjectRef) -> PyTypeObjectRef = "py_type" 124 | 125 | ///| 126 | extern "C" fn __py_type_name(t : PyTypeObjectRef) -> CStr = "_PyType_Name" 127 | 128 | ///| 129 | pub fn py_type_name(t : PyTypeObjectRef) -> String { 130 | let cstr = __py_type_name(t) 131 | cstr.to_string() 132 | } 133 | 134 | ///| 135 | extern "C" fn __py_tuple_check(obj : PyObjectRef) -> Int = "py_tuple_check" 136 | 137 | ///| 138 | pub fn py_tuple_check(obj : PyObjectRef) -> Bool { 139 | __py_tuple_check(obj) != 0 140 | } 141 | 142 | ///| 143 | extern "C" fn __py_list_check(obj : PyObjectRef) -> Int = "py_list_check" 144 | 145 | ///| 146 | pub fn py_list_check(obj : PyObjectRef) -> Bool { 147 | __py_list_check(obj) != 0 148 | } 149 | 150 | ///| 151 | pub fn PyObjectRef::is_list(self : PyObjectRef) -> Bool { 152 | __py_list_check(self) != 0 153 | } 154 | 155 | ///| 156 | extern "C" fn __py_dict_check(obj : PyObjectRef) -> Int = "py_dict_check" 157 | 158 | ///| 159 | pub fn py_dict_check(obj : PyObjectRef) -> Bool { 160 | __py_dict_check(obj) != 0 161 | } 162 | 163 | ///| 164 | pub fn PyObjectRef::is_dict(self : PyObjectRef) -> Bool { 165 | __py_dict_check(self) != 0 166 | } 167 | 168 | ///| 169 | extern "C" fn __py_set_check(obj : PyObjectRef) -> Int = "py_set_check" 170 | 171 | ///| 172 | pub fn py_set_check(obj : PyObjectRef) -> Bool { 173 | __py_set_check(obj) != 0 174 | } 175 | 176 | ///| 177 | pub fn PyObjectRef::is_set(self : PyObjectRef) -> Bool { 178 | __py_set_check(self) != 0 179 | } 180 | 181 | ///| 182 | extern "C" fn __py_int_check(obj : PyObjectRef) -> Int = "py_int_check" 183 | 184 | ///| 185 | pub fn py_int_check(obj : PyObjectRef) -> Bool { 186 | __py_int_check(obj) != 0 187 | } 188 | 189 | ///| 190 | pub fn PyObjectRef::is_int(self : PyObjectRef) -> Bool { 191 | __py_int_check(self) != 0 192 | } 193 | 194 | ///| 195 | extern "C" fn __py_float_check(obj : PyObjectRef) -> Int = "py_float_check" 196 | 197 | ///| 198 | pub fn py_float_check(obj : PyObjectRef) -> Bool { 199 | __py_float_check(obj) != 0 200 | } 201 | 202 | ///| 203 | pub fn PyObjectRef::is_float(self : PyObjectRef) -> Bool { 204 | __py_float_check(self) != 0 205 | } 206 | 207 | ///| 208 | extern "C" fn __py_string_check(obj : PyObjectRef) -> Int = "py_string_check" 209 | 210 | ///| 211 | pub fn py_string_check(obj : PyObjectRef) -> Bool { 212 | __py_string_check(obj) != 0 213 | } 214 | 215 | ///| 216 | pub fn PyObjectRef::is_string(self : PyObjectRef) -> Bool { 217 | __py_string_check(self) != 0 218 | } 219 | 220 | ///| 221 | extern "C" fn __py_bool_check(obj : PyObjectRef) -> Int = "py_bool_check" 222 | 223 | ///| 224 | pub fn py_bool_check(obj : PyObjectRef) -> Bool { 225 | __py_bool_check(obj) != 0 226 | } 227 | 228 | ///| 229 | pub fn PyObjectRef::is_bool(self : PyObjectRef) -> Bool { 230 | __py_bool_check(self) != 0 231 | } 232 | 233 | ///| 234 | extern "C" fn __py_module_check(obj : PyObjectRef) -> Int = "py_module_check" 235 | 236 | ///| 237 | pub fn py_module_check(obj : PyObjectRef) -> Bool { 238 | __py_module_check(obj) != 0 239 | } 240 | 241 | ///| 242 | pub fn PyObjectRef::is_module(self : PyObjectRef) -> Bool { 243 | __py_module_check(self) != 0 244 | } 245 | 246 | ///| 247 | extern "C" fn __py_function_check(f : PyObjectRef) -> Int = "py_function_check" 248 | 249 | ///| 250 | pub fn py_function_check(f : PyObjectRef) -> Bool { 251 | __py_function_check(f) != 0 252 | } 253 | 254 | ///| 255 | pub fn PyObjectRef::is_function(self : PyObjectRef) -> Bool { 256 | __py_function_check(self) != 0 257 | } 258 | 259 | ///| 260 | pub extern "C" fn __py_callable_check(a : PyObjectRef) -> Int = "PyCallable_Check" 261 | 262 | ///| 263 | pub fn py_callable_check(a : PyObjectRef) -> Bool { 264 | __py_callable_check(a) != 0 265 | } 266 | 267 | ///| 268 | pub fn PyObjectRef::is_callable(self : PyObjectRef) -> Bool { 269 | __py_callable_check(self) != 0 270 | } 271 | 272 | ///| 273 | extern "C" fn __py_none_check(obj : PyObjectRef) -> Int = "py_none_check" 274 | 275 | ///| 276 | pub fn py_none_check(obj : PyObjectRef) -> Bool { 277 | __py_none_check(obj) != 0 278 | } 279 | -------------------------------------------------------------------------------- /cpython/odict.mbt: -------------------------------------------------------------------------------- 1 | // ODict 2 | ///| 3 | pub extern "C" fn py_odict_new() -> PyObjectRef = "PyODict_New" 4 | 5 | ///| 6 | pub extern "C" fn py_odict_set_item( 7 | od : PyObjectRef, 8 | key : PyObjectRef, 9 | item : PyObjectRef 10 | ) -> Int = "PyODict_SetItem" 11 | 12 | ///| 13 | pub extern "C" fn py_odict_del_item(od : PyObjectRef, key : PyObjectRef) -> Int = "PyODict_DelItem" 14 | -------------------------------------------------------------------------------- /cpython/set.mbt: -------------------------------------------------------------------------------- 1 | // Set 2 | ///| 3 | pub extern "C" fn py_set_new(a : PyObjectRef) -> PyObjectRef = "PySet_New" 4 | 5 | ///| 6 | pub extern "C" fn py_frozen_set_new(a : PyObjectRef) -> PyObjectRef = "PyFrozenSet_New" 7 | 8 | ///| 9 | pub extern "C" fn py_set_add(set : PyObjectRef, key : PyObjectRef) -> Int = "PySet_Add" 10 | 11 | ///| 12 | pub extern "C" fn py_set_clear(set : PyObjectRef) -> Int = "PySet_Clear" 13 | 14 | ///| 15 | pub extern "C" fn py_set_contains( 16 | anyset : PyObjectRef, 17 | key : PyObjectRef 18 | ) -> Int = "PySet_Contains" 19 | 20 | ///| 21 | pub extern "C" fn py_set_discard(set : PyObjectRef, key : PyObjectRef) -> Int = "PySet_Discard" 22 | 23 | ///| 24 | pub extern "C" fn py_set_pop(set : PyObjectRef) -> PyObjectRef = "PySet_Pop" 25 | 26 | ///| 27 | pub extern "C" fn py_set_size(anyset : PyObjectRef) -> Int64 = "PySet_Size" 28 | -------------------------------------------------------------------------------- /cpython/tuple.mbt: -------------------------------------------------------------------------------- 1 | // Tuple 2 | ///| 3 | pub extern "C" fn pytuple_new(sz : UInt64) -> PyObjectRef = "PyTuple_New" 4 | 5 | ///| 6 | pub extern "C" fn pytuple_size(tuple : PyObjectRef) -> UInt64 = "PyTuple_Size" 7 | 8 | ///| 9 | pub extern "C" fn pytuple_get_item( 10 | tuple : PyObjectRef, 11 | idx : UInt64 12 | ) -> PyObjectRef = "PyTuple_GetItem" 13 | 14 | ///| 15 | pub extern "C" fn pytuple_set_item( 16 | tuple : PyObjectRef, 17 | idx : UInt64, 18 | item : PyObjectRef 19 | ) -> Int = "PyTuple_SetItem" 20 | 21 | ///| 22 | pub extern "C" fn pytuple_get_slice( 23 | tuple : PyObjectRef, 24 | start : UInt64, 25 | end : UInt64 26 | ) -> PyObjectRef = "PyTuple_GetSlice" 27 | 28 | // PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...); 29 | -------------------------------------------------------------------------------- /cpython/unicode.mbt: -------------------------------------------------------------------------------- 1 | // Unicode 2 | ///| 3 | pub extern "C" fn py_unicode_from_unicode( 4 | u : CWStr, 5 | size : UInt64 6 | ) -> PyObjectRef = "PyUnicode_FromStringAndSize" 7 | 8 | ///| 9 | pub extern "C" fn py_unicode_from_string_and_size( 10 | u : CStr, 11 | size : UInt64 12 | ) -> PyObjectRef = "PyUnicode_FromStringAndSize" 13 | 14 | ///| 15 | extern "C" fn __py_unicode_from_string(u : CStr) -> PyObjectRef = "PyUnicode_FromString" 16 | 17 | ///| 18 | pub fn py_unicode_from_string(s : String) -> PyObjectRef { 19 | let u = CStr::from(s) 20 | __py_unicode_from_string(u) 21 | } 22 | 23 | // PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode); 24 | ///| 25 | extern "C" fn __py_unicode_as_utf8(u : PyObjectRef) -> CStr = "PyUnicode_AsUTF8" 26 | 27 | ///| 28 | pub extern "C" fn py_unicode_as_utf16_string(u : PyObjectRef) -> PyObjectRef = "PyUnicode_AsUTF16String" 29 | 30 | ///| 31 | pub extern "C" fn py_unicode_as_moonbit_string(u : PyObjectRef) -> String = "py_unicode_as_moonbit_string" 32 | 33 | ///| 34 | pub fn py_unicode_as_utf8(u : PyObjectRef) -> String { 35 | let cstr = __py_unicode_as_utf8(u) 36 | cstr.to_string() 37 | } 38 | 39 | ///| 40 | extern "C" fn __py_unicode_from_kind_and_data( 41 | kind : Int, 42 | buffer : String, 43 | size : UInt64 44 | ) -> PyObjectRef = "PyUnicode_FromKindAndData" 45 | 46 | ///| 47 | pub fn py_unicode_from_moonbit_string(s : String) -> PyObjectRef { 48 | let kind = 2 // 2 = PyUnicode_2BYTE_KIND 49 | let size = s.length().to_uint64() 50 | __py_unicode_from_kind_and_data(kind, s, size) 51 | } 52 | -------------------------------------------------------------------------------- /cpython/utils.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | priv trait ToCStr { 3 | to_cstr(Self) -> Bytes 4 | } 5 | 6 | ///| 7 | impl ToCStr for String with to_cstr(self) { 8 | let s = self.to_bytes().to_array().filter(fn(c) { c != 0 }) 9 | s.push(0) 10 | s |> @bytes.from_array 11 | } 12 | -------------------------------------------------------------------------------- /cpython/wrap.c: -------------------------------------------------------------------------------- 1 | #include "moonbit.h" 2 | #include 3 | #include 4 | #include 5 | 6 | void *moonbit_str_to_c_str(moonbit_string_t ms) { 7 | int32_t len = Moonbit_array_length(ms); 8 | char *ptr = (char *)malloc(len + 1); 9 | for (int i = 0; i < len; i++) { 10 | if (ms[i] < 0x80) { 11 | ptr[i] = ms[i]; 12 | } else { 13 | ptr[i] = '?'; 14 | } 15 | } 16 | ptr[len] = '\0'; 17 | return ptr; 18 | } 19 | 20 | moonbit_string_t c_str_to_moonbit_str(void *ptr) { 21 | char *cptr = (char *)ptr; 22 | int32_t len = strlen(cptr); 23 | moonbit_string_t ms = moonbit_make_string(len, 0); 24 | for (int i = 0; i < len; i++) { 25 | ms[i] = (uint16_t)cptr[i]; 26 | } 27 | // free(ptr); 28 | return ms; 29 | } 30 | 31 | moonbit_string_t c_str_to_moonbit_str_with_length(void *ptr, unsigned len) { 32 | char *cptr = (char *)ptr; 33 | moonbit_string_t ms = moonbit_make_string(len, 0); 34 | for (int i = 0; i < len; i++) { 35 | ms[i] = (uint16_t)cptr[i]; 36 | } 37 | // free(ptr); 38 | return ms; 39 | } 40 | 41 | void print_pyobject(PyObject *obj) { PyObject_Print(obj, stdout, 0); } 42 | 43 | void py_incref(PyObject *obj) { Py_INCREF(obj); } 44 | 45 | void py_decref(PyObject *obj) { Py_DECREF(obj); } 46 | 47 | int Moonbit_PyObjectRef_is_null(PyObject *obj) { return obj == NULL; } 48 | 49 | PyTypeObject *py_type(PyObject *obj) { return obj->ob_type; } 50 | 51 | int py_tuple_check(PyObject *obj) { return PyTuple_Check(obj); } 52 | 53 | int py_list_check(PyObject *obj) { return PyList_Check(obj); } 54 | 55 | int py_dict_check(PyObject *obj) { return PyDict_Check(obj); } 56 | 57 | int py_set_check(PyObject *obj) { return PySet_Check(obj); } 58 | 59 | int py_string_check(PyObject *obj) { return PyUnicode_Check(obj); } 60 | 61 | int py_int_check(PyObject *obj) { return PyLong_Check(obj); } 62 | 63 | int py_float_check(PyObject *obj) { return PyFloat_Check(obj); } 64 | 65 | int py_bool_check(PyObject *obj) { return PyBool_Check(obj); } 66 | 67 | int py_none_check(PyObject *obj) { return Py_None == obj; } 68 | 69 | int py_callable_check(PyObject *obj) { return PyCallable_Check(obj); } 70 | 71 | int py_iter_check(PyObject *obj) { return PyIter_Check(obj); } 72 | 73 | int py_module_check(PyObject *obj) { return PyModule_Check(obj); } 74 | 75 | int py_type_check(PyObject *obj) { return PyType_Check(obj); } 76 | 77 | int py_function_check(PyObject *obj) { return PyFunction_Check(obj); } 78 | 79 | int py_method_check(PyObject *obj) { return PyMethod_Check(obj); } 80 | 81 | int py_is_true(PyObject *obj) { return 0 != Py_IsTrue(obj); }; 82 | 83 | int py_is_false(PyObject *obj) { return 0 == Py_IsTrue(obj); } 84 | 85 | PyObject* py_import_import_module(const char* name) { 86 | PyObject *module = PyImport_ImportModule(name); 87 | return module; 88 | } 89 | 90 | moonbit_string_t py_unicode_as_moonbit_string(PyObject* obj) { 91 | void* data = PyUnicode_DATA(obj); 92 | int64_t len = PyUnicode_GET_LENGTH(obj); 93 | moonbit_string_t ms = moonbit_make_string(len, 0); 94 | if (PyUnicode_KIND(obj) == PyUnicode_2BYTE_KIND) { 95 | memcpy(ms, data, len * 2); 96 | } else if (PyUnicode_KIND(obj) == PyUnicode_1BYTE_KIND) { 97 | for (int i = 0; i < len; i++) { 98 | ms[i] = (uint16_t)(((Py_UCS1*)data)[i]); 99 | } 100 | } else { // PyUnicode_4BYTE_KIND 101 | for (int i = 0; i < len; i++) { 102 | ms[i] = (uint16_t)(((Py_UCS4*)data)[i]); 103 | } 104 | } 105 | return ms; 106 | } 107 | -------------------------------------------------------------------------------- /dict.mbt: -------------------------------------------------------------------------------- 1 | // ======================================== 2 | // Dict 3 | // ======================================== 4 | ///| 5 | pub struct PyDict { 6 | priv obj : PyObject 7 | } 8 | 9 | ///| Create a python dict object. 10 | /// If the python object is not a dict, it will raise a TypeMisMatchError. 11 | pub fn PyDict::create(obj : PyObject) -> PyDict!PyRuntimeError { 12 | guard obj.is_dict() else { raise TypeMisMatchError } 13 | PyDict::{ obj, } 14 | } 15 | 16 | ///| 17 | fn PyDict::create_unchecked(obj : PyObject) -> PyDict { 18 | PyDict::{ obj, } 19 | } 20 | 21 | ///| Create a python dict object from a python object reference. 22 | /// If the python object is not a dict, it will raise a TypeMisMatchError. 23 | pub fn PyDict::create_by_ref( 24 | obj : @cpython.PyObjectRef 25 | ) -> PyDict!PyRuntimeError { 26 | guard @cpython.py_dict_check(obj) else { raise TypeMisMatchError } 27 | PyDict::{ obj: PyObject::create(obj) } 28 | } 29 | 30 | ///| Creates a new python dict object. 31 | /// 32 | /// ## Example 33 | /// 34 | /// ```moonbit 35 | /// test "PyDict::new" { 36 | /// let dict = PyDict::new() 37 | /// dict 38 | /// ..set("one", PyInteger::from(1)) 39 | /// ..set("two", PyFloat::from(2.0)) 40 | /// ..set("three", PyBool::from(true)); 41 | /// 42 | /// inspect!(dict, content="{\'one\': 1, \'two\': 2.0, \'three\': True}") 43 | /// } 44 | /// ``` 45 | /// 46 | /// The above code is equivalent to: 47 | /// 48 | /// ```python 49 | /// d = { 'one': 1, 'two': 2.0, 'three': True } 50 | /// 51 | /// print(d) # Output: {'one': 1, 'two': 2.0, 'three': True} 52 | /// ``` 53 | pub fn PyDict::new() -> PyDict { 54 | PyDict::{ obj: PyObject::create(@cpython.py_dict_new()) } 55 | } 56 | 57 | ///| Return the length of the dict. 58 | /// 59 | /// ## Example 60 | /// 61 | /// ```moonbit 62 | /// test "PyDict::len" { 63 | /// let dict = PyDict::new() 64 | /// dict 65 | /// ..set("one", PyInteger::from(1)) 66 | /// ..set("two", PyFloat::from(2.0)) 67 | /// ..set("three", PyString::from("three")); 68 | /// 69 | /// assert_eq!(dict.len(), 3); 70 | /// } 71 | /// ``` 72 | pub fn PyDict::len(self : PyDict) -> Int { 73 | @cpython.py_dict_size(self.obj_ref()).to_int() 74 | } 75 | 76 | ///| Return the elements of the dict by its key. 77 | /// 78 | /// ## Example 79 | /// 80 | /// ```moonbit 81 | /// 82 | /// ```moonbit 83 | /// test "PyDict::get" { 84 | /// let dict = PyDict::new() 85 | /// dict 86 | /// ..set("one", PyInteger::from(1)) 87 | /// ..set("two", PyFloat::from(2.0)) 88 | /// ..set("three", PyBool::from(true)); 89 | /// 90 | /// inspect!(dict.get("one").unwrap(), content="PyInteger(1)") 91 | /// inspect!(dict.get("two"), content="Some(PyFloat(2.0))") 92 | /// inspect!(dict.get("four"), content="None") 93 | /// } 94 | /// ``` 95 | pub fn PyDict::get(self : PyDict, key : String) -> PyObjectEnum? { 96 | let dict = self.obj_ref() 97 | let obj_ref = @cpython.py_dict_get_item_string(dict, key) 98 | @option.when(not(obj_ref.is_null()), fn() { 99 | PyObjectEnum::create_by_ref(obj_ref) 100 | }) 101 | } 102 | 103 | ///| Return the elements of the dict by its key, when the key is not string. 104 | pub fn PyDict::getByObj(self : PyDict, key : PyObject) -> PyObjectEnum? { 105 | let dict = self.obj_ref() 106 | let obj_ref = @cpython.py_dict_get_item(dict, key.obj_ref()) 107 | @option.when(not(obj_ref.is_null()), fn() { 108 | PyObjectEnum::create_by_ref(obj_ref) 109 | }) 110 | } 111 | 112 | ///| Return the elements of the dict by its key. 113 | /// 114 | /// **Note**: Will panic if the key is not found. 115 | /// 116 | /// ## Example 117 | /// 118 | /// ```moonbit 119 | /// test "PyDict::op_get" { 120 | /// let dict = PyDict::new() 121 | /// dict 122 | /// ..set("one", PyInteger::from(1)) 123 | /// ..set("two", PyFloat::from(2.0)) 124 | /// ..set("three", PyBool::from(true)); 125 | /// 126 | /// inspect!(dict["one"], content="PyInteger(1)") 127 | /// inspect!(dict["two"], content="PyFloat(2.0)") 128 | /// inspect!(dict["three"], content="PyBool(True)") 129 | /// } 130 | /// ``` 131 | pub fn PyDict::op_get(self : PyDict, key : String) -> PyObjectEnum { 132 | self.get(key).unwrap() 133 | } 134 | 135 | ///| Set the elements of the dict by its key (String). 136 | /// 137 | /// ## Example 138 | /// 139 | /// ```moonbit 140 | /// test "PyDict::set" { 141 | /// let dict = PyDict::new() 142 | /// dict 143 | /// ..set("one", PyInteger::from(1)) 144 | /// ..set("two", PyFloat::from(2.0)) 145 | /// ..set("three", PyBool::from(true)); 146 | /// 147 | /// inspect!(dict, content="{\'one\': 1, \'two\': 2.0, \'three\': True}") 148 | /// } 149 | /// ``` 150 | /// 151 | /// The above code is equivalent to: 152 | /// 153 | /// ```python 154 | /// d = dict() 155 | /// d['one'] = 1 156 | /// d['two'] = 2.0 157 | /// d['three'] = True 158 | /// ``` 159 | pub fn[V : IsPyObject] PyDict::set( 160 | self : PyDict, 161 | key : String, 162 | val : V 163 | ) -> Unit { 164 | let dict = self.obj_ref() 165 | let val = val.obj_ref() 166 | let _ = @cpython.py_dict_set_item_string(dict, key, val) 167 | 168 | } 169 | 170 | ///| Set the elements of the dict by its key. (Object) 171 | /// 172 | /// ## Example 173 | /// 174 | /// ```moonbit 175 | /// test "PyDict::setByObj" { 176 | /// let dict = PyDict::new() 177 | /// dict 178 | /// ..setByObj!(PyInteger::from(1), PyInteger::from(1)) 179 | /// ..setByObj!(PyInteger::from(2), PyInteger::from(4)) 180 | /// ..setByObj!(PyInteger::from(3), PyInteger::from(9)) 181 | /// 182 | /// inspect!(dict, content="{1: 1, 2: 4, 3: 9}") 183 | /// } 184 | /// ``` 185 | /// 186 | /// The above code is equivalent to: 187 | /// 188 | /// ```python 189 | /// d = dict() 190 | /// d[1] = 1 191 | /// d[2] = 4 192 | /// d[3] = 9 193 | /// 194 | /// print(d) # Output: {1: 1, 2: 4, 3: 9} 195 | /// ``` 196 | pub fn[K : IsPyObject, V : IsPyObject] PyDict::setByObj( 197 | self : PyDict, 198 | key : K, 199 | val : V 200 | ) -> Unit!PyRuntimeError { 201 | let dict = self.obj_ref() 202 | @cpython.py_err_clear() 203 | let _ = @cpython.py_dict_set_item(dict, key.obj_ref(), val.obj_ref()) 204 | let e = @cpython.py_err_occurred() 205 | if not(e.is_null()) { 206 | @cpython.py_err_clear() 207 | raise KeyIsUnHashableError 208 | } 209 | } 210 | 211 | ///| Set the elements of the dict by its key (String). 212 | /// 213 | /// ## Example 214 | /// 215 | /// ```moonbit 216 | /// test "PyDict::set" { 217 | /// let dict = PyDict::new() 218 | /// 219 | /// dict["one"] = PyInteger::from(1); 220 | /// dict["two"] = PyFloat::from(2.0); 221 | /// dict["three"] = PyBool::from(true); 222 | /// 223 | /// inspect!(dict, content="{\'one\': 1, \'two\': 2.0, \'three\': True}") 224 | /// } 225 | /// ``` 226 | /// 227 | /// The above code is equivalent to: 228 | /// 229 | /// ```python 230 | /// d = dict() 231 | /// d['one'] = 1 232 | /// d['two'] = 2.0 233 | /// d['three'] = True 234 | /// ``` 235 | pub fn[V : IsPyObject] PyDict::op_set( 236 | self : PyDict, 237 | key : String, 238 | val : V 239 | ) -> Unit { 240 | self.set(key, val) 241 | } 242 | 243 | ///| Check if the dict contains the key. Note that the key is a string. 244 | /// If the key is not string, use `containsObj` instead. 245 | pub fn PyDict::contains(self : PyDict, key : String) -> Bool { 246 | let dict = self.obj_ref() 247 | @cpython.py_dict_contains(dict, PyString::from(key).obj_ref()) 248 | } 249 | 250 | ///| Check if the dict contains the key. 251 | pub fn PyDict::containsObj(self : PyDict, key : PyObject) -> Bool { 252 | let dict = self.obj_ref() 253 | @cpython.py_dict_contains(dict, key.obj_ref()) 254 | } 255 | 256 | ///| Get the keys of the dict. 257 | /// 258 | /// **Notes**: It is slight different from the python dict.keys() method. 259 | /// In python, dict.keys() returns a view object that displays a list of all the keys. 260 | /// While here in moonbit, keys() returns a list of all the keys. 261 | /// 262 | /// ## Example 263 | /// 264 | /// ```moonbit 265 | /// test "PyDict::keys" { 266 | /// let dict = PyDict::new() 267 | /// dict 268 | /// ..set("one", PyInteger::from(1)) 269 | /// ..set("two", PyFloat::from(2.0)) 270 | /// ..set("three", PyBool::from(true)); 271 | /// 272 | /// inspect!(dict.keys(), content="[\'one\', \'two\', \'three\']") 273 | /// } 274 | /// ``` 275 | /// 276 | /// The above code is equivalent to: 277 | /// 278 | /// ```python 279 | /// d = { 'one': 1, 'two': 2.0, 'three': True } 280 | /// dict_keys = d.keys() 281 | /// print(dict_keys) # Output: dict_keys(['one', 'two', 'three']) 282 | /// ``` 283 | pub fn PyDict::keys(self : PyDict) -> PyList { 284 | PyList::create_by_ref_unchecked(@cpython.py_dict_keys(self.obj_ref())) 285 | } 286 | 287 | ///| Get the values of the dict. 288 | /// 289 | /// **Notes**: It is slight different from the python dict.values() method. 290 | /// In python, dict.values() returns a view object that displays a list of all the values. 291 | /// While here in moonbit, values() returns a list of all the values. 292 | /// 293 | /// ## Example 294 | /// 295 | /// ```moonbit 296 | /// test "PyDict::values" { 297 | /// let dict = PyDict::new() 298 | /// dict 299 | /// ..set("one", PyInteger::from(1)) 300 | /// ..set("two", PyFloat::from(2.0)) 301 | /// ..set("three", PyBool::from(true)); 302 | /// 303 | /// inspect!(dict.values(), content="[1, 2.0, True]") 304 | /// } 305 | /// ``` 306 | /// 307 | /// The above code is equivalent to: 308 | /// 309 | /// ```python 310 | /// d = { 'one': 1, 'two': 2.0, 'three': True } 311 | /// dict_values = d.values() 312 | /// print(dict_values) # Output: dict_values([1, 2.0, True]) 313 | /// ``` 314 | pub fn PyDict::values(self : PyDict) -> PyList { 315 | PyList::create_by_ref_unchecked(@cpython.py_dict_values(self.obj_ref())) 316 | } 317 | 318 | ///| Get the items of the dict. 319 | /// 320 | /// **Notes**: It is slight different from the python dict.items() method. 321 | /// In python, dict.items() returns a view object that displays a list of all the items. 322 | /// While here in moonbit, items() returns a list of all the items. 323 | /// 324 | /// ## Example 325 | /// 326 | /// ```moonbit 327 | /// test "PyDict::items" { 328 | /// let dict = PyDict::new() 329 | /// dict 330 | /// ..set("one", PyInteger::from(1)) 331 | /// ..set("two", PyFloat::from(2.0)) 332 | /// ..set("three", PyBool::from(true)); 333 | /// 334 | /// inspect!(dict.items(), content="[('one', 1), ('two', 2.0), ('three', True)]") 335 | /// } 336 | /// ``` 337 | pub fn PyDict::items(self : PyDict) -> PyList { 338 | PyList::create_by_ref_unchecked(@cpython.py_dict_items(self.obj_ref())) 339 | } 340 | 341 | ///| Let python interpret print the dict directly. 342 | /// 343 | /// **Note**: This is different from `println(dict)` and `dict.dump()`. 344 | /// although they always print the same content. 345 | pub fn PyDict::dump(self : PyDict) -> Unit { 346 | PyObject::dump(self.obj) 347 | } 348 | 349 | ///| 350 | pub fn PyDict::drop(self : PyDict) -> Unit { 351 | self.obj.drop() 352 | } 353 | 354 | ///| 355 | pub impl IsPyObject for PyDict with obj(self) { 356 | self.obj 357 | } 358 | 359 | ///| 360 | pub impl Show for PyDict with to_string(self) -> String { 361 | self.obj.to_string() 362 | } 363 | 364 | ///| 365 | pub impl Show for PyDict with output(self : PyDict, logger : &Logger) -> Unit { 366 | logger.write_string(self.to_string()) 367 | } 368 | -------------------------------------------------------------------------------- /enums.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub enum PyType { 3 | PyInteger 4 | PyFloat 5 | PyBool 6 | PyString 7 | PyTuple 8 | PyList 9 | PyDict 10 | PyModule 11 | PyCallable 12 | PyClass 13 | } 14 | 15 | ///| 16 | pub(all) enum PyObjectEnum { 17 | PyInteger(PyInteger) 18 | PyFloat(PyFloat) 19 | PyBool(PyBool) 20 | PyString(PyString) 21 | PyTuple(PyTuple) 22 | PyList(PyList) 23 | PyDict(PyDict) 24 | PyModule(PyModule) 25 | PyCallable(PyCallable) 26 | PyClass(PyObject) 27 | } derive(Show) 28 | 29 | ///| 30 | pub fn PyObjectEnum::create(obj : PyObject) -> PyObjectEnum { 31 | match obj.type_of() { 32 | PyInteger => PyInteger(PyInteger::create_unchecked(obj)) 33 | PyFloat => PyFloat(PyFloat::create_unchecked(obj)) 34 | PyBool => PyBool(PyBool::create_unchecked(obj)) 35 | PyString => PyString(PyString::create_unchecked(obj)) 36 | PyTuple => PyTuple(PyTuple::create_unchecked(obj)) 37 | PyList => PyList(PyList::create_unchecked(obj)) 38 | PyDict => PyDict(PyDict::create_unchecked(obj)) 39 | PyModule => PyModule(PyModule::create_unchecked(obj)) 40 | PyCallable => PyCallable(PyCallable::create_unchecked(obj)) 41 | PyClass => PyClass(obj) 42 | } 43 | } 44 | 45 | ///| 46 | pub fn PyObjectEnum::dump(self : PyObjectEnum) -> Unit { 47 | match self { 48 | PyInteger(obj) => obj.dump() 49 | PyFloat(obj) => obj.dump() 50 | PyBool(obj) => obj.dump() 51 | PyString(obj) => obj.dump() 52 | PyTuple(obj) => obj.dump() 53 | PyList(obj) => obj.dump() 54 | PyDict(obj) => obj.dump() 55 | PyModule(obj) => obj.dump() 56 | PyCallable(obj) => obj.dump() 57 | PyClass(obj) => obj.dump() 58 | } 59 | } 60 | 61 | ///| 62 | pub fn PyObjectEnum::create_by_ref( 63 | obj_ref : @cpython.PyObjectRef 64 | ) -> PyObjectEnum { 65 | let obj = PyObject::create(obj_ref) 66 | PyObjectEnum::create(obj) 67 | } 68 | -------------------------------------------------------------------------------- /errors.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub type! PyRuntimeError { 3 | TypeMisMatchError 4 | IndexOutOfBoundsError 5 | KeyIsUnHashableError 6 | InVokeError 7 | } derive(Show) 8 | -------------------------------------------------------------------------------- /float.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub struct PyFloat { 3 | priv obj : PyObject 4 | } 5 | 6 | ///| Create a python float object from a python object. 7 | /// If the python object is not a float, it will raise a TypeMisMatchError. 8 | pub fn PyFloat::create(obj : PyObject) -> PyFloat!PyRuntimeError { 9 | guard obj.is_float() else { raise TypeMisMatchError } 10 | PyFloat::{ obj, } 11 | } 12 | 13 | ///| 14 | fn PyFloat::create_unchecked(obj : PyObject) -> PyFloat { 15 | PyFloat::{ obj, } 16 | } 17 | 18 | ///| Ceate a python float object from a python object reference. 19 | /// If the python object is not a float, it will raise a TypeMisMatchError. 20 | pub fn PyFloat::create_by_ref( 21 | obj : @cpython.PyObjectRef 22 | ) -> PyFloat!PyRuntimeError { 23 | guard @cpython.py_float_check(obj) else { raise TypeMisMatchError } 24 | PyFloat::{ obj: PyObject::create(obj) } 25 | } 26 | 27 | ///| 28 | fn PyFloat::create_by_ref_unchecked(obj : @cpython.PyObjectRef) -> PyFloat { 29 | PyFloat::{ obj: PyObject::create(obj) } 30 | } 31 | 32 | ///| Create a PyFloat from a Double value. 33 | /// 34 | /// ## Example 35 | /// 36 | /// ```moonbit 37 | /// test "PyFloat::from" { 38 | /// let f = @python.PyFloat::from(3.5); 39 | /// inspect!(f, content="3.5") 40 | /// } 41 | /// ``` 42 | pub fn PyFloat::from(value : Double) -> PyFloat { 43 | PyFloat::{ obj: @cpython.py_float_from_double(value) |> PyObject::create } 44 | } 45 | 46 | ///| Convert a PyFloat to a Double. 47 | /// 48 | /// ## Example 49 | /// 50 | /// ```moonbit 51 | /// test "PyFloat::to_double" { 52 | /// let f = @python.PyFloat::from(3.5); 53 | /// assert_eq!(f.to_double(), 3.5); 54 | /// } 55 | /// ``` 56 | pub fn PyFloat::to_double(self : PyFloat) -> Double { 57 | @cpython.py_float_as_double(self.obj_ref()) 58 | } 59 | 60 | ///| Print the PyFloat object direcly. 61 | /// 62 | /// Different from use `println`, `dump` means we made python interpreter 63 | /// print the object directly. 64 | /// 65 | /// ## Example 66 | /// 67 | /// ```moonbit-no-test 68 | /// let f = @python.PyFloat::from(3.5); 69 | /// f.dump() 70 | /// ``` 71 | /// 72 | /// the code above will print: 3.5 73 | pub fn PyFloat::dump(self : PyFloat) -> Unit { 74 | PyObject::dump(self.obj) 75 | } 76 | 77 | ///| 78 | pub fn PyFloat::drop(self : PyFloat) -> Unit { 79 | self.obj.drop() 80 | } 81 | 82 | ///| 83 | pub impl IsPyObject for PyFloat with obj(self) { 84 | self.obj 85 | } 86 | 87 | ///| 88 | pub impl Show for PyFloat with to_string(self) -> String { 89 | @cpython.py_object_moonbit_repr(self.obj_ref()) 90 | } 91 | 92 | ///| 93 | pub impl Show for PyFloat with output(self : PyFloat, logger : &Logger) -> Unit { 94 | logger.write_string(self.to_string()) 95 | } 96 | -------------------------------------------------------------------------------- /integer.mbt: -------------------------------------------------------------------------------- 1 | // ======================================== 2 | // PyInteger 3 | // ======================================== 4 | ///| 5 | pub struct PyInteger { 6 | priv obj : PyObject 7 | } 8 | 9 | ///| Create a python integer object from a python object. 10 | /// If 11 | pub fn PyInteger::create(obj : PyObject) -> PyInteger!PyRuntimeError { 12 | guard obj.is_int() else { raise TypeMisMatchError } 13 | PyInteger::{ obj, } 14 | } 15 | 16 | ///| 17 | pub fn PyInteger::create_unchecked(obj : PyObject) -> PyInteger { 18 | PyInteger::{ obj, } 19 | } 20 | 21 | ///| 22 | pub fn PyInteger::create_by_ref( 23 | obj : @cpython.PyObjectRef 24 | ) -> PyInteger!PyRuntimeError { 25 | guard @cpython.py_int_check(obj) else { raise TypeMisMatchError } 26 | PyInteger::{ obj: PyObject::create(obj) } 27 | } 28 | 29 | ///| 30 | fn PyInteger::create_by_ref_unchecked(obj : @cpython.PyObjectRef) -> PyInteger { 31 | PyInteger::{ obj: PyObject::create(obj) } 32 | } 33 | 34 | ///| Create a PyInteger from an integer. 35 | /// 36 | /// ## Example 37 | /// 38 | /// ```moonbit 39 | /// test "PyInteger::from" { 40 | /// let i = @python.PyInteger::from(42); 41 | /// inspect!(i, content="42") 42 | /// } 43 | /// ``` 44 | pub fn PyInteger::from(value : Int64) -> PyInteger { 45 | PyInteger::{ obj: PyObject::create(@cpython.py_long_from_long(value)) } 46 | } 47 | 48 | ///| Convert a PyInteger to an integer. 49 | /// 50 | /// ## Example 51 | /// 52 | /// ```moonbit 53 | /// test "PyInteger::to_int64" { 54 | /// let i = @python.PyInteger::from(42); 55 | /// assert_eq!(i.to_int64(), 42); 56 | /// } 57 | /// ``` 58 | pub fn PyInteger::to_int64(self : PyInteger) -> Int64 { 59 | @cpython.py_long_as_long(self.obj_ref()) 60 | } 61 | 62 | ///| Convert a PyInteger to a double. 63 | /// 64 | /// ## Example 65 | /// 66 | /// ```moonbit 67 | /// test "PyInteger::to_double" { 68 | /// let i = @python.PyInteger::from(42); 69 | /// assert_eq!(i.to_double(), 42.0); 70 | /// } 71 | /// /// ``` 72 | pub fn PyInteger::to_double(self : PyInteger) -> Double { 73 | @cpython.py_long_as_double(self.obj_ref()) 74 | } 75 | 76 | ///| Print the PyInteger object direcly. 77 | /// 78 | /// Different from use `println`, `dump` means we made python interpreter 79 | /// print the object directly. 80 | /// 81 | /// ## Example 82 | /// 83 | /// ```moonbit-no-test 84 | /// let i = @python.PyInteger::from(42); 85 | /// i.dump() 86 | /// ``` 87 | /// 88 | /// the code above will print: 42 89 | pub fn PyInteger::dump(self : PyInteger) -> Unit { 90 | PyObject::dump(self.obj) 91 | } 92 | 93 | ///| 94 | pub fn PyInteger::drop(self : PyInteger) -> Unit { 95 | self.obj.drop() 96 | } 97 | 98 | ///| 99 | pub impl IsPyObject for PyInteger with obj(self) { 100 | self.obj 101 | } 102 | 103 | ///| 104 | pub impl Show for PyInteger with to_string(self) -> String { 105 | self.obj.to_string() 106 | } 107 | 108 | ///| 109 | pub impl Show for PyInteger with output(self, logger) -> Unit { 110 | logger.write_string(self.to_string()) 111 | } 112 | -------------------------------------------------------------------------------- /list.mbt: -------------------------------------------------------------------------------- 1 | // ======================================== 2 | // py_list 3 | // ======================================== 4 | ///| 5 | pub struct PyList { 6 | priv obj : PyObject 7 | } 8 | 9 | ///| Create an empty python list. 10 | /// 11 | /// ## Example 12 | /// 13 | /// ```moonbit 14 | /// test "PyList::new" { 15 | /// let list = @python.PyList::new(); 16 | /// inspect!(list, content="[]") 17 | /// assert_eq!(list.len(), 0); 18 | /// } 19 | /// ``` 20 | pub fn PyList::new() -> PyList { 21 | PyList::{ obj: @cpython.py_list_new(0) |> PyObject::create } 22 | } 23 | 24 | ///| Create a python list object from a pyobject. 25 | /// If the pyobject is not a list, it will raise a TypeMisMatchError. 26 | pub fn PyList::create(obj : PyObject) -> PyList!PyRuntimeError { 27 | guard obj.is_list() else { raise TypeMisMatchError } 28 | PyList::{ obj, } 29 | } 30 | 31 | ///| 32 | fn PyList::create_unchecked(obj : PyObject) -> PyList { 33 | PyList::{ obj, } 34 | } 35 | 36 | ///| Create a python list object from a pyobject reference. 37 | /// If the pyobject is not a list, it will raise a TypeMisMatchError. 38 | pub fn PyList::create_by_ref( 39 | obj : @cpython.PyObjectRef 40 | ) -> PyList!PyRuntimeError { 41 | guard @cpython.py_list_check(obj) else { raise TypeMisMatchError } 42 | PyList::{ obj: PyObject::create(obj) } 43 | } 44 | 45 | ///| 46 | fn PyList::create_by_ref_unchecked(obj : @cpython.PyObjectRef) -> PyList { 47 | PyList::{ obj: PyObject::create(obj) } 48 | } 49 | 50 | ///| Returns the length of the list. 51 | /// 52 | /// ## Example 53 | /// 54 | /// ```moonbit 55 | /// test "PyList::len" { 56 | /// let list = @python.PyList::new(); 57 | /// list.append(@python.PyInteger::from(1)); 58 | /// list.append(@python.PyFloat::from(2.0)); 59 | /// list.append(@python.PyString::from("hello")); 60 | /// 61 | /// assert_eq!(list.len(), 3); 62 | /// } 63 | /// ``` 64 | /// 65 | /// The above code is equivalent to the following Python code: 66 | /// 67 | /// ```python 68 | /// list = [] 69 | /// list.append(1) 70 | /// list.append(2.0) 71 | /// list.append("hello") 72 | /// 73 | /// print(len(list)) # Output: 3 74 | /// ``` 75 | pub fn PyList::len(self : PyList) -> Int { 76 | @cpython.py_list_size(self.obj_ref()).to_int() 77 | } 78 | 79 | ///| Append an item to the end of the list. 80 | /// 81 | /// ## Example 82 | /// 83 | /// ```moonbit 84 | /// test "PyList::append" { 85 | /// let list = @python.PyList::new(); 86 | /// list.append(@python.PyInteger::from(1)); 87 | /// list.append(@python.PyFloat::from(2.0)); 88 | /// list.append(@python.PyString::from("hello")); 89 | /// inspect!(list, content="[1, 2.0, \'hello\']") 90 | /// } 91 | /// ``` 92 | /// 93 | /// The above code is equivalent to the following Python code: 94 | /// 95 | /// ```python 96 | /// list = [] 97 | /// list.append(1) 98 | /// list.append(2.0) 99 | /// list.append("hello") 100 | /// 101 | /// print(list) # Output: [1, 2.0, 'hello'] 102 | /// ``` 103 | pub fn[T : IsPyObject] PyList::append(self : PyList, item : T) -> Unit { 104 | let _ = @cpython.py_list_append(self.obj_ref(), item.obj_ref()) 105 | 106 | } 107 | 108 | // Review: The following code is available, but I don't think it is necessary. 109 | ///| Sort the elements inside the list, using python's built-in sort. 110 | //pub fn PyList::sort(self: PyList) -> Unit { 111 | // let _ = @cpython.py_list_sort(self.obj_ref()) 112 | //} 113 | 114 | // Review: The following code is available, but I don't think it is necessary. 115 | //pub fn PyList::reverse(self: PyList) -> Unit { 116 | // let _ = @cpython.py_list_reverse(self.obj_ref()) 117 | //} 118 | 119 | ///| Create a new python list from a python object array 120 | /// 121 | /// ## Example 122 | /// 123 | /// ```moonbit 124 | /// test "PyList::from" { 125 | /// let arr: Array[&IsPyObject] = Array::new() 126 | /// let one = PyInteger::from(1); 127 | /// let two = PyFloat::from(2.0); 128 | /// let three = PyString::from("three"); 129 | /// 130 | /// arr.push(one) 131 | /// arr.push(two) 132 | /// arr.push(three) 133 | /// 134 | /// let list = PyList::from(arr); 135 | /// inspect!(list, content="[1, 2.0, \'three\']") 136 | /// } 137 | /// ``` 138 | pub fn[T : IsPyObject] PyList::from(items : Array[T]) -> PyList { 139 | let pylist = PyList::new() 140 | items.each(fn(item) { pylist.append(item) }) 141 | pylist 142 | } 143 | 144 | ///| Get the item at the specified index. 145 | /// 146 | /// **Notes**: Although python support negative index, the moonbit api does not 147 | /// support it. Code like `list.get(-1)` will return `None`. 148 | /// 149 | /// ## Example 150 | /// 151 | /// ```moonbit 152 | /// test "PyList::get" { 153 | /// let list = @python.PyList::new(); 154 | /// list.append(@python.PyInteger::from(1)); 155 | /// list.append(@python.PyFloat::from(2.0)); 156 | /// list.append(@python.PyString::from("hello")); 157 | /// 158 | /// inspect!(list.get(0).unwrap(), content="PyInteger(1)") 159 | /// inspect!(list.get(1), content="Some(PyFloat(2.0))") 160 | /// inspect!(list.get(3), content="None") 161 | /// inspect!(list.get(-1), content="None") 162 | /// } 163 | /// ``` 164 | pub fn PyList::get(self : PyList, idx : Int) -> PyObjectEnum? { 165 | @option.when(idx >= 0 && idx < self.len(), fn() { 166 | @cpython.py_list_get_item(self.obj_ref(), idx.to_int64()) 167 | |> PyObject::create 168 | |> PyObjectEnum::create 169 | }) 170 | } 171 | 172 | ///| Get the item at the specified index. 173 | /// 174 | /// **Notes**: Although python support negative index, the moonbit api does not 175 | /// support it. which means code like `list[-1]` will be panic. 176 | /// 177 | /// ## Example 178 | /// 179 | /// ```moonbit 180 | /// test "PyList::op_get" { 181 | /// let list = @python.PyList::new(); 182 | /// list.append(@python.PyInteger::from(1)); 183 | /// list.append(@python.PyFloat::from(2.0)); 184 | /// list.append(@python.PyString::from("hello")); 185 | /// 186 | /// inspect!(list[0], content="PyInteger(1)") 187 | /// inspect!(list[1], content="PyFloat(2.0)") 188 | /// inspect!(list[2], content="PyString(hello)") 189 | /// } 190 | /// ``` 191 | pub fn PyList::op_get(self : PyList, idx : Int) -> PyObjectEnum { 192 | self.get(idx).unwrap() 193 | } 194 | 195 | ///| Set the item at the specified index. 196 | /// 197 | /// **Notes**: Although python support negative index, the moonbit api does not 198 | /// support it. which means code like `list.set(-1) = ...` will raise IndexOutOfBoundsError. 199 | /// 200 | /// ## Example 201 | /// 202 | /// ```moonbit 203 | /// test "PyList::set" { 204 | /// let list = @python.PyList::new(); 205 | /// list.append(@python.PyInteger::from(1)); 206 | /// list.append(@python.PyFloat::from(2.0)); 207 | /// list.append(@python.PyString::from("hello")); 208 | /// inspect!(list, content="[1, 2.0, \'hello\']") 209 | /// 210 | /// list.set!(0, @python.PyInteger::from(42)); 211 | /// inspect!(list, content="[42, 2.0, \'hello\']") 212 | /// } 213 | /// ``` 214 | pub fn[T : IsPyObject] PyList::set( 215 | self : PyList, 216 | idx : Int, 217 | item : T 218 | ) -> Unit!PyRuntimeError { 219 | guard idx >= 0 && idx < self.len() else { raise IndexOutOfBoundsError } 220 | let _ = @cpython.py_list_set_item( 221 | self.obj_ref(), 222 | idx.to_int64(), 223 | item.obj_ref(), 224 | ) 225 | 226 | } 227 | 228 | ///| Set the item at the specified index. 229 | /// 230 | /// **Notes**: Although python support negative index, the moonbit api does not 231 | /// support it. which means code like `list[-1] = ...` will be panic. 232 | /// 233 | /// ## Example 234 | /// 235 | /// ```moonbit 236 | /// test "PyList::op_set" { 237 | /// let list = @python.PyList::new(); 238 | /// list.append(@python.PyInteger::from(1)); 239 | /// list.append(@python.PyFloat::from(2.0)); 240 | /// list.append(@python.PyString::from("hello")); 241 | /// inspect!(list, content="[1, 2.0, \'hello\']") 242 | /// 243 | /// list[0] = @python.PyInteger::from(42); 244 | /// inspect!(list, content="[42, 2.0, \'hello\']") 245 | /// } 246 | /// ``` 247 | pub fn[T : IsPyObject] PyList::op_set( 248 | self : PyList, 249 | idx : Int, 250 | item : T 251 | ) -> Unit { 252 | self.set?(idx, item).unwrap() 253 | } 254 | 255 | ///| Let python interpreter print the list directly. 256 | /// 257 | /// **Note**: It is different from `println(list)` and `list.dump()` 258 | /// although they always print the same content. 259 | pub fn PyList::dump(self : PyList) -> Unit { 260 | self.obj.dump() 261 | } 262 | 263 | ///| 264 | pub fn PyList::drop(self : PyList) -> Unit { 265 | self.obj.drop() 266 | } 267 | 268 | ///| 269 | pub impl IsPyObject for PyList with obj(self) { 270 | self.obj 271 | } 272 | 273 | ///| 274 | pub impl Show for PyList with to_string(self) -> String { 275 | self.obj.to_string() 276 | } 277 | 278 | ///| 279 | pub impl Show for PyList with output(self : PyList, logger : &Logger) -> Unit { 280 | logger.write_string(self.to_string()) 281 | } 282 | -------------------------------------------------------------------------------- /main/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | typealias @python.(PyInteger, PyList, PyTuple) 3 | 4 | ///| 5 | fn main { 6 | // It's equivalent to `nums = [1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4]` 7 | let nums = [1L, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4] 8 | let py_nums = nums.map(PyInteger::from) |> PyList::from 9 | println(py_nums) // Output: [1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4] 10 | 11 | // It's equivalent to `import collections` 12 | guard @python.pyimport("collections") is Some(collections) 13 | 14 | // It's equivalent to `from collections import Counter` 15 | guard collections.get_attr("Counter") is Some(PyCallable(counter)) 16 | let args = PyTuple::new(1) 17 | args..set(0, py_nums) 18 | 19 | // It's equivalent to `cnt = Counter(nums)` 20 | guard counter.invoke?(args~) is Ok(Some(cnt)) 21 | guard cnt is PyDict(cnt) 22 | 23 | // `print(cnt)` 24 | println(cnt) // Output: Counter({4: 4, 3: 3, 2: 2, 1: 2}) 25 | } 26 | -------------------------------------------------------------------------------- /main/main.mbti: -------------------------------------------------------------------------------- 1 | package "Kaida-Amethyst/python/main" 2 | 3 | // Values 4 | 5 | // Types and methods 6 | 7 | // Type aliases 8 | 9 | // Traits 10 | 11 | -------------------------------------------------------------------------------- /main/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": ["Kaida-Amethyst/python"] 4 | } 5 | -------------------------------------------------------------------------------- /module.mbt: -------------------------------------------------------------------------------- 1 | // ======================================== 2 | // Import 3 | // ======================================== 4 | ///| 5 | pub struct PyModule { 6 | priv obj : PyObject 7 | priv mut name : String? 8 | priv attrs : Map[String, PyObjectEnum] 9 | } 10 | 11 | ///| 12 | pub fn PyModule::create(obj : PyObject) -> PyModule!PyRuntimeError { 13 | guard obj.is_module() else { raise TypeMisMatchError } 14 | PyModule::{ obj, name: None, attrs: Map::new() } 15 | } 16 | 17 | ///| 18 | fn PyModule::create_unchecked(obj : PyObject) -> PyModule { 19 | PyModule::{ obj, name: None, attrs: Map::new() } 20 | } 21 | 22 | ///| 23 | pub fn PyModule::create_by_ref( 24 | obj_ref : @cpython.PyObjectRef 25 | ) -> PyModule!PyRuntimeError { 26 | guard @cpython.py_module_check(obj_ref) else { raise TypeMisMatchError } 27 | PyModule::{ obj: PyObject::create(obj_ref), name: None, attrs: Map::new() } 28 | } 29 | 30 | ///| 31 | fn PyModule::create_by_ref_unchecked( 32 | obj_ref : @cpython.PyObjectRef 33 | ) -> PyModule { 34 | PyModule::{ obj: PyObject::create(obj_ref), name: None, attrs: Map::new() } 35 | } 36 | 37 | // REVIEW: what if user call pyimport twice or more? 38 | ///| Import a python module 39 | /// 40 | /// ## Example 41 | /// 42 | /// ```moonbit 43 | /// test "Py Import" { 44 | /// let os = @python.pyimport("os") 45 | /// 46 | /// assert_true!(os is Some(_)) 47 | /// } 48 | /// ``` 49 | pub fn pyimport(name : String, print_err~ : Bool = false) -> PyModule? { 50 | let obj = @cpython.py_import_import_module(name) 51 | if obj.is_null() { 52 | if print_err { 53 | println("module \{name} not found") 54 | @cpython.py_err_print() 55 | } 56 | @cpython.py_err_clear() 57 | return None 58 | } 59 | PyModule::{ obj: PyObject::create(obj), name: None, attrs: Map::new() } 60 | |> Some 61 | } 62 | 63 | ///| Get the name of the module. 64 | /// 65 | /// ## Example 66 | /// 67 | /// ```moonbit 68 | /// test "Py Import" { 69 | /// let os = @python.pyimport("os").unwrap() 70 | /// 71 | /// inspect!(os.get_name(), content="os") 72 | /// } 73 | /// ``` 74 | pub fn PyModule::get_name(self : PyModule) -> String { 75 | if self.name is Some(n) { 76 | return n 77 | } 78 | let attr = self.get_attr("__name__") 79 | if attr is None { 80 | println("module has no attribute __name__") 81 | panic() 82 | } 83 | let attr = attr.unwrap() 84 | guard attr is PyString(s) else { 85 | println("module __name__ is not a string") 86 | panic() 87 | } 88 | let n = s.to_string() |> strip_quot 89 | self.name = Some(n) 90 | n 91 | } 92 | 93 | ///| 94 | pub fn PyModule::dump(self : PyModule) -> Unit { 95 | self.obj.dump() 96 | } 97 | 98 | ///| Get attribute by name. 99 | /// 100 | /// ## Example 101 | /// 102 | /// ```moonbit 103 | /// test "Py Import" { 104 | /// let collections = pyimport("collections").unwrap() 105 | /// guard collections.get_attr("Counter").unwrap() is PyCallable(counter) 106 | /// 107 | /// let list = [1L, 2L, 2L, 3L, 3L, 3L].map(PyInteger::from) |> PyList::from 108 | /// let args = PyTuple::new(1) 109 | /// args .. set(0, list) 110 | /// guard counter.invoke(args~) is Some(PyDict(cnt)) 111 | /// inspect!(cnt, content="Counter({3: 3, 2: 2, 1: 1})") 112 | /// 113 | /// guard cnt.obj().get_attr("total") is Some(PyCallable(total)) 114 | /// inspect!(total.invoke().unwrap(), content="PyInteger(6)") 115 | /// } 116 | /// ``` 117 | /// 118 | /// // The above code is equivalent to the following python code: 119 | /// 120 | /// ```python 121 | /// import collections 122 | /// from collections import Counter 123 | /// 124 | /// list = [1, 2, 2, 3, 3, 3] 125 | /// cnt = Counter(list) 126 | /// print(cnt) # Counter({3: 3, 2: 2, 1: 1}) 127 | /// 128 | /// total = cnt.total() 129 | /// print(total) # 6 130 | /// ``` 131 | pub fn PyModule::get_attr( 132 | self : PyModule, 133 | attr : String, 134 | print_err~ : Bool = false 135 | ) -> PyObjectEnum? { 136 | if self.attrs.contains(attr) { 137 | return self.attrs.get(attr) 138 | } 139 | let f = @cpython.py_object_get_attr_string(self.obj_ref(), attr) 140 | if f.is_null() { 141 | if print_err { 142 | println("module \{self.get_name()} has no attribute \{attr}") 143 | @cpython.py_err_print() 144 | } 145 | @cpython.py_err_clear() 146 | return None 147 | } 148 | let c = PyObjectEnum::create_by_ref(f) 149 | self.attrs.set(attr, c) 150 | Some(c) 151 | } 152 | 153 | ///| 154 | pub impl IsPyObject for PyModule with obj(self) { 155 | self.obj 156 | } 157 | 158 | ///| 159 | pub impl Show for PyModule with to_string(self) { 160 | self.obj.to_string() 161 | } 162 | 163 | ///| 164 | pub impl Show for PyModule with output(self, logger) { 165 | logger.write_string(self.to_string()) 166 | } 167 | -------------------------------------------------------------------------------- /moon.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Kaida-Amethyst/python", 3 | "version": "0.1.4", 4 | "readme": "README.md", 5 | "repository": "https://github.com/moonbitlang/python.mbt", 6 | "license": "Apache-2.0", 7 | "keywords": ["python", "Native-Only"], 8 | "description": "Manipulate Python code in Moonbit", 9 | "scripts": { 10 | "postadd": "curl -O https://raw.githubusercontent.com/Kaida-Amethyst/python.mbt/blob/master/env.sh" 11 | }, 12 | "--moonbit-unstable-prebuild": "build.js" 13 | } 14 | -------------------------------------------------------------------------------- /moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": false, 3 | "import": ["Kaida-Amethyst/python/cpython"] 4 | } 5 | -------------------------------------------------------------------------------- /obj.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub struct PyObject { 3 | priv obj : @cpython.PyObjectRef 4 | } 5 | 6 | ///| 7 | fn PyObject::obj_ref(self : PyObject) -> @cpython.PyObjectRef { 8 | self.obj 9 | } 10 | 11 | ///| 12 | pub fn PyObject::create(obj : @cpython.PyObjectRef) -> PyObject { 13 | PyObject::{ obj, } 14 | } 15 | 16 | ///| 17 | pub fn PyObject::is_null(self : PyObject) -> Bool { 18 | self.obj.is_null() 19 | } 20 | 21 | ///| 22 | pub fn PyObject::is_bool(self : PyObject) -> Bool { 23 | @cpython.py_bool_check(self.obj_ref()) 24 | } 25 | 26 | ///| 27 | pub fn PyObject::is_int(self : PyObject) -> Bool { 28 | @cpython.py_int_check(self.obj_ref()) 29 | } 30 | 31 | ///| 32 | pub fn PyObject::is_float(self : PyObject) -> Bool { 33 | @cpython.py_float_check(self.obj_ref()) 34 | } 35 | 36 | ///| 37 | pub fn PyObject::is_string(self : PyObject) -> Bool { 38 | @cpython.py_string_check(self.obj_ref()) 39 | } 40 | 41 | ///| 42 | pub fn PyObject::is_list(self : PyObject) -> Bool { 43 | @cpython.py_list_check(self.obj_ref()) 44 | } 45 | 46 | ///| 47 | pub fn PyObject::is_tuple(self : PyObject) -> Bool { 48 | @cpython.py_tuple_check(self.obj_ref()) 49 | } 50 | 51 | ///| 52 | pub fn PyObject::is_dict(self : PyObject) -> Bool { 53 | @cpython.py_dict_check(self.obj_ref()) 54 | } 55 | 56 | ///| 57 | pub fn PyObject::is_module(self : PyObject) -> Bool { 58 | @cpython.py_module_check(self.obj_ref()) 59 | } 60 | 61 | ///| 62 | pub fn PyObject::is_callable(self : PyObject) -> Bool { 63 | @cpython.py_callable_check(self.obj_ref()) 64 | } 65 | 66 | ///| 67 | pub fn PyObject::type_of(self : PyObject) -> PyType { 68 | if @cpython.py_bool_check(self.obj_ref()) { 69 | PyType::PyBool 70 | } else if @cpython.py_int_check(self.obj_ref()) { 71 | PyType::PyInteger 72 | } else if @cpython.py_float_check(self.obj_ref()) { 73 | PyType::PyFloat 74 | } else if @cpython.py_string_check(self.obj_ref()) { 75 | PyType::PyString 76 | } else if @cpython.py_list_check(self.obj_ref()) { 77 | PyType::PyList 78 | } else if @cpython.py_tuple_check(self.obj_ref()) { 79 | PyType::PyTuple 80 | } else if @cpython.py_dict_check(self.obj_ref()) { 81 | PyType::PyDict 82 | } else if @cpython.py_module_check(self.obj_ref()) { 83 | PyType::PyModule 84 | } else if @cpython.py_callable_check(self.obj_ref()) { 85 | PyType::PyCallable 86 | } else { 87 | PyType::PyClass 88 | } 89 | } 90 | 91 | ///| 92 | pub fn PyObject::dump(self : PyObject) -> Unit { 93 | @cpython.print_pyobject(self.obj_ref()) 94 | } 95 | 96 | ///| 97 | pub fn PyObject::drop(self : PyObject) -> Unit { 98 | @cpython.py_decref(self.obj_ref()) 99 | } 100 | 101 | ///| 102 | pub fn PyObject::type_name(self : PyObject) -> String { 103 | let ty = @cpython.py_type(self.obj_ref()) 104 | let tyname = @cpython.py_type_name(ty) 105 | tyname 106 | } 107 | 108 | ///| 109 | pub fn PyObject::get_attr( 110 | self : PyObject, 111 | attr : String, 112 | print_err~ : Bool = false 113 | ) -> PyObjectEnum? { 114 | let f = @cpython.py_object_get_attr_string(self.obj_ref(), attr) 115 | if f.is_null() { 116 | if print_err { 117 | @cpython.py_err_print() 118 | } 119 | @cpython.py_err_clear() 120 | return None 121 | } 122 | let c = PyObjectEnum::create_by_ref(f) 123 | Some(c) 124 | } 125 | 126 | ///| 127 | pub impl IsPyObject for PyObject with obj(self) { 128 | self 129 | } 130 | 131 | ///| 132 | pub impl Show for PyObject with to_string(self : PyObject) -> String { 133 | @cpython.py_object_moonbit_str(self.obj) 134 | } 135 | 136 | ///| 137 | pub impl Show for PyObject with output(self : PyObject, logger : &Logger) -> Unit { 138 | logger.write_string(self.to_string()) 139 | } 140 | -------------------------------------------------------------------------------- /python.mbti: -------------------------------------------------------------------------------- 1 | package "Kaida-Amethyst/python" 2 | 3 | import( 4 | "Kaida-Amethyst/python/cpython" 5 | ) 6 | 7 | // Values 8 | fn init_py() -> Unit 9 | 10 | fn pyimport(String, print_err~ : Bool = ..) -> PyModule? 11 | 12 | fn strip_quot(String) -> String 13 | 14 | // Types and methods 15 | pub struct PyBool { 16 | // private fields 17 | } 18 | fn PyBool::create(PyObject) -> Self!PyRuntimeError 19 | fn PyBool::create_by_ref(@cpython.PyObjectRef) -> Self!PyRuntimeError 20 | fn PyBool::dump(Self) -> Unit 21 | fn PyBool::from(Bool) -> Self 22 | fn PyBool::is_false(Self) -> Bool 23 | fn PyBool::is_true(Self) -> Bool 24 | fn PyBool::not(Self) -> Self 25 | fn PyBool::to_bool(Self) -> Bool 26 | impl IsPyObject for PyBool 27 | impl Show for PyBool 28 | 29 | pub struct PyCallable { 30 | // private fields 31 | } 32 | fn PyCallable::create(PyObject) -> Self!PyRuntimeError 33 | fn PyCallable::create_by_ref(@cpython.PyObjectRef) -> Self!PyRuntimeError 34 | fn PyCallable::dump(Self) -> Unit 35 | fn PyCallable::invoke(Self, args~ : PyTuple = .., kwargs~ : PyDict = .., print_err~ : Bool = ..) -> PyObjectEnum?!PyRuntimeError 36 | impl IsPyObject for PyCallable 37 | impl Show for PyCallable 38 | 39 | pub struct PyDict { 40 | // private fields 41 | } 42 | fn PyDict::contains(Self, String) -> Bool 43 | fn PyDict::containsObj(Self, PyObject) -> Bool 44 | fn PyDict::create(PyObject) -> Self!PyRuntimeError 45 | fn PyDict::create_by_ref(@cpython.PyObjectRef) -> Self!PyRuntimeError 46 | fn PyDict::drop(Self) -> Unit 47 | fn PyDict::dump(Self) -> Unit 48 | fn PyDict::get(Self, String) -> PyObjectEnum? 49 | fn PyDict::getByObj(Self, PyObject) -> PyObjectEnum? 50 | fn PyDict::items(Self) -> PyList 51 | fn PyDict::keys(Self) -> PyList 52 | fn PyDict::len(Self) -> Int 53 | fn PyDict::new() -> Self 54 | fn PyDict::op_get(Self, String) -> PyObjectEnum 55 | fn[V : IsPyObject] PyDict::op_set(Self, String, V) -> Unit 56 | fn[V : IsPyObject] PyDict::set(Self, String, V) -> Unit 57 | fn[K : IsPyObject, V : IsPyObject] PyDict::setByObj(Self, K, V) -> Unit!PyRuntimeError 58 | fn PyDict::values(Self) -> PyList 59 | impl IsPyObject for PyDict 60 | impl Show for PyDict 61 | 62 | pub struct PyFloat { 63 | // private fields 64 | } 65 | fn PyFloat::create(PyObject) -> Self!PyRuntimeError 66 | fn PyFloat::create_by_ref(@cpython.PyObjectRef) -> Self!PyRuntimeError 67 | fn PyFloat::drop(Self) -> Unit 68 | fn PyFloat::dump(Self) -> Unit 69 | fn PyFloat::from(Double) -> Self 70 | fn PyFloat::to_double(Self) -> Double 71 | impl IsPyObject for PyFloat 72 | impl Show for PyFloat 73 | 74 | pub struct PyInteger { 75 | // private fields 76 | } 77 | fn PyInteger::create(PyObject) -> Self!PyRuntimeError 78 | fn PyInteger::create_by_ref(@cpython.PyObjectRef) -> Self!PyRuntimeError 79 | fn PyInteger::create_unchecked(PyObject) -> Self 80 | fn PyInteger::drop(Self) -> Unit 81 | fn PyInteger::dump(Self) -> Unit 82 | fn PyInteger::from(Int64) -> Self 83 | fn PyInteger::to_double(Self) -> Double 84 | fn PyInteger::to_int64(Self) -> Int64 85 | impl IsPyObject for PyInteger 86 | impl Show for PyInteger 87 | 88 | pub struct PyList { 89 | // private fields 90 | } 91 | fn[T : IsPyObject] PyList::append(Self, T) -> Unit 92 | fn PyList::create(PyObject) -> Self!PyRuntimeError 93 | fn PyList::create_by_ref(@cpython.PyObjectRef) -> Self!PyRuntimeError 94 | fn PyList::drop(Self) -> Unit 95 | fn PyList::dump(Self) -> Unit 96 | fn[T : IsPyObject] PyList::from(Array[T]) -> Self 97 | fn PyList::get(Self, Int) -> PyObjectEnum? 98 | fn PyList::len(Self) -> Int 99 | fn PyList::new() -> Self 100 | fn PyList::op_get(Self, Int) -> PyObjectEnum 101 | fn[T : IsPyObject] PyList::op_set(Self, Int, T) -> Unit 102 | fn[T : IsPyObject] PyList::set(Self, Int, T) -> Unit!PyRuntimeError 103 | impl IsPyObject for PyList 104 | impl Show for PyList 105 | 106 | pub struct PyModule { 107 | // private fields 108 | } 109 | fn PyModule::create(PyObject) -> Self!PyRuntimeError 110 | fn PyModule::create_by_ref(@cpython.PyObjectRef) -> Self!PyRuntimeError 111 | fn PyModule::dump(Self) -> Unit 112 | fn PyModule::get_attr(Self, String, print_err~ : Bool = ..) -> PyObjectEnum? 113 | fn PyModule::get_name(Self) -> String 114 | impl IsPyObject for PyModule 115 | impl Show for PyModule 116 | 117 | pub struct PyObject { 118 | // private fields 119 | } 120 | fn PyObject::create(@cpython.PyObjectRef) -> Self 121 | fn PyObject::drop(Self) -> Unit 122 | fn PyObject::dump(Self) -> Unit 123 | fn PyObject::get_attr(Self, String, print_err~ : Bool = ..) -> PyObjectEnum? 124 | fn PyObject::is_bool(Self) -> Bool 125 | fn PyObject::is_callable(Self) -> Bool 126 | fn PyObject::is_dict(Self) -> Bool 127 | fn PyObject::is_float(Self) -> Bool 128 | fn PyObject::is_int(Self) -> Bool 129 | fn PyObject::is_list(Self) -> Bool 130 | fn PyObject::is_module(Self) -> Bool 131 | fn PyObject::is_null(Self) -> Bool 132 | fn PyObject::is_string(Self) -> Bool 133 | fn PyObject::is_tuple(Self) -> Bool 134 | fn PyObject::type_name(Self) -> String 135 | fn PyObject::type_of(Self) -> PyType 136 | impl IsPyObject for PyObject 137 | impl Show for PyObject 138 | 139 | pub(all) enum PyObjectEnum { 140 | PyInteger(PyInteger) 141 | PyFloat(PyFloat) 142 | PyBool(PyBool) 143 | PyString(PyString) 144 | PyTuple(PyTuple) 145 | PyList(PyList) 146 | PyDict(PyDict) 147 | PyModule(PyModule) 148 | PyCallable(PyCallable) 149 | PyClass(PyObject) 150 | } 151 | fn PyObjectEnum::create(PyObject) -> Self 152 | fn PyObjectEnum::create_by_ref(@cpython.PyObjectRef) -> Self 153 | fn PyObjectEnum::dump(Self) -> Unit 154 | impl Show for PyObjectEnum 155 | 156 | pub type! PyRuntimeError { 157 | TypeMisMatchError 158 | IndexOutOfBoundsError 159 | KeyIsUnHashableError 160 | InVokeError 161 | } 162 | impl Show for PyRuntimeError 163 | 164 | pub struct PyString { 165 | // private fields 166 | } 167 | fn PyString::create(PyObject) -> Self!PyRuntimeError 168 | fn PyString::create_by_ref(@cpython.PyObjectRef) -> Self!PyRuntimeError 169 | fn PyString::drop(Self) -> Unit 170 | fn PyString::dump(Self) -> Unit 171 | fn PyString::from(String) -> Self 172 | impl IsPyObject for PyString 173 | impl Show for PyString 174 | 175 | pub struct PyTuple { 176 | // private fields 177 | } 178 | fn PyTuple::create(PyObject) -> Self!PyRuntimeError 179 | fn PyTuple::create_by_ref(@cpython.PyObjectRef) -> Self!PyRuntimeError 180 | fn PyTuple::drop(Self) -> Unit 181 | fn PyTuple::dump(Self) -> Unit 182 | fn PyTuple::get(Self, Int) -> PyObjectEnum? 183 | fn PyTuple::len(Self) -> UInt64 184 | fn PyTuple::new(UInt64) -> Self 185 | fn PyTuple::op_get(Self, Int) -> PyObjectEnum 186 | fn[T : IsPyObject] PyTuple::op_set(Self, Int, T) -> Unit 187 | fn[T : IsPyObject] PyTuple::set(Self, Int, T) -> Unit 188 | impl IsPyObject for PyTuple 189 | impl Show for PyTuple 190 | 191 | pub enum PyType { 192 | PyInteger 193 | PyFloat 194 | PyBool 195 | PyString 196 | PyTuple 197 | PyList 198 | PyDict 199 | PyModule 200 | PyCallable 201 | PyClass 202 | } 203 | 204 | // Type aliases 205 | 206 | // Traits 207 | pub trait IsPyObject { 208 | obj(Self) -> PyObject 209 | obj_ref(Self) -> @cpython.PyObjectRef 210 | type_name(Self) -> String 211 | } 212 | 213 | -------------------------------------------------------------------------------- /set.mbt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /str.mbt: -------------------------------------------------------------------------------- 1 | // ======================================== 2 | // PyString 3 | // ======================================== 4 | 5 | ///| 6 | pub struct PyString { 7 | priv obj : PyObject 8 | } 9 | 10 | ///| Create a python string from a python object. 11 | /// If the python object is not a string, it will raise a TypeMisMatchError. 12 | pub fn PyString::create(obj : PyObject) -> PyString!PyRuntimeError { 13 | guard obj.is_string() else { raise TypeMisMatchError } 14 | PyString::{ obj, } 15 | } 16 | 17 | ///| 18 | fn PyString::create_unchecked(obj : PyObject) -> PyString { 19 | PyString::{ obj, } 20 | } 21 | 22 | ///| Create a python string from a python object reference. 23 | ///If the python object is not a string, it will raise a TypeMisMatchError. 24 | pub fn PyString::create_by_ref( 25 | obj_ref : @cpython.PyObjectRef 26 | ) -> PyString!PyRuntimeError { 27 | guard @cpython.py_string_check(obj_ref) else { raise TypeMisMatchError } 28 | PyString::{ obj: PyObject::create(obj_ref) } 29 | } 30 | 31 | ///| 32 | fn PyString::create_by_ref_unchecked( 33 | obj_ref : @cpython.PyObjectRef 34 | ) -> PyString { 35 | PyString::{ obj: PyObject::create(obj_ref) } 36 | } 37 | 38 | ///| Create a PyString from a string 39 | /// 40 | /// ## Example 41 | /// 42 | /// ```moonbit 43 | /// test "PyString::from" { 44 | /// let s = @python.PyString::from("hello"); 45 | /// inspect(s, content="\'hello\'"); 46 | /// } 47 | pub fn PyString::from(s : String) -> PyString { 48 | PyString::{ 49 | obj: PyObject::create(@cpython.py_unicode_from_moonbit_string(s)), 50 | } 51 | } 52 | 53 | ///| Print the PyString object direcly. 54 | /// 55 | /// Different from use `println`, `dump` means we made python interpreter 56 | /// print the object directly. 57 | /// 58 | /// ## Example 59 | /// 60 | /// ```moonbit-no-test 61 | /// let s = @python.PyString::from("hello"); 62 | /// s.dump() 63 | /// ``` 64 | /// 65 | /// the code above will print: 'hello' 66 | pub fn PyString::dump(self : PyString) -> Unit { 67 | PyObject::dump(self.obj) 68 | } 69 | 70 | ///| 71 | pub fn PyString::drop(self : PyString) -> Unit { 72 | self.obj.drop() 73 | } 74 | 75 | ///| 76 | pub impl IsPyObject for PyString with obj(self) { 77 | self.obj 78 | } 79 | 80 | ///| 81 | pub impl Show for PyString with to_string(self) { 82 | self.obj.to_string() 83 | } 84 | 85 | ///| 86 | pub impl Show for PyString with output(self : PyString, logger : &Logger) -> Unit { 87 | logger.write_string(self.to_string()) 88 | } 89 | -------------------------------------------------------------------------------- /test/module_test.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "Module Test" { 3 | let os = @python.pyimport("os", print_err=true) 4 | assert_true!(os is Some(_)) 5 | let os = os.unwrap() 6 | inspect!(os.get_name(), content="os") 7 | guard os.get_attr("name").unwrap() is PyString(s) 8 | assert_true!(["posix", "nt", "java"].contains(s.to_string())) 9 | assert_true!(os.get_attr("listdir") is Some(PyCallable(_))) 10 | 11 | /// ```python 12 | /// import collections 13 | /// ``` 14 | let collections = @python.pyimport("collections", print_err=true) 15 | assert_true!(collections is Some(_)) 16 | let collections = collections.unwrap() 17 | 18 | /// ```python 19 | /// from collections import Counter 20 | /// ``` 21 | guard collections.get_attr("Counter").unwrap() is PyCallable(counter) 22 | 23 | // ```python 24 | // elements = [1, 2, 2, 3, 3, 3] 25 | // counter = Counter(elements) 26 | // print(counter) # Output: Counter({3: 3, 2: 2, 1: 1}) 27 | // ``` 28 | let list = [1L, 2, 2, 3, 3, 3].map(PyInteger::from) |> PyList::from 29 | let args = PyTuple::new(1) 30 | args..set(0, list) 31 | guard counter.invoke(args~) is Some(PyDict(cnt)) 32 | inspect!(cnt, content="Counter({3: 3, 2: 2, 1: 1})") 33 | 34 | // ```python 35 | // print(cnt.total()) # Output: 6 36 | // ``` 37 | guard cnt.obj().get_attr("total") is Some(PyCallable(total)) 38 | let args = PyTuple::new(0) 39 | inspect!(total.invoke(args~).unwrap(), content="PyInteger(6)") 40 | } 41 | -------------------------------------------------------------------------------- /test/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": false, 3 | "test-import": ["Kaida-Amethyst/python"] 4 | } 5 | -------------------------------------------------------------------------------- /test/object_test.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | typealias @python.( 3 | PyInteger, 4 | PyFloat, 5 | PyString, 6 | PyList, 7 | PyTuple, 8 | PyBool, 9 | PyDict 10 | ) 11 | 12 | ///| 13 | test "PyInteger Test" { 14 | let i = PyInteger::from(42) 15 | inspect!(i, content="42") 16 | inspect!(i.type_name(), content="int") 17 | assert_eq!(i.to_int64(), 42) 18 | assert_eq!(i.to_double(), 42.0) 19 | } 20 | 21 | ///| 22 | test "PyFloat Test" { 23 | let f = PyFloat::from(3.5) 24 | inspect!(f, content="3.5") 25 | inspect!(f.type_name(), content="float") 26 | assert_eq!(f.to_double(), 3.5) 27 | } 28 | 29 | ///| 30 | test "PyBool Test" { 31 | let t = PyBool::from(true) 32 | let f = PyBool::from(false) 33 | let f2 = t.not() 34 | inspect!(t, content="True") 35 | inspect!(f, content="False") 36 | inspect!(t.type_name(), content="bool") 37 | assert_true!(t.is_true()) 38 | assert_true!(f.is_false()) 39 | assert_true!(f2.is_false()) 40 | } 41 | 42 | ///| 43 | test "PyString Test" { 44 | let s = PyString::from("hello") 45 | inspect!(s, content="hello") 46 | inspect!(s.type_name(), content="str") 47 | inspect!(PyString::from("one"), content="one") 48 | inspect!(PyString::from("two"), content="two") 49 | let hw = PyString::from("你好,世界") 50 | inspect!(hw, content="你好,世界") 51 | } 52 | 53 | ///| 54 | test "PyList Test" { 55 | let list = PyList::new() 56 | inspect!(list, content="[]") 57 | assert_eq!(list.len(), 0) 58 | inspect!(list.type_name(), content="list") 59 | let one = PyInteger::from(1) 60 | let two = PyFloat::from(2.0) 61 | let three = PyString::from("three") 62 | list.append(one) 63 | list.append(two) 64 | list.append(three) 65 | assert_eq!(list.len(), 3) 66 | inspect!(list, content="[1, 2.0, \'three\']") 67 | inspect!(list.get(0).unwrap(), content="PyInteger(1)") 68 | inspect!(list.get(1).unwrap(), content="PyFloat(2.0)") 69 | inspect!(list.get(2), content="Some(PyString(three))") 70 | inspect!(list.get(3), content="None") 71 | inspect!(list.get(-1), content="None") 72 | inspect!(list[0], content="PyInteger(1)") 73 | inspect!(list[1], content="PyFloat(2.0)") 74 | inspect!(list[2], content="PyString(three)") 75 | let forty_two = PyInteger::from(42) 76 | list.set!(0, forty_two) 77 | inspect!(list, content="[42, 2.0, \'three\']") 78 | list[1] = forty_two 79 | inspect!(list, content="[42, 42, \'three\']") 80 | } 81 | 82 | ///| 83 | test "PyTuple Test" { 84 | let tuple = PyTuple::new(3) 85 | tuple 86 | ..set(0, PyInteger::from(1)) 87 | ..set(1, PyFloat::from(2.0)) 88 | ..set(2, PyString::from("three")) 89 | inspect!(tuple.type_name(), content="tuple") 90 | assert_eq!(tuple.len(), 3) 91 | inspect!(tuple, content="(1, 2.0, \'three\')") 92 | inspect!(tuple.get(0).unwrap(), content="PyInteger(1)") 93 | inspect!(tuple.get(1).unwrap(), content="PyFloat(2.0)") 94 | inspect!(tuple.get(2).unwrap(), content="PyString(three)") 95 | inspect!(tuple.get(3), content="None") 96 | tuple[0] = PyInteger::from(42) 97 | inspect!(tuple, content="(42, 2.0, \'three\')") 98 | } 99 | 100 | ///| 101 | test "PyDict Test" { 102 | let dict = PyDict::new() 103 | dict 104 | ..set("one", PyInteger::from(1)) 105 | ..set("two", PyFloat::from(2.0)) 106 | ..set("three", PyBool::from(true)) 107 | inspect!(dict.type_name(), content="dict") 108 | assert_eq!(dict.len(), 3) 109 | inspect!(dict, content="{\'one\': 1, \'two\': 2.0, \'three\': True}") 110 | inspect!(dict.get("one").unwrap(), content="PyInteger(1)") 111 | inspect!(dict.get("two"), content="Some(PyFloat(2.0))") 112 | inspect!(dict.get("four"), content="None") 113 | inspect!(dict["one"], content="PyInteger(1)") 114 | inspect!(dict["two"], content="PyFloat(2.0)") 115 | inspect!(dict["three"], content="PyBool(True)") 116 | inspect!(dict.keys(), content="[\'one\', \'two\', \'three\']") 117 | inspect!(dict.values(), content="[1, 2.0, True]") 118 | let dict = PyDict::new() 119 | dict 120 | ..setByObj!(PyInteger::from(1), PyInteger::from(1)) 121 | ..setByObj!(PyInteger::from(2), PyInteger::from(4)) 122 | ..setByObj!(PyInteger::from(3), PyInteger::from(9)) 123 | inspect!(dict, content="{1: 1, 2: 4, 3: 9}") 124 | let list = PyList::new() 125 | list..append(PyInteger::from(3))..append(PyInteger::from(2)) 126 | let e = dict.setByObj?(list, PyInteger::from(42)) 127 | inspect!(e, content="Err(KeyIsUnHashableError)") 128 | } 129 | -------------------------------------------------------------------------------- /test/test.mbti: -------------------------------------------------------------------------------- 1 | package "Kaida-Amethyst/python/test" 2 | 3 | // Values 4 | 5 | // Types and methods 6 | 7 | // Type aliases 8 | 9 | // Traits 10 | 11 | -------------------------------------------------------------------------------- /time/lib.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | typealias @python.(PyModule, PyTuple, PyFloat) 3 | 4 | ///| 5 | pub struct TimeModule { 6 | priv time : PyModule 7 | } 8 | 9 | ///| 10 | pub type! TurtleError { 11 | LoadTimeModuleError 12 | } derive(Show) 13 | 14 | ///| 15 | fn new() -> TimeModule!Error { 16 | guard @python.pyimport("time") is Some(time) else { 17 | raise LoadTimeModuleError 18 | } 19 | TimeModule::{ time, } 20 | } 21 | 22 | ///| 23 | let singleton : () -> TimeModule = get_lib() 24 | 25 | ///| 26 | fn get_lib() -> () -> TimeModule { 27 | @python.init_py() 28 | let lib = match new?() { 29 | Ok(lib) => lib 30 | Err(e) => { 31 | println(e) 32 | panic() 33 | } 34 | } 35 | fn() { lib } 36 | } 37 | 38 | ///| 39 | pub fn sleep(seconds : Double) -> Unit { 40 | let lib = singleton() 41 | guard lib.time.get_attr("sleep") is Some(PyCallable(f)) 42 | let args = PyTuple::new(1) 43 | args..set(0, PyFloat::from(seconds)) 44 | let _ = f.invoke?(args~) 45 | () 46 | } 47 | 48 | ///| Returns the time in seconds since the epoch as a floating-point number. 49 | /// Corresponds to `time.time()` in Python. 50 | pub fn time() -> Double { 51 | let lib = singleton() 52 | guard lib.time.get_attr("time") is Some(PyCallable(f)) else { 53 | // Consider how to handle errors, e.g., return a specific error or panic 54 | println("Error: Could not get time.time function") // Placeholder error value 55 | return 0.0 56 | } 57 | guard f.invoke?().unwrap() is Some(PyFloat(t)) else { 58 | println("Error: time.time did not return a float") // Placeholder error value 59 | return 0.0 60 | } 61 | t.to_double() 62 | } 63 | 64 | ///| Returns the time in nanoseconds since the epoch as an integer. 65 | /// Corresponds to `time.time_ns()` in Python. 66 | pub fn time_ns() -> Int64 { 67 | let lib = singleton() 68 | guard lib.time.get_attr("time_ns") is Some(PyCallable(f)) else { 69 | println("Error: Could not get time.time_ns function") // Placeholder error value 70 | return 0L 71 | } 72 | guard f.invoke?().unwrap() is Some(PyInteger(t)) else { 73 | println("Error: time.time_ns did not return an integer") // Placeholder error value 74 | return 0L 75 | } 76 | t.to_int64() 77 | } 78 | 79 | ///| Returns the value (in fractional seconds) of a monotonic clock. 80 | /// Corresponds to `time.monotonic()` in Python. 81 | pub fn monotonic() -> Double { 82 | let lib = singleton() 83 | guard lib.time.get_attr("monotonic") is Some(PyCallable(f)) else { 84 | println("Error: Could not get time.monotonic function") 85 | return 0.0 86 | } 87 | guard f.invoke?().unwrap() is Some(PyFloat(t)) else { 88 | println("Error: time.monotonic did not return a float") 89 | return 0.0 90 | } 91 | t.to_double() 92 | } 93 | 94 | ///| Returns the value (in nanoseconds) of a monotonic clock. 95 | /// Corresponds to `time.monotonic_ns()` in Python. 96 | pub fn monotonic_ns() -> Int64 { 97 | let lib = singleton() 98 | guard lib.time.get_attr("monotonic_ns") is Some(PyCallable(f)) else { 99 | println("Error: Could not get time.monotonic_ns function") 100 | return 0L 101 | } 102 | guard f.invoke?().unwrap() is Some(PyInteger(t)) else { 103 | println("Error: time.monotonic_ns did not return an integer") 104 | return 0L 105 | } 106 | t.to_int64() 107 | } 108 | 109 | ///| Returns the value (in fractional seconds) of a performance counter. 110 | /// Corresponds to `time.perf_counter()` in Python. 111 | pub fn perf_counter() -> Double { 112 | let lib = singleton() 113 | guard lib.time.get_attr("perf_counter") is Some(PyCallable(f)) else { 114 | println("Error: Could not get time.perf_counter function") 115 | return 0.0 116 | } 117 | guard f.invoke?().unwrap() is Some(PyFloat(t)) else { 118 | println("Error: time.perf_counter did not return a float") 119 | return 0.0 120 | } 121 | t.to_double() 122 | } 123 | 124 | ///| Returns the value (in nanoseconds) of a performance counter. 125 | /// Corresponds to `time.perf_counter_ns()` in Python. 126 | pub fn perf_counter_ns() -> Int64 { 127 | let lib = singleton() 128 | guard lib.time.get_attr("perf_counter_ns") is Some(PyCallable(f)) else { 129 | println("Error: Could not get time.perf_counter_ns function") 130 | return 0L 131 | } 132 | guard f.invoke?().unwrap() is Some(PyInteger(t)) else { 133 | println("Error: time.perf_counter_ns did not return an integer") 134 | return 0L 135 | } 136 | t.to_int64() 137 | } 138 | 139 | ///| Returns the value (in fractional seconds) of the sum of the system and user CPU time of the current process. 140 | /// Corresponds to `time.process_time()` in Python. 141 | pub fn process_time() -> Double { 142 | let lib = singleton() 143 | guard lib.time.get_attr("process_time") is Some(PyCallable(f)) else { 144 | println("Error: Could not get time.process_time function") 145 | return 0.0 146 | } 147 | guard f.invoke?().unwrap() is Some(PyFloat(t)) else { 148 | println("Error: time.process_time did not return a float") 149 | return 0.0 150 | } 151 | t.to_double() 152 | } 153 | 154 | ///| Returns the value (in nanoseconds) of the sum of the system and user CPU time of the current process. 155 | /// Corresponds to `time.process_time_ns()` in Python. 156 | pub fn process_time_ns() -> Int64 { 157 | let lib = singleton() 158 | guard lib.time.get_attr("process_time_ns") is Some(PyCallable(f)) else { 159 | println("Error: Could not get time.process_time_ns function") 160 | return 0L 161 | } 162 | guard f.invoke?().unwrap() is Some(PyInteger(t)) else { 163 | println("Error: time.process_time_ns did not return an integer") 164 | return 0L 165 | } 166 | t.to_int64() 167 | } 168 | 169 | ///| Converts a time expressed in seconds since the epoch to a string representing local time. 170 | /// If `secs_option` is `None`, the current time as returned by `time()` is used. 171 | /// Corresponds to `time.ctime([secs])` in Python. 172 | pub fn ctime(secs_option : Double?) -> String { 173 | let lib = singleton() 174 | guard lib.time.get_attr("ctime") is Some(PyCallable(f)) else { 175 | println("Error: Could not get time.ctime function") // Placeholder error value 176 | return "" 177 | } 178 | let result = match secs_option { 179 | Some(secs) => { 180 | let args = PyTuple::new(1) 181 | args..set(0, PyFloat::from(secs)) 182 | f.invoke?(args~).unwrap() 183 | } 184 | None => f.invoke?().unwrap() // Call without arguments 185 | } 186 | guard result is Some(PyString(s)) else { 187 | println("Error: time.ctime did not return a string") // Placeholder error value 188 | return "" 189 | } 190 | s.to_string() 191 | } 192 | -------------------------------------------------------------------------------- /time/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "import": [ 3 | "Kaida-Amethyst/python" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /time/time.mbti: -------------------------------------------------------------------------------- 1 | package "Kaida-Amethyst/python/time" 2 | 3 | // Values 4 | fn ctime(Double?) -> String 5 | 6 | fn monotonic() -> Double 7 | 8 | fn monotonic_ns() -> Int64 9 | 10 | fn perf_counter() -> Double 11 | 12 | fn perf_counter_ns() -> Int64 13 | 14 | fn process_time() -> Double 15 | 16 | fn process_time_ns() -> Int64 17 | 18 | fn sleep(Double) -> Unit 19 | 20 | fn time() -> Double 21 | 22 | fn time_ns() -> Int64 23 | 24 | // Types and methods 25 | pub struct TimeModule { 26 | // private fields 27 | } 28 | 29 | pub type! TurtleError { 30 | LoadTimeModuleError 31 | } 32 | impl Show for TurtleError 33 | 34 | // Type aliases 35 | 36 | // Traits 37 | 38 | -------------------------------------------------------------------------------- /tkinter/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "import": [ 3 | "Kaida-Amethyst/python" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /tkinter/tkinter.mbt: -------------------------------------------------------------------------------- 1 | // Example 2 | //typealias Window = @tkinter.Window 3 | //typealias Label = @tkinter.Label 4 | // 5 | //fn main { 6 | // let window = Window::new() 7 | // window.set_title("Hello, World!") 8 | // 9 | // let label = Label::new(window, "Hello, World!") 10 | // label.pack() 11 | // 12 | // window.mainloop() 13 | //} 14 | 15 | ///| 16 | typealias @python.(PyModule, PyObject, PyTuple, PyDict, PyString) 17 | 18 | ///| 19 | pub type! TkinterError { 20 | LoadTkinterError 21 | } derive(Show) 22 | 23 | ///| 24 | pub struct Tkinter { 25 | priv tkinter : PyModule 26 | } 27 | 28 | ///| 29 | pub struct Window { 30 | priv window : PyObject 31 | } 32 | 33 | ///| 34 | pub struct Label { 35 | priv label : PyObject 36 | } 37 | 38 | ///| 39 | fn new() -> Tkinter!Error { 40 | guard @python.pyimport("tkinter") is Some(tkinter) else { 41 | raise LoadTkinterError 42 | } 43 | Tkinter::{ tkinter, } 44 | } 45 | 46 | ///| 47 | let singleton : () -> Tkinter = get_lib() 48 | 49 | ///| 50 | fn get_lib() -> () -> Tkinter { 51 | @python.init_py() 52 | let lib = match new?() { 53 | Ok(lib) => lib 54 | Err(e) => { 55 | println(e) 56 | panic() 57 | } 58 | } 59 | fn() { lib } 60 | } 61 | 62 | ///| 63 | pub fn Window::new() -> Window { 64 | let lib = singleton() 65 | guard lib.tkinter.get_attr("Tk") is Some(PyCallable(createWindow)) 66 | guard createWindow.invoke?().unwrap() is Some(PyClass(window)) 67 | Window::{ window, } 68 | } 69 | 70 | ///| 71 | pub fn Window::set_title(self : Window, title : String) -> Unit { 72 | guard self.window.get_attr("title") is Some(PyCallable(setTitle)) 73 | let args = PyTuple::new(1) 74 | args..set(0, PyString::from(title)) 75 | let _ = setTitle.invoke?(args~) 76 | 77 | } 78 | 79 | ///| 80 | pub fn Window::mainloop(self : Window) -> Unit { 81 | guard self.window.get_attr("mainloop") is Some(PyCallable(mainloop)) 82 | let _ = mainloop.invoke?() 83 | 84 | } 85 | 86 | ///| 87 | pub fn Label::new(window : Window, text : String) -> Label { 88 | let lib = singleton() 89 | guard lib.tkinter.get_attr("Label") is Some(PyCallable(createLabel)) 90 | let args = PyTuple::new(1) 91 | args..set(0, window.window) 92 | let kwargs = PyDict::new() 93 | kwargs..set("text", PyString::from(text)) 94 | guard createLabel.invoke?(args~, kwargs~).unwrap() is Some(PyClass(label)) 95 | Label::{ label, } 96 | } 97 | 98 | ///| 99 | pub fn Label::pack(self : Label) -> Unit { 100 | guard self.label.get_attr("pack") is Some(PyCallable(pack)) 101 | let _ = pack.invoke?() 102 | 103 | } 104 | -------------------------------------------------------------------------------- /tkinter/tkinter.mbti: -------------------------------------------------------------------------------- 1 | package "Kaida-Amethyst/python/tkinter" 2 | 3 | // Values 4 | 5 | // Types and methods 6 | pub struct Label { 7 | // private fields 8 | } 9 | fn Label::new(Window, String) -> Self 10 | fn Label::pack(Self) -> Unit 11 | 12 | pub struct Tkinter { 13 | // private fields 14 | } 15 | 16 | pub type! TkinterError { 17 | LoadTkinterError 18 | } 19 | impl Show for TkinterError 20 | 21 | pub struct Window { 22 | // private fields 23 | } 24 | fn Window::mainloop(Self) -> Unit 25 | fn Window::new() -> Self 26 | fn Window::set_title(Self, String) -> Unit 27 | 28 | // Type aliases 29 | 30 | // Traits 31 | 32 | -------------------------------------------------------------------------------- /traits.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub trait IsPyObject { 3 | obj(Self) -> PyObject 4 | obj_ref(Self) -> @cpython.PyObjectRef = _ 5 | type_name(Self) -> String = _ 6 | } 7 | 8 | ///| 9 | impl IsPyObject with obj_ref(self) { 10 | self.obj().obj 11 | } 12 | 13 | ///| Return the type name of the object. 14 | /// 15 | /// ## Example 16 | /// 17 | /// ```moonbit 18 | /// test "type_name" { 19 | /// let t = PyBool::from(true); 20 | /// inspect!(t.type_name(), content="bool") 21 | /// 22 | /// let i = PyInteger::from(42); 23 | /// inspect!(i.type_name(), content="int") 24 | /// 25 | /// let f = PyFloat::from(3.14); 26 | /// inspect!(f.type_name(), content="float") 27 | /// 28 | /// let s = PyString::from("hello"); 29 | /// inspect!(s.type_name(), content="str") 30 | /// 31 | /// let tup = PyTuple::new(1) 32 | /// inspect!(tup.type_name(), content="tuple") 33 | /// 34 | /// let lst = PyList::new() 35 | /// inspect!(lst.type_name(), content="list") 36 | /// } 37 | /// ``` 38 | /// 39 | /// The above code is equivalent to: 40 | /// 41 | /// ```python 42 | /// t = True 43 | /// print(type(t)) # Output: 44 | /// 45 | /// i = 42 46 | /// print(type(i)) # Output: 47 | /// 48 | /// f = 3.14 49 | /// print(type(f)) # Output: 50 | /// 51 | /// s = "hello" 52 | /// print(type(s)) # Output: 53 | /// 54 | /// tup = (1,) 55 | /// print(type(tup)) # Output: 56 | /// 57 | /// lst = [] 58 | /// print(type(lst)) # Output: 59 | /// ``` 60 | impl IsPyObject with type_name(self) { 61 | self.obj().type_name() 62 | } 63 | -------------------------------------------------------------------------------- /tuple.mbt: -------------------------------------------------------------------------------- 1 | // ======================================== 2 | // Tuple 3 | // ======================================== 4 | ///| 5 | pub struct PyTuple { 6 | priv obj : PyObject 7 | } 8 | 9 | ///| Create a PyTuple object. 10 | /// 11 | /// **Notes**: Tuple type must know the size of the tuple. 12 | /// 13 | /// ## Example: 14 | /// 15 | /// ```moonbit 16 | /// test "PyTuple::new" { 17 | /// let tuple = PyTuple::new(3) 18 | /// tuple 19 | /// ..set(0, PyInteger::from(1)) 20 | /// ..set(1, PyFloat::from(2.0)) 21 | /// ..set(2, PyString::from("three")); 22 | /// 23 | /// inspect!(tuple, content="(1, 2.0, \'three\')") 24 | /// } 25 | /// ``` 26 | pub fn PyTuple::new(size : UInt64) -> PyTuple { 27 | PyTuple::{ obj: @cpython.pytuple_new(size) |> PyObject::create } 28 | } 29 | 30 | ///| Create a PyTuple object from a python object. 31 | /// If the python object is not a tuple, it will raise a TypeMisMatchError. 32 | pub fn PyTuple::create(obj : PyObject) -> PyTuple!PyRuntimeError { 33 | guard obj.is_tuple() else { raise TypeMisMatchError } 34 | PyTuple::{ obj, } 35 | } 36 | 37 | ///| 38 | fn PyTuple::create_unchecked(obj : PyObject) -> PyTuple { 39 | PyTuple::{ obj, } 40 | } 41 | 42 | ///| Create a PyTuple object from a python object reference. 43 | /// If the python object is not a tuple, it will raise a TypeMisMatchError. 44 | pub fn PyTuple::create_by_ref( 45 | obj_ref : @cpython.PyObjectRef 46 | ) -> PyTuple!PyRuntimeError { 47 | guard @cpython.py_tuple_check(obj_ref) else { raise TypeMisMatchError } 48 | PyTuple::{ obj: PyObject::create(obj_ref) } 49 | } 50 | 51 | ///| 52 | fn PyTuple::create_by_ref_unchecked(obj_ref : @cpython.PyObjectRef) -> PyTuple { 53 | PyTuple::{ obj: PyObject::create(obj_ref) } 54 | } 55 | 56 | ///| Return the size of the tuple. 57 | /// 58 | /// ## Example: 59 | /// 60 | /// ```moonbit 61 | /// test "PyTuple::len" { 62 | /// let tuple = PyTuple::new(3) 63 | /// 64 | /// assert_eq!(tuple.len(), 3); 65 | /// } 66 | /// ``` 67 | pub fn PyTuple::len(self : PyTuple) -> UInt64 { 68 | @cpython.pytuple_size(self.obj_ref()) 69 | } 70 | 71 | ///| Get the item at the given index. 72 | /// 73 | /// **Notes**: Although python supports negative index, in moonbit, we don't have plan to 74 | /// support it. Code like `tuple.get(-1)` will return `None`. 75 | /// 76 | /// ## Example: 77 | /// 78 | /// ```moonbit 79 | /// test "PyTuple::get" { 80 | /// let tuple = PyTuple::new(3) 81 | /// tuple 82 | /// ..set(0, PyInteger::from(1)) 83 | /// ..set(1, PyFloat::from(2.0)) 84 | /// ..set(2, PyString::from("three")); 85 | /// 86 | /// inspect!(tuple, content="(1, 2.0, \'three\')") 87 | /// inspect!(tuple.get(0).unwrap(), content="PyInteger(1)") 88 | /// inspect!(tuple.get(1).unwrap(), content="PyFloat(2.0)") 89 | /// inspect!(tuple.get(2).unwrap(), content="PyString(three)") 90 | /// inspect!(tuple.get(3), content="None") 91 | /// } 92 | /// ``` 93 | /// 94 | /// The above code is equivalent the following python code: 95 | /// 96 | /// ```python 97 | /// tuple = (1, 2.0, "three") 98 | /// 99 | /// print(tuple) # Output: (1, 2.0, 'three') 100 | /// print(tuple[0]) # Output: 1 101 | /// print(tuple[1]) # Output: 2.0 102 | /// print(tuple[2]) # Output: three 103 | pub fn PyTuple::get(self : PyTuple, idx : Int) -> PyObjectEnum? { 104 | @option.when(idx >= 0 && idx.to_uint64() < self.len(), fn() { 105 | @cpython.pytuple_get_item(self.obj_ref(), idx.to_uint64()) 106 | |> PyObject::create 107 | |> PyObjectEnum::create 108 | }) 109 | } 110 | 111 | ///| Get the item at the given index. 112 | /// 113 | /// **Notes**: Although python supports negative index, in moonbit, we don't have plan to 114 | /// support it. Code like `tuple[-1]` will return `None`. 115 | /// 116 | /// ## Example: 117 | /// 118 | /// ```moonbit 119 | /// test "PyTuple::op_get" { 120 | /// let tuple = PyTuple::new(3) 121 | /// tuple 122 | /// ..set(0, PyInteger::from(1)) 123 | /// ..set(1, PyFloat::from(2.0)) 124 | /// ..set(2, PyString::from("three")); 125 | /// 126 | /// inspect!(tuple[0], content="PyInteger(1)") 127 | /// inspect!(tuple[1], content="PyFloat(2.0)") 128 | /// inspect!(tuple[2], content="PyString(three)") 129 | /// } 130 | /// ``` 131 | pub fn PyTuple::op_get(self : PyTuple, idx : Int) -> PyObjectEnum { 132 | self.get(idx).unwrap() 133 | } 134 | 135 | ///| Set the item at the given index. 136 | /// 137 | /// **Notes**: Although python supports negative index, in moonbit, we don't have plan to 138 | /// support it. Code like `tuple.set(-1, item)` will raise `IndexOutOfBoundError`. 139 | /// 140 | /// ## Example: 141 | /// 142 | /// ```moonbit 143 | /// test "PyTuple::set" { 144 | /// let tuple = PyTuple::new(3) 145 | /// tuple 146 | /// ..set(0, PyInteger::from(1)) 147 | /// ..set(1, PyFloat::from(2.0)) 148 | /// ..set(2, PyString::from("three")); 149 | /// 150 | /// inspect!(tuple, content="(10, 2.0, \'three\')") 151 | /// } 152 | pub fn[T : IsPyObject] PyTuple::set( 153 | self : PyTuple, 154 | idx : Int, 155 | item : T 156 | ) -> Unit { 157 | guard idx >= 0 && idx.to_uint64() < self.len() 158 | let _ = @cpython.pytuple_set_item( 159 | self.obj_ref(), 160 | idx.to_uint64(), 161 | item.obj_ref(), 162 | ) 163 | 164 | } 165 | 166 | ///| Set the item at the given index. 167 | /// 168 | /// **Notes**: Although python supports negative index, in moonbit, we don't have plan to 169 | /// support it. Code like `tuple[-1] = item` will raise `IndexOutOfBoundError`. 170 | /// 171 | /// ## Example: 172 | /// 173 | /// ```moonbit 174 | /// test "PyTuple::op_set" { 175 | /// let tuple = PyTuple::new(3) 176 | /// tuple 177 | /// ..set(0, PyInteger::from(1)) 178 | /// ..set(1, PyFloat::from(2.0)) 179 | /// ..set(2, PyString::from("three")); 180 | /// 181 | /// inspect!(tuple, content="(1, 2.0, \'three\')") 182 | /// } 183 | /// ``` 184 | pub fn[T : IsPyObject] PyTuple::op_set( 185 | self : PyTuple, 186 | idx : Int, 187 | item : T 188 | ) -> Unit { 189 | self.set(idx, item) 190 | } 191 | 192 | ///| 193 | pub fn PyTuple::dump(self : PyTuple) -> Unit { 194 | PyObject::dump(self.obj) 195 | } 196 | 197 | ///| 198 | pub fn PyTuple::drop(self : PyTuple) -> Unit { 199 | self.obj.drop() 200 | } 201 | 202 | ///| 203 | pub impl IsPyObject for PyTuple with obj(self) -> PyObject { 204 | self.obj 205 | } 206 | 207 | ///| 208 | pub impl Show for PyTuple with to_string(self) -> String { 209 | self.obj.to_string() 210 | } 211 | 212 | ///| 213 | pub impl Show for PyTuple with output(self : PyTuple, logger : &Logger) -> Unit { 214 | logger.write_string(self.to_string()) 215 | } 216 | -------------------------------------------------------------------------------- /turtle/color.mbt: -------------------------------------------------------------------------------- 1 | ///| Represents common colors used for drawing. 2 | /// Deriving Show provides a default to_string() which can be converted to lowercase for Python. 3 | pub(all) enum Color { 4 | Red 5 | Green 6 | Blue 7 | Purple 8 | Orange 9 | Yellow 10 | Black 11 | Silver 12 | White // Added more colors 13 | Gray 14 | Brown 15 | Cyan 16 | Magenta 17 | Lime 18 | Pink 19 | Teal 20 | Indigo 21 | Violet 22 | } derive(Show) 23 | 24 | ///| Converts the Color enum to a lowercase string representation suitable for Python turtle. 25 | /// - self: The Color enum value. 26 | /// Returns: The color name as a PyString. 27 | pub fn Color::to_pystr(self : Color) -> PyString { 28 | let s = self.to_string().to_lower() 29 | PyString::from(s) 30 | } 31 | -------------------------------------------------------------------------------- /turtle/double_pendulum.mbt.md: -------------------------------------------------------------------------------- 1 | 2 | ```moonbit-no-run 3 | /// 4 | typealias @turtle.(Screen, Pen) 5 | 6 | /// 7 | fnalias @math.(sin, cos) 8 | 9 | /// 10 | const PI : Double = @math.PI 11 | 12 | /// 13 | const G : Double = 600 14 | 15 | /// 16 | const Dt : Double = 1.0 / 60.0 17 | 18 | /// 19 | struct PhysicState { 20 | m1 : Double 21 | m2 : Double 22 | l1 : Double 23 | l2 : Double 24 | pivot_x : Double 25 | pivot_y : Double 26 | } 27 | 28 | // 快速定义类型 29 | /// 30 | type Position (Double, Double, Double, Double) 31 | 32 | /// 33 | type Update (Double, Double, Double, Double) 34 | 35 | /// 36 | fn animate( 37 | phys : PhysicState, 38 | theta1 : Double, 39 | theta2 : Double, 40 | omega1 : Double, 41 | omega2 : Double 42 | ) -> (Position, Update) { 43 | // 优雅的结构体解包 44 | let { m1, m2, l1, l2, pivot_x, pivot_y } = phys 45 | 46 | // --- 计算角加速度 (alpha1, alpha2) --- 47 | // 这些公式是双摆运动方程的标准形式之一 48 | let num1_1 = -G * (2.0 * m1 + m2) * sin(theta1) 49 | let num1_2 = -m2 * G * sin(theta1 - 2.0 * theta2) 50 | let num1_3 = -2.0 * 51 | sin(theta1 - theta2) * 52 | m2 * 53 | (omega2 * omega2 * l2 + omega1 * omega1 * l1 * cos(theta1 - theta2)) 54 | let den1 = l1 * (2.0 * m1 + m2 - m2 * cos(2.0 * theta1 - 2.0 * theta2)) 55 | let alpha1 = match den1.abs() < 1.0e-9 { 56 | true => 0.0 // 避免除以非常小的值,增强稳定性 57 | false => (num1_1 + num1_2 + num1_3) / den1 58 | } 59 | let num2_1 = 2.0 * sin(theta1 - theta2) 60 | let num2_2 = omega1 * omega1 * l1 * (m1 + m2) 61 | let num2_3 = G * (m1 + m2) * cos(theta1) 62 | let num2_4 = omega2 * omega2 * l2 * m2 * cos(theta1 - theta2) 63 | let den2 = l2 * (2.0 * m1 + m2 - m2 * cos(2.0 * theta1 - 2.0 * theta2)) 64 | let alpha2 = match den2.abs() < 1.0e-9 { 65 | true => 0.0 // 避免除以非常小的值,增强稳定性 66 | false => num2_1 * (num2_2 + num2_3 + num2_4) / den2 67 | } 68 | // --- 更新角速度和角度 (欧拉积分) --- 69 | let omega1 = omega1 + alpha1 * Dt 70 | let omega2 = omega2 + alpha2 * Dt 71 | let theta1 = theta1 + omega1 * Dt 72 | let theta2 = theta2 + omega2 * Dt 73 | 74 | // --- 计算节点和球的位置 --- 75 | // 节点1 (连接点) 76 | let x1 = pivot_x + l1 * sin(theta1) 77 | let y1 = pivot_y - l1 * cos(theta1) // Turtle Y轴向上为正,角度0向下 78 | 79 | // 球 (摆锤2) 80 | let x2 = x1 + l2 * sin(theta2) 81 | let y2 = y1 - l2 * cos(theta2) 82 | let position = (x1, y1, x2, y2) 83 | let update = (theta1, theta2, omega1, omega2) 84 | (position, update) 85 | } 86 | 87 | /// 88 | fn run() -> Unit { 89 | let screen = Screen::new() 90 | screen 91 | ..setup(800, 700) 92 | ..bgcolor(Black) 93 | ..title("Double Pendulum Simulation") 94 | ..tracer(0) 95 | let rod = Pen::new() 96 | rod..hide()..speed(Fastest)..pensize(3)..pencolor(Silver) 97 | let masses = Pen::new() 98 | masses..hide()..speed(Fastest) 99 | let (pivot_x, pivot_y) = (0.0, 200.0) 100 | 101 | // --- 长度和质量 102 | let (l1, l2, m1, m2) = (150.0, 120.0, 10.0, 40.0) 103 | 104 | // --- 初始角度和角速度 --- 105 | let (theta1, theta2) = (PI / 1.5, PI / 2) 106 | let (omega1, omega2) = (0.0, 0.0) 107 | 108 | // --- 设置初始物理量 --- 109 | let phys = PhysicState::{ m1, m2, l1, l2, pivot_x, pivot_y } 110 | 111 | // 函数式循环,更清晰 112 | loop theta1, theta2, omega1, omega2, 0.0 { 113 | theta1, theta2, omega1, omega2, total_time if total_time < 3.0 => { 114 | let (positions, updates) = animate(phys, theta1, theta2, omega1, omega2) 115 | let Position((x1, y1, x2, y2)) = positions 116 | let Update((theta1, theta2, omega1, omega2)) = updates 117 | rod.clear() 118 | masses.clear() 119 | 120 | // --- 绘制杆1 --- 121 | rod..penup()..goto(pivot_x, pivot_y)..pendown().goto(x1, y1) 122 | 123 | // --- 绘制杆2 --- 124 | rod..penup()..goto(x1, y1)..pendown().goto(x2, y2) 125 | 126 | // --- 绘制节点 (质量m1) --- 127 | masses..penup()..goto(x1, y1).dot(15, Orange) 128 | 129 | // --- 绘制球 (质量m2) --- 130 | masses..penup()..goto(x2, y2).dot(20, Blue) 131 | 132 | // --- 更新屏幕 --- 133 | screen.update() 134 | @time.sleep(Dt) 135 | continue theta1, theta2, omega1, omega2, total_time + Dt 136 | } 137 | _, _, _, _, _ => break 138 | } 139 | } 140 | 141 | test "Double Pendulum" { 142 | run() 143 | } 144 | ``` 145 | -------------------------------------------------------------------------------- /turtle/lib.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | typealias @python.( 3 | PyModule, 4 | PyObject, 5 | PyTuple, 6 | PyDict, 7 | PyString, 8 | PyInteger, 9 | PyFloat, 10 | PyCallable 11 | ) 12 | 13 | ///| 14 | pub type! TurtleError { 15 | LoadTurtleError 16 | } derive(Show) 17 | 18 | ///| 19 | pub struct Turtle { 20 | priv turtle : PyModule 21 | } 22 | 23 | ///| 24 | fn new() -> Turtle!Error { 25 | guard @python.pyimport("turtle") is Some(turtle) else { 26 | raise LoadTurtleError 27 | } 28 | Turtle::{ turtle, } 29 | } 30 | 31 | ///| 32 | let singleton : () -> Turtle = get_lib() 33 | 34 | ///| 35 | fn get_lib() -> () -> Turtle { 36 | @python.init_py() 37 | let lib = match new?() { 38 | Ok(lib) => lib 39 | Err(e) => { 40 | println(e) 41 | panic() 42 | } 43 | } 44 | fn() { lib } 45 | } 46 | 47 | ///| 48 | pub fn bgcolor(color : Color) -> Unit { 49 | let lib = singleton() 50 | guard lib.turtle.get_attr("bgcolor") is Some(PyCallable(bgcolor)) 51 | let args = PyTuple::new(1) 52 | args..set(0, PyString::from(color.to_string())) 53 | let _ = bgcolor.invoke?(args~) 54 | () 55 | } 56 | -------------------------------------------------------------------------------- /turtle/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "import": [ 3 | "Kaida-Amethyst/python" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /turtle/pen.mbt: -------------------------------------------------------------------------------- 1 | /////| 2 | //pub struct Pen { 3 | // priv pen : PyObject 4 | // methods: Map[String,PyCallable] 5 | //} 6 | // 7 | //fn Pen::get_method(self : Pen, name : String) -> PyCallable? { 8 | // match self.methods.get(name) { 9 | // Some(m) => Some(m) 10 | // None => match self.pen.get_attr(name) { 11 | // Some(PyCallable(m)) => Some(m) 12 | // _ => None 13 | // } 14 | // } 15 | //} 16 | // 17 | /////| 18 | //pub fn Pen::new() -> Pen { 19 | // let lib = singleton() 20 | // guard lib.turtle.get_attr("Pen") is Some(PyCallable(createPen)) 21 | // guard createPen.invoke() is Some(PyClass(pen)) 22 | // Pen::{ pen, methods:Map::new()} 23 | //} 24 | // 25 | /////| 26 | //pub fn Pen::home(self : Pen) -> Unit { 27 | // guard self.get_method("home") is Some(func) 28 | // let _ = func.invoke() 29 | // () 30 | //} 31 | // 32 | /////| 33 | //pub fn Pen::pensize(self : Pen, size : Double) -> Unit { 34 | // guard self.get_method("pensize") is Some(func) 35 | // let args = PyTuple::new(1)..set(0, PyFloat::from(size)) 36 | // let _ = func.invoke(args~) 37 | // 38 | //} 39 | // 40 | /////| 41 | //pub fn Pen::xcor(self : Pen) -> Double { 42 | // guard self.get_method("xcor") is Some(func) 43 | // let res = func.invoke() 44 | // guard res is Some(PyFloat(x)) 45 | // x.to_double() 46 | //} 47 | // 48 | /////| 49 | //pub fn Pen::ycor(self : Pen) -> Double { 50 | // guard self.get_method("ycor") is Some(func) 51 | // let res = func.invoke() 52 | // guard res is Some(PyFloat(y)) 53 | // y.to_double() 54 | //} 55 | // 56 | /////| 57 | //pub fn Pen::position(self : Pen) -> (Double, Double) { 58 | // guard self.get_method("position") is Some(func) 59 | // let res = func.invoke() 60 | // guard res is Some(PyTuple(tup)) 61 | // let x = tup.get(0) 62 | // guard x is Some(PyFloat(x)) 63 | // let y = tup.get(1) 64 | // guard y is Some(PyFloat(y)) 65 | // (x.to_double(), y.to_double()) 66 | //} 67 | // 68 | /////| 69 | //pub fn Pen::heading(self : Pen) -> Double { 70 | // guard self.get_method("heading") is Some(func) 71 | // let res = func.invoke() 72 | // guard res is Some(PyFloat(h)) 73 | // h.to_double() 74 | //} 75 | // 76 | /////| 77 | //pub fn Pen::radians(self : Pen) -> Double { 78 | // guard self.get_method("radians") is Some(func) 79 | // let res = func.invoke() 80 | // guard res is Some(PyFloat(r)) 81 | // r.to_double() 82 | //} 83 | // 84 | /////| 85 | //pub fn Pen::speed(self : Pen, speed : Speed) -> Unit { 86 | // guard self.get_method("speed") is Some(func) 87 | // let args = PyTuple::new(1)..set(0, speed.to_pynum()) 88 | // let _ = func.invoke(args~) 89 | // 90 | //} 91 | // 92 | // 93 | /////| 94 | //pub fn Pen::pencolor(self : Pen, color : Color) -> Unit { 95 | // guard self.get_method("pencolor") is Some(func) 96 | // let args = PyTuple::new(1)..set(0, PyString::from(color.to_string())) 97 | // let _ = func.invoke(args~) 98 | // 99 | //} 100 | // 101 | /////| 102 | //pub fn Pen::width(self : Pen, width : Double) -> Unit { 103 | // guard width > 0 else { 104 | // println("width must be positive") 105 | // return 106 | // } 107 | // guard self.get_method("width") is Some(func) 108 | // let args = PyTuple::new(1)..set(0, PyFloat::from(width)) 109 | // let _ = func.invoke(args~) 110 | // 111 | //} 112 | // 113 | /////| 114 | //pub fn Pen::forward(self : Pen, distance : Double) -> Unit { 115 | // guard distance > 0 else { 116 | // println("distance must be positive") 117 | // return 118 | // } 119 | // guard self.get_method("forward") is Some(func) 120 | // let args = PyTuple::new(1)..set(0, PyFloat::from(distance)) 121 | // let _ = func.invoke(args~) 122 | // 123 | //} 124 | // 125 | /////| 126 | //pub fn Pen::backward(self : Pen, distance : Double) -> Unit { 127 | // guard distance > 0 else { 128 | // println("distance must be positive") 129 | // return 130 | // } 131 | // guard self.pen.get_attr("backward") is Some(PyCallable(func)) 132 | // let args = PyTuple::new(1)..set(0, PyFloat::from(distance)) 133 | // let _ = func.invoke(args~) 134 | // 135 | //} 136 | // 137 | /////| 138 | //pub fn Pen::left(self : Pen, angle : Double) -> Unit { 139 | // guard self.get_method("left") is Some(func) 140 | // let args = PyTuple::new(1)..set(0, PyFloat::from(angle)) 141 | // let _ = func.invoke(args~) 142 | // 143 | //} 144 | // 145 | /////| 146 | //pub fn Pen::right(self : Pen, angle : Double) -> Unit { 147 | // guard self.get_method("right") is Some(func) 148 | // let args = PyTuple::new(1)..set(0, PyFloat::from(angle)) 149 | // let _ = func.invoke(args~) 150 | // 151 | //} 152 | // 153 | //pub fn Pen::goto(self : Pen, x : Double, y : Double) -> Unit { 154 | // guard self.get_method("goto") is Some(func) 155 | // let args = PyTuple::new(2)..set(0, PyFloat::from(x))..set(1, PyFloat::from(y)) 156 | // let _ = func.invoke(args~) 157 | // 158 | //} 159 | // 160 | //pub fn Pen::hide(self : Pen) -> Unit { 161 | // guard self.get_method("hideturtle") is Some(func) 162 | // let _ = func.invoke() 163 | // 164 | //} 165 | // 166 | //pub fn Pen::penup(self : Pen) -> Unit { 167 | // guard self.get_method("penup") is Some(func) 168 | // let _ = func.invoke() 169 | // 170 | //} 171 | // 172 | //pub fn Pen::pendown(self : Pen) -> Unit { 173 | // guard self.get_method("pendown") is Some(func) 174 | // let _ = func.invoke() 175 | // 176 | //} 177 | // 178 | //pub fn Pen::dot(self : Pen, size : Double, color : Color) -> Unit { 179 | // guard self.get_method("dot") is Some(func) 180 | // let args = PyTuple::new(2)..set(0, PyFloat::from(size))..set(1, PyString::from(color.to_string())) 181 | // guard func.invoke(args~) is Some(PyClass(r)) 182 | // r.drop() 183 | // () 184 | //} 185 | // 186 | //pub fn Pen::clear(self : Pen) -> Unit { 187 | // guard self.get_method("clear") is Some(func) 188 | // let _ = func.invoke() 189 | // 190 | //} 191 | -------------------------------------------------------------------------------- /turtle/pen2.mbt: -------------------------------------------------------------------------------- 1 | ///| Represents a turtle pen object, capable of drawing on the screen. 2 | /// corresponds to `turtle.Pen` or the default turtle instance in Python. 3 | pub struct Pen { 4 | priv pen : PyObject 5 | methods : Map[String, PyCallable] // Caches method lookups 6 | } 7 | 8 | ///| Retrieves a callable Python method from the cached methods or the underlying Python object. 9 | /// - name: The name of the method. 10 | /// Returns Some(PyCallable) if the method is found, None otherwise. 11 | fn Pen::get_method(self : Pen, name : String) -> PyCallable? { 12 | match self.methods.get(name) { 13 | Some(m) => Some(m) 14 | None => 15 | match self.pen.get_attr(name) { 16 | Some(PyCallable(m)) => { 17 | self.methods.set(name, m) // Cache the method 18 | Some(m) 19 | } 20 | _ => None 21 | } 22 | } 23 | } 24 | 25 | ///| Creates a new turtle pen instance. 26 | /// In Python, this might correspond to `turtle.Pen()` or obtaining the default instance. 27 | /// This Moonbit function creates a new `turtle.Pen()` instance. 28 | pub fn Pen::new() -> Pen { 29 | let lib = singleton() 30 | guard lib.turtle.get_attr("Pen") is Some(PyCallable(createPen)) 31 | guard createPen.invoke?().unwrap() is Some(PyClass(pen)) 32 | Pen::{ pen, methods: Map::new() } 33 | } 34 | 35 | ///| Moves the pen to the home position (0,0) and sets heading to 0 degrees. 36 | /// corresponds to `pen.home()` in Python. 37 | pub fn Pen::home(self : Pen) -> Unit { 38 | guard self.get_method("home") is Some(func) else { 39 | println("Failed to get Pen::home method") 40 | panic() 41 | } 42 | let _ = func.invoke?() 43 | () 44 | } 45 | 46 | ///| Sets the pen size (thickness). 47 | /// - size: The pen thickness. Must be positive. 48 | /// corresponds to `pen.pensize(size)` in Python. 49 | pub fn Pen::pensize(self : Pen, size : Double) -> Unit { 50 | guard size > 0.0 else { 51 | println("Pensize must be positive") 52 | return 53 | } 54 | guard self.get_method("pensize") is Some(func) else { 55 | println("Failed to get Pen::pensize method") 56 | return 57 | } 58 | let args = PyTuple::new(1) 59 | args..set(0, PyFloat::from(size)) 60 | let _ = func.invoke?(args~) 61 | 62 | } 63 | 64 | ///| Returns the current x-coordinate of the pen. 65 | /// corresponds to `pen.xcor()` in Python. 66 | pub fn Pen::xcor(self : Pen) -> Double { 67 | guard self.get_method("xcor") is Some(func) else { 68 | println("Failed to get Pen::xcor method") // Return a default value 69 | return 0.0 70 | } 71 | let res = func.invoke?().unwrap() 72 | guard res is Some(PyFloat(x)) 73 | x.to_double() 74 | } 75 | 76 | ///| Returns the current y-coordinate of the pen. 77 | /// corresponds to `pen.ycor()` in Python. 78 | pub fn Pen::ycor(self : Pen) -> Double { 79 | guard self.get_method("ycor") is Some(func) else { 80 | println("Failed to get Pen::ycor method") // Return a default value 81 | return 0.0 82 | } 83 | let res = func.invoke?().unwrap() 84 | guard res is Some(PyFloat(y)) 85 | y.to_double() 86 | } 87 | 88 | ///| Returns the current position as a tuple of (x, y) coordinates. 89 | /// corresponds to `pen.position()` or `pen.pos()` in Python. 90 | pub fn Pen::position(self : Pen) -> (Double, Double) { 91 | guard self.get_method("position") is Some(func) else { 92 | println("Failed to get Pen::position method") 93 | return (0.0, 0.0) // Return a default value 94 | } 95 | let res = func.invoke?().unwrap() 96 | guard res is Some(PyTuple(tup)) else { 97 | println("Pen::position did not return a tuple") 98 | return (0.0, 0.0) // Return a default value 99 | } 100 | guard tup.len() == 2 else { 101 | println("Pen::position returned a tuple of incorrect length") 102 | return (0.0, 0.0) // Return a default value 103 | } 104 | let x = tup.get(0) 105 | guard x is Some(PyFloat(x_py)) else { 106 | println("Pen::position tuple element 0 is not a float") 107 | return (0.0, 0.0) // Return a default value 108 | } 109 | let y = tup.get(1) 110 | guard y is Some(PyFloat(y_py)) else { 111 | println("Pen::position tuple element 1 is not a float") 112 | return (0.0, 0.0) // Return a default value 113 | } 114 | (x_py.to_double(), y_py.to_double()) 115 | } 116 | 117 | ///| Returns the current heading of the pen in degrees. 118 | /// corresponds to `pen.heading()` in Python. 119 | pub fn Pen::heading(self : Pen) -> Double { 120 | guard self.get_method("heading") is Some(func) else { 121 | println("Failed to get Pen::heading method") // Return a default value 122 | return 0.0 123 | } 124 | let res = func.invoke?().unwrap() 125 | guard res is Some(PyFloat(h)) else { 126 | println("Pen::heading did not return a float") // Return a default value 127 | return 0.0 128 | } 129 | h.to_double() 130 | } 131 | 132 | ///| Returns the current unit for angles set by the `degrees()` or `radians()` methods. 133 | /// Note: This method name might be slightly misleading in Python's turtle documentation. 134 | /// corresponds to `pen.radians()` in Python (when radians are used). 135 | /// If using degrees, you might check `turtle.degrees()` which is usually global. 136 | /// This encapsulation assumes it checks the current angle unit setting. 137 | pub fn Pen::radians(self : Pen) -> Double { 138 | guard self.get_method("radians") is Some(func) else { 139 | println("Failed to get Pen::radians method") // Return a default value 140 | return 0.0 141 | } 142 | let res = func.invoke?().unwrap() 143 | guard res is Some(PyFloat(r)) else { 144 | println("Pen::radians did not return a float") // Return a default value 145 | return 0.0 146 | } 147 | r.to_double() 148 | } 149 | 150 | ///| Sets the pen speed. 151 | /// - speed: An enum representing the desired drawing speed. 152 | /// corresponds to `pen.speed(speed)` in Python, where speed is an integer. 153 | pub fn Pen::speed(self : Pen, speed : Speed) -> Unit { 154 | guard self.get_method("speed") is Some(func) else { 155 | println("Failed to get Pen::speed method") 156 | return 157 | } 158 | let args = PyTuple::new(1) 159 | args..set(0, speed.to_pynum()) // speed.to_pynum() converts enum to PyInteger 160 | let _ = func.invoke?(args~) 161 | 162 | } 163 | 164 | ///| Sets the pen color. 165 | /// - color: The pen color. 166 | /// corresponds to `pen.pencolor(color)` in Python. 167 | pub fn Pen::pencolor(self : Pen, color : Color) -> Unit { 168 | guard self.get_method("pencolor") is Some(func) else { 169 | println("Failed to get Pen::pencolor method") 170 | return 171 | } 172 | let args = PyTuple::new(1) 173 | args..set(0, PyString::from(color.to_string().to_lower())) // Ensure lowercase 174 | let _ = func.invoke?(args~) 175 | 176 | } 177 | 178 | ///| Sets the pen width. 179 | /// - width: The pen width. Must be positive. 180 | /// corresponds to `pen.width(width)` in Python. 181 | pub fn Pen::width(self : Pen, width : Double) -> Unit { 182 | guard width > 0.0 else { 183 | println("Width must be positive") 184 | return 185 | } 186 | guard self.get_method("width") is Some(func) else { 187 | println("Failed to get Pen::width method") 188 | return 189 | } 190 | let args = PyTuple::new(1) 191 | args..set(0, PyFloat::from(width)) 192 | let _ = func.invoke?(args~) 193 | 194 | } 195 | 196 | ///| Moves the pen forward by the specified distance. 197 | /// - distance: The distance to move forward. Must be positive. 198 | /// corresponds to `pen.forward(distance)` or `pen.fd(distance)` in Python. 199 | pub fn Pen::forward(self : Pen, distance : Double) -> Unit { 200 | guard distance > 0.0 else { 201 | println("Distance must be positive") 202 | return 203 | } 204 | guard self.get_method("forward") is Some(func) else { 205 | println("Failed to get Pen::forward method") 206 | return 207 | } 208 | let args = PyTuple::new(1) 209 | args..set(0, PyFloat::from(distance)) 210 | let _ = func.invoke?(args~) 211 | 212 | } 213 | 214 | ///| Moves the pen backward by the specified distance. 215 | /// - distance: The distance to move backward. Must be positive. 216 | /// corresponds to `pen.backward(distance)` or `pen.bk(distance)` or `pen.ba(distance)` in Python. 217 | pub fn Pen::backward(self : Pen, distance : Double) -> Unit { 218 | guard distance > 0.0 else { 219 | println("Distance must be positive") 220 | return 221 | } 222 | // Corrected from self.pen.get_attr to self.get_method for caching 223 | guard self.get_method("backward") is Some(func) else { 224 | println("Failed to get Pen::backward method") 225 | return 226 | } 227 | let args = PyTuple::new(1) 228 | args..set(0, PyFloat::from(distance)) 229 | let _ = func.invoke?(args~) 230 | 231 | } 232 | 233 | ///| Turns the pen left by the specified angle. 234 | /// - angle: The angle in degrees to turn left. 235 | /// corresponds to `pen.left(angle)` or `pen.lt(angle)` in Python. 236 | pub fn Pen::left(self : Pen, angle : Double) -> Unit { 237 | guard self.get_method("left") is Some(func) else { 238 | println("Failed to get Pen::left method") 239 | return 240 | } 241 | let args = PyTuple::new(1) 242 | args..set(0, PyFloat::from(angle)) 243 | let _ = func.invoke?(args~) 244 | 245 | } 246 | 247 | ///| Turns the pen right by the specified angle. 248 | /// - angle: The angle in degrees to turn right. 249 | /// corresponds to `pen.right(angle)` or `pen.rt(angle)` in Python. 250 | pub fn Pen::right(self : Pen, angle : Double) -> Unit { 251 | guard self.get_method("right") is Some(func) else { 252 | println("Failed to get Pen::right method") 253 | return 254 | } 255 | let args = PyTuple::new(1) 256 | args..set(0, PyFloat::from(angle)) 257 | let _ = func.invoke?(args~) 258 | 259 | } 260 | 261 | ///| Moves the pen to an absolute position (x, y). 262 | /// - x: The target x-coordinate. 263 | /// - y: The target y-coordinate. 264 | /// corresponds to `pen.goto(x, y)` or `pen.setpos(x, y)` or `pen.setposition(x, y)` in Python. 265 | pub fn Pen::goto(self : Pen, x : Double, y : Double) -> Unit { 266 | guard self.get_method("goto") is Some(func) else { 267 | println("Failed to get Pen::goto method") 268 | return 269 | } 270 | let args = PyTuple::new(2) 271 | args..set(0, PyFloat::from(x))..set(1, PyFloat::from(y)) 272 | let _ = func.invoke?(args~) 273 | 274 | } 275 | 276 | ///| Makes the turtle invisible. 277 | /// corresponds to `pen.hideturtle()` or `pen.ht()` in Python. 278 | pub fn Pen::hide(self : Pen) -> Unit { 279 | guard self.get_method("hideturtle") is Some(func) else { 280 | println("Failed to get Pen::hideturtle method") 281 | return 282 | } 283 | let _ = func.invoke?() 284 | 285 | } 286 | 287 | ///| Lifts the pen up. No drawing will occur when the pen moves. 288 | /// corresponds to `pen.penup()` or `pen.pu()` or `pen.up()` in Python. 289 | pub fn Pen::penup(self : Pen) -> Unit { 290 | guard self.get_method("penup") is Some(func) else { 291 | println("Failed to get Pen::penup method") 292 | return 293 | } 294 | let _ = func.invoke?() 295 | 296 | } 297 | 298 | ///| Puts the pen down. Drawing will occur when the pen moves. 299 | /// corresponds to `pen.pendown()` or `pen.pd()` or `pen.down()` in Python. 300 | pub fn Pen::pendown(self : Pen) -> Unit { 301 | guard self.get_method("pendown") is Some(func) else { 302 | println("Failed to get Pen::pendown method") 303 | return 304 | } 305 | let _ = func.invoke?() 306 | 307 | } 308 | 309 | ///| Draws a dot at the current position. 310 | /// - size: The diameter of the dot. Must be positive. 311 | /// - color: The color of the dot. 312 | /// corresponds to `pen.dot(size, color)` in Python. 313 | pub fn Pen::dot(self : Pen, size : Double, color : Color) -> Unit { 314 | guard size > 0.0 else { 315 | println("Dot size must be positive") 316 | return 317 | } 318 | guard self.get_method("dot") is Some(func) else { 319 | println("Failed to get Pen::dot method") 320 | return 321 | } 322 | let args = PyTuple::new(2) 323 | args 324 | ..set(0, PyFloat::from(size)) 325 | ..set(1, PyString::from(color.to_string().to_lower())) // Ensure lowercase 326 | // The return value of dot is the turtle object itself, which we ignore and drop. 327 | // The original code had a 'guard func.invoke(args~) is Some(PyClass(r)) r.drop()', which is correct for ignoring the return value. 328 | let _ = func.invoke?(args~) 329 | // Simpler way to ignore return value 330 | } 331 | 332 | ///| Deletes the pen's drawings from the screen, but does not move the pen. 333 | /// corresponds to `pen.clear()` in Python. 334 | pub fn Pen::clear(self : Pen) -> Unit { 335 | guard self.get_method("clear") is Some(func) else { 336 | println("Failed to get Pen::clear method") 337 | return 338 | } 339 | let _ = func.invoke?() 340 | 341 | } 342 | 343 | // Add more Pen methods 344 | 345 | ///| Sets the fill color. 346 | /// - color: The color used for filling. 347 | /// corresponds to `pen.fillcolor(color)` in Python. 348 | pub fn Pen::fillcolor(self : Pen, color : Color) -> Unit { 349 | guard self.get_method("fillcolor") is Some(func) else { 350 | println("Failed to get Pen::fillcolor method") 351 | return 352 | } 353 | let args = PyTuple::new(1) 354 | args..set(0, PyString::from(color.to_string().to_lower())) 355 | let _ = func.invoke?(args~) 356 | 357 | } 358 | 359 | ///| Sets the pen color and fill color. 360 | /// - color: The color used for pen and fill. 361 | /// corresponds to `pen.color(color)` in Python. Can also take two colors, but we simplify here. 362 | pub fn Pen::color(self : Pen, color : Color) -> Unit { 363 | guard self.get_method("color") is Some(func) else { 364 | println("Failed to get Pen::color method") 365 | return 366 | } 367 | let args = PyTuple::new(1) 368 | args..set(0, PyString::from(color.to_string().to_lower())) 369 | let _ = func.invoke?(args~) 370 | 371 | } 372 | 373 | ///| Returns True if the pen is down, False otherwise. 374 | /// corresponds to `pen.isdown()` in Python. 375 | pub fn Pen::isdown(self : Pen) -> Bool { 376 | guard self.get_method("isdown") is Some(func) else { 377 | println("Failed to get Pen::isdown method") // Return a default value 378 | return false 379 | } 380 | let res = func.invoke?().unwrap() 381 | guard res is Some(PyBool(b)) 382 | b.to_bool() 383 | } 384 | 385 | ///| Makes the turtle visible. 386 | /// corresponds to `pen.showturtle()` or `pen.st()` in Python. 387 | pub fn Pen::show(self : Pen) -> Unit { 388 | guard self.get_method("showturtle") is Some(func) else { 389 | println("Failed to get Pen::showturtle method") 390 | return 391 | } 392 | let _ = func.invoke?() 393 | 394 | } 395 | 396 | ///| Returns True if the turtle is visible, False otherwise. 397 | /// corresponds to `pen.isvisible()` in Python. 398 | pub fn Pen::isvisible(self : Pen) -> Bool { 399 | guard self.get_method("isvisible") is Some(func) else { 400 | println("Failed to get Pen::isvisible method") // Return a default value 401 | return false 402 | } 403 | let res = func.invoke?().unwrap() 404 | guard res is Some(PyBool(b)) 405 | b.to_bool() 406 | } 407 | 408 | ///| Starts color filling. 409 | /// corresponds to `pen.begin_fill()` in Python. 410 | pub fn Pen::begin_fill(self : Pen) -> Unit { 411 | guard self.get_method("begin_fill") is Some(func) else { 412 | println("Failed to get Pen::begin_fill method") 413 | return 414 | } 415 | let _ = func.invoke?() 416 | 417 | } 418 | 419 | ///| Stops color filling and fills the area bounded by the last begin_fill() and this call. 420 | /// corresponds to `pen.end_fill()` in Python. 421 | pub fn Pen::end_fill(self : Pen) -> Unit { 422 | guard self.get_method("end_fill") is Some(func) else { 423 | println("Failed to get Pen::end_fill method") 424 | return 425 | } 426 | let _ = func.invoke?() 427 | 428 | } 429 | 430 | ///| Draws a circle. 431 | /// - radius: The radius of the circle. A positive radius means counterclockwise, negative means clockwise. 432 | /// - extent: Optional. An angle in degrees. If given, only part of the circle is drawn. 433 | /// - steps: Optional. An integer. The number of steps to use for approximating the circle. 434 | /// corresponds to `pen.circle(radius, extent=None, steps=None)` in Python. 435 | pub fn Pen::circle( 436 | self : Pen, 437 | radius : Double, 438 | extent~ : Double? = None, 439 | steps~ : Int? = None 440 | ) -> Unit { 441 | guard self.get_method("circle") is Some(func) else { 442 | println("Failed to get Pen::circle method") 443 | return 444 | } 445 | let args = PyTuple::new(1) 446 | args..set(0, PyFloat::from(radius)) 447 | let kwargs = PyDict::new() 448 | match extent { 449 | Some(e) => kwargs.set("extent", PyFloat::from(e)) 450 | None => () 451 | } 452 | match steps { 453 | Some(s) => kwargs.set("steps", PyInteger::from(s.to_int64())) 454 | None => () 455 | } 456 | let _ = func.invoke?(args~, kwargs~) 457 | 458 | } 459 | 460 | ///| Leaves a copy of the turtle shape at the current location. 461 | /// Returns a stamp_id which can be used later with clearstamp() or clearstamps(). 462 | /// corresponds to `pen.stamp()` in Python. 463 | /// Note: The return value (stamp_id) is an integer in Python, we return it as Int. 464 | pub fn Pen::stamp(self : Pen) -> Int { 465 | guard self.get_method("stamp") is Some(func) else { 466 | println("Failed to get Pen::stamp method") // Return a default error value 467 | return -1 468 | } 469 | let res = func.invoke?().unwrap() 470 | guard res is Some(PyInteger(i)) else { 471 | println("Pen::stamp did not return an integer") // Return a default error value 472 | return -1 473 | } 474 | i.to_int64().to_int() // Convert to Int 475 | } 476 | 477 | ///| Deletes the stamp with the given stampid. 478 | /// - stamp_id: The id of the stamp to delete, as returned by stamp(). 479 | /// corresponds to `pen.clearstamp(stampid)` in Python. 480 | pub fn Pen::clearstamp(self : Pen, stamp_id : Int) -> Unit { 481 | guard self.get_method("clearstamp") is Some(func) else { 482 | println("Failed to get Pen::clearstamp method") 483 | return 484 | } 485 | let args = PyTuple::new(1) 486 | args..set(0, PyInteger::from(stamp_id.to_int64())) 487 | let _ = func.invoke?(args~).unwrap() 488 | 489 | } 490 | 491 | ///| Deletes all or the first/last n stamps. 492 | /// - n: Optional. If None, delete all stamps. If n > 0, delete the first n stamps. If n < 0, delete the last abs(n) stamps. 493 | /// corresponds to `pen.clearstamps(n=None)` in Python. 494 | pub fn Pen::clearstamps(self : Pen, n~ : Int? = None) -> Unit { 495 | guard self.get_method("clearstamps") is Some(func) else { 496 | println("Failed to get Pen::clearstamps method") 497 | return 498 | } 499 | let kwargs = PyDict::new() 500 | match n { 501 | Some(num) => kwargs.set("n", PyInteger::from(num.to_int64())) 502 | None => () // If n is None, we don't add it to kwargs, defaulting to None in Python 503 | } 504 | 505 | // Although Python's clearstamps takes n as positional or keyword, 506 | // passing it as keyword is safer with Option handling. 507 | // We invoke with an empty args tuple and the kwargs dictionary. 508 | let _ = func.invoke?(kwargs~).unwrap() 509 | 510 | } 511 | 512 | ///| Resets the pen's and screen's state. Deletes drawings, recenters pen, resets variables. 513 | /// corresponds to `pen.reset()` in Python. 514 | pub fn Pen::reset(self : Pen) -> Unit { 515 | guard self.get_method("reset") is Some(func) else { 516 | println("Failed to get Pen::reset method") 517 | return 518 | } 519 | let _ = func.invoke?() 520 | 521 | } 522 | 523 | ///| Sets the turtle shape. 524 | /// - name: The name of the shape. Use the Shape enum for common shapes. 525 | /// corresponds to `pen.shape(name)` in Python. 526 | pub fn Pen::shape(self : Pen, name : Shape) -> Unit { 527 | guard self.get_method("shape") is Some(func) else { 528 | println("Failed to get Pen::shape method") 529 | return 530 | } 531 | let args = PyTuple::new(1) 532 | args..set(0, PyString::from(name.to_string().to_lower())) // Assuming Shape enum with Show derived 533 | let _ = func.invoke?(args~) 534 | 535 | } 536 | 537 | ///| Sets the shape's stretches and outline. 538 | /// - stretch_width: Stretchfactor for width, perpendicular to orientation. 539 | /// - stretch_len: Stretchfactor for length, in direction of orientation. 540 | /// - outline: Optional outline thickness. 541 | /// corresponds to `pen.shapesize(stretch_wid=None, stretch_len=None, outline=None)` in Python. 542 | pub fn Pen::shapesize( 543 | self : Pen, 544 | stretch_width~ : Double? = None, 545 | stretch_len~ : Double? = None, 546 | outline~ : Int? = None 547 | ) -> Unit { 548 | guard self.get_method("shapesize") is Some(func) else { 549 | println("Failed to get Pen::shapesize method") 550 | return 551 | } 552 | let kwargs = PyDict::new() 553 | match stretch_width { 554 | Some(w) => kwargs.set("stretch_wid", PyFloat::from(w)) 555 | None => () 556 | } 557 | match stretch_len { 558 | Some(l) => kwargs.set("stretch_len", PyFloat::from(l)) 559 | None => () 560 | } 561 | match outline { 562 | Some(o) => kwargs.set("outline", PyInteger::from(o.to_int64())) 563 | None => () 564 | } 565 | let _ = func.invoke?(kwargs~) 566 | 567 | } 568 | -------------------------------------------------------------------------------- /turtle/screen.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub struct Screen { 3 | priv screen : PyObject 4 | } 5 | 6 | ///| 7 | pub fn Screen::new() -> Screen { 8 | let lib = singleton() 9 | guard lib.turtle.get_attr("Screen") is Some(PyCallable(createScreen)) 10 | guard createScreen.invoke?().unwrap() is Some(PyClass(screen)) 11 | Screen::{ screen, } 12 | } 13 | 14 | ///| 15 | pub fn Screen::setup(self : Screen, width : Double, height : Double) -> Unit { 16 | guard self.screen.get_attr("setup") is Some(PyCallable(setup)) 17 | let args = PyTuple::new(2) 18 | args..set(0, PyFloat::from(width))..set(1, PyFloat::from(height)) 19 | let _ = setup.invoke?(args~) 20 | 21 | } 22 | 23 | ///| 24 | pub fn Screen::title(self : Screen, text : String) -> Unit { 25 | guard self.screen.get_attr("title") is Some(PyCallable(title)) 26 | let args = PyTuple::new(1) 27 | args..set(0, PyString::from(text)) 28 | let _ = title.invoke?(args~) 29 | 30 | } 31 | 32 | ///| 33 | pub fn Screen::tracer(self : Screen, n : Int) -> Unit { 34 | guard self.screen.get_attr("tracer") is Some(PyCallable(tracer)) 35 | let args = PyTuple::new(1) 36 | args..set(0, PyInteger::from(n.to_int64())) 37 | let _ = tracer.invoke?(args~) 38 | 39 | } 40 | 41 | ///| 42 | pub fn Screen::update(self : Screen) -> Unit { 43 | guard self.screen.get_attr("update") is Some(PyCallable(update)) 44 | let _ = update.invoke?() 45 | 46 | } 47 | 48 | ///| 49 | pub fn Screen::bgcolor(self : Screen, color : Color) -> Unit { 50 | guard self.screen.get_attr("bgcolor") is Some(PyCallable(bgcolor)) 51 | let args = PyTuple::new(1) 52 | args..set(0, PyString::from(color.to_string())) 53 | let _ = bgcolor.invoke?(args~) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /turtle/shape.mbt: -------------------------------------------------------------------------------- 1 | ///| Represents common shapes for the turtle cursor. 2 | /// Deriving Show provides a default to_string() which can be converted to lowercase for Python. 3 | pub(all) enum Shape { 4 | Arrow 5 | Turtle 6 | Circle 7 | Square 8 | Triangle 9 | Classic 10 | } derive(Show) 11 | -------------------------------------------------------------------------------- /turtle/speed.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub(all) enum Speed { 3 | Fastest 4 | Fast 5 | Normal 6 | Slow 7 | Slowest 8 | } 9 | 10 | ///| 11 | fn Speed::to_pynum(self : Speed) -> PyInteger { 12 | let i = match self { 13 | Speed::Fastest => 0L 14 | Speed::Fast => 10 15 | Speed::Normal => 6 16 | Speed::Slow => 3 17 | Speed::Slowest => 1 18 | } 19 | PyInteger::from(i) 20 | } 21 | -------------------------------------------------------------------------------- /turtle/turtle.mbti: -------------------------------------------------------------------------------- 1 | package "Kaida-Amethyst/python/turtle" 2 | 3 | import( 4 | "Kaida-Amethyst/python" 5 | ) 6 | 7 | // Values 8 | fn bgcolor(Color) -> Unit 9 | 10 | // Types and methods 11 | pub(all) enum Color { 12 | Red 13 | Green 14 | Blue 15 | Purple 16 | Orange 17 | Yellow 18 | Black 19 | Silver 20 | White 21 | Gray 22 | Brown 23 | Cyan 24 | Magenta 25 | Lime 26 | Pink 27 | Teal 28 | Indigo 29 | Violet 30 | } 31 | fn Color::to_pystr(Self) -> @python.PyString 32 | impl Show for Color 33 | 34 | pub struct Pen { 35 | methods : Map[String, @python.PyCallable] 36 | // private fields 37 | } 38 | fn Pen::backward(Self, Double) -> Unit 39 | fn Pen::begin_fill(Self) -> Unit 40 | fn Pen::circle(Self, Double, extent~ : Double? = .., steps~ : Int? = ..) -> Unit 41 | fn Pen::clear(Self) -> Unit 42 | fn Pen::clearstamp(Self, Int) -> Unit 43 | fn Pen::clearstamps(Self, n~ : Int? = ..) -> Unit 44 | fn Pen::color(Self, Color) -> Unit 45 | fn Pen::dot(Self, Double, Color) -> Unit 46 | fn Pen::end_fill(Self) -> Unit 47 | fn Pen::fillcolor(Self, Color) -> Unit 48 | fn Pen::forward(Self, Double) -> Unit 49 | fn Pen::goto(Self, Double, Double) -> Unit 50 | fn Pen::heading(Self) -> Double 51 | fn Pen::hide(Self) -> Unit 52 | fn Pen::home(Self) -> Unit 53 | fn Pen::isdown(Self) -> Bool 54 | fn Pen::isvisible(Self) -> Bool 55 | fn Pen::left(Self, Double) -> Unit 56 | fn Pen::new() -> Self 57 | fn Pen::pencolor(Self, Color) -> Unit 58 | fn Pen::pendown(Self) -> Unit 59 | fn Pen::pensize(Self, Double) -> Unit 60 | fn Pen::penup(Self) -> Unit 61 | fn Pen::position(Self) -> (Double, Double) 62 | fn Pen::radians(Self) -> Double 63 | fn Pen::reset(Self) -> Unit 64 | fn Pen::right(Self, Double) -> Unit 65 | fn Pen::shape(Self, Shape) -> Unit 66 | fn Pen::shapesize(Self, stretch_width~ : Double? = .., stretch_len~ : Double? = .., outline~ : Int? = ..) -> Unit 67 | fn Pen::show(Self) -> Unit 68 | fn Pen::speed(Self, Speed) -> Unit 69 | fn Pen::stamp(Self) -> Int 70 | fn Pen::width(Self, Double) -> Unit 71 | fn Pen::xcor(Self) -> Double 72 | fn Pen::ycor(Self) -> Double 73 | 74 | pub struct Screen { 75 | // private fields 76 | } 77 | fn Screen::bgcolor(Self, Color) -> Unit 78 | fn Screen::new() -> Self 79 | fn Screen::setup(Self, Double, Double) -> Unit 80 | fn Screen::title(Self, String) -> Unit 81 | fn Screen::tracer(Self, Int) -> Unit 82 | fn Screen::update(Self) -> Unit 83 | 84 | pub(all) enum Shape { 85 | Arrow 86 | Turtle 87 | Circle 88 | Square 89 | Triangle 90 | Classic 91 | } 92 | impl Show for Shape 93 | 94 | pub(all) enum Speed { 95 | Fastest 96 | Fast 97 | Normal 98 | Slow 99 | Slowest 100 | } 101 | 102 | pub struct Turtle { 103 | // private fields 104 | } 105 | 106 | pub type! TurtleError { 107 | LoadTurtleError 108 | } 109 | impl Show for TurtleError 110 | 111 | // Type aliases 112 | 113 | // Traits 114 | 115 | -------------------------------------------------------------------------------- /utils.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub fn init_py() -> Unit { 3 | if not(@cpython.py_is_initialized()) { 4 | @cpython.py_init() 5 | if not(@cpython.py_is_initialized()) { 6 | println("Python initialization failed") 7 | return 8 | } 9 | } 10 | } 11 | 12 | ///| 13 | fn init { 14 | init_py() 15 | } 16 | 17 | ///| elimnate the quotes from a string 18 | /// 19 | /// ## Example 20 | /// 21 | /// ```moonbit 22 | /// let s = "\'os\'" 23 | /// inspect!(@python.strip_quot(s), content="os") 24 | /// ``` 25 | pub fn strip_quot(s : String) -> String { 26 | if s.has_prefix("\'") && s.has_suffix("\'") { 27 | return s.view(start_offset=1, end_offset=s.length() - 1).to_string() 28 | } 29 | s 30 | } 31 | --------------------------------------------------------------------------------