All Projects → danii → hematita

danii / hematita

Licence: GPL-3.0 license
A memory safe Lua interpreter

Programming Languages

rust
11053 projects
lua
6591 projects

Projects that are alternatives of or similar to hematita

jaws
Jaws is an invisible programming language! Inject invisible code into other languages and files! Created for security research -- see blog post
Stars: ✭ 204 (+72.88%)
Mutual labels:  interpreter, virtual-machine
vein
🔮⚡️Vein is an open source high-level strictly-typed programming language with a standalone OS, arm and quantum computing support.
Stars: ✭ 31 (-73.73%)
Mutual labels:  interpreter, virtual-machine
openj9
Eclipse OpenJ9: A Java Virtual Machine for OpenJDK that's optimized for small footprint, fast start-up, and high throughput. Builds on Eclipse OMR (https://github.com/eclipse/omr) and combines with the Extensions for OpenJDK for OpenJ9 repo.
Stars: ✭ 2,973 (+2419.49%)
Mutual labels:  interpreter, virtual-machine
Laythe
A gradually typed language originally based on the crafting interpreters series
Stars: ✭ 58 (-50.85%)
Mutual labels:  interpreter, virtual-machine
Arduino-FVM
Byte Token Threaded Forth Virtual Machine (FVM) for Arduino
Stars: ✭ 35 (-70.34%)
Mutual labels:  interpreter, virtual-machine
embed
An embeddable, tiny Forth interpreter with metacompiler.
Stars: ✭ 80 (-32.2%)
Mutual labels:  interpreter, virtual-machine
minima
A fast, byte-code interpreted language
Stars: ✭ 43 (-63.56%)
Mutual labels:  interpreter, virtual-machine
Tagha
Minimal, low-level, fast, and self-contained register-based bytecode virtual machine/runtime environment.
Stars: ✭ 101 (-14.41%)
Mutual labels:  interpreter, virtual-machine
ol
Otus Lisp (Ol in short) is a purely* functional dialect of Lisp.
Stars: ✭ 157 (+33.05%)
Mutual labels:  interpreter, virtual-machine
RSqueak
A Squeak/Smalltalk VM written in RPython.
Stars: ✭ 78 (-33.9%)
Mutual labels:  interpreter, virtual-machine
ciao
Ciao is a modern Prolog implementation that builds up from a logic-based simple kernel designed to be portable, extensible, and modular.
Stars: ✭ 190 (+61.02%)
Mutual labels:  interpreter, virtual-machine
jingle
🔔 Jingle is a dynamically-typed, multi-paradigm programming language designed for humans and machines.
Stars: ✭ 34 (-71.19%)
Mutual labels:  interpreter, virtual-machine
Freeze-OS
An Operating System that runs on top of an interpreter.
Stars: ✭ 24 (-79.66%)
Mutual labels:  interpreter, virtual-machine
lunatic
lunatic: a toy lua interpreter
Stars: ✭ 16 (-86.44%)
Mutual labels:  interpreter, virtual-machine
wizard-engine
Research WebAssembly Engine
Stars: ✭ 164 (+38.98%)
Mutual labels:  interpreter, virtual-machine
thislang
A subset of javascript implemented in that subset of javascript. Yes, it can run itself.
Stars: ✭ 31 (-73.73%)
Mutual labels:  interpreter, virtual-machine
clox
A virtual machine and a tree-walk interpreter for the Lox programming language in C89 🌀
Stars: ✭ 38 (-67.8%)
Mutual labels:  interpreter, virtual-machine
LLVM-JVM
[W.I.P] A Just-In-Time Java Virtual Machine written in Haskell
Stars: ✭ 22 (-81.36%)
Mutual labels:  interpreter, virtual-machine
clover2
Clover2 can be used as shell. The completion is powerfull like IDE. Also clover2 is a Ruby-like compiler language with static type like Java. This is high performnace. Please see the wiki for details
Stars: ✭ 100 (-15.25%)
Mutual labels:  interpreter, virtual-machine
Animach
Scheme语言实现和运行时环境 / A Scheme runtime & implementation
Stars: ✭ 45 (-61.86%)
Mutual labels:  interpreter, virtual-machine

Hematita Da Lua


Hematita Da Lua is an interpreter for the scripting language Lua, written entirely in 100% safe Rust. Hematita is the portugese word for hematite, a type of iron oxide, or rust, and lua is the portugese word for moon. 'Hematita Da Lua' is a pun on what the project is, and the discovery that iron on the moon is rusting.

The purpose of the project is to provide a hardened Lua interpreter resiliant to security vulnerabilities. It accomplishes this by using no unsafe code, being compileable on stable, and by relying upon a minimal number of dependencies. With this, we can be confident we are safe from any yet-to-be-found security vulnerabilities in C code. No disrespect to the standard Lua implementation and other C projects.

That said, it is important to note that Hematita is not stable, is very early in it's development and may be buggy. It is my hope that, with enough time to mature, Hematita will be able to garuntee these things.

Running Hematita Standalone

If you'd like to give the interpreter a test drive, run cargo install hematita_cli, and then run hematita_cli. You'll be placed in a basic REPL, and you can press Ctrl + C at any time to exit. A large proportion of the Lua code you throw at it should work fine, but not everything, such as some features of for loops. Please file an issue if you encounter anything that doesn't work, and it'll be fixed soon in a future version!

The command line interface has quite a few options; running it with --help will show them all.

OPTIONS:
	-h, --help        Displays this and quits
	-V, --version     Displays version information
	-v, --verbose     Runs with verbose output
	-i, --interactive Runs in interactive mode, after running SOURCE
	-e, --evaluate    Treats source as direct source code, rather than a file
	-b, --byte-code   Shows byte code rather than executing
	-s, --ast         Shows abstract syntax tree rather than executing
	-t, --tokens      Shows tokens rather than executing

Currently, --verbose does nothing, and is ignored. Running with either --help or --version will prevent any code from being ran. --interactive can be passed with a file, and after execution of the file ends, you'll be dropped into a REPL with all the state of the script left for you to mess with. Using --evaluate will evaluate code passed directly on the command line, rather than loading it from a file.

The --byte-code, --ast, and --tokens options all change the output of the interpreter. Using --byte-code will print out the compiled byte code of the program rather than executing it. --ast will print out the interpreted abstract syntax tree rather than executing, and --tokens will print out debug views of the token stream rather than executing. Each of these options correspond to a different segment of the interpreter, see the internals section for more information.

Embedding Hematita

Embedding Hematitia is fairly straight forward and only requires stringing together each segment of the interpreter. As always, require the crate in your Cargo.toml. Then, you're just six lines of code away from running Lua code in your next big project.

use hematita::{ast::{lexer, parser}, compiler, vm, lua_lib, lua_tuple};

// Ready our Lua source code.
let source = "print(\"Hello, World!\")";
// Create a lexer (just a token iterator) from the characters of our source code.
let lexer = lexer::Lexer {source: source.chars().peekable()}.peekable();
// Parse from the lexer a block of statements.
let parsed = parser::parse_block(&mut parser::TokenIterator(lexer)).unwrap();
// Compile bytecode from the block of statements.
let compiled = compiler::compile_block(&parsed);

// Prepare the global scope.
let global = lua_lib::standard_globals();
// Create the virtual machine...
let virtual_machine = vm::VirtualMachine::new(global);
// And run the byte code.
virtual_machine.execute(&compiled.into(), lua_tuple![].arc()).unwrap();

VirtualMachine is Send + Sync, and includes a lifetime 'n for the native functions and user data you make for your convenience. So, bust out the old crossbeam::thread::Scope, and go wild. If you're curious about what each of the lines do, see the internals section for more information.

Creating your own native function is easy too. All it takes is to modify the global scope with any old function like type, i.e. any dynamically dispatchable Fn.

let number = Mutex::new(0);
// Rust is bad at inferring closure paramaters, so it needs a &_. :(
let counter = move |_, _: &_| {
	let mut lock = number.lock().unwrap();
	let old = *lock;
	*lock += 1;
	Ok(lua_tuple![old].arc())
};

let global = {
	let globals = standard_globals();

	let mut data = globals.data.lock().unwrap();
	data.insert(lua_value!("counter"), Value::NativeFunction(&counter));
	drop(data);

	globals
};

The same goes for creating your own user data. Make a type, implement vm::value::UserData for it, and insert it into the global scope with Value::UserData. (Or, if you prefer, make a native function function that returns it.) As is typical with implementing your own user data, the vast majority of your type will be implemented via the metatable. You can lock your metatable by adding a __metatable entry into it.

The Internals

Hematita is composed of four main segments. Those being, ast::lexer, ast::parser, compiler, and vm, each segment depending on the last. Each segment represents a different process, the lexer is the lexing process, the parser is the parsing process, so on and so forth.

Each segment can be used on it's own, but they're best used all together. If you'd like to just lex and parse lua code, the ast module can totally handle that. If you'd like to just run hand crafted bytecode, the vm module is well suited for it. But the real effect comes from stringing everything together, to form a complete interpreter.

The Lexer

The lexer just turns a stream of characters into a stream of Tokens. It's effectively just an operation over an iterator. You can read it's docs here, note that they are incomplete.

The Parser

The parser takes a stream of tokens, and turns it into a Block. A Block is just a Vec of Statements. Statements are an internal representation of a Lua statement. You can read it's docs here, note that they are incomplete.

The Compiler

The compiler takes a Block, and produces a Chunk. A Chunk is just a Vec of OpCodes, with some metadata. It is effectively a one to one transformation, so no error handling is needed. You can read it's docs here, note that they are incomplete.

The Virtual Machine

The virtual machine takes a Function, and executes it. A Function is just an instantiated form of a Chunk, with associated up-values. It can be made just by calling into on a Chunk. The virtual machine is effectively a match statement over every OpCode, and the code that implements it. You can read it's docs here, note that they are incomplete.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].