https://github.com/healeycodes/hoot-language
🦉 A general-purpose interpreted scripting language with an event loop.
https://github.com/healeycodes/hoot-language
crafting-interpreters lox lox-language programming-language tree-walk-interpreter
Last synced: 8 months ago
JSON representation
🦉 A general-purpose interpreted scripting language with an event loop.
- Host: GitHub
- URL: https://github.com/healeycodes/hoot-language
- Owner: healeycodes
- License: mit
- Created: 2021-03-13T22:49:52.000Z (almost 5 years ago)
- Default Branch: main
- Last Pushed: 2021-03-14T22:23:44.000Z (almost 5 years ago)
- Last Synced: 2025-05-08T02:39:35.829Z (9 months ago)
- Topics: crafting-interpreters, lox, lox-language, programming-language, tree-walk-interpreter
- Language: Python
- Homepage:
- Size: 646 KB
- Stars: 8
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Hoot Lang 🦉
Hoot is a general-purpose interpreted scripting language with an event loop. It's dynamically typed, with classes, inheritance, and closures. It's an implementation and extension of the [Lox](https://github.com/munificent/craftinginterpreters) Programming language.
Hoot extends Lox by introducing an event loop for non-blocking I/O, more complex types (string, list, map), and a tiny standard library (web requests, file reading/writing, delay functions).
Why? I wrote it to learn more about interpreters! [Crafting Interpreters](https://craftinginterpreters.com/contents.html) is a useful handbook and I strongly recommend it.
Hoot uses (mostly-typed) Python 3.8 and no additional libraries.
Run the integration tests with `python test_hoot.py`. It should also pass `mypy .` with no issues.
Run a program with `python hoot.py ./file.hoot`.
Open the REPL with `python hoot.py`.
* [Example programs](#example-programs)
* [Language reference](#language-reference)
* [Standard library](#standard-library)
* [License](#license)
## Example programs
Print the headers from a HTTP response.
```
fun print_headers(response) {
print response.headers; // This is a map()
}
request("https://google.com", nil, nil, "GET", print_headers);
print "This message will print before print_headers is called.";
```
Delay a function.
```
fun make_logger(time) {
fun logger () {
print string(time) + "ms";
}
return logger;
}
delay(make_logger(0), 0); // 0ms delay
print "This message prints first because each task 'Runs-to-completion' a la JavaScript";
delay(make_logger(50), 50);
delay(make_logger(100), 100);
```
Everyone's favorite inefficient sorting algorithm.
```
fun bubble_sort(numbers) {
for (let i = 0; i < numbers.length() - 1; i = i + 1) {
for (let j = 0; j < numbers.length() - 1; j = j + 1) {
if (numbers.at(j) > numbers.at(j + 1)) {
let tmp = numbers.at(j);
numbers.alter(j, numbers.at(j + 1));
numbers.alter(j + 1, tmp);
}
}
}
return numbers;
}
let unordered_numbers = list(1, -1, 0.5, 12, 2);
print bubble_sort(unordered_numbers);
```
Read a file, print the length, append to it, then print the new length.
```
fun show_length(text) {
print "File length: " + string(text.length());
}
fun show_original_length(text) {
print "File length: " + string(text.length());
fun callback() {
read("examples/test_file.txt", show_length);
}
write("examples/test_file.txt", "a", "More text", callback);
}
read("examples/test_file.txt", show_original_length);
```
## Language reference
Variables
```
let bool = true; // or `false`
let num = 0; // All numbers are floats and support `+`, `-`, `*`, `/`
let raw = "raw string"; // Strings support `+`
// Compare with `==`
```
Types
```
// string has `at(index)`, `alter(index, element)`, `length()`
let some_text = string("Hello, World!");
some_text.alter(12, "?");
print some_text; // "Hello, World?"
// list has `at(index)`, `alter(index, element)`, `length()`, `push(element)`, and `pop()`
let some_numbers = list(1, -1, 0.5, 12, 2);
print some_numbers.at(1); // -1
// map has `get(key)` and `set(key, element)`
let food_store = map();
food_store.set("burgers", 20);
```
Loops
```
for (let i = 0; i < 5; i = i + 1) {
print i;
}
while (true) {
print "Um.. let's quit this infinite loop.;
break;
}
```
Functions/closures
```
fun make_adder(y) {
fun adder(x) {
return x + y;
}
return adder;
}
let my_adder = make_adder(10);
adder(5); // 15
```
Classes
```
// Lifted this example straight from chapter 13 of Crafting Interpreters
class Doughnut {
init() {
this.ending_mark = "!";
}
cook() {
print "Fry until golden brown.";
}
}
class BostonCream < Doughnut {
cook() {
super.cook();
print "Pipe full of custard and coat with chocolate" + this.ending_mark;
}
}
BostonCream().cook();
```
## Standard library
See `native.py` for implementation details.
`input(prompt)` — Returns standard input.
`read(file_path, callback)` — reads a UTF-8 compatible file and passes it as the first argument to _callback_.
`write(file_path, mode, data, callback)` — writes _data_ to a file. _mode_ is the same as Python's `open`. Calls _callback_ without passing any arguments.
`clock()` — UNIX seconds.
`delay(milliseconds, callback)` — like setTimeout in JavaScript.
`request(url, data, headers, http_method, callback)` — _callback_ is passed a response instance with the fields `body` and `header` which can be accessed via `.` dot.
## License
MIT.