Skip to content

Commit

Permalink
enh(java) Match numeric literals per Java Language Specification (#2812)
Browse files Browse the repository at this point in the history
  • Loading branch information
gibson042 committed Oct 31, 2020
1 parent f998a50 commit 259b7c9
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 108 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Language Improvements:
- enh(python) Match numeric literals per the language reference [Richard Gibson][]
- enh(ruby) Match numeric literals per language documentation [Richard Gibson][]
- enh(javascript) Match numeric literals per ECMA-262 spec [Richard Gibson][]
- enh(java) Match numeric literals per Java Language Specification [Richard Gibson][]
- enh(php) highlight variables (#2785) [Taufik Nurrohman][]

Dev Improvements:
Expand Down
70 changes: 32 additions & 38 deletions src/languages/java.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,44 +27,38 @@ export default function(hljs) {
},
]
};
/**
* A given sequence, possibly with underscores
* @type {(s: string | RegExp) => string} */
var SEQUENCE_ALLOWING_UNDERSCORES = (seq) => regex.concat('[', seq, ']+([', seq, '_]*[', seq, ']+)?');
var JAVA_NUMBER_MODE = {

// https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.10
var decimalDigits = '[0-9](_*[0-9])*';
var frac = `\\.(${decimalDigits})`;
var hexDigits = '[0-9a-fA-F](_*[0-9a-fA-F])*';
var NUMBER = {
className: 'number',
variants: [
{ begin: `\\b(0[bB]${SEQUENCE_ALLOWING_UNDERSCORES('01')})[lL]?` }, // binary
{ begin: `\\b(0${SEQUENCE_ALLOWING_UNDERSCORES('0-7')})[dDfFlL]?` }, // octal
{
begin: regex.concat(
/\b0[xX]/,
regex.either(
regex.concat(SEQUENCE_ALLOWING_UNDERSCORES('a-fA-F0-9'), /\./, SEQUENCE_ALLOWING_UNDERSCORES('a-fA-F0-9')),
regex.concat(SEQUENCE_ALLOWING_UNDERSCORES('a-fA-F0-9'), /\.?/),
regex.concat(/\./, SEQUENCE_ALLOWING_UNDERSCORES('a-fA-F0-9'))
),
/([pP][+-]?(\d+))?/,
/[fFdDlL]?/ // decimal & fp mixed for simplicity
)
},
// scientific notation
{ begin: regex.concat(
/\b/,
regex.either(
regex.concat(/\d*\./, SEQUENCE_ALLOWING_UNDERSCORES("\\d")), // .3, 3.3, 3.3_3
SEQUENCE_ALLOWING_UNDERSCORES("\\d") // 3, 3_3
),
/[eE][+-]?[\d]+[dDfF]?/)
},
// decimal & fp mixed for simplicity
{ begin: regex.concat(
/\b/,
SEQUENCE_ALLOWING_UNDERSCORES(/\d/),
regex.optional(/\.?/),
regex.optional(SEQUENCE_ALLOWING_UNDERSCORES(/\d/)),
/[dDfFlL]?/)
}
// DecimalFloatingPointLiteral
// including ExponentPart
{ begin: `(\\b(${decimalDigits})((${frac})|\\.)?|(${frac}))` +
`[eE][+-]?(${decimalDigits})[fFdD]?\\b` },
// excluding ExponentPart
{ begin: `\\b(${decimalDigits})((${frac})[fFdD]?\\b|\\.([fFdD]\\b)?)` },
{ begin: `(${frac})[fFdD]?\\b` },
{ begin: `\\b(${decimalDigits})[fFdD]\\b` },

// HexadecimalFloatingPointLiteral
{ begin: `\\b0[xX]((${hexDigits})\\.?|(${hexDigits})?\\.(${hexDigits}))` +
`[pP][+-]?(${decimalDigits})[fFdD]?\\b` },

// DecimalIntegerLiteral
{ begin: '\\b(0|[1-9](_*[0-9])*)[lL]?\\b' },

// HexIntegerLiteral
{ begin: `\\b0[xX](${hexDigits})[lL]?\\b` },

// OctalIntegerLiteral
{ begin: '\\b0(_*[0-7])*[lL]?\\b' },

// BinaryIntegerLiteral
{ begin: '\\b0[bB][01](_*[01])*[lL]?\\b' },
],
relevance: 0
};
Expand Down Expand Up @@ -160,15 +154,15 @@ export default function(hljs) {
ANNOTATION,
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE,
hljs.C_NUMBER_MODE,
NUMBER,
hljs.C_BLOCK_COMMENT_MODE
]
},
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
JAVA_NUMBER_MODE,
NUMBER,
ANNOTATION
]
};
Expand Down
140 changes: 105 additions & 35 deletions test/markup/java/numbers.expect.txt
Original file line number Diff line number Diff line change
@@ -1,35 +1,105 @@
<span class="hljs-keyword">long</span> creditCardNumber = <span class="hljs-number">1234_5678_9012_3456L</span>;
<span class="hljs-keyword">long</span> socialSecurityNumber = <span class="hljs-number">999_99_9999L</span>;
<span class="hljs-keyword">float</span> pi = <span class="hljs-number">3.14_15F</span>;
<span class="hljs-keyword">long</span> hexBytes = <span class="hljs-number">0xFF_EC_DE_5E</span>;
<span class="hljs-keyword">long</span> hexWords = <span class="hljs-number">0xCAFE_BABE</span>;
<span class="hljs-keyword">long</span> maxLong = <span class="hljs-number">0x7fff_ffff_ffff_ffffL</span>;
<span class="hljs-keyword">byte</span> nybbles = <span class="hljs-number">0b0010_0101</span>;
<span class="hljs-keyword">long</span> bytes = <span class="hljs-number">0b11010010_01101001_10010100_10010010</span>;
<span class="hljs-keyword">int</span> n = <span class="hljs-number">1234</span> + Contacts._ID;
<span class="hljs-keyword">float</span> f = <span class="hljs-number">0x1.4p2f</span>;
<span class="hljs-keyword">double</span> d = <span class="hljs-number">0x.ep-6</span>;
<span class="hljs-keyword">int</span> octal = <span class="hljs-number">0777</span>;
<span class="hljs-keyword">float</span> f = <span class="hljs-number">2e3f</span>;
<span class="hljs-keyword">double</span> d = <span class="hljs-number">1.2e4D</span>;
a = <span class="hljs-number">0x4fa6p2</span>;
b = <span class="hljs-number">0x.4p2</span>;
c = <span class="hljs-number">0xa.ffp3f</span>;
d = <span class="hljs-number">0x1.0p2F</span>;
e = <span class="hljs-number">0x1.0p2f</span>;
f = <span class="hljs-number">0x1p1</span>;
g = <span class="hljs-number">0x.3p4d</span>;
h = <span class="hljs-number">0x1.2ep5D</span>;
i = <span class="hljs-number">0x1.p2</span>;
<span class="hljs-keyword">int</span> i = <span class="hljs-number">23</span>;
<span class="hljs-keyword">byte</span> mask = <span class="hljs-number">0x0f</span>;
<span class="hljs-keyword">int</span> i = <span class="hljs-number">4</span>;
<span class="hljs-keyword">byte</span> mask = <span class="hljs-number">0xa</span>;
<span class="hljs-keyword">float</span> f = <span class="hljs-number">5.4</span>;
<span class="hljs-keyword">float</span> f = <span class="hljs-number">2e3</span>;
<span class="hljs-keyword">int</span> n = <span class="hljs-number">0b1</span>;
<span class="hljs-keyword">float</span> f = <span class="hljs-number">3.</span>;
f = <span class="hljs-number">3_3.</span>;
<span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> in the future</span>
<span class="hljs-comment">// float f = .2;</span>
<span class="hljs-comment">// f = .2_022;</span>
<span class="hljs-keyword">int</span>[] decimalIntegers = {
<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">10</span>, <span class="hljs-number">999</span>,
<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1_0</span>, <span class="hljs-number">9_9__9</span>,
};
<span class="hljs-keyword">long</span>[] longDecimalIntegers = {
<span class="hljs-number">0l</span>, <span class="hljs-number">1L</span>, <span class="hljs-number">10l</span>, <span class="hljs-number">999L</span>,
<span class="hljs-number">0L</span>, <span class="hljs-number">1l</span>, <span class="hljs-number">1_0L</span>, <span class="hljs-number">9_9__9l</span>,
};

<span class="hljs-keyword">int</span>[] hexIntegers = {
<span class="hljs-number">0x0</span>, <span class="hljs-number">0Xa0</span>, <span class="hljs-number">0X7FF</span>, <span class="hljs-number">0xd3aD</span>, <span class="hljs-number">0x00000000ffffffff</span>,
<span class="hljs-number">0X0</span>, <span class="hljs-number">0xa_0</span>, <span class="hljs-number">0x7__FF</span>, <span class="hljs-number">0Xd__3_aD</span>, <span class="hljs-number">0X0000_0000__ffff_ffff</span>,
};
<span class="hljs-keyword">long</span>[] longHexIntegers = {
<span class="hljs-number">0x0L</span>, <span class="hljs-number">0Xa0l</span>, <span class="hljs-number">0X7FFL</span>, <span class="hljs-number">0xd3aDl</span>, <span class="hljs-number">0x7fffffffffffffffL</span>,
<span class="hljs-number">0X0l</span>, <span class="hljs-number">0xa_0L</span>, <span class="hljs-number">0x7__FFl</span>, <span class="hljs-number">0Xd__3_aDL</span>, <span class="hljs-number">0X7fff_ffff__ffff_ffffl</span>,
};

<span class="hljs-keyword">int</span>[] octalIntegers = {
<span class="hljs-number">00</span>, <span class="hljs-number">001</span>, <span class="hljs-number">0777</span>,
<span class="hljs-number">0_0</span>, <span class="hljs-number">0__01</span>, <span class="hljs-number">07__77</span>,
};
<span class="hljs-keyword">long</span>[] longOctalIntegers = {
<span class="hljs-number">00l</span>, <span class="hljs-number">001L</span>, <span class="hljs-number">0777l</span>,
<span class="hljs-number">0_0L</span>, <span class="hljs-number">0__01l</span>, <span class="hljs-number">07__77L</span>,
};

<span class="hljs-keyword">int</span>[] binaryIntegers = {
<span class="hljs-number">0b0</span>, <span class="hljs-number">0B11</span>, <span class="hljs-number">0B000</span>, <span class="hljs-number">0b01011</span>,
<span class="hljs-number">0b0</span>, <span class="hljs-number">0B1_1</span>, <span class="hljs-number">0B00__0</span>, <span class="hljs-number">0b01__0_1__1</span>,
};
<span class="hljs-keyword">long</span>[] longBinaryIntegers = {
<span class="hljs-number">0b0l</span>, <span class="hljs-number">0B11L</span>, <span class="hljs-number">0B000l</span>, <span class="hljs-number">0b01011L</span>,
<span class="hljs-number">0b0L</span>, <span class="hljs-number">0B1_1l</span>, <span class="hljs-number">0B00__0L</span>, <span class="hljs-number">0b01__0_1__1l</span>,
};


<span class="hljs-keyword">double</span>[] doubleDecimalIntegers = {
<span class="hljs-number">0d</span>, <span class="hljs-number">00D</span>, <span class="hljs-number">1d</span>, <span class="hljs-number">00800d</span>,
<span class="hljs-number">0D</span>, <span class="hljs-number">0_0d</span>, <span class="hljs-number">1D</span>, <span class="hljs-number">0_0__8__0_0D</span>,
};
<span class="hljs-keyword">float</span>[] floatDecimalIntegers = {
<span class="hljs-number">0f</span>, <span class="hljs-number">00F</span>, <span class="hljs-number">1f</span>, <span class="hljs-number">00800f</span>,
<span class="hljs-number">0F</span>, <span class="hljs-number">0_0f</span>, <span class="hljs-number">1F</span>, <span class="hljs-number">0_0__8__0_0F</span>,
};

<span class="hljs-keyword">double</span>[] doubleDecimals = {
<span class="hljs-number">.0</span>, <span class="hljs-number">.00</span>, <span class="hljs-number">.9</span>, <span class="hljs-number">4.2</span>, <span class="hljs-number">40.010</span>, <span class="hljs-number">0.</span>, <span class="hljs-number">00.</span>, <span class="hljs-number">10.</span>,
<span class="hljs-number">.0</span>, <span class="hljs-number">.0__0</span>, <span class="hljs-number">.9</span>, <span class="hljs-number">4.2</span>, <span class="hljs-number">4_0.0__1_0</span>, <span class="hljs-number">0.</span>, <span class="hljs-number">0_0.</span>, <span class="hljs-number">1__0.</span>,

<span class="hljs-number">.0D</span>, <span class="hljs-number">.00d</span>, <span class="hljs-number">.9D</span>, <span class="hljs-number">4.2d</span>, <span class="hljs-number">40.010D</span>, <span class="hljs-number">0.d</span>, <span class="hljs-number">00.D</span>, <span class="hljs-number">10.d</span>,
<span class="hljs-number">.0d</span>, <span class="hljs-number">.0__0D</span>, <span class="hljs-number">.9d</span>, <span class="hljs-number">4.2D</span>, <span class="hljs-number">4_0.0__1_0d</span>, <span class="hljs-number">0.D</span>, <span class="hljs-number">0_0.d</span>, <span class="hljs-number">1__0.D</span>,
};
<span class="hljs-keyword">float</span>[] floatDecimals = {
<span class="hljs-number">.0F</span>, <span class="hljs-number">.00f</span>, <span class="hljs-number">.9F</span>, <span class="hljs-number">4.2f</span>, <span class="hljs-number">40.010F</span>, <span class="hljs-number">0.f</span>, <span class="hljs-number">00.F</span>, <span class="hljs-number">10.f</span>,
<span class="hljs-number">.0f</span>, <span class="hljs-number">.0__0F</span>, <span class="hljs-number">.9f</span>, <span class="hljs-number">4.2F</span>, <span class="hljs-number">4_0.0__1_0f</span>, <span class="hljs-number">0.F</span>, <span class="hljs-number">0_0.f</span>, <span class="hljs-number">1__0.F</span>,
};

<span class="hljs-keyword">double</span>[] doubleDecimalExponents = {
<span class="hljs-number">.0e10</span>, <span class="hljs-number">.00e+10</span>, <span class="hljs-number">.9e-10</span>, <span class="hljs-number">4.2E10</span>, <span class="hljs-number">40.010E+08</span>, <span class="hljs-number">0.E-10</span>, <span class="hljs-number">00.e100</span>, <span class="hljs-number">00800e+10</span>,
<span class="hljs-number">.0e1_0</span>, <span class="hljs-number">.0_0e+10</span>, <span class="hljs-number">.9e-1_0</span>, <span class="hljs-number">4.2E1_0</span>, <span class="hljs-number">4_0.0__1_0E+0_8</span>, <span class="hljs-number">0.E-1_0</span>, <span class="hljs-number">0_0.e1_0_0</span>, <span class="hljs-number">0_0__8__00e+1___0</span>,

<span class="hljs-number">.0e10d</span>, <span class="hljs-number">.00e+10D</span>, <span class="hljs-number">.9e-10d</span>, <span class="hljs-number">4.2E10D</span>, <span class="hljs-number">40.010E+08d</span>, <span class="hljs-number">0.E-10D</span>, <span class="hljs-number">00.e100d</span>, <span class="hljs-number">00800e+10D</span>,
<span class="hljs-number">.0e1_0D</span>, <span class="hljs-number">.0_0e+10d</span>, <span class="hljs-number">.9e-1_0D</span>, <span class="hljs-number">4.2E1_0d</span>, <span class="hljs-number">4_0.0__1_0E+0_8D</span>, <span class="hljs-number">0.E-1_0d</span>, <span class="hljs-number">0_0.e1_0_0D</span>, <span class="hljs-number">0_0__8__00e+1___0d</span>,
};
<span class="hljs-keyword">float</span>[] floatDecimalExponents = {
<span class="hljs-number">.0e10f</span>, <span class="hljs-number">.00e+10F</span>, <span class="hljs-number">.9e-10f</span>, <span class="hljs-number">4.2E10F</span>, <span class="hljs-number">40.010E+08f</span>, <span class="hljs-number">0.E-10F</span>, <span class="hljs-number">00.e100f</span>, <span class="hljs-number">00800e+10F</span>,
<span class="hljs-number">.0e1_0F</span>, <span class="hljs-number">.0_0e+10f</span>, <span class="hljs-number">.9e-1_0F</span>, <span class="hljs-number">4.2E1_0f</span>, <span class="hljs-number">4_0.0__1_0E+0_8F</span>, <span class="hljs-number">0.E-1_0f</span>, <span class="hljs-number">0_0.e1_0_0F</span>, <span class="hljs-number">0_0__8__00e+1___0f</span>,
};

<span class="hljs-keyword">double</span>[] doubleHexExponents = {
<span class="hljs-number">0x0p0</span>, <span class="hljs-number">0x.ep6</span>, <span class="hljs-number">0Xa0.p+01</span>, <span class="hljs-number">0X.7FFp-18</span>, <span class="hljs-number">0xd3aD.B00p9</span>,
<span class="hljs-number">0X0P0</span>, <span class="hljs-number">0x.Ep6</span>, <span class="hljs-number">0xa_0.p+0_1</span>, <span class="hljs-number">0X.7__F_FP-1__8</span>, <span class="hljs-number">0Xd__3_aD.b00p9</span>,

<span class="hljs-number">0x0p0D</span>, <span class="hljs-number">0x.ep6D</span>, <span class="hljs-number">0Xa0.p+01d</span>, <span class="hljs-number">0X.7FFp-18D</span>, <span class="hljs-number">0xd3aD.B00p9d</span>,
<span class="hljs-number">0X0P0d</span>, <span class="hljs-number">0x.eP6d</span>, <span class="hljs-number">0xa_0.p+0_1D</span>, <span class="hljs-number">0X.7__F_FP-1__8d</span>, <span class="hljs-number">0Xd__3_aD.b00p9D</span>,
};
<span class="hljs-keyword">float</span>[] floatHexExponents = {
<span class="hljs-number">0x0p0F</span>, <span class="hljs-number">0x.ep6F</span>, <span class="hljs-number">0Xa0.p+01f</span>, <span class="hljs-number">0X.7FFp-18F</span>, <span class="hljs-number">0xf3aF.B00p9f</span>,
<span class="hljs-number">0X0P0f</span>, <span class="hljs-number">0x.eP6f</span>, <span class="hljs-number">0xa_0.p+0_1F</span>, <span class="hljs-number">0X.7__F_FP-1__8f</span>, <span class="hljs-number">0Xf__3_aF.b00p9F</span>,
};


<span class="hljs-comment">// expressions containing numeric literals</span>
fn(<span class="hljs-number">.5</span>);
fn(<span class="hljs-number">5.</span>);

<span class="hljs-comment">// expressions not containing numeric literals</span>
fn(x0.d);

<span class="hljs-comment">// invalid pseudo-numeric literals</span>
<span class="hljs-keyword">int</span>[] badNonDecimalIntegers = { 08, 0_8, 019, 0x0g, 0B02, };
<span class="hljs-keyword">long</span>[] longBadNonDecimalIntegers = { 08L, 0_8l, 01_9L, 0x0__GL, 0B0_2l, };

<span class="hljs-keyword">int</span>[] badUnderscoreIntegers = { 3_, 0x_0, 0X1_, 0B_0, 0b1_, };
<span class="hljs-keyword">long</span>[] longBadUnderscoreIntegers = { 3_l, 0X_0L, 0x1_l, 0b_0L, 0B1_l, };

<span class="hljs-keyword">double</span>[] doubleBadDecimals = { 0_d, 0_., <span class="hljs-number">0.</span>_1, <span class="hljs-number">0.</span>_D, <span class="hljs-number">0.</span>1_d, };
<span class="hljs-keyword">float</span>[] floatBadDecimals = { 0_F, 0_.f, <span class="hljs-number">0.</span>_1F, <span class="hljs-number">0.</span>_f, <span class="hljs-number">0.</span>1_F, };

<span class="hljs-keyword">double</span>[] doubleBadDecimalExponents = { 0_e0, <span class="hljs-number">0.</span>_E1, 1e_2, 2E3_, 3e4_d, };
<span class="hljs-keyword">float</span>[] floatBadDecimalExponents = { 0_e0f, <span class="hljs-number">0.</span>_E1F, 1e_2f, 2E3_F, 3e4_f, };

<span class="hljs-keyword">double</span>[] doubleBadHexExponents = { 0x0pA, 0x0_P0, <span class="hljs-number">0x0</span>._p1, 0x1P_2, 0x2p3_, 0x3P4_D, };
<span class="hljs-keyword">float</span>[] floatBadHexExponents = { 0x0pAF, 0x0_P0f, <span class="hljs-number">0x0</span>._p1F, 0x1P_2f, 0x2p3_F, 0x3P4_f, };

0 comments on commit 259b7c9

Please sign in to comment.