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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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"))))