Skip to content

Commit ffc8f35

Browse files
committed
Support parsing numbered parameters
1 parent 99c9193 commit ffc8f35

File tree

9 files changed

+103
-167
lines changed

9 files changed

+103
-167
lines changed

include/yarp/diagnostic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ typedef enum {
150150
YP_ERR_MULTI_ASSIGN_MULTI_SPLATS,
151151
YP_ERR_NOT_EXPRESSION,
152152
YP_ERR_NUMBER_LITERAL_UNDERSCORE,
153+
YP_ERR_NUMBERED_PARAMETER_NOT_ALLOWED,
153154
YP_ERR_OPERATOR_MULTI_ASSIGN,
154155
YP_ERR_OPERATOR_WRITE_BLOCK,
155156
YP_ERR_PARAMETER_ASSOC_SPLAT_MULTI,

lib/yarp.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,10 +440,6 @@ def self.cruby_locals(source)
440440
# arguments. We get rid of that here.
441441
names = names.grep_v(Integer)
442442

443-
# TODO: We don't support numbered local variables yet, so we get rid
444-
# of those here.
445-
names = names.grep_v(/^_\d$/)
446-
447443
# For some reason, CRuby occasionally pushes this special local
448444
# variable when there are splat arguments. We get rid of that here.
449445
names = names.grep_v(:"#arg_rest")

src/diagnostic.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,9 @@ static const char* const diagnostic_messages[YP_DIAGNOSTIC_ID_LEN] = {
184184
[YP_ERR_MULTI_ASSIGN_MULTI_SPLATS] = "Multiple splats in multiple assignment",
185185
[YP_ERR_NOT_EXPRESSION] = "Expected an expression after `not`",
186186
[YP_ERR_NUMBER_LITERAL_UNDERSCORE] = "Number literal ending with a `_`",
187-
[YP_ERR_OPERATOR_WRITE_BLOCK] = "Unexpected operator after a call with a block",
187+
[YP_ERR_NUMBERED_PARAMETER_NOT_ALLOWED] = "Numbered parameters are not allowed alongside explicit parameters",
188188
[YP_ERR_OPERATOR_MULTI_ASSIGN] = "Unexpected operator for a multiple assignment",
189+
[YP_ERR_OPERATOR_WRITE_BLOCK] = "Unexpected operator after a call with a block",
189190
[YP_ERR_PARAMETER_ASSOC_SPLAT_MULTI] = "Unexpected multiple `**` splat parameters",
190191
[YP_ERR_PARAMETER_BLOCK_MULTI] = "Multiple block parameters; only one block is allowed",
191192
[YP_ERR_PARAMETER_NAME_REPEAT] = "Repeated parameter name",

src/util/yp_constant_pool.c

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,10 @@ yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity) {
107107
}
108108

109109
// Insert a constant into a constant pool and return its index in the pool.
110-
static size_t
111-
yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t length) {
110+
static inline yp_constant_id_t
111+
yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t length, bool owned) {
112112
if (pool->size >= (pool->capacity / 4 * 3)) {
113-
if (!yp_constant_pool_resize(pool)) return pool->capacity;
113+
if (!yp_constant_pool_resize(pool)) return 0;
114114
}
115115

116116
size_t hash = yp_constant_pool_hash(start, length);
@@ -122,7 +122,24 @@ yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t l
122122
// same as the content we are trying to insert. If it is, then we can
123123
// return the id of the existing constant.
124124
if ((constant->length == length) && memcmp(constant->start, start, length) == 0) {
125-
return index;
125+
// Since we have found a match, we need to check if this is
126+
// attempting to insert a shared or an owned constant. We want to
127+
// prefer shared constants since they don't require allocations.
128+
if (owned) {
129+
// If we're attempting to insert an owned constant and we have
130+
// an existing constant, then either way we don't want the given
131+
// memory. Either it's duplicated with the existing constant or
132+
// it's not necessary because we have a shared version.
133+
free((void *) start);
134+
} else if (constant->owned) {
135+
// If we're attempting to insert a shared constant and the
136+
// existing constant is owned, then we can free the owned
137+
// constant and replace it with the shared constant.
138+
free((void *) constant->start);
139+
constant->start = start;
140+
}
141+
142+
return constant->id;
126143
}
127144

128145
index = (index + 1) % pool->capacity;
@@ -131,35 +148,30 @@ yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t l
131148
pool->size++;
132149
assert(pool->size < ((size_t) (1 << 31)));
133150

134-
pool->constants[index] = (yp_constant_t) {
151+
*constant = (yp_constant_t) {
135152
.id = (unsigned int) (pool->size & 0x7FFFFFFF),
153+
.owned = owned & 0x1,
136154
.start = start,
137155
.length = length,
138156
.hash = hash
139157
};
140158

141-
return index;
159+
return constant->id;
142160
}
143161

144162
// Insert a constant into a constant pool. Returns the id of the constant, or 0
145163
// if any potential calls to resize fail.
146164
yp_constant_id_t
147165
yp_constant_pool_insert_shared(yp_constant_pool_t *pool, const uint8_t *start, size_t length) {
148-
size_t index = yp_constant_pool_insert(pool, start, length);
149-
return index == pool->capacity ? 0 : ((yp_constant_id_t) pool->constants[index].id);
166+
return yp_constant_pool_insert(pool, start, length, false);
150167
}
151168

152169
// Insert a constant into a constant pool from memory that is now owned by the
153170
// constant pool. Returns the id of the constant, or 0 if any potential calls to
154171
// resize fail.
155172
yp_constant_id_t
156173
yp_constant_pool_insert_owned(yp_constant_pool_t *pool, const uint8_t *start, size_t length) {
157-
size_t index = yp_constant_pool_insert(pool, start, length);
158-
if (index == pool->capacity) return 0;
159-
160-
yp_constant_t *constant = &pool->constants[index];
161-
constant->owned = true;
162-
return ((yp_constant_id_t) constant->id);
174+
return yp_constant_pool_insert(pool, start, length, true);
163175
}
164176

165177
// Free the memory associated with a constant pool.

src/yarp.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10111,6 +10111,30 @@ parse_variable_call(yp_parser_t *parser) {
1011110111
return (yp_node_t *) yp_local_variable_read_node_create(parser, &parser->previous, (uint32_t) depth);
1011210112
}
1011310113

10114+
if (!parser->current_scope->closed && token_is_numbered_parameter(parser->previous.start, parser->previous.end)) {
10115+
// Now that we know we have a numbered parameter, we need to check
10116+
// if it's allowed in this context. If it is, then we will create a
10117+
// local variable read. If it's not, then we'll create a normal call
10118+
// node but add an error.
10119+
if (parser->current_scope->explicit_params) {
10120+
yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_NUMBERED_PARAMETER_NOT_ALLOWED);
10121+
} else {
10122+
uint8_t number = parser->previous.start[1];
10123+
uint8_t current = '1';
10124+
uint8_t *value;
10125+
10126+
while (current < number) {
10127+
value = malloc(2);
10128+
value[0] = '_';
10129+
value[1] = current++;
10130+
yp_parser_local_add_owned(parser, value, 2);
10131+
}
10132+
10133+
yp_parser_local_add_token(parser, &parser->previous);
10134+
return (yp_node_t *) yp_local_variable_read_node_create(parser, &parser->previous, 0);
10135+
}
10136+
}
10137+
1011410138
flags |= YP_CALL_NODE_FLAGS_VARIABLE_CALL;
1011510139
}
1011610140

test/yarp/snapshots/unparser/corpus/literal/block.txt

Lines changed: 7 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/yarp/snapshots/unparser/corpus/literal/since/27.txt

Lines changed: 7 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)