String Replacement Language++ or SRL++ for short is an esoteric programming language developed by MattiDragon. It has an official python interpreter available on github. It's based on replacing all matches of a regex in a string with an other string. It differs from most string replacement langs due to using regex for matches and allowing usage of match groups in replacement.
Every line of source code is a command unless it's empty or a comment. A command consists of four parts separated by spaces: the regex, the source bank, the destination bank and the replacement. The command is executed but taking the data in the source bank, replacing every match of the regex with the replacement and placing it in the destination bank. The replacements are done in the default interpreter with re.sub from the python regex library. Use it as a reference for escape sequences.
The regex is a python regex and supports all of their features. Except for the fact that it may not contain any spaces. You can use the \s escape sequence or unicode sequence if needed. Captured groups in the regex matter outside of it so be careful.
Data in SRL++ is stored in banks. Almost all banks work by simply holding a single string. If you try to take data from a non-existent bank it will be set to an empty string. A banks name can be of any length and may not contain spaces. It's recommended that banks are named in lowerCamelCase.
Some banks have a special meaning. These are special banks. The currently available special banks are:
- io: allows for command-line io
- _ voids all input and outputs nothing
- pointer allows jumping to a line number by setting it's value. The line set will be executed. If it's empty or a comment the next executable line is used. If no usable lines are found or if the input is negative the program terminates.
A replacement is the last part of the command. It can contain spaces and can be omitted in which case it's assumed to be empty. Escape sequences are supported as specified in the docs for re.sub from the python regex library. Some of the common ones include \n for newline and \1 for the first match group in the regex. Use the docs as a reference for escape sequences.
Comments and empty lines
Comments can be made by prefixing a line with a #. It's recommended to have a space between the # and the text. Empty lines are also allowed. Both are treated as no-ops but do count towards line numbers.
(.*) io input \1 0 input input 7 1 input input 5 (.*) input pointer \1 .* _ io 1 .* _ pointer 3 .* _ io 0
99 bottles of beer
# Set up initial state. We use the amount of Is in count to keep track of beer .* _ count IIIIIIIII I count count IIIIIIIIIII (I+) count count >\1< .* _ num 99 # Print first three lines (.+) num io \1 bottles of beer on the wall,\n\1 bottles of beer.\nTake one down, pass it around,\n # Convert to readable numbers I< count count < IIIIIIIIII count num X >X num num >1 >1X num num >2 >2X num num >3 >3X num num >4 >4X num num >5 >5X num num >6 >6X num num >7 >7X num num >8 >8X num num >9 ([0-9])< num num \1\\0< \\ num num I< num num 1< I1< num num 2< I2< num num 3< I3< num num 4< I4< num num 5< I5< num num 6< I6< num num 7< I7< num num 8< I8< num num 9< >< num num 0 [<>] num num # Print last line (.+) num io \1 bottles of beer on the wall.\n\n # Conditional jump magic >< count jump : [^:] jump jump (.*) jump jump \1: :: jump jump -1 : jump jump 8 (.*) jump pointer \1
Common mistakes, errors and tricks
Here are some mistakes I made while using this esolang as well as a few I think can be common:
Double selection when using .*
For some reason if you use the regex .* or (.*) on a non empty string you will get an additional match at the end. To fix it you can usually just use .+ or (.+).
Digit after group reference
If you've tried to use a digit after a group ref you will notice that you get an error for an unknown group ref. The workaround is usually to put a different character in between and remove it afterwards.
Conditional jumps can be tricky. You usually want to first get a bank set so that you know it has one of a few states. Then you can replace each of them with their target line number (or just the next one) and then set pointer to it.