A snake inside of a gear shape

Hebi

This repository hosts a dynamically typed language, its compiler, and VM.

Usage

Everything is still in flux, and many interesting features are not yet implemented (see issues), but it can already execute some basic code:

```rust use hebi::Hebi;

let vm = Hebi::new();

println!("{}", vm.eval::("1 + 1").unwrap());

vm.eval::<()>(r#"

class Test: v = 10 fn test(self): print self.v

t := Test(v=100) t.test() # prints 100 t.v = 20 t.test() # prints 20

"#).unwrap(); ```

A general overview of the language's currently implemented syntax and semantics is available in the design file. To see more examples, visit src/tests or samples[^1]. Some features are currently only documented in the changelog.

The language also has a REPL at cli:

``` $ cargo run -p cli Hebi REPL v0.0.0 Press CTRL-D to exit

```

Development

All you need to contribute is a recent version of the Rust compiler. See Getting Started for how to obtain it.

Other tooling that is highly recommended: - rust-analyzer, a Rust language server for your editor of choice - clippy, a helpful linter - just, which is used to run various commands

Repository structure

Goals, Design and Implementation

The main goal is to have a reasonably feature-full language with simple (as in, can fit in a single person's head), unsurprising semantics that's easily embeddable within a Rust program. It isn't a priority for it to be a standalone, general-purpose language, but it isn't out of the question.

The language design is heavily inspired by Python. Hebi blatantly copies most of Python's syntax, and a lot of the semantics, but some parts have been removed, or changed. Python is very difficult to optimize, and has many quirks which make it unsuitable for embedding within another program.

The implementation borrows a lot of ideas from V8. Ideas shamelessly stolen include: - Bytecode encoded with variable-width operands using a prefix opcode. This means there is no limit to the number of variables or constants in a function, the maximum distance of a jump, etc. It also results in very compact bytecode. - An implicit accumulator to store temporary values. This greatly reduces call frame sizes and the number of register moves. It also helps make the bytecode more compact, because every instruction operating on two or more registers now needs one less register operand. - Function calling convention which copies arguments into the new call frame, instead of referencing them directly. This opens up the implementation space for stackless coroutines. - Module variables on top of globals. This allows for a clear separation of concerns into different modules, as functions declared in different modules may not access the variables in each others' global scopes, unless they are explicitly imported.

Currently, the VM uses reference counting as its garbage collection strategy, but the plan is to implement a tracing garbage collector at some point. Some possible approaches are described in LuaJIT's wiki.

Why Hebi?

I thought it was appropritate, because the language is in the Python family, and Hebi (蛇) means snake in Japanese.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.