moonsharp bytecode types, assembler, disassembler, and static analyzer
- Rust 98.5%
- Nix 1.5%
| .vscode | ||
| src | ||
| .editorconfig | ||
| .envrc | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| flake.lock | ||
| flake.nix | ||
| grammar.pest | ||
| README.md | ||
| rustfmt.toml | ||
moongen provides both
- a command line program for assembling/disassembling/analyzing moonsharp bytecode
- a library for interacting with it
installing
as a CLI
any of the following:
- Nix:
nix run git+https://code.dolls.today/voidstella/moongen -- asm test.txtto run directlynix shell git+https://code.dolls.today/voidstella/moongento get in a shell
- NixOS:
- add
moongen.url = "git+https://code.dolls.today/voidstella/moongen"to flake inputs - then get the package from
inputs.moongen.packages.${system}.default
- add
- cargo:
cargo install moongen
as a library
cargo add moongen
CLI usage
the CLI has the following global args:
[--color,-c = auto,always,never]choose whether output will be colored
and the following subcommands:
asm <src> <dst>assembles the textual format into a bytecode dumpdisasm <src> <dst> [--asm,-a]disassembles a bytecode dump into the textual formatanalyze <src> <dst> [--asm,-a]analyzes a bytecode dump and prints any diagnostics if it violated any rules, along with the full path taken to the diagnosticsoptimize <src> <dst> [--asm,-a] [--disasm,-d]attempt to optimize bytecode by analyzing it and applying changes the analyzer foundvanity <src> <dst> <vanity>modify an existing bytecode dump and add a somewhat-readable string near the start, useful if you want to add a note for someone reading the bytecodecompile <src> <dst>unfinished, will compile lua source code into bytecodebundle <src> <dst>unfinished, will compile and bundle multiple files into one, walking anyrequires it can finddecompile <src> <dst>unfinished, will attempt to decompile bytecode into somewhat readable source
notes:
- all src/dst args accept
-as their path, indicating they should read data from stdin (src) or write it to stdout (dst) --asmindicates thatsrcshould be treated as the textual form rather than the binary form--disasmindicates thatdstshould be written with the textual form rather than the binary form
assembly format
for an instruction reference, review the Inst documentation
syntax is defined by grammar.pest, and follows the following format
- each line may start with a label definition:
@ident: - each line may have one instruction
- an instruction name (ident)
- if the instruction takes
addr, one of the following:- an integer specifying the instruction address relative to the start of the chunk
~, followed by an integer specifying the instruction address relative to the current instruction@, followed by an ident referring to a label
- if the instruction takes
arg1, an integer - if the instruction takes
arg2, an integer - if the instruction takes
name, a string - if the instruction takes
value, an=, followed by one of the following:nullnilvoidtruefalse- a float
- a string
{}(creates an empty table)
- if the instruction takes
symbol, a symbol - if the instruction takes
symbol_list,[, comma-separated symbols,]
terminology
- idents follow the regex
/[a-zA-Z_][a-zA-Z0-9_]*/ - integers follow the regex
/-?(?:0|[1-9][0-9]*)/ - floats follow the regex
/-?(?:0|[1-9][0-9]*)(?:\.[0-9]*)/ - strings are either
- JSON-escaped content wrapped in quotes (
"this is a string with \"embedded\" quotes") - base64-encoded content wrapped in quotes and prefixed with
b(b"dGhpcyBpcyBhIHN0cmluZyB3aXRoICJlbWJlZGRlZCIgcXVvdGVz", useful for binary data)
- JSON-escaped content wrapped in quotes (
- symbols are one of the following:
&, symbol name (local name),:, integer (local index)^, symbol name (upvalue name),:, integer (upvalue index)%, symbol name (global name),:, symbol (global_ENV)env(_ENVsymbol)nullref(null symbol)
- symbol names are one of the following:
- an ident (name)
- an ident,
@, integer (name + disambiguation) ...(vararg)
full demonstration
#![has_env]
// useful for debugging purposes
meta 25 1 "greeter" =null
// does nothing but is in the function header anyways
fn 0 -1 []
fn.new @greet []
upv.ld ^_ENV:0
// %greet:^_ENV:0 isnt necessary, but moonsharp emits it anyways
// you can use nullref for index.set
index.set 0 0 ="greet" %greet:^_ENV:0
// moonsharp likes to generate closures by emitting their instructions and jumping over them
// you dont have to do it this way though (it also saves an instruction to Not Do That)
// but this example will do it moonsharp's way
jmp @over_greet
@greet:
meta 9 1 "greet" =null
fn 1 0 [&who:0]
fn.args [&who:0]
lit ="hello "
loc.ld &who:0
lit ="!"
op.concat
op.concat
ret 1
// moonsharp also generates unreachable `ret 0`s even when the last instruction in a function is a `ret 1`...
ret 0
@over_greet:
// indentation isn't forced either way! lay it out in a way that makes more sense if you'd like
upv.ld ^_ENV:0
index ="print"
upv.ld ^_ENV:0
index ="greet"
lit ="dolly"
call 1 "calling greet"
call 1 "calling print"
pop 1
ret 0