mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
[Bug #20504] Move dynamic regexp concatenation to iseq compiler
This commit is contained in:
parent
77fe82286b
commit
6bbb470dc7
Notes:
git
2025-01-03 02:06:04 +00:00
6 changed files with 112 additions and 102 deletions
120
compile.c
120
compile.c
|
@ -3820,6 +3820,24 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
|
|||
}
|
||||
ELEM_REMOVE(&iobj->link);
|
||||
}
|
||||
if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
|
||||
INSN *next = (INSN *)iobj->link.next;
|
||||
if (OPERAND_AT(next, 1) == INT2FIX(1)) {
|
||||
VALUE src = OPERAND_AT(iobj, 0);
|
||||
int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
|
||||
VALUE path = rb_iseq_path(iseq);
|
||||
int line = iobj->insn_info.line_no;
|
||||
VALUE errinfo = rb_errinfo();
|
||||
VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
|
||||
if (NIL_P(re)) {
|
||||
VALUE message = rb_attr_get(rb_errinfo(), idMesg);
|
||||
rb_set_errinfo(errinfo);
|
||||
COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
|
||||
}
|
||||
RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
|
||||
ELEM_REMOVE(iobj->link.next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_INSN_ID(iobj, concatstrings)) {
|
||||
|
@ -4502,47 +4520,91 @@ all_string_result_p(const NODE *node)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
|
||||
{
|
||||
const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
|
||||
VALUE lit = rb_node_dstr_string_val(node);
|
||||
LINK_ELEMENT *first_lit = 0;
|
||||
int cnt = 0;
|
||||
struct dstr_ctxt {
|
||||
rb_iseq_t *const iseq;
|
||||
LINK_ANCHOR *const ret;
|
||||
VALUE lit;
|
||||
const NODE *lit_node;
|
||||
int cnt;
|
||||
int dregx;
|
||||
};
|
||||
|
||||
debugp_param("nd_lit", lit);
|
||||
if (!NIL_P(lit)) {
|
||||
cnt++;
|
||||
if (!RB_TYPE_P(lit, T_STRING)) {
|
||||
COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
|
||||
rb_builtin_type_name(TYPE(lit)));
|
||||
static int
|
||||
append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
|
||||
{
|
||||
VALUE s = rb_str_new_mutable_parser_string(str);
|
||||
if (args->dregx) {
|
||||
VALUE error = rb_reg_check_preprocess(s);
|
||||
if (!NIL_P(error)) {
|
||||
COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
|
||||
return COMPILE_NG;
|
||||
}
|
||||
}
|
||||
if (NIL_P(args->lit)) {
|
||||
args->lit = s;
|
||||
args->lit_node = node;
|
||||
}
|
||||
else {
|
||||
rb_str_buf_append(args->lit, s);
|
||||
}
|
||||
return COMPILE_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
flush_dstr_fragment(struct dstr_ctxt *args)
|
||||
{
|
||||
if (!NIL_P(args->lit)) {
|
||||
rb_iseq_t *iseq = args->iseq;
|
||||
VALUE lit = args->lit;
|
||||
args->lit = Qnil;
|
||||
lit = rb_fstring(lit);
|
||||
ADD_INSN1(ret, node, putobject, lit);
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, lit);
|
||||
if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
|
||||
ADD_INSN1(args->ret, args->lit_node, putobject, lit);
|
||||
RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
|
||||
args->cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
|
||||
{
|
||||
const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
|
||||
rb_parser_string_t *str = RNODE_DSTR(node)->string;
|
||||
|
||||
if (str) {
|
||||
CHECK(append_dstr_fragment(args, node, str));
|
||||
}
|
||||
|
||||
while (list) {
|
||||
const NODE *const head = list->nd_head;
|
||||
if (nd_type_p(head, NODE_STR)) {
|
||||
lit = rb_node_str_string_val(head);
|
||||
ADD_INSN1(ret, head, putobject, lit);
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, lit);
|
||||
lit = Qnil;
|
||||
CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
|
||||
}
|
||||
else if (nd_type_p(head, NODE_DSTR)) {
|
||||
CHECK(compile_dstr_fragments_0(args, head));
|
||||
}
|
||||
else {
|
||||
CHECK(COMPILE(ret, "each string", head));
|
||||
flush_dstr_fragment(args);
|
||||
rb_iseq_t *iseq = args->iseq;
|
||||
CHECK(COMPILE(args->ret, "each string", head));
|
||||
args->cnt++;
|
||||
}
|
||||
cnt++;
|
||||
list = (struct RNode_LIST *)list->nd_next;
|
||||
}
|
||||
if (NIL_P(lit) && first_lit) {
|
||||
ELEM_REMOVE(first_lit);
|
||||
--cnt;
|
||||
}
|
||||
*cntp = cnt;
|
||||
return COMPILE_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
|
||||
{
|
||||
struct dstr_ctxt args = {
|
||||
.iseq = iseq, .ret = ret,
|
||||
.lit = Qnil, .lit_node = NULL,
|
||||
.cnt = 0, .dregx = dregx,
|
||||
};
|
||||
CHECK(compile_dstr_fragments_0(&args, node));
|
||||
flush_dstr_fragment(&args);
|
||||
|
||||
*cntp = args.cnt;
|
||||
|
||||
return COMPILE_OK;
|
||||
}
|
||||
|
@ -4571,7 +4633,7 @@ compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
|
|||
RB_OBJ_WRITTEN(iseq, Qundef, lit);
|
||||
}
|
||||
else {
|
||||
CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
|
||||
CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
|
||||
ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
|
||||
}
|
||||
return COMPILE_OK;
|
||||
|
@ -4593,7 +4655,7 @@ compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
|
|||
return COMPILE_OK;
|
||||
}
|
||||
|
||||
CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
|
||||
CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
|
||||
ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
|
||||
|
||||
if (popped) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue