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.
Files changed (45) hide show
  1. tawla-0.1.0/LICENSE +21 -0
  2. tawla-0.1.0/PKG-INFO +150 -0
  3. tawla-0.1.0/README.md +130 -0
  4. tawla-0.1.0/pyproject.toml +31 -0
  5. tawla-0.1.0/setup.cfg +4 -0
  6. tawla-0.1.0/tawla/__init__.py +3 -0
  7. tawla-0.1.0/tawla/__main__.py +8 -0
  8. tawla-0.1.0/tawla/ast_nodes.py +199 -0
  9. tawla-0.1.0/tawla/cli.py +104 -0
  10. tawla-0.1.0/tawla/codegen.py +815 -0
  11. tawla-0.1.0/tawla/compiler.py +61 -0
  12. tawla-0.1.0/tawla/gc_runtime.py +106 -0
  13. tawla-0.1.0/tawla/lexer.py +125 -0
  14. tawla-0.1.0/tawla/monomorphize.py +220 -0
  15. tawla-0.1.0/tawla/parser.py +517 -0
  16. tawla-0.1.0/tawla/project.py +62 -0
  17. tawla-0.1.0/tawla/sema.py +554 -0
  18. tawla-0.1.0/tawla/tokens.py +79 -0
  19. tawla-0.1.0/tawla.egg-info/PKG-INFO +150 -0
  20. tawla-0.1.0/tawla.egg-info/SOURCES.txt +43 -0
  21. tawla-0.1.0/tawla.egg-info/dependency_links.txt +1 -0
  22. tawla-0.1.0/tawla.egg-info/entry_points.txt +2 -0
  23. tawla-0.1.0/tawla.egg-info/requires.txt +1 -0
  24. tawla-0.1.0/tawla.egg-info/top_level.txt +1 -0
  25. tawla-0.1.0/tests/test_cli.py +48 -0
  26. tawla-0.1.0/tests/test_m1.py +58 -0
  27. tawla-0.1.0/tests/test_m10.py +52 -0
  28. tawla-0.1.0/tests/test_m11.py +54 -0
  29. tawla-0.1.0/tests/test_m12.py +56 -0
  30. tawla-0.1.0/tests/test_m13.py +60 -0
  31. tawla-0.1.0/tests/test_m15.py +26 -0
  32. tawla-0.1.0/tests/test_m16.py +32 -0
  33. tawla-0.1.0/tests/test_m17.py +45 -0
  34. tawla-0.1.0/tests/test_m18.py +63 -0
  35. tawla-0.1.0/tests/test_m19.py +64 -0
  36. tawla-0.1.0/tests/test_m2.py +43 -0
  37. tawla-0.1.0/tests/test_m3.py +83 -0
  38. tawla-0.1.0/tests/test_m4.py +72 -0
  39. tawla-0.1.0/tests/test_m5.py +64 -0
  40. tawla-0.1.0/tests/test_m6.py +86 -0
  41. tawla-0.1.0/tests/test_m7.py +69 -0
  42. tawla-0.1.0/tests/test_m8.py +55 -0
  43. tawla-0.1.0/tests/test_m9.py +81 -0
  44. tawla-0.1.0/tests/test_m9b.py +43 -0
  45. 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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """Tawla — a little programming language and its compiler, `tawlac`."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,8 @@
1
+ """Lets you run the CLI with `python -m tawla ...`."""
2
+
3
+ import sys
4
+
5
+ from .cli import main
6
+
7
+ if __name__ == "__main__":
8
+ sys.exit(main())
@@ -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]
@@ -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())