The T-Regs Programming Language

T-Regs is a Next Generation Regular Expression Based Programming Language, brought to you by the world leader in Next Generation Regular Expression Based Programming Languages.

T-Regs (Pronounced "T-Regs") stands for Text and Regular Expressions. We feel strongly that free text is the most natural way of expressing one's thoughts. Therefore T-Regs does away with the restrictions found in traditional programming languages and is entirely based on free text. Free text which is conveniently manipulated by lots and lots of regular expressions.

Quick examples

Hello world

See, pretty straightforward. You can try this out right here.

10 /.*/Hello world!/

Subtracting 2 numbers

This is admittedly more advanced, but will become clear enough once you step through it in the online interpreter.

# Goto main program (skip functions) 1 /.*/$0;1000/ 2 /^(.*?);(?<goto>1000)$/$1/ # Minus 1 # input: number;returnlabel;rest # output: result;rest 10 /^(\d+)(;.*)$/$1;15$2/ 15 /^(?<left>[1-9]\d*?-*)0(?=0*;)(?<right>.*(?<goto>15).*)/${left}-${right}/ 20 /(\d*);15(;.*)/$1;0123456789$2/ 25 /^(\d*)(?<lastDigit>\d)(?<lookup>-*;\d*(?<newLastDigit>\d)\2.*)(;.*)$/$1${newLastDigit}${lookup}$5/ 30 /(\d*);\d+(;.*)/$1;35$2/ 35 /-(?=-*;)(?<right>.*(?<goto>35).*)/9${right}/ 40 /^0+([^0;])/$1/ 45 /^(\d*);[^;]+;(?<goto>\d+)(;.*)$/$1$3/ # Main calculate "a - b" for positive integers # infinite loop when b>9 1000 /^(\d+)\s*-\s*(\d+)$/$1;$2;0;1050/ 1003 /^(\d+);([^0]\d*);\1;(?<goto>\d+)$/-$2/ 1005 /^(\d+);(\d+);\2;(?<goto>\d+)$/$1/ 1010 /^(\d+);(\d+).*$/10;$1;1020;$2/ 1015 /^(?<goto>10);(.*)$/$2/ 1020 /^(\d+);(\d+)$/10;$2;1040;$1/ 1030 /^(?<goto>10);(.*)$/$2/ 1040 /^(\d+);(\d+)$/$2-$1;1000/ 1045 /^(\d+-\d+);(?<goto>\d+)$/$1/ 1050 /^(\d+).*$/$1/

Learn more about the syntax

Taking it further

The T-Regs Language Commitee will soon set forth guidelines for the Certified T-Regs Programmer Initiative. Follow @ProgramTRegs for further information.

The T-Regs Language Specification

Overview

T-Regs programs consist of lines of find and replace instructions, which are applied to one body of text, which exists as long as the program runs.

This body of text is either input passed to the program on startup or an empty string if no input was defined.

When the program has executed its last line, this text is returned as output.

Syntax

Comments start with a hash.

# this is a comment

Code starts with a unique numeric label like this:

10 /.*/Hello World/

followed by a find regular expression

10 /.*/Hello World/

and a replace string.

10 /.*/Hello World/

These are separated by slashes

10 /.*/Hello World/

and optionally followed by flags

10 /^(?<greetings>h(a?i|ello)).*$/${greetings} world/in

Program flow

The lines in a program are executed in order of their numerical label.

The program

10 /.*/aaa/ 30 /.*/bbb/ 20 /.*/ccc/

will be executed in order 10, 20, 30 and as such result in bbb.

And then there was goto

All looping and decision making is done using goto.

If a find has a named capture "goto", the program will attempt to jump to that label.

10 /.*/hello 40/ 20 /(?<greeting>\w+) (?<goto>\d+)/${greeting}/ 30 /.*/$0 cruel/ 40 /.*/$0 world/ # output: "hello world"

In this example at label 20 the value "40" is captured with name goto and the program will jump to label 40 as a consequence.

Regular Expression Specifics

The Regex dialect

used in this implementation is the one as implemented by xregexp.

The important thing to know is that it has named captures which are used like this:

# given an input "3 + 4" # outputs "4 + 3" 10 /^(?<left>\d+)(?<operator>\s*[-+\/*]\s*)(?<right>\d+)$/
${right}${operator}${left}/

But of course nameless captures are equally fine.

# given an input "3 + 4" # outputs "4 + 3" 10 /^(\d+)(\s*[-+\/*]\s*)(\d+)$/$3$2$1/

Matching behaviour

By default the regular expression is case sensitive and applied only once

# input "aaaa" 10 /a/b/ # results in "baaa"
# input "AAAA" 10 /a/b/ # results in "AAAA"

By setting flags the matching behaviour can be modified.

g is for global

# input "aaaa" 10 /a/b/g # results in "bbbb"

i is for ignore case

# input "AAAA" 10 /a/b/i # results in "bAAA"

m is for multiline anchors

Which makes ^ and $ match at the begining and end of lines, rather than at the begining and end of the whole string. So this:

# input "aa\naa" 10 /^a/b/gm # results in "ba\nba

instead of this:

# input "aa\naa" 10 /^a/b/g # results in "ba\naa"

n is for explicit capture

Making only named groups capturing groups.

In the following example the second group does not capture. This is a great technique for writing highly performant T-Regs and is widely used in enterprise applications.

10 /^(?<greetings>H(a?i|ello)).*$/${greetings} World/n

The above is basically a shorthand for this:

10 /^(?<greetings>H(?:a?i|ello)).*$/${greetings} World/

s is for singleline

where dot matches all characters, including linebreaks. So we get this:

# input "aaa\nbbb" 10 /./c/gs # results in "ccccccc"

Instead of this:

# input "aaa\nbbb" 10 /./c/g # results in "ccc\nccc"

For more information on regular expressions we recommend

regular-expressions.info

T-Regs demonstration code

Hello world run

Observe T-Regs' concise syntax.

10 /.*/Hello world!/

Object Oriented T-Regs run

Being a modern language, T-Regs is absolutely multi paradigm and adapts well to an object-oriented programming style.

10 /"greetings"\s*:\s*"(?<greetings>[^"]+)"\s*,\s*"planet"\s*:\s*"(?<planet>[^"]+)"/"output" : "${greetings} ${planet}"/s

Palindrome checker run

T-Regs is exceptionally well suited for natural language processing tasks, as demonstrated here.

### Palindrome 10 /.*/$0;20;yes,no/ 20 /^(?<ZeroOrOneCharacter>.?;.*(?<yes>yes))|(?<FirstSameAsLast>(.)(?<middle>.*)\4;(?<goto>20)(?<remainder>.*))|(?<NotAPalindrome>.*(?<no>no)).*$/${yes}${no}${middle};${goto}${remainder}/ 30 /^(?<output>[^;]+);.*/${output}/

Conway's Game of Life run

T-Regs is gaining popularity in the scientific community. It has become to be recognized as a pragmatic tool for a wide variety of simulations. It's expressive power is illustrated here by this 13 line Game of Life implementation.

1 /^([^\n]+).*\n([^\n]+)$/$2\n$0\n$1/s 2 /^(.).*(.)$/$2$0$1/mg 3 /(#)|-/$0w$1W/g 4 /w(?=\W*W(?:\Ww\W*W\n?){0}#)/w#/gs 5 /w(?=\W*W(?:\Ww\W*W\n?){1}#)/w#/gs 6 /w(?=\W*W(?:\Ww\W*W\n?){41}#)/w#/gs 7 /w(?=\W*W(?:\Ww\W*W\n?){43}#)/w#/gs 8 /w(?=\W*W(?:\Ww\W*W\n?){83}#)/w#/gs 9 /w(?=\W*W(?:\Ww\W*W\n?){84}#)/w#/gs 10 /w(?=\W*W(?:\Ww\W*W\n?){85}#)/w#/gs 11 /\Ww(?:###|#(#))W(?=(?:\Ww\W*W\n?){42}\1)/#/gs 12 /\Ww#*W/-/g 13 /(?:\n[^\n]+){2}$|.{2}(?=\n|$)//gs

99 Bottles of beer run

T-Regs can hold up a conversation, while attentively commenting on real world events:

### 99 Bottles of beer 1 /.*/100/ 2 /(?<goto>.*)// # Minus 1 # input: number;returnlabel;rest # output: result;rest 10 /^(\d+)/$1;15/ 15 /^(?<left>[1-9]\d*?-*)0(?=0*;)(?<right>.*(?<goto>15).*)/${left}-${right}/ 20 /(\d*);15(;.*)/$1;0123456789$2/ 25 /^(\d*)(?<lastDigit>\d)(?<lookup>-*;\d*(?<newLastDigit>\d)\2.*)/$1${newLastDigit}${lookup}/ 30 /(\d*);\d+/$1;35/ 35 /-(?=-*;)(?<right>.*(?<goto>35).*)/9${right}/ 40 /^0+([^0;])/$1/ 45 /^(\d*);[^;]+;(?<goto>\d+)/$1/ # init at 99 100 /.*/98;01Nno more bottles;\n99 bottles of beer on the wall, 99 bottles of beer./ # add next line of lyrics # input: number;rest 110 /^(?:(\d+)(;\k<1>1(N)(n)([^;]+))|(\d+)(;0\6N.*?( b[^s]+).)|(\d+)(;01N.*?( b[^;]+)));(.*)$/$1$6$9;10-110-150$2$7$10;$12\nTake one down and pass it around, $4$6$9$5$8$11 of beer on the wall.\n\n$3$6$9$5$8$11 of beer on the wall, $4$6$9$5$8$11 of beer./s # if at 0, skip to end 120 /^0;\d+-\d+-(?<goto>\d+);/$0/ # minus 1 and goto print line 140 /^(\d+;)(?<goto>\d+)-(\d+)-\d+/$1$3/ 150 /^[^\n]+\n(.*)/$1\nGo to the store and buy some more, 99 bottles of beer on the wall./s

Fibonacci sequence run

In T-Regs one can easily define custom libraries to solve advanced mathematical problems.

### Fibonacci 1 /.*/100;$0/ 2 /(?<goto>\d+);// # Main 100 /.*/500;1000;200;7;0 1/ 110 /^(?<goto>\d+);// # Add Fibonacci number 200 /^(?<return>\d+);(([ 0-9]+ )?(\d+) (\d+))/500;220;50;$4;$5;$2;${return}/ 210 /^(?<goto>\d+);// 220 /^(\d+);([ 0-9]+);(?<goto>\d+)/${goto};$2 $1/ 1000 /// # Minus 1 # input: returnlabel;number;rest # output: returnlabel;result;rest 10 /^(\d+);(\d+)(;.*)?$/$2;15;$1$3/ 15 /^(?<left>[1-9]\d*?-*)0(?=0*;)(?<right>.*(?<goto>15).*)/${left}-${right}/ 20 /(\d*);15(;.*)/$1;0123456789$2/ 25 /^(\d*)(?<lastDigit>\d)(?<lookup>-*;\d*(?<newLastDigit>\d)\2.*)(;.*)$/$1${newLastDigit}${lookup}$5/ 30 /(\d*);\d+(;.*)/$1;35$2/ 35 /-(?=-*;)(?<right>.*(?<goto>35).*)/9${right}/ 40 /^(\d*);[^;]+;(?<goto>\d+)(;.*)?$/$2;$1$3/ # Plus 1 # input: returnlabel;number;rest # output: returnlabel;result;rest 50 /^(\d+);(\d+)(;.*)$/$2;0123456789;60;$1$3/ 55 /^9+;/0$0/ 60 /^(?<left>[0-8]\d*?-*)9(?=9*;)(?<right>.*(?<goto>60).*)/${left}-${right}/ 65 /^(\d*)(?<lastDigit>\d)(?<lookup>-*;\d*\2(?<newLastDigit>\d).*)(;.*)$/$1${newLastDigit}${lookup}$5/ 75 /(\d*);\d+;\d+(;.*)/$1;80$2/ 80 /-(?=-*;)(?<right>.*(?<goto>80).*)/0${right}/ 85 /^(\d*);[^;]+;(?<goto>\d+)(.*)$/$2;$1$3/ # repeatedly calls a function # input: returnlabel;label;itterations;input for function # output: ouput from function # the function will get it's own exact output as input again, so should in- and out-put in the same format # 1. initialize 500 /^(?<returnlabel>\d+);(?<label>\d+);(?<itterations>\d+);(?<rest>.*)$/${label};${rest};${itterations}-0;10-530-${label}-${returnlabel}/s # 2. goto returnlabel if itterations == 0 510 /^(\d+);(?<result>.*?);(?<itterations>\d+)-\3;(\d+)-(\d+)-(\d+)-(?<goto>\d+)$/${result}/ # 3. itterations-- 520 /^(.*);(?<itterations>\d+)-0;(?<goto>\d+)-(?<return>\d+)-(\d+)-(\d+)$/${return};${itterations};$0/ 530 /^(\d+);(?<itterations>\d+);(.*);(\d+)(-0;)\d+-\d+(-\d+-\d+)$/$3;${itterations}${5}550$6/ # 4. call function 540 /^(?<goto>\d+);(?<arguments>.*;(?<return>\d+)-\d+-\d+)$/${return};${arguments}/ 550 /^\d+;(?<arguments>.*);(?<itterations>\d+)-0;\d+-(?<label>\d+)-(?<return>\d+)$/500;${return};${label};${itterations};${arguments}/ 560 /^(?<goto>\d+);//

Prime numbers run

This is left as an exercise for the reader.

# ...

Challenge! a Quine has not yet been written

# ...
  1. Input
  2. Output
  3. Debug Info
  4. Trace
  5. Errors

About

T-Regs was designed by @mathiasbaert and fits in a long tradition of Esoteric Programming Languages of which is said

Some languages are designed to solve a problem.
Others are designed to prove a point.
— Dennis M. Ritchie 1

Thanks

Several existing libraries made this implementation rather easy.

  1. The extended Regular Expressions syntax was delivered by the excellent xregexp by Steven Levithan.
  2. The beautiful editor is CodeMirror by Marijn Haverbeke.

Prior art

T-Regs is not the first language to be based on regular expressions. Several different approaches can be found for instance on the esolangs wiki like RegexPL and Thutu (which added regular expressions to Thue's mechanism of computation through text replacement).

Compared to these languages T-Regs stays very close to plain regular expressions. T-Regs is not intentionally hard or unreadable, but to the contrary is trying to be as practical as possible. Given of course, that you want to do general purpose programming through text manipulation.

1 He said this in fact about a whole other class of languages, but let us ignore the facts for a moment.