Allow keywords in named import/export syntax (#107)

This commit is contained in:
Alan Pierce 2018-05-13 04:26:12 -07:00 committed by Daniel Wirtz
parent e415377cda
commit 5ab81a00a1
8 changed files with 119 additions and 35 deletions

View File

@ -14,7 +14,8 @@ import {
Tokenizer,
Token,
Range,
CommentHandler
CommentHandler,
IdentifierHandling
} from "./tokenizer";
import {
@ -579,7 +580,7 @@ export class Parser extends DiagnosticEmitter {
this.tryParseSignatureIsSignature = false;
return null;
}
} else if (tn.skip(Token.IDENTIFIER)) {
} else if (tn.skipIdentifier()) {
let name = Node.createIdentifierExpression(tn.readIdentifier(), tn.range(tn.tokenPos, tn.pos));
if (tn.skip(Token.QUESTION)) {
isSignature = true;
@ -678,11 +679,11 @@ export class Parser extends DiagnosticEmitter {
// at '@': Identifier ('.' Identifier)* '(' Arguments
var startPos = tn.tokenPos;
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
let name = tn.readIdentifier();
let expression: Expression = Node.createIdentifierExpression(name, tn.range(startPos, tn.pos));
while (tn.skip(Token.DOT)) {
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
name = tn.readIdentifier();
expression = Node.createPropertyAccessExpression(
expression,
@ -744,7 +745,7 @@ export class Parser extends DiagnosticEmitter {
// before: Identifier (':' Type)? ('=' Expression)?
if (!tn.skip(Token.IDENTIFIER)) {
if (!tn.skipIdentifier()) {
this.error(
DiagnosticCode.Identifier_expected,
tn.range()
@ -853,7 +854,7 @@ export class Parser extends DiagnosticEmitter {
// before: Identifier ('=' Expression)?
if (!tn.skip(Token.IDENTIFIER)) {
if (!tn.skipIdentifier()) {
this.error(
DiagnosticCode.Identifier_expected,
tn.range()
@ -1081,7 +1082,7 @@ export class Parser extends DiagnosticEmitter {
}
isRest = true;
}
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
if (!isRest) startRange = tn.range();
let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
let type: CommonTypeNode | null = null;
@ -1154,7 +1155,7 @@ export class Parser extends DiagnosticEmitter {
// '{' Statement* '}'
// ';'?
if (!tn.skip(Token.IDENTIFIER)) {
if (!tn.skipIdentifier()) {
this.error(
DiagnosticCode.Identifier_expected,
tn.range(tn.pos)
@ -1281,7 +1282,7 @@ export class Parser extends DiagnosticEmitter {
// Statement
if (tn.token == Token.FUNCTION) {
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
name = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
} else { // empty name
name = Node.createEmptyIdentifierExpression(tn.range(tn.pos));
@ -1397,7 +1398,7 @@ export class Parser extends DiagnosticEmitter {
var isInterface = tn.token == Token.INTERFACE;
if (!tn.skip(Token.IDENTIFIER)) {
if (!tn.skipIdentifier()) {
this.error(
DiagnosticCode.Identifier_expected,
tn.range()
@ -1565,7 +1566,7 @@ export class Parser extends DiagnosticEmitter {
var setStart: i32 = 0;
var setEnd: i32 = 0;
if (tn.skip(Token.GET)) {
if (tn.peek(true, true) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
if (tn.peek(true, IdentifierHandling.PREFER) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
flags |= CommonFlags.GET;
isGetter = true;
setStart = tn.tokenPos;
@ -1580,7 +1581,7 @@ export class Parser extends DiagnosticEmitter {
tn.reset(state);
}
} else if (tn.skip(Token.SET)) {
if (tn.peek(true, true) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
if (tn.peek(true, IdentifierHandling.PREFER) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
flags |= CommonFlags.SET | CommonFlags.SET;
isSetter = true;
setStart = tn.tokenPos;
@ -1617,7 +1618,7 @@ export class Parser extends DiagnosticEmitter {
}
}
if (!isConstructor && !tn.skip(Token.IDENTIFIER)) {
if (!isConstructor && !tn.skipIdentifier()) {
this.error(
DiagnosticCode.Identifier_expected,
tn.range()
@ -1833,7 +1834,7 @@ export class Parser extends DiagnosticEmitter {
// at 'namespace': Identifier '{' (Variable | Function)* '}'
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
if (tn.skip(Token.OPENBRACE)) {
let members = new Array<Statement>();
@ -1926,11 +1927,11 @@ export class Parser extends DiagnosticEmitter {
// before: Identifier ('as' Identifier)?
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
let asIdentifier: IdentifierExpression | null = null;
if (tn.skip(Token.AS)) {
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifierName()) {
asIdentifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
} else {
this.error(
@ -1986,7 +1987,7 @@ export class Parser extends DiagnosticEmitter {
}
} else if (tn.skip(Token.ASTERISK)) {
if (tn.skip(Token.AS)) {
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
namespaceName = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
} else {
this.error(
@ -2044,11 +2045,11 @@ export class Parser extends DiagnosticEmitter {
// before: Identifier ('as' Identifier)?
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifierName()) {
let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
let asIdentifier: IdentifierExpression | null = null;
if (tn.skip(Token.AS)) {
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
asIdentifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
} else {
this.error(
@ -2081,10 +2082,10 @@ export class Parser extends DiagnosticEmitter {
// at 'export' 'import': Identifier ('=' Identifier)? ';'?
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
let asIdentifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
if (tn.skip(Token.EQUALS)) {
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
let ret = Node.createExportImportStatement(identifier, asIdentifier, tn.range(startPos, tn.pos));
tn.skip(Token.SEMICOLON);
@ -2242,7 +2243,7 @@ export class Parser extends DiagnosticEmitter {
var identifier: IdentifierExpression | null = null;
if (tn.peek(true) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
tn.next(true);
tn.next(IdentifierHandling.PREFER);
identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
}
var ret = Node.createBreakStatement(identifier, tn.range());
@ -2258,7 +2259,7 @@ export class Parser extends DiagnosticEmitter {
var identifier: IdentifierExpression | null = null;
if (tn.peek(true) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
tn.next(true);
tn.next(IdentifierHandling.PREFER);
identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
}
var ret = Node.createContinueStatement(identifier, tn.range());
@ -2578,7 +2579,7 @@ export class Parser extends DiagnosticEmitter {
);
return null;
}
if (!tn.skip(Token.IDENTIFIER)) {
if (!tn.skipIdentifier()) {
this.error(
DiagnosticCode.Identifier_expected,
tn.range()
@ -2656,7 +2657,7 @@ export class Parser extends DiagnosticEmitter {
// at 'type': Identifier ('<' TypeParameters '>')? '=' Type ';'?
if (tn.skip(Token.IDENTIFIER)) {
if (tn.skipIdentifier()) {
let name = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
let typeParameters: TypeParameterNode[] | null = null;
if (tn.skip(Token.LESSTHAN)) {
@ -2744,7 +2745,7 @@ export class Parser extends DiagnosticEmitter {
tn: Tokenizer
): Expression | null {
var token = tn.next(true);
var token = tn.next(IdentifierHandling.PREFER);
var startPos = tn.tokenPos;
var expr: Expression | null = null;
@ -2821,7 +2822,7 @@ export class Parser extends DiagnosticEmitter {
let state = tn.mark();
let again = true;
do {
switch (tn.next(true)) {
switch (tn.next(IdentifierHandling.PREFER)) {
// function expression
case Token.DOT_DOT_DOT: {

View File

@ -166,6 +166,12 @@ export enum Token {
ENDOFFILE
}
export enum IdentifierHandling {
DEFAULT,
PREFER,
ALWAYS
}
export function tokenFromKeyword(text: string): Token {
switch (text.length && text.charCodeAt(0)) {
case CharCode.a: {
@ -523,12 +529,15 @@ export class Tokenizer extends DiagnosticEmitter {
}
}
next(preferIdentifier: bool = false): Token {
next(identifierHandling: IdentifierHandling = IdentifierHandling.DEFAULT): Token {
this.nextToken = -1;
return this.token = this.unsafeNext(preferIdentifier);
return this.token = this.unsafeNext(identifierHandling);
}
private unsafeNext(preferIdentifier: bool = false, maxTokenLength: i32 = i32.MAX_VALUE): Token {
private unsafeNext(
identifierHandling: IdentifierHandling = IdentifierHandling.DEFAULT,
maxTokenLength: i32 = i32.MAX_VALUE
): Token {
var text = this.source.text;
while (this.pos < this.end) {
this.tokenPos = this.pos;
@ -908,7 +917,11 @@ export class Tokenizer extends DiagnosticEmitter {
let keywordToken = tokenFromKeyword(keywordText);
if (
keywordToken != Token.INVALID &&
!(preferIdentifier && tokenIsAlsoIdentifier(keywordToken))
identifierHandling !== IdentifierHandling.ALWAYS &&
!(
identifierHandling === IdentifierHandling.PREFER &&
tokenIsAlsoIdentifier(keywordToken)
)
) {
return keywordToken;
}
@ -933,7 +946,7 @@ export class Tokenizer extends DiagnosticEmitter {
peek(
checkOnNewLine: bool = false,
preferIdentifier: bool = false,
identifierHandling: IdentifierHandling = IdentifierHandling.DEFAULT,
maxCompoundLength: i32 = i32.MAX_VALUE
): Token {
var text = this.source.text;
@ -941,7 +954,7 @@ export class Tokenizer extends DiagnosticEmitter {
let posBefore = this.pos;
let tokenBefore = this.token;
let tokenPosBefore = this.tokenPos;
this.nextToken = this.unsafeNext(preferIdentifier, maxCompoundLength);
this.nextToken = this.unsafeNext(identifierHandling, maxCompoundLength);
this.nextTokenPos = this.tokenPos;
if (checkOnNewLine) {
this.nextTokenOnNewLine = false;
@ -959,7 +972,15 @@ export class Tokenizer extends DiagnosticEmitter {
return this.nextToken;
}
skip(token: Token): bool {
skipIdentifier(): bool {
return this.skip(Token.IDENTIFIER, IdentifierHandling.PREFER);
}
skipIdentifierName(): bool {
return this.skip(Token.IDENTIFIER, IdentifierHandling.ALWAYS);
}
skip(token: Token, identifierHandling: IdentifierHandling = IdentifierHandling.DEFAULT): bool {
var posBefore = this.pos;
var tokenBefore = this.token;
var tokenPosBefore = this.tokenPos;
@ -970,7 +991,7 @@ export class Tokenizer extends DiagnosticEmitter {
break;
}
}
this.token = this.unsafeNext(token == Token.IDENTIFIER, maxCompoundLength);
this.token = this.unsafeNext(identifierHandling, maxCompoundLength);
if (this.token == token) {
this.nextToken = -1;
return true;

View File

@ -0,0 +1,9 @@
(module
(type $i (func (result i32)))
(memory $0 1)
(export "default" (func $named-export-default/get3))
(export "memory" (memory $0))
(func $named-export-default/get3 (; 0 ;) (type $i) (result i32)
(i32.const 3)
)
)

View File

@ -0,0 +1,5 @@
function get3(): i32 {
return 3;
}
export {get3 as default};

View File

@ -0,0 +1,12 @@
(module
(type $i (func (result i32)))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "default" (func $named-export-default/get3))
(export "memory" (memory $0))
(func $named-export-default/get3 (; 0 ;) (type $i) (result i32)
(return
(i32.const 3)
)
)
)

View File

@ -0,0 +1,12 @@
(module
(type $i (func (result i32)))
(memory $0 1)
(export "getValue" (func $named-import-default/getValue))
(export "memory" (memory $0))
(func $named-export-default/get3 (; 0 ;) (type $i) (result i32)
(i32.const 3)
)
(func $named-import-default/getValue (; 1 ;) (type $i) (result i32)
(call $named-export-default/get3)
)
)

View File

@ -0,0 +1,7 @@
import {
default as get3
} from "./named-export-default";
export function getValue(): i32 {
return get3();
}

View File

@ -0,0 +1,17 @@
(module
(type $i (func (result i32)))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "getValue" (func $named-import-default/getValue))
(export "memory" (memory $0))
(func $named-export-default/get3 (; 0 ;) (type $i) (result i32)
(return
(i32.const 3)
)
)
(func $named-import-default/getValue (; 1 ;) (type $i) (result i32)
(return
(call $named-export-default/get3)
)
)
)