Polyphony
Paradigm(s) | stack-based |
---|---|
Designed by | User:A-jar-of-peanuts, Hanson Sun |
Appeared in | 2024 |
Computational class | Turing complete |
Reference implementation | polyphony |
Influenced by | Velato |
File extension(s) | .mid |
Polyphony is an interpreted stack-based concatenative esoteric programming language that uses MIDI files as source code.
Language overview
In general, certain chords reserved as keywords. For our purposes, a chord is defined as 2 or more notes played simultaneously (Take care that one note can be part of multiple chords depending on its length and overlap with other notes). If a chord that is not recognized as a keyword is played, the highest note of the chord will be used as the literal. Outside of this, single notes are considered as literals.
Polyphony operates on a base 12 number system. Each semitone represents a digit, with C being 0 and B being 11. The octave doesn't matter so both C#4 and C#5 represent 1.
As opposed to being identified by the specific notes in a chord, chords are identified by the intervals between its notes (More specifically, the amount of semitones between any 2 consecutive notes of a chord as opposed to intervals based on scales). From now on, we will represent a chord by its intervals. ex: an octave is written as (13) and the chord CC#E is written as (2,4). In case it is not obvious these are written in base 10.
Syntax
Polyphony has 31 keywords and they are all listed below. For readability, we have provided descriptive keywords along with the interval based ones. Binary operations read in RPN, meaning the operation 1 - 2 is 1 2 - in Polyphony.
Chord | Description |
---|---|
(5): def | start of definition |
`(5, 4)`: `end` | marks the end of identifier calls, control flow chunks, definitions |
`(5, 5)`: `space` | optionally marks the end of literals |
`(13)`: `#` | comment wrappers |
`(4)`: `f` | start of identifier call (executes definition or pushes variable address to top of stack, depending on the identifier) |
`(8, 2)`: `+` | pops 2 items off the stack and pushes their sum onto the stack |
`(8, 3)`: `-` | pops 2 items off the stack and pushes (s1 - s0) |
`(8, 4)`: `*` | pops 2 items off the stack and pushes their product onto the stack |
`(8, 5)`: `/` | pops 2 items off the stack and pushes (s1 / s0) |
`(8, 6)`: `%` | pops 2 items off the stack and pushes (s1 mod s0) |
`(7, 2)`: `=` | pops 2 items off the stack and pushes 1 if they are equal, 0 otherwise |
`(7, 3)`: `<` | pops 2 items off the stack and pushes 1 if (s1 < s0), 0 otherwise |
`(7, 4)`: `>` | pops 2 items off the stack and pushes 1 if (s1 > s0), 0 otherwise |
`(6, 2)`: `&` | pops 2 items off the stack and pushes bitwise and |
(6, 3): | | pops 2 items off the stack and pushes bitwise or |
`(6, 4)`: `~` | pops 2 items off the stack and pushes bitwise not |
`(9, 2)`: `pop` | pops the top of the stack |
`(9, 3)`: `dup` | duplicates the top of the stack |
`(9, 4)`: `dup.` | pops the top of the stack. not counting the item just popped, duplicates the nth item. ex: `1 dup.` duplicates the second item on the stack not counting 1. |
`(9, 5)`: `swap` | swaps the first and second items on the stack |
`(9, 6)`: `size` | returns the size of the stack and pushes it onto the stack |
`(5, 4, 4)`: `input` | reads a value from the console and pushes it onto the stack |
`(5, 4, 5)`: `print` | pops and prints the top of the stack onto the console as a number |
`(5, 4, 6)`: `print-` | pops and prints the top of the stack onto the console as a ASCII character |
`(5, 4, 7)`: `debug` | prints the entire stack onto the console |
`(5, 5, 4)`: `if` | pops the top of the stack, if it is 0, executes the second (`else`) block, otherwise executes the first (`if`) block |
`(5, 5, 5)`: `else` | see above |
`(5, 5, 6)`: `while` | pops the top of the stack, if it is 0, exit the loop. Otherwise, executes the block between the `while` and `end` commands |
`(8)`: `var` | start of variable declaration |
`(9)`: `!` | pops 2 items off the stack. top of the stack is the value, second item is the address. Stores the value at the address |
`(10)`: `@` | pops the top of the stack, gets the value at the address and pushes it onto the the stack |
`(11)`: `^` | pops the top of the stack, frees the memory at the address on the top of the stack |
See also
- Velato (2009)