Skip to content

Commit

Permalink
ES6 Generators
Browse files Browse the repository at this point in the history
Summary: Generators are iterable. Each value yielded from the generator function
is iterated.

Generators are iterators. Values can be passed in through the `next`
method. The iterator result values will be either a) the yielded values,
b) the value returned from the generator (the completion value) or c)
`undefined`, if `next` is called after completion.

Generators can delegate to other iterables, including other generators.
Values passed to `next` on the delegator generator will be passed
through to the delegatee. Similarly, values yielded by the delegatee
will be returned along the iterable/iterator interfaces.

The "delegate yield" expression, `yield *`, returns the completion value
of the delegatee.

While normal functions' return type is the type of the `return`
statement, generators are different. The return type is always a
Generator, where the second type argument is the type of the `return`
statement.

We use the same process to infer this type--an
Closes #534

Reviewed By: @jeffmo

Differential Revision: D2416847

Pulled By: @gabelevi
  • Loading branch information
samwgoldman authored and facebook-github-bot-8 committed Sep 8, 2015
1 parent 4912896 commit f49a11e
Show file tree
Hide file tree
Showing 16 changed files with 503 additions and 79 deletions.
18 changes: 13 additions & 5 deletions lib/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,13 +300,21 @@ interface IteratorResult<T> {
value?: T;
}

interface Iterator<T> {
next(): IteratorResult<T>;
@@iterator(): Iterator<T>;
interface $Iterator<Yield,Return,Next> {
@@iterator(): $Iterator<Yield,Return,Next>;
next(value?: Next): IteratorResult<Yield|Return>;
}
type Iterator<T> = $Iterator<T,void,void>;

interface Iterable<T> {
@@iterator(): Iterator<T>;
interface $Iterable<Yield,Return,Next> {
@@iterator(): $Iterator<Yield,Return,Next>;
}
type Iterable<T> = $Iterable<T,void,void>;

/* Generators */
interface Generator<Yield,Return,Next> {
@@iterator(): $Iterator<Yield,Return,Next>;
next(value?: Next): IteratorResult<Yield|Return>;
}

/* Maps and Sets */
Expand Down
15 changes: 8 additions & 7 deletions src/typing/constraint_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,8 @@ module Scope = struct
(* a var scope corresponds to a runtime activation,
e.g. a function. *)
type var_scope_attrs = {
async: bool
async: bool;
generator: bool
}

(* var and lexical scopes differ in hoisting behavior
Expand Down Expand Up @@ -836,11 +837,10 @@ module Scope = struct
refis = KeyMap.empty;
}

(* return a fresh scope of the most common kind (var, non-async) *)
let fresh () = fresh_impl (VarScope { async = false })

(* return a fresh async var scope *)
let fresh_async () = fresh_impl (VarScope { async = true })
(* return a fresh scope of the most common kind (var) *)
let fresh ?(async=false) ?(generator=false) () =
assert (not (async && generator));
fresh_impl (VarScope { async; generator })

(* return a fresh lexical scope *)
let fresh_lex () = fresh_impl LexScope
Expand Down Expand Up @@ -2520,7 +2520,8 @@ let string_of_scope = Scope.(
in

let string_of_scope_kind = function
| VarScope attrs -> spf "VarScope { async: %b }" attrs.async
| VarScope { async; generator } ->
spf "VarScope { async: %b; generator: %b }" async generator
| LexScope -> "Lex"
in

Expand Down
6 changes: 3 additions & 3 deletions src/typing/constraint_js.mli
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ module Scope: sig
= Key.t

type var_scope_attrs = {
async: bool
async: bool;
generator: bool
}

type kind =
Expand All @@ -361,8 +362,7 @@ module Scope: sig
mutable refis: refi_binding KeyMap.t
}

val fresh: unit -> t
val fresh_async: unit -> t
val fresh: ?async:bool -> ?generator:bool -> unit -> t
val fresh_lex: unit -> t
val clone: t -> t

Expand Down
8 changes: 7 additions & 1 deletion src/typing/env_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,13 @@ let clone_scopes scopes =
(* TODO will need to walk once LexScopes appear *)
let in_async_scope () = Scope.(
match (peek_scope ()).kind with
| VarScope { async } -> async
| VarScope { async; _ } -> async
| _ -> false
)

let in_generator_scope () = Scope.(
match (peek_scope ()).kind with
| VarScope { generator; _ } -> generator
| _ -> false
)

Expand Down
1 change: 1 addition & 0 deletions src/typing/env_js.mli
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ val get_scopes: unit -> Scope.t list
val clone_scopes: Scope.t list -> Scope.t list

val in_async_scope: unit -> bool
val in_generator_scope: unit -> bool

val all_entries: unit -> Entry.t SMap.t

Expand Down
Loading

0 comments on commit f49a11e

Please sign in to comment.