Benky is a small programming language with its own lexer, parser, and
interpreter, written in Dart. Programs are saved as .benky files and
run with the benky command-line tool.
benky run main.benkyThere are two roles here: building the benky tool, and using it.
You only need Dart for the first one.
-
Install the Dart SDK: https://dart.dev/get-dart
-
From the project folder:
dart pub get dart compile exe bin/benky.dart -o benky
This produces a single standalone native executable called
benky(orbenky.exeon Windows). It does not require Dart to run — the Dart runtime is statically baked into the binary. You can copy this one file to any machine of the same OS/architecture and it will run with nothing else installed. -
Put it on your PATH so you can call it from anywhere:
- macOS/Linux:
sudo mv benky /usr/local/bin/benky - Windows: move
benky.exeinto a folder that's on yourPATH(e.g.C:\Tools\, then add that folder to PATH via System Settings → Environment Variables).
- macOS/Linux:
If someone hands you the benky (or benky.exe) binary directly —
no Dart SDK, no pub get, nothing else to install. Just:
benky run main.benkyThat's the whole point of compiling it with dart compile exe: it's a
real, independent compiler/runtime in one file, the same way a C program
compiles to an .exe that doesn't need a C compiler to run.
benky run main.benky # run a benky programErrors print to stderr with a line number and a non-zero exit code (65 for syntax errors, 70 for runtime errors).
# everything after a # to end of line is a comment
let x = 5 # declare (required before use)
x = x + 1 # reassign
5 # number (stored as a double)
3.14
"hello" # string — supports escapes: \n \t \r \" \\
true
false
+ - * / % # arithmetic (+ also concatenates strings)
== != # equality
< > <= >= # comparison
= # assignment
-x # unary negation
( ) # grouping
print "hello"
print "line one\nline two"
if x > 4 {
print "big"
} else if x > 0 {
print "medium"
} else {
print "small"
}
let i = 0
while i < 3 {
print i
i = i + 1
}
fun add(a, b) {
return a + b
}
let result = add(2, 3)
return with no value ends the function early.
fun divide(a, b) {
if b == 0 {
throw "cannot divide by zero"
}
return a / b
}
Throwing prints Uncaught error: <value> and exits the program with
code 70. There is no try/catch yet — every throw is unrecoverable.
| Function | Description |
|---|---|
len(s) |
length of a string |
str(v) |
convert a value to a string |
num(s) |
parse a string into a number |
http_get(url) |
blocking HTTP GET, returns the response body as a string |
These draw directly into the terminal window using ANSI escape codes — no GUI window, just live text drawn in your existing cmd/terminal.
| Function | Description |
|---|---|
ui_clear() |
clear the screen |
ui_hide_cursor() / ui_show_cursor() |
toggle cursor visibility |
ui_text(x, y, text, color?) |
print text at a position (supports \n for multi-line) |
ui_box(x, y, w, h, title?, color?) |
draw a bordered box |
ui_button(x, y, label, color?) |
draw a [ label ] button (visual only — no click handling) |
ui_input(x, y, prompt?) |
blocking read of a line of input at a position |
Valid color names: black red green yellow blue magenta cyan white.
Example:
ui_clear()
ui_box(2, 1, 40, 5, "My App", "cyan")
ui_text(5, 3, "Hello there!", "green")
let name = ui_input(2, 6, "Name: ")
ui_text(2, 8, "Hi, " + name + "!", "magenta")
No lists/arrays, no maps/objects, no classes, no for loops, no
&&/|| logical operators, no try/catch, no modules/imports,
no closures over outer function scopes (functions only see globals
- their own locals). These are the natural next features if you want to keep growing the language.
benky/
bin/benky.dart CLI entry point ("benky run main.benky")
lib/src/token.dart token definitions
lib/src/lexer.dart text -> tokens
lib/src/ast.dart AST node classes
lib/src/parser.dart tokens -> AST
lib/src/interpreter.dart walks the AST and executes it
lib/src/ui.dart terminal UI drawing primitives
main.benky example program