mipearson/lIl

lI| is an esoteric language written in lI| that only uses l, I, and |

★ 0Forks 0GoGitHub ↗Compare

README

lI|

lI| is a tiny esoteric language where the only instruction tokens are l, I, and |.

Interpreter usage:

go run . '<program.lI|>' [args...]

Source format

  • Instructions are separated by a single space character.
  • Newlines are ignored entirely and are only for visual wrapping.
  • Only l, I, |, space, and newline are valid source characters.
  • Canonical style is hard-wrapped at 40 columns.

Trit mapping

The language treats tokens as base-3 digits (trits):

  • l => 0
  • I => 1
  • | => 2

Instructions

Each instruction starts with a 3-token opcode.

  • lll<literal>: print a packed string literal.
    • The literal is encoded as 6 trits per byte (big-endian base-3).
    • Every 6-token chunk must decode to 0..255.
  • llI<number>: push base-3 integer onto stack.
  • ll|: pop two values, push (a+b) mod 256.
  • lIl: pop one value and print it as a byte.
  • lII: duplicate top stack value.
  • II|: pop two values, push a-b.
  • I||: pop one value and print it in decimal.
  • Ill: read one line from stdin into the line register (trailing \n/\r\n removed).
  • IlI: print the current line register.
  • I|I: parse the line register as decimal and push it onto stack.
  • |Il: shift the next CLI argument into the line register.
  • IIl<target>: unconditional jump to instruction number target (1-based instruction index).
  • III<target>: pop one value, jump to target if it is 0.
  • |ll: run another lI| program from the path in the line register.
  • lI|: halt immediately.
  • l|I: drop one stack value.
  • l||: swap top two stack values.

Meta-interpreter opcodes

These are used by lI|.lI| to implement a real interpreter in lI|:

  • ||I: load target program from path in line register.
  • |||: fetch next target instruction, push 1 if fetched else 0.
  • ||l: decode fetched target instruction, push opcode id and cache payload.
  • |II: decode cached payload as base-3 integer and push.
  • |I|: decode cached payload as packed literal and print it.
  • Il|: move one value from main stack to target stack.
  • I|l: move one value from target stack to main stack.
  • |lI: pop target PC and jump target program unconditionally.
  • |l|: pop target, pop cond; jump target program if cond == 0.

Formatter

Normalize and wrap a source file:

go run . -fmt 'helloworld.lI|'

Formatter output rules:

  • instructions joined by exactly one space
  • no blank lines
  • hard-wrapped at 40 columns

Note: -fmt rewrites the input file in place.

Example

Run:

go run . 'helloworld.lI|'

Output:

He||o world!

Interactive example:

go run . 'helloname.lI|'

Meta-interpreter example:

go build -o 'lI|' .
'./lI|' 'lI|.lI|' 'helloworld.lI|'

Looping example:

$ go run . 'countdown.lI|'
Enter countdown start: 10
10
9
8
7
6
5
4
3
2
1
lI|||lll||IIII|||II!

Contributors

pda

Issues