Repository: DmitrySoshnikov/regexp-tree (js)

Issue:
Show symbol for char-code nodes
For HEX, Octal, Decimal, and Unicode char codes we can show also an actual symbol corresponding to the code:

```
\u003B
```

Currently produces:

```js
{
  "type": "Char",
  "value": "\\u003B",
  "kind": "unicode"
}
```

We should add `symbol` property to the node:

```js
{
  "type": "Char",
  "value": "\\u003B",
  "kind": "unicode",
  "symbol": ";"
}
```

Pull request description:
Add `symbol` on `Char` objects
Closes #4.

Patch:
diff --git a/src/parser/generated/regexp-tree.js b/src/parser/generated/regexp-tree.js
index 07780fd..be14c02 100644
--- a/src/parser/generated/regexp-tree.js
+++ b/src/parser/generated/regexp-tree.js
@@ -754,10 +754,33 @@ function getRange(text) {
  * Creates a character node.
  */
 function Char(value, kind, loc) {
+  let symbol;
+
+  switch (kind) {
+    case 'decimal': {
+      const code = Number(value.slice(1));
+      symbol = String.fromCodePoint(code);
+      break;
+    }
+    case 'oct': {
+      const code = parseInt(value.slice(1), 8);
+      symbol = String.fromCodePoint(code);
+      break;
+    }
+    case 'hex':
+    case 'unicode': {
+      const hex = value.slice(2).replace('{', '');
+      const code = parseInt(hex, 16);
+      symbol = String.fromCodePoint(code);
+      break;
+    }
+  }
+
   return Node({
     type: 'Char',
     value,
     kind,
+    symbol,
   }, loc);
 }
 
diff --git a/src/parser/regexp.bnf b/src/parser/regexp.bnf
index e20e8b0..b524ec7 100644
--- a/src/parser/regexp.bnf
+++ b/src/parser/regexp.bnf
@@ -130,10 +130,33 @@ function getRange(text) {
  * Creates a character node.
  */
 function Char(value, kind, loc) {
+  let symbol;
+
+  switch (kind) {
+    case 'decimal': {
+      const code = Number(value.slice(1));
+      symbol = String.fromCodePoint(code);
+      break;
+    }
+    case 'oct': {
+      const code = parseInt(value.slice(1), 8);
+      symbol = String.fromCodePoint(code);
+      break;
+    }
+    case 'hex':
+    case 'unicode': {
+      const hex = value.slice(2).replace('{', '');
+      const code = parseInt(hex, 16);
+      symbol = String.fromCodePoint(code);
+      break;
+    }
+  }
+
   return Node({
     type: 'Char',
     value,
     kind,
+    symbol,
   }, loc);
 }
 


Test patch:
diff --git a/src/parser/__tests__/parser-basic-test.js b/src/parser/__tests__/parser-basic-test.js
index 2c079cb..546844e 100644
--- a/src/parser/__tests__/parser-basic-test.js
+++ b/src/parser/__tests__/parser-basic-test.js
@@ -244,6 +244,7 @@ describe('basic', () => {
           {
             type: 'Char',
             value: '\\1',
+            symbol: String.fromCodePoint(1),
             kind: 'decimal'
           }
         ]
@@ -263,7 +264,7 @@ describe('basic', () => {
         idx <= end;
         ++idx
       ) {
-        range.push(String.fromCharCode(idx));
+        range.push(String.fromCodePoint(idx));
       }
 
       return range;
@@ -294,6 +295,7 @@ describe('basic', () => {
     expect(re(/\u003B/).body).toEqual({
       type: 'Char',
       value: '\\u003B',
+      symbol: String.fromCodePoint(0x003b),
       kind: 'unicode',
     });
 
@@ -301,6 +303,7 @@ describe('basic', () => {
     expect(re(/\u{9}/u).body).toEqual({
       type: 'Char',
       value: '\\u{9}',
+      symbol: String.fromCodePoint(9),
       kind: 'unicode',
     });
 
@@ -308,6 +311,7 @@ describe('basic', () => {
     expect(re(/\u{10FFFF}/u).body).toEqual({
       type: 'Char',
       value: '\\u{10FFFF}',
+      symbol: String.fromCodePoint(0x10ffff),
       kind: 'unicode',
     });
 
@@ -315,6 +319,7 @@ describe('basic', () => {
     expect(re(/\u{000001D306}/u).body).toEqual({
       type: 'Char',
       value: '\\u{000001D306}',
+      symbol: String.fromCodePoint(0x000001d306),
       kind: 'unicode',
     });
 
@@ -364,6 +369,32 @@ describe('basic', () => {
       flags: 'gimuy',
     });
   });
+  
+  it('hex escape', () => {
+    expect(re(/\x33/)).toEqual({
+      type: 'RegExp',
+      body: {
+        type: 'Char',
+        value: '\\x33',
+        kind: 'hex',
+        symbol: String.fromCodePoint(0x33),
+      },
+      flags: '',
+    });
+  });
+
+  it('decimal escape', () => {
+    expect(re(/\99/)).toEqual({
+      type: 'RegExp',
+      body: {
+        type: 'Char',
+        value: '\\99',
+        kind: 'decimal',
+        symbol: String.fromCodePoint(99),
+      },
+      flags: '',
+    });
+  });
 
   it('dotAll (/s) flag', () => {
     // Not using `re` helper here because /s flag is not yet implemented