Skip to content

Commit

Permalink
parser: add parse-only support for "import.meta"
Browse files Browse the repository at this point in the history
Summary:
Resolves facebook#6913. As with `new.target`, we can parse the expression, but
we fail to typecheck it. Clients can use a suppression comment to ignore
uses of `import.meta` in an otherwise valid file.

The parse error message on inputs like `import.notMeta` was chosen to be
consistent with the message emitted by Babylon.

Test Plan:
Unit tests added, and all existing tests pass.

wchargin-branch: parse-import-meta
  • Loading branch information
wchargin committed Oct 2, 2018
1 parent a57bf20 commit b8cb2c0
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 5 deletions.
39 changes: 35 additions & 4 deletions src/parser/expression_parser.ml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ module Expression
let is_assignable_lhs = Expression.(function
| _, MetaProperty { MetaProperty.meta = (_, "new"); property = (_, "target") }
-> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *)
| _, MetaProperty { MetaProperty.meta = (_, "import"); property = (_, "meta") }
-> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *)
(* draft spec: https://tc39.github.io/proposal-import-meta/ *)

| _, Array _
| _, Identifier _
Expand Down Expand Up @@ -193,6 +196,9 @@ module Expression
and is_lhs = Expression.(function
| _, MetaProperty { MetaProperty.meta = (_, "new"); property = (_, "target") }
-> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *)
| _, MetaProperty { MetaProperty.meta = (_, "import"); property = (_, "meta") }
-> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *)
(* draft spec: https://tc39.github.io/proposal-import-meta/ *)

| _, Identifier _
| _, Member _
Expand Down Expand Up @@ -534,11 +540,36 @@ module Expression
super

and import env = with_loc (fun env ->
let start_loc = Peek.loc env in
Expect.token env T_IMPORT;
Expect.token env T_LPAREN;
let arg = assignment (with_no_in false env) in
Expect.token env T_RPAREN;
Expression.Import arg
match Peek.token env with
| T_LPAREN ->
(* "import(...)" syntax *)
Eat.token env;
let arg = assignment (with_no_in false env) in
Expect.token env T_RPAREN;
Expression.Import arg
| T_PERIOD -> begin
(* "import.meta" syntax (no other metaproperties are permitted) *)
Eat.token env;
match Peek.token env with
| T_IDENTIFIER { raw = "meta"; _ } ->
Eat.token env;
let end_loc = Peek.loc env in
Expression.(MetaProperty MetaProperty.({
meta = start_loc, "import";
property = end_loc, "meta";
}))
| T_IDENTIFIER _ ->
error_at env (start_loc, Parse_error.InvalidImportMetaProperty);
Expression.Identifier (start_loc, "import")
| _ ->
error_unexpected env;
Expression.Identifier (start_loc, "import")
end
| _ ->
error_unexpected env;
Expression.Identifier (start_loc, "import")
) env

and call_cover ?(allow_optional_chain=true) ?(in_optional_chain=false) env start_loc left =
Expand Down
2 changes: 2 additions & 0 deletions src/parser/parse_error.ml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type t =
| InvalidLHSInExponentiation
| InvalidLHSInForIn
| InvalidLHSInForOf
| InvalidImportMetaProperty
| ExpectedPatternFoundExpression
| MultipleDefaultsInSwitch
| NoCatchOrFinally
Expand Down Expand Up @@ -154,6 +155,7 @@ module PP =
| InvalidLHSInExponentiation -> "Invalid left-hand side in exponentiation expression"
| InvalidLHSInForIn -> "Invalid left-hand side in for-in"
| InvalidLHSInForOf -> "Invalid left-hand side in for-of"
| InvalidImportMetaProperty -> "The only valid meta property for import is import.meta"
| ExpectedPatternFoundExpression -> (
"Expected an object pattern, array pattern, or an identifier but " ^
"found an expression instead"
Expand Down
2 changes: 1 addition & 1 deletion src/parser/parser_flow.ml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ module rec Parse : PARSER = struct
| T_IMPORT ->
error_on_decorators env decorators;
let statement = match Peek.ith_token ~i:1 env with
| T_LPAREN -> Statement.expression env
| T_LPAREN | T_PERIOD -> Statement.expression env
| _ -> Statement.import_declaration env in
statement
| T_DECLARE when Peek.ith_token ~i:1 env = T_EXPORT ->
Expand Down
3 changes: 3 additions & 0 deletions tests/import_meta/.flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[options]
module.system=haste
no_flowlib=false
42 changes: 42 additions & 0 deletions tests/import_meta/import_meta.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Error ----------------------------------------------------------------------------------------------- import_meta.js:9:1

Not supported.

9| import.meta;
^^^^^^^^^^^


Error ---------------------------------------------------------------------------------------------- import_meta.js:12:1

Not supported.

12| import.meta.hello = "world";
^^^^^^^^^^^


Error --------------------------------------------------------------------------------------------- import_meta.js:15:14

Not supported.

15| const meta = import.meta;
^^^^^^^^^^^


Error ---------------------------------------------------------------------------------- no_assign_to_import_meta.js:4:1

Invalid left-hand side in assignment

4| import.meta = {wat: "wat"}; // parse error
^^^^^^^^^^^


Error ----------------------------------------------------------------------------------- no_other_metaproperties.js:4:1

The only valid meta property for import is import.meta

4| import.atem; // parse error
^^^^^^



Found 5 errors
22 changes: 22 additions & 0 deletions tests/import_meta/import_meta.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @flow

// NOTE: The following tests all currently yield a "Not supported."
// error because Flow does not process MetaProperty expressions at all.
// The comments above each test case describe what the behavior _should_
// be once typechecking is implemented.

// You can access `import.meta` at the root of the module.
import.meta;

// You can write to `import.meta` at the root of the module.
import.meta.hello = "world";

// You can use `import.meta` in a normal expression context.
const meta = import.meta;

// All properties are `mixed`.
(meta.whatever: mixed);
(meta.whatnever: number); // error

// Properties are writable.
meta.writeable = "definitely";
4 changes: 4 additions & 0 deletions tests/import_meta/no_assign_to_import_meta.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// @flow

// You can't assign to it.
import.meta = {wat: "wat"}; // parse error
4 changes: 4 additions & 0 deletions tests/import_meta/no_other_metaproperties.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// @flow

// You can't access any other metaproperties on `import`.
import.atem; // parse error

0 comments on commit b8cb2c0

Please sign in to comment.