spork-lang 0.1.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.
- spork_lang-0.1.0/LICENSE +21 -0
- spork_lang-0.1.0/MANIFEST.in +13 -0
- spork_lang-0.1.0/PKG-INFO +408 -0
- spork_lang-0.1.0/README.md +370 -0
- spork_lang-0.1.0/pyproject.toml +85 -0
- spork_lang-0.1.0/setup.cfg +4 -0
- spork_lang-0.1.0/setup.py +15 -0
- spork_lang-0.1.0/spork/__init__.py +305 -0
- spork_lang-0.1.0/spork/__main__.py +7 -0
- spork_lang-0.1.0/spork/cli.py +740 -0
- spork_lang-0.1.0/spork/compiler/__init__.py +86 -0
- spork_lang-0.1.0/spork/compiler/codegen.py +7717 -0
- spork_lang-0.1.0/spork/compiler/loader.py +302 -0
- spork_lang-0.1.0/spork/compiler/macros.py +726 -0
- spork_lang-0.1.0/spork/compiler/reader.py +549 -0
- spork_lang-0.1.0/spork/lsp/__init__.py +17 -0
- spork_lang-0.1.0/spork/lsp/protocol.py +671 -0
- spork_lang-0.1.0/spork/lsp/server.py +942 -0
- spork_lang-0.1.0/spork/project/__init__.py +101 -0
- spork_lang-0.1.0/spork/project/build.py +397 -0
- spork_lang-0.1.0/spork/project/config.py +309 -0
- spork_lang-0.1.0/spork/project/dist.py +351 -0
- spork_lang-0.1.0/spork/project/manager.py +499 -0
- spork_lang-0.1.0/spork/project/scaffold.py +369 -0
- spork_lang-0.1.0/spork/repl/__init__.py +48 -0
- spork_lang-0.1.0/spork/repl/backend.py +1639 -0
- spork_lang-0.1.0/spork/repl/nrepl.py +599 -0
- spork_lang-0.1.0/spork/runtime/__init__.py +384 -0
- spork_lang-0.1.0/spork/runtime/core.py +1531 -0
- spork_lang-0.1.0/spork/runtime/json.py +341 -0
- spork_lang-0.1.0/spork/runtime/ns.py +562 -0
- spork_lang-0.1.0/spork/runtime/pds.c +7841 -0
- spork_lang-0.1.0/spork/runtime/pds.pyi +212 -0
- spork_lang-0.1.0/spork/runtime/types.py +357 -0
- spork_lang-0.1.0/spork/runtime/utils.py +553 -0
- spork_lang-0.1.0/spork/std/__init__.py +21 -0
- spork_lang-0.1.0/spork/std/json.spork +77 -0
- spork_lang-0.1.0/spork/std/map.spork +161 -0
- spork_lang-0.1.0/spork/std/prelude.spork +301 -0
- spork_lang-0.1.0/spork/std/string.spork +120 -0
- spork_lang-0.1.0/spork_lang.egg-info/PKG-INFO +408 -0
- spork_lang-0.1.0/spork_lang.egg-info/SOURCES.txt +97 -0
- spork_lang-0.1.0/spork_lang.egg-info/dependency_links.txt +1 -0
- spork_lang-0.1.0/spork_lang.egg-info/entry_points.txt +2 -0
- spork_lang-0.1.0/spork_lang.egg-info/requires.txt +8 -0
- spork_lang-0.1.0/spork_lang.egg-info/top_level.txt +1 -0
- spork_lang-0.1.0/tests/bench_data_structures.spork +451 -0
- spork_lang-0.1.0/tests/test_async.spork +109 -0
- spork_lang-0.1.0/tests/test_async_advanced.spork +174 -0
- spork_lang-0.1.0/tests/test_block_with_result.spork +172 -0
- spork_lang-0.1.0/tests/test_comprehensive.spork +41 -0
- spork_lang-0.1.0/tests/test_decorators.spork +95 -0
- spork_lang-0.1.0/tests/test_defclass.spork +183 -0
- spork_lang-0.1.0/tests/test_destructuring.spork +181 -0
- spork_lang-0.1.0/tests/test_exceptions.spork +280 -0
- spork_lang-0.1.0/tests/test_expression_everywhere.spork +208 -0
- spork_lang-0.1.0/tests/test_fmt.spork +174 -0
- spork_lang-0.1.0/tests/test_generator_error.spork +84 -0
- spork_lang-0.1.0/tests/test_gensym.spork +217 -0
- spork_lang-0.1.0/tests/test_import_macros.spork +161 -0
- spork_lang-0.1.0/tests/test_keyword_args.spork +168 -0
- spork_lang-0.1.0/tests/test_lazy_minimal.spork +31 -0
- spork_lang-0.1.0/tests/test_lazy_seqs.spork +356 -0
- spork_lang-0.1.0/tests/test_let_do_refactor_demo.spork +172 -0
- spork_lang-0.1.0/tests/test_let_refactor.spork +125 -0
- spork_lang-0.1.0/tests/test_let_statements.spork +120 -0
- spork_lang-0.1.0/tests/test_loop_recur.spork +191 -0
- spork_lang-0.1.0/tests/test_lsp.py +520 -0
- spork_lang-0.1.0/tests/test_macro.spork +9 -0
- spork_lang-0.1.0/tests/test_macros.spork +26 -0
- spork_lang-0.1.0/tests/test_map_merge.spork +137 -0
- spork_lang-0.1.0/tests/test_method_call.spork +56 -0
- spork_lang-0.1.0/tests/test_multi_arity.spork +128 -0
- spork_lang-0.1.0/tests/test_multi_dispatch.spork +231 -0
- spork_lang-0.1.0/tests/test_nested_let.spork +83 -0
- spork_lang-0.1.0/tests/test_ns.spork +33 -0
- spork_lang-0.1.0/tests/test_pattern_matching.spork +332 -0
- spork_lang-0.1.0/tests/test_pds.spork +71 -0
- spork_lang-0.1.0/tests/test_protocols.spork +146 -0
- spork_lang-0.1.0/tests/test_quasiquote_vector.spork +28 -0
- spork_lang-0.1.0/tests/test_set.spork +184 -0
- spork_lang-0.1.0/tests/test_set_expr.spork +43 -0
- spork_lang-0.1.0/tests/test_set_operations.spork +177 -0
- spork_lang-0.1.0/tests/test_slice.spork +193 -0
- spork_lang-0.1.0/tests/test_source_mapping.spork +75 -0
- spork_lang-0.1.0/tests/test_stage0.spork +111 -0
- spork_lang-0.1.0/tests/test_stage1.spork +233 -0
- spork_lang-0.1.0/tests/test_stage2.spork +187 -0
- spork_lang-0.1.0/tests/test_std_json.spork +268 -0
- spork_lang-0.1.0/tests/test_std_map.spork +151 -0
- spork_lang-0.1.0/tests/test_std_string.spork +84 -0
- spork_lang-0.1.0/tests/test_throw.spork +237 -0
- spork_lang-0.1.0/tests/test_transients.spork +487 -0
- spork_lang-0.1.0/tests/test_try_catch.spork +260 -0
- spork_lang-0.1.0/tests/test_type_predicates.spork +141 -0
- spork_lang-0.1.0/tests/test_typed_vectors.spork +170 -0
- spork_lang-0.1.0/tests/test_types.spork +170 -0
- spork_lang-0.1.0/tests/test_varargs.spork +94 -0
- spork_lang-0.1.0/tests/test_with.spork +386 -0
spork_lang-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Grant Wade
|
|
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.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
include *.md
|
|
2
|
+
include LICENSE
|
|
3
|
+
include pyproject.toml
|
|
4
|
+
include setup.py
|
|
5
|
+
|
|
6
|
+
# C extension source
|
|
7
|
+
recursive-include spork/runtime *.c
|
|
8
|
+
|
|
9
|
+
# Spork library files (macros)
|
|
10
|
+
recursive-include spork/std *.spork
|
|
11
|
+
|
|
12
|
+
# Test files
|
|
13
|
+
recursive-include tests *.spork
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spork-lang
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Lisp to Python transpiler with persistent data structures
|
|
5
|
+
Author-email: Grant Wade <grant@spork.sh>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/spork-it/spork-lang
|
|
8
|
+
Project-URL: Documentation, https://github.com/spork-it/spork-lang#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/spork-it/spork-lang
|
|
10
|
+
Project-URL: Issues, https://github.com/spork-it/spork-lang/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/grant-wade/spork/releases
|
|
12
|
+
Keywords: lisp,clojure,transpiler,compiler,persistent-data-structures,functional-programming,repl
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Lisp
|
|
23
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
24
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
25
|
+
Classifier: Topic :: Software Development :: Interpreters
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: build>=1.0
|
|
31
|
+
Requires-Dist: setuptools>=61.0
|
|
32
|
+
Requires-Dist: wheel
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: build; extra == "dev"
|
|
35
|
+
Requires-Dist: twine; extra == "dev"
|
|
36
|
+
Requires-Dist: numpy; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# Spork
|
|
41
|
+
|
|
42
|
+
[](https://github.com/spork-it/spork-lang/actions/workflows/test.yml)
|
|
43
|
+
|
|
44
|
+
Spork is a language designed to bring structural integrity to the Python ecosystem. It combines the massive ecosystem of Python with a modern, expression-oriented Lisp syntax.
|
|
45
|
+
|
|
46
|
+
While Spork compiles to Python AST, it introduces a new engine for your data: Persistent Data Structures implemented in a C extension under the hood. These immutable collections prevent a whole class of bugs related to unintended mutation, while still allowing efficient updates via structural sharing. Spork is built for developers who want the productivity of Python with the safety and expressiveness of a modern Lisp.
|
|
47
|
+
|
|
48
|
+
## Philosophy
|
|
49
|
+
|
|
50
|
+
Spork is built on a few core opinions:
|
|
51
|
+
|
|
52
|
+
1. **The Python Ecosystem is Great:** We want access to NumPy, PyTorch, Django, and the massive repository of PyPI packages. We do not want to rewrite the world.
|
|
53
|
+
2. **Data Integrity:** Python's mutable defaults are convenient for scripts but dangerous for systems. Spork fixes this at the foundation. `[1 2 3]` isn't a Python list; it is a persistent vector. Your data is immutable by default, ensuring that state management remains predictable as complexity grows.
|
|
54
|
+
3. **Unified Tooling:** Spork includes a unified toolchain to manage compilation, REPL, and testing, similar to `cargo` or `go`. It handles the bridge between Spork source and the Python environment so you don't have to configure build hooks manually.
|
|
55
|
+
4. **Pragmatism:** We believe a hosted language should not fight its host. Spork compiles directly to Python AST. When you need raw performance or side effects, the escape hatch to Python's native mutability and types is always open.
|
|
56
|
+
|
|
57
|
+
## **Alpha Warning**
|
|
58
|
+
|
|
59
|
+
Spork is currently in alpha. The language, standard library, and tooling are all under active development. Breaking changes may occur between releases. We welcome feedback, issues, and contributions!
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
### As a User
|
|
64
|
+
|
|
65
|
+
The recommended way to install Spork is via `pipx`, which isolates the tool environment while making the CLI globally available.
|
|
66
|
+
|
|
67
|
+
**Prerequisites:** Python 3.10+ and a C compiler (for the persistent data structures extension).
|
|
68
|
+
|
|
69
|
+
From the source directory:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
$ git clone https://github.com/spork-it/spork-lang.git
|
|
73
|
+
|
|
74
|
+
$ cd spork-lang
|
|
75
|
+
|
|
76
|
+
$ make pipx-install
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
To uninstall:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
$ make pipx-uninstall
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### For Development
|
|
86
|
+
|
|
87
|
+
If you wish to contribute to Spork or modify the compiler:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Sets up virtual environment and builds C extensions
|
|
91
|
+
make venv
|
|
92
|
+
|
|
93
|
+
# Run the test suite
|
|
94
|
+
make test
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Quick Start
|
|
98
|
+
|
|
99
|
+
### The REPL
|
|
100
|
+
|
|
101
|
+
Once installed, simply run `spork` to enter the Read-Eval-Print Loop.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
$ spork
|
|
105
|
+
Spork REPL - A Lisp for Python
|
|
106
|
+
user> (+ 1 2 3)
|
|
107
|
+
6
|
|
108
|
+
user> (map inc [1 2 3])
|
|
109
|
+
[2 3 4]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Language Overview
|
|
113
|
+
|
|
114
|
+
### Immutable Data Structures
|
|
115
|
+
|
|
116
|
+
Spork provides Persistent Data Structures (PDS) implemented in C for performance. These are the default literals in the language.
|
|
117
|
+
|
|
118
|
+
```clojure
|
|
119
|
+
;; Vectors
|
|
120
|
+
(def v [1 2 3])
|
|
121
|
+
(def v2 (conj v 4))
|
|
122
|
+
(print v) ; [1 2 3] - original is unchanged
|
|
123
|
+
(print v2) ; [1 2 3 4] - new structure sharing memory with old
|
|
124
|
+
|
|
125
|
+
;; Maps
|
|
126
|
+
(def m {:name "Spork" :version 1})
|
|
127
|
+
(def m2 (assoc m :version 2))
|
|
128
|
+
(print m) ; {:name "Spork", :version 1}
|
|
129
|
+
(print m2) ; {:name "Spork", :version 2}
|
|
130
|
+
|
|
131
|
+
;; Sets
|
|
132
|
+
(def s #{1 2 3})
|
|
133
|
+
(contains? s 2) ; true
|
|
134
|
+
|
|
135
|
+
; create new subset of s without 2
|
|
136
|
+
(def s2 (disj s 2))
|
|
137
|
+
(print s) ; #{1 2 3}
|
|
138
|
+
(print s2) ; #{1 3}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Python Interop
|
|
142
|
+
|
|
143
|
+
Spork compiles to Python, so interop is seamless.
|
|
144
|
+
|
|
145
|
+
```clojure
|
|
146
|
+
;; Imports
|
|
147
|
+
(ns examples
|
|
148
|
+
(:import [os] [random] [antigravity]) ; Python stdlibs
|
|
149
|
+
(:require [std.json :as j]) ; spork stdlib
|
|
150
|
+
|
|
151
|
+
;; Method calls (dot syntax)
|
|
152
|
+
(def text "hello world")
|
|
153
|
+
(.upper text) ; "HELLO WORLD"
|
|
154
|
+
|
|
155
|
+
;; Attribute access
|
|
156
|
+
(print os.name)
|
|
157
|
+
|
|
158
|
+
;; Mixing Python types (escape hatch)
|
|
159
|
+
(def py-list (list [1 2 3])) ; Convert Spork Vector to Python list
|
|
160
|
+
(.append py-list 4) ; Mutate it in place
|
|
161
|
+
|
|
162
|
+
(print py-list) ; [1, 2, 3, 4]
|
|
163
|
+
|
|
164
|
+
(def data {:name "Spork" :version 1.0}) ; Immutable Spork Map
|
|
165
|
+
(print (j.dumps data)) ; '{"name": "Spork", "version": 1.0}'
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Pattern Matching
|
|
169
|
+
|
|
170
|
+
Spork includes structural pattern matching out of the box.
|
|
171
|
+
|
|
172
|
+
```clojure
|
|
173
|
+
(defn describe [x]
|
|
174
|
+
(match x
|
|
175
|
+
0 "zero"
|
|
176
|
+
(^int n) (+ "integer: " (str n))
|
|
177
|
+
[a b] (+ "vector pair: " (str a) ", " (str b))
|
|
178
|
+
{:keys [name]} (+ "Hello " name)
|
|
179
|
+
_ "something else"))
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Type Annotations
|
|
183
|
+
|
|
184
|
+
Spork supports Python type hints using metadata syntax. These compile down to standard Python type annotations.
|
|
185
|
+
|
|
186
|
+
```clojure
|
|
187
|
+
(defn ^int add [^int x ^int y]
|
|
188
|
+
(+ x y))
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Compiles to:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
def add(x: int, y: int) -> int:
|
|
195
|
+
return x + y
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Macros
|
|
199
|
+
|
|
200
|
+
As a Lisp, Spork allows you to extend the compiler via macros.
|
|
201
|
+
|
|
202
|
+
```clojure
|
|
203
|
+
(defmacro unless [test & body]
|
|
204
|
+
`(if ~test
|
|
205
|
+
nil
|
|
206
|
+
(do ~@body)))
|
|
207
|
+
|
|
208
|
+
(unless (= (add 1 1) 3)
|
|
209
|
+
(print "Math still works"))
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Output from all of the above examples
|
|
213
|
+
|
|
214
|
+
```sh
|
|
215
|
+
$ spork readme.spork
|
|
216
|
+
[1 2 3]
|
|
217
|
+
[1 2 3 4]
|
|
218
|
+
{:name 'Spork' :version 1}
|
|
219
|
+
{:name 'Spork' :version 2}
|
|
220
|
+
#{1 2 3}
|
|
221
|
+
#{1 3}
|
|
222
|
+
posix
|
|
223
|
+
py-list before: [1, 2, 3]
|
|
224
|
+
py-list after: [1, 2, 3, 4]
|
|
225
|
+
Json: {"name": "Spork", "version": 1.0}
|
|
226
|
+
Math still works
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Error Reporting
|
|
230
|
+
|
|
231
|
+
Spork provides source-mapped error reporting, meaning that runtime errors point to the original `.spork` source files with accurate line numbers and code context—not the generated Python code.
|
|
232
|
+
|
|
233
|
+
### Example
|
|
234
|
+
|
|
235
|
+
Given this Spork file:
|
|
236
|
+
|
|
237
|
+
```clojure
|
|
238
|
+
;; math.spork
|
|
239
|
+
(defn divide [a b]
|
|
240
|
+
(/ a b))
|
|
241
|
+
|
|
242
|
+
(defn nested-call [x]
|
|
243
|
+
(let [y (divide x 0)]
|
|
244
|
+
(+ y 10)))
|
|
245
|
+
|
|
246
|
+
(defn deep-stack []
|
|
247
|
+
(nested-call 42))
|
|
248
|
+
|
|
249
|
+
(deep-stack)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Running it produces a traceback that references the original Spork source:
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
Error: division by zero
|
|
256
|
+
Traceback (most recent call last):
|
|
257
|
+
File "math.spork", line 12, in <module>
|
|
258
|
+
(deep-stack)
|
|
259
|
+
~~~~~^~~~~~~
|
|
260
|
+
File "math.spork", line 10, in deep_stack
|
|
261
|
+
(nested-call 42))
|
|
262
|
+
^^^^^^^^^^^^^^^^
|
|
263
|
+
File "math.spork", line 6, in nested_call
|
|
264
|
+
(let [y (divide x 0)]
|
|
265
|
+
^^^^^^^^^^^^
|
|
266
|
+
File "math.spork", line 3, in divide
|
|
267
|
+
(/ a b))
|
|
268
|
+
^^^^^^^
|
|
269
|
+
ZeroDivisionError: division by zero
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
## Project Management
|
|
274
|
+
|
|
275
|
+
### Creating a Project
|
|
276
|
+
|
|
277
|
+
Spork includes a scaffolding tool to set up a standard project structure with dependency management.
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
$ spork new my-project
|
|
281
|
+
✓ Created new Spork project: .../my-project
|
|
282
|
+
|
|
283
|
+
Next steps:
|
|
284
|
+
cd my-project
|
|
285
|
+
spork run # Run the project entrypoint
|
|
286
|
+
spork repl # Start the REPL in the project context
|
|
287
|
+
|
|
288
|
+
$ cd my-project/
|
|
289
|
+
|
|
290
|
+
$ tree
|
|
291
|
+
.
|
|
292
|
+
├── README.md
|
|
293
|
+
├── spork.it
|
|
294
|
+
└── src
|
|
295
|
+
└── my-project
|
|
296
|
+
└── core.spork
|
|
297
|
+
|
|
298
|
+
3 directories, 3 files
|
|
299
|
+
|
|
300
|
+
$ spork run
|
|
301
|
+
Project venv not found, initializing...
|
|
302
|
+
Creating virtual environment at .../my-project/.venv...
|
|
303
|
+
✓ Created virtual environment
|
|
304
|
+
✓ Upgraded pip
|
|
305
|
+
✓ Installed spork-lang (copied from current environment)
|
|
306
|
+
✓ All dependencies installed
|
|
307
|
+
|
|
308
|
+
Welcome to my-project!
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Project Structure (`spork.it`)
|
|
312
|
+
|
|
313
|
+
This generates a `spork.it` configuration file (the Spork equivalent of pyproject.toml), a source directory, and a test directory.
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
Spork aims to unify the fragmented Python tooling ecosystem. A project is defined by a `spork.it` file:
|
|
317
|
+
|
|
318
|
+
```clojure
|
|
319
|
+
{:name "my-project"
|
|
320
|
+
:version "0.1.0"
|
|
321
|
+
:dependencies ["requests" "numpy>=1.20"]
|
|
322
|
+
:source-paths ["src"]
|
|
323
|
+
:test-paths ["tests"]
|
|
324
|
+
:main "my-project.core/main"}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Commands:
|
|
328
|
+
* `spork sync`: Creates a virtual environment and installs dependencies defined in `spork.it`.
|
|
329
|
+
* `spork run`: Runs the project's main function.
|
|
330
|
+
* `spork repl`: Starts a REPL with the project's source roots and dependencies loaded.
|
|
331
|
+
* `spork build`: Compiles Spork source files to Python `.py` files in a `.spork-out/` directory.
|
|
332
|
+
* `spork dist`: Builds a distributable package (wheel & archives) for the project.
|
|
333
|
+
|
|
334
|
+
## Using Spork in an existing Python project
|
|
335
|
+
|
|
336
|
+
**Note:** Not currently on PyPI, so you must install from source.
|
|
337
|
+
|
|
338
|
+
1. Install Spork:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
$ pip install /path/to/spork
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
2. Import `spork` **once** at startup to register the import hooks:
|
|
345
|
+
|
|
346
|
+
```python
|
|
347
|
+
# e.g. in your app's __init__.py or main.py
|
|
348
|
+
import spork
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
3. Create a Spork module:
|
|
352
|
+
|
|
353
|
+
```clojure
|
|
354
|
+
;; my_module.spork
|
|
355
|
+
(defn add [x y]
|
|
356
|
+
(+ x y))
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
4. Import it from Python:
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
from my_module import add
|
|
363
|
+
print(add(1, 2)) # 3
|
|
364
|
+
```
|
|
365
|
+
> If you forget step 2 (`import spork`), Python will just say `ModuleNotFoundError: No module named 'my_module'` because the .spork import hook hasn’t been installed yet.
|
|
366
|
+
|
|
367
|
+
### Using Spork Persistent Data Structures from Python
|
|
368
|
+
You can use Spork's persistent data structures directly in Python by importing them from the `spork.runtime.pds` module. This gives Python developers access to the same immutable collections used in Spork.
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
from spork.runtime.pds import Vector, vec
|
|
372
|
+
|
|
373
|
+
v: Vector = vec([1, 2, 3])
|
|
374
|
+
v2 = v.conj(4)
|
|
375
|
+
print(v) # Vector([1, 2, 3])
|
|
376
|
+
print(v2) # Vector([1, 2, 3, 4])
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## Why Lisp?
|
|
380
|
+
|
|
381
|
+
Spork is a Lisp because we believe in **Homoiconicity**: the code is represented by the language's own data structures.
|
|
382
|
+
|
|
383
|
+
1. **Metaprogramming:** Because code is data, you can write code that writes code (Macros). This allows you to add features that look like language primitives (like the `match` or `unless` examples above) without waiting for the compiler developers to implement them.
|
|
384
|
+
2. **Structural Editing:** Tools like Parinfer or Paredit make editing code structurally (moving entire blocks, expressions, or function bodies) significantly faster and less error-prone than editing line-based languages like Python.
|
|
385
|
+
3. **Expression Oriented:** In Spork, almost everything is an expression that returns a value. `if`, `let`, and `do` blocks all return values, reducing the need for temporary variables and side effects.
|
|
386
|
+
|
|
387
|
+
## Under the Hood
|
|
388
|
+
|
|
389
|
+
Spork is not just a syntax skin; it is a runtime system optimized for the Python memory model.
|
|
390
|
+
|
|
391
|
+
* **Native Persistence:** Spork's data structures are not wrappers. They are custom C extensions.
|
|
392
|
+
* **Vectors:** 32-way Bit-Partitioned Tries (similar to Clojure/Rust im-rs).
|
|
393
|
+
* **Maps & Sets:** Hash Array Mapped Tries (HAMT).
|
|
394
|
+
* **Transient Internals:** The runtime utilizes mutable "Transients" internally to construct immutable results. This ensures that Spork remains performant at the boundary between mutation and persistence, giving you safety without the typical "copy-everything" penalty.
|
|
395
|
+
* **Source Mapping:** We track every AST node back to its origin. When an error happens, Spork points to *your* code, not the generated Python.
|
|
396
|
+
|
|
397
|
+
## Roots
|
|
398
|
+
|
|
399
|
+
* **Clojure:** The primary inspiration for our syntax and the sequence abstraction. We admire Clojure's discipline, but Spork is native to Python, not a JVM port.
|
|
400
|
+
* **Rust/Cargo:** The inspiration for our unified tooling and project structure (`spork.it`).
|
|
401
|
+
* **Python:** The host we love to live in. Spork is designed to be a good citizen of the Python ecosystem.
|
|
402
|
+
|
|
403
|
+
## Documentation
|
|
404
|
+
Checkout the [docs](docs) folder for more detailed documentation on language features, the standard library, and some benchmarks of the persistent data structures.
|
|
405
|
+
|
|
406
|
+
## License
|
|
407
|
+
|
|
408
|
+
[MIT License](LICENSE)
|