Skip to content

Commit fa87304

Browse files
committed
Merge branch 'experimental-try-catch-finally' into v0.29
2 parents 5d3a559 + e751d27 commit fa87304

File tree

13 files changed

+13545
-14
lines changed

13 files changed

+13545
-14
lines changed

src/compiler.ts

Lines changed: 364 additions & 10 deletions
Large diffs are not rendered by default.

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"Initializer, definitive assignment or nullable type expected.": 238,
5353
"Definitive assignment has no effect on local variables.": 239,
5454
"Ambiguous operator overload '{0}' (conflicting overloads '{1}' and '{2}').": 240,
55+
"Only Error or its subclasses can be thrown, but found type '{0}'.": 241,
5556

5657
"Importing the table disables some indirect call optimizations.": 901,
5758
"Exporting the table disables some indirect call optimizations.": 902,

src/flow.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,35 @@ export class Flow {
265265
trueFlows: Map<ExpressionRef,Flow> | null = null;
266266
/** Alternative flows if a compound expression is false-ish. */
267267
falseFlows: Map<ExpressionRef,Flow> | null = null;
268+
/** Try-finally context: local index for pending action (0=none, 1=return, 2=break, 3=continue). */
269+
tryFinallyPendingActionLocal: i32 = -1;
270+
/** Try-finally context: local index for pending return value. */
271+
tryFinallyPendingValueLocal: i32 = -1;
272+
/** Try-finally context: label to branch to for finally dispatch. */
273+
tryFinallyDispatchLabel: string | null = null;
274+
/** Try-finally context: return type for the pending value. */
275+
tryFinallyReturnType: Type | null = null;
268276

269277
/** Tests if this is an inline flow. */
270278
get isInline(): bool {
271279
return this.inlineFunction != null;
272280
}
273281

282+
/** Tests if this flow or any parent is in a try-finally context. */
283+
get isInTryFinally(): bool {
284+
return this.tryFinallyPendingActionLocal >= 0;
285+
}
286+
287+
/** Gets the try-finally context from this flow or a parent flow. */
288+
getTryFinallyContext(): Flow | null {
289+
let flow: Flow | null = this;
290+
while (flow) {
291+
if (flow.tryFinallyPendingActionLocal >= 0) return flow;
292+
flow = flow.parent;
293+
}
294+
return null;
295+
}
296+
274297
/** Gets the source function being compiled. Differs from target when inlining. */
275298
get sourceFunction(): Function {
276299
// Obtaining the source function is useful when resolving elements relative

src/program.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,14 @@ export class Program extends DiagnosticEmitter {
636636
}
637637
private _stringInstance: Class | null = null;
638638

639+
/** Gets the standard `Error` instance. */
640+
get errorInstance(): Class {
641+
let cached = this._errorInstance;
642+
if (!cached) this._errorInstance = cached = this.requireClass(CommonNames.Error);
643+
return cached;
644+
}
645+
private _errorInstance: Class | null = null;
646+
639647
/** Gets the standard `RegExp` instance. */
640648
get regexpInstance(): Class {
641649
let cached = this._regexpInstance;

std/assembly/builtins.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2603,13 +2603,32 @@ export abstract class i31 { // FIXME: usage of 'new' requires a class :(
26032603
// @ts-ignore: decorator
26042604
@external("env", "abort")
26052605
@external.js("throw Error(`${message} in ${fileName}:${lineNumber}:${columnNumber}`);")
2606-
declare function abort(
2606+
declare function __abort_impl(
26072607
message?: string | null,
26082608
fileName?: string | null,
26092609
lineNumber?: u32,
26102610
columnNumber?: u32
26112611
): void;
26122612

2613+
// When exception-handling is enabled, abort throws an Error that can be caught.
2614+
// When disabled, it calls the external abort function (host implementation).
2615+
function abort(
2616+
message: string | null = null,
2617+
fileName: string | null = null,
2618+
lineNumber: u32 = 0,
2619+
columnNumber: u32 = 0
2620+
): void {
2621+
if (isDefined(ASC_FEATURE_EXCEPTION_HANDLING)) {
2622+
let fullMessage = message ? message : "abort";
2623+
if (fileName) {
2624+
fullMessage += " in " + fileName + ":" + lineNumber.toString() + ":" + columnNumber.toString();
2625+
}
2626+
throw new Error(fullMessage);
2627+
} else {
2628+
__abort_impl(message, fileName, lineNumber, columnNumber);
2629+
}
2630+
}
2631+
26132632
// @ts-ignore: decorator
26142633
@external("env", "trace")
26152634
@external.js("console.log(message, ...[a0, a1, a2, a3, a4].slice(0, n));")

tests/compiler.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,10 @@ async function runTest(basename) {
254254

255255
if (config.features) {
256256
config.features.forEach(feature => {
257-
if (!features.includes(feature) && !features.includes("*")) {
257+
let featureConfig = featuresConfig[feature];
258+
if (!features.includes(feature) && !features.includes("*") && !featureConfig.enabled) {
258259
missing_features.push(feature);
259260
}
260-
let featureConfig = featuresConfig[feature];
261261
if (featureConfig.asc_flags) {
262262
featureConfig.asc_flags.forEach(flag => {
263263
Array.prototype.push.apply(asc_flags, flag.split(" "));

tests/compiler/exceptions.debug.wat

Lines changed: 7315 additions & 0 deletions
Large diffs are not rendered by default.

tests/compiler/exceptions.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"features": ["exception-handling"]
3+
}

0 commit comments

Comments
 (0)