summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/codegen.c39
-rw-r--r--test/t/syntax.rb28
2 files changed, 65 insertions, 2 deletions
diff --git a/src/codegen.c b/src/codegen.c
index 2efad00bc..708c207dc 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -2087,14 +2087,48 @@ codegen(codegen_scope *s, node *tree, int val)
gen_literal_array(s, tree, TRUE, val);
break;
+ case NODE_DXSTR:
+ {
+ node *n;
+ int ai = mrb_gc_arena_save(s->mrb);
+ int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
+
+ if (val == NOVAL) { push(); }
+ genop(s, MKOP_A(OP_OCLASS, cursp()));
+ genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+ push();
+ codegen(s, tree->car, VAL);
+ n = tree->cdr;
+ while (n) {
+ if ((intptr_t)n->car->car == NODE_XSTR) {
+ n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR;
+ mrb_assert(!n->cdr); /* must be the end */
+ }
+ codegen(s, n->car, VAL);
+ pop(); pop();
+ genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+ push();
+ n = n->cdr;
+ }
+ pop();
+ pop();
+ sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
+ genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+ if (val == NOVAL) { pop(); }
+ else { push(); }
+ mrb_gc_arena_restore(s->mrb, ai);
+ }
+ break;
+
case NODE_XSTR:
- if (val) {
+ {
char *p = (char*)tree->car;
size_t len = (intptr_t)tree->cdr;
int ai = mrb_gc_arena_save(s->mrb);
int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
int off = new_lit(s, mrb_str_new(s->mrb, p, len));
+ if (val == NOVAL) { push(); }
genop(s, MKOP_A(OP_OCLASS, cursp()));
genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
push();
@@ -2102,8 +2136,9 @@ codegen(codegen_scope *s, node *tree, int val)
pop();
sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+ if (val == NOVAL) { pop(); }
+ else { push(); }
mrb_gc_arena_restore(s->mrb, ai);
- push();
}
break;
diff --git a/test/t/syntax.rb b/test/t/syntax.rb
index 3569193bc..fac73aa7b 100644
--- a/test/t/syntax.rb
+++ b/test/t/syntax.rb
@@ -226,3 +226,31 @@ assert('splat in case statement') do
assert_equal [5], resultb
assert_equal [3,8], resultc
end
+
+assert('External command execution.') do
+ class << Kernel
+ sym = '`'.to_sym
+ alias_method :old_cmd, sym
+
+ results = []
+ define_method(sym) do |str|
+ results.push str
+ str
+ end
+
+ `test` # NOVAL NODE_XSTR
+ `test dynamic #{sym}` # NOVAL NODE_DXSTR
+ assert_equal ['test', 'test dynamic `'], results
+
+ t = `test` # VAL NODE_XSTR
+ assert_equal 'test', t
+ assert_equal ['test', 'test dynamic `', 'test'], results
+
+ t = `test dynamic #{sym}` # VAL NODE_DXSTR
+ assert_equal 'test dynamic `', t
+ assert_equal ['test', 'test dynamic `', 'test', 'test dynamic `'], results
+
+ alias_method sym, :old_cmd
+ end
+ true
+end