Another statement expression-related proposal

Isiah Meadows isiahmeadows at gmail.com
Wed Nov 2 12:36:10 UTC 2016


Inline.

On Wed, Nov 2, 2016, 01:01 Bob Myers <rtm at gol.com> wrote:

> Just a random thought, but would `{= =}` work for expression blocks?
>
> ```js
> // plain block
> const foo = {= let a = 1; a =};
>
> assert.equal(foo, 1)
>
> // if-else
> let cond = false
> const bar = {= if (cond) "hi" else "bye" =};
>
> assert.equal(bar, "bye")
>
> // try-catch
> let e = new Error()
> const error = {= try { throw e } catch (e) { e } =};
> assert.equal(error, e)
> ```
>

In theory, yes, but it doesn't exactly look very pretty (too many equals
signs and curly braces).


>
> I don't know about the loop idea. It seems like it's trying to do too much.
>

The loop thing is a bit extra, complicating things some, but I feel it's
merited by the ability to avoid a lot of the confusion when using loops
with the current `do` expression proposal (loops currently act like
`reduce`, which is incredibly unintuitive).


> On Wed, Nov 2, 2016 at 10:13 AM, Isiah Meadows <isiahmeadows at gmail.com>
> wrote:
>
> Yes, there's been a bit of talk about modifying the `do` proposal in
> various ways (like allowing more than a block, using `=` to
> differentiate, etc.), but each of these have potential ambiguities
> (like conflicting with `do-while` or object literal syntax,
> respectively), and give unintuitive results with loops.
>
> Here's my idea: prepend a `::` to any non-expression statement, and it
> becomes an expression. The last statement's value (as if through
> `eval`) is used as the return value, with exception of loops, which
> return an array generated from their loop body. Here's a few examples
> to clarify:
>
> ```js
> // plain block
> const foo = :: { let a = 1; a }
> assert.equal(foo, 1)
>
> // if-else
> let cond = false
> const bar = :: if (cond) "hi" else "bye"
> assert.equal(bar, "bye")
>
> // try-catch
> let e = new Error()
> const error = :: try { throw e } catch (e) { e }
> assert.equal(error, e)
>
> // while loop
> let i = 0
> const range = :: while (i < 10) i++
> assert.deepEqual(range, [
>   0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
> ])
>
> // for + nested if-else
> const fizzBuzz = :: for (let i = 0; i < 100; i++) {
>   if (i % 15) "FizzBuzz"
>   else if (i % 3) "Fizz"
>   else if (i % 5) "Buzz"
>   // If no expression is evaluated in the body, then no value
>   // is pushed.
> }
> assert.deepEqual(fizzBuzz, [
>   // 100 lines of the classic "Fizz", "Buzz", and "FizzBuzz"
> ])
> ```
>
> What do you all think of this?
>
> -----------
>
> To clarify, here's some more detailed semantics:
>
> ### Grammar
>
> - `:: ExpressionStatement`
> - `:: Declaration`
> - `:: VariableStatement`
>
> These are early errors, and they are all redundant, anyways, since you
> already have a value you could use.
>
> - `:: ContinueStatement`
> - `:: BreakStatement`
> - `:: ReturnStatement`
> - `:: DebuggerStatement`
> - `:: ThrowStatement`
> - `:: EmptyStatement`
>
> These are also early errors, since there's no real value you can
> associate with them.
>
> - `:: BlockStatement`
> - `:: IfStatement`
> - `:: SwitchStatement`
> - `:: WithStatement`
> - `:: TryStatement`
>
> 1. Let `completion` be ? ExecuteStatement(`statement`), where
> `statement` is one of the statements above.
> 2. If `completion` is *none*, return `undefined`
> 3. Otherwise, return `completion`.
>
> - `:: IterationStatement`
>
> 1. Return ? ExecuteIterationStatement(`statement`), where `statement`
> is one of the statements above.
>
> - `:: LabelledStatement`
>
> This works similarly, but has an outer label instead. The same above
> statements are also similarly banned as `LabelledItem` entries.
> Additionally, the Annex B extension for FunctionDeclaraions are also
> early errors.
>
> (Should these even be allowed? I'm open to making this an early error
> instead.)
>
> ### Abstract Operation ExecuteStatement(`statement`)
>
> 1. If `statement` is an IterationStatement:
>   1. Let `list` be a new empty list.
>   2. Evaluate `statement`, but for each `child` statement:
>     1. Let `result` be ? ExecuteStatement(`child`).
>     2. If `result` is not *empty*, then append `result` to `list`.
>   3. Return `list`.
> 2. If `statement` is an ExpressionStatement:
>   1. Return the result of evaluating the expression within.
> 3. If `statement` is a `BreakStatement` or `ContinueStatement`:
>   1. Evaluate `statement`
>   2. Return *empty*.
> 4. If `statement` is a `Declaration`:
>   1. Evaluate `statement`.
>   2. Return the value of the resulting declaration
> 5. Otherwise:
>   1. Let `last` be *empty*
>   2. Evaluate `statement`. For each `child` statement:
>     1. Let `last` be ? ExecuteStatement(`child`).
>   3. Note: `last` is the final expression's value, or `empty` if there
> was no final expression.
>   4. Return `last`.
>
> (I probably missed several edge cases, but this is just a mailing list
> strawman.)
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20161102/e58e8f6a/attachment.html>


More information about the es-discuss mailing list