Skip to content

Commit d1647e3

Browse files
Report when error is missing in comma delimited regions. (rescript-lang#101)
When a comma is missing between nodes in a region and the current token looks like the start of something valid in the current region, we should report an error with regards to the missing comma. Example: type student<'extraInfo> = { name: string, age: int otherInfo: 'extraInfo } There is a missing comma between `int` and `otherInfo`. `otherInfo` looks like a valid start of the record declaration. We report the error here and then continue parsing the region. Fixes rescript-lang/syntax#100
1 parent 07b54cc commit d1647e3

File tree

6 files changed

+79
-3
lines changed

6 files changed

+79
-3
lines changed

syntax/src/res_core.ml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,21 @@ let parseCommaDelimitedRegion p ~grammar ~closing ~f =
904904
loop (node::nodes)
905905
| token when token = closing || token = Eof ->
906906
List.rev (node::nodes)
907+
| _ when Grammar.isListElement grammar p.token ->
908+
(* missing comma between nodes in the region and the current token
909+
* looks like the start of something valid in the current region.
910+
* Example:
911+
* type student<'extraInfo> = {
912+
* name: string,
913+
* age: int
914+
* otherInfo: 'extraInfo
915+
* }
916+
* There is a missing comma between `int` and `otherInfo`.
917+
* `otherInfo` looks like a valid start of the record declaration.
918+
* We report the error here and then continue parsing the region.
919+
*)
920+
Parser.expect Comma p;
921+
loop (node::nodes)
907922
| _ ->
908923
if not (p.token = Eof || p.token = closing || Recover.shouldAbortListParse p) then
909924
Parser.expect Comma p;
@@ -934,6 +949,21 @@ let parseCommaDelimitedReversedList p ~grammar ~closing ~f =
934949
loop (node::nodes)
935950
| token when token = closing || token = Eof ->
936951
(node::nodes)
952+
| _ when Grammar.isListElement grammar p.token ->
953+
(* missing comma between nodes in the region and the current token
954+
* looks like the start of something valid in the current region.
955+
* Example:
956+
* type student<'extraInfo> = {
957+
* name: string,
958+
* age: int
959+
* otherInfo: 'extraInfo
960+
* }
961+
* There is a missing comma between `int` and `otherInfo`.
962+
* `otherInfo` looks like a valid start of the record declaration.
963+
* We report the error here and then continue parsing the region.
964+
*)
965+
Parser.expect Comma p;
966+
loop (node::nodes)
937967
| _ ->
938968
if not (p.token = Eof || p.token = closing || Recover.shouldAbortListParse p) then
939969
Parser.expect Comma p;

syntax/tests/parsing/errors/other/__snapshots__/parse.spec.js.snap

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,42 @@ exports[`patternMatching.js 1`] = `
1414
Pattern matching needs at least one case
1515
1616
17+
========================================================"
18+
`;
19+
20+
exports[`regionMissingComma.res 1`] = `
21+
"=====Parsetree==========================================
22+
external make :
23+
?style:ReactDOMRe.Style.t -> ((?image:bool -> React.element)[@bs ]) =
24+
\\"ModalContent\\"
25+
type nonrec 'extraInfo student =
26+
{
27+
name: string ;
28+
age: int ;
29+
otherInfo: 'extraInfo }
30+
=====Errors=============================================
31+
32+
Syntax error!
33+
parsing/errors/other/regionMissingComma.res 2:31
34+
1external make: (
35+
2~style: ReactDOMRe.Style.t=?.
36+
3~image: bool=?,
37+
4 │ ) => React.element = \\"ModalContent\\"
38+
39+
Did you forget a \`,\` here?
40+
41+
Syntax error!
42+
parsing/errors/other/regionMissingComma.res 8:11-9:11
43+
6 │ type student<'extraInfo> = {
44+
7name: string,
45+
8age: int
46+
9otherInfo: 'extraInfo
47+
10}
48+
11 │
49+
50+
Did you forget a \`,\` here?
51+
52+
1753
========================================================"
1854
`;
1955
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
external make: (
2+
~style: ReactDOMRe.Style.t=?.
3+
~image: bool=?,
4+
) => React.element = "ModalContent"
5+
6+
type student<'extraInfo> = {
7+
name: string,
8+
age: int
9+
otherInfo: 'extraInfo
10+
}

syntax/tests/printer/comments/modExpr.res

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
// Pmod_functor
3636
/* c0 */ module /* c1 */ F /* c2 */ = /* before parameters */ (
3737
/* c3 */ A /* c4 */: /* c5 */ X /* c6 */,
38-
/* c7 */ B /* c8 */: /* c9 */ Y /* c 10 */
38+
/* c7 */ B /* c8 */: /* c9 */ Y /* c 10 */,
3939
/* c7 */ C /* c8 */: /* c9 */ Z /* c 10 */
4040
) => /* c11 */ ReturnMod /* c12 */
4141

syntax/tests/printer/expr/exoticIdent.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ let x = Extension.Type.\"type"
33

44
let \"+++" = (a, b) => a + b
55

6-
\"+++"(~a=\"let", \"module" ~\"type")
6+
\"+++"(~a=\"let", \"module", ~\"type")
77

88
switch \"type" {
99
| () => ()

syntax/tests/printer/ffi/import.res

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
@disableGc @disableJit
33
delimiter: string,
4-
cwd as currentWorkingDirectory : unit => string
4+
cwd as currentWorkingDirectory : unit => string,
55
isAbsolute: string => bool,
66
toNamespacedPath as \"ToNamespacedPath": string => string,
77
} from "path"

0 commit comments

Comments
 (0)