Skip to content

Commit 0e0a304

Browse files
committed
update with a simpler spec
1 parent 8cd5d98 commit 0e0a304

File tree

1 file changed

+105
-262
lines changed

1 file changed

+105
-262
lines changed

spec.emu

Lines changed: 105 additions & 262 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ stage: 0
1010
contributors: Arthur Fiorette, Arlen Beiler
1111
</pre>
1212

13+
<emu-biblio href="node_modules/@tc39/ecma262-biblio/biblio.json"></emu-biblio>
14+
1315
<emu-intro id="sec-intro">
1416
<h1>Introduction</h1>
1517
<emu-note>
@@ -18,276 +20,117 @@ contributors: Arthur Fiorette, Arlen Beiler
1820
<p>This proposal introduces a `try` operator and `Result` class to JavaScript for improved error handling ergonomics. The `try` operator evaluates an expression within an implicit try-catch block and returns a `Result` instance containing either the successful value or the caught error.</p>
1921
</emu-intro>
2022

21-
<emu-clause id="sec-result-objects">
22-
<h1>Result Objects</h1>
23-
24-
<emu-clause id="sec-result-constructor">
25-
<h1>The Result Constructor</h1>
26-
<p>The Result constructor is the %Result% intrinsic object. When called as a constructor, it creates and initializes a new Result object.</p>
27-
28-
<emu-clause id="sec-result">
29-
<h1>Result ( _ok_, _error_, _value_ )</h1>
30-
<p>When `Result` is called with arguments _ok_, _error_, and _value_, the following steps are taken:</p>
31-
<emu-alg>
32-
1. If NewTarget is *undefined*, throw a *TypeError* exception.
33-
1. Let _result_ be ? OrdinaryCreateFromConstructor(NewTarget, *"%Result.prototype%"*, « [[ResultState]], [[ResultValue]], [[ResultError]] »).
34-
1. Let _booleanOk_ be ToBoolean(_ok_).
35-
1. Perform ! CreateDataPropertyOrThrow(_result_, *"ok"*, _booleanOk_).
36-
1. If _booleanOk_ is *true*, then
37-
1. Set _result_.[[ResultState]] to ~success~.
38-
1. Set _result_.[[ResultValue]] to _value_.
39-
1. Perform ! CreateDataPropertyOrThrow(_result_, *"value"*, _value_).
40-
1. Else,
41-
1. Set _result_.[[ResultState]] to ~failure~.
42-
1. Set _result_.[[ResultError]] to _error_.
43-
1. Perform ! CreateDataPropertyOrThrow(_result_, *"error"*, _error_).
44-
1. Return _result_.
45-
</emu-alg>
46-
</emu-clause>
47-
</emu-clause>
48-
49-
<emu-clause id="sec-properties-of-the-result-constructor">
50-
<h1>Properties of the Result Constructor</h1>
51-
52-
<emu-clause id="sec-result.ok">
53-
<h1>Result.ok ( _value_ )</h1>
54-
<p>When the `Result.ok` method is called with argument _value_, the following steps are taken:</p>
55-
<emu-alg>
56-
1. Let _result_ be ? Construct(%Result%, « *true*, *undefined*, _value_ »).
57-
1. Return _result_.
58-
</emu-alg>
59-
</emu-clause>
60-
61-
<emu-clause id="sec-result.error">
62-
<h1>Result.error ( _error_ )</h1>
63-
<p>When the `Result.error` method is called with argument _error_, the following steps are taken:</p>
64-
<emu-alg>
65-
1. Let _result_ be ? Construct(%Result%, « *false*, _error_, *undefined* »).
66-
1. Return _result_.
67-
</emu-alg>
68-
</emu-clause>
69-
70-
<emu-clause id="sec-result.try">
71-
<h1>Result.try ( _arg_, ..._args_ )</h1>
72-
<p>When the `Result.try` method is called with argument _arg_ and optional arguments _args_, the following steps are taken:</p>
73-
<emu-alg>
74-
1. Let _completion_ be Completion(ResultTryImplementation(_arg_, _args_)).
75-
1. If _completion_ is an abrupt completion, then
76-
1. Return ! Call(%Result.error%, %Result%, « _completion_.[[Value]] »).
77-
1. Return _completion_.[[Value]].
78-
</emu-alg>
79-
80-
<emu-clause id="sec-result-try-implementation" type="abstract operation">
81-
<h1>ResultTryImplementation ( _arg_, _args_ )</h1>
82-
<dl class="header">
83-
</dl>
84-
<emu-alg>
85-
1. Let _result_ be *undefined*.
86-
1. If IsCallable(_arg_) is *true*, then
87-
1. Let _callResult_ be Completion(Call(_arg_, *undefined*, _args_)).
88-
1. If _callResult_ is an abrupt completion, then
89-
1. Return ! Call(%Result.error%, %Result%, « _callResult_.[[Value]] »).
90-
1. Set _result_ to _callResult_.[[Value]].
91-
1. Else,
92-
1. Set _result_ to _arg_.
93-
1. If _result_ is an Object and IsPromise(_result_) is *true*, then
94-
1. Let _fulfillmentHandler_ be a new Abstract Closure with parameters (_value_) that captures nothing and performs the following steps when called:
95-
1. Return ! Call(%Result.ok%, %Result%, « _value_ »).
96-
1. Let _rejectionHandler_ be a new Abstract Closure with parameters (_reason_) that captures nothing and performs the following steps when called:
97-
1. Return ! Call(%Result.error%, %Result%, « _reason_ »).
98-
1. Let _onFulfilled_ be CreateBuiltinFunction(_fulfillmentHandler_, 1, *""*, « »).
99-
1. Let _onRejected_ be CreateBuiltinFunction(_rejectionHandler_, 1, *""*, « »).
100-
1. Return PerformPromiseThen(_result_, _onFulfilled_, _onRejected_).
101-
1. Return ! Call(%Result.ok%, %Result%, « _result_ »).
102-
</emu-alg>
103-
</emu-clause>
104-
</emu-clause>
105-
106-
<emu-clause id="sec-result.prototype">
107-
<h1>Result.prototype</h1>
108-
<p>The initial value of `Result.prototype` is the Result prototype object.</p>
109-
<p>This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.</p>
110-
</emu-clause>
111-
</emu-clause>
112-
113-
<emu-clause id="sec-properties-of-the-result-prototype-object">
114-
<h1>Properties of the Result Prototype Object</h1>
115-
<p>The Result prototype object:</p>
116-
<ul>
117-
<li>is an ordinary object.</li>
118-
<li>is not a Result instance and does not have [[ResultState]], [[ResultValue]], or [[ResultError]] internal slots.</li>
119-
<li>has a [[Prototype]] internal slot whose value is %Object.prototype%.</li>
120-
</ul>
121-
122-
<emu-clause id="sec-result.prototype-@@iterator">
123-
<h1>Result.prototype [ %Symbol.iterator% ] ( )</h1>
124-
<p>When the %Symbol.iterator% method is called, the following steps are taken:</p>
125-
<emu-alg>
126-
1. Let _result_ be the *this* value.
127-
1. Return ? CreateResultIterator(_result_).
128-
</emu-alg>
129-
</emu-clause>
130-
131-
<emu-clause id="sec-result.prototype.constructor">
132-
<h1>Result.prototype.constructor</h1>
133-
<p>The initial value of `Result.prototype.constructor` is %Result%.</p>
134-
</emu-clause>
135-
136-
<emu-clause id="sec-result.prototype-@@toStringTag">
137-
<h1>Result.prototype [ %Symbol.toStringTag% ]</h1>
138-
<p>The initial value of the %Symbol.toStringTag% property is the String value *"Result"*.</p>
139-
<p>This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.</p>
140-
</emu-clause>
141-
</emu-clause>
142-
143-
<emu-clause id="sec-result-iterator-objects">
144-
<h1>Result Iterator Objects</h1>
145-
<p>A Result Iterator is an object that represents a specific iteration over a Result instance. There is not a named constructor for Result Iterator objects.</p>
146-
147-
<emu-clause id="sec-createresultiterator" type="abstract operation">
148-
<h1>
149-
CreateResultIterator (
150-
_result_: a Result object,
151-
): either a normal completion containing a Result Iterator or a throw completion
152-
</h1>
153-
<dl class="header">
154-
</dl>
155-
<emu-alg>
156-
1. Perform ? RequireInternalSlot(_result_, [[ResultState]]).
157-
1. Let _iterator_ be OrdinaryObjectCreate(%ResultIteratorPrototype%, « [[IteratedResult]], [[ResultIteratorNextIndex]] »).
158-
1. Set _iterator_.[[IteratedResult]] to _result_.
159-
1. Set _iterator_.[[ResultIteratorNextIndex]] to 0.
160-
1. Return _iterator_.
161-
</emu-alg>
162-
</emu-clause>
163-
164-
<emu-clause id="sec-%resultiteratorprototype%-object">
165-
<h1>The %ResultIteratorPrototype% Object</h1>
166-
<p>The %ResultIteratorPrototype% object:</p>
167-
<ul>
168-
<li>has a [[Prototype]] internal slot whose value is %IteratorPrototype%.</li>
169-
<li>is an ordinary object.</li>
170-
</ul>
23+
<emu-clause id="sec-assignment-operators">
24+
<h1>Assignment Operators</h1>
25+
<h2>Syntax</h2>
26+
<emu-grammar type="definition">
27+
AssignmentExpression[In, Yield, Await] :
28+
TryExpression[?In, ?Yield, ?Await]
29+
TryExpression[In, Yield, Await] :
30+
`try` [no LineTerminator here] [lookahead != `{`] AssignmentExpression[?In, ?Yield, ?Await]
31+
</emu-grammar>
17132

172-
<emu-clause id="sec-%resultiteratorprototype%.next">
173-
<h1>%ResultIteratorPrototype%.next ( )</h1>
174-
<emu-alg>
175-
1. Let _iterator_ be the *this* value.
176-
1. Perform ? RequireInternalSlot(_iterator_, [[IteratedResult]]).
177-
1. Let _result_ be _iterator_.[[IteratedResult]].
178-
1. Let _index_ be _iterator_.[[ResultIteratorNextIndex]].
179-
1. If _index_ is 0, then
180-
1. Set _iterator_.[[ResultIteratorNextIndex]] to 1.
181-
1. Let _okValue_ be ? Get(_result_, *"ok"*).
182-
1. Return CreateIteratorResultObject(_okValue_, *false*).
183-
1. Else if _index_ is 1, then
184-
1. Set _iterator_.[[ResultIteratorNextIndex]] to 2.
185-
1. If ? HasProperty(_result_, *"error"*) is *true*, then
186-
1. Let _errorValue_ be ? Get(_result_, *"error"*).
187-
1. Return CreateIteratorResultObject(_errorValue_, *false*).
188-
1. Else,
189-
1. Return CreateIteratorResultObject(*undefined*, *false*).
190-
1. Else if _index_ is 2, then
191-
1. Set _iterator_.[[ResultIteratorNextIndex]] to 3.
192-
1. If ? HasProperty(_result_, *"value"*) is *true*, then
193-
1. Let _valueValue_ be ? Get(_result_, *"value"*).
194-
1. Return CreateIteratorResultObject(_valueValue_, *false*).
195-
1. Else,
196-
1. Return CreateIteratorResultObject(*undefined*, *false*).
197-
1. Else,
198-
1. Return CreateIteratorResultObject(*undefined*, *true*).
199-
</emu-alg>
200-
</emu-clause>
201-
202-
<emu-clause id="sec-%resultiteratorprototype%-@@toStringTag">
203-
<h1>%ResultIteratorPrototype% [ %Symbol.toStringTag% ]</h1>
204-
<p>The initial value of the %Symbol.toStringTag% property is the String value *"Result Iterator"*.</p>
205-
<p>This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.</p>
206-
</emu-clause>
207-
</emu-clause>
208-
</emu-clause>
209-
</emu-clause>
210-
211-
<emu-clause id="sec-try-operator">
212-
<h1>The Try Operator</h1>
213-
214-
<emu-clause id="sec-try-operator-runtime-semantics">
215-
<h1>Runtime Semantics</h1>
216-
217-
<emu-clause id="sec-try-operator-static-semantics">
218-
<h1>Static Semantics</h1>
219-
<emu-grammar>
220-
UnaryExpression[Yield, Await] :
221-
`try` UnaryExpression[?Yield, ?Await]
222-
</emu-grammar>
223-
</emu-clause>
224-
225-
<emu-clause id="sec-try-operator-evaluation" type="sdo">
226-
<h1>Runtime Semantics: Evaluation</h1>
227-
<emu-grammar>UnaryExpression : `try` UnaryExpression</emu-grammar>
228-
<emu-alg>
229-
1. Let _exprRef_ be Completion(Evaluation of |UnaryExpression|).
230-
1. If _exprRef_ is an abrupt completion, then
231-
1. Return ! Call(%Result.error%, %Result%, « _exprRef_.[[Value]] »).
232-
1. Let _value_ be Completion(GetValue(_exprRef_)).
233-
1. If _value_ is an abrupt completion, then
234-
1. Return ! Call(%Result.error%, %Result%, « _value_.[[Value]] »).
235-
1. Return ! Call(%Result.ok%, %Result%, « _value_.[[Value]] »).
236-
</emu-alg>
237-
</emu-clause>
238-
</emu-clause>
239-
240-
<emu-clause id="sec-try-operator-await-interaction">
241-
<h1>Interaction with Await</h1>
242-
<p>When the try operator is used with await, it captures both synchronous exceptions and asynchronous rejections.</p>
33+
<emu-note>
34+
<p>Placing the `try` operator in assignment expression allows it to protect an entire assignment expression.</p>
35+
</emu-note>
24336

244-
<emu-grammar>UnaryExpression : `try` `await` UnaryExpression</emu-grammar>
37+
<emu-clause id="sec-comma-operator-runtime-semantics-evaluation" type="sdo">
38+
<h1>Runtime Semantics: Evaluation</h1>
39+
<emu-grammar>TryExpression : `try` AssignmentExpression</emu-grammar>
24540
<emu-alg>
246-
1. Let _exprRef_ be the result of evaluating |UnaryExpression|.
247-
1. Let _value_ be ? GetValue(_exprRef_).
248-
1. Let _promise_ be ? PromiseResolve(%Promise%, _value_).
249-
1. Let _fulfillmentHandler_ be a new Abstract Closure with parameters (_value_) that captures nothing and performs the following steps when called:
250-
1. Return ! Call(%Result.ok%, %Result%, « _value_ »).
251-
1. Let _rejectionHandler_ be a new Abstract Closure with parameters (_reason_) that captures nothing and performs the following steps when called:
252-
1. Return ! Call(%Result.error%, %Result%, « _reason_ »).
253-
1. Let _promiseFulfill_ be CreateBuiltinFunction(_fulfillmentHandler_, 1, *""*, « »).
254-
1. Let _promiseReject_ be CreateBuiltinFunction(_rejectionHandler_, 1, *""*, « »).
255-
1. Return ? Await(PerformPromiseThen(_promise_, _promiseFulfill_, _promiseReject_)).
41+
1. Let _A_ be Completion(Evaluation of |Expression|).
42+
1. If _A_ is an abrupt completion, return ? TryExpressionResult(_A_).
43+
1. Let _B_ be Completion(GetValue(_A_)).
44+
1. Return ? TryExpressionResult(_B_).
25645
</emu-alg>
46+
<emu-note>
47+
<p>GetValue must be called even though its value is not used because it may have observable side-effects.</p>
48+
</emu-note>
49+
<emu-note>
50+
<p>This is identical to <emu-xref href="#sec-try-statement-runtime-semantics-evaluation">evaluation of a try statement</emu-xref>.</p>
51+
</emu-note>
25752
</emu-clause>
258-
</emu-clause>
25953

260-
<emu-clause id="sec-syntax-directed-operations">
261-
<h1>Syntax-Directed Operations</h1>
262-
263-
<emu-clause id="sec-isvalidsimpleassignmenttarget" type="sdo">
264-
<h1>Static Semantics: IsValidSimpleAssignmentTarget</h1>
265-
<emu-grammar>UnaryExpression : `try` UnaryExpression</emu-grammar>
54+
<emu-clause id="sec-try-expression-result" type="abstract operation">
55+
<h1>
56+
TryExpressionResult (
57+
_result_: a Completion Record,
58+
): either a normal completion containing a Result or an abrupt completion
59+
</h1>
60+
<dl class="header">
61+
</dl>
26662
<emu-alg>
267-
1. Return *false*.
63+
1. If _result_ is a normal completion, return Result.ok(_result_.[[VALUE]]).
64+
1. If _result_ is a throw completion, return Result.error(_result_.[[VALUE]]).
65+
1. Return ? _result_.
26866
</emu-alg>
26967
</emu-clause>
68+
<emu-clause id="sec-try-expression-result-ok" type="abstract operation">
69+
<h1>
70+
Result.ok (
71+
_value_: an ECMAScript language value,
72+
): a Result
73+
</h1>
74+
<dl class="header">
75+
<dt>description</dt>
76+
<dd>It is the abstract equivelant of calling `Result.ok(value)`</dd>
77+
</dl>
78+
</emu-clause>
79+
<emu-clause id="sec-try-expression-result-error" type="abstract operation">
80+
<h1>
81+
Result.error (
82+
_value_: an ECMAScript language value,
83+
): a Result
84+
</h1>
85+
<dl class="header">
86+
<dt>description</dt>
87+
<dd>It is the abstract equivelant of calling `Result.error(value)`</dd>
88+
</dl>
89+
</emu-clause>
27090
</emu-clause>
27191

272-
<emu-annex id="sec-grammar-summary">
273-
<h1>Grammar Summary</h1>
274-
275-
<emu-annex id="sec-expressions">
276-
<h1>Expressions</h1>
277-
278-
<emu-prodref name="UnaryExpression"></emu-prodref>
279-
<emu-grammar>
280-
UnaryExpression[Yield, Await] :
281-
UpdateExpression[?Yield, ?Await]
282-
`delete` UnaryExpression[?Yield, ?Await]
283-
`void` UnaryExpression[?Yield, ?Await]
284-
`typeof` UnaryExpression[?Yield, ?Await]
285-
`+` UnaryExpression[?Yield, ?Await]
286-
`-` UnaryExpression[?Yield, ?Await]
287-
`~` UnaryExpression[?Yield, ?Await]
288-
`!` UnaryExpression[?Yield, ?Await]
289-
<ins>`try` UnaryExpression[?Yield, ?Await]</ins>
290-
[+Await] AwaitExpression[?Yield]
291-
</emu-grammar>
292-
</emu-annex>
293-
</emu-annex>
92+
<emu-clause id="sec-result-constructor">
93+
<h1>The Result Constructor</h1>
94+
<pre><code class="javascript">
95+
class Result {
96+
constructor(ok, error, value) {
97+
ok = Boolean(ok)
98+
this.ok = ok
99+
if (ok) {
100+
this.value = value
101+
} else {
102+
this.error = error
103+
}
104+
}
105+
*[Symbol.iterator]() {
106+
yield this.ok
107+
yield this.error
108+
yield this.value
109+
}
110+
static ok(value) {
111+
return new Result(true, undefined, value)
112+
}
113+
static error(error) {
114+
return new Result(false, error, undefined)
115+
}
116+
/* a convenience method for user-land, not used by the try operator */
117+
static try(arg, ...args) {
118+
try {
119+
let result;
120+
if (/* IsCallable(arg) */typeof arg === "function") {
121+
result = arg.call(undefined, args)
122+
} else {
123+
result = arg;
124+
}
125+
if (/* IsPromise (result) */result instanceof Promise) {
126+
return result.then(Result.ok, Result.error)
127+
} else {
128+
return Result.ok(result);
129+
}
130+
} catch (e) {
131+
return Result.error(e)
132+
}
133+
}
134+
}
135+
</code></pre>
136+
</emu-clause>

0 commit comments

Comments
 (0)