World-first Static time RegEx engine with O(0) time complexity
Tags: typescript, regularexpression, javascript, regex
Published: 2021-02-15 15:45:49


## What the heck is that?

- `RegEx` engine written with static types?!
- Code which evaluates `RegEx` "templates" in compile time so you know the result before you run your app?!
- `RegEx` engine which works with `O(0)` run-time complexity?!
- Minified 0-bite (GZip) length output?!
- Fully bugged and not ready for production?!

## I'm not kidding!!! This is not just a dream!

 
This is the first world `RegEx` engine written in pure Typescript types.




Check the working examples!

![preview 1](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/preview-1.png)

![preview 2](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/preview-2.png)

![preview 3](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/preview-3.png)

![preview 4](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/preview-4.png)

[Github Repo - ts-generics-RegEx-engine](https://github.com/Svehla/ts-generics-RegEx-engine)


[you can play with the source code here](https://www.typescriptlang.org/play?target=1&ssl=1&ssc=1&pln=321&pc=1#code/PTAEFpK6dv4YgsAKBBRtQFkCGAXAC1AHsAHAUwCcCBLEgOwGcNN5V02vufxV8AnpVABJfNTqM8ZUAF5QAb1ShQAcnABGDaoBcoANqaNAGjXhVp9RoBMFsxoAMd1VtUBdZfad7Djy+f9XfwBOZ0d3T3VQn3Bg-2dNJ38ADmdQjxQVdVSY5PiQhIB2Z1SMrPBimML8s1T-ADZnYrKzRpj6mvVi-wBWZ0aW9T6Yns7wRv8AFmc+wfBpmMmxvv8AZmdpufWY1bHp-1tLdbnbGOsx9cDnWzntGJMzBMO1JLVtQe8DB0tXqzDnJyDO4GB6qADUAOuCXekVOBnOaghlm0RyeEUyam2Bl2iKhln2ZmOkQWBiWuNRlhWZk2kWGBlG5LUBNUEzMs0ibQMHUZqipqm6rXRWUqBmqPNZqjqZmakRyBjyPIFqlCKSFamiBjiPKlLl+sTVut0IO+PJVbxRXgNrh8WksSLevxs0JhGJccP0NjtYQtLku9hukQ0WI9OPBYWeLmZmiJro0JI9ZLDyL9Lj5mhpsbpHoZSbezI0Es07NjnI93NzqbCSs0A0DIo9YorBbCOs0Mtjco9CqbSo0ZqspUDGo9WqbOuser7BonRv0E69yP71h94Bng2Xs+XC7UM8s1gjq5dWX3m4RFY3e5Tq4Druswbv29UJ73Ubv0-j1kT9qfKesac-05Zn+j4AXuhZ-tOpbWOW34QXu1bQdO9bWI2sEStYrYodOnYYSBSrWP2q6Drew4ESBOqrHqBEGpRs6USB-arCutGDExdGgt+tFHAebGse6qxnpxPqrFeAk0cGImPmJRxRiJNHxqsX7OHJRxpopNFZqsOaccyqyFlpNGlnpUl8qs1Z6TR9ZmVJEqrK2Zk0Z2dlSUqqyEXZNHDm5Uk6pMepuQafmzn5Un9pMK5BRkAC+qAcGAAAC+BMOAFAAB6UAAxvgKVUFQJBUPwQgUKAACCAAmZUaAAPAAKgAfHIojiDQ+D0Aw0j6DVbj6KsGToIlyVpZl2XUHlBUoIIwgAMoAK4AEbVfVjViBIrVSLgZCdd11gZIVwgAPrlWVtWmAAqqYABKFAsPIS3yAACrgVBMBQIgMPgVWnQ1aXiAwZUsA4oAAPygFdLB6IdFVVUdi11aYs0LZ9cOlRV1Vg3VdWxRNRWgPtCMnaA52g9djV3aAj3Pa971I6AP0UH9APA8T4O4-jCOw-D83VV9nOI+jmMoHFoADSl6UUFlOVjXtxUUy9b0fWTK0tW1HVdfoDi7djwhHQTX2NbLVMfZDx0G-LtXI6b1NfRj0ugPjNVnQ1D1PXL1N4-NVWWwrFsu4bSM24LaBgLwIch0LId2-gZUADK0HNrCh9A4eJynyCB5wkClbluACCwM2tQANkwtsABIULgx1kzVtOpb9-0GLQDAAGbUKAABitDPfgK0ALamAAdIPjct1QuNg-gbhMx3Xe96AegMBQABu1C2zVuC0AX5ukzXdcsPow+t-t09MN34h96Ag-9wfo-j5PIPj3PoAL8v42TcVV09yQy-R7gJ9b7dO96b130Jfa+zN8CmDAftH+J8RAUB7nfcBj9n4ry1sVGB3tt50wZgYUBzdD7j0gfg0eGDEEYOQUvVBtsP5fwoMfJKAA5XuTACYAGESAzXek7UA7DOH4EATgwGINq56BocvehTAmFnxYWvDe5teZVV4e9UwGgA7UIoGQAuuAMoUAwb3AmDCKAAHc9Fn24SAweYjdG-29qYQxJibG901m-cmM0mCEGhrlAR9dcAMAEPoNwphe7mMviVXKQSz7OJxgAUTKrQfApj4ElXwPgKgVVPBhNHtgnxfiAnGE8AAaQoAIbxLAT5UEbgAc3yRiAAargAuM1irZJYL4gQNSVA1UBvIAA8j3eJVUMGeKoMjIpAgGoADJFAGAANbFNAI3UAYy3B6HqY04qUUOmgBqhoRqSgMQqH0AUhZDBQBzIECQJu2yNZ6C6UcloMUUDcKupo7R1jYFn2GaYHZAtbaxPiYknuPSm6AuSak9JGJMmlNAG0gJeTCnzJaaAcpVStlrKadCtpqBnkaK0TowFXzQD-ISY4s+YK0lDMyaM4pph0UUDUWg1x7iaokAJVCpFsLuqBKavAnFrz8WkvgYS+6biPGUtysjYJvyg6sGRakqpedC7F0ZVNTR8Sao-VqtClFDBKncOrki1QqhPAgwCZ4W50KAAGAASBQYD6FRVtWA8eUVLUmtAP1JKothqS3yp4Q59CB6DxZXMhgtAABeFApryt1VVcedUWi3KxhnLgoAqAUEqWlUAZBfaj1DkLaN2iZmgDmr-CgZVs25pOUwMgndy0lpKUQWgrSjHXRID3YqTAOFUB0ULBqhAUlkCYDoEARix39wufneaFB+4ZXbcAIxBAMqECBovWQM0HAaAAFZzWSAATQYdYaORisYuJDfTCNUaY2VP-ts6FRr3VmoxBapFlqAA6b6nXEPAa691nrBpiwlqNP1ByDCqA-XYS+56w2RujRU2N8bE13tfV+ke7dO4n0dXa79Lq3UYhBv+714sRq5RAyoANGGIEX2DSQUNl64NVLjddfACbzXbNPTjA2V1KnRNStBmRHqABUSKdWVICYJ4A8N8BFsxbkye8h9ABLcPq6FT6VAg0LRlGZbGy4Vy3oa-uxr8Pk19tx3j-Harr03vVUwIrmWssFT3KqmmZmmAUKAN+ehVBGI3mVDKT0yqqAANygAAI4zV8a1JutBqBebSto-ABcBA9IXqoUAUUA4qD0Lpyu31a5AJYKoIGRn1MmcpmZvjtH6YyKs-IolcSSUfPgcC0FKS0kucsOFyLtBovUGcJGvKPSqApYoKoTLj8cv6fyzg1QgmStMy4xm8zVXmCWbkTZ+rALHMtcc+S5z0mtOdYi+9HrMWqD9eoCQIb2B8qjfG9l8uuX70QndYtnjlXQ0sP9eR2R1m4bfZUHZwgLKCUA-Ix1sHKh0BzrICUrRJ9aYF3gfTfhviK0zTIGVAgxUF4n3rec0Alqusnd61QPD5GKegCGcS1r4KhkueRqoYnUWzsXcG1QG76axsC0p6AHn5H+cPb00tQ1AAKebIM3vLc+2tv7tnRX7aLaYAJ93QCTZF9N+uqgACUEuysvQqxZsHv35Fg6ByDxzELedQ7ADVHpAARHpOh00MFwB2jzVmTn4BINm8gQN-eQ+Jp-b+NjFdaf+6Bin+zrfkc82oSpeUMfRKRx29682Y8n2x8OqnoeGeB5UMz07sW1Dxayklkb6fKePN5-zlQgu1ePam7vNQEHXumaWx96rVvKfoHiatYqtDR7WAWdImF-DGC9sj9s2rJv6oR95+bhzTWnOB4h1PlQ0eY8eaKnFlPKPK+88I0NYjvrxpb9AIvBpTTbkehaDHwvpO4upQS+X1Lgfq+U9r3ztjUvO+reNzPvPpTovgSh1tMnHqoBQHvmniFpfuskLrliFg-mdk-i-slqlull-tKkfoBiRlLIygbGVBVrer-hZtBvRteubHVOrJrCmogGmhmlmo3M1GQOms1AnGwELC4gABqNQlRkCaICDYAzQFytSaIUAABal212t2EK6AG+QsFOEBCeHCZAyeyOMBih5Gme4g2e+gWhUe2+lAu+Gh+AwWF+V+FAegAARHNNYUgcdizsXpAc-mXugaNkFpsgYeRu5hAVAaYeYXAdfqANYRlPYWFo4UXlQKgW4RXkFt4VFG4PETKhTsgcXtYQNldhzrdvYVoV4SkXbGqvgBqrXFVKoKlM-nNBlFUalGNjUvIaAKsH2rbPwYIcIaIbQOIVIezpzhQN3ugHbo7noC7m7sVN7qAAwiQGVBQJ4IWuINCu5kEVYTCn4iFnHm0iFjoddHoG0ullsiUfwiJtevChiG9NMalNCgwDND3HNNQGig0o1HMRQHgPgMutdAxrqskmcWlIruIN8j9EEn9GlEATgT6sBmfjwowEwNcfWvIGsrftio1OwswDCRWkig4I+sidCR2mVEhvoVPjrIHliaiVsofglF6sfkBqRqPF6t7iQAXLcaISjBWkYvlDMiwJUiQFMaAE3PlMiu2sVOmr-IwIHq0Ulu0WIUjt0Vkb0b8RQP8bXKYDrN8alKYMSTiRjDQWDl-lEtNNJuIC8W8UwB8ZUl8UCalN3k8QsRYfASsQIGsTvnaZsfqdsXaXsZ4AcdqscYEp4CqZcdcbceNE7J4AMT9LMS6foKoG-O4Pej5gXH5gFpXqaqkk0ionfo-E8ZGdGZPIav4anmYd9hphGaoEsTGUigcfoCqemaVvoCmfKaABoNWY-PoE3A0i9KYBrN9noJmVGUVGWZroVioUntAQWaBsIsxhVmQHKZGVsUwO4JdPArQhIlIvAjIgCaIOaRjKpoHmAiIEwIaYQOWqSZTmAuqeWmDk2SDHuQefWkinWYHsmVQKmZCSiTiU2VlgYK2UXPWWebiWDnoOgLjuIGidScDIHi2W2fWZ2aBvPJQqPOgJAdSQAITIqEAcLxlPxwWgCEAbSUAMBGarwTkd5TmTklRTQOzbLrl+nyAOA4rvZkBkUGoDkGAtCPnPlVlsagkn7gmeCTakXkXUFM6RGk79nN4uFoEV5-q24iD3R6BgLNorEkBECtzkBrSnJoVGIeY+5MC4DLw2kYpGKEAbzFSsEkA6JMBMBVKgBY7SZGEzGgZcVUn4EU5PE3nGnXpmnnFVR8XEWMXIwHGAnnF5bN74m867n7lLqHllTHkqCnlQmonfbplXkRWvFRXQr3lT7jknyTmy5Mb0V+UKlUbKnmlqnxUalf4fmhVb5fntn54bnnExWU6b7n6NznF6Aql1UqA2IIF5W8YMUCWdUeY-S3Jhnr6U5zqvnlp6C-l1Uf687pmwUvycXkkAZgnUm8WN78X1SRlpHnY5nMWqCZFDaSXGauWRXvEeXdzmnd4U6OV4FkaU4+X5UCWNUBVg4dWgbBUFYNzfrXnnXRUnJoa-lJWiApVvFonMUZW85ZX4A5Um5bX+XrnFUNUvnYnlrjYU4jXZXEW5UI2FWBXAldmYVLXPoeorVEZOUPVPV9V+U7XCWs77ViVHXZFc7upilCEiGSmSHSEs19Fg53Wn5g7U3pQFXG4AnvXmnfZfU4L7zfrA2FmUXY30W42+UvWUWKnMlVQqmlWTVlQY2PwapK19Uq3PUbYBX1WE2k2qBIU220zIU20EWMr24UBzQzSVKG0fSeCTlenwbVIek-Q+2oqeCEGenyCqoFzqqaoHFAFgykxEXK2EHEGTk+yUxlTR2ImyAhnk2Un3UQlgw0HpVPn2UU4EZgBvFaYLJXLKWK2w3EUj796kAvygCGX0mdrXr83Z24GC1T752NnQoh0-SRlI66pEBqgl3TLNprK0BlR6B1khYFwkCVKiIkxzXkZ6DuaT0NLT16A1UUAhbgnRyL3L1MAhbDwkBeaibWUkAkwMBKWgA9yRUeYbwFweaHm0x-Rpar3r0LJMBT0z08mQX73UmH1L3MzpYcbCAe29XpSB26qFWwN6qNTO2u3u3MbQNkCFWCWb0R2BaaxYwQPFQ7JIMu1u1QOqC4BAyi5zSi7hrhra6CYZTa5gg0MCBMO1GWBzS0NcPhrVG8PhoCC1HSr4OMo1TD63RoPkOUPUOpSsMMP0MZTOC4BzQyMyMZQKNCOByryrBx1-yqCi4fr6Nvr9wfra70POCi79za4WNWOWNjbJq24O49LDpCyDFO521jStLppPx32mU5qVLY4VplQkBGIMCoBAA)

## Disclaimer
- The code is not ready to use in production environment.
- Because of the stack limits of Typescript, some `regEx`s stop working because they are too long and trigger recursion stack overflow known as `Type instantiation is excessively deep and possibly infinite`.
- `RegEx` backtracking is not implemented yet. 
- The parser supports only a small subset of *PCRE* standard. Specifically `.?*+()\\` symbols.



## Motivation + usage

Thanks to new features of Typescript 4.1.x we are able to parse a string into a Tuple of tokens and much more! So I decided to write my own custom `RegEx` engine just by using Typescript static types to demonstrate how powerful the type system of Typescripts is.

## How does the RegEx engine work under the hood?

As you may know, programming languages compilers + interpreters. You may know that they are pretty complex and includes *Lexers*, *Parsers*, *Interpreters*, and so on.

On the other side, this small engine is quite simple, so there are just 3 small modules:
- 1. Tokenizer
- 2. Parser
- 3. Interpreter

### 1. Tokenizer
A small generic `type TokenizeString<T>` just parses `RegEx` template to tokens which are used as the input for `2. Parser` to build `RegEx` Abstract-Syntax-Tree (AST).

Examples:

```typescript
type T0 = TokenizeString<'\\(+(ab)+'>
```

![Tokenize 1 preview](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/tokenize.png)


```typescript
type T1 = TokenizeString<'\\(+(a(xy)+(xx)b)+'>
```

![Tokenize 2 preview](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/tokenize-2.png)


### 2. Parser

`type ParseRegExTokens<T> = ...` takes the tokenized template and does the syntax analysis which produces an Abstract-Syntax-Tree (AST) Model of the `RegEx` template.


Examples:

```typescript
type T3 = ParsedRegEx<TokenizeString<'\\(+(a(xy)+(xx)b)+'>>
```

![Parser preview](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/parser.png)

As you can see, the parser supports nesting of structures (like brackets in brackets in brackets etc...)


AST for `'\\(+(a(xy)+(xx)b)+'` template will look like this:

```js
[{
    type: 'element';
    value: "(";
    quantifier: 'exactlyOne';
}, {
    type: 'element';
    value: "(";
    quantifier: "zeroOrMore";
}, {
    type: 'groupElement';
    states: [{
        type: 'element';
        value: "a";
        quantifier: 'exactlyOne';
    }, {
        type: 'groupElement';
        states: [{
            type: 'element';
            value: "x";
            quantifier: 'exactlyOne';
        }, {
            type: 'element';
            value: "y";
            quantifier: 'exactlyOne';
        }];
        quantifier: 'exactlyOne';
    }, {
        ...; // and so on
    }, {
        ...; // and so on
    }, {
        ...; // and so on
    }];
    quantifier: 'exactlyOne';
}]
```

### 3. RegEx Interpreter

The last step is to create a proper "interpreter" `type Test<RegExp, TestString> = ...` which takes a template and a test string by applying rules from the `RegEx` AST.

Examples:

![Alt Text](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/interpreter-1.png)

![Alt Text](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/interpreter-2.png)

![Alt Text](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/interpreter-3.png)

![Alt Text](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/interpreter-4.png)

![Alt Text](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/interpreter-5.png)

![Alt Text](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/interpreter-6.png)

![Alt Text](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/interpreter-7.png)

![Alt Text](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/interpreter-8.png)

![Alt Text](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/interpreter-9.png)

And that's it! 🎉 🎉

If you don't believe, you can check the full source code in this GitHub repo: https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine

Wait... And what about the real `Javascript` output? Let's check it out!

![Zero runtime preview](https://raw.githubusercontent.com/Svehla/ts-generics-RegEx-engine/main/imgs/zero-runtime.png)

Haha! A few hundreds line of static types and runtime output is empty with `O(0)` time complexity! That's the magic of Typescript 🦄 


## And what's next?

If you're interested in another advanced usage of the Typescript type system, you can check these step-by-step articles/tutorials on how to create some advanced Typescript generics.

- [Object Deep Merge](https://dev.to/svehla/typescript-how-to-deep-merge-170c)
- [How to Object.fromEntries tuples](https://dev.to/svehla/typescript-object-fromentries-389c)
- [UPPER_CASE to lowerCase transformator](https://dev.to/svehla/typescript-transform-case-strings-450b)
- [and so on](https://dev.to/svehla)