RegRep

From Esolang
Jump to navigation Jump to search

RegRep is a language that can be compiled down entirely to JavaScript replaceAlls or sed expressions.

Syntax

The program is split into two parts, separated by //. The first part is a list of regular expression replacements, in the format of regex/replacement, such as (\d)\d/$1, which matches a pair of digits and replaces it with the first one. \/ can be used for a literal slash, and \\ can be used for a literal backslash. In the replacement, \n can be used for a newline. If the separating slash does not exist, it is implicitly appended to the end. Any line starting with a space will be ignored.

The second part of the program is the input. For problems that contain an "input", such as cat, the input can be appended to the program. All replacements will be run on the input from top to bottom, until no replacements can be done anymore.

Example Programs

Infinite Loop

a/a
//
a

Hello, World!

//
Hello, world!

Cat

//

Truth Machine

1/1
0
//

FizzBuzz

 inc1 -> 2
 inc2 -> 3
 etc.
inc(\d+)/inc0$1~01234567890
(?<=inc.*)(\d)(?=9*~\d*?\1(\d).*?)/$2
inc(.*?)~\d*/inc$1
inc0*(.*?)/evalfive$1

 takes the last number in the input and creates a new line with inc#num#
(\d+)$/$1\ninc$1

 is divisible by 5...
evalfive(\d*[05])(?!\d)/evalthree$1 1
evalfive(\d*)/evalthree$1 0

 is divisible by 3... modified from https://stackoverflow.com/a/10992534
evalthree((?:[0369]+|[147](?:[0369]*[147][0369]*[258])*(?:[0369]*[258]|[0369]*[147][0369]*[147])|[258](?:[0369]*[258][0369]*[147])*(?:[0369]*[147]|[0369]*[258][0369]*[258]))+)\s(1|0)/map$1 1 $2
evalthree(\d*)/map$1 0

 map these indicators to actual words
map(\d*) 0 0/$1
map\d* 1 0/Fizz
map\d* 0 1/Buzz
map\d* 1 1/FizzBuzz

//
evalfive1

Implementations

A simple implementation written in JS exists.

class RegRep {
    constructor(input) {
        const parsed = this.parse(input);
        this.reps = parsed.reps;
        this.text = parsed.text;
    }
    parse(input) {
        const parts = input.split('//\n');
        if (parts.length !== 2) throw new Error('Incorrect number of program parts.');
        const reps = [];
        for (const line of parts[0].split('\n')) {
            if (line === '') continue;
            if (line.startsWith(' ')) continue;
            let s1 = '';
            let s2 = '';
            let escaped = false;
            let past_bar = false;
            for (const c of line) {
                if (past_bar) {
                    if (escaped) {
                        if (c == 'n') s2 += '\n';
                        else s2 += c;
                        escaped = false;
                    } else {
                        if (c == '\\') escaped = true;
                        else s2 += c;
                    }
                } else {
                    if (escaped) {
                        if (c == '/') s1 += c;
                        else if (c == '\\') s1 += c;
                        else s1 += '\\' + c;
                        escaped = false;
                    } else {
                        if (c == '/') past_bar = true;
                        else if (c == '\\') escaped = true;
                        else s1 += c;
                    }
                }
            }
            reps.push({ reg: new RegExp(s1, 'g'), rep: s2 });
        }
        return { reps: reps, text: parts[1] };
    }
    step() {
        let ntext = this.text;
        let match = false;
        for (const rep of this.reps) {
            if (rep.reg.test(ntext)) {
                match = true;
                ntext = ntext.replaceAll(rep.reg, rep.rep);
            }
        }
        this.text = ntext;
        return match;
    }
    run() {
        let match = true;
        while (match) {
            match = this.step();
        }
    }
}