Skip to content

Commit 4ca0dcb

Browse files
committed
handle exotic ident properly
1 parent 89f2cb1 commit 4ca0dcb

File tree

11 files changed

+99
-23
lines changed

11 files changed

+99
-23
lines changed

jscomp/ext/ext_ident.ml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,15 @@ let [@inline] no_escape (c : char) =
132132
| '0' .. '9' | '_' | '$' -> true
133133
| _ -> false
134134

135+
let is_exotic name =
136+
match String.unsafe_get name 0 with
137+
| '\\' -> true
138+
| _ -> false
139+
140+
let unwrap_exotic name =
141+
let len = String.length name in
142+
String.sub name 2 (len - 3)
143+
135144
exception Not_normal_letter of int
136145
let name_mangle name =
137146
let len = String.length name in
@@ -157,14 +166,18 @@ let name_mangle name =
157166
Ext_ident.convert "^";;
158167
- : string = "$caret"
159168
]}
160-
[convert name] if [name] is a js keyword,add "$$"
169+
[convert name] if [name] is a js keyword, and also is not explicitly used as exotic identifier, add "$$"
161170
otherwise do the name mangling to make sure ocaml identifier it is
162171
a valid js identifier
163172
*)
164173
let convert (name : string) =
165-
if Js_reserved_map.is_reserved name then
166-
"$$" ^ name
167-
else name_mangle name
174+
if is_exotic name then
175+
let name = unwrap_exotic name in
176+
name_mangle name
177+
else
178+
if Js_reserved_map.is_reserved name then
179+
"$$" ^ name
180+
else name_mangle name
168181

169182
(** keyword could be used in property *)
170183

jscomp/ext/ext_ident.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ val create_tmp : ?name:string -> unit -> Ident.t
4848

4949
val make_unused : unit -> Ident.t
5050

51+
val is_exotic : string -> bool
5152

53+
val unwrap_exotic : string -> string
5254

5355
(**
5456
Invariant: if name is not converted, the reference should be equal

jscomp/frontend/ast_external_process.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,10 @@ let parse_external_attributes (no_arguments : bool) (prim_name_check : string)
316316
| Pexp_constant (Pconst_string (s, _)) -> (
317317
match l.txt with
318318
| Longident.Lident "type_" -> Some ("type", s)
319-
| Longident.Lident txt -> Some (txt, s)
319+
| Longident.Lident name when Ext_ident.is_exotic name
320+
->
321+
Some (Ext_ident.unwrap_exotic name, s)
322+
| Longident.Lident name -> Some (name, s)
320323
| _ ->
321324
Location.raise_errorf ~loc:exp.pexp_loc
322325
"Field must be a regular key.")

jscomp/stdlib-406/release.ninja

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ o stdlib-406/pervasives.cmj : cc_cmi stdlib-406/pervasives.res | stdlib-406/perv
1212
bsc_flags = $bsc_flags -nopervasives
1313
o stdlib-406/pervasives.cmi : cc stdlib-406/pervasives.resi | $bsc others
1414
bsc_flags = $bsc_flags -nopervasives
15-
o stdlib-406/arg.cmj : cc_cmi stdlib-406/arg.res | stdlib-406/arg.cmi stdlib-406/array.cmj stdlib-406/buffer.cmj stdlib-406/list.cmj stdlib-406/string.cmj stdlib-406/sys.cmj $bsc others
15+
o stdlib-406/arg.cmj : cc_cmi stdlib-406/arg.res | stdlib-406/arg.cmi stdlib-406/array.cmj stdlib-406/buffer.cmj stdlib-406/list.cmj stdlib-406/set.cmj stdlib-406/string.cmj stdlib-406/sys.cmj $bsc others
1616
o stdlib-406/arg.cmi : cc stdlib-406/arg.resi | stdlib-406/pervasives.cmj $bsc others
1717
o stdlib-406/array.cmj : cc_cmi stdlib-406/array.res | stdlib-406/array.cmi $bsc others
1818
o stdlib-406/array.cmi : cc stdlib-406/array.resi | stdlib-406/pervasives.cmj $bsc others

jscomp/syntax/src/res_scanner.ml

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -283,11 +283,10 @@ let scanNumber scanner =
283283
else Token.Int {i = literal; suffix}
284284

285285
let scanExoticIdentifier scanner =
286-
let buffer = Buffer.create 20 in
287286
let startPos = position scanner in
287+
let startOff = scanner.offset in
288288

289-
(* TODO: are we disregarding the current char...? Should be a quote *)
290-
next scanner;
289+
next2 scanner;
291290

292291
let rec scan () =
293292
match scanner.ch with
@@ -302,23 +301,29 @@ let scanExoticIdentifier scanner =
302301
let endPos = position scanner in
303302
scanner.err ~startPos ~endPos
304303
(Diagnostics.message "Did you forget a \" here?")
305-
| ch ->
306-
Buffer.add_char buffer ch;
304+
| _ ->
307305
next scanner;
308306
scan ()
309307
in
310308
scan ();
311309

312-
let ident = Buffer.contents buffer in
310+
let ident =
311+
(String.sub [@doesNotRaise]) scanner.src startOff (scanner.offset - startOff)
312+
in
313+
let name =
314+
(String.sub [@doesNotRaise]) scanner.src (startOff + 2)
315+
(scanner.offset - startOff - 3)
316+
in
317+
313318
let _ =
314-
if ident = "" then
319+
if name = String.empty then
315320
let endPos = position scanner in
316321
scanner.err ~startPos ~endPos
317322
(Diagnostics.message "A quoted identifier can't be empty string.")
318323
in
319324

320-
(* TODO: do we really need to create a new buffer instead of substring once? *)
321-
Token.Lident ident
325+
if Token.isInfixOperatorTxt name then Token.Lident name
326+
else Token.Lident ident
322327

323328
let scanStringEscapeSequence ~startPos scanner =
324329
let scan ~n ~base ~max =
@@ -756,9 +761,7 @@ let rec scan scanner =
756761
| _ ->
757762
next scanner;
758763
Token.Colon)
759-
| '\\' ->
760-
next scanner;
761-
scanExoticIdentifier scanner
764+
| '\\' -> scanExoticIdentifier scanner
762765
| '/' -> (
763766
match peek scanner with
764767
| '/' ->

jscomp/syntax/src/res_token.ml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,4 +257,38 @@ let isKeywordTxt str =
257257
true
258258
with Not_found -> false
259259

260+
let infixOperatorTable = function
261+
| "==" -> EqualEqual
262+
| "===" -> EqualEqualEqual
263+
| "-" -> Minus
264+
| "-." -> MinusDot
265+
| "+" -> Plus
266+
| "+." -> PlusDot
267+
| "++" -> PlusPlus
268+
| "/" -> Forwardslash
269+
| "/." -> ForwardslashDot
270+
| ">" -> GreaterThan
271+
| "<" -> LessThan
272+
| "*" -> Asterisk
273+
| "*." -> AsteriskDot
274+
| "**" -> Exponentiation
275+
| "||" -> Lor
276+
| "&&" -> Land
277+
| "!=" -> BangEqual
278+
| "!==" -> BangEqualEqual
279+
| ">=" -> GreaterEqual
280+
| "<=" -> LessEqual
281+
| _ -> raise Not_found
282+
[@@raises Not_found]
283+
284+
let isInfixOperatorTxt str =
285+
match str with
286+
| "=" | "<>" | "^" | "~-" | "~-." | ":=" | "|." | "|.u" | "|>" ->
287+
true (* Allow internally aliases to OCaml ones *)
288+
| _ -> (
289+
try
290+
let _ = infixOperatorTable str in
291+
true
292+
with Not_found -> false)
293+
260294
let catch = Lident "catch"

jscomp/test/build.ninja

Lines changed: 2 additions & 1 deletion
Large diffs are not rendered by default.

jscomp/test/exotic_labels_test.js

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

jscomp/test/exotic_labels_test.res

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
type \"Type1"
2+
3+
type \"Type2" = string
4+
5+
type \"Type3" = \"Type1"
6+
7+
type \"Type4" = {
8+
field: string,
9+
}
10+
let fn1 = v => v.field

jscomp/test/export_keyword.js

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

jscomp/test/key_word_property2.js

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

0 commit comments

Comments
 (0)