GitHub - uellenberg/Insert: Insert is a programming language for self-modifying code. · GitHub
/" data-turbo-transient="true" />
Skip to content
Search or jump to...
Search code, repositories, users, issues, pull requests...
-->
Search
Clear
Search syntax tips
Provide feedback
--><br>We read every piece of feedback, and take your input very seriously.
Include my email address so I can be contacted
Cancel
Submit feedback
Saved searches
Use saved searches to filter your results more quickly
-->
Name
Query
To see all available qualifiers, see our documentation.
Cancel
Create saved search
Sign in
/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up
Appearance settings
Resetting focus
You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
{{ message }}
uellenberg
Insert
Public
Notifications<br>You must be signed in to change notification settings
Fork
Star<br>61
master
BranchesTags
Go to file
CodeOpen more actions menu
Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit
History<br>209 Commits<br>209 Commits
.idea
.idea
docs
docs
src
src
std
std
test
test
.gitattributes
.gitattributes
.gitignore
.gitignore
Cargo.lock
Cargo.lock
Cargo.toml
Cargo.toml
Insert.iml
Insert.iml
README.md
README.md
pong.avif
pong.avif
quineRun.sh
quineRun.sh
rust-toolchain.toml
rust-toolchain.toml
test.mjs
test.mjs
View all files
Repository files navigation
Insert
Insert is a programming language for self-modifying code.
It can be used to create programs that produce modified versions of themselves. For example, the pong game<br>above (which was one of the winners of IOCCC29) can be found<br>at test/snapshots/pong-target.stdout, with the source code used to create it<br>at test/src/pong.int and a helper script to run it at quineRun.sh.
Each iteration of this program produces the source code to create the next frame, with the current frame (display and<br>game state) rendered inside the source code itself. For a high-level overview of how this all works, check out<br>the IOCCC writeup.
A simple quine
This program prints a copy of itself with an embedded counter incremented each time it runs:
i32 {<br>quineStr[incrValMarker] = string(incrVal + 1);<br>printQuine(quineStr, $quineLen);<br>}">static incrVal: i32 = binding incrValMarker (0);
static quineStr: &[string] = $quine;
import "std/quine.int";
function main() -> i32 {<br>quineStr[incrValMarker] = string(incrVal + 1);<br>printQuine(quineStr, $quineLen);
$quine gives you your own source as an array of string fragments, binding marks a specific value in that array so<br>you can find and overwrite it, and printQuine prints the result.<br>See docs/self-modifying-code.md for how this works.
Getting started
Make sure you're using rustup, as this project requires a nightly toolchain (specified<br>in rust-toolchain.toml).
main.c
# Build and run the C program.<br>gcc main.c -o a.out && ./a.out
# Or use the included script to iterate it.<br>./quineRun.sh"># Compile an Insert program to C.<br>cargo run -- test/src/pong.int > main.c
# Build and run the C program.<br>gcc main.c -o a.out && ./a.out
# Or use the included script to iterate it.<br>./quineRun.sh
For a full walkthrough, including how to run a self-modifying program,<br>see docs/getting-started.md.
Documentation
Getting started - install, build, and run your<br>first program.
Language guide - types, functions, control flow,<br>and the rest of the syntax.
Self-modifying code - markers, bindings, and<br>quines.
Architecture - how the compiler is put together.
High-level architecture
The compiler has three main stages, and you can inspect the output using --stage. For a deeper look, including how<br>quines are emitted, see docs/architecture.md.
AST
First, the input text is transformed into an AST. This step is performed by the pest library, and can be found<br>under src/parser/program.pest.
Then, this AST is converted into MIR (this should really just be IR, although the name is a remnant from an older<br>version of the compiler that had two levels of IR). This conversion can be found<br>under src/parser/mod.rs. This conversion is mostly one-to-one, although a small amount of syntax<br>sugar is removed.
Here, we declare markers which maintain their order in the program all the way down to the output. We can also declare<br>bindings, which wrap an expression in two markers (before and after) to modify it specifically.
MIR
The MIR (mid-level intermediate representation) is where most of the compilation work is done. You can see a high-level<br>view of what happens in src/mir/mod.rs (under visit_mir). Initially, the MIR looks like the AST,<br>and is gradually transformed as more compiler passes run. This transformation includes things like type checking,<br>constant evaluation, and expression simplification.
After these transformations,...