Skip to content

Commit

Permalink
support bigint and numeric seperators
Browse files Browse the repository at this point in the history
  • Loading branch information
jogibear9988 committed Nov 3, 2021
1 parent b834e6d commit 571b235
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 38 deletions.
9 changes: 8 additions & 1 deletion src/character.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,15 @@ export const Character = {
(cp >= 0x61 && cp <= 0x66); // a..f
},

isHexDigitChar(ch: string): ch is '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'a'| 'b'| 'c'| 'd'| 'e'| 'f'| 'A'| 'B'| 'C'| 'D'| 'E'| 'F' {
return ch.length === 1 && Character.isHexDigit(ch.charCodeAt(0));
},

isOctalDigit(cp: number): boolean {
return (cp >= 0x30 && cp <= 0x37); // 0..7
}
},

isOctalDigitChar(ch: string): ch is '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' {
return ch.length === 1 && Character.isOctalDigit(ch.charCodeAt(0));
}
};
2 changes: 2 additions & 0 deletions src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export const Messages = {
NewlineAfterThrow: 'Illegal newline after throw',
NoAsAfterImportNamespace: 'Unexpected token',
NoCatchOrFinally: 'Missing catch or finally after try',
NumericSeperatorOneUnderscore: 'Numeric separator must be exactly one underscore',
NumericSeperatorNotAllowedHere: 'Numeric separator is not allowed here',
ParameterAfterRestParameter: 'Rest parameter must be last formal parameter',
PropertyAfterRestProperty: 'Unexpected token',
Redeclaration: '%0 \'%1\' has already been declared',
Expand Down
13 changes: 13 additions & 0 deletions src/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,19 @@ export class AwaitExpression {
}
}

export class BigIntLiteral {
readonly type: string;
readonly value: null | string; //should be bigint
readonly raw: string;
readonly bigint: string;
constructor(value: null | string /*should be bigint*/, raw: string, bigint: string) {
this.type = Syntax.Literal;
this.value = value;
this.raw = raw;
this.bigint = bigint;
}
}

export class BinaryExpression {
readonly type: string;
readonly operator: string;
Expand Down
17 changes: 13 additions & 4 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ export class Parser {
const node = this.createNode();

let expr: Node.Expression;
let token, raw;
let token: RawToken, raw;

switch (this.lookahead.type) {
case Token.Identifier:
Expand All @@ -620,6 +620,7 @@ export class Parser {
break;

case Token.NumericLiteral:
case Token.BigIntLiteral:
case Token.StringLiteral:
if (this.context.strict && this.lookahead.octal) {
this.tolerateUnexpectedToken(this.lookahead, Messages.StrictOctalLiteral);
Expand All @@ -628,7 +629,10 @@ export class Parser {
this.context.isBindingElement = false;
token = this.nextToken();
raw = this.getTokenRaw(token);
expr = this.finalize(node, new Node.Literal(token.value, raw));
if (token.type == Token.BigIntLiteral)
expr = this.finalize(node, new Node.BigIntLiteral(token.value as string, raw, token.value.toString()));
else
expr = this.finalize(node, new Node.Literal(token.value as string, raw));
break;

case Token.BooleanLiteral:
Expand Down Expand Up @@ -670,7 +674,7 @@ export class Parser {
this.scanner.index = this.startMarker.index;
token = this.nextRegexToken();
raw = this.getTokenRaw(token);
expr = this.finalize(node, new Node.RegexLiteral(token.regex as RegExp, raw, token.pattern, token.flags));
expr = this.finalize(node, new Node.RegexLiteral(token.regex as RegExp, raw, token.pattern as string, token.flags as string));
break;
default:
expr = this.throwUnexpectedToken(this.nextToken());
Expand Down Expand Up @@ -803,11 +807,16 @@ export class Parser {
switch (token.type) {
case Token.StringLiteral:
case Token.NumericLiteral:
case Token.BigIntLiteral:
if (this.context.strict && token.octal) {
this.tolerateUnexpectedToken(token, Messages.StrictOctalLiteral);
}
const raw = this.getTokenRaw(token);
key = this.finalize(node, new Node.Literal(token.value as string, raw));
if (token.type === Token.BigIntLiteral)
key = this.finalize(node, new Node.BigIntLiteral(token.value as string, raw, token.value.toString()));
else
key = this.finalize(node, new Node.Literal(token.value as string, raw));

break;

case Token.Identifier:
Expand Down
70 changes: 38 additions & 32 deletions src/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type NotEscapeSequenceHead = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8'

export interface RawToken {
type: Token;
value: string | number;
value: string | number; //add bigint
pattern?: string;
flags?: string;
regex?: RegExp | null;
Expand Down Expand Up @@ -686,14 +686,7 @@ export class Scanner {
// https://tc39.github.io/ecma262/#sec-literals-numeric-literals

private scanHexLiteral(start: number): RawToken {
let num = '';

while (!this.eof()) {
if (!Character.isHexDigit(this.source.charCodeAt(this.index))) {
break;
}
num += this.source[this.index++];
}
let num = this.scanLiteralPart(Character.isHexDigitChar);

if (num.length === 0) {
this.throwUnexpectedToken();
Expand All @@ -714,16 +707,9 @@ export class Scanner {
}

private scanBinaryLiteral(start: number): RawToken {
let num = '';
let ch;

while (!this.eof()) {
ch = this.source[this.index];
if (ch !== '0' && ch !== '1') {
break;
}
num += this.source[this.index++];
}
let num = this.scanLiteralPart(c => c === '0' || c === '1');

if (num.length === 0) {
// only 0b or 0B
Expand Down Expand Up @@ -759,12 +745,7 @@ export class Scanner {
++this.index;
}

while (!this.eof()) {
if (!Character.isOctalDigit(this.source.charCodeAt(this.index))) {
break;
}
num += this.source[this.index++];
}
num += this.scanLiteralPart(Character.isOctalDigitChar);

if (!octal && num.length === 0) {
// only 0o or 0O
Expand Down Expand Up @@ -802,6 +783,26 @@ export class Scanner {
return true;
}

private scanLiteralPart(check: (str: string) => boolean) {
let num = '';

if (this.source[this.index] === '_')
this.throwUnexpectedToken(Messages.NumericSeperatorNotAllowedHere);

while (this.source[this.index] && (check(this.source[this.index]) || this.source[this.index] === '_')) {
if (this.source[this.index] !== '_')
num += this.source[this.index];
this.index++;
if (this.source[this.index - 1] === '_' && this.source[this.index] === '_')
this.throwUnexpectedToken(Messages.NumericSeperatorOneUnderscore);
}

if (this.source[this.index - 1] === '_')
this.throwUnexpectedToken(Messages.NumericSeperatorNotAllowedHere);

return num;
}

private scanNumericLiteral(): RawToken {
const start = this.index;
let ch = this.source[start];
Expand Down Expand Up @@ -837,17 +838,14 @@ export class Scanner {
}
}

while (Character.isDecimalDigit(this.source.charCodeAt(this.index))) {
num += this.source[this.index++];
}
this.index--;
num = this.scanLiteralPart(Character.isDecimalDigitChar);
ch = this.source[this.index];
}

if (ch === '.') {
num += this.source[this.index++];
while (Character.isDecimalDigit(this.source.charCodeAt(this.index))) {
num += this.source[this.index++];
}
num += this.scanLiteralPart(Character.isDecimalDigitChar);
ch = this.source[this.index];
}

Expand All @@ -859,12 +857,20 @@ export class Scanner {
num += this.source[this.index++];
}
if (Character.isDecimalDigit(this.source.charCodeAt(this.index))) {
while (Character.isDecimalDigit(this.source.charCodeAt(this.index))) {
num += this.source[this.index++];
}
num += this.scanLiteralPart(Character.isDecimalDigitChar);
} else {
this.throwUnexpectedToken();
}
} else if (ch === 'n') {
this.index++;
return {
type: Token.BigIntLiteral,
value: num, // should be BigInt(num),
lineNumber: this.lineNumber,
lineStart: this.lineStart,
start: start,
end: this.index
};
}

if (Character.isIdentifierStart(this.source.charCodeAt(this.index))) {
Expand Down
4 changes: 3 additions & 1 deletion src/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export const enum Token {
Punctuator,
StringLiteral,
RegularExpression,
Template
Template,
BigIntLiteral
}

export const TokenName = {};
Expand All @@ -22,3 +23,4 @@ TokenName[Token.Punctuator] = 'Punctuator';
TokenName[Token.StringLiteral] = 'String';
TokenName[Token.RegularExpression] = 'RegularExpression';
TokenName[Token.Template] = 'Template';
TokenName[Token.BigIntLiteral] = 'BigIntLiteral';

0 comments on commit 571b235

Please sign in to comment.