Skip to content

Commit 42f32f4

Browse files
committed
handle exotic ident properly
1 parent 5f6278f commit 42f32f4

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
@@ -291,11 +291,10 @@ let scanNumber scanner =
291291
else Token.Int {i = literal; suffix}
292292

293293
let scanExoticIdentifier scanner =
294-
let buffer = Buffer.create 20 in
295294
let startPos = position scanner in
295+
let startOff = scanner.offset in
296296

297-
(* TODO: are we disregarding the current char...? Should be a quote *)
298-
next scanner;
297+
next2 scanner;
299298

300299
let rec scan () =
301300
match scanner.ch with
@@ -310,23 +309,29 @@ let scanExoticIdentifier scanner =
310309
let endPos = position scanner in
311310
scanner.err ~startPos ~endPos
312311
(Diagnostics.message "Did you forget a \" here?")
313-
| ch ->
314-
Buffer.add_char buffer ch;
312+
| _ ->
315313
next scanner;
316314
scan ()
317315
in
318316
scan ();
319317

320-
let ident = Buffer.contents buffer in
318+
let ident =
319+
(String.sub [@doesNotRaise]) scanner.src startOff (scanner.offset - startOff)
320+
in
321+
let name =
322+
(String.sub [@doesNotRaise]) scanner.src (startOff + 2)
323+
(scanner.offset - startOff - 3)
324+
in
325+
321326
let _ =
322-
if ident = "" then
327+
if name = String.empty then
323328
let endPos = position scanner in
324329
scanner.err ~startPos ~endPos
325330
(Diagnostics.message "A quoted identifier can't be empty string.")
326331
in
327332

328-
(* TODO: do we really need to create a new buffer instead of substring once? *)
329-
Token.Lident ident
333+
if Token.isInfixOperatorTxt name then Token.Lident name
334+
else Token.Lident ident
330335

331336
let scanStringEscapeSequence ~startPos scanner =
332337
let scan ~n ~base ~max =
@@ -764,9 +769,7 @@ let rec scan scanner =
764769
| _ ->
765770
next scanner;
766771
Token.Colon)
767-
| '\\' ->
768-
next scanner;
769-
scanExoticIdentifier scanner
772+
| '\\' -> scanExoticIdentifier scanner
770773
| '/' -> (
771774
match peek scanner with
772775
| '/' ->

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)