brittainscript 0.1.0__tar.gz → 0.3.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.
- {brittainscript-0.1.0 → brittainscript-0.3.0}/Documentation/README.md +112 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/LICENSE +1 -1
- {brittainscript-0.1.0 → brittainscript-0.3.0}/PKG-INFO +114 -2
- {brittainscript-0.1.0 → brittainscript-0.3.0}/brittainscript.egg-info/PKG-INFO +114 -2
- {brittainscript-0.1.0 → brittainscript-0.3.0}/brittainscript.egg-info/SOURCES.txt +11 -1
- brittainscript-0.3.0/core/gui_backend.py +450 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/core/lexer.py +11 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/core/parser.py +191 -23
- brittainscript-0.3.0/core/parsetab.py +73 -0
- brittainscript-0.3.0/libs/datetime.bs +50 -0
- brittainscript-0.3.0/libs/gui.bs +156 -0
- brittainscript-0.3.0/libs/io.bs +28 -0
- brittainscript-0.3.0/libs/terminal.bs +49 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/pyproject.toml +1 -1
- brittainscript-0.3.0/tests/test_datetime_builtin.py +54 -0
- brittainscript-0.3.0/tests/test_gui_builtins.py +43 -0
- brittainscript-0.3.0/tests/test_operator_precedence.py +59 -0
- brittainscript-0.3.0/tests/test_parser_builtins.py +39 -0
- brittainscript-0.3.0/tests/test_python_bridge.py +192 -0
- brittainscript-0.1.0/core/parsetab.py +0 -71
- {brittainscript-0.1.0 → brittainscript-0.3.0}/brittainscript.egg-info/dependency_links.txt +0 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/brittainscript.egg-info/entry_points.txt +0 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/brittainscript.egg-info/requires.txt +0 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/brittainscript.egg-info/top_level.txt +0 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/core/__init__.py +0 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/core/main.py +0 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/libs/__init__.py +0 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/libs/convert.bs +0 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/libs/math.bs +0 -0
- {brittainscript-0.1.0 → brittainscript-0.3.0}/setup.cfg +0 -0
|
@@ -180,6 +180,118 @@ push(len(nums))
|
|
|
180
180
|
|
|
181
181
|
---
|
|
182
182
|
|
|
183
|
+
## Python Interop
|
|
184
|
+
|
|
185
|
+
BrittainScript can call into any Python library installed in the same Python
|
|
186
|
+
environment — `numpy`, `requests`, `torch`, anything. There is nothing to
|
|
187
|
+
install beyond the library itself; the interpreter's only dependency is `ply`.
|
|
188
|
+
|
|
189
|
+
### `pyimport(name)`
|
|
190
|
+
|
|
191
|
+
Imports a Python module and hands it back as an ordinary BrittainScript value.
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
np = pyimport("numpy")
|
|
195
|
+
json = pyimport("json")
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
If the module cannot be imported, `pyimport` prints an error and returns
|
|
199
|
+
nothing:
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
missing = pyimport("not_a_real_module")
|
|
203
|
+
=> Error: cannot import 'not_a_real_module': No module named 'not_a_real_module'
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Calling Python methods
|
|
207
|
+
|
|
208
|
+
Method-call syntax falls through to Python whenever the name is not one of
|
|
209
|
+
BrittainScript's own methods (`upper`, `lower`, `trim`, `contains`, `locate`,
|
|
210
|
+
`add`, `remove`, `pop`, `has`). Those built-ins always win, so existing scripts
|
|
211
|
+
are unaffected.
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
np = pyimport("numpy")
|
|
215
|
+
matrix = np.array([[1, 2], [3, 4]])
|
|
216
|
+
|
|
217
|
+
push(matrix.sum()) => 10
|
|
218
|
+
push(matrix.transpose())
|
|
219
|
+
push("a,b,c".split(",")) => ['a', 'b', 'c']
|
|
220
|
+
push("hello".replace("l", "L"))
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Note that arguments are positional only — BrittainScript has no keyword
|
|
224
|
+
argument syntax. Where a Python API needs a keyword, look for a method form of
|
|
225
|
+
it (`tensor.requires_grad_()` rather than `requires_grad=true`).
|
|
226
|
+
|
|
227
|
+
### Attribute access
|
|
228
|
+
|
|
229
|
+
A dotted name with no call reads the attribute directly.
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
np = pyimport("numpy")
|
|
233
|
+
matrix = np.array([[1, 2], [3, 4]])
|
|
234
|
+
|
|
235
|
+
push(matrix.shape) => (2, 2)
|
|
236
|
+
push(matrix.T)
|
|
237
|
+
push(pyimport("math").pi) => 3.141592653589793
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Reserved words such as `pi`, `sin`, `cos` and `tan` are treated as ordinary
|
|
241
|
+
names when they follow a `.`, so `math.pi` and `np.sin(x)` both work.
|
|
242
|
+
|
|
243
|
+
### The `@` operator
|
|
244
|
+
|
|
245
|
+
`@` is matrix multiplication, passed straight through to Python's `__matmul__`.
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
np = pyimport("numpy")
|
|
249
|
+
a = np.array([[1, 2], [3, 4]])
|
|
250
|
+
push(a @ a) => [[ 7 10]
|
|
251
|
+
[15 22]]
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
It binds at the same level as `*`, so `x @ w + b` multiplies before it adds.
|
|
255
|
+
|
|
256
|
+
### Why this works everywhere else too
|
|
257
|
+
|
|
258
|
+
BrittainScript values are native Python objects, so once a Python object is in
|
|
259
|
+
a variable, the rest of the language already applies to it — arithmetic,
|
|
260
|
+
indexing, slicing, comparison and `for` loops all use Python's own behaviour:
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
np = pyimport("numpy")
|
|
264
|
+
values = np.array([10, 20, 30, 40])
|
|
265
|
+
|
|
266
|
+
push(values * 2)
|
|
267
|
+
push(values[1])
|
|
268
|
+
push(values[1:3])
|
|
269
|
+
for value in values:
|
|
270
|
+
push(value)
|
|
271
|
+
end
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### A worked example
|
|
275
|
+
|
|
276
|
+
`examples/torch_demo.bs` trains a small linear model with PyTorch, including a
|
|
277
|
+
hand-written SGD loop driven by autograd. Run it with:
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
python3 run.py examples/torch_demo.bs
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
It prints a message and stops if `torch` is not installed.
|
|
284
|
+
|
|
285
|
+
### A note on scope
|
|
286
|
+
|
|
287
|
+
`pyimport` gives a script the whole Python environment — including `os`,
|
|
288
|
+
`subprocess` and `shutil`. That is the expected trade-off for a scripting
|
|
289
|
+
language FFI and is the same power a Python script has, but it does mean a
|
|
290
|
+
`.bs` file can do anything the Python interpreter running it can do. Treat
|
|
291
|
+
untrusted BrittainScript the way you would treat untrusted Python.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
183
295
|
## Test Files
|
|
184
296
|
|
|
185
297
|
There are two standalone test suites in `TestFiles/`. These are self-contained and independent from the main interpreter — they were used to prototype the lexer and parser separately.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brittainscript
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: The BrittainScript programming language interpreter
|
|
5
5
|
Author-email: Luke Brittain <luke.brittain@gmail.com>
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
8
|
-
Copyright (c)
|
|
8
|
+
Copyright (c) 2026 Luke Brittain
|
|
9
9
|
|
|
10
10
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
11
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -218,6 +218,118 @@ push(len(nums))
|
|
|
218
218
|
|
|
219
219
|
---
|
|
220
220
|
|
|
221
|
+
## Python Interop
|
|
222
|
+
|
|
223
|
+
BrittainScript can call into any Python library installed in the same Python
|
|
224
|
+
environment — `numpy`, `requests`, `torch`, anything. There is nothing to
|
|
225
|
+
install beyond the library itself; the interpreter's only dependency is `ply`.
|
|
226
|
+
|
|
227
|
+
### `pyimport(name)`
|
|
228
|
+
|
|
229
|
+
Imports a Python module and hands it back as an ordinary BrittainScript value.
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
np = pyimport("numpy")
|
|
233
|
+
json = pyimport("json")
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
If the module cannot be imported, `pyimport` prints an error and returns
|
|
237
|
+
nothing:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
missing = pyimport("not_a_real_module")
|
|
241
|
+
=> Error: cannot import 'not_a_real_module': No module named 'not_a_real_module'
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Calling Python methods
|
|
245
|
+
|
|
246
|
+
Method-call syntax falls through to Python whenever the name is not one of
|
|
247
|
+
BrittainScript's own methods (`upper`, `lower`, `trim`, `contains`, `locate`,
|
|
248
|
+
`add`, `remove`, `pop`, `has`). Those built-ins always win, so existing scripts
|
|
249
|
+
are unaffected.
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
np = pyimport("numpy")
|
|
253
|
+
matrix = np.array([[1, 2], [3, 4]])
|
|
254
|
+
|
|
255
|
+
push(matrix.sum()) => 10
|
|
256
|
+
push(matrix.transpose())
|
|
257
|
+
push("a,b,c".split(",")) => ['a', 'b', 'c']
|
|
258
|
+
push("hello".replace("l", "L"))
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Note that arguments are positional only — BrittainScript has no keyword
|
|
262
|
+
argument syntax. Where a Python API needs a keyword, look for a method form of
|
|
263
|
+
it (`tensor.requires_grad_()` rather than `requires_grad=true`).
|
|
264
|
+
|
|
265
|
+
### Attribute access
|
|
266
|
+
|
|
267
|
+
A dotted name with no call reads the attribute directly.
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
np = pyimport("numpy")
|
|
271
|
+
matrix = np.array([[1, 2], [3, 4]])
|
|
272
|
+
|
|
273
|
+
push(matrix.shape) => (2, 2)
|
|
274
|
+
push(matrix.T)
|
|
275
|
+
push(pyimport("math").pi) => 3.141592653589793
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Reserved words such as `pi`, `sin`, `cos` and `tan` are treated as ordinary
|
|
279
|
+
names when they follow a `.`, so `math.pi` and `np.sin(x)` both work.
|
|
280
|
+
|
|
281
|
+
### The `@` operator
|
|
282
|
+
|
|
283
|
+
`@` is matrix multiplication, passed straight through to Python's `__matmul__`.
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
np = pyimport("numpy")
|
|
287
|
+
a = np.array([[1, 2], [3, 4]])
|
|
288
|
+
push(a @ a) => [[ 7 10]
|
|
289
|
+
[15 22]]
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
It binds at the same level as `*`, so `x @ w + b` multiplies before it adds.
|
|
293
|
+
|
|
294
|
+
### Why this works everywhere else too
|
|
295
|
+
|
|
296
|
+
BrittainScript values are native Python objects, so once a Python object is in
|
|
297
|
+
a variable, the rest of the language already applies to it — arithmetic,
|
|
298
|
+
indexing, slicing, comparison and `for` loops all use Python's own behaviour:
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
np = pyimport("numpy")
|
|
302
|
+
values = np.array([10, 20, 30, 40])
|
|
303
|
+
|
|
304
|
+
push(values * 2)
|
|
305
|
+
push(values[1])
|
|
306
|
+
push(values[1:3])
|
|
307
|
+
for value in values:
|
|
308
|
+
push(value)
|
|
309
|
+
end
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### A worked example
|
|
313
|
+
|
|
314
|
+
`examples/torch_demo.bs` trains a small linear model with PyTorch, including a
|
|
315
|
+
hand-written SGD loop driven by autograd. Run it with:
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
python3 run.py examples/torch_demo.bs
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
It prints a message and stops if `torch` is not installed.
|
|
322
|
+
|
|
323
|
+
### A note on scope
|
|
324
|
+
|
|
325
|
+
`pyimport` gives a script the whole Python environment — including `os`,
|
|
326
|
+
`subprocess` and `shutil`. That is the expected trade-off for a scripting
|
|
327
|
+
language FFI and is the same power a Python script has, but it does mean a
|
|
328
|
+
`.bs` file can do anything the Python interpreter running it can do. Treat
|
|
329
|
+
untrusted BrittainScript the way you would treat untrusted Python.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
221
333
|
## Test Files
|
|
222
334
|
|
|
223
335
|
There are two standalone test suites in `TestFiles/`. These are self-contained and independent from the main interpreter — they were used to prototype the lexer and parser separately.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brittainscript
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: The BrittainScript programming language interpreter
|
|
5
5
|
Author-email: Luke Brittain <luke.brittain@gmail.com>
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
8
|
-
Copyright (c)
|
|
8
|
+
Copyright (c) 2026 Luke Brittain
|
|
9
9
|
|
|
10
10
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
11
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -218,6 +218,118 @@ push(len(nums))
|
|
|
218
218
|
|
|
219
219
|
---
|
|
220
220
|
|
|
221
|
+
## Python Interop
|
|
222
|
+
|
|
223
|
+
BrittainScript can call into any Python library installed in the same Python
|
|
224
|
+
environment — `numpy`, `requests`, `torch`, anything. There is nothing to
|
|
225
|
+
install beyond the library itself; the interpreter's only dependency is `ply`.
|
|
226
|
+
|
|
227
|
+
### `pyimport(name)`
|
|
228
|
+
|
|
229
|
+
Imports a Python module and hands it back as an ordinary BrittainScript value.
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
np = pyimport("numpy")
|
|
233
|
+
json = pyimport("json")
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
If the module cannot be imported, `pyimport` prints an error and returns
|
|
237
|
+
nothing:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
missing = pyimport("not_a_real_module")
|
|
241
|
+
=> Error: cannot import 'not_a_real_module': No module named 'not_a_real_module'
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Calling Python methods
|
|
245
|
+
|
|
246
|
+
Method-call syntax falls through to Python whenever the name is not one of
|
|
247
|
+
BrittainScript's own methods (`upper`, `lower`, `trim`, `contains`, `locate`,
|
|
248
|
+
`add`, `remove`, `pop`, `has`). Those built-ins always win, so existing scripts
|
|
249
|
+
are unaffected.
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
np = pyimport("numpy")
|
|
253
|
+
matrix = np.array([[1, 2], [3, 4]])
|
|
254
|
+
|
|
255
|
+
push(matrix.sum()) => 10
|
|
256
|
+
push(matrix.transpose())
|
|
257
|
+
push("a,b,c".split(",")) => ['a', 'b', 'c']
|
|
258
|
+
push("hello".replace("l", "L"))
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Note that arguments are positional only — BrittainScript has no keyword
|
|
262
|
+
argument syntax. Where a Python API needs a keyword, look for a method form of
|
|
263
|
+
it (`tensor.requires_grad_()` rather than `requires_grad=true`).
|
|
264
|
+
|
|
265
|
+
### Attribute access
|
|
266
|
+
|
|
267
|
+
A dotted name with no call reads the attribute directly.
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
np = pyimport("numpy")
|
|
271
|
+
matrix = np.array([[1, 2], [3, 4]])
|
|
272
|
+
|
|
273
|
+
push(matrix.shape) => (2, 2)
|
|
274
|
+
push(matrix.T)
|
|
275
|
+
push(pyimport("math").pi) => 3.141592653589793
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Reserved words such as `pi`, `sin`, `cos` and `tan` are treated as ordinary
|
|
279
|
+
names when they follow a `.`, so `math.pi` and `np.sin(x)` both work.
|
|
280
|
+
|
|
281
|
+
### The `@` operator
|
|
282
|
+
|
|
283
|
+
`@` is matrix multiplication, passed straight through to Python's `__matmul__`.
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
np = pyimport("numpy")
|
|
287
|
+
a = np.array([[1, 2], [3, 4]])
|
|
288
|
+
push(a @ a) => [[ 7 10]
|
|
289
|
+
[15 22]]
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
It binds at the same level as `*`, so `x @ w + b` multiplies before it adds.
|
|
293
|
+
|
|
294
|
+
### Why this works everywhere else too
|
|
295
|
+
|
|
296
|
+
BrittainScript values are native Python objects, so once a Python object is in
|
|
297
|
+
a variable, the rest of the language already applies to it — arithmetic,
|
|
298
|
+
indexing, slicing, comparison and `for` loops all use Python's own behaviour:
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
np = pyimport("numpy")
|
|
302
|
+
values = np.array([10, 20, 30, 40])
|
|
303
|
+
|
|
304
|
+
push(values * 2)
|
|
305
|
+
push(values[1])
|
|
306
|
+
push(values[1:3])
|
|
307
|
+
for value in values:
|
|
308
|
+
push(value)
|
|
309
|
+
end
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### A worked example
|
|
313
|
+
|
|
314
|
+
`examples/torch_demo.bs` trains a small linear model with PyTorch, including a
|
|
315
|
+
hand-written SGD loop driven by autograd. Run it with:
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
python3 run.py examples/torch_demo.bs
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
It prints a message and stops if `torch` is not installed.
|
|
322
|
+
|
|
323
|
+
### A note on scope
|
|
324
|
+
|
|
325
|
+
`pyimport` gives a script the whole Python environment — including `os`,
|
|
326
|
+
`subprocess` and `shutil`. That is the expected trade-off for a scripting
|
|
327
|
+
language FFI and is the same power a Python script has, but it does mean a
|
|
328
|
+
`.bs` file can do anything the Python interpreter running it can do. Treat
|
|
329
|
+
untrusted BrittainScript the way you would treat untrusted Python.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
221
333
|
## Test Files
|
|
222
334
|
|
|
223
335
|
There are two standalone test suites in `TestFiles/`. These are self-contained and independent from the main interpreter — they were used to prototype the lexer and parser separately.
|
|
@@ -8,10 +8,20 @@ brittainscript.egg-info/entry_points.txt
|
|
|
8
8
|
brittainscript.egg-info/requires.txt
|
|
9
9
|
brittainscript.egg-info/top_level.txt
|
|
10
10
|
core/__init__.py
|
|
11
|
+
core/gui_backend.py
|
|
11
12
|
core/lexer.py
|
|
12
13
|
core/main.py
|
|
13
14
|
core/parser.py
|
|
14
15
|
core/parsetab.py
|
|
15
16
|
libs/__init__.py
|
|
16
17
|
libs/convert.bs
|
|
17
|
-
libs/
|
|
18
|
+
libs/datetime.bs
|
|
19
|
+
libs/gui.bs
|
|
20
|
+
libs/io.bs
|
|
21
|
+
libs/math.bs
|
|
22
|
+
libs/terminal.bs
|
|
23
|
+
tests/test_datetime_builtin.py
|
|
24
|
+
tests/test_gui_builtins.py
|
|
25
|
+
tests/test_operator_precedence.py
|
|
26
|
+
tests/test_parser_builtins.py
|
|
27
|
+
tests/test_python_bridge.py
|