kabir-lang 1.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.
- kabir_lang-1.1.0/LICENSE +21 -0
- kabir_lang-1.1.0/PKG-INFO +352 -0
- kabir_lang-1.1.0/README.md +327 -0
- kabir_lang-1.1.0/kabir/__init__.py +15 -0
- kabir_lang-1.1.0/kabir/__main__.py +8 -0
- kabir_lang-1.1.0/kabir/ast_nodes.py +167 -0
- kabir_lang-1.1.0/kabir/builtins.py +237 -0
- kabir_lang-1.1.0/kabir/cli.py +165 -0
- kabir_lang-1.1.0/kabir/errors.py +49 -0
- kabir_lang-1.1.0/kabir/interpreter.py +668 -0
- kabir_lang-1.1.0/kabir/lexer.py +206 -0
- kabir_lang-1.1.0/kabir/parser.py +400 -0
- kabir_lang-1.1.0/kabir/stdlib.py +265 -0
- kabir_lang-1.1.0/kabir_lang.egg-info/PKG-INFO +352 -0
- kabir_lang-1.1.0/kabir_lang.egg-info/SOURCES.txt +27 -0
- kabir_lang-1.1.0/kabir_lang.egg-info/dependency_links.txt +1 -0
- kabir_lang-1.1.0/kabir_lang.egg-info/entry_points.txt +2 -0
- kabir_lang-1.1.0/kabir_lang.egg-info/top_level.txt +1 -0
- kabir_lang-1.1.0/pyproject.toml +38 -0
- kabir_lang-1.1.0/setup.cfg +4 -0
- kabir_lang-1.1.0/tests/test_builtins.py +129 -0
- kabir_lang-1.1.0/tests/test_errors.py +76 -0
- kabir_lang-1.1.0/tests/test_examples.py +134 -0
- kabir_lang-1.1.0/tests/test_import.py +348 -0
- kabir_lang-1.1.0/tests/test_interpreter.py +179 -0
- kabir_lang-1.1.0/tests/test_lexer.py +117 -0
- kabir_lang-1.1.0/tests/test_parser.py +156 -0
- kabir_lang-1.1.0/tests/test_stdlib.py +180 -0
- kabir_lang-1.1.0/tests/test_string_methods.py +176 -0
kabir_lang-1.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Afrain Kabir Rafid
|
|
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,352 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kabir-lang
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Kabir — a small, friendly programming language, built from scratch in Python.
|
|
5
|
+
Author: Afrain Kabir Rafid
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/afrainkabirrafid/kabir
|
|
8
|
+
Project-URL: Repository, https://github.com/afrainkabirrafid/kabir
|
|
9
|
+
Keywords: programming-language,interpreter,kabir
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Education
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Interpreters
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# Kabir
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+

|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
**Kabir is a small, friendly programming language, built from scratch in Python — no dependencies, no magic, just a lexer, a parser, and a tree-walking interpreter you can read in an afternoon.**
|
|
33
|
+
|
|
34
|
+
## What is Kabir?
|
|
35
|
+
|
|
36
|
+
Kabir is a complete little language: variables, numbers, strings with interpolation, arrays, dicts, `if`/`elif`/`else`, `while` and `for` loops, first-class functions with closures and recursion, `import` for `.kbr` files, string methods, and 15 core built-in functions plus 12 standard-library functions — all in about 1,700 lines of plain, dependency-free Python. Programs live in `.kbr` files and run with `python -m kabir run`.
|
|
37
|
+
|
|
38
|
+
It is a **tree-walking interpreter**: source code is lexed into tokens, parsed into an abstract syntax tree (AST), and the interpreter walks that tree and runs it directly. There is no JIT compiler and no native compilation — Kabir trades speed for clarity, so the whole implementation is easy to read, learn from, and hack on.
|
|
39
|
+
|
|
40
|
+
## Why Kabir exists
|
|
41
|
+
|
|
42
|
+
Kabir is named to honour the **Kabir family** of its creator, **Afrain Kabir Rafid**. It started as a from-scratch language-building project: no parser generators, no existing language renamed, no `eval`/`exec` — every token, grammar rule, and runtime behaviour was written by hand.
|
|
43
|
+
|
|
44
|
+
## Quickstart
|
|
45
|
+
|
|
46
|
+
You need **Python 3.8 or newer** (the code avoids newer-only features; it was developed and tested on Python 3.12.3 — Python 3.8 itself was not run here). There is nothing to install: Kabir uses only the Python standard library.
|
|
47
|
+
|
|
48
|
+
```console
|
|
49
|
+
$ git clone https://github.com/afrainkabirrafid/kabir.git
|
|
50
|
+
$ cd kabir
|
|
51
|
+
$ python -m kabir run examples/hello.kbr
|
|
52
|
+
Hello, Rafid!
|
|
53
|
+
Welcome to Kabir version 1.1.0.
|
|
54
|
+
2 + 3 = 5
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
That's it — clone, run. (See [Usage](#usage) for the `kabir` command itself.)
|
|
58
|
+
|
|
59
|
+
## Hello, World
|
|
60
|
+
|
|
61
|
+
Save this as `hello.kbr`:
|
|
62
|
+
|
|
63
|
+
```kabir
|
|
64
|
+
let name = "Rafid"
|
|
65
|
+
let language = "Kabir"
|
|
66
|
+
|
|
67
|
+
print("Hello, {name}!")
|
|
68
|
+
print("Welcome to {language} version 1.1.0.")
|
|
69
|
+
print("2 + 3 = {2 + 3}")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Run it:
|
|
73
|
+
|
|
74
|
+
```console
|
|
75
|
+
$ python -m kabir run hello.kbr
|
|
76
|
+
Hello, Rafid!
|
|
77
|
+
Welcome to Kabir version 1.1.0.
|
|
78
|
+
2 + 3 = 5
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
All commands work both as `python -m kabir ...` (zero-install, from a fresh clone) and as `kabir ...` once the launcher or the package is on your `PATH` (see below).
|
|
84
|
+
|
|
85
|
+
| Command | What it does |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `python -m kabir run <file.kbr>` | Run a Kabir program |
|
|
88
|
+
| `python -m kabir <file.kbr>` | Same — a bare `.kbr` argument is run directly |
|
|
89
|
+
| `python -m kabir repl` | Start the interactive REPL |
|
|
90
|
+
| `python -m kabir` | Start the REPL (no arguments) |
|
|
91
|
+
| `python -m kabir --help` | Show help (`-h` and `help` work too) |
|
|
92
|
+
| `python -m kabir --version` | Print the version (`-v` and `version` work too) |
|
|
93
|
+
|
|
94
|
+
```console
|
|
95
|
+
$ python -m kabir --version
|
|
96
|
+
kabir 1.1.0
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### The `kabir` command
|
|
100
|
+
|
|
101
|
+
The repository ships an executable launcher at `bin/kabir`:
|
|
102
|
+
|
|
103
|
+
```console
|
|
104
|
+
$ ./bin/kabir --version
|
|
105
|
+
kabir 1.1.0
|
|
106
|
+
$ ./bin/kabir run examples/fizzbuzz.kbr
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
It lives in `bin/` for a real reason: a repo-root file named `kabir` cannot coexist with the `kabir/` package directory (same path), so the launcher is `bin/kabir`, not `./kabir`. If you install the package with pip (see `pyproject.toml`), the `kabir` command is installed on your `PATH` automatically.
|
|
110
|
+
|
|
111
|
+
### The REPL
|
|
112
|
+
|
|
113
|
+
```console
|
|
114
|
+
$ python -m kabir repl
|
|
115
|
+
Kabir 1.1.0 -- type 'exit' or press Ctrl-D to leave.
|
|
116
|
+
kabir> let x = 5
|
|
117
|
+
kabir> x + 1
|
|
118
|
+
6
|
|
119
|
+
kabir> "hi {x}"
|
|
120
|
+
hi 5
|
|
121
|
+
kabir> exit
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Expression statements print their value; other statements print nothing. Multi-line input (for example a `func` definition) is supported — the REPL waits with a `... ` prompt until the braces balance. Type `exit` or `quit`, or press Ctrl-D, to leave.
|
|
125
|
+
|
|
126
|
+
### Exit codes
|
|
127
|
+
|
|
128
|
+
| Code | Meaning |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| `0` | Program ran successfully (or `--help` / `--version` was shown) |
|
|
131
|
+
| `1` | A Kabir error (lex, parse, or runtime) or runaway recursion |
|
|
132
|
+
| `2` | A usage error — unknown command, missing file argument, unreadable file |
|
|
133
|
+
|
|
134
|
+
## A tour of the language
|
|
135
|
+
|
|
136
|
+
```kabir
|
|
137
|
+
# Comments start with # and run to the end of the line.
|
|
138
|
+
|
|
139
|
+
let name = "Rafid"
|
|
140
|
+
let scores = [64, 34, 25, 12, 22, 11, 90]
|
|
141
|
+
|
|
142
|
+
# Strings interpolate any expression inside { ... }.
|
|
143
|
+
print("Hello, {name}! You have {len(scores)} scores.")
|
|
144
|
+
|
|
145
|
+
# if / elif / else, while, and for over arrays, strings, dicts, or range().
|
|
146
|
+
for score in scores {
|
|
147
|
+
if score >= 50 {
|
|
148
|
+
print("{score} is a pass")
|
|
149
|
+
} elif score >= 40 {
|
|
150
|
+
print("{score} is close")
|
|
151
|
+
} else {
|
|
152
|
+
print("{score} needs work")
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let total = 0
|
|
157
|
+
for n in scores { total += n }
|
|
158
|
+
print("Average: {total / len(scores)}")
|
|
159
|
+
|
|
160
|
+
# Functions are first-class values; closures capture their surroundings.
|
|
161
|
+
func make_adder(n) {
|
|
162
|
+
return func(x) { return x + n }
|
|
163
|
+
}
|
|
164
|
+
let add5 = make_adder(5)
|
|
165
|
+
print(add5(10)) # 15
|
|
166
|
+
|
|
167
|
+
# Dicts have string keys.
|
|
168
|
+
let user = {"name": "Rafid", "language": "Kabir"}
|
|
169
|
+
print(user["name"])
|
|
170
|
+
print(keys(user))
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Expected output:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
Hello, Rafid! You have 7 scores.
|
|
177
|
+
64 is a pass
|
|
178
|
+
34 needs work
|
|
179
|
+
25 needs work
|
|
180
|
+
12 needs work
|
|
181
|
+
22 needs work
|
|
182
|
+
11 needs work
|
|
183
|
+
90 is a pass
|
|
184
|
+
Average: 36.857142857142854
|
|
185
|
+
15
|
|
186
|
+
Rafid
|
|
187
|
+
[name, language]
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
A few things worth noticing:
|
|
191
|
+
|
|
192
|
+
- **One number type.** There is no separate `int`/`float`: `5.0` prints as `5`, `7 / 2` is `3.5`, and `6 / 3` is `2` (an exact integer division stays an integer).
|
|
193
|
+
- **Truthiness is broad.** `0`, `""`, `[]`, `{}`, `false`, and `null` are falsy; everything else — including non-empty strings, arrays, and functions — is truthy.
|
|
194
|
+
- **`and` / `or` return values, not booleans.** `false or "fallback"` is `"fallback"`; `true and "yes"` is `"yes"`. They short-circuit: the right side is only evaluated when needed.
|
|
195
|
+
- **Negative indexes work.** `[10, 20, 30][-1]` is `30`, and `"abc"[-1]` is `"c"`.
|
|
196
|
+
- **Errors are friendly.** A mistake gives you `file:line:col`, the offending source line, and a caret — never a Python traceback. See [Errors](#errors) below.
|
|
197
|
+
|
|
198
|
+
The full reference — every construct, every built-in, each with a runnable example and its exact output — is in [docs/LANGUAGE.md](docs/LANGUAGE.md).
|
|
199
|
+
|
|
200
|
+
## Examples
|
|
201
|
+
|
|
202
|
+
All ten example files live in [`examples/`](examples/) and are covered by the test suite: nine runnable programs, plus `greet-lib.kbr`, a small library file that `import-demo.kbr` loads.
|
|
203
|
+
|
|
204
|
+
| File | What it shows |
|
|
205
|
+
| --- | --- |
|
|
206
|
+
| [`examples/hello.kbr`](examples/hello.kbr) | First program: variables and string interpolation |
|
|
207
|
+
| [`examples/fizzbuzz.kbr`](examples/fizzbuzz.kbr) | `for` over `range()`, `if`/`elif`/`else`, `%` |
|
|
208
|
+
| [`examples/fibonacci.kbr`](examples/fibonacci.kbr) | Recursion — `fib(n)`, first 15 numbers |
|
|
209
|
+
| [`examples/primes.kbr`](examples/primes.kbr) | `while` loop, helper function, primes up to 100 |
|
|
210
|
+
| [`examples/sorting.kbr`](examples/sorting.kbr) | Bubble sort, index assignment, arrays as values |
|
|
211
|
+
| [`examples/guessing-game.kbr`](examples/guessing-game.kbr) | Interactive loop with `input()` (the secret is a random number from `randint(1, 100)`) |
|
|
212
|
+
| [`examples/import-demo.kbr`](examples/import-demo.kbr) | `import "greet-lib.kbr"` — load and reuse code from another file |
|
|
213
|
+
| [`examples/todo.kbr`](examples/todo.kbr) | In-memory todo CLI: `add`, `list`, `done`, `quit` |
|
|
214
|
+
| [`examples/calculator.kbr`](examples/calculator.kbr) | Interactive calculator; accepts `2+3` and `2 + 3`, handles division by zero |
|
|
215
|
+
|
|
216
|
+
Try the interactive ones by piping input, for example:
|
|
217
|
+
|
|
218
|
+
```console
|
|
219
|
+
$ printf '2 + 3\n10 / 4\nquit\n' | python -m kabir run examples/calculator.kbr
|
|
220
|
+
Calculator -- type like '2 + 3', or 'quit' to stop.
|
|
221
|
+
calc> 2 + 3 = 5
|
|
222
|
+
calc> 10 / 4 = 2.5
|
|
223
|
+
calc> Goodbye!
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Built-ins
|
|
227
|
+
|
|
228
|
+
Kabir ships 15 core built-in functions, available in every program with no import:
|
|
229
|
+
|
|
230
|
+
| Function | Purpose |
|
|
231
|
+
| --- | --- |
|
|
232
|
+
| `print(...)` | Print values, space-separated, with a newline |
|
|
233
|
+
| `input(prompt?)` | Read a line from the user (prompt is optional) |
|
|
234
|
+
| `len(x)` | Length of a string, array, or dict |
|
|
235
|
+
| `str(x)` | Convert a value to a string |
|
|
236
|
+
| `num(x)` | Parse a string (or pass a number through) as a number |
|
|
237
|
+
| `type(x)` | Type name: `"number"`, `"string"`, `"boolean"`, `"null"`, `"array"`, `"dict"`, `"function"` |
|
|
238
|
+
| `range(n)` / `range(a, b)` | List of whole numbers: `0..n-1`, or `a..b-1` |
|
|
239
|
+
| `push(array, value)` | Append to an array (returns the array) |
|
|
240
|
+
| `pop(array)` | Remove and return the last item |
|
|
241
|
+
| `sqrt(x)` | Square root |
|
|
242
|
+
| `pow(x, y)` | `x` to the power of `y` |
|
|
243
|
+
| `abs(x)` | Absolute value |
|
|
244
|
+
| `keys(dict)` | List of a dict's keys, in insertion order |
|
|
245
|
+
| `int(x)` | Convert to an integer (truncates) |
|
|
246
|
+
| `float(x)` | Convert to a float |
|
|
247
|
+
|
|
248
|
+
Each one is documented with a runnable example in [docs/LANGUAGE.md](docs/LANGUAGE.md#built-in-functions).
|
|
249
|
+
|
|
250
|
+
### Standard library
|
|
251
|
+
|
|
252
|
+
On top of the core built-ins, Kabir ships 12 standard-library functions — also plain globals, no import needed — plus the constants `pi` and `e`, and 9 string methods (see [docs/LANGUAGE.md](docs/LANGUAGE.md#standard-library)):
|
|
253
|
+
|
|
254
|
+
| Function | Purpose |
|
|
255
|
+
| --- | --- |
|
|
256
|
+
| `randint(a, b)` | Random whole number from `a` to `b`, both ends included |
|
|
257
|
+
| `randrange(n)` / `randrange(a, b)` | One random number from a `range()` |
|
|
258
|
+
| `choice(array)` | One random item from an array |
|
|
259
|
+
| `shuffle(array)` | Shuffle an array in place (returns the array) |
|
|
260
|
+
| `seed(n)` | Seed the random sequence, so it is repeatable |
|
|
261
|
+
| `floor(x)` / `ceil(x)` | Round a number down / up to a whole number |
|
|
262
|
+
| `sin(x)` / `cos(x)` / `tan(x)` | Trigonometry, in radians |
|
|
263
|
+
| `log(x)` | Natural logarithm |
|
|
264
|
+
| `exp(x)` | `e` to the power of `x` |
|
|
265
|
+
| `pi`, `e` | The constants `3.141592653589793` and `2.718281828459045` |
|
|
266
|
+
|
|
267
|
+
String methods live on the string itself: `"abc".upper()`, `" a ".strip()`, `"a,b".split(",")`, `", ".join(["a", "b"])`, `"hello".contains("ell")`, `"hello".starts_with("he")`, `"hello".ends_with("lo")`, `"aaa".replace("a", "b")`, and `"ABC".lower()`.
|
|
268
|
+
|
|
269
|
+
Code can also be shared across files with `import "other.kbr"` — see [docs/LANGUAGE.md](docs/LANGUAGE.md#import).
|
|
270
|
+
|
|
271
|
+
## Errors
|
|
272
|
+
|
|
273
|
+
Kabir errors always look like this — location, source line, caret, plain message:
|
|
274
|
+
|
|
275
|
+
```text
|
|
276
|
+
/tmp/demo.kbr:1:9: Undefined variable 'y' -- it was never defined with 'let'. Check the spelling
|
|
277
|
+
let x = y
|
|
278
|
+
^
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
```text
|
|
282
|
+
/tmp/demo.kbr:1:9: Division by zero -- the number after '/' cannot be 0
|
|
283
|
+
print(1 / 0)
|
|
284
|
+
^
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Strings even get a hint when you use the wrong quotes:
|
|
288
|
+
|
|
289
|
+
```text
|
|
290
|
+
/tmp/demo.kbr:1:7: Strings use double quotes, not single quotes -- write "hello" instead of 'hello'
|
|
291
|
+
print('hi')
|
|
292
|
+
^
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Architecture
|
|
296
|
+
|
|
297
|
+
In plain words, running a program goes through four stages:
|
|
298
|
+
|
|
299
|
+
1. **Lexer** (`kabir/lexer.py`) — turns source text into tokens (`NUMBER`, `STRING`, `IDENT`, `KEYWORD`, `OP`, `PUNCT`, `NEWLINE`, `EOF`). Strings are tokenised into literal/interpolation parts here.
|
|
300
|
+
2. **Parser** (`kabir/parser.py`) — a hand-written recursive-descent parser that turns tokens into an AST, following a precedence ladder from `or` down to calls and indexing. `**` is right-associative; a `{` followed by a string key and `:` is read as a dict literal, not a block.
|
|
301
|
+
3. **AST** (`kabir/ast_nodes.py`) — one small class per node type (`LetStmt`, `IfStmt`, `BinaryOp`, …), each carrying its source line and column so errors can point at the exact spot.
|
|
302
|
+
4. **Interpreter** (`kabir/interpreter.py`) — walks the AST directly. Lexical scoping is a chain of `Environment` objects; closures capture their defining environment; `return`/`break`/`continue` are implemented as internal signals. Built-ins live in `kabir/builtins.py` and are registered into the global environment at startup.
|
|
303
|
+
|
|
304
|
+
The full internals guide — token types, the precedence ladder, environment/scoping rules, evaluator dispatch, error rendering, and the CLI/REPL flow — is in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
305
|
+
|
|
306
|
+
## Tests
|
|
307
|
+
|
|
308
|
+
Zero dependencies here too — the suite is plain `unittest`, run by a small runner:
|
|
309
|
+
|
|
310
|
+
```console
|
|
311
|
+
$ python tests/run_tests.py
|
|
312
|
+
Ran 176 tests in 0.818s
|
|
313
|
+
|
|
314
|
+
OK
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
The 176 tests cover the lexer, parser, interpreter, built-ins, standard library, string methods, imports, errors, and every example in `examples/`. Run them before sending a pull request (see [CONTRIBUTING.md](CONTRIBUTING.md)).
|
|
318
|
+
|
|
319
|
+
## Honest limits
|
|
320
|
+
|
|
321
|
+
Kabir 1.1.0 is a small language, and it is honest about what it is not:
|
|
322
|
+
|
|
323
|
+
- **No JIT, no native compilation.** It is a tree-walking interpreter; it is fast enough for scripts and learning, not for number-crunching.
|
|
324
|
+
- **`import` loads other `.kbr` files** — a program can be split across files, and each file runs once (see the [roadmap](#roadmap) for what is still missing).
|
|
325
|
+
- **No package manager.** There is no package registry; `import` loads a file by path, and the standard library is the 15 core built-ins plus the `random`/`math` functions and string methods listed above.
|
|
326
|
+
- **No file I/O, no dates, no networking.** The only way in or out is `print` and `input` (plus `import`, which reads `.kbr` files).
|
|
327
|
+
- **Recursion depth is capped** at 500 nested calls, and there is no tail-call optimisation.
|
|
328
|
+
- **One number type** means no separate integer/float semantics; a power that overflows float range fails with a friendly error, while integer powers use arbitrary-precision integers.
|
|
329
|
+
|
|
330
|
+
## Roadmap
|
|
331
|
+
|
|
332
|
+
Roughly in order, and open to discussion:
|
|
333
|
+
|
|
334
|
+
1. **`import` for `.kbr` files** — load and reuse code across files. — done in 1.1.0
|
|
335
|
+
2. **Standard-library modules** — starting with `random` (so the guessing game gets a real secret), then string helpers and math. — done in 1.1.0 (random, math, and string methods as built-ins)
|
|
336
|
+
3. **A formatter** (`kabir fmt`) for canonical `.kbr` style.
|
|
337
|
+
4. **Pip packaging** — `pyproject.toml` is already in the repo; publishing to PyPI so `pip install kabir` gives you the `kabir` command.
|
|
338
|
+
5. **More of the language** — `else` on loops is not planned; instead: string methods — done in 1.1.0, a `switch`-style construct only if it earns its place, and better REPL history.
|
|
339
|
+
|
|
340
|
+
Ideas and pull requests are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
341
|
+
|
|
342
|
+
## Contributing
|
|
343
|
+
|
|
344
|
+
Fork the repo, make a small focused change, add tests for any new behaviour, and run the suite (`python tests/run_tests.py`). The full guide — style rules (stdlib only, no `eval`/`exec`), how to add a built-in, and what a good PR looks like — is in [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
345
|
+
|
|
346
|
+
## License
|
|
347
|
+
|
|
348
|
+
Kabir is released under the MIT License. See [LICENSE](LICENSE).
|
|
349
|
+
|
|
350
|
+
## Author
|
|
351
|
+
|
|
352
|
+
Created by **Afrain Kabir Rafid** — named to honour his Kabir family.
|