hexagony-tools
v0.0.8
Published
Tools for emitting Hexagony.
Readme
Tools for emitting Hexagony
There are two planned usecases:
- Using this on its own on a handwritten programs.
- Using this as a last step in compiling Polygolf to Hexagony.
This doesn't do any golfing optimizations, but of course it chooses the smallest Hexagon size that it can fit the code in.
Features:
- [x] Manipulating memory pointers.
- [x] Formatting Hexagony.
- [x] Minifying Hexagony.
- [x] Compiling
Program<false>to Hexagony (1).Program<false>is an array of 1-6 control flow graphs withif currentEdge > 0&while currentEdge > 0as control flows and with Hexagony code except$_|/\<>in the basic blocks. It represents Hexagony programs with no path intersections. - [x] Transforming
Program<true>toProgram<false>with balanced memory pointer (2).Program<true>is an array of 1-6 control flow graphs withif currentEdge > 0&while currentEdge > 0as control flows and Commands of where to move the memory pointer to or Hexagony code except$_|/\<>{}"'=in the basic blocks. It represents Hexagony programs with no path intersections and with statically constant memory pointer state at each point. - [x] Interpreting Hexagony.
- [x] Interpreting
Program<false>. - [ ] Inverting (1).
- [ ] Inverting (2).
Examples
The fibonacciProgram1 and fibonacciProgram2 vars hold equivalent programs and they demonstrate how to define a program using automatic mPointer movements and manual mPointer movements respectively.
const counter = mPointer(`"`)
const a = mPointer(`{=`)
const b = mPointer(``)
const c = mPointer(`}=`)
const fibonacciProgram1 = calcMPointerMovements(program([
b.edge, // goto b
")", // inc to 1, a will be 0
counter.edge, // goto counter
chr(100), // set to 100
whilePos([ // while counter > 0
"(", // dec counter
c, // goto c
"+", // set c to a+b
a, // goto a
"!", // print a
chr(256+32), // prepare a to print " "
";&", // print " " from a, set a to b
b, // goto b
"&", // set b to c
]),
]));
const fibonacciProgram2 = program([
"", // goto b (noop at the start of the program)
")", // inc to 1, a will be 0
a.to(counter), // goto counter
chr(100), // set to 100
whilePos([ // while counter > 0
"(", // dec counter
counter.to(c), // goto c
"+", // set c to a+b
c.to(a), // goto a
"!", // print a
chr(256+32), // prepare a to print " "
";&", // print " " from a, set a to b
a.to(b), // goto b
"&", // set b to c
b.to(counter), // goto counter (to keep the loop balanced!)
])
]);Development
Install
- Node 20
- pnpm
- the rest of deps with
pnpm i
To format, lint & unit test the code, run pnpm check.
Hexagon
Instances of Hexagon represent a raw Hexagony source, new Hexagon(n) is an empty hexagon of size n. To minify or format a hexagony source, use
Hexagon.fromSource(source).toMinifiedSource(), orHexagon.fromSource(source).toLayoutSource(), respectively.
Memory
A memory edge is represented by the Edge type. An edge, along with an orientation is a MPointer. To specify a memory pointer in a specific state, describe how you get there from the origin: mPointer("{{}"). If you only care about the edge, use mPointer("{{}").edge.
Coordinates
You don't really need to know the coordinate system to work with the edges & mPointers as you can use the paths from origin.
Edge is defined by the coordinates of its center in a coordinate system with the following basis vectors:
A mPointer has an orientation (±1) in addition. Positive orientation is in the direction of a, b & a+b vectors.
Manipulating memory pointers
MPointer.move(commands: string)- mutates the mPointer by moving it based on the commandsMPointer.moved(commands: string): MPointer- returns a new mPointer by moving based on the commandsMPointer.to(to: MPointer): string- returns commands needed to get the provided MPointerMPointer.toEdge(to: Edge): { commands: string; to: MPointer }- returns commands and final MPointer needed to get the provided Edge
Programs
Program type represents a control-flow graph for one or more command mPointers.
calcMPointerMovements(program: Program): Program<false>emit(program: Program<false>, layouts?: Layout | Record<string, Layout>): stringdecompile(hexagonySource: string): Program<false>
Layouts
Layouts are where most of the work gets done. Each layout supports a subset of Programs. Layouts have an emit method which should either return a Hexagon of size at most n containing the provided Program, or undefined. Several layouts are provided, or you can define your own. Layouts can emit the programs by using methods rotateIp, advanceIp & write on Hexagon.
If you have a good layout, consider contributing it to the library.
