From 696e6b752555738537f3dbfe4803a7f8018c940a Mon Sep 17 00:00:00 2001 From: Changqing Jing Date: Sat, 17 Oct 2026 17:16:16 +0800 Subject: [PATCH] WIP --- src/parser.ts | 96 ++++++--- tests/compiler/asi.debug.wat | 52 +++++ tests/compiler/asi.release.wat | 28 +++ tests/compiler/asi.ts | 9 + .../compiler/resolve-elementaccess.debug.wat | 184 ++++++++++-------- .../resolve-elementaccess.release.wat | 119 ++++++----- tests/compiler/resolve-elementaccess.ts | 5 + tests/parser/asi.ts | 111 +++++++++++ tests/parser/asi.ts.fixture.ts | 109 +++++++++++ tests/parser/interface-errors.ts.fixture.ts | 1 + tests/parser/literals.ts | 2 +- tests/parser/literals.ts.fixture.ts | 7 + 12 files changed, 565 insertions(+), 158 deletions(-) create mode 100644 tests/compiler/asi.debug.wat create mode 100644 tests/compiler/asi.release.wat create mode 100644 tests/compiler/asi.ts diff --git a/src/parser.ts b/src/parser.ts index 157351cd3a..d7da54f951 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -649,7 +649,7 @@ export class Parser extends DiagnosticEmitter { let parameters: TypeNode[] | null = null; // Name - if (tn.skip(Token.LessThan)) { + if (!tn.peekOnNewLine() && tn.skip(Token.LessThan)) { do { let parameter = this.parseType(tn, true, suppressErrors); if (!parameter) return null; @@ -703,7 +703,7 @@ export class Parser extends DiagnosticEmitter { } } // ... [][] - while (tn.skip(Token.OpenBracket)) { + while (!tn.peekOnNewLine() && tn.skip(Token.OpenBracket)) { let bracketStart = tn.tokenPos; if (!tn.skip(Token.CloseBracket)) { if (!suppressErrors) { @@ -991,7 +991,8 @@ export class Parser extends DiagnosticEmitter { } while (tn.skip(Token.Comma)); let ret = Node.createVariableStatement(decorators, declarations, tn.range(startPos, tn.pos)); - if (!tn.skip(Token.Semicolon) && !isFor) this.checkASI(tn); + if (isFor) tn.skip(Token.Semicolon); + else this.parseSemicolon(tn); return ret; } @@ -1019,7 +1020,8 @@ export class Parser extends DiagnosticEmitter { ); } let flags = parentFlags; - if (tn.skip(Token.Exclamation)) { + if (tn.peek() == Token.Exclamation && !tn.peekOnNewLine()) { + tn.next(); flags |= CommonFlags.DefinitelyAssigned; } @@ -1175,7 +1177,7 @@ export class Parser extends DiagnosticEmitter { } let ret = Node.createReturnStatement(expr, tn.range(startPos, tn.pos)); - if (!tn.skip(Token.Semicolon)) this.checkASI(tn); + this.parseSemicolon(tn); return ret; } @@ -1601,7 +1603,8 @@ export class Parser extends DiagnosticEmitter { tn.range(startPos, tn.pos) ); ret.overriddenModuleName = this.currentModuleName; - tn.skip(Token.Semicolon); + if (body) tn.skip(Token.Semicolon); + else this.parseSemicolon(tn); return ret; } @@ -1669,6 +1672,13 @@ export class Parser extends DiagnosticEmitter { } if (arrowKind) { + if (tn.peek() == Token.Equals_GreaterThan && tn.peekOnNewLine()) { + this.error( + DiagnosticCode.Unexpected_token, + tn.range(tn.nextTokenPos) + ); + return null; + } if (!tn.skip(Token.Equals_GreaterThan)) { this.error( DiagnosticCode._0_expected, @@ -2203,7 +2213,7 @@ export class Parser extends DiagnosticEmitter { } return null; } - tn.skip(Token.Semicolon); + this.parseSemicolon(tn); return retIndex; } if (!tn.skipIdentifier(IdentifierHandling.Always)) { @@ -2367,8 +2377,10 @@ export class Parser extends DiagnosticEmitter { body, tn.range(startPos, tn.pos) ); - if (!(isInterface && tn.skip(Token.Comma))) { - tn.skip(Token.Semicolon); + let hasComma = isInterface && tn.skip(Token.Comma); + if (!hasComma) { + if (body) tn.skip(Token.Semicolon); + else this.parseSemicolon(tn); } return retMethod; @@ -2421,7 +2433,8 @@ export class Parser extends DiagnosticEmitter { tn.range(startPos, tn.pos) ); } - if (tn.skip(Token.Exclamation)) { + if (tn.peek() == Token.Exclamation && !tn.peekOnNewLine()) { + tn.next(); flags |= CommonFlags.DefinitelyAssigned; } if (tn.skip(Token.Colon)) { @@ -2465,9 +2478,7 @@ export class Parser extends DiagnosticEmitter { initializer, range ); - if (!(isInterface && tn.skip(Token.Comma))) { - tn.skip(Token.Semicolon); - } + if (!(isInterface && tn.skip(Token.Comma))) this.parseSemicolon(tn); return retField; } return null; @@ -2656,7 +2667,7 @@ export class Parser extends DiagnosticEmitter { this.seenlog.add(internalPath); } } - tn.skip(Token.Semicolon); + this.parseSemicolon(tn); return ret; } else if (tn.skip(Token.Asterisk)) { if (tn.skip(Token.From)) { @@ -2672,7 +2683,7 @@ export class Parser extends DiagnosticEmitter { this.dependees.set(internalPath, new Dependee(currentSource, path)); this.backlog.push(internalPath); } - tn.skip(Token.Semicolon); + this.parseSemicolon(tn); return ret; } else { this.error( @@ -2754,7 +2765,7 @@ export class Parser extends DiagnosticEmitter { range ) ], null, false, tn.range(startPos, tn.pos)); - tn.skip(Token.Semicolon); + this.parseSemicolon(tn); return ret; } @@ -2844,7 +2855,7 @@ export class Parser extends DiagnosticEmitter { this.dependees.set(internalPath, new Dependee(assert(this.currentSource), path)); this.backlog.push(internalPath); } - tn.skip(Token.Semicolon); + this.parseSemicolon(tn); return ret; } else { this.error( @@ -2915,7 +2926,7 @@ export class Parser extends DiagnosticEmitter { 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); + this.parseSemicolon(tn); return ret; } else { this.error( @@ -3078,7 +3089,7 @@ export class Parser extends DiagnosticEmitter { identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); } let ret = Node.createBreakStatement(identifier, tn.range()); - tn.skip(Token.Semicolon); + this.parseSemicolon(tn); return ret; } @@ -3094,7 +3105,7 @@ export class Parser extends DiagnosticEmitter { identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); } let ret = Node.createContinueStatement(identifier, tn.range()); - tn.skip(Token.Semicolon); + this.parseSemicolon(tn); return ret; } @@ -3140,7 +3151,8 @@ export class Parser extends DiagnosticEmitter { } parseExpressionStatement( - tn: Tokenizer + tn: Tokenizer, + isFor: bool = false ): ExpressionStatement | null { // at previous token @@ -3149,7 +3161,8 @@ export class Parser extends DiagnosticEmitter { if (!expr) return null; let ret = Node.createExpressionStatement(expr); - tn.skip(Token.Semicolon); + if (isFor) tn.skip(Token.Semicolon); + else this.parseSemicolon(tn); return ret; } @@ -3172,7 +3185,7 @@ export class Parser extends DiagnosticEmitter { initializer = this.parseVariable(tn, CommonFlags.None, null, tn.tokenPos, true); } else if (!tn.skip(Token.Semicolon)) { - initializer = this.parseExpressionStatement(tn); + initializer = this.parseExpressionStatement(tn, true); if (!initializer) return null; } @@ -3234,7 +3247,7 @@ export class Parser extends DiagnosticEmitter { if (tn.token == Token.Semicolon) { let condition: ExpressionStatement | null = null; if (!tn.skip(Token.Semicolon)) { - condition = this.parseExpressionStatement(tn); + condition = this.parseExpressionStatement(tn, true); if (!condition) return null; } @@ -3375,7 +3388,6 @@ export class Parser extends DiagnosticEmitter { switchCases.push(switchCase); } let ret = Node.createSwitchStatement(condition, switchCases, tn.range(startPos, tn.pos)); - tn.skip(Token.Semicolon); return ret; } else { this.error( @@ -3467,10 +3479,17 @@ export class Parser extends DiagnosticEmitter { // at 'throw': Expression ';'? let startPos = tn.tokenPos; + if (tn.peekOnNewLine()) { + this.error( + DiagnosticCode.Unexpected_token, + tn.range(tn.nextTokenPos) + ); + return null; + } let expression = this.parseExpression(tn); if (!expression) return null; let ret = Node.createThrowStatement(expression, tn.range(startPos, tn.pos)); - if (!tn.skip(Token.Semicolon)) this.checkASI(tn); + this.parseSemicolon(tn); return ret; } @@ -3561,7 +3580,6 @@ export class Parser extends DiagnosticEmitter { finallyStatements, tn.range(startPos, tn.pos) ); - tn.skip(Token.Semicolon); return ret; } else { this.error( @@ -3608,7 +3626,7 @@ export class Parser extends DiagnosticEmitter { type, tn.range(startPos, tn.pos) ); - tn.skip(Token.Semicolon); + this.parseSemicolon(tn); ret.overriddenModuleName = this.currentModuleName; return ret; } else { @@ -3638,7 +3656,7 @@ export class Parser extends DiagnosticEmitter { let moduleName = tn.readString(); let ret = Node.createModuleDeclaration(moduleName, flags, tn.range(startPos, tn.pos)); this.currentModuleName = moduleName; - tn.skip(Token.Semicolon); + this.parseSemicolon(tn); return ret; } @@ -3649,10 +3667,10 @@ export class Parser extends DiagnosticEmitter { // at 'void': Expression ';'? let startPos = tn.tokenPos; - let expression = this.parseExpression(tn, Precedence.Grouping); + let expression = this.parseExpression(tn, Precedence.UnaryPrefix); if (!expression) return null; let ret = Node.createVoidStatement(expression, tn.range(startPos, tn.pos)); - tn.skip(Token.Semicolon); + this.parseSemicolon(tn); return ret; } @@ -3670,7 +3688,6 @@ export class Parser extends DiagnosticEmitter { let statement = this.parseStatement(tn); if (!statement) return null; let ret = Node.createWhileStatement(expression, statement, tn.range(startPos, tn.pos)); - tn.skip(Token.Semicolon); return ret; } else { this.error( @@ -4131,6 +4148,15 @@ export class Parser extends DiagnosticEmitter { while ( (nextPrecedence = determinePrecedence(tn.peek())) >= precedence ) { + let nextToken = tn.peek(); + if ( + ( + nextToken == Token.Plus_Plus || + nextToken == Token.Minus_Minus || + nextToken == Token.As || + nextToken == Token.Exclamation + ) && tn.peekOnNewLine() + ) break; let token = tn.next(); switch (token) { @@ -4430,6 +4456,12 @@ export class Parser extends DiagnosticEmitter { ); } + private parseSemicolon( + tn: Tokenizer + ): void { + if (!tn.skip(Token.Semicolon)) this.checkASI(tn); + } + /** Skips over a statement on errors in an attempt to reduce unnecessary diagnostic noise. */ skipStatement(tn: Tokenizer): void { if (tn.peekOnNewLine()) tn.next(); // if reset() to the previous line diff --git a/tests/compiler/asi.debug.wat b/tests/compiler/asi.debug.wat new file mode 100644 index 0000000000..ba4458a01d --- /dev/null +++ b/tests/compiler/asi.debug.wat @@ -0,0 +1,52 @@ +(module + (type $0 (func)) + (type $1 (func (param i32 i32 i32 i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (global $asi/i (mut i32) (i32.const 0)) + (global $asi/j (mut i32) (i32.const 7)) + (global $asi/k (mut i32) (i32.const 1)) + (global $~lib/memory/__data_end i32 (i32.const 44)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 32812)) + (global $~lib/memory/__heap_base i32 (i32.const 32812)) + (memory $0 1) + (data $0 (i32.const 12) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\0c\00\00\00a\00s\00i\00.\00t\00s\00") + (table $0 1 1 funcref) + (elem $0 (i32.const 1)) + (export "memory" (memory $0)) + (start $~start) + (func $start:asi + global.get $asi/j + global.set $asi/i + global.get $asi/k + i32.const 1 + i32.add + global.set $asi/k + global.get $asi/i + i32.const 7 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 8 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $asi/k + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 9 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + ) + (func $~start + call $start:asi + ) +) diff --git a/tests/compiler/asi.release.wat b/tests/compiler/asi.release.wat new file mode 100644 index 0000000000..1b20708c98 --- /dev/null +++ b/tests/compiler/asi.release.wat @@ -0,0 +1,28 @@ +(module + (type $0 (func)) + (type $1 (func (param i32 i32 i32 i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (global $asi/k (mut i32) (i32.const 1)) + (memory $0 1) + (data $0 (i32.const 1036) "\1c") + (data $0.1 (i32.const 1048) "\02\00\00\00\0c\00\00\00a\00s\00i\00.\00t\00s") + (export "memory" (memory $0)) + (start $~start) + (func $~start + global.get $asi/k + i32.const 1 + i32.add + global.set $asi/k + global.get $asi/k + i32.const 2 + i32.ne + if + i32.const 0 + i32.const 1056 + i32.const 9 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + ) +) diff --git a/tests/compiler/asi.ts b/tests/compiler/asi.ts new file mode 100644 index 0000000000..2158fa53d2 --- /dev/null +++ b/tests/compiler/asi.ts @@ -0,0 +1,9 @@ +let i: i32 = 0; +let j: i32 = 7; +let k: i32 = 1; + +i = j +++k + +assert(i == 7); +assert(k == 2); \ No newline at end of file diff --git a/tests/compiler/resolve-elementaccess.debug.wat b/tests/compiler/resolve-elementaccess.debug.wat index f6a7e9d7e2..a8e9ae57e3 100644 --- a/tests/compiler/resolve-elementaccess.debug.wat +++ b/tests/compiler/resolve-elementaccess.debug.wat @@ -44,6 +44,7 @@ (global $~lib/util/number/_exp_pow (mut i32) (i32.const 0)) (global $~lib/native/ASC_SHRINK_LEVEL i32 (i32.const 0)) (global $resolve-elementaccess/buf (mut i32) (i32.const 0)) + (global $resolve-elementaccess/voidIndex (mut i32) (i32.const 0)) (global $~lib/rt/__rtti_base i32 (i32.const 3776)) (global $~lib/memory/__data_end i32 (i32.const 3808)) (global $~lib/memory/__stack_pointer (mut i32) (i32.const 36576)) @@ -4929,6 +4930,7 @@ (local $2 i32) (local $3 i32) (local $4 i32) + (local $5 i32) global.get $~lib/memory/__stack_pointer i32.const 20 i32.sub @@ -4960,38 +4962,38 @@ call $~lib/typedarray/Float32Array#constructor global.set $resolve-elementaccess/arr global.get $resolve-elementaccess/arr - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 0 f32.const 1 call $~lib/typedarray/Float32Array#__set global.get $resolve-elementaccess/arr - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 1 f32.const 2 call $~lib/typedarray/Float32Array#__set global.get $resolve-elementaccess/arr - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=4 - local.get $4 + local.get $5 i32.const 0 call $~lib/typedarray/Float32Array#__get i32.const 0 call $~lib/number/F32#toString - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 2144 call $~lib/string/String.__eq i32.eqz @@ -5004,20 +5006,20 @@ unreachable end global.get $resolve-elementaccess/arr - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=4 - local.get $4 + local.get $5 i32.const 1 call $~lib/typedarray/Float32Array#__get i32.const 0 call $~lib/number/F32#toString - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 2256 call $~lib/string/String.__eq i32.eqz @@ -5034,39 +5036,39 @@ local.tee $0 i32.store offset=8 local.get $0 - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=4 - local.get $4 + local.get $5 i32.const 0 local.tee $1 global.get $resolve-elementaccess/arr - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=12 - local.get $4 + local.get $5 i32.const 0 call $~lib/typedarray/Float32Array#__get f32.const 10 f32.add call $~lib/typedarray/Float32Array#__set local.get $0 - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=4 - local.get $4 + local.get $5 local.get $1 call $~lib/typedarray/Float32Array#__get i32.const 0 call $~lib/number/F32#toString - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 2288 call $~lib/string/String.__eq i32.eqz @@ -5079,29 +5081,29 @@ unreachable end global.get $resolve-elementaccess/arr - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 0 global.get $resolve-elementaccess/arr - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=4 - local.get $4 + local.get $5 i32.const 0 call $~lib/typedarray/Float32Array#__get f32.const 10 f32.add call $~lib/typedarray/Float32Array#__set global.get $resolve-elementaccess/arr - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 0 call $~lib/typedarray/Float32Array#__get f32.const 21 @@ -5120,38 +5122,38 @@ call $resolve-elementaccess/Buffer#constructor global.set $resolve-elementaccess/buf global.get $resolve-elementaccess/buf - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 0 i32.const 1 call $~lib/typedarray/Uint8Array#__set global.get $resolve-elementaccess/buf - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 1 i32.const 2 call $~lib/typedarray/Uint8Array#__set global.get $resolve-elementaccess/buf - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=4 - local.get $4 + local.get $5 i32.const 0 call $~lib/typedarray/Uint8Array#__get i32.const 10 call $~lib/number/U8#toString - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 3696 call $~lib/string/String.__eq i32.eqz @@ -5164,20 +5166,20 @@ unreachable end global.get $resolve-elementaccess/buf - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=4 - local.get $4 + local.get $5 i32.const 1 call $~lib/typedarray/Uint8Array#__get i32.const 10 call $~lib/number/U8#toString - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 3728 call $~lib/string/String.__eq i32.eqz @@ -5194,39 +5196,39 @@ local.tee $2 i32.store offset=16 local.get $2 - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=4 - local.get $4 + local.get $5 i32.const 0 local.tee $3 global.get $resolve-elementaccess/buf - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=12 - local.get $4 + local.get $5 i32.const 0 call $~lib/typedarray/Uint8Array#__get i32.const 10 i32.add call $~lib/typedarray/Uint8Array#__set local.get $2 - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=4 - local.get $4 + local.get $5 local.get $3 call $~lib/typedarray/Uint8Array#__get i32.const 10 call $~lib/number/U8#toString - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 3760 call $~lib/string/String.__eq i32.eqz @@ -5239,29 +5241,29 @@ unreachable end global.get $resolve-elementaccess/buf - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 0 global.get $resolve-elementaccess/buf - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store offset=4 - local.get $4 + local.get $5 i32.const 0 call $~lib/typedarray/Uint8Array#__get i32.const 10 i32.add call $~lib/typedarray/Uint8Array#__set global.get $resolve-elementaccess/buf - local.set $4 + local.set $5 global.get $~lib/memory/__stack_pointer - local.get $4 + local.get $5 i32.store - local.get $4 + local.get $5 i32.const 0 call $~lib/typedarray/Uint8Array#__get i32.const 21 @@ -5275,6 +5277,32 @@ call $~lib/builtins/abort unreachable end + global.get $resolve-elementaccess/buf + local.set $5 + global.get $~lib/memory/__stack_pointer + local.get $5 + i32.store + local.get $5 + global.get $resolve-elementaccess/voidIndex + local.tee $4 + i32.const 1 + i32.add + global.set $resolve-elementaccess/voidIndex + local.get $4 + call $~lib/typedarray/Uint8Array#__get + drop + global.get $resolve-elementaccess/voidIndex + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 2176 + i32.const 49 + i32.const 1 + call $~lib/builtins/abort + unreachable + end global.get $~lib/memory/__stack_pointer i32.const 20 i32.add diff --git a/tests/compiler/resolve-elementaccess.release.wat b/tests/compiler/resolve-elementaccess.release.wat index 8a6fc68b91..80af465806 100644 --- a/tests/compiler/resolve-elementaccess.release.wat +++ b/tests/compiler/resolve-elementaccess.release.wat @@ -33,6 +33,7 @@ (global $~lib/util/number/_frc_pow (mut i64) (i64.const 0)) (global $~lib/util/number/_exp_pow (mut i32) (i32.const 0)) (global $resolve-elementaccess/buf (mut i32) (i32.const 0)) + (global $resolve-elementaccess/voidIndex (mut i32) (i32.const 0)) (global $~lib/memory/__stack_pointer (mut i32) (i32.const 37600)) (memory $0 1) (data $0 (i32.const 1036) ",") @@ -114,6 +115,53 @@ global.set $~lib/rt/itcms/visitCount end ) + (func $~lib/typedarray/Uint8Array#__get (param $0 i32) (param $1 i32) (result i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 4832 + i32.lt_s + if + i32.const 37632 + i32.const 37680 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $1 + local.get $0 + i32.load offset=8 + i32.ge_u + if + i32.const 1360 + i32.const 1568 + i32.const 167 + i32.const 45 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $1 + local.get $0 + i32.load offset=4 + i32.add + i32.load8_u + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + ) (func $~lib/rt/itcms/__new (param $0 i32) (param $1 i32) (result i32) (local $2 i32) (local $3 i32) @@ -428,53 +476,6 @@ memory.fill local.get $1 ) - (func $~lib/typedarray/Uint8Array#__get (param $0 i32) (param $1 i32) (result i32) - global.get $~lib/memory/__stack_pointer - i32.const 4 - i32.sub - global.set $~lib/memory/__stack_pointer - global.get $~lib/memory/__stack_pointer - i32.const 4832 - i32.lt_s - if - i32.const 37632 - i32.const 37680 - i32.const 1 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - global.get $~lib/memory/__stack_pointer - i32.const 0 - i32.store - global.get $~lib/memory/__stack_pointer - local.get $0 - i32.store - local.get $1 - local.get $0 - i32.load offset=8 - i32.ge_u - if - i32.const 1360 - i32.const 1568 - i32.const 167 - i32.const 45 - call $~lib/builtins/abort - unreachable - end - global.get $~lib/memory/__stack_pointer - local.get $0 - i32.store - local.get $1 - local.get $0 - i32.load offset=4 - i32.add - i32.load8_u - global.get $~lib/memory/__stack_pointer - i32.const 4 - i32.add - global.set $~lib/memory/__stack_pointer - ) (func $~lib/typedarray/Float32Array#__get (param $0 i32) (param $1 i32) (result f32) (local $2 f32) global.get $~lib/memory/__stack_pointer @@ -3834,6 +3835,30 @@ unreachable end global.get $~lib/memory/__stack_pointer + global.get $resolve-elementaccess/buf + local.tee $0 + i32.store + global.get $resolve-elementaccess/voidIndex + local.tee $1 + i32.const 1 + i32.add + global.set $resolve-elementaccess/voidIndex + local.get $0 + local.get $1 + call $~lib/typedarray/Uint8Array#__get + drop + global.get $resolve-elementaccess/voidIndex + i32.const 1 + i32.ne + if + i32.const 0 + i32.const 3200 + i32.const 49 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer i32.const 20 i32.add global.set $~lib/memory/__stack_pointer diff --git a/tests/compiler/resolve-elementaccess.ts b/tests/compiler/resolve-elementaccess.ts index d10029bb63..33a4ca3bbb 100644 --- a/tests/compiler/resolve-elementaccess.ts +++ b/tests/compiler/resolve-elementaccess.ts @@ -42,3 +42,8 @@ assert( ); buf[0] += 10; // void context assert(buf[0] == 21); + +let voidIndex: i32 = 0; +void buf +[voidIndex++]; +assert(voidIndex == 1); diff --git a/tests/parser/asi.ts b/tests/parser/asi.ts index cb15d11762..fe4aef5a58 100644 --- a/tests/parser/asi.ts +++ b/tests/parser/asi.ts @@ -23,3 +23,114 @@ function successAfterLet(): i32 { let a = 0 return a } + +function failExpressionStatement(): void { + let first: i32 = 1; + first second; +} + +function failThrowNewline(): void { + throw + 123; +} + +function failArrowNewline(): void { + let fn = (value: i32) + => value; +} + +function failAsNewline(value: any): any { + return value + as any; +} + +function failVariableAssertionNewline(): void { + let value + !: i32; +} + +function successPostfixNewline(): void { + let current: i32 = 0; + let previous: i32 = 45; + let count: i32 = 13; + current = previous + ++count + current = previous++ +} + +function successExpressionContinuations(first: any, second: any): any { + let call = first + (second); + let element = first + [0]; + let property = first + .value; + return first + + second; +} + +function successPrefixAfterNewline(value: any, next: any): any { + return value + !next +} + +function failBreakTerminator(): void { + while (true) { + break target next; + } +} + +function failContinueTerminator(): void { + while (true) { + continue target next; + } +} + +function failFieldTerminator(): void { + class Fields { + first: i32 = 1 second: i32 = 2; + } +} + +class FieldsWithASI { + first: i32 = 1 + second: i32 = 2 +} + +function failElseAfterWhileEmptyStatement(): void { + if (true) while (false) {}; else {} +} + +function failElseAfterSwitchEmptyStatement(): void { + if (true) switch (false) {}; else {} +} + +function failElseAfterTryEmptyStatement(): void { + if (true) try {} finally {}; else {} +} + +type FirstType = i32 +type SecondType = i32; + +type SameLineArrayType = i32[]; +type SameLineGenericType = Array; + +type ArrayTypeBeforeNewlineLiteral = i32 +[]; + +type GenericTypeBeforeNewlineAssertion = Array +genericValue; + +type FailSameLineType = i32 type NextType = i32; + +import "module" +consume(); + +export {} consume(); + +module "test" +let moduleValue: i32 = 0; + +{ + let blockValue: i32 = 0; +}; diff --git a/tests/parser/asi.ts.fixture.ts b/tests/parser/asi.ts.fixture.ts index 8db95c3eaf..6c6e410bcd 100644 --- a/tests/parser/asi.ts.fixture.ts +++ b/tests/parser/asi.ts.fixture.ts @@ -21,6 +21,115 @@ function successAfterLet(): i32 { let a = 0; return a; } +function failExpressionStatement(): void { + let first: i32 = 1; + first; + second; +} +function failThrowNewline(): void { + 123; +} +function failArrowNewline(): void {} +function failAsNewline(value: any): any { + return value; + as; + any; +} +function failVariableAssertionNewline(): void { + let value; +} +function successPostfixNewline(): void { + let current: i32 = 0; + let previous: i32 = 45; + let count: i32 = 13; + current = previous; + ++count; + current = previous++; +} +function successExpressionContinuations(first: any, second: any): any { + let call = first(second); + let element = first[0]; + let property = first.value; + return first + second; +} +function successPrefixAfterNewline(value: any, next: any): any { + return value; + !next; +} +function failBreakTerminator(): void { + while (true) { + break target; + next; + } +} +function failContinueTerminator(): void { + while (true) { + continue target; + next; + } +} +function failFieldTerminator(): void { + class Fields { + first: i32 = 1; + second: i32 = 2; + }; +} +class FieldsWithASI { + first: i32 = 1; + second: i32 = 2; +} +function failElseAfterWhileEmptyStatement(): void { + if (true) while (false) {}; +; + ; +} +function failElseAfterSwitchEmptyStatement(): void { + if (true) switch (false) { +}; +; + ; +} +function failElseAfterTryEmptyStatement(): void { + if (true) try { + } finally { + }; +; + ; + } +type FirstType = i32; +type SecondType = i32; +type SameLineArrayType = Array; +type SameLineGenericType = Array; +type ArrayTypeBeforeNewlineLiteral = i32; +[]; +type GenericTypeBeforeNewlineAssertion = Array; +genericValue; +type FailSameLineType = i32; +type NextType = i32; +import "module"; +consume(); +export {}; +consume(); +module "test"; +let moduleValue: i32 = 0; +{ + let blockValue: i32 = 0; + } // ERROR 1012: "Unexpected token." in asi.ts(2,13+0) // ERROR 1012: "Unexpected token." in asi.ts(7,14+0) // ERROR 1012: "Unexpected token." in asi.ts(11,13+0) +// ERROR 1012: "Unexpected token." in asi.ts(29,9+0) +// ERROR 1012: "Unexpected token." in asi.ts(34,5+0) +// ERROR 1012: "Unexpected token." in asi.ts(39,5+0) +// ERROR 1109: "Expression expected." in asi.ts(39,5+2) +// ERROR 1012: "Unexpected token." in asi.ts(44,8+0) +// ERROR 1110: "Type expected." in asi.ts(48,12+0) +// ERROR 1109: "Expression expected." in asi.ts(49,6+1) +// ERROR 1012: "Unexpected token." in asi.ts(79,18+0) +// ERROR 1012: "Unexpected token." in asi.ts(85,21+0) +// ERROR 1012: "Unexpected token." in asi.ts(91,20+0) +// ERROR 1109: "Expression expected." in asi.ts(101,31+4) +// ERROR 1109: "Expression expected." in asi.ts(105,32+4) +// ERROR 1109: "Expression expected." in asi.ts(109,32+4) +// ERROR 1012: "Unexpected token." in asi.ts(124,29+0) +// ERROR 1012: "Unexpected token." in asi.ts(129,11+0) diff --git a/tests/parser/interface-errors.ts.fixture.ts b/tests/parser/interface-errors.ts.fixture.ts index bc1285e3d3..9dd947be22 100644 --- a/tests/parser/interface-errors.ts.fixture.ts +++ b/tests/parser/interface-errors.ts.fixture.ts @@ -18,6 +18,7 @@ interface Foo { constructor(); } // ERROR 1242: "'abstract' modifier can only appear on a class, method, or property declaration." in interface-errors.ts(1,1+8) +// ERROR 1012: "Unexpected token." in interface-errors.ts(1,10+0) // ERROR 1176: "Interface declaration cannot have 'implements' clause." in interface-errors.ts(8,15+10) // ERROR 1042: "'abstract' modifier cannot be used here." in interface-errors.ts(15,3+8) // ERROR 1042: "'private' modifier cannot be used here." in interface-errors.ts(16,3+7) diff --git a/tests/parser/literals.ts b/tests/parser/literals.ts index 086346090b..093efeb04e 100644 --- a/tests/parser/literals.ts +++ b/tests/parser/literals.ts @@ -112,7 +112,7 @@ tag`\unicode\xGG\u\x`; // see https://tc39.es/proposal-template-literal-revision 0o2000000000000000000000; 0b10000000000000000000000000000000000000000000000000000000000000000; -// technically invalid, but not handled by AS yet, TS1005: ';' expected +// technically invalid; retained to test parser recovery 3 4; 5 c; 6.7 d; diff --git a/tests/parser/literals.ts.fixture.ts b/tests/parser/literals.ts.fixture.ts index 3f71d572ae..bd1b934442 100644 --- a/tests/parser/literals.ts.fixture.ts +++ b/tests/parser/literals.ts.fixture.ts @@ -117,10 +117,13 @@ b; // ERROR 1109: "Expression expected." in literals.ts(98,4+1) // ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(99,2+0) // ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(100,2+0) +// ERROR 1012: "Unexpected token." in literals.ts(100,2+0) // ERROR 1109: "Expression expected." in literals.ts(101,3+1) // ERROR 6188: "Numeric separators are not allowed here." in literals.ts(103,2+0) // ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(104,3+0) +// ERROR 1012: "Unexpected token." in literals.ts(104,3+0) // ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(105,4+0) +// ERROR 1012: "Unexpected token." in literals.ts(105,4+0) // ERROR 1125: "Hexadecimal digit expected." in literals.ts(106,4+1) // ERROR 1125: "Hexadecimal digit expected." in literals.ts(106,12+1) // ERROR 1125: "Hexadecimal digit expected." in literals.ts(106,16+1) @@ -129,3 +132,7 @@ b; // ERROR 236: "Literal '0xFFF000000000000FFF' does not fit into 'i64' or 'u64' types." in literals.ts(111,1+20) // ERROR 236: "Literal '0o2000000000000000000000' does not fit into 'i64' or 'u64' types." in literals.ts(112,1+24) // ERROR 236: "Literal '0b10000000000000000000000000000000000000000000000000000000000000000' does not fit into 'i64' or 'u64' types." in literals.ts(113,1+67) +// ERROR 1012: "Unexpected token." in literals.ts(116,3+0) +// ERROR 1012: "Unexpected token." in literals.ts(117,3+0) +// ERROR 1012: "Unexpected token." in literals.ts(118,5+0) +// ERROR 1012: "Unexpected token." in literals.ts(119,3+0)