Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(353)

Unified Diff: docs/language/dartLangSpec.tex

Issue 2399343002: Change how the language specification describes control flow. (Closed)
Patch Set: Update version number Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: docs/language/dartLangSpec.tex
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index dad91137eb3ac8e0a713928ec68c68c62828d2e8..54b5b3c8698889bbc2877937490fcb0cafa96d86 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -9,7 +9,7 @@
\newcommand{\code}[1]{{\sf #1}}
\title{Dart Programming Language Specification \\
{4th edition draft}\\
-{\large Version 1.14}}
+{\large Version 1.15.0}}
% For information about Location Markers (and in particular the
% commands \LMHash and \LMLabel), see the long comment at the
@@ -139,6 +139,10 @@ The specifications of operators often involve statements such as $x$ $op$ $y$ is
When the specification refers to the order given in the program, it means the order of the program source code text, scanning left-to-right and top-to-bottom.
\LMHash{}
+When the specification refers to a {\em fresh variable}, it means a variable with a name that doesn't occur anywhere in the current program.
+When the specification introduces a fresh variable bound to a value, the fresh variable is implicitly bound in a surrounding scope.
+
+\LMHash{}
References to otherwise unspecified names of program entities (such as classes or functions) are interpreted as the names of members of the Dart core library.
\commentary{
@@ -164,7 +168,7 @@ Type tests also examine the types in a program explicitly. Nevertheless, in most
}
\LMHash{}
-In checked mode, assignments are dynamically checked, and certain violations of the type system raise exceptions at run time.
+In checked mode, assignments are dynamically checked, and certain violations of the type system throw exceptions at run time.
\commentary{
The coexistence between optional typing and reification is based on the following:
@@ -325,12 +329,11 @@ a program that interfaces between the engine and the surrounding computing envir
{\em Dynamic type errors} are type errors reported in checked mode.
\LMHash{}
-{\em Run-time errors} are exceptions raised during execution. Whenever we say that an exception $ex$ is {\em raised} or {\em thrown}, we mean that a throw expression (\ref{throw}) of the form: \code{\THROW{} $ex$;} was implicitly evaluated or that a rethrow statement (\ref{rethrow}) of the form \code{\RETHROW} was executed. When we say that {\em a} $C$ {\em is thrown}, where $C$ is a class, we mean that an instance of class $C$ is thrown. When we say that a stream raises an exception, we mean that an exception occurred while computing the value(s) of the stream.
+{\em Run-time errors} are exceptions thrown during execution. Whenever we say that an exception $ex$ is {\em thrown}, it acts like an expression had {\em thrown} (\ref{completion}) with $ex$ as exception object and with a stack trace corresponding to the current system state. When we say that {\em a} $C$ {\em is thrown}, where $C$ is a class, we mean that an instance of class $C$ is thrown.
\LMHash{}
If an uncaught exception is thrown by a running isolate $A$, $A$ is immediately suspended.
-
\section{Variables}
\LMLabel{variables}
@@ -815,7 +818,7 @@ Examples of external functions might be foreign functions (defined in C, or Java
}
\LMHash{}
-An external function is connected to its body by an implementation specific mechanism. Attempting to invoke an external function that has not been connected to its body will raise a \code{NoSuchMethodError} or some subclass thereof.
+An external function is connected to its body by an implementation specific mechanism. Attempting to invoke an external function that has not been connected to its body will throw a \code{NoSuchMethodError} or some subclass thereof.
\LMHash{}
The actual syntax is given in sections \ref{classes} and \ref{librariesAndScripts} below.
@@ -1212,7 +1215,8 @@ An instance getter for it can always be defined manually if desired.
\LMLabel{constructors}
\LMHash{}
-A {\em constructor} is a special function that is used in instance creation expressions (\ref{instanceCreation}) to produce objects. Constructors may be generative (\ref{generativeConstructors}) or they may be factories (\ref{factories}).
+A {\em constructor} is a special function that is used in instance creation expressions (\ref{instanceCreation}) to obtain objects, typically by creating or initializing them.
+Constructors may be generative (\ref{generativeConstructors}) or they may be factories (\ref{factories}).
\LMHash{}
A {\em constructor name} always begins with the name of its immediately enclosing class, and may optionally be followed by a dot and an identifier $id$. It is a compile-time error if $id$ is the name of a member declared in the immediately enclosing class. It is a compile-time error if the name of a constructor is not a constructor name.
@@ -1229,7 +1233,7 @@ Iff no constructor is specified for a class $C$, it implicitly has a default con
\LMLabel{generativeConstructors}
\LMHash{}
-A {\em generative constructor} consists of a constructor name, a constructor parameter list, and either a redirect clause or an initializer list and an optional body.
+A {\em generative constructor} consists of a constructor name, a constructor parameter list, and either a redirect clause or an initializer list and an optional body.
\begin{grammar}
{\bf constructorSignature:}
@@ -1255,7 +1259,7 @@ The type of the constructor is defined in terms of its formal parameters, includ
}
\LMHash{}
-Initializing formals are executed during the execution of generative constructors detailed below. Executing an initializing formal \code{\THIS{}.id} causes the field \code{id} of the immediately surrounding class to be assigned the value of the corresponding actual parameter, unless $id$ is a final variable that has already been initialized, in which case a runtime error occurs.
+Initializing formals are executed during the execution of generative constructors detailed below. Executing an initializing formal \code{\THIS{}.$id$} causes the field $id$ of the immediately surrounding class to be assigned the value of the corresponding actual parameter, unless $id$ is a final variable that has already been initialized, in which case a runtime error occurs.
\commentary{
@@ -1301,9 +1305,6 @@ A generative constructor may be {\em redirecting}, in which case its only action
.
\end{grammar}
-% Need to specify exactly how executing a redirecting constructor works
-
-
%\Q{We now have generative constructors with no bodies as well.}
\paragraph{Initializer Lists}
@@ -1312,7 +1313,7 @@ A generative constructor may be {\em redirecting}, in which case its only action
\LMHash{}
An initializer list begins with a colon, and consists of a comma-separated list of individual {\em initializers}. There are two kinds of initializers.
\begin{itemize}
-\item A {\em superinitializer} identifies a {\em superconstructor} - that is, a specific constructor of the superclass. Execution of the superinitializer causes the initializer list of the superconstructor to be executed.
+\item A {\em superinitializer} identifies a {\em superconstructor} - that is, a specific constructor of the superclass. Execution of the superinitializer causes the initializer list of the superconstructor to be executed.
\item An {\em instance variable initializer} assigns a value to an individual instance variable.
\end{itemize}
@@ -1341,7 +1342,7 @@ Let $k$ be a generative constructor. Then $k$ may include at most one superini
Each final instance variable $f$ declared in the immediately enclosing class must have an initializer in $k$'s initializer list unless it has already been initialized by one of the following means:
\begin{itemize}
\item Initialization at the declaration of $f$.
- \item Initialization by means of an initializing formal of $k$.
+ \item Initialization by means of an initializing formal of $k$.
\end{itemize}
or a static warning occurs. It is a compile-time error if $k$'s initializer list contains an initializer for a variable that is not an instance variable declared in the immediately surrounding class.
@@ -1351,12 +1352,14 @@ or a static warning occurs. It is a compile-time error if $k$'s initializer list
}
\LMHash{}
- It is a compile-time error if a generative constructor of class \code{Object} includes a superinitializer.
+It is a compile-time error if a generative constructor of class \code{Object} includes a superinitializer.
\LMHash{}
-Execution of a generative constructor $k$ is always done with respect to a set of bindings for its formal parameters and with \THIS{} bound to a fresh instance $i$ and the type parameters of the immediately enclosing class bound to a set of actual type arguments $V_1, \ldots , V_m$.
+Execution of a generative constructor $k$ of type $T$ to initialize a fresh instance $i$
+is always done with respect to a set of bindings for its formal parameters
+and the type parameters of the immediately enclosing class bound to a set of actual type arguments of $T$, $V_1, \ldots , V_m$.
-\commentary{These bindings are usually determined by the instance creation expression that invoked the constructor (directly or indirectly). However, they may also be determined by a reflective call,.
+\commentary{These bindings are usually determined by the instance creation expression that invoked the constructor (directly or indirectly). However, they may also be determined by a reflective call.
}
\LMHash{}
@@ -1364,36 +1367,63 @@ If $k$ is redirecting then its redirect clause has the form
\THIS{}$.g(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$
-where $g$ identifies another generative constructor of the immediately surrounding class. Then execution of $k$ proceeds by evaluating the argument list $(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$, and then executing $g$ with respect to the bindings resulting from the evaluation of $(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$ and with \THIS{} bound to $i$ and the type parameters of the immediately enclosing class bound to $V_1, \ldots , V_m$.
+where $g$ identifies another generative constructor of the immediately surrounding class. Then execution of $k$ to initialize $i$ proceeds by evaluating the argument list $(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$, and then executing $g$ to initialize $i$ with respect to the bindings resulting from the evaluation of $(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$ and with \THIS{} bound to $i$ and the type parameters of the immediately enclosing class bound to $V_1, \ldots , V_m$.
\LMHash{}
Otherwise, execution proceeds as follows:
\LMHash{}
-%First, a fresh instance (\ref{generativeConstructors}) $i$ of the immediately enclosing class is allocated. Next, the instance variable declarations of the immediately enclosing class are visited in the order they appear in the program text. For each such declaration $d$, if $d$ has the form \code{$finalConstVarOrType$ $v$ = $e$; } then the instance variable $v$ of $i$ is bound to the value of $e$ (which is necessarily a compile-time constant).
-%Next, a
+The instance variable declarations of the immediately enclosing class are visited in the order they appear in the program text.
+For each such declaration $d$, if $d$ has the form \code{$finalConstVarOrType$ $v$ = $e$; }
+then $e$ is evaluated to an object $o$
+and the instance variable $v$ of $i$ is bound to $o$.
+
+\LMHash{}
Any initializing formals declared in $k$'s parameter list are executed in the order they appear in the program text.
% In fact, this order is unobservable; this could be done any time prior to running the body, since
% these only effect \THIS{}.
-Then, $k$'s initializers are executed in the order they appear in the program.
+Then, the initializers of $k$'s initializer list are executed to initialize $i$
+in the order they appear in the program.
+
+\rationale {We could observe the order by side effecting external routines called. So we need to specify the order.}
+
+\LMHash{}
+Then if any instance variable of $i$ declared by the immediately enclosing class
+is not yet bound to a value,
+it is a dynamic error if such a variable is a \FINAL{} variable,
+otherwise all such variables are initialized with the \NULL{} value.
+
+\LMHash{}
+Then, unless the enclosing class is \code{Object}, the explicitly specified or
+implicitly added superinitializer (\ref{initializerLists}) is executed to
+further initialize $i$.
-\rationale {We could observe the order by side effecting external routines called. So we need to specify the order.}
+\commentary{
+The super constructor call can be written anywhere
+in the initializer list of $k$,
+but the actual call always happens after all initializers have been processed.
+It is not equivalent to moving the super call to the end of the initializer list
+because the argument expressions may have visible side effects
+which must happen in the order the expressions occur in the program text.
+}
\LMHash{}
-After all the initializers have completed, the body of $k$ is executed in a scope where \THIS{} is bound to $i$. Execution of the body begins with execution of the body of the superconstructor with \THIS{} bound to $i$, the type parameters of the immediately enclosing class bound to a set of actual type arguments $V_1, \ldots , V_m$ and the formal parameters bindings determined by the argument list of the superinitializer of $k$.
+After the superinitializer has completed, the body of $k$ is executed in a scope where \THIS{} is bound to $i$.
\rationale{
-This process ensures that no uninitialized final field is ever seen by code. Note that \THIS{} is not in scope on the right hand side of an initializer (see \ref{this}) so no instance method can execute during initialization: an instance method cannot be directly invoked, nor can \THIS{} be passed into any other code being invoked in the initializer.
+This process ensures that no uninitialized final field is ever seen by code. Note that \THIS{} is not in scope on the right hand side of an initializer (see \ref{this}) so no instance method can execute during initialization: an instance method cannot be directly invoked, nor can \THIS{} be passed into any other code being invoked in the initializer.
}
\LMHash{}
-Execution of an initializer of the form \code{\THIS{}.$v$ = $e$} proceeds as follows:
+During the execution of a generative constructor to initialize an instance $i$,
+execution of an initializer of the form \code{\THIS{}.$v$ = $e$}
+proceeds as follows:
\LMHash{}
-First, the expression $e$ is evaluated to an object $o$. Then, the instance variable $v$ of the object denoted by \THIS{} is bound to $o$, unless $v$ is a final variable that has already been initialized, in which case a runtime error occurs. In checked mode, it is a dynamic type error if $o$ is not \NULL{} and the interface of the class of $o$ is not a subtype of the actual type of the field $v$.
+First, the expression $e$ is evaluated to an object $o$. Then, the instance variable $v$ of $i$ is bound to $o$, unless $v$ is a final variable that has already been initialized, in which case a runtime error occurs. In checked mode, it is a dynamic type error if $o$ is not \NULL{} and the interface of the class of $o$ is not a subtype of the actual type of the field $v$.
\LMHash{}
-An initializer of the form \code{$v$ = $e$} is equivalent to an initializer of the form \code{\THIS{}.$v$ = $e$}.
+An initializer of the form \code{$v$ = $e$} is equivalent to an initializer of the form \code{\THIS{}.$v$ = $e$}.
\LMHash{}
Execution of a superinitializer of the form
@@ -1408,10 +1438,17 @@ proceeds as follows:
First, the argument list $(a_1, \ldots, a_n, x_{n+1}: a_{n+1}, \ldots, x_{n+k}: a_{n+k})$ is evaluated.
\LMHash{}
-Let $C$ be the class in which the superinitializer appears and let $S$ be the superclass of $C$. If $S$ is generic (\ref{generics}), let $U_1, , \ldots, U_m$ be the actual type arguments passed to $S$ in the superclass clause of $C$.
+Then, after the remainder of the initializer list of $k$ has been executed,
+the superconstructor is executed as follows:
+
+\LMHash{}
+Let $C$ be the class in which the superinitializer appears and let $S$ be the superclass of $C$. If $S$ is generic (\ref{generics}), let $U_1, \ldots, U_m$ be the actual type arguments passed to $S$ in the superclass clause of $C$.
\LMHash{}
-Then, the initializer list of the constructor $S$ (respectively $S.id$) is executed with respect to the bindings that resulted from the evaluation of the argument list, with \THIS{} bound to the current binding of \THIS{}, and the type parameters (if any) of class $S$ bound to the current bindings of $U_1, , \ldots, U_m$.
+The generative constructor $S$ (respectively $S.id$) of $S$ is executed
+to initialize $i$ with respect to the bindings that resulted from the evaluation of
+$(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$,
+and the type parameters (if any) of class $S$ bound to $U_1, \ldots, U_m$.
\LMHash{}
It is a compile-time error if class $S$ does not declare a generative constructor named $S$ (respectively $S.id$).
@@ -1444,7 +1481,6 @@ In checked mode, it is a dynamic type error if a factory returns a non-null obje
\rationale{Factories address classic weaknesses associated with constructors in other languages.
Factories can produce instances that are not freshly allocated: they can come from a cache. Likewise, factories can return instances of different classes.
-
}
\paragraph{Redirecting Factory Constructors}
@@ -2352,8 +2388,20 @@ The constant expression given in an annotation is type checked and evaluated in
\LMLabel{expressions}
\LMHash{}
-An {\em expression} is a fragment of Dart code that can be evaluated at run time to yield a {\em value}, which is always an object. Every expression has an associated static type (\ref{staticTypes}). Every value has an associated dynamic type (\ref{dynamicTypeSystem}).
+\label{evaluation}
+An {\em expression} is a fragment of Dart code that can be evaluated at run time.
+Evaluating an expression either {\em produces a value} (an object),
+or it {\em throws} an exception object and an associated stack trace.
+In the former case, we also say that the expression {\em evaluates to a value}.
+\LMHash{}
+Every expression has an associated static type (\ref{staticTypes}).
+Every value has an associated dynamic type (\ref{dynamicTypeSystem}).
+
+\LMHash{}
+If evaluation of one expression, $e$, is defined in terms of evaluation of another expression, typically a subexpression of $e$,
+and the evaluation of the other expression throws an exception and a stack trace,
+the evaluation of $e$ stops at that point and throws the same exception object and stack trace.
\begin{grammar}
@@ -2472,13 +2520,13 @@ A constant expression is one of the following:
% designed so constants do not depend on check diode being on or not.
\LMHash{}
-It is a compile-time error if an expression is required to be a constant expression but its evaluation would raise an exception.
+It is a compile-time error if an expression is required to be a constant expression but its evaluation would throw an exception.
% so, checked mode? analyzers? editor/development compilers?
\commentary{
Note that there is no requirement that every constant expression evaluate correctly. Only when a constant expression is required (e.g., to initialize a constant variable, or as a default value of a formal parameter, or as metadata) do we insist that a constant expression actually be evaluated successfully at compile time.
-The above is not dependent on program control-flow. The mere presence of a required compile time constant whose evaluation would fail within a program is an error. This also holds recursively: since compound constants are composed out of constants, if any subpart of a constant would raise an exception when evaluated, that is an error.
+The above is not dependent on program control-flow. The mere presence of a required compile time constant whose evaluation would fail within a program is an error. This also holds recursively: since compound constants are composed out of constants, if any subpart of a constant would throw an exception when evaluated, that is an error.
On the other hand, since implementations are free to compile code late, some compile-time errors may manifest quite late.
}
@@ -2555,7 +2603,7 @@ As an example, consider:
\LMLabel{null}
\LMHash{}
-The reserved word \NULL{} denotes the {\em null object}.
+The reserved word \NULL{} evaluates to the {\em null object}.
%\Q{Any methods, such as \code{isNull}?}
\begin{grammar}
@@ -2565,8 +2613,8 @@ The reserved word \NULL{} denotes the {\em null object}.
\end{grammar}
\LMHash{}
-The null object is the sole instance of the built-in class \code{Null}. Attempting to instantiate \code{Null} causes a run-time error. It is a compile-time error for a class to attempt to extend, mix in or implement \code{Null}.
-Invoking a method on \NULL{} yields a \code{NoSuchMethodError} unless the method is explicitly implemented by class \code{Null}.
+The null object is the sole instance of the built-in class \code{Null}. Attempting to instantiate \code{Null} causes a run-time error. It is a compile-time error for a class to extend, mix in or implement \code{Null}.
+The \code{Null} class declares no methods except those also declared by \code{Object}.
\LMHash{}
The static type of \NULL{} is $\bot$.
@@ -2605,7 +2653,17 @@ A {\em numeric literal} is either a decimal or hexadecimal integer of arbitrary
\end{grammar}
\LMHash{}
-If a numeric literal begins with the prefix `0x' or `0X', it denotes the hexadecimal integer represented by the part of the literal following `0x' (respectively `0X'). Otherwise, if the numeric literal contains only decimal digits, it denotes a decimal integer. Otherwise, the numeric literal contains either a decimal point or an exponent part and it denotes a 64 bit double precision floating point number as specified by the IEEE 754 standard.
+If a numeric literal begins with the prefix `0x' or `0X',
+it denotes the integer represented by the hexadecimal numeral
+following `0x' (respectively `0X').
+Otherwise, if the numeric literal contains only decimal digits,
+it denotes an integer represented as a decimal numeral.
+In either case the literal evaluates to an instance of the class \code{int}
+with the integer value represented by that numeral.
+Otherwise, the numeric literal contains either a decimal point or an exponent part
+and it evaluates to a an instance of the `double` class
+representing a 64 bit double precision floating point number
+as specified by the IEEE 754 standard.
\LMHash{}
In principle, the range of integers supported by a Dart implementations is unlimited. In practice, it is limited by available memory. Implementations may also be limited by other considerations.
@@ -2615,20 +2673,23 @@ For example, implementations may choose to limit the range to facilitate efficie
}
\LMHash{}
-It is a compile-time error for a class to attempt to extend, mix in or implement \code{int}. It is a compile-time error for a class to attempt to extend, mix in or implement \code{double}. It is a compile-time error for any type other than the types \code{int} and \code{double} to attempt to extend, mix in or implement \code{num}.
+It is a compile-time error for a class to extend, mix in or implement \code{int}.
+It is a compile-time error for a class to extend, mix in or implement \code{double}.
+It is a compile-time error for any class other than \code{int} and \code{double} to extend, mix in or implement \code{num}.
\LMHash{}
-An {\em integer literal} is either a hexadecimal integer literal or a decimal integer literal. Invoking the getter \code{runtimeType} on an integer literal returns the \code{Type} object that is the value of the expression \code{int}. The static type of an integer literal is \code{int}.
+An {\em integer literal} is either a hexadecimal integer literal or a decimal integer literal.
+The static type of an integer literal is \code{int}.
\LMHash{}
-A {\em literal double} is a numeric literal that is not an integer literal. Invoking the getter \code{runtimeType} on a literal double returns the \code{Type} object that is the value of the expression \code{double}.
-The static type of a literal double is \code{double}.
+A {\em literal double} is a numeric literal that is not an integer literal. The static type of a literal double is \code{double}.
\subsection{Booleans}
\LMLabel{booleans}
\LMHash{}
-The reserved words \TRUE{} and \FALSE{} denote objects that represent the boolean values true and false respectively. They are the {\em boolean literals}.
+The reserved words \TRUE{} and \FALSE{} evaluate to objects {\em true} and {\em false} that represent the boolean values true and false respectively.
+They are the {\em boolean literals}.
\begin{grammar}
{\bf booleanLiteral:}\TRUE{};
@@ -2637,14 +2698,12 @@ The reserved words \TRUE{} and \FALSE{} denote objects that represent the boolea
\end{grammar}
\LMHash{}
-Both \TRUE{} and \FALSE{} implement the built-in class \code{bool}. It is a compile-time error for a class to attempt to extend, mix in or implement\code{ bool}.
-
-\commentary{
-It follows that the two boolean literals are the only two instances of \code{bool}.
-}
+Both {\em true} and {\em false} are instances of the built-in class \code{bool},
+and there are no other objects that implement \code{bool}.
+It is a compile-time error for a class to extend, mix in or implement \code{bool}.
\LMHash{}
-Invoking the getter \code{runtimeType} on a boolean literal returns the \code{Type} object that is the value of the expression \code{bool}. The static type of a boolean literal is \code{bool}.
+Invoking the getter \code{runtimeType} on a boolean value returns the \code{Type} object that is the value of the expression \code{bool}. The static type of a boolean literal is \code{bool}.
\subsubsection{Boolean Conversion}
\LMLabel{booleanConversion}
@@ -2845,7 +2904,9 @@ It is a compile-time error if a non-raw string literal contains a character sequ
\end{grammar}
\LMHash{}
-All string literals implement the built-in class \code{String}. It is a compile-time error for a class to attempt to extend, mix in or implement \code{String}. Invoking the getter \code{runtimeType} on a string literal returns the \code{Type} object that is the value of the expression \code{String}. The static type of a string literal is \code{String}.
+All string literals evaluate to instances of the built-in class \code{String}.
+It is a compile-time error for a class to extend, mix in or implement \code{String}.
+The static type of a string literal is \code{String}.
\subsubsection{String Interpolation}
\LMLabel{stringInterpolation}
@@ -2870,7 +2931,16 @@ An unescaped \$ character in a string signifies the beginning of an interpolated
\end{itemize}
\LMHash{}
-The form \code{\$id} is equivalent to the form \code{\$\{id\}}. An interpolated string \code{`$s_1$\$\{$e$\}$s_2$'} is equivalent to the concatenation of the strings \code{`$s_1$'}, \code{$e$.toString()} and \code{$`s_2$'}. Likewise an interpolated string \code{``$s_1$\$\{e\}$s_2$''} is equivalent to the concatenation of the strings \code{``$s_1$''}, \code{$e$.toString()} and \code{``$s_2$''}.
+The form \code{\$id} is equivalent to the form \code{\$\{id\}}.
+An interpolated string, $s$, with content `\code{$s_0$\$\{$e_1$\}$s_1\ldots{}s_{n-1}\$\{e_n\}s_{n}$}' (where any of $s_0 \ldots{} s_n$ can be empty)
+is evaluated by evaluating each expression $e_i$ ($1 \le i \le n$) in to a string $r_i$ in the order they occur in the source text, as follows:
+\begin{itemize}
+\item{} Evaluate $e_i$ to an object $o_i$.
+\item{} Invoke the \code{toString} method on $o_i$ with no arguments, and let
+ $r_i$ be the returned value.
+\item{} If $r_i$ is not an instance of the built-in type \code{String}, throw an \code{Error}.
+\end{itemize}
+Finally, the result of the evaluation of $s$ is the concatenation of the strings $s_0$, $r_1$, \ldots{}, $r_n$, and $s_n$.
\subsection{Symbols}
\LMLabel{symbols}
@@ -2934,8 +3004,8 @@ Let $list_1 =$ \CONST{} $<V>[e_{11} \ldots e_{1n}]$ and $list_2 =$ \CONST{} $<U
A run-time list literal $<E>[e_1 \ldots e_n]$ is evaluated as follows:
\begin{itemize}
\item
-First, the expressions $e_1 \ldots e_n$ are evaluated in order they appear in the program, yielding objects $o_1 \ldots o_n$.
-\item A fresh instance (\ref{generativeConstructors}) $a$, of size $n$, whose class implements the built-in class $List<E>$ is allocated.
+First, the expressions $e_1 \ldots e_n$ are evaluated in order they appear in the program, producing objects $o_1 \ldots o_n$.
+\item A fresh instance (\ref{generativeConstructors}) $a$, of size $n$, whose class implements the built-in class $List<E>$ is allocated.
\item
The operator \code{[]=} is invoked on $a$ with first argument $i$ and second argument
%The $i$th element of $a$ is set to
@@ -3010,12 +3080,13 @@ Let $map_1 =$ \CONST{}$ <K, V>\{k_{11}:e_{11} \ldots k_{1n} :e_{1n}\}$ and $map
A runtime map literal $<K, V>\{k_1:e_1\ldots k_n :e_n\}$ is evaluated as follows:
\begin{itemize}
\item
-First, the expression $k_i$ is evaluated yielding object $u_i$, the $e_i$ is vaulted yielding object $o_i$, for $i \in 1..n$ in left to right order, yielding objects $u_1, o_1\ldots u_n, o_n$.
-\item A fresh instance (\ref{generativeConstructors}) $m$ whose class implements the built-in class
-
- $Map<K, V>$ is allocated.
+For each $i \in 1..n$ in numeric order,
+first the expression $k_i$ is evaluated producing object $u_i$,
+and then $e_i$ is evaluated producing object $o_i$.
+This produces all the objects $u_1, o_1\ldots u_n, o_n$.
+\item A fresh instance (\ref{generativeConstructors}) $m$ whose class implements the built-in class $Map<K, V>$ is allocated.
\item
-The operator \code{[]=} is invoked on $m$ with first argument $u_i$ and second argument $o_i, i \in 1.. n$.
+The operator \code{[]=} is invoked on $m$ with first argument $u_i$ and second argument $o_i$ for each $i \in 1.. n$.
\item
The result of the evaluation is $m$.
\end{itemize}
@@ -3045,7 +3116,7 @@ The static type of a map literal of the form \CONST{}$ <K, V>\{k_1:e_1\ldots k_
\LMLabel{throw}
\LMHash{}
-The {\em throw expression} is used to raise an exception.
+The {\em throw expression} is used to throw an exception.
\begin{grammar}
{\bf throwExpression:}
@@ -3059,45 +3130,32 @@ The {\em throw expression} is used to raise an exception.
\end{grammar}
\LMHash{}
- The {\em current exception} is the last exception raised and not subsequently caught at a given moment during runtime.
+Evaluation of a throw expression of the form \code{\THROW{} $e$;} proceeds as follows:
\LMHash{}
- Evaluation of a throw expression of the form \code{\THROW{} $e$;} proceeds as follows:
-
-\LMHash{}
-The expression $e$ is evaluated yielding a value $v$.
+The expression $e$ is evaluated to a value $v$ (\ref{evaluation}).
\commentary{
-There is no requirement that the expression $e$ evaluate to a special kind of exception or error object.
-}
-
-\LMHash{}
-If $e$ evaluates to \NULL{} (\ref{null}), then a \code{NullThrownError} is thrown. Otherwise the current exception is set to $v$ and the current return value (\ref{return}) becomes undefined.
-
-\rationale{The current exception and the current return value must never be simultaneously defined, as they represent mutually exclusive options for exiting the current function.
+There is no requirement that the expression $e$ evaluate to any special kind of object.
}
\LMHash{}
-Let $f$ be the immediately enclosing function.
+If $v$ is the null value (\ref{null}), then a \code{NullThrownError} is thrown.
+Otherwise let $t$ be a stack trace corresponding to the current execution state,
+and the \THROW{} statement throws with $v$ as exception object
+and $t$ as stack trace (\ref{evaluation}).
\LMHash{}
-If $f$ is synchronous (\ref{functions}), control is transferred to the nearest dynamically enclosing exception handler.
+If $v$ is an instance of class \code{Error} or a subclass thereof,
+and it is the first time that \code{Error} object is thrown,
+the stack trace $t$ is stored on $v$ so that it will be returned
+by the $v$'s \code{stackTrace} getter
\commentary{
-If $f$ is marked \SYNC* then a dynamically enclosing exception handler encloses the call to \code{moveNext()} that initiated the evaluation of the throw expression.
+If the same \code{Error} object is thrown more than once, its \code{stackTrace} getter will return the stack trace from the {\em first} time it was thrown.
}
\LMHash{}
-If $f$ is asynchronous then if there is a dynamically enclosing exception handler $h$ (\ref{try}) introduced by the current activation, control is transferred to $h$, otherwise $f$ terminates.
-
-\rationale{
-The rules for where a thrown exception will be handled must necessarily differ between the synchronous and asynchronous cases. Asynchronous functions cannot transfer control to an exception handler defined outside themselves. Asynchronous generators post exceptions to their stream. Other asynchronous functions report exceptions via their future.
-}
-
-\LMHash{}
-If the object being thrown is an instance of class \code{Error} or a subclass thereof, its \code{stackTrace} getter will return the stack trace current at the point where the object was first thrown.
-
-\LMHash{}
The static type of a throw expression is $\bot$.
@@ -3359,22 +3417,21 @@ Then, if $q$ is a non-factory constructor of an abstract class then an \code{Abs
\LMHash{}
If $T$ is malformed or if $T$ is a type variable a dynamic error occurs. In checked mode, if $T$ or any of its superclasses is malbounded a dynamic error occurs.
- Otherwise, if $q$ is not defined or not accessible, a \code{NoSuchMethodError} is thrown. If $q$ has less than $n$ positional parameters or more than $n$ required parameters, or if $q$ lacks any of the keyword parameters $\{ x_{n+1}, \ldots, x_{n+k}\}$ a \code{NoSuchMethodError} is thrown.
+Otherwise, if $q$ is not defined or not accessible, a \code{NoSuchMethodError} is thrown. If $q$ has fewer than $n$ positional parameters or more than $n$ required parameters, or if $q$ lacks any of the keyword parameters $\{ x_{n+1}, \ldots, x_{n+k}\}$ a \code{NoSuchMethodError} is thrown.
\LMHash{}
Otherwise, if $q$ is a generative constructor (\ref{generativeConstructors}), then:
-\commentary{Note that it this point we are assured that the number of actual type arguments match the number of formal type parameters.}
+\commentary{Note that at this point we are assured that the number of actual type arguments match the number of formal type parameters.}
\LMHash{}
-A fresh instance (\ref{generativeConstructors}), $i$, of class $R$ is allocated. For each instance variable $f$ of $i$, if the variable declaration of $f$ has an initializer expression $e_f$, then $e_f$ is evaluated, with the type parameters (if any) of $R$ bound to the actual type arguments $V_1, \ldots, V_l$, to an object $o_f$ and $f$ is bound to $o_f$. Otherwise $f$ is bound to \NULL{}.
+A fresh instance (\ref{generativeConstructors}), $i$, of class $R$ is allocated.
+Then $q$ is executed to initialize $i$ with respect to the bindings that resulted from the evaluation of the argument list, and, if $R$ is a generic class, with its type parameters bound to $V_1 \ldots V_m$.
-\commentary{
-Observe that \THIS{} is not in scope in $e_f$. Hence, the initialization cannot depend on other properties of the object being instantiated.
-}
-
-\LMHash{}
-Next, $q$ is executed with \THIS{} bound to $i$, the type parameters (if any) of $R$ bound to the actual type arguments $V_1, \ldots, V_l$ and the formal parameter bindings that resulted from the evaluation of the argument list. The result of the evaluation of $e$ is $i$.
+If execution of $q$ completes normally (\ref{completion}), $e$ evaluates to $i$.
+Otherwise execution of $q$ throws an exception object $x$ and stack trace $t$,
+and then evaluation of $e$ also throws exception object $x$ and stack trace $t$
+(\ref{evaluation}).
\LMHash{}
Otherwise, $q$ is a factory constructor (\ref{factories}). Then:
@@ -3382,11 +3439,18 @@ Otherwise, $q$ is a factory constructor (\ref{factories}). Then:
\LMHash{}
If $q$ is a redirecting factory constructor of the form $T(p_1, \ldots, p_{n+k}) = c;$ or of the form $T.id(p_1, \ldots, p_{n+k}) = c;$ then the result of the evaluation of $e$ is equivalent to evaluating the expression
-$[V_1, \ldots, V_m/T_1, \ldots, T_m]($\code{\NEW{} $c(a_1, \ldots, a_n, x_{n+1}: a_{n+1}, \ldots, x_{n+k}: a_{n+k}))$}. If evaluation of $q$ causes $q$ to be re-evaluated cyclically, a runtime error occurs.
+$[V_1, \ldots, V_m/T_1, \ldots, T_m]($\code{\NEW{} $c(a_1, \ldots, a_n, x_{n+1}: a_{n+1}, \ldots, x_{n+k}: a_{n+k}))$}. If evaluation of $q$ causes $q$ to be re-evaluated cyclically, with only factory constructor redirections in-between, a runtime error occurs.
+% Used to not have the "in-between" clause, which would disallow a factory constructor redirecting to another constructor which conditionally calls the original factory constructor again with different arguments.
\LMHash{}
-Otherwise, the body of $q$ is executed with respect to the bindings that resulted from the evaluation of the argument list and the type parameters (if any) of $q$ bound to the actual type arguments $V_1, \ldots, V_l$ resulting in an object $i$. The result of the evaluation of $e$ is $i$.
+Otherwise, the body of $q$ is executed with respect to the bindings that resulted from the evaluation of the argument list, and with the type parameters (if any) of $q$ bound to the actual type arguments $V_1, \ldots, V_l$.
+If this execution returns a value (\ref{completion}),
+then $e$ evaluates to the returned value.
+Otherwise, if the execution completes normally or returns with no value,
+then $e$ evaluates to \NULL.
+Otherwise the execution throws an exception $x$ and stack trace $t$,
+and then evaluation of $e$ also throws $x$ and $t$ (\ref{evaluation}).
\LMHash{}
It is a static warning if $q$ is a constructor of an abstract class and $q$ is not a factory constructor.
@@ -3550,37 +3614,21 @@ As discussed in section \ref{errorsAndWarnings}, the handling of a suspended iso
Function invocation occurs in the following cases: when a function expression (\ref{functionExpressions}) is invoked (\ref{functionExpressionInvocation}), when a method (\ref{methodInvocation}), getter (\ref{topLevelGetterInvocation}, \ref{propertyExtraction}) or setter (\ref{assignment}) is invoked or when a constructor is invoked (either via instance creation (\ref{instanceCreation}), constructor redirection (\ref{redirectingConstructors}) or super initialization). The various kinds of function invocation differ as to how the function to be invoked, $f$, is determined, as well as whether \THIS{} (\ref{this}) is bound. Once $f$ has been determined, the formal parameters of $f$ are bound to corresponding actual arguments. When the body of $f$ is executed it will be executed with the aforementioned bindings.
\LMHash{}
-If $f$ is marked \ASYNC{} (\ref{functions}), then a fresh instance (\ref{generativeConstructors}) $o$ implementing the built-in class \code{Future} is associated with the invocation and immediately returned to the caller. The body of $f$ is scheduled for execution at some future time. The future $o$ will complete when $f$ terminates. The value used to complete $o$ is the current return value (\ref{return}), if it is defined, and the current exception (\ref{throw}) otherwise.
-
-\LMHash{}
-If $f$ is marked \ASYNC* (\ref{functions}), then a fresh instance $s$ implementing the built-in class \code{Stream} is associated with the invocation and immediately returned. When $s$ is listened to, execution of the body of $f$ will begin. When $f$ terminates:
-\begin{itemize}
-\item If the current return value is defined then, if $s$ has been canceled then its cancellation future is completed with \NULL{} (\ref{null}).
-\item If the current exception $x$ is defined:
- \begin{itemize}
- \item $x$ is added to $s$.
- \item If $s$ has been canceled then its cancellation future is completed with $x$ as an error.
- \end{itemize}
-\item $s$ is closed.
-\end{itemize}
-
-\rationale{
-When an asynchronous generator's stream has been canceled, cleanup will occur in the \FINALLY{} clauses (\ref{try}) inside the generator. We choose to direct any exceptions that occur at this time to the cancellation future rather than have them be lost.
-}
-
-\LMHash{}
-If $f$ is asynchronous then, when $f$ terminates, any open stream subscriptions associated with any asynchronous for loops (\ref{asynchronousFor-in}) or yield-each statements (\ref{yieldEach}) executing within $f$ are canceled, in the order of their nesting, innermost first.
+If $f$ is synchronous and is not a generator (\ref{functions}) then execution of the body of $f$ begins immediately.
+If the execution of the body of $f$ returns a value, $v$, (\ref{completion}), the invocation evaluates to $v$.
+If the execution completes normally or it returns without a value, the invocation evaluates to \NULL (\ref{null}).
+If the execution throws an exception object and stack trace, the invocation throws the same exception object and stack trace (\ref{evaluation}).
-\rationale{Such streams may be left open by for loops that were escaped when an exception was thrown within them for example.
+\commentary{
+A complete function body can never break or contine (\ref{completion})
+because a \BREAK{} or \CONTINUE{} statement must always occur inside the statement that is the target of the \BREAK{} or \CONTINUE{}.
+This means that a function body can only either complete normally, throw, or return. Completing normally or returning without a value is treated the same as returning \NULL, so the result of executing a function body can always be used as the result of evaluating an expression, either by evaluating to a value or by the evaluation throwing.
}
-%\LMHash{}
-%When a stream is canceled, the implementation must wait for the cancelation future returned by \cd{cancell()} to complete before proceeding.
\LMHash{}
If $f$ is marked \SYNC* (\ref{functions}), then a fresh instance $i$ implementing the built-in class \code{Iterable} is associated with the invocation and immediately returned.
-
\commentary{
A Dart implementation will need to provide a specific implementation of \code{Iterable} that will be returned by \SYNC* methods. A typical strategy would be to produce an instance of a subclass of class \code{IterableBase} defined in \code{dart:core}. The only method that needs to be added by the Dart implementation in that case is \code{iterator}.
}
@@ -3593,7 +3641,11 @@ The contract explicitly mentions a number of situations where certain iterables
}
\LMHash{}
-When iteration over the iterable is started, by getting an iterator $j$ from the iterable and calling \code{moveNext()}, execution of the body of $f$ will begin. When $f$ terminates, $j$ is positioned after its last element, so that its current value is \NULL{} and the current call to \code{moveNext()} on $j$ returns false, as will all further calls.
+When iteration over the iterable is started, by getting an iterator $j$ from the iterable and calling \code{moveNext()}, execution of the body of $f$ will begin. When execution of the body of $f$ completes (\ref{completion},
+\begin{itemize}
+\item If it returns without a value or it completes normally (\ref{completion}), $j$ is positioned after its last element, so that its current value is \code{null} and the current call to \code{moveNext()} on $j$ returns false, as must all further calls.
+\item If it throws an exception object $e$ and stack trace $t$ then the current value of $j$ is \NULL and the current call to \code{moveNext()} throws $e$ and $t$ as well. Further calls to \code{moveNext()} must return false.
+\end{itemize}
Each iterator starts a separate computation. If the \SYNC* function is impure, the sequence of values yielded by each iterator may differ.
@@ -3612,21 +3664,31 @@ Two executions of an iterator interact only via state outside the function.
}
% The alternative would be to cache the results of an iterator in the iterable, and check the cache at each \YIELD{}. This would have strange issues as well. The yielded value might differ from the expression in the yield. And it is a potential memory leak as the cache is kept alive by any iterator.
-
\LMHash{}
-If $f$ is synchronous and is not a generator (\ref{functions}) then execution of the body of $f$ begins immediately. When $f$ terminates the current return value is returned to the caller.
-
+If $f$ is marked \ASYNC{} (\ref{functions}), then a fresh instance (\ref{generativeConstructors}) $o$ implementing the built-in class \code{Future} is associated with the invocation and immediately returned to the caller. The body of $f$ is scheduled for execution at some future time. The future $o$ will be completed when execution of the body of $f$ completes (\ref{completion}). If execution of the body returns a value, $o$ is completed with that value, if it completes normally or returns without a value, $o$ is completed with the \NULL{} value, and if it throws an exception $e$ and stack trace $t$, $o$ is completed with the error $e$ and stack trace $t$.
\LMHash{}
-Execution of $f$ terminates when the first of the following occurs:
+If $f$ is marked \ASYNC* (\ref{functions}), then a fresh instance $s$ implementing the built-in class \code{Stream} is associated with the invocation and immediately returned. When $s$ is listened to, execution of the body of $f$ will begin.
+When execution of the body of $f$ completes:
\begin{itemize}
-\item An exception is thrown and not caught within the current function activation.
-\item A return statement (\ref{return}) immediately nested in the body of $f$ is executed and not intercepted in a \FINALLY{} (\ref{try}) clause.
-\item The last statement of the body completes execution.
+\item If it completes normally or returns with no value (\ref{completion}), then if $s$ has been canceled then its cancellation future is completed with \NULL{} (\ref{null}).
+\item If it throws an exception object $e$ and stack trace $t$:
+ \begin{itemize}
+ \item If $s$ has been canceled then its cancellation future is completed with error $e$ and stack trace $t$.
+ \item otherwise the error $e$ and stack trace $t$ are emitted by $s$.
+ \end{itemize}
+\item $s$ is closed.
\end{itemize}
+\commentary{
+The body of an asynchronous generator function cannot break, continue or return a value (\ref{completion}). The first two are only allowed in contexts that will handle the break or continue, and return statements with an expression are not allowed in generator functions.
+}
+\rationale{
+When an asynchronous generator's stream has been canceled, cleanup will occur in the \FINALLY{} clauses (\ref{try}) inside the generator. We choose to direct any exceptions that occur at this time to the cancellation future rather than have them be lost.
+}
-
+%\LMHash{}
+%When a stream is canceled, the implementation must wait for the cancelation future returned by \cd{cancell()} to complete before proceeding.
\subsubsection{ Actual Argument List Evaluation}
\LMLabel{actualArguments}
@@ -3661,7 +3723,7 @@ $(a_1, \ldots, a_m, q_1: a_{m+1}, \ldots, q_l: a_{m+l})$
proceeds as follows:
\LMHash{}
-The arguments $a_1, \ldots, a_{m+l}$ are evaluated in the order they appear in the program, yielding objects $o_1, \ldots, o_{m+l}$.
+The arguments $a_1, \ldots, a_{m+l}$ are evaluated in the order they appear in the program, producing objects $o_1, \ldots, o_{m+l}$.
\commentary{Simply stated, an argument list consisting of $m$ positional arguments and $l$ named arguments is evaluated from left to right.
}
@@ -3985,7 +4047,7 @@ $\SUPER{}.m(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$.
Evaluation of $i$ proceeds as follows:
\LMHash{}
-First, the argument list $(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$ is evaluated yielding actual argument objects $o_1, \ldots , o_{n+k}$. Let $g$ be the method currently executing, and let $C$ be the class in which $g$ was looked up (\ref{methodLookup}). Let $S_{dynamic}$ be the superclass of $C$, and let $f$ be the result of looking up method (\ref{methodLookup}) $m$ in $S_{dynamic}$ with respect to the current library $L$.
+First, the argument list $(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$ is evaluated producing actual argument objects $o_1, \ldots , o_{n+k}$. Let $g$ be the method currently executing, and let $C$ be the class in which $g$ was looked up (\ref{methodLookup}). Let $S_{dynamic}$ be the superclass of $C$, and let $f$ be the result of looking up method (\ref{methodLookup}) $m$ in $S_{dynamic}$ with respect to the current library $L$.
Let $p_1 \ldots p_h$ be the required parameters of $f$, let $p_1 \ldots p_m$ be the positional parameters of $f$ and let $p_{h+1}, \ldots, p_{h+l}$ be the optional parameters declared by $f$.
\LMHash{}
@@ -4431,6 +4493,7 @@ It is a compile-time error to invoke any of the setters of class \cd{Object} on
Evaluation of a compound assignment $a$ of the form \code{$v$ ??= $e$}
proceeds as follows:
+\LMHash{}
Evaluate $v$ to an object $o$.
If $o$ is not the null value, $a$ evaluates to $o$.
Otherwise evaluate \code{$v$ = $e$} to a value $r$,
@@ -4439,6 +4502,7 @@ and then $a$ evaluates to $r$.
\LMHash{}
Evaluation of a compound assignment, $a$ of the form \code{$C$.$v$ ??= $e$}, where $C$ is a type literal, proceeds as follow:
+\LMHash{}
Evaluate \code{$C$.$v$} to an object $o$.
If $o$ is not the null value, $a$ evaluates to $o$.
Otherwise evaluate \code{$C$.$v$ = $e$} to a value $r$,
@@ -4455,7 +4519,7 @@ proceeds as follows:
\LMHash{}
Evaluate $e_1$ to an object $u$.
Let $x$ be a fresh variable bound to $u$.
-Evalute \code{$x$.$v$} to an object $o$.
+Evaluate \code{$x$.$v$} to an object $o$.
If $o$ is not the null value, $a$ evaluates to $o$.
Otherwise evaluate \code{$x$.$v$ = $e_2$} to an object $r$,
and then $a$ evaluates to $r$.
@@ -4478,7 +4542,7 @@ proceeds as follows:
\LMHash{}
Evaluate \code{\SUPER.$v$} to an object $o$.
-If $o$ is not the null value then $a$ evaluats to $o$.
+If $o$ is not the null value then $a$ evaluates to $o$.
Otherwise evaluate \code{\SUPER.$v$ = $e$} to an object $r$,
and then $a$ evaluates to $r$.
@@ -4643,10 +4707,10 @@ The logical boolean expressions combine boolean objects using the boolean conjun
A {\em logical boolean expression} is either an equality expression (\ref{equality}), or an invocation of a logical boolean operator on an expression $e_1$ with argument $e_2$.
\LMHash{}
-Evaluation of a logical boolean expression $b$ of the form $e_1 || e_2$ causes the evaluation of $e_1$ which is then subjected to boolean conversion, yielding an object $o_1$; if $o_1$ is \TRUE, the result of evaluating $b$ is \TRUE, otherwise $e_2$ is evaluated to an object $o_2$, which is then subjected to boolean conversion (\ref{booleanConversion}) producing an object $r$, which is the value of $b$.
+Evaluation of a logical boolean expression $b$ of the form $e_1 || e_2$ causes the evaluation of $e_1$ which is then subjected to boolean conversion, producing an object $o_1$; if $o_1$ is \TRUE, the result of evaluating $b$ is \TRUE, otherwise $e_2$ is evaluated to an object $o_2$, which is then subjected to boolean conversion (\ref{booleanConversion}) producing an object $r$, which is the value of $b$.
\LMHash{}
-Evaluation of a logical boolean expression $b$ of the form $e_1 \&\& e_2$ causes the evaluation of $e_1$ which is then subjected to boolean conversion, yielding an object $o_1$; if $o_1$ is not \TRUE, the result of evaluating $b$ is \FALSE, otherwise $e_2$ is evaluated to an object $o_2$, which is then subjected to boolean conversion producing an object $r$, which is the value of $b$.
+Evaluation of a logical boolean expression $b$ of the form $e_1 \&\& e_2$ causes the evaluation of $e_1$ which is then subjected to boolean conversion, producing an object $o_1$; if $o_1$ is not \TRUE, the result of evaluating $b$ is \FALSE, otherwise $e_2$ is evaluated to an object $o_2$, which is then subjected to boolean conversion evaluating to an object $r$, which is the value of $b$.
\LMHash{}
A logical boolean expression $b$ of the form $e_1 \&\& e_2$ shows that a variable $v$ has type
@@ -4933,18 +4997,24 @@ An {\em await expression} allows code to yield control until an asynchronous ope
\LMHash{}
Evaluation of an await expression $a$ of the form \AWAIT{} $e$ proceeds as follows:
-First, the expression $e$ is evaluated. Next:
+First, the expression $e$ is evaluated to an object $o$.
\LMHash{}
-If $e$ raises an exception $x$, then an instance $f$ of class \code{Future} is allocated and later completed with $x$. Otherwise, if $e$ evaluates to an object $o$ that is not an instance of \code{Future}, then let $f$ be the result of calling \code{Future.value()} with $o$ as its argument; otherwise let $f$ be the result of evaluating $e$.
+% NOTICE: Removed the requirement that an error thrown by $e$ is caught in a
+% future. There is no reason $var x = e; await x;$ and $await e$ should behave
+% differently, and no implementation actually implemented it.
+Then, if $o$ is not an instance of \code{Future}, then let $f$ be the result of creating a new object using the constructor \code{Future.value()} with $o$ as its argument; otherwise let $f$ be $o$.
\LMHash{}
-Next, execution of the function $m$ immediately enclosing $a$ is suspended until after $f$ completes. The stream associated with the innermost enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is paused. At some time after $f$ is completed, control returns to the current invocation. The stream associated with the innermost enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is resumed. If $f$ has completed with an exception $x$, $a$ raises $x$. If $f$ completes with a value $v$, $a$ evaluates to $v$.
+Next, the stream associated with the innermost enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is paused. The current invocation of the function body immediately enclosing $a$ is suspended until after $f$ completes. At some time after $f$ is completed, control returns to the current invocation. If $f$ has completed with an error $x$ and stack trace $t$, $a$ throws $x$ and $t$ (\ref{evaluation}). If $f$ completes with a value $v$, $a$ evaluates to $v$.
%Otherwise, the value of $a$ is the value of $e$. If evaluation of $e$ raises an exception $x$, $a$ raises $x$.
\commentary{
It is a compile-time error if the function immediately enclosing $a$ is not declared asynchronous. However, this error is simply a syntax error, because in the context of a normal function, \AWAIT{} has no special meaning.
+% TODO(lrn): Update this, it's not actually correct,
+% the expression "await(expr)" is valid non-async syntax *and* a valid
+% async await expression.
}
\rationale{
@@ -5130,7 +5200,7 @@ where $e_1$ is not a type literal, proceeds as follows:
If $e_1$ is a type literal, $e$ is equivalent to \code{$e_1$.$v$-{}-}.
Otherwise evaluate $e_1$ to an object $u$.
-If $u$ is the null value, $e$ evalkuates to the null value.
+If $u$ is the null value, $e$ evaluates to the null value.
Otherwise let $x$ be a fresh variable bound to $u$.
Evaluate \code{$x$.$v$-{}-} to an object $o$.
Then $e$ evaluates to $o$.
@@ -5408,6 +5478,35 @@ The static type of a cast expression \code{$e$ \AS{} $T$} is $T$.
\section{Statements}
\LMLabel{statements}
+\LMHash{}
+A {\em statement} is a fragment of Dart code that can be executed at runtime. Statements, unlike expressions, do not evaluate to a value, but are instead executed for their effect on the program state and control flow.
+
+\label{completion}
+Execution of a statement {\em completes} in one of five ways: either it {\em completes normally}, it {\em breaks} or it {\em continues} (either to a label or without a label), it {\em returns} (with or without a value), or it {\em throws} an exception object and an associated stack trace.
+
+In the description of statement execution, the default is that the execution
+completes normally unless otherwise stated.
+
+If the execution of a statement, $s$, is defined in terms of executing
+another statement,
+and the execution of that other statement does not complete normally,
+then, unless otherwise stated, the execution of $s$ stops
+at that point and completes in the same way.
+\commentary{
+For example, if execution of the body of a \DO{} loop returns a value, so does execution of the \DO{} loop statement itself.
+}
+
+If the execution of a statement is defined in terms of evaluating an expression
+and the evaluation of that expression throws,
+then, unless otherwise stated, the execution of the statement stops
+at that point and throws the same exception object and stack trace.
+\commentary{
+For example, if evaluation of the condition expression of an \IF{} statement throws,
+then so does execution of the \IF{} statement. Likewise, if evaluation of the expression of a \RETURN{} statement throws, so does execution of the \RETURN{} statement.
+}
+
+\LMHash{}
+
\begin{grammar}
{\bf statements:}
statement*
@@ -5442,7 +5541,7 @@ The static type of a cast expression \code{$e$ \AS{} $T$} is $T$.
\LMLabel{blocks}
\LMHash{}
- A {\em block statement} supports sequencing of code.
+A {\em block statement} supports sequencing of code.
\LMHash{}
Execution of a block statement $\{s_1, \ldots, s_n\}$ proceeds as follows:
@@ -5454,9 +5553,8 @@ For $i \in 1 .. n, s_i$ is executed.
A block statement introduces a new scope, which is nested in the lexically enclosing scope in which the block statement appears.
-
- \subsection{Expression Statements}
- \LMLabel{expressionStatements}
+\subsection{Expression Statements}
+\LMLabel{expressionStatements}
\LMHash{}
An {\em expression statement} consists of an expression other than a non-constant map literal (\ref{maps}) that has no explicit type arguments.
@@ -5583,15 +5681,14 @@ The {\em if statement} allows for conditional execution of statements.
\begin{grammar}
{\bf ifStatement:}
- \IF{} `(' expression `)' statement ( \ELSE{} statement)? % we could allow top level expression
+ \IF{} `(' expression `)' statement ( \ELSE{} statement)?
.
- \end{grammar}
+\end{grammar}
Execution of an if statement of the form \code {\IF{} (}$b$\code{)}$s_1$ \code{\ELSE{} } $s_2$ proceeds as follows:
\LMHash{}
- First, the expression $b$ is evaluated to an object $o$. Then, $o$ is subjected to boolean conversion (\ref{booleanConversion}), producing an object $r$. If $r$ is \TRUE{}, then the statement $\{s_1\}$ is executed, otherwise statement $\{s_2\}$ is executed.
-
+ First, the expression $b$ is evaluated to an object $o$. Then, $o$ is subjected to boolean conversion (\ref{booleanConversion}), producing an object $r$. If $r$ is \TRUE{}, then the statement $\{s_1\}$ is executed, otherwise statement $\{s_2\}$ is executed.
\commentary {
Put another way, \code {\IF{} (}$b$\code{)}$s_1$ \code{\ELSE{} } $s_2$ is equivalent to
@@ -5661,7 +5758,7 @@ The {\em for statement} supports iteration.
\LMHash{}
-Execution of a for statement of the form \code{ \FOR{} (\VAR{} $v = e_0$ ; $c$; $e$) $s$} proceeds as follows:
+Execution of a for statement of the form \code{ \FOR{} (\VAR{} $v$ = $e_0$ ; $c$; $e$) $s$} proceeds as follows:
\LMHash{}
If $c$ is empty then let $c^\prime$ be \TRUE{} otherwise let $c^\prime$ be $c$.
@@ -5673,12 +5770,16 @@ First the variable declaration statement \VAR{} $v = e_0$ is executed. Then:
\label{beginFor}
If this is the first iteration of the for loop, let $v^\prime$ be $v$. Otherwise, let $v^\prime$ be the variable $v^{\prime\prime}$ created in the previous execution of step \ref{allocateFreshVar}.
\item
-The expression $[v^\prime/v]c$ is evaluated and subjected to boolean conversion (\ref{booleans}). If the result is \FALSE{}, the for loop completes. Otherwise, execution continues at step
+The expression $[v^\prime/v]c$ is evaluated and subjected to boolean conversion (\ref{booleans}). If the result is \FALSE{}, the for loop completes normally. Otherwise, execution continues at step
\ref{beginIteration}.
\item
\label{beginIteration}
The statement $[v^\prime/v]\{s\}$ is executed.
-\item
+
+If this execution completes normally, continues without a label,
+or continues to a label (\ref{labels}) that prefixes this \FOR{} statement (\ref{completion}),
+then execution of the statement is treated as if it had completed normally.
+
\label{allocateFreshVar}
Let $v^{\prime\prime}$ be a fresh variable. $v^{\prime\prime}$ is bound to the value of $v^\prime$.
\item
@@ -5722,8 +5823,6 @@ var n0 = $e$.iterator;
\end{dartCode}
where \code{n0} is an identifier that does not occur anywhere in the program, except that for purposes of static typechecking, it is checked under the assumption that $n0$ is declared to be of type $T$, where $T$ is the static type of $e.iterator$.
-
-
\subsubsection{Asynchronous For-in}
\LMLabel{asynchronousFor-in}
@@ -5731,22 +5830,71 @@ where \code{n0} is an identifier that does not occur anywhere in the program, ex
A for-in statement may be asynchronous. The asynchronous form is designed to iterate over streams. An asynchronous for loop is distinguished by the keyword \AWAIT{} immediately preceding the keyword \FOR.
\LMHash{}
-Execution of a for-in statement of the form \code{\AWAIT{} \FOR{} (finalConstVarOrType? id \IN{} $e$) $s$} proceeds as follows:
+Execution of a for-in statement, $f$, of the form \code{\AWAIT{} \FOR{} (finalConstVarOrType? $id$ \IN{} $e$) $s$} proceeds as follows:
+
+\LMHash{}
+The expression $e$ is evaluated to an object $o$.
+It is a dynamic error if $o$ is not an instance of a class that implements \code{Stream}.
\LMHash{}
-The expression $e$ is evaluated to an object $o$. It is a dynamic error if $o$ is not an instance of a class that implements \code{Stream}. Otherwise, the expression \code{\AWAIT{} $v_f$} (\ref{awaitExpressions}) is evaluated, where $v_f$ is a fresh variable whose value is a fresh instance (\ref{generativeConstructors}) $f$ implementing the built-in class \code{Future}.
+The stream associated with the innermost enclosing asynchronous for loop, if any, is paused.
+The stream $o$ is listened to, producing a stream subscription $u$,
+and execution of the asynchronous for-in loop is suspended
+until a stream event is available.
+\commentary{
+This allows other asynchronous events to execute while this loop is waiting for stream events.
+}
+
+Pausing an asynchronous for loop means pausing the associated stream subscription.
+A stream subscription is paused by calling its \code{pause} method.
+If the subscription is already paused, an implementation may omit further calls to \code{pause}.
+
+\commentary{
+The \code{pause} call can throw, although that should never happen for a correctly implemented stream.
+}
\LMHash{}
-The stream $o$ is listened to, and on each data event in $o$ the statement $s$ is executed with \code{id} bound to the value of the current element of the stream. If $s$ raises an exception, or if $o$ raises an exception, then $f$ is completed with that exception. Otherwise, when all events in the stream $o$ have been processed, $f$ is completed with \NULL{} (\ref{null}).
+For each {\em data event} from $u$,
+the statement $s$ is executed with $id$ bound to the value of the current data event.
\LMHash{}
-Let $u$ be the stream associated with the immediately enclosing asynchronous for loop or generator function (\ref{functions}), if any. If another event $e_u$ of $u$ occurs before execution of $s$ is complete, handling of $e_u$ must wait until $s$ is complete.
+\commentary{
+Either execution of $s$ is completely synchronous, or it contains an
+asynchronous construct (\AWAIT{}, \AWAIT{} \FOR{}, \YIELD{} or \YIELD*)
+which will pause the stream subscription of its surrounding asynchronous loop.
+This ensures that no other event of $u$ occurs before execution of $s$ is complete, if $o$ is a correctly implemented stream.
+If $o$ doesn't act as a valid stream, for example by not respecting pause requests, the behavior of the asynchronous loop may become unpredictable.
+}
-\rationale{
-The future $f$ and the corresponding \AWAIT{} expression ensure that execution suspends as an asynchronous for loop begins and resumes after the \FOR{} statement when it ends. They also ensure that the stream of any enclosing asynchronous \FOR{} loop is paused for the duration of this loop.
+\LMHash{}
+If execution of $s$ continues without a label, or to a label (\ref{labels}) that prefixes the asynchronous for statement (\ref{completion}), then the execution of $s$ is treated as if it had completed normally.
+
+If execution of $s$ otherwise does not complete normally, the subscription $u$ is canceled by evaluating \code{\AWAIT{} $v$.cancel()} where $v$ is a fresh variable referencing the stream subscription $u$.
+If that evaluation throws,
+execution of $f$ throws the same exception and stack trace.
+Otherwise execution of $f$ completes in the same way as the execution of $s$.
+% Notice: The previous specification was unclear about what happened when
+% a subscripton is canceled. This text is explicit, and existing
+% implementations may not properly await the cancel call.
+Otherwise the execution of $f$ is suspended again, waiting for the next stream subscription event, and $u$ is resumed if it has been paused.
+\commentary{
+The \code{resume} call can throw, in which case the asynchronous for
+loop also throws. That should never happen for a correctly implemented stream.
}
\LMHash{}
+On an {\em error event} from $u$,
+with error object $e$ and stack trace $st$,
+the subscription $u$ is canceled by evaluating \code{\AWAIT{} v.cancel()}
+where $v$ is a fresh variable referencing the stream subscription $u$.
+If that evaluation throws,
+execution of $f$ throws the same exception object and stack trace.
+Otherwise execution of $f$ throws with $e$ as exception object and $st$ as stack trace.
+
+\LMHash{}
+When $u$ is done, execution of $f$ completes normally.
+
+\LMHash{}
It is a compile-time error if an asynchronous for-in statement appears inside a synchronous function (\ref{functions}). It is a compile-time error if a traditional for loop (\ref{forLoop}) is prefixed by the \AWAIT{} keyword.
\rationale{An asynchronous loop would make no sense within a synchronous function, for the same reasons that an await expression makes no sense in a synchronous function.}
@@ -5765,10 +5913,23 @@ The while statement supports conditional iteration, where the condition is evalu
\end{grammar}
\LMHash{}
- Execution of a while statement of the form \code{\WHILE{} ($e$) $s$;} proceeds as follows:
+Execution of a while statement of the form \code{\WHILE{} ($e$) $s$;} proceeds as follows:
\LMHash{}
-The expression $e$ is evaluated to an object $o$. Then, $o$ is subjected to boolean conversion (\ref{booleanConversion}), producing an object $r$. If $r$ is \TRUE{}, then the statement $\{s\}$ is executed and then the while statement is re-executed recursively. If $r$ is \FALSE{}, execution of the while statement is complete.
+The expression $e$ is evaluated to an object $o$. Then, $o$ is subjected to boolean conversion (\ref{booleanConversion}), producing an object $r$.
+
+\LMHash{}
+If $r$ is \FALSE{}, then execution of the while statement completes normally
+(\ref{completion}).
+
+\LMHash{}
+Otherwise $r$ is \TRUE{} and then the statement $\{s\}$ is executed.
+If that execution completes normally or it continues with no label or to a label (\ref{labels}) that prefixes the \WHILE{} statement (\ref{completion}), then the while statement is re-executed.
+If the execution breaks without a label, execution of the while statement completes normally.
+\commentary{
+If the execution breaks with a label that prefixes the \WHILE{} statement,
+it does end execution of the loop, but the break itself is handled by the surrounding labeled statement (\ref{labels}).
+}
\LMHash{}
It is a static type warning if the static type of $e$ may not be assigned to \code{bool}.
@@ -5791,7 +5952,13 @@ The do statement supports conditional iteration, where the condition is evaluate
Execution of a do statement of the form \code{\DO{} $s$ \WHILE{} ($e$);} proceeds as follows:
\LMHash{}
-The statement $\{s\}$ is executed. Then, the expression $e$ is evaluated to an object $o$. Then, $o$ is subjected to boolean conversion (\ref{booleanConversion}), producing an object $r$. If $r$ is \FALSE{}, execution of the do statement is complete. If $r$ is \TRUE{}, then the do statement is re-executed recursively.
+The statement $\{s\}$ is executed.
+If that execution continues with no label, or to a label (\ref{labels}) that prefixes the do statement (\ref{completion}), then the execution of $s$ is treated as if it had completed normally.
+
+\LMHash{}
+Then, the expression $e$ is evaluated to an object $o$. Then, $o$ is subjected to boolean conversion (\ref{booleanConversion}), producing an object $r$.
+If $r$ is \FALSE{}, execution of the do statement completes normally (\ref{completion}).
+If $r$ is \TRUE{}, then the do statement is re-executed.
\LMHash{}
It is a static type warning if the static type of $e$ may not be assigned to \code{bool}.
@@ -5802,7 +5969,7 @@ It is a static type warning if the static type of $e$ may not be assigned to \co
\LMHash{}
The {\em switch statement} supports dispatching control among a large number of cases.
- \begin{grammar}
+\begin{grammar}
{\bf switchStatement:}
\SWITCH{} `(' expression `)' `\{' switchCase* defaultCase? `\}'% could do top level here and in cases
.
@@ -5886,18 +6053,15 @@ or the form
proceeds as follows:
\LMHash{}
-The statement \code{\VAR{} id = $e$;} is evaluated, where \code{id} is a variable whose name is distinct from any other variable in the program. In checked mode, it is a run time error if the value of $e$ is not an instance of the same class as the constants $e_1 \ldots e_n$.
+The statement \code{\VAR{} $id$ = $e$;} is evaluated, where $id$ is a fresh variable. In checked mode, it is a run time error if the value of $e$ is not an instance of the same class as the constants $e_1 \ldots e_n$.
\commentary{Note that if there are no case clauses ($n = 0$), the type of $e$ does not matter.}
\LMHash{}
-Next, the case clause \CASE{} $e_{1}: s_{1}$ is executed if it exists. If \CASE{} $e_{1}: s_{1}$ does not exist, then if there is a \DEFAULT{} clause it is executed by executing $s_{n+1}$.
-
-\LMHash{}
-A case clause introduces a new scope, nested in the lexically surrounding scope. The scope of a case clause ends immediately after the case clause's statement list.
+Next, the case clause \CASE{} $e_{1}$: $s_{1}$ is matched against $id$, if $n > 0$. Otherwise if there is a \DEFAULT{} clause, the case statements $s_{n+1}$ are executed (\ref{case-execute}).
\LMHash{}
-Execution of a \CASE{} clause \CASE{} $e_{k}: s_{k}$ of a switch statement
+Matching of a \CASE{} clause \CASE{} $e_{k}: s_{k}$ of a switch statement
\begin{dartCode}
\SWITCH{} ($e$) \{
@@ -5908,16 +6072,15 @@ Execution of a \CASE{} clause \CASE{} $e_{k}: s_{k}$ of a switch statement
\}
\end{dartCode}
-proceeds as follows:
+against the value of a variable $id$ proceeds as follows:
\LMHash{}
-The expression \code{$e_k$ == id} is evaluated to an object $o$ which is then subjected to boolean conversion yielding a value $v$.
-If $v$ is not \TRUE{} the following case, \CASE{} $e_{k+1}: s_{k+1}$ is executed if it exists. If \CASE{} $e_{k+1}: s_{k+1}$ does not exist, then the \DEFAULT{} clause is executed by executing $s_{n+1}$.
-If $v$ is \TRUE{}, let $h$ be the smallest number such that $h \ge k$ and $s_h$ is non-empty. If no such $h$ exists, let $h = n + 1$. The sequence of statements $s_h$ is then executed.
-If execution reaches the point after $s_h$ then a runtime error occurs, unless $h = n+1$.
+The expression \code{$e_k$ == $id$} is evaluated to an object $o$ which is then subjected to boolean conversion evaluating to a value $v$.
+If $v$ is not \TRUE{} the following case, \CASE{} $e_{k+1}: s_{k+1}$ is matched against $id$ if $k < n$. If $k = n$, then the \DEFAULT{} clause's statements are executed (\ref{case-execute}).
+If $v$ is \TRUE{}, let $h$ be the smallest number such that $h \ge k$ and $s_h$ is non-empty. If no such $h$ exists, let $h = n + 1$. The case statements $s_h$ are then executed (\ref{case-execute}).
\LMHash{}
-Execution of a \CASE{} clause \CASE{} $e_{k}: s_{k}$ of a switch statement
+Matching of a \CASE{} clause \CASE{} $e_{k}: s_{k}$ of a switch statement
\begin{dartCode}
\SWITCH{} ($e$) \{
@@ -5927,24 +6090,20 @@ Execution of a \CASE{} clause \CASE{} $e_{k}: s_{k}$ of a switch statement
\}
\end{dartCode}
-proceeds as follows:
+against the value of a variable $id$ proceeds as follows:
\LMHash{}
-The expression \code{$e_k$ == id} is evaluated to an object $o$ which is then subjected to boolean conversion yielding a value $v$.
-If $v$ is not \TRUE{} the following case, \CASE{} $e_{k+1}: s_{k+1}$ is executed if it exists.
-If $v$ is \TRUE{}, let $h$ be the smallest integer such that $h \ge k$ and $s_h$ is non-empty. The sequence of statements $s_h$ is executed if it exists.
-If execution reaches the point after $s_h$ then a runtime error occurs, unless $h = n$.
+The expression \code{$e_k$ == $id$} is evaluated to an object $o$ which is then subjected to boolean conversion evaluating to a value $v$.
+If $v$ is not \TRUE{} the following case, \CASE{} $e_{k+1}: s_{k+1}$ is matched against $id$ if $k < n$.
+If $v$ is \TRUE{}, let $h$ be the smallest integer such that $h \ge k$ and $s_h$ is non-empty. If such a $h$ exists, the case statements $s_h$ are executed (\ref{case-execute}). Otherwise the switch statement completes normally (
+ref{completion}).
-\commentary{
-In other words, there is no implicit fall-through between non-empty cases. The last case in a switch (default or otherwise) can `fall-through' to the end of the statement.
-}
-
\LMHash{}
It is a static warning if the type of $e$ may not be assigned to the type of $e_k$.
Let $s$ be the last statement of the statement sequence $s_k$.
-If $s$ is a non-empty block statement, let $s$ instead be the last statment of the block statement.
-It is a static warning $s$ is not a \BREAK{}, \CONTINUE{}, \RETHROW{} or \RETURN{} statement or an expression statment where the expression is a \THROW{} expression.
+If $s$ is a non-empty block statement, let $s$ instead be the last statement of the block statement.
+It is a static warning $s$ is not a \BREAK{}, \CONTINUE{}, \RETHROW{} or \RETURN{} statement or an expression statement where the expression is a \THROW{} expression.
\rationale{
The behavior of switch cases intentionally differs from the C tradition. Implicit fall through is a known cause of programming errors and therefore disallowed. Why not simply break the flow implicitly at the end of every case, rather than requiring explicit code to do so? This would indeed be cleaner. It would also be cleaner to insist that each case have a single (possibly compound) statement. We have chosen not to do so in order to facilitate porting of switch statements from other languages. Implicitly breaking the control flow at the end of a case would silently alter the meaning of ported code that relied on fall-through, potentially forcing the programmer to deal with subtle bugs. Our design ensures that the difference is immediately brought to the coder's attention. The programmer will be notified at compile-time if they forget to end a case with a statement that terminates the straight-line control flow. We could make this warning a compile-time error, but refrain from doing so because do not wish to force the programmer to deal with this issue immediately while porting code. If developers ignore the warning and run their code, a run time error will prevent the program from misbehaving in hard-to-debug ways (at least with respect to this issue).
@@ -5974,13 +6133,63 @@ The sophistication of the analysis of fall-through is another issue. For now, we
In other words, a warning will be issued if a switch statement over an enum is not exhaustive.
}
+\LMHash{}
+\subsubsection{Switch case statements}
+\LMLabel{case-execute}
+
+\LMHash{}
+Execution of the case statements $s_h$ of a switch statement
+
+\begin{dartCode}
+\SWITCH{} ($e$) \{
+ $label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
+ $\ldots$
+ $label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
+\}
+\end{dartCode}
+
+or a switch statement
+
+\begin{dartCode}
+\SWITCH{} ($e$) \{
+ $label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
+ $\ldots$
+ $label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
+ $label_{(n+1)1} \ldots label_{(n+1)j_{n+1}}$ \DEFAULT{}: $s_{n+1}$
+\}
+\end{dartCode}
+
+proceeds as follows:
+
+\LMHash{}
+Execute $\{s_h\}$.
+If this execution completes normally,
+and if $s_h$ is not the statements of the last case of the switch
+($h = n$ if there is no \DEFAULT{} clause,
+$h = n+1$ if there is a \DEFAULT{} clause),
+then the execution of the switch case throws an error.
+Otherwise $s_h$ are the last statements of the switch case,
+and execution of the switch case completes normally.
+
+\commentary{
+In other words, there is no implicit fall-through between non-empty cases. The last case in a switch (default or otherwise) can `fall-through' to the end of the statement.
+}
+
+If execution of $\{s_h\}$ breaks with no label (\ref{completion}), then the execution of the switch statement completes normally.
+
+If execution of $\{s_h\}$ continues to a label (\ref{completion}), and the label is $label_{ij}$, where $1 \le i \le n+1$ if the \SWITCH{} statement has a \DEFAULT{}, or $1 \le i \le n$ if there is no \DEFAULT{}, and where $1 \le j \le j_{i}$, then
+let $h$ be the smallest number such that $h \ge i$ and $s_h$ is non-empty. If no such $h$ exists, let $h = n + 1$ if the \SWITCH{} statement has a \DEFAULT{}, otherwise let $h = n$.
+The case statements $s_h$ are then executed (\ref{case-execute}).
+
+If execution of $\{s_h\}$ completes in any other way, execution of the \SWITCH{} statement completes in the same way.
+
\subsection{ Rethrow}
\LMLabel{rethrow}
\LMHash{}
-The {\em rethrow statement} is used to re-raise an exception.
+The {\em rethrow statement} is used to re-throw an exception and its associated stack trace.
\begin{grammar}
{\bf rethrowStatement:}
@@ -5999,25 +6208,12 @@ A \RETHROW{} statement always appears inside a \CATCH{} clause, and any \CATCH{}
}
\LMHash{}
-The current exception (\ref{throw}) is set to $p_1$, the current return value (\ref{return}) becomes undefined, and the active stack trace (\ref{try}) is set to $p_2$.
-
-\LMHash{}
-If $f$ is marked \ASYNC{} or \ASYNC* (\ref{functions}) and there is a dynamically enclosing exception handler (\ref{try}) $h$ introduced by the current activation, control is transferred to $h$, otherwise $f$ terminates.
-
-\rationale{
-In the case of an asynchronous function, the dynamically enclosing exception handler is only relevant within the function. If an exception is not caught within the function, the exception value is channelled through a future or stream rather than propagating via exception handlers.
-}
-
-\LMHash{}
-Otherwise, control is transferred to the innermost enclosing exception handler.
-
-\commentary{The change in control may result in multiple functions terminating if these functions do not catch the exception via a \CATCH{} or \FINALLY{} clause, both of which introduce a dynamically enclosing exception handler.}
+The \RETHROW{} statement {\em throws} (\ref{completion}) with $p_1$ as the exception object and $p_2$ as the stack trace.
\LMHash{}
It is a compile-time error if a \code{\RETHROW{}} statement is not enclosed within an \ON-\CATCH{} clause.
-
\subsection{ Try}
\LMLabel{try}
@@ -6043,10 +6239,10 @@ The try statement supports the definition of exception handling code in a struct
\end{grammar}
\LMHash{}
- A try statement consists of a block statement, followed by at least one of:
- \begin{enumerate}
- \item
-A set of \ON{}-\CATCH{} clauses, each of which specifies (either explicitly or implicitly) the type of exception object to be handled, one or two exception parameters and a block statement.
+A try statement consists of a block statement, followed by at least one of:
+\begin{enumerate}
+\item
+A set of \ON{}-\CATCH{} clauses, each of which specifies (either explicitly or implicitly) the type of exception object to be handled, one or two exception parameters, and a block statement.
\item
A \FINALLY{} clause, which consists of a block statement.
\end{enumerate}
@@ -6056,123 +6252,84 @@ The syntax is designed to be upward compatible with existing Javascript programs
}
\LMHash{}
-An \ON{}-\CATCH{} clause of the form \code{\ON{} $T$ \CATCH{} ($p_1, p_2$) $s$} {\em matches} an object $o$ if the type of $o$ is a subtype of $T$. If $T$ is a malformed or deferred type (\ref{staticTypes}), then performing a match causes a run time error.
-
-\commentary {
-It is of course a static warning if $T$ is a deferred or malformed type.
-}
-
-\LMHash{}
-An \ON{}-\CATCH{} clause of the form \code{\ON{} $T$ \CATCH{} ($p_1, p_2$) $s$} introduces a new scope $CS$ in which final local variables specified by $p_1$ and $p_2$ are defined. The statement $s$ is enclosed within $CS$. The static type of $p_1$ is $T$ and the static type of $p_2$ is \code{StackTrace}.
-
+A try statement of the form \code{\TRY{} $s_1$ $on-catch_1 \ldots on-catch_n$;} is equivalent to the statement \code{\TRY{} $s_1$ $on-catch_1 \ldots on-catch_n$ \FINALLY{} $\{\}$}.
\LMHash{}
-An \ON{}-\CATCH{} clause of the form \code{\ON{} $T$ \CATCH{} ($p_1$) $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} $T$ \CATCH{} ($p_1, p_2$) $s$} where $p_2$ is an identifier that does not occur anywhere else in the program.
-
+An \ON{}-\CATCH{} clause of the form \code{\ON{} $T$ \CATCH{} ($p_1$) $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} $T$ \CATCH{} ($p_1$, $p_2$) $s$} where $p_2$ is a fresh identifier.
\LMHash{}
-An \ON{}-\CATCH{} clause of the form \code{\CATCH{} ($p$) $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} \DYNAMIC{} \CATCH{} ($p$) $s$}. An \ON{}-\CATCH{} clause of the form \code{\CATCH{} ($p_1, p_2$) $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} \DYNAMIC{} \CATCH{} ($p_1, p_2$) $s$}.
-
-
-%If an explicit type is associated with of $p_2$, it is a static warning if that type is not \code{Object} or \DYNAMIC{}.
+An \ON{}-\CATCH{} clause of the form \code{\ON{} $T$ $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} $T$ \CATCH{} ($p_1$, $p_2$) $s$} where $p_1$ and $p_2$ are fresh identifiers.
\LMHash{}
-The {\em active stack trace} is an object whose \code{toString()} method produces a string that is a record of exactly those function activations within the current isolate that had not completed execution at the point where the current exception (\ref{throw}) was thrown.
-%\begin{enumerate}
-%\item Started execution after the currently executing function.
-%\item Had not completed execution at the point where the exception caught by the currently executing \ON{}-\CATCH{} clause was initially thrown.
-%\commentary{The active stack trace contains the frames between the exception handling code and the original point when an exception is thrown, not where it was rethrown.}
-%\end{enumerate}
-
- \commentary{
-This implies that no synthetic function activations may be added to the trace, nor may any source level activations be omitted.
-This means, for example, that any inlining of functions done as an optimization must not be visible in the trace. Similarly, any synthetic routines used by the implementation must not appear in the trace.
-
-Nothing is said about how any native function calls may be represented in the trace.
- }
-
-\commentary{
-Note that we say nothing about the identity of the stack trace, or what notion of equality is defined for stack traces.
-}
-
-% Sadly, the info below cannot be computed efficiently. It would need to be computed at the throw point, since at latte points it might be destroyed. Native code in calling frames executes relative to the stack pointer, which therefore needs to be reset as each frame is unwound. This means that the
-% OS kernel can dispose of this stack memory - it is not reliably preserved. And such code must execute if only to test if the exception should be caught or sent onward.
-
-% For each such function activation, the active stack trace includes the name of the function, the bindings of all its formal parameters, local variables and \THIS{}, and the position at which the function was executing.
-
- % Is this controversial? We were thinking of viewing the trace as a List<Invocation>,
- % but that won't capture the receiver or the locals. More generally, we need a standard interface that describes these traces, so one can type the stack trace variable in the catch.
+An \ON{}-\CATCH{} clause of the form \code{\CATCH{} ($p$) $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} \DYNAMIC{} \CATCH{} ($p$, $p_2$) $s$} where $p_2$ is a fresh identifier.
- \commentary{The term position should not be interpreted as a line number, but rather as a precise position - the exact character index of the expression that raised the exception. }
-
- % A position can be represented via a Token. If we make that part of the core reflection facility, we can state this here.
+An \ON{}-\CATCH{} clause of the form \code{\CATCH{} ($p_1$, $p_2$) $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} \DYNAMIC{} \CATCH{} ($p_1$, $p_2$) $s$}.
\LMHash{}
-A try statement \TRY{} $s_1$ $on-catch_1 \ldots on-catch_n$ \FINALLY{} $s_f$ defines an exception handler $h$ that executes as follows:
+An \ON{}-\CATCH{} clause of the form \code{\ON{} $T$ \CATCH{} ($p_1$, $p_2$) $s$} introduces a new scope $CS$ in which final local variables specified by $p_1$ and $p_2$ are defined. The statement $s$ is enclosed within $CS$. The static type of $p_1$ is $T$ and the static type of $p_2$ is \code{StackTrace}.
\LMHash{}
-The \ON{}-\CATCH{} clauses are examined in order, starting with $catch_1$, until either an \ON{}-\CATCH{} clause that matches the current exception (\ref{throw}) is found, or the list of \ON{}-\CATCH{} clauses has been exhausted. If an \ON{}-\CATCH{} clause $on-catch_k$ is found, then $p_{k1}$ is bound to the current exception, $p_{k2}$, if declared, is bound to the active stack trace, and then $catch_k$ is executed. If no \ON{}-\CATCH{} clause is found, the \FINALLY{} clause is executed. Then, execution resumes at the end of the try statement.
-
+Execution of a \TRY{} statement $s$ on the form:
+\begin{dartCode}
+\TRY{} $b$
+\ON{} $T_1$ \CATCH{} ($e_1$, $t_1$) $c_1$
+\ldots{}
+\ON{} $T_n$ \CATCH{} ($e_n$, $t_n$) $c_n$
+\FINALLY{} $f$
+\end{dartCode}
+proceeds as follows:
\LMHash{}
-A finally clause \FINALLY{} $s$ defines an exception handler $h$ that executes as follows:
+First $b$ is executed.
+If execution of $b$ throws (\ref{completion}) with exception object $e$ and stack trace $t$, then $e$ and $t$ are matched against the \ON{}-\CATCH{} clauses to yield a new completion (\ref{on-catch}).
-\LMHash{}
-Let $r$ be the current return value (\ref{return}). Then the current return value becomes undefined. Any open streams associated with any asynchronous for loops (\ref{asynchronousFor-in}) and yield-each (\ref{yieldEach}) statements executing within the dynamic scope of $h$ are canceled, in the order of their nesting, innermost first.
+Then, even if execution of $b$ did not complete normally or matching against the \ON{}-\CATCH{} clauses did not complete normally, the $f$ block is executed.
-\rationale{
-Streams left open by for loops that were escaped for whatever reason would be canceled at function termination, but it is best to cancel them as soon as possible.
-}
+If execution of $f$ does not complete normally,
+execution of the \TRY{} statement completes in the same way.
+Otherwise if execution of $b$ threw (\ref{completion}), the \TRY{} statement completes in the same way as the matching against the \ON{}-\CATCH{} clauses.
+Otherwise the \TRY{} statement completes in the same way as the execution of $b$.
\LMHash{}
-Then the \FINALLY{} clause is executed. Let $m$ be the immediately enclosing function. If $r$ is defined then the current return value is set to $r$ and then:
-\begin{itemize}
-\item
- if there is a dynamically enclosing error handler $g$ defined by a \FINALLY{} clause in $m$, control is transferred to $g$.
- \item
-Otherwise $m$ terminates.
-\end{itemize}
-
-Otherwise, execution resumes at the end of the try statement.
+If $T_1$ is a malformed or deferred type (\ref{staticTypes}), then performing a match causes a run time error.
+It is a static warning if $T_i$, $1 \le i \le n$ is a deferred or malformed type.
-\LMHash{}
-Execution of an \ON{}-\CATCH{} clause \code{\ON{} $T$ \CATCH{} ($p_1$, $p_2$)} $s$ of a try statement $t$ proceeds as follows:
-The statement $s$ is executed in the dynamic scope of the exception handler defined by the finally clause of $t$. Then, the current exception and active stack trace both become undefined.
+\subsubsection{\ON{}-\CATCH{} clauses}
+\LMLabel{on-catch}
\LMHash{}
-Execution of a \FINALLY{} clause \FINALLY{} $s$ of a try statement proceeds as follows:
+Matching an exception object $e$ and stack trace $t$ against a (potentially empty) sequence of \ON{}-\CATCH{} clauses on the form
+\begin{dartCode}
+\ON{} $T_1$ \CATCH{} ($e_1$, $st_1$) \{ $s_1$ \}
+\ldots
+\ON{} $T_n$ \CATCH{} ($e_n$, $st_n$) \{ $s_n$ \}
+\end{dartCode}
+proceeds as follows:
\LMHash{}
-Let $x$ be the current exception and let $t$ be the active stack trace. Then the current exception and the active stack trace both become undefined. The statement $s$ is executed. Then, if $x$ is defined, it is rethrown as if by a rethrow statement (\ref{rethrow}) enclosed in a \CATCH{} clause of the form \code{\CATCH{} ($v_x$, $v_t$)} where $v_x$ and $v_t$ are fresh variables bound to $x$ and $t$ respectively.
-
+If there are no \ON{}-\CATCH{} clauses ($n = 0$), matching throws the exception object $e$ and stack trace $t$ (\ref{completion}).
\LMHash{}
-Execution of a try statement of the form \code{\TRY{} $s_1$ $on-catch_1 \ldots on-catch_n$ \FINALLY{} $s_f$;} proceeds as follows:
+Otherwise the exception is matched against the first clause.
\LMHash{}
-The statement $s_1$ is executed in the dynamic scope of the exception handler defined by the try statement. Then, the \FINALLY{} clause is executed.
-
-\commentary{
-Whether any of the \ON{}-\CATCH{} clauses is executed depends on whether a matching exception has been raised by $s_1$ (see the specification of the throw statement).
-
-If $s_1$ has raised an exception, it will transfer control to the try statement's handler, which will examine the catch clauses in order for a match as specified above. If no matches are found, the handler will execute the \FINALLY{} clause.
-
-If a matching \ON{}-\CATCH{} was found, it will execute first, and then the \FINALLY{} clause will be executed.
-
-If an exception is thrown during execution of an \ON{}-\CATCH{} clause, this will transfer control to the handler for the \FINALLY{} clause, causing the \FINALLY{} clause to execute in this case as well.
-
-If no exception was raised, the \FINALLY{} clause is also executed. Execution of the \FINALLY{} clause could also raise an exception, which will cause transfer of control to the next enclosing handler.
-}
+Otherwise, if the type of $e$ is a subtype of $T_1$, then the first clause matches, and then $e_1$ is bound to the exception object $e$ and $t_1$ is bound to the stack trace $t$, and $s_1$ is executed in this scope.
+The matching completes in the same way as this execution.
\LMHash{}
-A try statement of the form \code{\TRY{} $s_1$ $on-catch_1 \ldots on-catch_n$;} is equivalent to the statement \code{\TRY{} $s_1$ $on-catch_1 \ldots on-catch_n$ \FINALLY{} $\{\}$}.
+Otherwise, if the first clause did not match $e$, $e$ and $t$ are recursively matched against the remaining \ON{}-\CATCH{} clauses:
+\begin{dartCode}
+\ON{} $T_2$ \CATCH{} ($e_2$, $t_2$) \{ $s_2$ \}
+\ldots
+\ON{} $T_n$ \CATCH{} ($e_n$, $t_n$) \{ $s_n$ \}
+\end{dartCode}
\subsection{ Return}
\LMLabel{return}
\LMHash{}
-The {\em return statement} returns a result to the caller of a synchronous function, completes the future associated with an asynchronous function or terminates the stream or iterable associated with a generator (\ref{functions}).
+The {\em return statement} returns a result to the caller of a synchronous function, completes the future associated with an asynchronous function or terminates the stream or iterable associated with a generator (\ref{functions}).
\begin{grammar}
@@ -6181,31 +6338,12 @@ The {\em return statement} returns a result to the caller of a synchronous funct
.
\end{grammar}
- \commentary{
- Due to \FINALLY{} clauses, the precise behavior of \RETURN{} is a little more involved. Whether the value a return statement is supposed to return is actually returned depends on the behavior of any \FINALLY{} clauses in effect when executing the return. A \FINALLY{} clause may choose to return another value, or throw an exception, or even redirect control flow leading to other returns or throws. All a return statement really does is set a value that is intended to be returned when the function terminates.
- }
-
-\LMHash{}
-The {\em current return value} is a unique value specific to a given function activation. It is undefined unless explicitly set in this specification.
-
\LMHash{}
Executing a return statement \code{\RETURN{} $e$;} proceeds as follows:
\LMHash{}
-First the expression $e$ is evaluated, producing an object $o$. Next:
-\begin{itemize}
-\item
-The current return value is set to $o$ and the current exception (\ref{throw}) and active stack trace (\ref{try}) become undefined.
-\item
-Let $c$ be the \FINALLY{} clause of the innermost enclosing try-finally statement (\ref{try}), if any. If $c$ is defined, let $h$ be the handler induced by $c$. If $h$ is defined, control is transferred to $h$.
-\item
-Otherwise execution of the current method terminates.
-\end{itemize}
-
-\commentary{
-In the simplest case, the immediately enclosing function is an ordinary, synchronous non-generator, and upon function termination, the current return value is given to the caller. The other possibility is that the function is marked \ASYNC{}, in which case the current return value is used to complete the future associated with the function invocation. Both these scenarios are specified in section \ref{functionInvocation}.
-The enclosing function cannot be marked as generator (i.e, \ASYNC* or \SYNC*), since generators are not allowed to contain a statement of the form \code{\RETURN{} $e$;} as discussed below.
-}
+First the expression $e$ is evaluated, producing an object $o$.
+Then the return statement returns the value $o$ (\ref{completion}).
\LMHash{}
Let $T$ be the static type of $e$ and let $f$ be the immediately enclosing function.
@@ -6249,40 +6387,13 @@ Hence, a static warning will not be issued if $f$ has no declared return type, s
\rationale{ An asynchronous non-generator always returns a future of some sort. If no expression is given, the future will be completed with \NULL{} and this motivates the requirement above.} \commentary{Leaving the return type of a function marked \ASYNC{} blank will be interpreted as \DYNAMIC{} as always, and cause no type error. Using \code{Future} or \code{Future<Object>} is acceptable as well, but any other type will cause a warning, since \NULL{} has no subtypes.}
\LMHash{}
-A return statement with no expression, \code{\RETURN;} is executed as follows:
-
-\LMHash{}
-If the immediately enclosing function $f$ is a generator, then:
-\begin{itemize}
-\item
-The current return value is set to \NULL{}.
-\item
-Let $c$ be the \FINALLY{} clause of the innermost enclosing try-finally statement, if any. If $c$ is defined, let $h$ be the handler induced by $c$. If $h$ is defined, control is transferred to $h$.
-\item
-Otherwise, execution of the current method terminates.
-\end{itemize}
-
-\LMHash{}
-Otherwise the return statement is executed by executing the statement \code{\RETURN{} \NULL{};} if it occurs inside a method, getter, setter or factory; otherwise, the return statement necessarily occurs inside a generative constructor, in which case it is executed by executing \code{\RETURN{} \THIS{};}.
-
-\commentary{Despite the fact that \code{\RETURN{};} is executed as if by a \code{\RETURN{} $e$;}, it is important to understand that it is not a static warning to include a statement of the form \code{\RETURN{};}
-%in a \VOID{} function; neither is it illegal
-in a generative constructor. The rules relate only to the specific syntactic form \code{\RETURN{} $e$;}.
-}
-
+Executing a return statement with no expression, \code{\RETURN;} returns with no value (\ref{completion}).
-\rationale{
-The motivation for formulating \code{\RETURN{};} in this way stems from the basic requirement that all function invocations indeed return a value. Function invocations are expressions, and we cannot rely on a mandatory typechecker to always prohibit use of \VOID{} functions in expressions. Hence, a return statement must always return a value, even if no expression is specified.
-
-The question then becomes, what value should a return statement return when no return expression is given. In a generative constructor, it is obviously the object being constructed (\THIS{}). A void function is not expected to participate in an expression, which is why it is marked \VOID{} in the first place. Hence, this situation is a mistake which should be detected as soon as possible. The static rules help here, but if the code is executed, using \NULL{} leads to fast failure, which is desirable in this case. The same rationale applies for function bodies that do not contain a return statement at all.
-}
\LMHash{}
It is a static warning if a function contains both one or more explicit return statements of the form \code{\RETURN;} and one or more return statements of the form \code{\RETURN{} $e$;}.
-
-
\subsection{ Labels}
\LMLabel{labels}
@@ -6300,7 +6411,13 @@ A {\em label} is an identifier followed by a colon. A {\em labeled statement} is
\end{grammar}
\LMHash{}
- The semantics of a labeled statement $L: s$ are identical to those of the statement $s$. The namespace of labels is distinct from the one used for types, functions and variables.
+Execution a labeled statement $s$, $label: s_l$, consists of executing $s_l$.
+If execution of $s_l$ breaks to the label $label$ (\ref{completion}),
+then execution of $s$ completes normally,
+otherwise execution of $s$ completes in the same ways as the execution of $s_l$.
+
+\LMHash{}
+The namespace of labels is distinct from the one used for types, functions and variables.
\LMHash{}
The scope of a label that labels a statement $s$ is $s$. The scope of a label that labels a case clause of a switch statement $s$ is $s$.
@@ -6322,11 +6439,12 @@ The {\em break statement} consists of the reserved word \BREAK{} and an optional
\end{grammar}
\LMHash{}
-Let $s_b$ be a \BREAK{} statement. If $s_b$ is of the form \code{\BREAK{} $L$;}, then let $s_E$ be the innermost labeled statement with label $L$ enclosing $s_b$. If $s_b$ is of the form \code{\BREAK{};}, then let $s_E$ be the innermost \DO{} (\ref{do}), \FOR{} (\ref{for}), \SWITCH{} (\ref{switch}) or \WHILE{} (\ref{while}) statement enclosing $s_b$. It is a compile-time error if no such statement $s_E$ exists within the innermost function in which $s_b$ occurs. Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose $s_b$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$. Executing $s_b$ first executes $f_1, \ldots, f_n$ in innermost-clause-first order and then terminates $s_E$.
+Let $s_b$ be a \BREAK{} statement. If $s_b$ is of the form \code{\BREAK{} $L$;}, then let $s_E$ be the innermost labeled statement with label $L$ enclosing $s_b$. If $s_b$ is of the form \code{\BREAK{};}, then let $s_E$ be the innermost \DO{} (\ref{do}), \FOR{} (\ref{for}), \SWITCH{} (\ref{switch}) or \WHILE{} (\ref{while}) statement enclosing $s_b$. It is a compile-time error if no such statement $s_E$ exists within the innermost function in which $s_b$ occurs.
\LMHash{}
-If $s_E$ is an asynchronous for loop (\ref{asynchronousFor-in}), its associated stream subscription is canceled. Furthermore, let $a_k$ be the set of asynchronous for loops and yield-each statements (\ref{yieldEach}) enclosing $s_b$ that are enclosed in $s_E , 1 \le k \le m$, where $a_k$ is enclosed in $a_{k+1}$. The stream subscriptions associated with $a_j$ are canceled, $1 \le j \le m$, innermost first, so that $a_j$ is canceled before $a_{j+1}$.
+Execution of a \BREAK{} statement \code{\BREAK{} $L$;} breaks to the label $L$ (\ref{completion}).
+Execution of a \BREAK{} statement \code{\BREAK{};} breaks without a label (\ref{completion}).
\subsection{ Continue}
@@ -6342,25 +6460,23 @@ The {\em continue statement} consists of the reserved word \CONTINUE{} and an op
\end{grammar}
\LMHash{}
- Let $s_c$ be a \CONTINUE{} statement. If $s_c$ is of the form \code{\CONTINUE{} $L$;}, then let $s_E$ be the innermost labeled \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement or case clause with label $L$ enclosing $s_c$. If $s_c$ is of the form \code{\CONTINUE{};} then let $s_E$ be the innermost \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement enclosing $s_c$. It is a compile-time error if no such statement or case clause $s_E$ exists within the innermost function in which $s_c$ occurs. Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose $s_c$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$. Executing $s_c$ first executes $f_1, \ldots, f_n$ in innermost-clause-first order. Then, if $s_E$ is a case clause, control is transferred to the case clause. Otherwise, $s_E$ is necessarily a loop and execution resumes after the last statement in the loop body.
+Let $s_c$ be a \CONTINUE{} statement. If $s_c$ is of the form \code{\CONTINUE{} $L$;}, then let $s_E$ be the innermost labeled \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement or case clause with label $L$ enclosing $s_c$. If $s_c$ is of the form \code{\CONTINUE{};} then let $s_E$ be the innermost \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement enclosing $s_c$. It is a compile-time error if no such statement or case clause $s_E$ exists within the innermost function in which $s_c$ occurs.
- \commentary{
- In a while loop, that would be the boolean expression before the body. In a do loop, it would be the boolean expression after the body. In a for loop, it would be the increment clause. In other words, execution continues to the next iteration of the loop.
- }
+Execution of a \CONTINUE{} statement \code{\CONTINUE{} $L$;} continues to the label $L$ (\ref{completion}).
+
+Execution of a \CONTINUE{} statement \code{\CONTINUE{};} continues without a label (\ref{completion}).
-\LMHash{}
- If $s_E$ is an asynchronous for loop (\ref{asynchronousFor-in}), let $a_k$ be the set of asynchronous for loops and yield-each statements (\ref{yieldEach}) enclosing $s_c$ that are enclosed in $s_E , 1 \le k \le m$, where $a_k$ is enclosed in $a_{k+1}$. The stream subscriptions associated with $a_j$ are canceled, $1 \le j \le m$, innermost first, so that $a_j$ is canceled before $a_{j+1}$.
- \subsection{ Yield and Yield-Each}
- \LMLabel{yieldAndYieldEach}
+\subsection{ Yield and Yield-Each}
+\LMLabel{yieldAndYieldEach}
- \subsubsection{ Yield}
- \LMLabel{yield}
+\subsubsection{ Yield}
+\LMLabel{yield}
\LMHash{}
- The {\em yield statement} adds an element to the result of a generator function (\ref{functions}).
+The {\em yield statement} adds an element to the result of a generator function (\ref{functions}).
- \begin{grammar}
+\begin{grammar}
{\bf yieldStatement:}
\YIELD{} expression `{\escapegrammar ;}'
.
@@ -6370,20 +6486,20 @@ The {\em continue statement} consists of the reserved word \CONTINUE{} and an op
Execution of a statement $s$ of the form \code{\YIELD{} $e$;} proceeds as follows:
\LMHash{}
-First, the expression $e$ is evaluated to an object $o$. If the enclosing function $m$ is marked \ASYNC* (\ref{functions}) and the stream $u$ associated with $m$ has been paused, then execution of $m$ is suspended until $u$ is resumed or canceled.
+First, the expression $e$ is evaluated to an object $o$. If the enclosing function $m$ is marked \ASYNC* (\ref{functions}) and the stream $u$ associated with $m$ has been paused, then the nearest enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is paused and execution of $m$ is suspended until $u$ is resumed or canceled.
\LMHash{}
Next, $o$ is added to the iterable or stream associated with the immediately enclosing function.
\LMHash{}
-If the enclosing function $m$ is marked \ASYNC* and the stream $u$ associated with $m$ has been canceled, then let $c$ be the \FINALLY{} clause (\ref{try}) of the innermost enclosing try-finally statement, if any. If $c$ is defined, let $h$ be the handler induced by $c$. If $h$ is defined, control is transferred to $h$. If $h$ is undefined, the immediately enclosing function terminates.
+If the enclosing function $m$ is marked \ASYNC* and the stream $u$ associated with $m$ has been canceled, then the \YIELD{} statement returns without a value (\ref{completion}), otherwise it completes normally.
\rationale{
The stream associated with an asynchronous generator could be canceled by any code with a reference to that stream at any point where the generator was passivated. Such a cancellation constitutes an irretrievable error for the generator. At this point, the only plausible action for the generator is to clean up after itself via its \FINALLY{} clauses.
}
\LMHash{}
-Otherwise, if the enclosing function $m$ is marked \ASYNC* (\ref{functions}) then the enclosing function may suspend.
+Otherwise, if the enclosing function $m$ is marked \ASYNC* (\ref{functions}) then the enclosing function may suspend, in which case the nearest enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is paused first.
\rationale {
If a \YIELD{} occurred inside an infinite loop and the enclosing function never suspended, there might not be an opportunity for consumers of the enclosing stream to run and access the data in the stream. The stream might then accumulate an unbounded number of elements. Such a situation is untenable. Therefore, we allow the enclosing function to be suspended when a new value is added to its associated stream. However, it is not essential (and in fact, can be quite costly) to suspend the function on every \YIELD{}. The implementation is free to decide how often to suspend the enclosing function. The only requirement is that consumers are not blocked indefinitely.
@@ -6436,7 +6552,7 @@ If the immediately enclosing function $m$ is marked \SYNC* (\ref{functions}), th
\item It is a dynamic error if the class of $o$ does not implement \code{Iterable}. Otherwise
\item The method \cd{iterator} is invoked upon $o$ returning an object $i$.
\item \label{moveNext} The \cd{moveNext} method of $i$ is invoked on it with no arguments. If \cd{moveNext} returns \FALSE{} execution of $s$ is complete. Otherwise
-\item The getter \cd{current} is invoked on $i$. If the invocation raises an exception $ex$, execution of $s$ throws $ex$. Otherwise, the result $x$ of the getter invocation is added to the iterable associated with $m$.
+\item The getter \cd{current} is invoked on $i$. If the invocation throws (\ref{evaluation}), execution of $s$ throws the same exception object and stack trace (\ref{completion}). Otherwise, the result $x$ of the getter invocation is added to the iterable associated with $m$.
Execution of the function $m$ immediately enclosing $s$ is suspended until the nullary method \code{moveNext()} is invoked upon the iterator used to initiate the current invocation of $m$, at which point execution of $s$ continues at \ref{moveNext}.
\item
The current call to \code{moveNext()} returns \TRUE.
@@ -6446,16 +6562,19 @@ The current call to \code{moveNext()} returns \TRUE.
If $m$ is marked \ASYNC* (\ref{functions}), then:
\begin{itemize}
\item It is a dynamic error if the class of $o$ does not implement \code{Stream}. Otherwise
-\item For each element $x$ of $o$:
+\item The nearest enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is paused.
+\item The $o$ stream is listened to, creating a subscription $s$, and for each event $x$, or error $e$ with stack trace $t$, of $s$:
\begin{itemize}
\item
-If the stream $u$ associated with $m$ has been paused, then execution of $m$ is suspended until $u$ is resumed or canceled.
- \item
-If the stream $u$ associated with $m$ has been canceled, then let $c$ be the \FINALLY{} clause (\ref{try}) of the innermost enclosing try-finally statement, if any. If $c$ is defined, let $h$ be the handler induced by $c$. If $h$ is defined, control is transferred to $h$. If $h$ is undefined, the immediately enclosing function terminates.
+If the stream $u$ associated with $m$ has been paused, then execution of $m$ is suspended until $u$ is resumed or canceled.
+\item
+If the stream $u$ associated with $m$ has been canceled,
+then $s$ is canceled by evaluating \code{\AWAIT{} v.cancel()} where $v$ is a fresh variable referencing the stream subscription $s$.
+Then, if the cancel completed normally, the stream execution of $s$ returns without a value (\ref{completion}).
\item
-Otherwise, $x$ is added to the stream associated with $m$ in the order it appears in $o$. The function $m$ may suspend.
+Otherwise, $x$, or $e$ with $t$, are added to the stream associated with $m$ in the order they appear in $o$. The function $m$ may suspend.
\end{itemize}
-\item If the stream $o$ is done, execution of $s$ is complete.
+\item If the stream $o$ is done, execution of $s$ completes normally.
\end{itemize}
@@ -6483,7 +6602,7 @@ The assert statement has no effect in production mode. In checked mode, executio
\LMHash{}
The expression $e$ is evaluated to an object $o$. If the class of $o$ is a subtype of \code{Function} then let $r$ be the result of invoking $o$ with no arguments. Otherwise, let $r$ be $o$.
-It is a dynamic type error if $o$ is not of type \code{bool} or of type \code{Function}, or if $r$ is not of type \code{bool}. If $r$ is \FALSE{}, we say that the assertion failed. If $r$ is \TRUE{}, we say that the assertion succeeded. If the assertion succeeded, execution of the assert statement is complete. If the assertion failed, an \code{AssertionError} is thrown.
+It is a dynamic type error if $o$ is not of type \code{bool} or of type \code{Function}, or if $r$ is not of type \code{bool}. If $r$ is \FALSE{}, we say that the assertion failed. If $r$ is \TRUE{}, we say that the assertion succeeded. If the assertion succeeded, execution of the assert statement is complete. If the assertion failed, the execution throws (\ref{completion}) an \code{AssertionError} with a stack trace corresponding to the current execution state at the \ASSERT{} statement.
%\Q{Might be cleaner to define it as \code{if (!$e$) \{\THROW{} \NEW{} AssertionError();\}} (in checked mode only).
%What about an error message as part of the assert?}
@@ -6650,7 +6769,7 @@ It is a static warning if the specified URI of a deferred import does not refer
The {\em current library} is the library currently being compiled. The import modifies the namespace of the current library in a manner that is determined by the imported library and by the optional elements of the import.
\LMHash{}
-An immediate import directive $I$ may optionally include a prefix clause of the form \AS{} \code{Id} used to prefix names imported by $I$. A deferred import must include a prefix clause or a compile time error occurs. It is a compile-time error if a prefix used in a deferred import is used in another import clause.
+An immediate import directive $I$ may optionally include a prefix clause of the form \code{\AS{} $id$} used to prefix names imported by $I$. A deferred import must include a prefix clause or a compile time error occurs. It is a compile-time error if a prefix used in a deferred import is used in another import clause.
\LMHash{}
An import directive $I$ may optionally include a namespace combinator clauses used to restrict the set of names imported by $I$. Currently, two namespace combinators are supported: \HIDE{} and \SHOW{}.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698