Source file reason_parser_explain.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
open Reason_string
module Parser = Reason_parser
module Interp = Parser.MenhirInterpreter
module Raw = Reason_parser_explain_raw
let identlike_keywords =
let reverse_table = lazy (
let table = Hashtbl.create 7 in
let flip_add k v = Hashtbl.add table v k in
Hashtbl.iter flip_add Reason_declarative_lexer.keyword_table;
table
) in
function
| Parser.SIG -> Some "sig"
| Parser.MODULE -> Some "module"
| Parser.BEGIN -> Some "begin"
| Parser.END -> Some "end"
| Parser.OBJECT -> Some "object"
| Parser.SWITCH -> Some "switch"
| Parser.TO -> Some "to"
| Parser.THEN -> Some "then"
| Parser.TYPE -> Some "type"
| token ->
match Hashtbl.find (Lazy.force reverse_table) token with
| name -> Some name
| exception Not_found -> None
let keyword_confused_with_ident state token =
match identlike_keywords token with
| Some name when Raw.transitions_on_lident state
|| Raw.transitions_on_uident state ->
(name ^ " is a reserved keyword, it cannot be used as an identifier. Try `" ^ name ^ "_` or `_" ^ name ^ "` instead")
| _ -> raise Not_found
let uppercased_instead_of_lowercased state token =
match token with
| Parser.UIDENT name when Raw.transitions_on_lident state ->
let name = String.uncapitalize_ascii name in
if Hashtbl.mem Reason_declarative_lexer.keyword_table name then
"variables and labels should be lowercased"
else
Printf.sprintf "variables and labels should be lowercased. Try `%s'" name
| _ -> raise Not_found
let semicolon_might_be_missing state _token =
if Raw.transitions_on_semi state then
"syntax error, consider adding a `;' before"
else
raise Not_found
let token_specific_message = function
| Parser.UNDERSCORE ->
"underscore is not a valid identifier. Use _ only in pattern matching and partial function application"
| _ ->
raise Not_found
let unclosed_parenthesis is_opening_symbol closing_symbol check_function env =
let state = Interp.current_state_number env in
if check_function state then
let rec find_opening_location = function
| None -> None
| Some env ->
let found =
match Interp.top env with
| Some (Interp.Element (state, _, startp, endp))
when (is_opening_symbol (Interp.X (Interp.incoming_symbol state))) ->
Some (startp, endp)
| Some (Interp.Element (state, _, _, _))
when (Interp.X (Interp.incoming_symbol state) = closing_symbol) ->
raise Not_found
| _ -> None
in
match found with
| Some _ -> found
| _ -> find_opening_location (Interp.pop env)
in
try find_opening_location (Some env)
with Not_found -> None
else
None
let check_unclosed env =
let check (message, opening_symbols, closing_symbol, check_function) =
match
unclosed_parenthesis (fun x -> List.mem x opening_symbols)
closing_symbol check_function env
with
| None -> None
| Some (loc_start, _) ->
Some (Format.asprintf "Unclosed %S (opened line %d, column %d)"
message loc_start.pos_lnum
(loc_start.pos_cnum - loc_start.pos_bol))
in
let rec check_list = function
| [] -> raise Not_found
| x :: xs ->
match check x with
| None -> check_list xs
| Some result -> result
in
check_list [
("(", Interp.[X (T T_LPAREN)],
Interp.X (T T_RPAREN),
Raw.transitions_on_rparen);
("{", Interp.[X (T T_LBRACE); X (T T_LBRACELESS)],
Interp.X (T T_RBRACE),
Raw.transitions_on_rbrace);
("[", Interp.[ X (T T_LBRACKET); X (T T_LBRACKETAT);
X (T T_LBRACKETBAR); X (T T_LBRACKETGREATER);
X (T T_LBRACKETLESS); X (T T_LBRACKETPERCENT);
X (T T_LBRACKETPERCENTPERCENT); ],
Interp.X (T T_RBRACKET),
Raw.transitions_on_rbracket);
]
let message env (token, _, _) =
let state = Interp.current_state_number env in
try keyword_confused_with_ident state token
with Not_found ->
try check_unclosed env
with Not_found ->
try uppercased_instead_of_lowercased state token
with Not_found ->
try semicolon_might_be_missing state token
with Not_found ->
try token_specific_message token
with Not_found ->
"Syntax error"