Skip to content

Commit b3e1096

Browse files
committed
Do not fail on invalid numeric escape sequences in ECMAScript mode
1 parent 3ab0363 commit b3e1096

File tree

2 files changed

+50
-5
lines changed

2 files changed

+50
-5
lines changed

regexp_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,43 @@ func TestECMAOctal(t *testing.T) {
740740

741741
}
742742

743+
func TestECMAInvalidEscape(t *testing.T) {
744+
re := MustCompile(`\x0`, ECMAScript)
745+
if m, err := re.MatchString("x0"); err != nil {
746+
t.Fatal(err)
747+
} else if !m {
748+
t.Fatal("Expected match")
749+
}
750+
751+
re = MustCompile(`\x0z`, ECMAScript)
752+
if m, err := re.MatchString("x0z"); err != nil {
753+
t.Fatal(err)
754+
} else if !m {
755+
t.Fatal("Expected match")
756+
}
757+
}
758+
759+
func TestECMAInvalidEscapeCharClass(t *testing.T) {
760+
re := MustCompile(`[\x0]`, ECMAScript)
761+
if m, err := re.MatchString("x"); err != nil {
762+
t.Fatal(err)
763+
} else if !m {
764+
t.Fatal("Expected match")
765+
}
766+
767+
if m, err := re.MatchString("0"); err != nil {
768+
t.Fatal(err)
769+
} else if !m {
770+
t.Fatal("Expected match")
771+
}
772+
773+
if m, err := re.MatchString("z"); err != nil {
774+
t.Fatal(err)
775+
} else if m {
776+
t.Fatal("Expected no match")
777+
}
778+
}
779+
743780
func TestNegateRange(t *testing.T) {
744781
re := MustCompile(`[\D]`, 0)
745782
if m, err := re.MatchString("A"); err != nil {

syntax/parser.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,7 @@ func (p *parser) scanOptions() {
16481648
}
16491649

16501650
// Scans \ code for escape codes that map to single unicode chars.
1651-
func (p *parser) scanCharEscape() (rune, error) {
1651+
func (p *parser) scanCharEscape() (r rune, err error) {
16521652

16531653
ch := p.moveRightGetChar()
16541654

@@ -1657,16 +1657,19 @@ func (p *parser) scanCharEscape() (rune, error) {
16571657
return p.scanOctal(), nil
16581658
}
16591659

1660+
pos := p.textpos()
1661+
16601662
switch ch {
16611663
case 'x':
16621664
// support for \x{HEX} syntax from Perl and PCRE
16631665
if p.charsRight() > 0 && p.rightChar(0) == '{' {
16641666
p.moveRight(1)
1665-
return p.scanHexUntilBrace()
1667+
r, err = p.scanHexUntilBrace()
1668+
} else {
1669+
r, err = p.scanHex(2)
16661670
}
1667-
return p.scanHex(2)
16681671
case 'u':
1669-
return p.scanHex(4)
1672+
r, err = p.scanHex(4)
16701673
case 'a':
16711674
return '\u0007', nil
16721675
case 'b':
@@ -1684,13 +1687,18 @@ func (p *parser) scanCharEscape() (rune, error) {
16841687
case 'v':
16851688
return '\u000B', nil
16861689
case 'c':
1687-
return p.scanControl()
1690+
r, err = p.scanControl()
16881691
default:
16891692
if !p.useOptionE() && IsWordChar(ch) {
16901693
return 0, p.getErr(ErrUnrecognizedEscape, string(ch))
16911694
}
16921695
return ch, nil
16931696
}
1697+
if err != nil && p.useOptionE() {
1698+
p.textto(pos)
1699+
return ch, nil
1700+
}
1701+
return
16941702
}
16951703

16961704
// Grabs and converts an ascii control character

0 commit comments

Comments
 (0)