-
Notifications
You must be signed in to change notification settings - Fork 471
fix JS regex literal parsing in char classes #7790
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
f2d3e4c
fe5e0f9
88efa86
16412d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -580,9 +580,53 @@ let scan_regex scanner = | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bring_buf_up_to_date ~start_offset:last_char_offset; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Buffer.contents buf) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let rec scan () = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(* Look ahead from a given absolute offset to see if a valid class closer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
exists on the same line. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Semantics: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- Applies BOS rules: an initial '^' does not count as content; the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
very first ']' after '[' or after '[^' is treated as literal. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- Skips escaped characters (\\.) while scanning. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- Returns true only if a subsequent unescaped ']' (after some content) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
is found before a line break or EOF. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let has_valid_class_closer_ahead ~from_offset = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let src = scanner.src in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let len = String.length src in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let i = ref (from_offset + 1) in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(* start scanning after current '[' *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let bos = ref true in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let rec loop () = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if !i >= len then false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
match String.unsafe_get src !i with | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| '\n' | '\r' -> false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| '\\' -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if !i + 1 < len then ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
i := !i + 2; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
loop ()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| '^' when !bos -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
incr i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
loop () | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ']' when !bos -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(* Leading ']' is literal content; after that, we're no longer at BOS. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bos := false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
incr i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
loop () | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ']' -> true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _ -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bos := false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
incr i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
loop () | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
loop () | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
in | |
(* Validate that from_offset points to '[' *) | |
if from_offset < 0 || from_offset >= len || String.unsafe_get src from_offset <> '[' then | |
false | |
else | |
let i = ref (from_offset + 1) in | |
(* start scanning after current '[' *) | |
let bos = ref true in | |
let rec loop () = | |
if !i >= len then false | |
else | |
match String.unsafe_get src !i with | |
| '\n' | '\r' -> false | |
| '\\' -> | |
if !i + 1 < len then ( | |
i := !i + 2; | |
loop ()) | |
else false | |
| '^' when !bos -> | |
incr i; | |
loop () | |
| ']' when !bos -> | |
(* Leading ']' is literal content; after that, we're no longer at BOS. *) | |
bos := false; | |
incr i; | |
loop () | |
| ']' -> true | |
| _ -> | |
bos := false; | |
incr i; | |
loop () | |
in | |
loop () |
Copilot uses AI. Check for mistakes.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -607,3 +607,16 @@ let re = /^((a)c)?(ab)$/ | |
let re = /^([ab]*?)(?=(b)?)c/ | ||
let re = /^([ab]*?)(?!(b))c/ | ||
let re = /^([ab]*?)(?<!(a))c/ | ||
|
||
let re = /\.[^/.]+$/ | ||
|
||
// Leading ']' is literal; '/' inside class must not terminate | ||
let re = /[]/]/ | ||
let re = /[^]]/ | ||
let re = /[/]/ | ||
|
||
// Additional leading ']' edge cases | ||
let re = /[]]/ | ||
let re = /[\]]/ | ||
let re = /[[]]/ | ||
let re = /[^]/]/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using
String.unsafe_get
can lead to bounds checking violations. Consider usingString.get
instead, or ensure proper bounds checking is performed before this call.Copilot uses AI. Check for mistakes.