Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bigint and seperator #2105

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
17 changes: 16 additions & 1 deletion 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 Expand Up @@ -485,8 +498,10 @@ export class IfStatement {

export class Import {
readonly type: string;
constructor() {
readonly source: Literal;
constructor(source) {
this.type = Syntax.Import;
this.source = source;
}
}

Expand Down
30 changes: 25 additions & 5 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 Expand Up @@ -1282,7 +1291,18 @@ export class Parser {
parseImportCall(): Node.Import {
const node = this.createNode();
this.expectKeyword('import');
return this.finalize(node, new Node.Import());
this.expect("(");

const source = this.parseAssignmentExpression();
if (!this.match(")") && this.config.tolerant) {
this.tolerateUnexpectedToken(this.nextToken());
} else {
this.expect(")");
if (this.match(";")) {
this.nextToken();
}
}
return this.finalize(node, new Node.Import(source));
}

parseLeftHandSideExpressionAllowCall(): Node.Expression {
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';
Loading