tawla 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.
- tawla-0.1.0/LICENSE +21 -0
- tawla-0.1.0/PKG-INFO +150 -0
- tawla-0.1.0/README.md +130 -0
- tawla-0.1.0/pyproject.toml +31 -0
- tawla-0.1.0/setup.cfg +4 -0
- tawla-0.1.0/tawla/__init__.py +3 -0
- tawla-0.1.0/tawla/__main__.py +8 -0
- tawla-0.1.0/tawla/ast_nodes.py +199 -0
- tawla-0.1.0/tawla/cli.py +104 -0
- tawla-0.1.0/tawla/codegen.py +815 -0
- tawla-0.1.0/tawla/compiler.py +61 -0
- tawla-0.1.0/tawla/gc_runtime.py +106 -0
- tawla-0.1.0/tawla/lexer.py +125 -0
- tawla-0.1.0/tawla/monomorphize.py +220 -0
- tawla-0.1.0/tawla/parser.py +517 -0
- tawla-0.1.0/tawla/project.py +62 -0
- tawla-0.1.0/tawla/sema.py +554 -0
- tawla-0.1.0/tawla/tokens.py +79 -0
- tawla-0.1.0/tawla.egg-info/PKG-INFO +150 -0
- tawla-0.1.0/tawla.egg-info/SOURCES.txt +43 -0
- tawla-0.1.0/tawla.egg-info/dependency_links.txt +1 -0
- tawla-0.1.0/tawla.egg-info/entry_points.txt +2 -0
- tawla-0.1.0/tawla.egg-info/requires.txt +1 -0
- tawla-0.1.0/tawla.egg-info/top_level.txt +1 -0
- tawla-0.1.0/tests/test_cli.py +48 -0
- tawla-0.1.0/tests/test_m1.py +58 -0
- tawla-0.1.0/tests/test_m10.py +52 -0
- tawla-0.1.0/tests/test_m11.py +54 -0
- tawla-0.1.0/tests/test_m12.py +56 -0
- tawla-0.1.0/tests/test_m13.py +60 -0
- tawla-0.1.0/tests/test_m15.py +26 -0
- tawla-0.1.0/tests/test_m16.py +32 -0
- tawla-0.1.0/tests/test_m17.py +45 -0
- tawla-0.1.0/tests/test_m18.py +63 -0
- tawla-0.1.0/tests/test_m19.py +64 -0
- tawla-0.1.0/tests/test_m2.py +43 -0
- tawla-0.1.0/tests/test_m3.py +83 -0
- tawla-0.1.0/tests/test_m4.py +72 -0
- tawla-0.1.0/tests/test_m5.py +64 -0
- tawla-0.1.0/tests/test_m6.py +86 -0
- tawla-0.1.0/tests/test_m7.py +69 -0
- tawla-0.1.0/tests/test_m8.py +55 -0
- tawla-0.1.0/tests/test_m9.py +81 -0
- tawla-0.1.0/tests/test_m9b.py +43 -0
- tawla-0.1.0/tests/test_project.py +68 -0
tawla-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ahmed Haddaji
|
|
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.
|
tawla-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tawla
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The Tawla programming language and its tawlac compiler
|
|
5
|
+
Author-email: Ahmed Haddaji <ahmedhaddajiahmed@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/HaddajiDev/tawla-lang
|
|
8
|
+
Project-URL: Repository, https://github.com/HaddajiDev/tawla-lang
|
|
9
|
+
Keywords: compiler,programming-language,llvm,tawla
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: llvmlite>=0.44
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# Tawla
|
|
22
|
+
|
|
23
|
+
Tawla is a small programming language with its own compiler, `tawlac`, built
|
|
24
|
+
from scratch. It looks a lot like C#: you write classes with fields and methods,
|
|
25
|
+
you get inheritance and interfaces, and everything is statically typed. Under the
|
|
26
|
+
hood `tawlac` turns your code into real machine code using LLVM and runs it on
|
|
27
|
+
the spot, so there's no separate "compile then run" dance.
|
|
28
|
+
|
|
29
|
+
It started as a learning project to understand how compilers actually work, and
|
|
30
|
+
it grew into a genuinely usable little language. Source files end in `.twl`.
|
|
31
|
+
|
|
32
|
+
Here's the whole "hello world":
|
|
33
|
+
|
|
34
|
+
```tawla
|
|
35
|
+
class Main {
|
|
36
|
+
void main() {
|
|
37
|
+
print("Hello, Tawla!");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
$ tawlac run hello.twl
|
|
44
|
+
Hello, Tawla!
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Getting it running
|
|
48
|
+
|
|
49
|
+
You need Python 3.11 or newer. The easiest way to install `tawlac` is with
|
|
50
|
+
[pipx](https://pipx.pypa.io/), which puts it in its own isolated environment and
|
|
51
|
+
on your PATH. It works the same on Windows, macOS, and Linux:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
pipx install tawla
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
(That works once Tawla is published to PyPI. Until then, install from a clone of
|
|
58
|
+
this repo: `pipx install .` from the project folder, or once it's pushed:
|
|
59
|
+
`pipx install git+https://github.com/HaddajiDev/tawla-lang`.)
|
|
60
|
+
|
|
61
|
+
Prefer plain pip, or just hacking on it from a checkout? That's fine too:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
pip install llvmlite
|
|
65
|
+
python -m tawla run examples/hello.twl
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Either way you get the `tawlac` command (or `python -m tawla`) with a few
|
|
69
|
+
subcommands:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
tawlac run app.twl # compile and run a file
|
|
73
|
+
tawlac new myapp # scaffold a new project (like cargo new)
|
|
74
|
+
tawlac init # scaffold one in the current folder
|
|
75
|
+
tawlac run # run the current project (reads Tawla.toml)
|
|
76
|
+
tawlac version # what version is this
|
|
77
|
+
tawlac help # or: tawlac help run
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## What the language can do
|
|
81
|
+
|
|
82
|
+
- **The basics:** `int`, `bool`, and `string`; arithmetic and comparisons;
|
|
83
|
+
`if`/`else`, `while`, and functions (recursion works fine).
|
|
84
|
+
- **`var`:** skip the type and let it be inferred — `var x = 5;`.
|
|
85
|
+
- **Classes:** fields, methods, constructors, `this`, and `new`. Objects live on
|
|
86
|
+
the heap.
|
|
87
|
+
- **Inheritance:** `class Dog : Animal { ... }`, with method overriding and
|
|
88
|
+
`super(...)` to call the base constructor.
|
|
89
|
+
- **Polymorphism:** methods are virtual, so the right one gets picked at runtime
|
|
90
|
+
based on the actual object type (this is done with vtables).
|
|
91
|
+
- **Interfaces:** `interface Shape { int area(); }`, and any class can implement
|
|
92
|
+
it, even classes that share no common parent.
|
|
93
|
+
- **Abstract classes:** mark a class `abstract` and leave some methods without a
|
|
94
|
+
body for subclasses to fill in.
|
|
95
|
+
- **Generics:** `class Box<T> { ... }`, used as `Box<int>` or `Box<string>`.
|
|
96
|
+
- **Strings:** literals with escapes, `s.length`, `==`, and `+` to join them.
|
|
97
|
+
- **Arrays:** `new int[n]`, indexing with `a[i]` (bounds-checked, so you get a
|
|
98
|
+
clear error instead of a crash), and `a.length`.
|
|
99
|
+
- **Comments:** `// like this`.
|
|
100
|
+
- **Garbage collection:** you don't free memory by hand. Call `collect()` when
|
|
101
|
+
you want a cleanup pass; `__live()` tells you how many objects are still around.
|
|
102
|
+
|
|
103
|
+
There's a runnable example for pretty much every feature in `examples/` — poke
|
|
104
|
+
around in there to see how things look in practice.
|
|
105
|
+
|
|
106
|
+
## How it works, roughly
|
|
107
|
+
|
|
108
|
+
`tawlac` runs your code through the usual compiler stages:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
source.twl -> lexer -> parser -> sema -> codegen -> LLVM -> JIT -> runs
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- the **lexer** chops the text into tokens
|
|
115
|
+
- the **parser** builds a tree out of those tokens
|
|
116
|
+
- **sema** checks the types and catches mistakes before any code is generated
|
|
117
|
+
- **codegen** turns the checked tree into LLVM instructions
|
|
118
|
+
- LLVM compiles that to machine code and the **JIT** runs it immediately
|
|
119
|
+
|
|
120
|
+
Each piece lives in its own file under `tawla/`, so it's not hard to follow if
|
|
121
|
+
you want to read along.
|
|
122
|
+
|
|
123
|
+
## Running the tests
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
./venv/Scripts/python -m pytest
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
There are around 200 tests. Programs that print output are checked by running
|
|
130
|
+
`tawlac` as a separate process and looking at what it prints (this sidesteps a
|
|
131
|
+
Windows quirk where output from JIT-compiled code is hard to capture in-process).
|
|
132
|
+
|
|
133
|
+
## What's not done yet
|
|
134
|
+
|
|
135
|
+
It's a real language, but it's still a young one. A few honest gaps:
|
|
136
|
+
|
|
137
|
+
- `tawlac build` (making a standalone `.exe` *from your Tawla program*) isn't
|
|
138
|
+
done — for now everything runs through `tawlac run`.
|
|
139
|
+
- Generics only cover classes, not standalone functions, and you can't nest them
|
|
140
|
+
like `Box<Box<int>>`.
|
|
141
|
+
- Garbage collection has to be triggered with `collect()`; it doesn't kick in on
|
|
142
|
+
its own yet.
|
|
143
|
+
- No file imports, modules, or a standard library to speak of.
|
|
144
|
+
|
|
145
|
+
The full design and the step-by-step history of how it was built are in
|
|
146
|
+
`docs/superpowers/specs/2026-05-29-tawla-language-design.md` if you're curious.
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT — see [LICENSE](LICENSE).
|
tawla-0.1.0/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Tawla
|
|
2
|
+
|
|
3
|
+
Tawla is a small programming language with its own compiler, `tawlac`, built
|
|
4
|
+
from scratch. It looks a lot like C#: you write classes with fields and methods,
|
|
5
|
+
you get inheritance and interfaces, and everything is statically typed. Under the
|
|
6
|
+
hood `tawlac` turns your code into real machine code using LLVM and runs it on
|
|
7
|
+
the spot, so there's no separate "compile then run" dance.
|
|
8
|
+
|
|
9
|
+
It started as a learning project to understand how compilers actually work, and
|
|
10
|
+
it grew into a genuinely usable little language. Source files end in `.twl`.
|
|
11
|
+
|
|
12
|
+
Here's the whole "hello world":
|
|
13
|
+
|
|
14
|
+
```tawla
|
|
15
|
+
class Main {
|
|
16
|
+
void main() {
|
|
17
|
+
print("Hello, Tawla!");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
$ tawlac run hello.twl
|
|
24
|
+
Hello, Tawla!
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Getting it running
|
|
28
|
+
|
|
29
|
+
You need Python 3.11 or newer. The easiest way to install `tawlac` is with
|
|
30
|
+
[pipx](https://pipx.pypa.io/), which puts it in its own isolated environment and
|
|
31
|
+
on your PATH. It works the same on Windows, macOS, and Linux:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
pipx install tawla
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
(That works once Tawla is published to PyPI. Until then, install from a clone of
|
|
38
|
+
this repo: `pipx install .` from the project folder, or once it's pushed:
|
|
39
|
+
`pipx install git+https://github.com/HaddajiDev/tawla-lang`.)
|
|
40
|
+
|
|
41
|
+
Prefer plain pip, or just hacking on it from a checkout? That's fine too:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
pip install llvmlite
|
|
45
|
+
python -m tawla run examples/hello.twl
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Either way you get the `tawlac` command (or `python -m tawla`) with a few
|
|
49
|
+
subcommands:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
tawlac run app.twl # compile and run a file
|
|
53
|
+
tawlac new myapp # scaffold a new project (like cargo new)
|
|
54
|
+
tawlac init # scaffold one in the current folder
|
|
55
|
+
tawlac run # run the current project (reads Tawla.toml)
|
|
56
|
+
tawlac version # what version is this
|
|
57
|
+
tawlac help # or: tawlac help run
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## What the language can do
|
|
61
|
+
|
|
62
|
+
- **The basics:** `int`, `bool`, and `string`; arithmetic and comparisons;
|
|
63
|
+
`if`/`else`, `while`, and functions (recursion works fine).
|
|
64
|
+
- **`var`:** skip the type and let it be inferred — `var x = 5;`.
|
|
65
|
+
- **Classes:** fields, methods, constructors, `this`, and `new`. Objects live on
|
|
66
|
+
the heap.
|
|
67
|
+
- **Inheritance:** `class Dog : Animal { ... }`, with method overriding and
|
|
68
|
+
`super(...)` to call the base constructor.
|
|
69
|
+
- **Polymorphism:** methods are virtual, so the right one gets picked at runtime
|
|
70
|
+
based on the actual object type (this is done with vtables).
|
|
71
|
+
- **Interfaces:** `interface Shape { int area(); }`, and any class can implement
|
|
72
|
+
it, even classes that share no common parent.
|
|
73
|
+
- **Abstract classes:** mark a class `abstract` and leave some methods without a
|
|
74
|
+
body for subclasses to fill in.
|
|
75
|
+
- **Generics:** `class Box<T> { ... }`, used as `Box<int>` or `Box<string>`.
|
|
76
|
+
- **Strings:** literals with escapes, `s.length`, `==`, and `+` to join them.
|
|
77
|
+
- **Arrays:** `new int[n]`, indexing with `a[i]` (bounds-checked, so you get a
|
|
78
|
+
clear error instead of a crash), and `a.length`.
|
|
79
|
+
- **Comments:** `// like this`.
|
|
80
|
+
- **Garbage collection:** you don't free memory by hand. Call `collect()` when
|
|
81
|
+
you want a cleanup pass; `__live()` tells you how many objects are still around.
|
|
82
|
+
|
|
83
|
+
There's a runnable example for pretty much every feature in `examples/` — poke
|
|
84
|
+
around in there to see how things look in practice.
|
|
85
|
+
|
|
86
|
+
## How it works, roughly
|
|
87
|
+
|
|
88
|
+
`tawlac` runs your code through the usual compiler stages:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
source.twl -> lexer -> parser -> sema -> codegen -> LLVM -> JIT -> runs
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- the **lexer** chops the text into tokens
|
|
95
|
+
- the **parser** builds a tree out of those tokens
|
|
96
|
+
- **sema** checks the types and catches mistakes before any code is generated
|
|
97
|
+
- **codegen** turns the checked tree into LLVM instructions
|
|
98
|
+
- LLVM compiles that to machine code and the **JIT** runs it immediately
|
|
99
|
+
|
|
100
|
+
Each piece lives in its own file under `tawla/`, so it's not hard to follow if
|
|
101
|
+
you want to read along.
|
|
102
|
+
|
|
103
|
+
## Running the tests
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
./venv/Scripts/python -m pytest
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
There are around 200 tests. Programs that print output are checked by running
|
|
110
|
+
`tawlac` as a separate process and looking at what it prints (this sidesteps a
|
|
111
|
+
Windows quirk where output from JIT-compiled code is hard to capture in-process).
|
|
112
|
+
|
|
113
|
+
## What's not done yet
|
|
114
|
+
|
|
115
|
+
It's a real language, but it's still a young one. A few honest gaps:
|
|
116
|
+
|
|
117
|
+
- `tawlac build` (making a standalone `.exe` *from your Tawla program*) isn't
|
|
118
|
+
done — for now everything runs through `tawlac run`.
|
|
119
|
+
- Generics only cover classes, not standalone functions, and you can't nest them
|
|
120
|
+
like `Box<Box<int>>`.
|
|
121
|
+
- Garbage collection has to be triggered with `collect()`; it doesn't kick in on
|
|
122
|
+
its own yet.
|
|
123
|
+
- No file imports, modules, or a standard library to speak of.
|
|
124
|
+
|
|
125
|
+
The full design and the step-by-step history of how it was built are in
|
|
126
|
+
`docs/superpowers/specs/2026-05-29-tawla-language-design.md` if you're curious.
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tawla"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "The Tawla programming language and its tawlac compiler"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "Ahmed Haddaji", email = "ahmedhaddajiahmed@gmail.com" }]
|
|
9
|
+
dependencies = ["llvmlite>=0.44"]
|
|
10
|
+
keywords = ["compiler", "programming-language", "llvm", "tawla"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Topic :: Software Development :: Compilers",
|
|
15
|
+
"Environment :: Console",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.urls]
|
|
20
|
+
Homepage = "https://github.com/HaddajiDev/tawla-lang"
|
|
21
|
+
Repository = "https://github.com/HaddajiDev/tawla-lang"
|
|
22
|
+
|
|
23
|
+
[project.scripts]
|
|
24
|
+
tawlac = "tawla.cli:main"
|
|
25
|
+
|
|
26
|
+
[build-system]
|
|
27
|
+
requires = ["setuptools>=68"]
|
|
28
|
+
build-backend = "setuptools.build_meta"
|
|
29
|
+
|
|
30
|
+
[tool.setuptools]
|
|
31
|
+
packages = ["tawla"]
|
tawla-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""The AST node types — the little tree the parser builds and codegen walks over."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Expr:
|
|
7
|
+
"""Parent of everything that's an expression (i.e. produces a value)."""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Stmt:
|
|
11
|
+
"""Parent of everything that's a statement (i.e. does something)."""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class IntLiteral(Expr):
|
|
16
|
+
value: int
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class BoolLiteral(Expr):
|
|
21
|
+
value: bool
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class StringLiteral(Expr):
|
|
26
|
+
value: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class Identifier(Expr):
|
|
31
|
+
name: str
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class Call(Expr):
|
|
36
|
+
name: str
|
|
37
|
+
args: list[Expr]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class ThisExpr(Expr):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class New(Expr):
|
|
47
|
+
class_name: str
|
|
48
|
+
args: list[Expr]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class NewArray(Expr):
|
|
53
|
+
elem_type: str
|
|
54
|
+
size: Expr
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class Index(Expr):
|
|
59
|
+
arr: Expr
|
|
60
|
+
index: Expr
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class FieldAccess(Expr):
|
|
65
|
+
obj: Expr
|
|
66
|
+
field: str
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class MethodCall(Expr):
|
|
71
|
+
obj: Expr
|
|
72
|
+
method: str
|
|
73
|
+
args: list[Expr]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass
|
|
77
|
+
class UnaryOp(Expr):
|
|
78
|
+
op: str
|
|
79
|
+
operand: Expr
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass
|
|
83
|
+
class BinaryOp(Expr):
|
|
84
|
+
op: str
|
|
85
|
+
left: Expr
|
|
86
|
+
right: Expr
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclass
|
|
92
|
+
class VarDecl(Stmt):
|
|
93
|
+
var_type: str
|
|
94
|
+
name: str
|
|
95
|
+
init: Expr
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass
|
|
99
|
+
class Assign(Stmt):
|
|
100
|
+
target: Expr
|
|
101
|
+
value: Expr
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@dataclass
|
|
105
|
+
class ExprStmt(Stmt):
|
|
106
|
+
expr: Expr
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass
|
|
110
|
+
class PrintStmt(Stmt):
|
|
111
|
+
expr: Expr
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@dataclass
|
|
115
|
+
class If(Stmt):
|
|
116
|
+
cond: Expr
|
|
117
|
+
then_body: list[Stmt]
|
|
118
|
+
else_body: list[Stmt] | None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@dataclass
|
|
122
|
+
class While(Stmt):
|
|
123
|
+
cond: Expr
|
|
124
|
+
body: list[Stmt]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@dataclass
|
|
128
|
+
class Return(Stmt):
|
|
129
|
+
value: Expr | None
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@dataclass
|
|
133
|
+
class SuperCall(Stmt):
|
|
134
|
+
args: list[Expr]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@dataclass
|
|
140
|
+
class Param:
|
|
141
|
+
var_type: str
|
|
142
|
+
name: str
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@dataclass
|
|
146
|
+
class FuncDecl:
|
|
147
|
+
ret_type: str
|
|
148
|
+
name: str
|
|
149
|
+
params: list[Param]
|
|
150
|
+
body: list[Stmt]
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@dataclass
|
|
156
|
+
class FieldDecl:
|
|
157
|
+
var_type: str
|
|
158
|
+
name: str
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@dataclass
|
|
162
|
+
class MethodDecl:
|
|
163
|
+
ret_type: str
|
|
164
|
+
name: str
|
|
165
|
+
params: list[Param]
|
|
166
|
+
body: list[Stmt]
|
|
167
|
+
is_abstract: bool = False
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@dataclass
|
|
171
|
+
class MethodSig:
|
|
172
|
+
ret_type: str
|
|
173
|
+
name: str
|
|
174
|
+
params: list[Param]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@dataclass
|
|
178
|
+
class CtorDecl:
|
|
179
|
+
params: list[Param]
|
|
180
|
+
body: list[Stmt]
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@dataclass
|
|
184
|
+
class ClassDecl:
|
|
185
|
+
name: str
|
|
186
|
+
fields: list[FieldDecl]
|
|
187
|
+
methods: list[MethodDecl]
|
|
188
|
+
ctor: CtorDecl | None
|
|
189
|
+
bases: list[str] = field(default_factory=list)
|
|
190
|
+
is_abstract: bool = False
|
|
191
|
+
type_params: list[str] = field(default_factory=list)
|
|
192
|
+
parent: str | None = None
|
|
193
|
+
interfaces: list[str] = field(default_factory=list)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@dataclass
|
|
197
|
+
class InterfaceDecl:
|
|
198
|
+
name: str
|
|
199
|
+
methods: list[MethodSig]
|
tawla-0.1.0/tawla/cli.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""The `tawlac` command line — this is what runs when you type `tawlac ...`."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from . import __version__
|
|
8
|
+
from .compiler import run_source
|
|
9
|
+
from .project import entry_path, find_manifest, scaffold
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _build_parser():
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
prog="tawlac",
|
|
15
|
+
description="The Tawla compiler",
|
|
16
|
+
epilog="Run 'tawlac help <command>' for details on a command.",
|
|
17
|
+
)
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"-V", "--version", action="version", version=f"tawlac {__version__}",
|
|
20
|
+
help="show the tawlac version and exit",
|
|
21
|
+
)
|
|
22
|
+
sub = parser.add_subparsers(dest="command", metavar="<command>")
|
|
23
|
+
|
|
24
|
+
run_p = sub.add_parser("run", help="compile and run a .twl file or project (JIT)")
|
|
25
|
+
run_p.add_argument(
|
|
26
|
+
"file", nargs="?", type=Path,
|
|
27
|
+
help="a .twl file; omit to run the project in the current directory",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
build_p = sub.add_parser("build", help="emit a native binary (not implemented yet)")
|
|
31
|
+
build_p.add_argument("file", nargs="?", type=Path, help="a .twl file")
|
|
32
|
+
|
|
33
|
+
new_p = sub.add_parser("new", help="create a new project in a new directory")
|
|
34
|
+
new_p.add_argument("name", help="project name (also the directory created)")
|
|
35
|
+
|
|
36
|
+
sub.add_parser("init", help="create a project in the current directory")
|
|
37
|
+
sub.add_parser("version", help="print the tawlac version")
|
|
38
|
+
help_p = sub.add_parser("help", help="show help for tawlac or a command")
|
|
39
|
+
help_p.add_argument("topic", nargs="?", help="a command to describe")
|
|
40
|
+
|
|
41
|
+
return parser, sub
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def main(argv=None) -> int:
|
|
45
|
+
parser, sub = _build_parser()
|
|
46
|
+
args = parser.parse_args(argv)
|
|
47
|
+
|
|
48
|
+
if args.command in (None, "help"):
|
|
49
|
+
topic = getattr(args, "topic", None)
|
|
50
|
+
if topic and topic in sub.choices:
|
|
51
|
+
sub.choices[topic].print_help()
|
|
52
|
+
else:
|
|
53
|
+
parser.print_help()
|
|
54
|
+
return 0
|
|
55
|
+
|
|
56
|
+
if args.command == "version":
|
|
57
|
+
print(f"tawlac {__version__}")
|
|
58
|
+
return 0
|
|
59
|
+
if args.command == "run":
|
|
60
|
+
return _run(args.file)
|
|
61
|
+
if args.command == "build":
|
|
62
|
+
return _build()
|
|
63
|
+
if args.command == "new":
|
|
64
|
+
return _new(args.name)
|
|
65
|
+
if args.command == "init":
|
|
66
|
+
return _init()
|
|
67
|
+
parser.error(f"unknown command: {args.command}")
|
|
68
|
+
return 2
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _build() -> int:
|
|
72
|
+
print(
|
|
73
|
+
"tawlac build isn't implemented yet. For now, run programs with "
|
|
74
|
+
"'tawlac run' (they're JIT-compiled and run in memory). Emitting a "
|
|
75
|
+
"standalone native binary is planned.",
|
|
76
|
+
file=sys.stderr,
|
|
77
|
+
)
|
|
78
|
+
return 1
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _run(file: Path | None) -> int:
|
|
82
|
+
if file is not None:
|
|
83
|
+
src = file.read_text(encoding="utf-8")
|
|
84
|
+
else:
|
|
85
|
+
src = entry_path(find_manifest(Path.cwd())).read_text(encoding="utf-8")
|
|
86
|
+
return run_source(src)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _new(name: str) -> int:
|
|
90
|
+
root = Path(name)
|
|
91
|
+
scaffold(root, name)
|
|
92
|
+
print(f"Created project '{name}' (run it with: cd {name} && tawlac run)")
|
|
93
|
+
return 0
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _init() -> int:
|
|
97
|
+
root = Path.cwd()
|
|
98
|
+
scaffold(root, root.name)
|
|
99
|
+
print("Initialized project in the current directory (run it with: tawlac run)")
|
|
100
|
+
return 0
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
sys.exit(main())
|