Skip to content

Commit e7babb2

Browse files
committed
WIP
1 parent 3606b7b commit e7babb2

File tree

95 files changed

+2318
-22
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+2318
-22
lines changed

analysis/examples/larger-project/src/res_printer.res

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ let convertBsExternalAttribute = x =>
2828
| "bs.ignore" => "ignore"
2929
| "bs.inline" => "inline"
3030
| "bs.int" => "int"
31-
| "bs.meth" => "meth"
3231
| "bs.module" => "module"
3332
| "bs.new" => "new"
3433
| "bs.obj" => "obj"

analysis/src/CompletionDecorators.ml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,6 @@ could potentially raise.
117117

118118
Hint: Did you know you can run an interactive code analysis in your project by running the command `> ReScript: Start Code Analyzer`? Try it!|};
119119
] );
120-
( "meth",
121-
None,
122-
[
123-
{|The `@meth` decorator is used to call a function on a JavaScript object, and avoid issues with currying.
124-
125-
[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#meth-decorator).|};
126-
] );
127120
( "module",
128121
Some "module(\"$0\")",
129122
[

breadcrumb.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# ReScript Parser Breadcrumbs
2+
3+
## What are Breadcrumbs?
4+
5+
Breadcrumbs are a **parsing context tracking mechanism** that helps provide better error messages by keeping track of what grammatical constructs the parser is currently inside.
6+
7+
## How they work:
8+
9+
### 1. **Data Structure**
10+
```ocaml
11+
mutable breadcrumbs: (Grammar.t * Lexing.position) list;
12+
```
13+
- A list of tuples containing:
14+
- `Grammar.t`: The type of grammar construct (like `AtomicTypExpr`, `ExprOperand`, etc.)
15+
- `Lexing.position`: Where this construct started in the source code
16+
17+
### 2. **Stack-based tracking**
18+
- **`leave_breadcrumb p circumstance`** (line 142): Pushes a new context onto the stack
19+
- **`eat_breadcrumb p`** (line 146): Pops the top context off the stack
20+
21+
### 3. **Usage Pattern**
22+
```ocaml
23+
(* When entering a parsing function *)
24+
Parser.leave_breadcrumb p Grammar.AtomicTypExpr;
25+
(* ... parse the construct ... *)
26+
Parser.eat_breadcrumb p; (* When exiting *)
27+
```
28+
29+
## How they improve error messages:
30+
31+
### 1. **Contextual error reporting**
32+
In `res_diagnostics.ml` lines 80-104, breadcrumbs are used to generate context-specific error messages:
33+
34+
```ocaml
35+
| (AtomicTypExpr, _) :: breadcrumbs ->
36+
(* We're inside a type expression *)
37+
"I'm missing a type here"
38+
39+
| (ExprOperand, _) :: breadcrumbs ->
40+
(* We're inside an expression operand *)
41+
"Did you forget to write an expression here?"
42+
```
43+
44+
### 2. **Grammar-aware recovery**
45+
In `Recover.should_abort_list_parse` (line 46), breadcrumbs help determine if parsing should abort:
46+
- Checks if current token makes sense in the context of outer grammatical constructs
47+
- Prevents infinite loops in error recovery
48+
49+
### 3. **Nested context awareness**
50+
The stack nature allows checking multiple levels:
51+
```ocaml
52+
| (ExprBlock, _) :: _, Rbrace ->
53+
"It seems that this expression block is empty"
54+
| (ExprArrayMutation, _) :: _, _ ->
55+
"Seems that an expression is missing, with what do I mutate the array?"
56+
```
57+
58+
## Example in `parse_atomic_typ_expr`:
59+
60+
```ocaml
61+
Parser.leave_breadcrumb p Grammar.AtomicTypExpr; (* Push context *)
62+
let typ = (* parse the type *) in
63+
Parser.eat_breadcrumb p; (* Pop context *)
64+
```
65+
66+
If an error occurs while parsing the type, the error reporting can see:
67+
- "We're currently in an `AtomicTypExpr`"
68+
- "The outer context might be a record field, function parameter, etc."
69+
- Generate appropriate error message like "I'm missing a type here"
70+
71+
## Benefits:
72+
73+
1. **Better error messages**: Instead of generic "unexpected token", users get contextual hints
74+
2. **Error recovery**: Helps parser decide how to recover from errors
75+
3. **Debugging**: Provides parsing context for diagnostics
76+
4. **User experience**: Makes compiler errors more helpful and actionable
77+
78+
The breadcrumb system is essentially a **parsing call stack** that enables sophisticated error reporting and recovery in the ReScript parser.

compiler/frontend/ast_attributes.ml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,13 @@ let process_method_attributes_rev (attrs : t) =
7474
({st with set = Some result}, acc)
7575
| _ -> (st, attr :: acc))
7676

77-
type attr_kind = Nothing | Meth_callback of attr | Method of attr
77+
type attr_kind = Nothing | Meth_callback of attr
7878

7979
let process_attributes_rev (attrs : t) : attr_kind * t =
8080
Ext_list.fold_left attrs (Nothing, [])
81-
(fun (st, acc) (({txt; loc}, _) as attr) ->
81+
(fun (st, acc) (({txt}, _) as attr) ->
8282
match (txt, st) with
8383
| "this", (Nothing | Meth_callback _) -> (Meth_callback attr, acc)
84-
| "meth", (Nothing | Method _) -> (Method attr, acc)
85-
| "this", _ -> Bs_syntaxerr.err loc Conflict_bs_bs_this_bs_meth
8684
| _, _ -> (st, attr :: acc))
8785

8886
let external_attrs =

compiler/frontend/ast_attributes.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type ('a, 'b) st = {get: 'a option; set: 'b option}
2929

3030
val process_method_attributes_rev : t -> (bool * bool, [`Get | `No_get]) st * t
3131

32-
type attr_kind = Nothing | Meth_callback of attr | Method of attr
32+
type attr_kind = Nothing | Meth_callback of attr
3333

3434
val process_attributes_rev : t -> attr_kind * t
3535

compiler/frontend/ast_core_type_class_type.ml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ let typ_mapper (self : Bs_ast_mapper.mapper) (ty : Parsetree.core_type) =
7575
match fst (Ast_attributes.process_attributes_rev ty.ptyp_attributes) with
7676
| Meth_callback _ ->
7777
Ast_typ_uncurry.to_method_callback_type loc self ~arity ty
78-
| Method _ -> Bs_ast_mapper.default_mapper.typ self ty
7978
| Nothing -> Bs_ast_mapper.default_mapper.typ self ty)
8079
| Ptyp_object (methods, closed_flag) ->
8180
let ( +> ) attr (typ : Parsetree.core_type) =
@@ -90,8 +89,6 @@ let typ_mapper (self : Bs_ast_mapper.mapper) (ty : Parsetree.core_type) =
9089
let attrs, core_type =
9190
match Ast_attributes.process_attributes_rev attrs with
9291
| Nothing, attrs -> (attrs, ty) (* #1678 *)
93-
| Method _, _ ->
94-
Location.raise_errorf ~loc "%@get/set conflicts with %@meth"
9592
| Meth_callback attr, attrs -> (attrs, attr +> ty)
9693
in
9794
Ast_compatible.object_field name attrs (self.typ self core_type)
@@ -100,8 +97,6 @@ let typ_mapper (self : Bs_ast_mapper.mapper) (ty : Parsetree.core_type) =
10097
let attrs, core_type =
10198
match Ast_attributes.process_attributes_rev attrs with
10299
| Nothing, attrs -> (attrs, ty)
103-
| Method _, _ ->
104-
Location.raise_errorf ~loc "%@get/set conflicts with %@meth"
105100
| Meth_callback attr, attrs -> (attrs, attr +> ty)
106101
in
107102
Ast_compatible.object_field name attrs
@@ -113,7 +108,6 @@ let typ_mapper (self : Bs_ast_mapper.mapper) (ty : Parsetree.core_type) =
113108
let attrs, core_type =
114109
match Ast_attributes.process_attributes_rev ptyp_attrs with
115110
| Nothing, attrs -> (attrs, ty)
116-
| Method attr, attrs -> (attrs, attr +> ty)
117111
| Meth_callback attr, attrs -> (attrs, attr +> ty)
118112
in
119113
Ast_compatible.object_field label attrs (self.typ self core_type)

compiler/frontend/bs_builtin_ppx.ml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,6 @@ let expr_mapper ~async_context ~in_function_def (self : mapper)
102102
async_context := (old_in_function_def && !async_context) || async;
103103
in_function_def := true;
104104
Ast_async.make_function_async ~async (default_expr_mapper self e)
105-
| Method _, _ ->
106-
Location.raise_errorf ~loc:e.pexp_loc
107-
"%@meth is not supported in function expression"
108105
| Meth_callback _, pexp_attributes ->
109106
(* FIXME: does it make sense to have a label for [this] ? *)
110107
async_context := false;

lib/bs/build.ninja

Whitespace-only changes.

lib/rescript.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
75521

tests/gentype_tests/typescript-react-example/src/AutoAnnotate.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)