diff --git a/src/parser.ts b/src/parser.ts index ff357f2a..4970aeed 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -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(); @@ -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: { diff --git a/src/tokenizer.ts b/src/tokenizer.ts index b276299f..7df2fb68 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -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; diff --git a/tests/compiler/named-export-default.optimized.wat b/tests/compiler/named-export-default.optimized.wat new file mode 100644 index 00000000..3804a389 --- /dev/null +++ b/tests/compiler/named-export-default.optimized.wat @@ -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) + ) +) diff --git a/tests/compiler/named-export-default.ts b/tests/compiler/named-export-default.ts new file mode 100644 index 00000000..84c10d96 --- /dev/null +++ b/tests/compiler/named-export-default.ts @@ -0,0 +1,5 @@ +function get3(): i32 { + return 3; +} + +export {get3 as default}; diff --git a/tests/compiler/named-export-default.untouched.wat b/tests/compiler/named-export-default.untouched.wat new file mode 100644 index 00000000..b10880c5 --- /dev/null +++ b/tests/compiler/named-export-default.untouched.wat @@ -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) + ) + ) +) diff --git a/tests/compiler/named-import-default.optimized.wat b/tests/compiler/named-import-default.optimized.wat new file mode 100644 index 00000000..e4db8237 --- /dev/null +++ b/tests/compiler/named-import-default.optimized.wat @@ -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) + ) +) diff --git a/tests/compiler/named-import-default.ts b/tests/compiler/named-import-default.ts new file mode 100644 index 00000000..2c6c26bd --- /dev/null +++ b/tests/compiler/named-import-default.ts @@ -0,0 +1,7 @@ +import { + default as get3 +} from "./named-export-default"; + +export function getValue(): i32 { + return get3(); +} diff --git a/tests/compiler/named-import-default.untouched.wat b/tests/compiler/named-import-default.untouched.wat new file mode 100644 index 00000000..e112ba2a --- /dev/null +++ b/tests/compiler/named-import-default.untouched.wat @@ -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) + ) + ) +)