Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a specification #51

Merged
merged 2 commits into from
Nov 10, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions spec.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!doctype html>
<meta charset="utf8">
<pre class=metadata>
title: Pipeline operator
stage: 0
contributors: Daniel Ehrenberg
</pre>

<emu-intro id=sec-intro>
<h1>Introduction</h1>
<p>This document specifies the pipeline operator `|>`. See <a href="https://github.com/tc39/proposal-pipeline-operator/">the explainer</a> for an introduction.</p>
<p>The main design decisions made in this specification are:
<ol>
<li>The right argument of `|>` is treated directly as a function; even if it is a |CallExpression|, the result of evaluating that |CallExpression| is treated as the function, rather than slotting the left argument into the arguments list. That is `x |> y(z)` is similar in semantics to `y(z)(x)`. <a href="https://github.com/tc39/proposal-pipeline-operator/issues/4">bug</a></li>
<li>The precedence of `|>` sits between the ternary operator and `||`. It is left-associative. <a href="https://github.com/tc39/proposal-pipeline-operator/issues/23">bug</a></li>
<li>All calls to `eval` are indirect eval.</li>
<li>The pipeline operator is eligible for proper tail calls, when appropriate.</li>
<li>The left argument to `|>` is evaluated before the right one.</li>
<li>If the right argument to `|>` has a receiver, it is used for the call, with rules similar to a method call. That is `x |> y.z` gets `y` as a receiver, just as if it were written `y.z(x)`.</li>
</ol>
</p>
</emu-intro>

<emu-clause id=sec-pipeline-syntax>
<h1>Syntax</h1>

<emu-grammar>
ConditionalExpression[In, Yield, Await] :
<del>LogicalORExpression[?In, ?Yield, ?Await]</del>
<del>LogicalORExpression[?In, ?Yield, ?Await] `?` AssignmentExpression[+In, ?Yield, ?Await] `:` AssignmentExpression[?In, ?Yield, ?Await]</del>
<ins>PipelineExpression[?In, ?Yield, ?Await]</ins>
<ins>PipelineExpression[?In, ?Yield, ?Await] `?` AssignmentExpression[+In, ?Yield, ?Await] `:` AssignmentExpression[?In, ?Yield, ?Await]</ins>

<ins>
PipelineExpression[In, Yield, Await] :
LogicalORExpression[?In, ?Yield, ?Await]
PipelineExpression[?In, ?Yield, ?Await] `|>` LogicalORExpression[?In, ?Yield, ?Await]
</ins>
</emu-grammar>
</emu-clause>

<emu-clause id=sec-pipeline-semantics>
<h1>Semantics</h1>
<emu-clause id=sec-pipeline-evaluation>
<h1>Runtime Semantics: Evaluation</h1>
<emu-grammar>PipelineExpression : PipelineExpression '|>` LogicalORExpression</emu-grammar>
<emu-alg>
1. Let _argRef_ be the result of evaluating |PipelineExpression|.
1. Let _arg_ be ? GetValue(_argRef_).
1. Let _funcRef_ be the result of evaluating |LogicalORExpression|.
1. Let _func_ be ? GetValue(_funcRef_).
1. If Type(_funcRef_) is Reference, then
1. If IsPropertyReference(_funcRef_) is *true*, then
1. Let _thisValue_ be GetThisValue(_funcRef_).
1. Else the base of _funcRef_ is an Environment Record,
1. Let _refEnv_ be GetBase(_funcRef_).
1. Let _thisValue_ be _refEnv_.WithBaseObject().
1. Else Type(_funcRef_) is not Reference,
1. Let _thisValue_ be *undefined*.
1. If Type(_func_) is not Object, throw a *TypeError* exception.
1. If IsCallable(_func_) is *false*, throw a *TypeError* exception.
1. Let _thisCall_ be this outer |PipelineExpression|.
1. Let _tailPosition_ be IsInTailPosition(_thisCall_).
1. If _tailPosition_ is *true*, perform PrepareForTailCall().
1. Let _result_ be Call(_func_, _thisValue_, &laquo; _arg_ &raquo;).
1. Assert: If _tailPosition_ is *true*, the above call will not return here, but instead evaluation will continue as if the following return has already occurred.
1. Assert: If _result_ is not an abrupt completion, then Type(_result_) is an ECMAScript language type.
1. Return _result_.
</emu-alg>
<emu-note>All calls to eval from a pipeline operator are indirect eval calls.</emu-note>
<emu-note type="editor">This definition is somewhat duplicated from the definition of evaluating CallExpression; when merging with the main specification, a refactoring will be done to de-duplicate it.</emu-note>
</emu-clause>
<emu-clause id=sec-pipeline-has-call-in-tail-position>
<h1>Static Semantics: HasCallInTailPosition</h1>
<emu-grammar>PipelineExpression : PipelineExpression '|>` LogicalORExpression</emu-grammar>
<emu-alg>
1. If this outer |PipelineExpression| is _call_, return *true*.
1. Return *false*.
</emu-alg>
</emu-clause>
</emu-clause>