Skip to content

Commit eaa2a4d

Browse files
committed
\\ and \’ are escaped in single quote too
1 parent 8d799cf commit eaa2a4d

3 files changed

Lines changed: 29 additions & 11 deletions

File tree

ext/rbs_extension/rbs_extension.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* '\\n' => "\n"
1616
*
1717
* */
18-
void rbs_unescape_string(VALUE string);
18+
void rbs_unescape_string(VALUE string, bool dq_string);
1919

2020
/**
2121
* Receives `parserstate` and `range`, which represents a string token or symbol token, and returns a string VALUE.

ext/rbs_extension/unescape.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
#include "rbs_extension.h"
22

3-
static VALUE REGEXP = 0;
3+
static VALUE DQ_REGEXP = 0;
4+
static VALUE SQ_REGEXP = 0;
45
static VALUE HASH = 0;
56

6-
static const char *regexp_str = "\\\\[abefnrstv\"\\\\]";
7+
static const char *dq_regexp_str = "\\\\[abefnrstv\"\\\\]";
8+
static const char *sq_regexp_str = "\\\\[\'\\\\]";
79

810
static ID gsub = 0;
911

10-
void rbs_unescape_string(VALUE string) {
11-
if (!REGEXP) {
12-
REGEXP = rb_reg_new(regexp_str, strlen(regexp_str), 0);
13-
rb_global_variable(&REGEXP);
12+
void rbs_unescape_string(VALUE string, bool dq_string) {
13+
if (!DQ_REGEXP) {
14+
DQ_REGEXP = rb_reg_new(dq_regexp_str, strlen(dq_regexp_str), 0);
15+
rb_global_variable(&DQ_REGEXP);
16+
}
17+
18+
if (!SQ_REGEXP) {
19+
SQ_REGEXP = rb_reg_new(sq_regexp_str, strlen(sq_regexp_str), 0);
20+
rb_global_variable(&SQ_REGEXP);
1421
}
1522

1623
if (!gsub) {
@@ -30,10 +37,11 @@ void rbs_unescape_string(VALUE string) {
3037
rb_hash_aset(HASH, rb_str_new_literal("\\t"), rb_str_new_literal("\t"));
3138
rb_hash_aset(HASH, rb_str_new_literal("\\v"), rb_str_new_literal("\v"));
3239
rb_hash_aset(HASH, rb_str_new_literal("\\\""), rb_str_new_literal("\""));
40+
rb_hash_aset(HASH, rb_str_new_literal("\\\'"), rb_str_new_literal("'"));
3341
rb_hash_aset(HASH, rb_str_new_literal("\\\\"), rb_str_new_literal("\\"));
3442
}
3543

36-
rb_funcall(string, gsub, 2, REGEXP, HASH);
44+
rb_funcall(string, gsub, 2, dq_string ? DQ_REGEXP : SQ_REGEXP, HASH);
3745
}
3846

3947
VALUE rbs_unquote_string(parserstate *state, range rg, int offset_bytes) {
@@ -57,9 +65,7 @@ VALUE rbs_unquote_string(parserstate *state, range rg, int offset_bytes) {
5765
char *buffer = RSTRING_PTR(state->lexstate->string) + rg.start.byte_pos + offset_bytes;
5866
VALUE str = rb_enc_str_new(buffer, byte_length, enc);
5967

60-
if (first_char == '\"') {
61-
rbs_unescape_string(str);
62-
}
68+
rbs_unescape_string(str, first_char == '\"');
6369

6470
return str;
6571
}

test/rbs/type_parsing_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,18 @@ def test_literal
581581
assert_instance_of Types::Literal, type
582582
assert_equal 'not escape sequences \a\b\e\f\n\r\s\t\v\"', type.literal
583583
end
584+
585+
# "\\" in RBS
586+
Parser.parse_type(%q{"\\\\"}).yield_self do |type|
587+
assert_instance_of Types::Literal, type
588+
assert_equal "\\", type.literal
589+
end
590+
591+
# '\\' in RBS
592+
Parser.parse_type(%q{'\\\\'}).yield_self do |type|
593+
assert_instance_of Types::Literal, type
594+
assert_equal "\\", type.literal
595+
end
584596
end
585597

586598
def test_literal_to_s

0 commit comments

Comments
 (0)