Skip to content

Commit 45fe3c1

Browse files
kddnewtonk0kubun
authored andcommitted
Backport Bug #21031
1 parent 24f48c8 commit 45fe3c1

File tree

7 files changed

+121
-14
lines changed

7 files changed

+121
-14
lines changed

prism/options.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ PRISM_EXPORTED_FUNCTION bool
163163
pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) {
164164
scope->locals_count = locals_count;
165165
scope->locals = xcalloc(locals_count, sizeof(pm_string_t));
166+
scope->forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE;
166167
return scope->locals != NULL;
167168
}
168169

@@ -174,6 +175,14 @@ pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index) {
174175
return &scope->locals[index];
175176
}
176177

178+
/**
179+
* Set the forwarding option on the given scope struct.
180+
*/
181+
PRISM_EXPORTED_FUNCTION void
182+
pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) {
183+
scope->forwarding = forwarding;
184+
}
185+
177186
/**
178187
* Free the internal memory associated with the options.
179188
*/
@@ -281,6 +290,9 @@ pm_options_read(pm_options_t *options, const char *data) {
281290
return;
282291
}
283292

293+
uint8_t forwarding = (uint8_t) *data++;
294+
pm_options_scope_forwarding_set(&options->scopes[scope_index], forwarding);
295+
284296
for (size_t local_index = 0; local_index < locals_count; local_index++) {
285297
uint32_t local_length = pm_options_read_u32(data);
286298
data += 4;

prism/options.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,26 @@ typedef struct pm_options_scope {
3939

4040
/** The names of the locals in the scope. */
4141
pm_string_t *locals;
42+
43+
/** Flags for the set of forwarding parameters in this scope. */
44+
uint8_t forwarding;
4245
} pm_options_scope_t;
4346

47+
/** The default value for parameters. */
48+
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_NONE = 0x0;
49+
50+
/** When the scope is fowarding with the * parameter. */
51+
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_POSITIONALS = 0x1;
52+
53+
/** When the scope is fowarding with the ** parameter. */
54+
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_KEYWORDS = 0x2;
55+
56+
/** When the scope is fowarding with the & parameter. */
57+
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_BLOCK = 0x4;
58+
59+
/** When the scope is fowarding with the ... parameter. */
60+
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_ALL = 0x8;
61+
4462
// Forward declaration needed by the callback typedef.
4563
struct pm_options;
4664

@@ -319,6 +337,14 @@ PRISM_EXPORTED_FUNCTION bool pm_options_scope_init(pm_options_scope_t *scope, si
319337
*/
320338
PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index);
321339

340+
/**
341+
* Set the forwarding option on the given scope struct.
342+
*
343+
* @param scope The scope struct to set the forwarding on.
344+
* @param forwarding The forwarding value to set.
345+
*/
346+
PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding);
347+
322348
/**
323349
* Free the internal memory associated with the options.
324350
*
@@ -367,6 +393,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options);
367393
* | # bytes | field |
368394
* | ------- | -------------------------- |
369395
* | `4` | the number of locals |
396+
* | `1` | the forwarding flags |
370397
* | ... | the locals |
371398
*
372399
* Each local is laid out as follows:

prism/prism.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22373,7 +22373,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
2237322373

2237422374
// Scopes given from the outside are not allowed to have numbered
2237522375
// parameters.
22376-
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
22376+
parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
2237722377

2237822378
for (size_t local_index = 0; local_index < scope->locals_count; local_index++) {
2237922379
const pm_string_t *local = pm_options_scope_local_get(scope, local_index);

prism_compile.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,6 @@ pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node
138138
#define PM_COMPILE_NOT_POPPED(node) \
139139
pm_compile_node(iseq, (node), ret, false, scope_node)
140140

141-
#define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t)(1 << 31))
142-
#define PM_CONSTANT_AND ((pm_constant_id_t)(idAnd | PM_SPECIAL_CONSTANT_FLAG))
143-
#define PM_CONSTANT_DOT3 ((pm_constant_id_t)(idDot3 | PM_SPECIAL_CONSTANT_FLAG))
144-
#define PM_CONSTANT_MULT ((pm_constant_id_t)(idMULT | PM_SPECIAL_CONSTANT_FLAG))
145-
#define PM_CONSTANT_POW ((pm_constant_id_t)(idPow | PM_SPECIAL_CONSTANT_FLAG))
146-
147141
#define PM_NODE_START_LOCATION(parser, node) \
148142
((pm_node_location_t) { .line = pm_newline_list_line(&(parser)->newline_list, ((const pm_node_t *) (node))->location.start, (parser)->start_line), .node_id = ((const pm_node_t *) (node))->node_id })
149143

prism_compile.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ typedef struct {
8383
bool parsed;
8484
} pm_parse_result_t;
8585

86+
#define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t)(1 << 31))
87+
#define PM_CONSTANT_AND ((pm_constant_id_t)(idAnd | PM_SPECIAL_CONSTANT_FLAG))
88+
#define PM_CONSTANT_DOT3 ((pm_constant_id_t)(idDot3 | PM_SPECIAL_CONSTANT_FLAG))
89+
#define PM_CONSTANT_MULT ((pm_constant_id_t)(idMULT | PM_SPECIAL_CONSTANT_FLAG))
90+
#define PM_CONSTANT_POW ((pm_constant_id_t)(idPow | PM_SPECIAL_CONSTANT_FLAG))
91+
8692
VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error);
8793
VALUE pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines);
8894
VALUE pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines);

test/ruby/test_syntax.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **
139139
inner(&)
140140
end
141141
assert_equal(10, all_kwrest(nil, nil, nil, nil, okw1: nil, okw2: nil){10})
142+
143+
def evaled(&)
144+
eval("inner(&)")
145+
end
146+
assert_equal(1, evaled{1})
142147
end;
143148
end
144149

@@ -156,8 +161,10 @@ def test_anonymous_rest_forwarding
156161
def b(*); c(*) end
157162
def c(*a); a end
158163
def d(*); b(*, *) end
164+
def e(*); eval("b(*)") end
159165
assert_equal([1, 2], b(1, 2))
160166
assert_equal([1, 2, 1, 2], d(1, 2))
167+
assert_equal([1, 2], e(1, 2))
161168
end;
162169
end
163170

@@ -177,10 +184,12 @@ def c(**kw); kw end
177184
def d(**); b(k: 1, **) end
178185
def e(**); b(**, k: 1) end
179186
def f(a: nil, **); b(**) end
187+
def g(**); eval("b(**)") end
180188
assert_equal({a: 1, k: 3}, b(a: 1, k: 3))
181189
assert_equal({a: 1, k: 3}, d(a: 1, k: 3))
182190
assert_equal({a: 1, k: 1}, e(a: 1, k: 3))
183191
assert_equal({k: 3}, f(a: 1, k: 3))
192+
assert_equal({a: 1, k: 3}, g(a: 1, k: 3))
184193
end;
185194
end
186195

@@ -2010,6 +2019,7 @@ def obj1.bar(*args, **kws, &block)
20102019
obj4 = obj1.clone
20112020
obj5 = obj1.clone
20122021
obj1.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
2022+
obj1.instance_eval('def foo(...) eval("bar(...)") end', __FILE__, __LINE__)
20132023
obj4.instance_eval("def foo ...\n bar(...)\n""end", __FILE__, __LINE__)
20142024
obj5.instance_eval("def foo ...; bar(...); end", __FILE__, __LINE__)
20152025

vm_eval.c

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,12 +1692,24 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
16921692
iseq = parent;
16931693
rb_encoding *encoding = rb_enc_get(src);
16941694

1695+
#define FORWARDING_POSITIONALS_CHR '*'
1696+
#define FORWARDING_POSITIONALS_STR "*"
1697+
#define FORWARDING_KEYWORDS_CHR ':'
1698+
#define FORWARDING_KEYWORDS_STR ":"
1699+
#define FORWARDING_BLOCK_CHR '&'
1700+
#define FORWARDING_BLOCK_STR "&"
1701+
#define FORWARDING_ALL_CHR '.'
1702+
#define FORWARDING_ALL_STR "."
1703+
16951704
for (int scopes_index = 0; scopes_index < scopes_count; scopes_index++) {
16961705
VALUE iseq_value = (VALUE)iseq;
16971706
int locals_count = ISEQ_BODY(iseq)->local_table_size;
1707+
16981708
pm_options_scope_t *options_scope = &result.options.scopes[scopes_count - scopes_index - 1];
16991709
pm_options_scope_init(options_scope, locals_count);
17001710

1711+
uint8_t forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE;
1712+
17011713
for (int local_index = 0; local_index < locals_count; local_index++) {
17021714
pm_string_t *scope_local = &options_scope->locals[local_index];
17031715
ID local = ISEQ_BODY(iseq)->local_table[local_index];
@@ -1729,10 +1741,23 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
17291741

17301742
RB_GC_GUARD(name_obj);
17311743

1732-
pm_string_owned_init(scope_local, (uint8_t *)name_dup, length);
1744+
pm_string_owned_init(scope_local, (uint8_t *) name_dup, length);
1745+
} else if (local == idMULT) {
1746+
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_POSITIONALS;
1747+
pm_string_constant_init(scope_local, FORWARDING_POSITIONALS_STR, 1);
1748+
} else if (local == idPow) {
1749+
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_KEYWORDS;
1750+
pm_string_constant_init(scope_local, FORWARDING_KEYWORDS_STR, 1);
1751+
} else if (local == idAnd) {
1752+
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_BLOCK;
1753+
pm_string_constant_init(scope_local, FORWARDING_BLOCK_STR, 1);
1754+
} else if (local == idDot3) {
1755+
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_ALL;
1756+
pm_string_constant_init(scope_local, FORWARDING_ALL_STR, 1);
17331757
}
17341758
}
17351759

1760+
pm_options_scope_forwarding_set(options_scope, forwarding);
17361761
iseq = ISEQ_BODY(iseq)->parent_iseq;
17371762

17381763
/* We need to GC guard the iseq because the code above malloc memory
@@ -1775,14 +1800,38 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
17751800

17761801
for (int local_index = 0; local_index < locals_count; local_index++) {
17771802
const pm_string_t *scope_local = &options_scope->locals[local_index];
1778-
17791803
pm_constant_id_t constant_id = 0;
1780-
if (pm_string_length(scope_local) > 0) {
1781-
constant_id = pm_constant_pool_insert_constant(
1782-
&result.parser.constant_pool, pm_string_source(scope_local),
1783-
pm_string_length(scope_local));
1784-
st_insert(parent_scope->index_lookup_table, (st_data_t)constant_id, (st_data_t)local_index);
1804+
1805+
const uint8_t *source = pm_string_source(scope_local);
1806+
size_t length = pm_string_length(scope_local);
1807+
1808+
if (length > 0) {
1809+
if (length == 1) {
1810+
switch (*source) {
1811+
case FORWARDING_POSITIONALS_CHR:
1812+
constant_id = PM_CONSTANT_MULT;
1813+
break;
1814+
case FORWARDING_KEYWORDS_CHR:
1815+
constant_id = PM_CONSTANT_POW;
1816+
break;
1817+
case FORWARDING_BLOCK_CHR:
1818+
constant_id = PM_CONSTANT_AND;
1819+
break;
1820+
case FORWARDING_ALL_CHR:
1821+
constant_id = PM_CONSTANT_DOT3;
1822+
break;
1823+
default:
1824+
constant_id = pm_constant_pool_insert_constant(&result.parser.constant_pool, source, length);
1825+
break;
1826+
}
1827+
}
1828+
else {
1829+
constant_id = pm_constant_pool_insert_constant(&result.parser.constant_pool, source, length);
1830+
}
1831+
1832+
st_insert(parent_scope->index_lookup_table, (st_data_t) constant_id, (st_data_t) local_index);
17851833
}
1834+
17861835
pm_constant_id_list_append(&parent_scope->locals, constant_id);
17871836
}
17881837

@@ -1791,6 +1840,15 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
17911840
iseq = ISEQ_BODY(iseq)->parent_iseq;
17921841
}
17931842

1843+
#undef FORWARDING_POSITIONALS_CHR
1844+
#undef FORWARDING_POSITIONALS_STR
1845+
#undef FORWARDING_KEYWORDS_CHR
1846+
#undef FORWARDING_KEYWORDS_STR
1847+
#undef FORWARDING_BLOCK_CHR
1848+
#undef FORWARDING_BLOCK_STR
1849+
#undef FORWARDING_ALL_CHR
1850+
#undef FORWARDING_ALL_STR
1851+
17941852
int error_state;
17951853
iseq = pm_iseq_new_eval(&result.node, name, fname, Qnil, line, parent, 0, &error_state);
17961854

0 commit comments

Comments
 (0)