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

View File

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