MeXiCo is an esoteric programming language, and a *compiler* for the language with the same name, compiling source code to [DNS MX records](https://en.m.wikipedia.org/wiki/MX_record). This also explains the name.
It's greatly inspired by [blinry](https://morr.cc)'s [legit](https://github.com/blinry/legit) project and [brainfuck](https://en.wikipedia.org/wiki/Brainfuck), and is written in [go](https://golang.org).
This project was born and written on a boring railroad trip from Hamburg to Düsseldorf.
## Machine specification
Like some other esoteric programming languages, a MeXiCo machine has a storage of unlimited size, also called *infinite tape*, and a first-in-last-out stack. It's possible to read from and write to the tape with a movable *head*. This makes MeXiCo turing-complete.
## Design
As stated above, the source code of a MeXiCo program completely resides in MX records. The compiler ensures that generated MX records are RFC-conform. This means, it is possible to deliver *MeXiCo* source code over a DNS server of your choice, and, using the [time-to-live](https://en.wikipedia.org/wiki/Time_to_live) value, cache source code on a DNS resolver of your choice.
Like in the old [BASIC](https://en.wikipedia.org/wiki/BASIC) days, source code *lines* are defined by a number at the beginning of a line, sitting in the [Priority](https://en.wikipedia.org/wiki/MX_record#MX_preference,_distance,_and_priority) value of the MX record. Lines which are not filled out are skipped. As a short explanation:
```
someprogram.esolang.mil IN MX 10 <line10>
someprogram.esolang.mil IN MX 20 <line20>
someprogram.esolang.mil IN MX 30 <line30>
```
Due to the fact that the payload of a MX records needs to be a [FQDN](https://en.wikipedia.org/wiki/FQDN), every command is represented as a subdomain of the domain `mexico.invalid.`, which is obviously non-existent. If a command contains spaces, for example if they carry an argument (`push 5`), every space is replaced by a minus sign.
## Instructions
Below, you can find the instructions used in the MX records.
| `left` | Tape Head | 0 | 0 | Moves the tape head one cell to the left |
| `right` | Tape Head | 0 | 0 | Moves the tape head one cell to the right |
| `pusht` | Tape, Stack | 0 | 1 | Reads the current cell value and pushes it on top of the stack |
| `push n` | Stack | 0 | 1 | Pushes the value `n` to the stack |
| `pop` | Tape, Stack | 1 | 0 | Pops top stack value to the current cell |
| `dup` | Stack | 1 | 2 | Duplicates the topmost stack value |
| `del` | Stack | 1 | 0 | Deletes the topmost stack value, ignoring its value |
| `eq` | Stack | 2 | 1 | Checks if `stack[0] == stack[1]`. Pushes `1` to the stack if equal, `0` otherwise |
| `not` | Stack | 1 | 1 | Inverses `stack[0]` |
| `gt` | Stack | 2 | 1 | Checks if `stack[0] > stack[1]`. Pushes `1` to the stack if greater, `0` otherwise |
| `lt` | Stack | 2 | 1 | Checks if `stack[0] < stack[1]`. Pushes `1` to the stack if smaller, `0` otherwise |
| `add` | Stack | 2 | 1 | Calculates `stack[0] + stack[1]`, and pushes the result to the stack |
| `sub` | Stack | 2 | 1 | Calculates `stack[0] - stack[1]`, and pushes the result to the stack |
| `mult` | Stack | 2 | 1 | Calculates `stack[0] * stack[1]`, and pushes the result to the stack |
| `div` | Stack | 2 | 1 | Calculates `stack[0] / stack[1]`, and pushes the result to the stack |
| `mod` | Stack | 2 | 1 | Calculates `stack[0] % stack[1]`, and pushes the result to the stack |
| `read` | Stack | 0 | 1 | Reads a character from the user, and pushes its char value to the stack |
| `print` | Stack | 1 | 0 | Prints `stack[0]` as a character |
| `jmp` | Program Flow, Stack | 1 | 0 | Jumps to the line number specified by `stack[0]` |
| `jmpc` | Program Flow, Stack | 2 | 0 | Jumps to the line number specified by `stack[0]`, if `stack[1]` is not `0`. |
Please note that `stack[0]` refers to the topmost stack value, and `stack[i]` refers to the i-th stack value.
## Source code
The syntax of the source code is strongly aligned with the Instructions table above. However, there's a bit of *syntactical sugar* to make programming in this language enjoyable. Take a look into the `examples` directory of this repository to get a basic idea of it.
### Comments
Every line starting with `#`, `//` or `;` is ignored by the compiler.
### Labels
You can define labels like this:
```
// This program reads a character from the user, and subtracts 1 from it, until it is zero.
read
// Let's loop here
LOOP:
push 1
sub
push 0
lt
push LOOP
jmpc
// We're done!
```
As you can see, labels can be defined with a `:` after the label name, and it can be used as a value for `push`. At compile time, it is replaced with the corresponding line number.
## Implementations
There is a reference implementation for the compiler, `mexico`, and a reference implementation for the interpreter, `mexigo`. Both can be found in this repository.