pythoc 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pythoc-0.2.0/LICENSE +21 -0
- pythoc-0.2.0/MANIFEST.in +11 -0
- pythoc-0.2.0/PKG-INFO +517 -0
- pythoc-0.2.0/README.md +484 -0
- pythoc-0.2.0/pyproject.toml +56 -0
- pythoc-0.2.0/pythoc/__init__.py +128 -0
- pythoc-0.2.0/pythoc/ast_visitor/__init__.py +20 -0
- pythoc-0.2.0/pythoc/ast_visitor/assignments.py +912 -0
- pythoc-0.2.0/pythoc/ast_visitor/base.py +814 -0
- pythoc-0.2.0/pythoc/ast_visitor/calls.py +387 -0
- pythoc-0.2.0/pythoc/ast_visitor/expressions.py +744 -0
- pythoc-0.2.0/pythoc/ast_visitor/functions.py +228 -0
- pythoc-0.2.0/pythoc/ast_visitor/helpers.py +225 -0
- pythoc-0.2.0/pythoc/ast_visitor/inline_visitor.py +375 -0
- pythoc-0.2.0/pythoc/ast_visitor/statements.py +18 -0
- pythoc-0.2.0/pythoc/ast_visitor/stmt_control.py +86 -0
- pythoc-0.2.0/pythoc/ast_visitor/stmt_if.py +195 -0
- pythoc-0.2.0/pythoc/ast_visitor/stmt_loops.py +474 -0
- pythoc-0.2.0/pythoc/ast_visitor/stmt_match.py +726 -0
- pythoc-0.2.0/pythoc/ast_visitor/subscripts.py +310 -0
- pythoc-0.2.0/pythoc/ast_visitor/varargs.py +292 -0
- pythoc-0.2.0/pythoc/ast_visitor/visitor_impl.py +37 -0
- pythoc-0.2.0/pythoc/ast_visitor/yield_inline.py +447 -0
- pythoc-0.2.0/pythoc/ast_visitor/yield_transform.py +89 -0
- pythoc-0.2.0/pythoc/build/__init__.py +9 -0
- pythoc-0.2.0/pythoc/build/cache.py +58 -0
- pythoc-0.2.0/pythoc/build/output_manager.py +137 -0
- pythoc-0.2.0/pythoc/builtin_entities/__init__.py +175 -0
- pythoc-0.2.0/pythoc/builtin_entities/array.py +305 -0
- pythoc-0.2.0/pythoc/builtin_entities/base.py +511 -0
- pythoc-0.2.0/pythoc/builtin_entities/composite_base.py +361 -0
- pythoc-0.2.0/pythoc/builtin_entities/enum.py +627 -0
- pythoc-0.2.0/pythoc/builtin_entities/func.py +255 -0
- pythoc-0.2.0/pythoc/builtin_entities/intrinsics.py +656 -0
- pythoc-0.2.0/pythoc/builtin_entities/linear.py +65 -0
- pythoc-0.2.0/pythoc/builtin_entities/python_type.py +563 -0
- pythoc-0.2.0/pythoc/builtin_entities/qualifiers.py +188 -0
- pythoc-0.2.0/pythoc/builtin_entities/refined.py +337 -0
- pythoc-0.2.0/pythoc/builtin_entities/struct.py +666 -0
- pythoc-0.2.0/pythoc/builtin_entities/type_subscript_parser.py +121 -0
- pythoc-0.2.0/pythoc/builtin_entities/types.py +665 -0
- pythoc-0.2.0/pythoc/builtin_entities/union.py +306 -0
- pythoc-0.2.0/pythoc/builtin_entities/utility.py +246 -0
- pythoc-0.2.0/pythoc/compiler.py +799 -0
- pythoc-0.2.0/pythoc/context.py +95 -0
- pythoc-0.2.0/pythoc/decorators/__init__.py +59 -0
- pythoc-0.2.0/pythoc/decorators/annotation_resolver.py +143 -0
- pythoc-0.2.0/pythoc/decorators/compile.py +565 -0
- pythoc-0.2.0/pythoc/decorators/extern.py +224 -0
- pythoc-0.2.0/pythoc/decorators/inline.py +168 -0
- pythoc-0.2.0/pythoc/decorators/jit.py +11 -0
- pythoc-0.2.0/pythoc/decorators/mangling.py +17 -0
- pythoc-0.2.0/pythoc/decorators/structs.py +339 -0
- pythoc-0.2.0/pythoc/decorators/visible.py +304 -0
- pythoc-0.2.0/pythoc/forward_ref.py +136 -0
- pythoc-0.2.0/pythoc/inline/__init__.py +29 -0
- pythoc-0.2.0/pythoc/inline/closure_adapter.py +199 -0
- pythoc-0.2.0/pythoc/inline/exit_rules.py +265 -0
- pythoc-0.2.0/pythoc/inline/inline_adapter.py +209 -0
- pythoc-0.2.0/pythoc/inline/kernel.py +409 -0
- pythoc-0.2.0/pythoc/inline/scope_analyzer.py +229 -0
- pythoc-0.2.0/pythoc/inline/transformers.py +248 -0
- pythoc-0.2.0/pythoc/inline/yield_adapter.py +206 -0
- pythoc-0.2.0/pythoc/ir_helpers.py +253 -0
- pythoc-0.2.0/pythoc/libc/__init__.py +34 -0
- pythoc-0.2.0/pythoc/libc/ctype.py +51 -0
- pythoc-0.2.0/pythoc/libc/math.py +130 -0
- pythoc-0.2.0/pythoc/libc/memory.py +29 -0
- pythoc-0.2.0/pythoc/libc/stdio.py +159 -0
- pythoc-0.2.0/pythoc/libc/stdlib.py +112 -0
- pythoc-0.2.0/pythoc/libc/string.py +108 -0
- pythoc-0.2.0/pythoc/llvm_extensions.py +145 -0
- pythoc-0.2.0/pythoc/logger.py +191 -0
- pythoc-0.2.0/pythoc/meta.py +273 -0
- pythoc-0.2.0/pythoc/native_executor.py +525 -0
- pythoc-0.2.0/pythoc/registry.py +1027 -0
- pythoc-0.2.0/pythoc/std/float_types.py +95 -0
- pythoc-0.2.0/pythoc/std/poly.py +296 -0
- pythoc-0.2.0/pythoc/std/seq.py +49 -0
- pythoc-0.2.0/pythoc/std/utility.py +23 -0
- pythoc-0.2.0/pythoc/std/vector.py +125 -0
- pythoc-0.2.0/pythoc/type_converter.py +786 -0
- pythoc-0.2.0/pythoc/type_id.py +41 -0
- pythoc-0.2.0/pythoc/type_resolver.py +493 -0
- pythoc-0.2.0/pythoc/utils/__init__.py +43 -0
- pythoc-0.2.0/pythoc/utils/ast_debug.py +336 -0
- pythoc-0.2.0/pythoc/utils/build_utils.py +200 -0
- pythoc-0.2.0/pythoc/utils/frame_utils.py +69 -0
- pythoc-0.2.0/pythoc/utils/id_generator.py +69 -0
- pythoc-0.2.0/pythoc/utils/inspect_utils.py +42 -0
- pythoc-0.2.0/pythoc/utils/link_utils.py +144 -0
- pythoc-0.2.0/pythoc/utils/naming.py +68 -0
- pythoc-0.2.0/pythoc/utils/path_utils.py +82 -0
- pythoc-0.2.0/pythoc/utils/test_utils.py +166 -0
- pythoc-0.2.0/pythoc/valueref.py +415 -0
- pythoc-0.2.0/pythoc.egg-info/PKG-INFO +517 -0
- pythoc-0.2.0/pythoc.egg-info/SOURCES.txt +101 -0
- pythoc-0.2.0/pythoc.egg-info/dependency_links.txt +1 -0
- pythoc-0.2.0/pythoc.egg-info/not-zip-safe +1 -0
- pythoc-0.2.0/pythoc.egg-info/requires.txt +5 -0
- pythoc-0.2.0/pythoc.egg-info/top_level.txt +1 -0
- pythoc-0.2.0/setup.cfg +4 -0
- pythoc-0.2.0/setup.py +66 -0
pythoc-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) PythoC Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pythoc-0.2.0/MANIFEST.in
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
include LICENSE
|
|
3
|
+
recursive-include pythoc *.py
|
|
4
|
+
recursive-exclude test *
|
|
5
|
+
recursive-exclude docs *
|
|
6
|
+
recursive-exclude backup *
|
|
7
|
+
recursive-exclude build *
|
|
8
|
+
exclude .gitignore
|
|
9
|
+
global-exclude __pycache__
|
|
10
|
+
global-exclude *.py[co]
|
|
11
|
+
global-exclude .DS_Store
|
pythoc-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pythoc
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: PythoC: A Python DSL compiler that maps statically-typed Python subset to LLVM IR, providing C-equivalent capabilities with Python syntax
|
|
5
|
+
Home-page: https://github.com/1flei/PythoC
|
|
6
|
+
Author: PythoC Compiler Team
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/1flei/PythoC
|
|
9
|
+
Project-URL: Repository, https://github.com/1flei/PythoC
|
|
10
|
+
Project-URL: Documentation, https://github.com/1flei/PythoC/blob/master/README.md
|
|
11
|
+
Keywords: compiler,llvm,python,static-typing,code-generation
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
22
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: llvmlite>=0.40.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
Dynamic: requires-python
|
|
33
|
+
|
|
34
|
+
# PythoC: Write C in Python
|
|
35
|
+
|
|
36
|
+
PythoC is a Python DSL compiler that compiles statically-typed Python to LLVM IR, providing C-equivalent runtime capabilities with Python syntax and compile-time metaprogramming.
|
|
37
|
+
|
|
38
|
+
## Design Philosophy
|
|
39
|
+
|
|
40
|
+
**Core principle**: C-level runtime + Python-powered compile-time
|
|
41
|
+
|
|
42
|
+
1. **C-compatible runtime**: Compiled code maps directly to native machine code with C-level control and performance
|
|
43
|
+
- Full access to low-level operations (pointers, manual memory, inline assembly)
|
|
44
|
+
- C calling conventions for seamless interoperability
|
|
45
|
+
- No runtime overhead beyond what C would have
|
|
46
|
+
2. **Compile-time = Python**: Full Python power for metaprogramming, generics, and code generation
|
|
47
|
+
3. **Zero-cost abstractions**: Python-level abstractions compile away completely
|
|
48
|
+
4. **Explicit typing**: All types must be annotated (like C, unlike Python)
|
|
49
|
+
5. **Explicit control flow**: No implicit control flow (no exceptions, no RAII, no destructors)
|
|
50
|
+
- Structs are plain data (no methods, no constructors)
|
|
51
|
+
- Manual resource management like C
|
|
52
|
+
6. **Optional safety features**: Linear types and refinement types provide memory safety guarantees without introducing hidden control flow
|
|
53
|
+
- Prevent memory leaks, use-after-free, null pointer dereference, array out-of-bounds
|
|
54
|
+
- Completely optional - use only when needed
|
|
55
|
+
- No extra runtime overhead
|
|
56
|
+
7. **Convenient Python-C interoperability**:
|
|
57
|
+
- Python can call PythoC compiled functions at runtime (via ctypes/cffi)
|
|
58
|
+
- PythoC can invoke Python code at compile-time for metaprogramming
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
### Installation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install pythoc
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Hello World
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from pythoc import compile, i32
|
|
72
|
+
|
|
73
|
+
@compile
|
|
74
|
+
def add(x: i32, y: i32) -> i32:
|
|
75
|
+
return x + y
|
|
76
|
+
|
|
77
|
+
# Can compile to native code
|
|
78
|
+
@compile
|
|
79
|
+
def main() -> i32:
|
|
80
|
+
return add(10, 20)
|
|
81
|
+
|
|
82
|
+
# Or call the compiled dynamic library from Python directly
|
|
83
|
+
result = main()
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Run Tests
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Run all tests
|
|
90
|
+
python test/run_all_tests.py
|
|
91
|
+
|
|
92
|
+
# Run specific test suites
|
|
93
|
+
python test/run_integration_tests.py
|
|
94
|
+
python test/run_examples.py
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Example: Binary Tree Benchmark
|
|
98
|
+
|
|
99
|
+
This example demonstrates PythoC's direct mapping to C - compare with `test/example/base_binary_tree_test.c`:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from __future__ import annotations
|
|
103
|
+
from pythoc import i32, ptr, compile, nullptr, seq, sizeof
|
|
104
|
+
from pythoc.libc.stdlib import malloc, free
|
|
105
|
+
from pythoc.libc.stdio import printf
|
|
106
|
+
|
|
107
|
+
# C: typedef struct tn { struct tn* left; struct tn* right; } treeNode;
|
|
108
|
+
@compile
|
|
109
|
+
class TreeNode:
|
|
110
|
+
left: ptr[TreeNode]
|
|
111
|
+
right: ptr[TreeNode]
|
|
112
|
+
|
|
113
|
+
# C: treeNode* NewTreeNode(treeNode* left, treeNode* right)
|
|
114
|
+
@compile
|
|
115
|
+
def NewTreeNode(left: ptr[TreeNode], right: ptr[TreeNode]) -> ptr[TreeNode]:
|
|
116
|
+
new: ptr[TreeNode] = ptr[TreeNode](malloc(sizeof(TreeNode)))
|
|
117
|
+
new.left = left
|
|
118
|
+
new.right = right
|
|
119
|
+
return new
|
|
120
|
+
|
|
121
|
+
# C: long ItemCheck(treeNode* tree)
|
|
122
|
+
@compile
|
|
123
|
+
def ItemCheck(tree: ptr[TreeNode]) -> i32:
|
|
124
|
+
if tree.left == nullptr:
|
|
125
|
+
return 1
|
|
126
|
+
else:
|
|
127
|
+
return 1 + ItemCheck(tree.left) + ItemCheck(tree.right)
|
|
128
|
+
|
|
129
|
+
# C: treeNode* BottomUpTree(unsigned depth)
|
|
130
|
+
@compile
|
|
131
|
+
def BottomUpTree(depth: i32) -> ptr[TreeNode]:
|
|
132
|
+
if depth > 0:
|
|
133
|
+
return NewTreeNode(BottomUpTree(depth - 1), BottomUpTree(depth - 1))
|
|
134
|
+
else:
|
|
135
|
+
return NewTreeNode(nullptr, nullptr)
|
|
136
|
+
|
|
137
|
+
# C: void DeleteTree(treeNode* tree)
|
|
138
|
+
@compile
|
|
139
|
+
def DeleteTree(tree: ptr[TreeNode]):
|
|
140
|
+
if tree.left != nullptr:
|
|
141
|
+
DeleteTree(tree.left)
|
|
142
|
+
DeleteTree(tree.right)
|
|
143
|
+
free(tree)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## C Parity: Full C Capabilities
|
|
147
|
+
|
|
148
|
+
### Supported Features
|
|
149
|
+
|
|
150
|
+
PythoC provides complete C runtime capabilities:
|
|
151
|
+
|
|
152
|
+
**Primitive types**:
|
|
153
|
+
- Integers: `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`
|
|
154
|
+
- Floats: `f16`, `f32`, `f64`, `bf16`, `f128`
|
|
155
|
+
- Boolean: `bool`
|
|
156
|
+
|
|
157
|
+
**Composite types**:
|
|
158
|
+
- Pointers: `ptr[T]`
|
|
159
|
+
- Arrays: `array[T, N]` or `array[T, N, M, ...]` for multi-dimensional
|
|
160
|
+
- Structs: `@compile class`, `@struct class`, `struct[x: i32, y: i32]` (named) or `struct[i32, i32]` (unnamed)
|
|
161
|
+
- Unions: `@union class` or `union[T1, T2, ...]`
|
|
162
|
+
- Enums: `@enum class`
|
|
163
|
+
- Function pointers: `func[[arg_types], return_type]`
|
|
164
|
+
|
|
165
|
+
**Control flow**:
|
|
166
|
+
- `if`/`else`, `while`, `for` loops
|
|
167
|
+
- `break`, `continue`, `return`
|
|
168
|
+
- Pattern matching: `match`/`case` (enhanced switch)
|
|
169
|
+
|
|
170
|
+
**Operations**:
|
|
171
|
+
- Arithmetic: `+`, `-`, `*`, `/`, `%`, `//`
|
|
172
|
+
- Comparison: `==`, `!=`, `<`, `>`, `<=`, `>=`
|
|
173
|
+
- Logical: `and`, `or`, `not`
|
|
174
|
+
- Bitwise: `&`, `|`, `^`, `~`, `<<`, `>>`
|
|
175
|
+
- Pointer arithmetic and dereferencing
|
|
176
|
+
|
|
177
|
+
**C Standard Library**:
|
|
178
|
+
```python
|
|
179
|
+
from pythoc.libc.stdio import printf, scanf
|
|
180
|
+
from pythoc.libc.stdlib import malloc, free, atoi
|
|
181
|
+
from pythoc.libc.string import memcpy, strlen
|
|
182
|
+
from pythoc.libc.math import sin, cos, pow
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Not Yet Supported
|
|
186
|
+
|
|
187
|
+
Features deliberately excluded or pending:
|
|
188
|
+
|
|
189
|
+
- **`goto`**: Use structured control flow instead
|
|
190
|
+
- **Fall-through `switch`**: Use `match`/`case` with explicit branches
|
|
191
|
+
- **Global variable initialization**: Workaround with init functions
|
|
192
|
+
- **Variable-length arrays (VLA)**: Use fixed-size arrays or malloc
|
|
193
|
+
- **Flexible array members**: Use separate size tracking
|
|
194
|
+
|
|
195
|
+
## PythoC Language Core
|
|
196
|
+
|
|
197
|
+
Beyond C parity, PythoC adds modern type system features (all optional, minimal support):
|
|
198
|
+
|
|
199
|
+
### Algebraic Data Types (ADT) and Pattern Matching
|
|
200
|
+
|
|
201
|
+
Provide Rust-like enums with payload for type-safe tagged unions:
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from pythoc import enum, compile, i32
|
|
205
|
+
|
|
206
|
+
@enum
|
|
207
|
+
class Result:
|
|
208
|
+
Ok: i32
|
|
209
|
+
Err: i32
|
|
210
|
+
|
|
211
|
+
@compile
|
|
212
|
+
def handle_result(r: Result) -> i32:
|
|
213
|
+
match r:
|
|
214
|
+
case (Result.Ok, value):
|
|
215
|
+
return value
|
|
216
|
+
case (Result.Err, code):
|
|
217
|
+
return -code
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Linear Types (Optional)
|
|
221
|
+
|
|
222
|
+
Prevent use-after-free and resource leaks without RAII or destructors:
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
from pythoc import compile, linear, consume, void, ptr, i8, i32, struct
|
|
226
|
+
from pythoc.libc.stdlib import malloc, free
|
|
227
|
+
|
|
228
|
+
# Allocator returns resource + linear proof
|
|
229
|
+
@compile
|
|
230
|
+
def lmalloc(size: i32) -> struct[ptr[i8], linear]:
|
|
231
|
+
return malloc(size), linear()
|
|
232
|
+
|
|
233
|
+
# Only the paired deallocator can consume the proof
|
|
234
|
+
@compile
|
|
235
|
+
def lfree(ptr: ptr[i8], prf: linear) -> void:
|
|
236
|
+
free(ptr)
|
|
237
|
+
consume(prf) # Proof consumed - resource released
|
|
238
|
+
|
|
239
|
+
@compile
|
|
240
|
+
def safe_usage() -> void:
|
|
241
|
+
mem, prf = lmalloc(100)
|
|
242
|
+
# ... use mem ...
|
|
243
|
+
lfree(mem, prf) # Must call lfree to consume prf
|
|
244
|
+
# Compile error if prf not consumed!
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Motivation**: Proof-carrying code pattern. The linear proof proves resource was allocated and must be deallocated. Compiler enforces pairing of alloc/free at compile-time.
|
|
248
|
+
|
|
249
|
+
### Refinement Types (Optional)
|
|
250
|
+
|
|
251
|
+
Check once, use safely everywhere without runtime overhead:
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
from pythoc import compile, i32, bool, refined, refine, array, ptr, nullptr
|
|
255
|
+
|
|
256
|
+
# Non-null pointer - check once, use safely everywhere
|
|
257
|
+
@compile
|
|
258
|
+
def is_nonnull(p: ptr[i32]) -> bool:
|
|
259
|
+
return p != nullptr
|
|
260
|
+
|
|
261
|
+
NonNull = refined[is_nonnull]
|
|
262
|
+
|
|
263
|
+
@compile
|
|
264
|
+
def process_data(p: ptr[i32]) -> i32:
|
|
265
|
+
for ptr_checked in refine(p, is_nonnull):
|
|
266
|
+
# Type system knows ptr_checked is non-null
|
|
267
|
+
return access_ptr(ptr_checked)
|
|
268
|
+
else:
|
|
269
|
+
return -1 # Handle null case
|
|
270
|
+
|
|
271
|
+
@compile
|
|
272
|
+
def access_ptr(p: refined[is_nonnull]) -> i32:
|
|
273
|
+
return p[0]
|
|
274
|
+
|
|
275
|
+
# Array bounds - check once, access many arrays safely
|
|
276
|
+
@compile
|
|
277
|
+
def is_valid_index(idx: i32) -> bool:
|
|
278
|
+
return 0 <= idx < 10
|
|
279
|
+
|
|
280
|
+
@compile
|
|
281
|
+
def process_arrays(i: i32, arr1: array[i32, 10], arr2: array[i32, 10]) -> i32:
|
|
282
|
+
for idx in refine(i, is_valid_index):
|
|
283
|
+
# Type system remembers idx is valid
|
|
284
|
+
a = arr1[idx[0]] # Safe: no bounds check
|
|
285
|
+
b = arr2[idx[0]] # Safe: no bounds check
|
|
286
|
+
c = arr1[idx[0]] # Safe: reuse safely
|
|
287
|
+
return a + b + c
|
|
288
|
+
else:
|
|
289
|
+
return -1
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Motivation**: Check once, encode in type system, use safely everywhere. Typical examples: non-null pointers, valid array indices, non-zero divisors. The type system remembers the property, eliminating redundant runtime checks. Zero overhead for subsequent uses.
|
|
293
|
+
|
|
294
|
+
## Python as Preprocessor
|
|
295
|
+
|
|
296
|
+
Use Python's full power at compile-time for metaprogramming:
|
|
297
|
+
|
|
298
|
+
### Compile-Time Constants: Zero-Size Fields
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
from pythoc import compile, i32, pyconst, struct, typeof, ptr
|
|
302
|
+
|
|
303
|
+
def Vec(T, size_type):
|
|
304
|
+
return struct['size': size_type, 'data': ptr[T]]
|
|
305
|
+
|
|
306
|
+
def make_vec(T, size):
|
|
307
|
+
ret: Vec(T, typeof(size))
|
|
308
|
+
ret.size = size
|
|
309
|
+
ret.data = malloc(size * sizeof(T))
|
|
310
|
+
return ret
|
|
311
|
+
|
|
312
|
+
@compile
|
|
313
|
+
def test()-> i32:
|
|
314
|
+
static_vec = make_vec(i32, 100) # sizeof(static_vec) == sizeof(ptr[T])
|
|
315
|
+
len: i32 = 100
|
|
316
|
+
dynamic_vec = make_vec(i32, len) # sizeof(dynamic_vec) == sizeof(struct[i32, ptr[T])
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Use case**: One generic definition, two instantiations with different memory layouts - static saves 4 bytes per instance.
|
|
320
|
+
|
|
321
|
+
### Generic Types via Python Functions
|
|
322
|
+
|
|
323
|
+
```python
|
|
324
|
+
from pythoc import compile, struct, i32, f64
|
|
325
|
+
|
|
326
|
+
# Python function generates specialized types and functions
|
|
327
|
+
def make_point(T):
|
|
328
|
+
@struct(suffix=T) # suffix creates unique type name
|
|
329
|
+
class Point:
|
|
330
|
+
x: T
|
|
331
|
+
y: T
|
|
332
|
+
|
|
333
|
+
@compile(suffix=T) # suffix creates unique function name
|
|
334
|
+
def add_points(p1: Point, p2: Point) -> Point:
|
|
335
|
+
result: Point = Point()
|
|
336
|
+
result.x = p1.x + p2.x
|
|
337
|
+
result.y = p1.y + p2.y
|
|
338
|
+
return result
|
|
339
|
+
|
|
340
|
+
return Point, add_points
|
|
341
|
+
|
|
342
|
+
# Generate specialized versions at compile-time
|
|
343
|
+
Point_i32, add_i32 = make_point(i32)
|
|
344
|
+
Point_f64, add_f64 = make_point(f64)
|
|
345
|
+
|
|
346
|
+
@compile
|
|
347
|
+
def test() -> i32:
|
|
348
|
+
p1: Point_i32 = Point_i32()
|
|
349
|
+
p1.x = 10
|
|
350
|
+
p2: Point_i32 = Point_i32()
|
|
351
|
+
p2.x = 20
|
|
352
|
+
result: Point_i32 = add_i32(p1, p2)
|
|
353
|
+
return result.x
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Code Generation at Compile-Time
|
|
357
|
+
|
|
358
|
+
```python
|
|
359
|
+
# Python computes values and generates code before compilation
|
|
360
|
+
UNROLL_COUNT = 4
|
|
361
|
+
|
|
362
|
+
def make_unrolled_sum(n):
|
|
363
|
+
@compile
|
|
364
|
+
def sum_unrolled(arr: array[i32, n]) -> i32:
|
|
365
|
+
result: i32 = 0
|
|
366
|
+
# Python loop runs at compile-time, generates n add operations
|
|
367
|
+
for i in range(n):
|
|
368
|
+
result = result + arr[i]
|
|
369
|
+
return result
|
|
370
|
+
return sum_unrolled
|
|
371
|
+
|
|
372
|
+
# Generate specialized unrolled versions
|
|
373
|
+
sum_4 = make_unrolled_sum(4)
|
|
374
|
+
sum_8 = make_unrolled_sum(8)
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
## Library: Polymorphism
|
|
379
|
+
|
|
380
|
+
PythoC provides compile-time and runtime polymorphism through the `Poly` library:
|
|
381
|
+
|
|
382
|
+
```python
|
|
383
|
+
from pythoc import compile, i32, f64, ptr, i8
|
|
384
|
+
from pythoc.std.poly import Poly
|
|
385
|
+
|
|
386
|
+
# Define specialized implementations (must have same return type)
|
|
387
|
+
@compile
|
|
388
|
+
def add_i32(a: i32, b: i32) -> i32:
|
|
389
|
+
return a + b
|
|
390
|
+
|
|
391
|
+
@compile
|
|
392
|
+
def add_f64(a: f64, b: f64) -> i32:
|
|
393
|
+
return i32(a + b) # Convert to i32 for uniform return type
|
|
394
|
+
|
|
395
|
+
@compile
|
|
396
|
+
def add_mixed(a: i32, b: f64) -> i32:
|
|
397
|
+
return i32(f64(a) + b)
|
|
398
|
+
|
|
399
|
+
# Create polymorphic function - dispatches based on argument types
|
|
400
|
+
add = Poly(add_i32, add_f64, add_mixed)
|
|
401
|
+
|
|
402
|
+
# Static dispatch - type known at compile-time (zero overhead)
|
|
403
|
+
@compile
|
|
404
|
+
def test_static():
|
|
405
|
+
x = add(10, 20) # Calls add_i32
|
|
406
|
+
y = add(1.5, 2.5) # Calls add_f64
|
|
407
|
+
z = add(10, 2.5) # Calls add_mixed
|
|
408
|
+
|
|
409
|
+
# Extensible - add implementations dynamically
|
|
410
|
+
@compile
|
|
411
|
+
def add_str(a: ptr[i8], b: ptr[i8]) -> i32:
|
|
412
|
+
return 42
|
|
413
|
+
|
|
414
|
+
add.append(add_str)
|
|
415
|
+
|
|
416
|
+
# Runtime dispatch via enum boxing
|
|
417
|
+
@enum(i32)
|
|
418
|
+
class Number:
|
|
419
|
+
Int: i32
|
|
420
|
+
Float: f64
|
|
421
|
+
|
|
422
|
+
@compile
|
|
423
|
+
def test_runtime():
|
|
424
|
+
a: Number = Number(Number.Int, 42)
|
|
425
|
+
b: Number = Number(Number.Float, 3.14)
|
|
426
|
+
add(a, b) # Dispatches based on runtime enum tags
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Key features**:
|
|
430
|
+
- All implementations must have the same return type
|
|
431
|
+
- Compile-time dispatch when argument types are statically known
|
|
432
|
+
- Runtime dispatch via enum boxing for dynamic polymorphism
|
|
433
|
+
- Extensible - add new implementations via `append()`
|
|
434
|
+
|
|
435
|
+
## AST Transformations Features: Inline, Yield, Closures
|
|
436
|
+
|
|
437
|
+
These features share the same underlying implementation: AST-level code transformation and inlining.
|
|
438
|
+
|
|
439
|
+
### Inline Functions
|
|
440
|
+
|
|
441
|
+
Zero-overhead abstraction - function body is expanded at call site:
|
|
442
|
+
|
|
443
|
+
```python
|
|
444
|
+
from pythoc import compile, inline, i32
|
|
445
|
+
|
|
446
|
+
@inline
|
|
447
|
+
def clamp(value: i32, min_val: i32, max_val: i32) -> i32:
|
|
448
|
+
if value < min_val:
|
|
449
|
+
return min_val
|
|
450
|
+
elif value > max_val:
|
|
451
|
+
return max_val
|
|
452
|
+
return value
|
|
453
|
+
|
|
454
|
+
@compile
|
|
455
|
+
def process(x: i32) -> i32:
|
|
456
|
+
# clamp body is inlined here - no function call
|
|
457
|
+
result: i32 = clamp(x, 0, 100)
|
|
458
|
+
return result
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Closures
|
|
462
|
+
|
|
463
|
+
Nested functions with variable capture - inlined automatically:
|
|
464
|
+
|
|
465
|
+
```python
|
|
466
|
+
from pythoc import compile, i32
|
|
467
|
+
|
|
468
|
+
@compile
|
|
469
|
+
def make_adder(base: i32) -> i32:
|
|
470
|
+
offset: i32 = 10
|
|
471
|
+
|
|
472
|
+
# Closure captures base and offset
|
|
473
|
+
def add_both(x: i32) -> i32:
|
|
474
|
+
return x + base + offset
|
|
475
|
+
|
|
476
|
+
return add_both(5) # Closure body inlined at call site
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
**Note**: Current implementation has limitations - closures cannot be called inside loops or nested (requires architecture redesign).
|
|
480
|
+
|
|
481
|
+
### Yield-based Iterators
|
|
482
|
+
|
|
483
|
+
Generator functions using `yield` - inlined automatically at call sites:
|
|
484
|
+
|
|
485
|
+
```python
|
|
486
|
+
from pythoc import compile, i32
|
|
487
|
+
|
|
488
|
+
@compile
|
|
489
|
+
def fibonacci(limit: i32) -> i32:
|
|
490
|
+
"""Generator yielding Fibonacci numbers < limit"""
|
|
491
|
+
a: i32 = 0
|
|
492
|
+
b: i32 = 1
|
|
493
|
+
while a < limit:
|
|
494
|
+
yield a
|
|
495
|
+
new_a: i32 = b
|
|
496
|
+
new_b: i32 = a + b
|
|
497
|
+
a = new_a
|
|
498
|
+
b = new_b
|
|
499
|
+
|
|
500
|
+
@compile
|
|
501
|
+
def sum_fibonacci(n: i32) -> i32:
|
|
502
|
+
total: i32 = 0
|
|
503
|
+
for num in fibonacci(n): # fibonacci body inlined here
|
|
504
|
+
total = total + num
|
|
505
|
+
return total
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
**Common kernel**: All three features use the same AST transformation and inlining kernel, maintaining C-level performance with high-level abstractions.
|
|
509
|
+
|
|
510
|
+
## More Examples
|
|
511
|
+
More examples can be found in the `test/` directory.
|
|
512
|
+
- Full examples: `test/example/`
|
|
513
|
+
- PythoC Integration tests: `test/integration/`
|
|
514
|
+
|
|
515
|
+
## License
|
|
516
|
+
|
|
517
|
+
MIT License - see LICENSE file for details
|