##Challenge: Your challenge is to write an interpreter for [Whitespace](https://web.archive.org/web/20150618184706/http://compsoc.dur.ac.uk/whitespace/tutorial.php). Given a string consisting of spaces, tabs, newlines, and potential other characters, as well as possible inputs for the Whitespace program itself, output the result of the given Whitespace program. ##Here an overview of the [Whitespace](https://web.archive.org/web/20150618184706/http://compsoc.dur.ac.uk/whitespace/tutorial.php) language and its builtins: Whitespace is a stack-based language which uses only three characters: spaces (ASCII codepoint 32); tabs (ASCII codepoint 9); and newlines (ASCII codepoint 10). Every other character is ignored. It only has a couple of basic builtins, which I will go over below. Whitespace has both a stack, which can only consists of integers. As well as a heap, which is a map of integers (both the key and value). From here on out I will be using `S` for spaces, `T` for tabs, and `N` for newlines to make the text more compact. *Stack Manipulation (always starts with leading `S`):* - Push a number to the stack: `SS`, followed by either an `S`/`T` for positive/negative respectively, followed by some `S` and/or `T` which is the binary representation of the number (`S=0`; `T=1`), followed by a trailing newline `N`. Some examples: - `SSSTN` pushes the number `1`; a positive integer with binary `1`. - `SSTTSN` pushes the number `-2`; a negative integer with binary `10`. - `SSSTSTSN` pushes the number `10`; a positive integer with binary `1010`. - `SSTTTSSTSSN` pushes the number `-100`; a negative integer with binary `1100100`. - Pushing number `0` is an edge case, since it can be done in multiple ways. Some examples: - `SSSN`: push a positive integer without any binary digits. - `SSTN`: push a negative integer without any binary digits. - `SSSSN`: push a positive integer with binary `0`. - `SSTSSSN`: push a negative integer with binary `000`. - Duplicate the top of the stack: `SNS`. - Copy the 0-based \$n\$th item from the top of the stack to the top of the stack: `STS` followed by a number similar as mentioned earlier (excluding the leading `SS`). I.e. let's say the stack currently contains the integers `[47,12,0,55]`, then we could use `STSSTSN` to copy the 0-based 2nd item (which is the `12` in this case) to the top. So the stack becomes: `[47,12,0,55,12]`. - NOTE: This index may not be negative. On TIO this [would result in a negative index error](https://tio.run/##K8/ILEktLkhMTv3/PzpYAQRDOP244gNKizPiDWPhQsEKMEEjhCBCpTGySoRaE2RhhGpTkDBECCFooJuUWJyaEq9rWFwSD3RUbmw0SBKkKD6gKDOvJL4kvyA@sTgeyExNTy2K/f8fAA), but that same program would push a `0` in [the vii5ard interpreter](http://vii5ard.github.io/whitespace/), and it could even be different in yet another interpreter. For the sake of this challenge, you can therefore assume a given copy will never be negative. So the copy will always start with `STSS`, followed by the binary of the top-to-bottom index, followed by a trailing `N`. - Swap the top two items on the stack: `SNT`. - Discard the top item of the stack: `SNN`. - Discard/slice \$n\$ items from the top of the stack, but keep the top item: `STN`, followed by a number similar as mentioned earlier (excluding the leading `SS`). I.e. let's say the stack currently contains the integers `[1,2,3,4,5,6,7]`, then we could use `STNSTTN` to discard 3 items from the stack (except the top one). So the stack becomes: `[1,2,3,7]`. - You can again assume no negative slice values will be used, so this will always start with `SNNS`, followed by the amount to slice, followed by a trailing `N`. *Arithmetic (always starts with leading `TS`):* - Addition; add the top two items on the stack together: `TSSS`. - Subtraction; subtract the top item of the stack from the (top-1)th item of the stack: `TSST`. - Multiplication; multiply the top two items on the stack: `TSSN`. - Integer division; integer divide the (top-1)th item of the stack by the top item of the stack: `TSTS`. (NOTE: Since Whitespace only has integers, this will always be integer division and never result in decimal values.) - Modulo; take the modulo of the (top-1)th item of the stack with the top item of the stack: `TSTT`. - You can assume no negative values will be used for the modulo. For each of these two argument builtins the same applies: if none or only a single integer is on the stack, this will result in an error. How you implement this error in your interpreter is up to you, as long as the program stops when this occurs. I thought about not allowing it for the sake of this challenge, but decided not to because it's a commonly used strategy to stop a program with an error when printing hardcoded texts, [using the approach explained in this Whitespace codegolfing tip](https://codegolf.stackexchange.com/a/158232/52210). *Heap Access (always starts with leading `TT`):* - Pop the top two items of the stack, and store the top item in the (top-1)th address of the heap: `TTS`. I.e. let's say the stack contains the integers `[1,2,3,4,5]` and the heap already contains `[{2:10}]`. When you use this store builtin twice in a row, the stack would contain `[1]` and the heap will contain `[{2:3},{4:5}]` (note how the `{2:10}` has been replaced with the `{2:3}`). - NOTE: Just like with the Arithmetic builtins, if no or a single argument is given, it will cause an error. But for the sake of this challenge you can assume this will never be given for this builtin. - Pop the top item of the stack, and push the item corresponding with that heap address to the top of the stack: `TTT`. I.e. let's say the stack contains the integers `[1,4]` and the heap contains `[{2:3},{4:5}]`. If you now use the retrieve builtin once, the stack would become `[1,5]` (and the heap will remain the same). - NOTE: If you use an address that isn't in the heap yet (or the heap is empty), it will push a `0` to the stack instead. But for the sake of this challenge you can also ignore this. *Flow Control (always starts with leading `N`):* - Mark a location in the program with a label: `NSS`, followed by some (optional) `S`/`T` which weren't used by previous labels/subroutines yet, followed by an `N`. I.e. if you're only using a single label in your full program, `NSSN` would be what to use when code-golfing. If you need two or three labels, you can add `NSSSN` or `NSSTN`. - Although it is possible to have multiple of the same labels in the TIO and vii5args interpreters, it will cause issues, so we assume the input will always only create a label once. - Also, although `NSSN` would be a logical first label to use, it's completely valid to use a label `NSSTSTSTTTSN` instead as only label in the program. - Call a subroutine with the given label: `NST`, followed by some (optional) `S`/`T` which weren't used by previous labels/subroutines yet, followed by an `N`. I.e. `NSTTSTSTTTSN` would jump to the label `TSTSTTTSN` as subroutine. - Jump unconditionally to a label: `NSN`, followed by some (optional) `S`/`T`, followed by an `N`. I.e. `NSNN` would jump to the (empty) label `N` and continue the program flow from there. - Jump to a label if the top of the stack is exactly 0: `NTS`, followed by some (optional) `S`/`T`, followed by an `N`. I.e. if the stack is currently `[4,1,0]` and we'd use `NTSSN`, it would jump to the label `SN` and continue the program flow from there (with stack `[4,1]`). If instead the stack is currently `[4,1]` and we'd use the `NTSSN`, it would jump past it to the next builtin below it (with stack `[4]`). - Jump to a label is the top of the stack is negative: `NTT`, followed by some (optional) `S`/`T`, followed by an `N`. I.e. if the stack is currently `[4,1,-10]` and we'd use `NTTTN`, it would jump to the label `TN` and continue the program flow from there (with stack `[4,1]`). If instead the stack is currently `[4,1]` and we'd use the `NTTTN`, it would jump past it to the next builtin below it (with stack `[4]`). - Minor note: There is no *Jump to label if positive* builtin available in Whitespace. - End a subroutine, and go back to the caller (a.k.a. return): `NTN`. - End the entire program: `NNN` (everything after that becomes no-ops). *I/O (always starts with leading `TN`):* - Pop the top integer, and print as character with that codepoint to STDOUT: `TNSS`. I.e. if the stack is currently `[10,101]` and we'd call the `TNSS` twice, it will output a lowercase `e` followed by a newline to STDOUT. - Pop the top integer, and print as integer to STDOUT: `TNST`. - Pop the top integer, and read a character from STDIN, for which its codepoint-integer will be stored in the heap with the popped integer as address: `TNTS`. I.e. if the stack is `[0,0]`, the heap is empty, and STDIN contains the capital letter `I`, and we'd use `TNTS`. The stack will become `[0]` and the heap `[{0:73}]`. (After which we could use the retrieve builtin `TTT` to put this input on the stack.) - Pop the top integer, and read an integer from STDIN, which will be stored in the heap with the popped integer as address: `TNTT`. ##Challenge rules: - You can assume the Whitespace input is always valid with the builtins above. So the compilation phase would always succeed. - You can assume executing the Whitespace input will never result in any errors, **except when the Arithmetic builtins will only get 0 or 1 stack-arguments instead of the required 2**. Although there are loads of other possible errors when executing a Whitespace program, like negative indices, jumps to labels that doesn't exist, read from STDIN when it's empty, etc. For the sake of this challenge you can assume none of those kind of errors will occur, and the input-program is error-free (except for the Arithmetic builtins). - You can assume the additional inputs given will be valid as well. So an integer when we want to read an integer or a character / string of multiple characters if we want to read those. - The Whitespace program-input can be taken in any reasonable format. Could be a string, list of characters, list of codepoint-integers, etc. Same applies to the other inputs. - Any non-whitespace character in the Whitespace-program input is ignored. You can assume the no-op characters will only be printable ASCII. So the Whitespace input will only contain the UTF-8/ASCII characters with the codepoints [9, 10, 32..126]. - Whitespace numbers can in theory be as large as you want, but for the sake of this challenge you can assume the integers used will be in the range [-9223372036854775808, 9223372036854775807] (signed 64 bit integer). ##General rules: - This is [tag:code-golf], so shortest answer in bytes wins. Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language. - [Standard rules apply](https://codegolf.meta.stackexchange.com/questions/2419/default-for-code-golf-program-function-or-snippet/2422#2422) for your answer with [default I/O rules](https://codegolf.meta.stackexchange.com/questions/2447/default-for-code-golf-input-output-methods/), so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call. - [Default Loopholes](https://codegolf.meta.stackexchange.com/questions/1061/loopholes-that-are-forbidden-by-default) are forbidden. - If possible, please add a link with a test for your code (i.e. [TIO](https://tio.run/#)). - Also, adding an explanation for your answer is highly recommended. ##Test cases: ***You should copy the actual test cases from the Try it online links to verify your interpreter.*** Input(s): SSTTSTTTTNSSSTSNSSSTNSTSSTNSSTTSTNSSTTSNSNSSSSTNSTSSTNSSTTSSTTTSNSSTTTSSTTNSSSNSSTTSTNSSTTTNSSSTSNSSTTNSSSTTTNSSSTSNSSTTSSTTTSNSSSTSNSSTTNSSSTTTNSSTTSNSSSTSNSSTTSSTTTSNSSTTTSSTTNSSTTTNSSTTSNSSTTSTNSSTTNSSTTSSTTTSNSSTTNSSSTTTNSSTTSTNSSSNSSTTSTNSSTTSNSNSSSSTNSSTTTTTSNNSSNSSSTTSTTTSNTSSSTNSSNSNN Builtins used: Push num; duplicate; copy; add; create label; jump to label; print as char Output: Pollinium milk; plump pumpkin; lollipop? [Try it online as actual program using raw spaces, tabs, newlines.](https://tio.run/##rVNdi4JAFH3OX@EfCJxqMdiHiPZpCRPsTeQwawNKloOOLPvr3UYbZ6IvpRAGPPd4zrn3Or9JKljJaczqOgzswN6OtqP2lI9nwa/KBOOZi0XUEGQxsFVhAq5hBRLkEpS8M7zK@R9IKRRbuXT6H0jNSodPkEncswIbXxXP0pgK1sG9bTNTXLVn2LhzNEPQNE3UGQk@lasCHRz7dGTgU@wfDvKCTHDQZLPionqq0qPT92S4vbNXsz3dwr3B3ovzeEXX/Q7IOXhYt1IM/qteuyf6ll8oTR34USiFGnBVMKm0pj8sw3qz8c32rmdDiBOF7dhOSZa7nXxrxeAX6VGAlogTWrQWnnX68Ls6cIjc9Kjrfw) [See this Whitespace answer of mine for an explanation.](https://codegolf.stackexchange.com/a/157709/52210) Input(s): SSTTSNSNSTSSNTNST Builtins used: Push num; duplicate; multiply; print as int Output: 4 [Try it online as actual program using spaces, tabs, newlines, and comments.](https://tio.run/##K8/ILEktLkhMTv3/PzpYIVghhDOEM1jBjys@oLQ4I17XKDYaxAtWiHcpLcjJTE4sSY2NBqkAq8ktzSnJLMipBAmBFIVwxgcUZeaVxCcWxwOp1PTUotj//wE) Input(s): SSTTNTNSTNNNTSNTNTSSS Builtins used: Push num; print as int; stop program; (no-ops) Output: -1 [Try it online as actual program using raw spaces, tabs, newlines.](https://tio.run/##K8/ILEktLkhMTv3/X0GBk5OLk0uBk4uLi1MByOJUUFD4/x8A) [See this Whitespace answer of mine for an explanation.](https://codegolf.stackexchange.com/a/192993/52210) Input(s): SSSNSNSSNSTNTTTTTNSSNSNSTNSTSSSTSTSNTNSSSNTSSSTNTSSSSTSSTNSTSSTNSNSSSSTSSNTSTTSNSNTSSNSSSTNTSSTSNSNTSTNSSSTNTSSTNTSSSNSNTSTSSTNTSSTNSNNNSSSNSNNTSTSSTSSTSNSTSSTSNTSTTNTSNNNNNSSTNSNNTSSNNSNNNSSSSNTSSSNSNN 21 Builtins used: Push num; duplicate; swap; copy; discard; add; subtract; multiply; divide; modulo; retrieve; create label; jump to label; jump to label if 0; stop program; read as int; print as char; print as int Output: 21 21 23 20 5 25 31 24 3 27 37 26 [Try it online as actual program using spaces, tabs, newlines, and comments.](https://tio.run/##jVPvboIwEP@MT@EjqNsLGOsHFlAy2JLFmEulnTZBINDKfHrWa0U0FrcQPtDr/f7d0RyE5HVJU962m3iMz2oEkaoPMNlu8CMeA1FlJlIq@dBZ4q1GiZd48M4pgzgh/gpoDSKXfM8rrF@qshL8xHWhVHK7QSDDt6g4IgV0xzMI1uvIQSOL0hLFYw0VVRr8jsOKTzz7diamE8h5k4mcd80a9NqcHmhFU2nb0QLEDS2RCmRT9JhXNASxhzBnDC/Yb3NlUZRnmOUMdKTHv2oud72F3sCrpTT5hQVTWTHUjfovnf43TOBNHdHKJVXif/pk@cQSmlc7iXk8ZzC9DobwI0j8KPj6L0end0jxnJDBsQwn6yRCFH31im82zC7D4/71SZkmIuqUVqzbP8utT0@C8VspFgjFvDhWwFV9mKtNxJ1Gp9loWv4Iqbe42Ff02BmxYdwauR2I24ohC1UmRZmdXUHdUdu4HgMzg7r/L54hte1s@gs) [See this Whitespace answer of mine for an explanation.](https://codegolf.stackexchange.com/a/193850/52210) Input(s): NSSNSSSNSNSTNTSTTTSNSTNSSTNSSNSNN Double speak! Builtins used: Push num; duplicate; retrieve; create label; jump to label; read as int; output as char Output: DDoouubbllee ssppeeaakk!! [Try it online as actual program using spaces, tabs, newlines, and comments.](https://tio.run/##fY/BDoIwDIbP7CnwDXwHuWjIIMKNmKbMRhYRlq3Tx5@rXDwY09v//fnavibLFBwaSmnQqiu7Uis4eEImqHGkGeqmaS@DkA9rY5hgL4HUoYputkbaOesLrfoip2fCK3R9ddSAAezCdCMvXCZT9pae9ENiFxd5E8k@aCLnQCRmQo@GN80/KkyrfOkpPhzw@v1GStUax5nK4Ajvuzc) [See this Whitespace answer of mine for an explanation.](https://codegolf.stackexchange.com/a/189008/52210) Input(s): NSSNSSSNSNSTNTSTTTSNSSSSTSTSNTSSTNTSSNSSSNSNSTNTSTTTTSSTNTSNSSSNTNSTNSSSN TThhiiss iiss ddoouubblee ssppeeaakk!!\n Builtins used: Push num; duplicate; subtract; retrieve; create label; jump to label if 0; read as char; read as int Output: 0 [Try it online as actual program using spaces, tabs, newlines, and comments.](https://tio.run/##tVHLDoIwEDzLV9Q/wG9QDxqDRHowIWSzwGobUZo@9PORLXpSj6Zpm8xMZ3a7D6U9OYMNDUOZJYUoRJbA0hJ6gh3W1MFuv8@rkpnI5cEpSBlgOayC6XTD6hGTsyyRsxE9ELagbyZ4QAeNQouNJ8sKXiPvraY7fbGJr955bMb7nbuIIRMDRag9@1bllBplmxOksA1XA75/NbA@buT/GvhZzvdifvwmB0eX3OpbzBwvOnPiNJXPucS2hkFKpbR2TojpbNu@D6GuOyIhnDOGCPFymc@TJw) [See this Whitespace answer of mine for an explanation.](https://codegolf.stackexchange.com/a/189381/52210) Inputs(s): SSSNSNSTNTTTTTSSSNSNSTNTTTTTTSSSTNST -3 5 Builtins used: Push num; duplicate; add; retrieve; read as int; print as int Output: 2 [Try it online as actual program using spaces, tabs, newlines, and comments.](https://tio.run/##K8/ILEktLkhMTv3/PzpYAQT9uOIDSosz4g1io0GcYIV4l9KCnMzkxJLU2OgQTj@uEM4Qzvig1MSU@OAQF0@/@MTi@My8ktT01CKQPFS2pCgztSw1liZmhnBCTI13TEmBaA9WACoIKAJqQdb5/7@uMZcpAA) [See this Whitespace answer of mine for an explanation.](https://codegolf.stackexchange.com/a/157996/52210) Input(s): SSSTSSSTTTTTSSSSSSSTTSSSTSTTTTTSSTTSNTNST Builtins used: Push num; print as int Output: 4815162342 [Try it online as actual program using spaces, tabs, newlines, and comments.](https://tio.run/##K8/ILEktLkhMTv3/PzpYAQRDOGE0DEL4MIgQAdGoqiC0H1d8QGlxRryJhaGpoZmRsYlRbHQIpx8XSD4@oCgzryQ@rzQ3KbUo9v9/AA) [See this Whitespace answer of mine for an explanation.](https://codegolf.stackexchange.com/a/175317/52210) Input(s): SSSTTTNTNTSSSSTSSSSTNSSSTSTSNNSSTTNSSSTNTSSTSNSNTTSNSTSSTNSNTNSNTTNNSSSNSSSTTTNTTTSTNSSSTSTNNSSTNSNNTNSSNSNTN 〹 Builtins used: Push num; duplicate; swap; discard; copy; slice; retrieve; create label; jump to label; jump to label if negative; read as char; print as char; print as int Output: 12345!!! [Try it online as actual program using spaces, tabs, newlines, and comments.](https://tio.run/##dVJLboMwEF2HU6QHiBQUVV11UYUuqBBBMTuERgamYDUFC0xRd71Wz9ODUA@uCUlbjZDB9vvMPIZKKOwkz3EcE7amildUoQNR31Vwlyb0Ea/YGo7IC2Cx54fAO8gr3vJcYZvOQLPSm4XvdnCzPKfHntX37jZNQseK6v19i1whBDzDEwSHQ3TGWtTGJUdmD1ifKTIBqpGghoauEyF4vUTiJt5J0X@GGkt46l/1xeZHgQX@/hEeQg@iox/GhLbUZKaR77DdZLzDAtxOzc0QLbCBy7MsiRo1DbwUMW2YNicrF03@YeGfEKh0BKoV@IYgatkrY9hSm/lqDDuJHOEWXhClqEtyaVKcZha1olYUoF6wpPhsBNfeZkeho4880eW8LZZsetAz2@J3sMP4NQpDOI5fH5/f) Inputs(s): SSSTTNSNSSNSSNSTTSSSSTTTNTTSNSTNTNSSNNNSSTNNSSNTTTNTNSSTN Builtins used: Push num; duplicate; store; retrieve; call subroutine; return; exit program; print as char; (no-ops) Output: (character with unicode value 7) [Try it online as actual program using spaces, tabs, newlines, and comments.](https://tio.run/##hY5BCsIwEEXX7Sl6AUFw4QGqgptYTF1JGWIZbKAmYZqot4@ZdlERivzVn5n3/7w67XFwqsUYr7Jg1VmdiRyqMHSwadJQ5LKAXXD43zKbrPSWsPnKmxO3v0fMj@tS9T3IcCMbvDYIh4so6@NJMMBHCalIGw9qgLZTxCgL9m/twZG9k3pMpXPdGoxdWTfV8LNQEiqPS0UsOKMnjc/xuTEqDQKZpewYPw)