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 9afd66d
Show file tree
Hide file tree
Showing 4 changed files with 216 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-gA-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: `(-?)\\b0x_*(${hexDigits})(\\.(${hexDigits}))?` + `([pP][+-]?(${decimalDigits}))?\\b`
},
// octal-literal
{
match: `(-?)\\b0b(${octalDigits})\\b`
},
// binary-literal
{
match: `(-?)\\b0b(${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
92 changes: 89 additions & 3 deletions test/markup/haskell/numbers.expect.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,89 @@
<span class="hljs-number">0b001_001</span>
<span class="hljs-number">0x000_0FF</span>
<span class="hljs-number">132_15</span>
-- 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_fffg

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

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

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

-- decimal
million = 1_000_000
billion = 1_000_000_000
lightspeed = 299_792_458
version = 8_04_1
date = 2017_12_31

-- hexadecimal
red_mask = 0xff_00_00
size1G = 0x3fff_fffg

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

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

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

-- negative numbers
n0 = -1
n0 = -1.0
n0 = -0xFF0
92 changes: 89 additions & 3 deletions test/markup/haskell/numbers.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,89 @@
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_fffg

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

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

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

-- decimal
million = 1_000_000
billion = 1_000_000_000
lightspeed = 299_792_458
version = 8_04_1
date = 2017_12_31

-- hexadecimal
red_mask = 0xff_00_00
size1G = 0x3fff_fffg

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

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

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

-- negative numbers
n0 = -1
n0 = -1.0
n0 = -0xFF0

0 comments on commit 9afd66d

Please sign in to comment.