Skip to content

Commit

Permalink
enh(haskell) Restucture Haskell number parsing
Browse files Browse the repository at this point in the history
Restructured Haskell's number parsing, taking a cue from Swift's
implementation. As a happy coincidence, this patch adds support for
Haskell's `HexFloatLiterals` language extension.
  • Loading branch information
martijnbastiaan committed Apr 19, 2021
1 parent c55ad76 commit afa912b
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Grammars:
- enh(javascript/typescript) highlight object properties (#3072) [Josh Goebel][]
- enh(haskell) add support for BinaryLiterals (#3150) [Martijn Bastiaan][]
- enh(haskell) add support for NumericUnderscores (#3150) [Martijn Bastiaan][]
- enh(haskell) add support for HexFloatLiterals (#3150) [Martijn Bastiaan][]

New Languages:

Expand Down
44 changes: 37 additions & 7 deletions src/languages/haskell.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,42 @@ export default function(hljs) {
contains: LIST.contains
};

/* See:
- https://www.haskell.org/onlinereport/lexemes.html
- https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/binary_literals.html
- https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/numeric_underscores.html
- https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/hex_float_literals.html
*/
const decimalDigits = '([0-9]_*)+';
const hexDigits = '([0-9a-fA-F]_*)+';
const binaryDigits = '([01]_*)+';
const octalDigits = '([0-7]_*)+';

const NUMBER = {
className: 'number',
relevance: 0,
variants: [
// decimal floating-point-literal (subsumes decimal-literal)
{
match: `(-?)\\b(${decimalDigits})(\\.(${decimalDigits}))?` + `([eE][+-]?(${decimalDigits}))?\\b`
},
// hexadecimal floating-point-literal (subsumes hexadecimal-literal)
{
match: `(-?)\\b0[xX]_*(${hexDigits})(\\.(${hexDigits}))?` + `([pP][+-]?(${decimalDigits}))?\\b`
},
// octal-literal
{
match: `(-?)\\b0[oO](${octalDigits})\\b`
},
// binary-literal
{
match: `(-?)\\b0[bB](${binaryDigits})\\b`
}
]
};

return {
name: 'Haskell',
aliases: ['hs'],
Expand Down Expand Up @@ -154,13 +190,7 @@ export default function(hljs) {
PREPROCESSOR,

// Literals and names.
hljs.inherit(hljs.BINARY_NUMBER_MODE, {
begin: '\\b(0b[01_]+)'
}),

hljs.inherit(hljs.C_NUMBER_MODE, {
begin: '(-?)(\\b0[xX][a-fA-F0-9_]+|(\\b(\\d|_)+(\\.(\\d|_)*)?|\\.(\\d|_)+)([eE][-+]?(\\d|_)+)?)'
}),
NUMBER,

// TODO: characters.
hljs.QUOTE_STRING_MODE,
Expand Down
64 changes: 61 additions & 3 deletions test/markup/haskell/numbers.expect.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,61 @@
<span class="hljs-number">0b001_001</span>
<span class="hljs-number">0x000_0FF</span>
<span class="hljs-number">132_15</span>
<span class="hljs-comment">-- decimal</span>
<span class="hljs-title">million</span> = <span class="hljs-number">1_000_000</span>
<span class="hljs-title">billion</span> = <span class="hljs-number">1_000_000_000</span>
<span class="hljs-title">lightspeed</span> = <span class="hljs-number">299_792_458</span>
<span class="hljs-title">version</span> = <span class="hljs-number">8_04_1</span>
<span class="hljs-title">date</span> = <span class="hljs-number">2017_12_31</span>
<span class="hljs-title">the_answer</span> = <span class="hljs-number">42</span>

<span class="hljs-comment">-- hexadecimal</span>
<span class="hljs-title">red_mask</span> = <span class="hljs-number">0xff_00_00</span>
<span class="hljs-title">size1G</span> = <span class="hljs-number">0x3fff_fff</span>
<span class="hljs-title">bigX</span> = <span class="hljs-number">0Xffff</span>

<span class="hljs-comment">-- octal</span>
<span class="hljs-title">world</span> = <span class="hljs-number">0o777</span>
<span class="hljs-title">me</span> = <span class="hljs-number">0o700</span>
<span class="hljs-title">bigO</span> = <span class="hljs-number">0O700</span>

<span class="hljs-comment">-- binary</span>
<span class="hljs-title">bit8th</span> = <span class="hljs-number">0b01_0000_0000</span>
<span class="hljs-title">packbits</span> = <span class="hljs-number">0b1_11_01_0000_0_111</span>
<span class="hljs-title">bigbits</span> = <span class="hljs-number">0b1100_1011__1110_1111__0101_0011</span>
<span class="hljs-title">bigB</span> = <span class="hljs-number">0B10</span>

<span class="hljs-comment">-- float</span>
<span class="hljs-title">pi</span> = <span class="hljs-number">3.141_592_653_589_793</span>
<span class="hljs-title">faraday</span> = <span class="hljs-number">96_485.332_89</span>
<span class="hljs-title">avogadro</span> = <span class="hljs-number">6.022_140_857e+23</span>

<span class="hljs-comment">-- negative numbers</span>
<span class="hljs-title">n0</span> = <span class="hljs-number">-1</span>
<span class="hljs-title">n1</span> = <span class="hljs-number">-1.0</span>
<span class="hljs-title">n2</span> = <span class="hljs-number">-0xFF0</span>
<span class="hljs-title">n3</span> = <span class="hljs-number">-0o123</span>
<span class="hljs-title">n4</span> = <span class="hljs-number">-0b001</span>

<span class="hljs-comment">-- Numeric underscores</span>
<span class="hljs-title">x0</span> = <span class="hljs-number">1_000_000</span>
<span class="hljs-title">x1</span> = <span class="hljs-number">1__000000</span>

<span class="hljs-title">e0</span> = <span class="hljs-number">0.0001</span>
<span class="hljs-title">e1</span> = <span class="hljs-number">0.000_1</span>

<span class="hljs-title">f0</span> = <span class="hljs-number">1e+23</span>
<span class="hljs-title">f1</span> = <span class="hljs-number">1_e+23</span>
<span class="hljs-title">f2</span> = <span class="hljs-number">1__e+23</span>

<span class="hljs-title">g0</span> = <span class="hljs-number">1e+23</span>

<span class="hljs-title">h0</span> = <span class="hljs-number">0xffff</span>
<span class="hljs-title">h1</span> = <span class="hljs-number">0xff_ff</span>
<span class="hljs-title">h2</span> = <span class="hljs-number">0x_ffff</span>
<span class="hljs-title">h3</span> = <span class="hljs-number">0x__ffff</span>

<span class="hljs-comment">-- hex float</span>
<span class="hljs-title">hf0</span> = <span class="hljs-number">0x0.1</span>
<span class="hljs-title">hf1</span> = <span class="hljs-number">0x0.01</span>
<span class="hljs-title">hf2</span> = <span class="hljs-number">0xF.FF</span>
<span class="hljs-title">hf3</span> = <span class="hljs-number">0x0.1p41</span>
<span class="hljs-title">hf4</span> = <span class="hljs-number">0x0.1p-4</span>
<span class="hljs-title">hf5</span> = <span class="hljs-number">0x0.1p12</span>
64 changes: 61 additions & 3 deletions test/markup/haskell/numbers.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,61 @@
0b001_001
0x000_0FF
132_15
-- decimal
million = 1_000_000
billion = 1_000_000_000
lightspeed = 299_792_458
version = 8_04_1
date = 2017_12_31
the_answer = 42

-- hexadecimal
red_mask = 0xff_00_00
size1G = 0x3fff_fff
bigX = 0Xffff

-- octal
world = 0o777
me = 0o700
bigO = 0O700

-- binary
bit8th = 0b01_0000_0000
packbits = 0b1_11_01_0000_0_111
bigbits = 0b1100_1011__1110_1111__0101_0011
bigB = 0B10

-- float
pi = 3.141_592_653_589_793
faraday = 96_485.332_89
avogadro = 6.022_140_857e+23

-- negative numbers
n0 = -1
n1 = -1.0
n2 = -0xFF0
n3 = -0o123
n4 = -0b001

-- Numeric underscores
x0 = 1_000_000
x1 = 1__000000

e0 = 0.0001
e1 = 0.000_1

f0 = 1e+23
f1 = 1_e+23
f2 = 1__e+23

g0 = 1e+23

h0 = 0xffff
h1 = 0xff_ff
h2 = 0x_ffff
h3 = 0x__ffff

-- hex float
hf0 = 0x0.1
hf1 = 0x0.01
hf2 = 0xF.FF
hf3 = 0x0.1p41
hf4 = 0x0.1p-4
hf5 = 0x0.1p12

0 comments on commit afa912b

Please sign in to comment.