Merge pull request #1039 from crimsonwoods/fix_the_type_of_opcode
authorYukihiro "Matz" Matsumoto <[email protected]>
Sat, 23 Mar 2013 02:11:51 +0000 (22 19:11 -0700)
committerYukihiro "Matz" Matsumoto <[email protected]>
Sat, 23 Mar 2013 02:11:51 +0000 (22 19:11 -0700)
Fix the type of value that is returned by bit shift expression.

27 files changed:
build_config.rb
include/mrbconf.h
include/mruby.h
include/mruby/compile.h
include/mruby/hash.h
mrbgems/mruby-array-ext/mrblib/array.rb [new file with mode: 0644]
mrbgems/mruby-array-ext/test/array.rb
mrbgems/mruby-enum-ext/mrblib/enum.rb
mrbgems/mruby-enum-ext/test/enum.rb
mrbgems/mruby-eval/mrbgem.rake [new file with mode: 0644]
mrbgems/mruby-eval/src/eval.c [new file with mode: 0644]
mrbgems/mruby-hash-ext/mrbgem.rake [new file with mode: 0644]
mrbgems/mruby-hash-ext/mrblib/hash.rb [new file with mode: 0644]
mrbgems/mruby-hash-ext/test/hash.rb [new file with mode: 0644]
mrbgems/mruby-struct/src/struct.c
src/array.c
src/class.c
src/codegen.c
src/error.c
src/hash.c
src/kernel.c
src/node.h
src/parse.y
src/string.c
src/symbol.c
src/variable.c
src/vm.c

index d41c44b..475ff27 100644 (file)
@@ -35,9 +35,15 @@ MRuby::Build.new do |conf|
   # Use extensional Array class
   conf.gem "#{root}/mrbgems/mruby-array-ext"
 
+  # Use extensional Hash class
+  conf.gem "#{root}/mrbgems/mruby-hash-ext"
+
+  # No use eval method
+  # conf.gem "#{root}/mrbgems/mruby-eval
+
   # Generate binaries
   # conf.bins = %w(mrbc mruby mirb)
-  
+
   # C compiler settings
   # conf.cc do |cc|
   #   cc.command = ENV['CC'] || 'gcc'
index 030e00c..a6914cd 100644 (file)
@@ -49,6 +49,8 @@
 /* initial minimum size for string buffer */
 //#define MRB_STR_BUF_MIN_SIZE 128
 
+/* array size for parser buffer */
+//#define MRB_PARSER_BUF_SIZE 1024
 
 /* -DDISABLE_XXXX to drop following features */
 //#define DISABLE_STDIO                /* use of stdio */
index 84aeff0..c5c6078 100644 (file)
@@ -189,13 +189,20 @@ int mrb_get_args(mrb_state *mrb, const char *format, ...);
 mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, int,...);
 mrb_value mrb_funcall_argv(mrb_state*, mrb_value, mrb_sym, int, mrb_value*);
 mrb_value mrb_funcall_with_block(mrb_state*, mrb_value, mrb_sym, int, mrb_value*, mrb_value);
-mrb_sym mrb_intern(mrb_state*,const char*);
+mrb_sym mrb_intern_cstr(mrb_state*,const char*);
 mrb_sym mrb_intern2(mrb_state*,const char*,size_t);
 mrb_sym mrb_intern_str(mrb_state*,mrb_value);
 const char *mrb_sym2name(mrb_state*,mrb_sym);
 const char *mrb_sym2name_len(mrb_state*,mrb_sym,size_t*);
 mrb_value mrb_str_format(mrb_state *, int, const mrb_value *, mrb_value);
 
+/* For backward compatibility. */
+static inline
+mrb_sym mrb_intern(mrb_state *mrb,const char *cstr)
+{
+  return mrb_intern_cstr(mrb, cstr);
+}
+
 void *mrb_malloc(mrb_state*, size_t);
 void *mrb_calloc(mrb_state*, size_t, size_t);
 void *mrb_realloc(mrb_state*, void*, size_t);
index 8b0743f..26f8a59 100644 (file)
@@ -65,6 +65,7 @@ struct mrb_parser_message {
 #define STR_FUNC_SYMBOL  0x10
 #define STR_FUNC_ARRAY   0x20
 #define STR_FUNC_HEREDOC 0x40
+#define STR_FUNC_XQUOTE  0x80
 
 enum mrb_string_type {
   str_not_parsing  = (0),
@@ -77,6 +78,7 @@ enum mrb_string_type {
   str_ssymbols = (STR_FUNC_PARSING|STR_FUNC_SYMBOL|STR_FUNC_ARRAY),
   str_dsymbols = (STR_FUNC_PARSING|STR_FUNC_SYMBOL|STR_FUNC_ARRAY|STR_FUNC_EXPAND),
   str_heredoc  = (STR_FUNC_PARSING|STR_FUNC_HEREDOC),
+  str_xquote   = (STR_FUNC_PARSING|STR_FUNC_XQUOTE|STR_FUNC_EXPAND),
 };
 
 /* heredoc structure */
@@ -89,6 +91,10 @@ struct mrb_parser_heredoc_info {
   mrb_ast_node *doc;
 };
 
+#ifndef MRB_PARSER_BUF_SIZE
+# define MRB_PARSER_BUF_SIZE 1024
+#endif
+
 /* parser structure */
 struct mrb_parser_state {
   mrb_state *mrb;
@@ -111,7 +117,7 @@ struct mrb_parser_state {
   mrb_ast_node *locals;
 
   mrb_ast_node *pb;
-  char buf[1024];
+  char buf[MRB_PARSER_BUF_SIZE];
   int bidx;
 
   mrb_ast_node *heredocs;      /* list of mrb_parser_heredoc_info* */
index ac28f13..baace75 100644 (file)
@@ -33,7 +33,7 @@ mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
 /* RHASH_TBL allocates st_table if not available. */
 #define RHASH(obj)   ((struct RHash*)((obj).value.p))
 #define RHASH_TBL(h)          (RHASH(h)->ht)
-#define RHASH_IFNONE(h)       mrb_iv_get(mrb, (h), mrb_intern(mrb, "ifnone"))
+#define RHASH_IFNONE(h)       mrb_iv_get(mrb, (h), mrb_intern2(mrb, "ifnone", 6))
 #define RHASH_PROCDEFAULT(h)  RHASH_IFNONE(h)
 struct kh_ht * mrb_hash_tbl(mrb_state *mrb, mrb_value hash);
 
diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb
new file mode 100644 (file)
index 0000000..b3ff9bf
--- /dev/null
@@ -0,0 +1,98 @@
+class Array
+  def uniq!
+    ary = self.dup
+    result = []
+    while ary.size > 0
+      result << ary.shift
+      ary.delete(result.last)
+    end
+    if result.size == self.size
+      nil
+    else
+      self.replace(result)
+    end
+  end
+
+  def uniq
+    ary = self.dup
+    ary.uniq!
+    ary
+  end
+
+  def -(elem)
+    raise TypeError, "can't convert to Array" unless elem.class == Array
+
+    hash = {}
+    array = []
+    elem.each { |x| hash[x] = true }
+    self.each { |x| array << x unless hash[x] }
+    array
+  end
+
+  def |(elem)
+    raise TypeError, "can't convert to Array" unless elem.class == Array
+
+    ary = self + elem
+    ary.uniq! or ary
+  end
+
+  def &(elem)
+    raise TypeError, "can't convert to Array" unless elem.class == Array
+
+    hash = {}
+    array = []
+    elem.each{|v| hash[v] = true }
+    self.each do |v|
+      if hash[v]
+        array << v
+        hash.delete v
+      end
+    end
+    array
+  end
+
+  def flatten(depth=nil)
+    ar = []
+    self.each do |e|
+      if e.is_a?(Array) && (depth.nil? || depth > 0)
+        ar += e.flatten(depth.nil? ? nil : depth - 1)
+      else
+        ar << e
+      end
+    end
+    ar
+  end
+
+  def flatten!(depth=nil)
+    modified = false
+    ar = []
+    self.each do |e|
+      if e.is_a?(Array) && (depth.nil? || depth > 0)
+        ar += e.flatten(depth.nil? ? nil : depth - 1)
+        modified = true
+      else
+        ar << e
+      end
+    end
+    if modified
+      self.replace(ar)
+    else
+      nil
+    end
+  end
+
+  def compact
+    result = self.dup
+    result.compact!
+    result
+  end
+
+  def compact!
+    result = self.select { |e| e != nil }
+    if result.size == self.size
+      nil
+    else
+      self.replace(result)
+    end
+  end
+end
index 36da6bb..1c441ce 100644 (file)
@@ -28,3 +28,82 @@ assert("Array#rassoc") do
   a.rassoc("four").nil?
 end
 
+assert("Array#uniq!") do
+  a = [1, 2, 3, 1]
+  a.uniq!
+  a == [1, 2, 3]
+end
+
+assert("Array#uniq") do
+  a = [1, 2, 3, 1]
+  a.uniq == [1, 2, 3] && a == [1, 2, 3, 1]
+end
+
+assert("Array#-") do
+  a = [1, 2, 3, 1]
+  b = [1]
+  c = 1
+  e1 = nil
+
+  begin
+    a - c
+  rescue => e1
+  end
+
+  (a - b) == [2, 3] and e1.class == TypeError and a == [1, 2, 3, 1]
+end
+
+assert("Array#|") do
+  a = [1, 2, 3, 1]
+  b = [1, 4]
+  c = 1
+  e1 = nil
+
+  begin
+    a | c
+  rescue => e1
+  end
+
+  (a | b) == [1, 2, 3, 4] and e1.class == TypeError and a == [1, 2, 3, 1]
+end
+
+assert("Array#&") do
+  a = [1, 2, 3, 1]
+  b = [1, 4]
+  c = 1
+  e1 = nil
+
+  begin
+    a & c
+  rescue => e1
+  end
+
+  (a & b) == [1] and e1.class == TypeError and a == [1, 2, 3, 1]
+end
+
+assert("Array#flatten") do
+  [1, 2, "3", {4=>5}, :'6'] == [1, 2, "3", {4=>5}, :'6'].flatten and
+  [1, 2, 3, 4, 5, 6] == [1, 2, [3, 4, 5], 6].flatten and
+  [1, 2, 3, 4, 5, 6] == [1, 2, [3, [4, 5], 6]].flatten and
+  [1, [2, [3, [4, [5, [6]]]]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(0) and
+  [1, 2, [3, [4, [5, [6]]]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(1) and
+  [1, 2, 3, [4, [5, [6]]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(2) and
+  [1, 2, 3, 4, [5, [6]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(3) and
+  [1, 2, 3, 4, 5, [6]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(4) and
+  [1, 2, 3, 4, 5, 6] == [1, [2, [3, [4, [5, [6]]]]]].flatten(5)
+end
+
+assert("Array#flatten!") do
+  [1, 2, 3, 4, 5, 6] == [1, 2, [3, [4, 5], 6]].flatten!
+end
+
+assert("Array#compact") do
+  a = [1, nil, "2", nil, :t, false, nil]
+  a.compact == [1, "2", :t, false] && a == [1, nil, "2", nil, :t, false, nil]
+end
+
+assert("Array#compact!") do
+  a = [1, nil, "2", nil, :t, false, nil]
+  a.compact!
+  a == [1, "2", :t, false]
+end
index a9545da..f250d39 100644 (file)
@@ -82,4 +82,83 @@ module Enumerable
     ary
   end
   
+  ##
+  # call-seq:
+  #   enum.each_cons(n) {...}   ->  nil
+  #
+  # Iterates the given block for each array of consecutive <n>
+  # elements.
+  #
+  # e.g.:
+  #     (1..10).each_cons(3) {|a| p a}
+  #     # outputs below
+  #     [1, 2, 3]
+  #     [2, 3, 4]
+  #     [3, 4, 5]
+  #     [4, 5, 6]
+  #     [5, 6, 7]
+  #     [6, 7, 8]
+  #     [7, 8, 9]
+  #     [8, 9, 10]
+
+  def each_cons(n, &block)
+    raise TypeError, "expected Integer for 1st argument" unless n.kind_of? Integer
+    raise ArgumentError, "invalid size" if n <= 0
+
+    ary = []
+    self.each do |e|
+      ary.shift if ary.size == n
+      ary << e
+      block.call(ary.dup) if ary.size == n
+    end
+  end
+
+  ##
+  # call-seq:
+  #   enum.each_slice(n) {...}  ->  nil
+  #
+  # Iterates the given block for each slice of <n> elements.
+  #
+  # e.g.:
+  #     (1..10).each_slice(3) {|a| p a}
+  #     # outputs below
+  #     [1, 2, 3]
+  #     [4, 5, 6]
+  #     [7, 8, 9]
+  #     [10]
+
+  def each_slice(n, &block)
+    raise TypeError, "expected Integer for 1st argument" unless n.kind_of? Integer
+    raise ArgumentError, "invalid slice size" if n <= 0
+
+    ary = []
+    self.each do |e|
+      ary << e
+      if ary.size == n
+        block.call(ary)
+        ary = []
+      end
+    end
+    block.call(ary) unless ary.empty?
+  end
+
+  ##
+  # call-seq:
+  #    enum.group_by {| obj | block }  -> a_hash
+  #
+  # Returns a hash, which keys are evaluated result from the
+  # block, and values are arrays of elements in <i>enum</i>
+  # corresponding to the key.
+  #
+  #    (1..6).group_by {|i| i%3}   #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
+
+  def group_by(&block)
+    h = {}
+    self.each do |e|
+      key = block.call(e)
+      h.key?(key) ? (h[key] << e) : (h[key] = [e])
+    end
+    h
+  end
+
 end
index 5fc9759..aa56cdf 100644 (file)
@@ -23,3 +23,22 @@ assert("Enumerable#take_while") do
   assert_equal a.take_while {|i| i < 3 }, [1, 2]
 end
 
+assert("Enumerable#each_cons") do
+  a = []
+  (1..5).each_cons(3){|e| a << e}
+  assert_equal a, [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
+end
+
+assert("Enumerable#each_slice") do
+  a = []
+  (1..10).each_slice(3){|e| a << e}
+  assert_equal  a, [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
+end
+
+assert("Enumerable#group_by") do
+  r = (1..6).group_by {|i| i % 3 }
+  assert_equal r[0], [3, 6]
+  assert_equal r[1], [1, 4]
+  assert_equal r[2], [2, 5]
+end
+
diff --git a/mrbgems/mruby-eval/mrbgem.rake b/mrbgems/mruby-eval/mrbgem.rake
new file mode 100644 (file)
index 0000000..f80cf1b
--- /dev/null
@@ -0,0 +1,4 @@
+MRuby::Gem::Specification.new('mruby-eval') do |spec|
+  spec.license = 'MIT'
+  spec.authors = 'mruby developers'
+end
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c
new file mode 100644 (file)
index 0000000..0395585
--- /dev/null
@@ -0,0 +1,23 @@
+#include "mruby.h"
+#include "mruby/compile.h"
+
+static mrb_value
+f_eval(mrb_state *mrb, mrb_value self)
+{
+  char *s;
+  int len;
+
+  mrb_get_args(mrb, "s", &s, &len);
+  return mrb_load_nstring(mrb, s, len);
+}
+
+void
+mrb_mruby_eval_gem_init(mrb_state* mrb)
+{
+  mrb_define_class_method(mrb, mrb->kernel_module, "eval", f_eval, ARGS_REQ(1));
+}
+
+void
+mrb_mruby_eval_gem_final(mrb_state* mrb)
+{
+}
diff --git a/mrbgems/mruby-hash-ext/mrbgem.rake b/mrbgems/mruby-hash-ext/mrbgem.rake
new file mode 100644 (file)
index 0000000..3163c8c
--- /dev/null
@@ -0,0 +1,4 @@
+MRuby::Gem::Specification.new('mruby-hash-ext') do |spec|
+  spec.license = 'MIT'
+  spec.authors = 'mruby developers'
+end
diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb
new file mode 100644 (file)
index 0000000..3e1bac0
--- /dev/null
@@ -0,0 +1,12 @@
+class Hash
+  def merge!(other, &block)
+    if block
+      other.each_key{|k|
+        self[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k]
+      }
+    else
+      other.each_key{|k| self[k] = other[k]}
+    end
+    self
+  end
+end
diff --git a/mrbgems/mruby-hash-ext/test/hash.rb b/mrbgems/mruby-hash-ext/test/hash.rb
new file mode 100644 (file)
index 0000000..98eb313
--- /dev/null
@@ -0,0 +1,20 @@
+##
+# Hash(Ext) Test
+
+assert('Hash#merge!') do
+  a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' }
+  b = { 'cba_key' => 'XXX',  'xyz_key' => 'xyz_value' }
+
+  result_1 = a.merge! b
+  
+  a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' }
+  result_2 = a.merge!(b) do |key, original, new|
+    original
+  end
+
+  result_1 == {'abc_key' => 'abc_value', 'cba_key' => 'XXX',
+               'xyz_key' => 'xyz_value' } and
+  result_2 == {'abc_key' => 'abc_value', 'cba_key' => 'cba_value',
+               'xyz_key' => 'xyz_value' }
+end
+
index cf20856..082843f 100644 (file)
@@ -49,7 +49,7 @@ mrb_struct_iv_get(mrb_state *mrb, mrb_value c, const char *name)
 mrb_value
 mrb_struct_s_members(mrb_state *mrb, mrb_value klass)
 {
-  mrb_value members = struct_ivar_get(mrb, klass, mrb_intern(mrb, "__members__"));
+  mrb_value members = struct_ivar_get(mrb, klass, mrb_intern2(mrb, "__members__", 11));
 
   if (mrb_nil_p(members)) {
     mrb_raise(mrb, E_TYPE_ERROR, "uninitialized struct");
@@ -258,7 +258,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * k
   }
   MRB_SET_INSTANCE_TT(c, MRB_TT_ARRAY);
   nstr = mrb_obj_value(c);
-  mrb_iv_set(mrb, nstr, mrb_intern(mrb, "__members__"), members);
+  mrb_iv_set(mrb, nstr, mrb_intern2(mrb, "__members__", 11), members);
 
   mrb_define_class_method(mrb, c, "new", mrb_instance_new, ARGS_ANY());
   mrb_define_class_method(mrb, c, "[]", mrb_instance_new, ARGS_ANY());
@@ -393,7 +393,7 @@ num_members(mrb_state *mrb, struct RClass *klass)
 {
   mrb_value members;
 
-  members = struct_ivar_get(mrb, mrb_obj_value(klass), mrb_intern(mrb, "__members__"));
+  members = struct_ivar_get(mrb, mrb_obj_value(klass), mrb_intern2(mrb, "__members__", 11));
   if (!mrb_array_p(members)) {
     mrb_raise(mrb, E_TYPE_ERROR, "broken members");
   }
index f5d82d3..bfdb1bb 100644 (file)
@@ -301,7 +301,7 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1)
   a1 = RARRAY(ary1); a2 = RARRAY(ary2);
   if (a1->len == a2->len && a1->ptr == a2->ptr) return mrb_fixnum_value(0);
   else {
-    mrb_sym cmp = mrb_intern(mrb, "<=>");
+    mrb_sym cmp = mrb_intern2(mrb, "<=>", 3);
 
     len = RARRAY_LEN(ary1);
     if (len > RARRAY_LEN(ary2)) {
@@ -1069,7 +1069,7 @@ mrb_ary_equal(mrb_state *mrb, mrb_value ary1)
     equal_p = 0;
   }
   else if (!mrb_array_p(ary2)) {
-    if (!mrb_respond_to(mrb, ary2, mrb_intern(mrb, "to_ary"))) {
+    if (!mrb_respond_to(mrb, ary2, mrb_intern2(mrb, "to_ary", 6))) {
         equal_p = 0;
     }
     else {
index 74bd104..63b9b39 100644 (file)
@@ -54,7 +54,7 @@ void
 mrb_name_class(mrb_state *mrb, struct RClass *c, mrb_sym name)
 {
   mrb_obj_iv_set(mrb, (struct RObject*)c,
-                 mrb_intern(mrb, "__classid__"), mrb_symbol_value(name));
+                 mrb_intern2(mrb, "__classid__", 11), mrb_symbol_value(name));
 }
 
 #define make_metaclass(mrb, c) prepare_singleton_class((mrb), (struct RBasic*)(c))
@@ -88,7 +88,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
   o->c = sc;
   mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc);
   mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o);
-  mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern(mrb, "__attached__"), mrb_obj_value(o));
+  mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern2(mrb, "__attached__", 12), mrb_obj_value(o));
 }
 
 struct RClass*
@@ -115,7 +115,7 @@ setup_class(mrb_state *mrb, mrb_value outer, struct RClass *c, mrb_sym id)
   mrb_name_class(mrb, c, id);
   mrb_const_set(mrb, outer, id, mrb_obj_value(c));
   mrb_obj_iv_set(mrb, (struct RObject*)c,
-                 mrb_intern(mrb, "__outer__"), outer);
+                 mrb_intern2(mrb, "__outer__", 9), outer);
 }
 
 struct RClass*
@@ -123,7 +123,7 @@ mrb_class_outer_module(mrb_state *mrb, struct RClass *c)
 {
   mrb_value outer;
 
-  outer = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern(mrb, "__outer__"));
+  outer = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern2(mrb, "__outer__", 9));
   if (mrb_nil_p(outer)) return 0;
   return mrb_class_ptr(outer);
 }
@@ -1138,7 +1138,7 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod)
     mrb_raise(mrb, E_TYPE_ERROR, "name should be a symbol");
   }
 
-  if (mrb_respond_to(mrb,mod,mrb_intern(mrb,"inspect"))){
+  if (mrb_respond_to(mrb,mod,mrb_intern2(mrb,"inspect",7))){
     inspect = mrb_funcall(mrb, mod, "inspect", 0);
     if (RSTRING_LEN(inspect) > 64) {
       inspect = mrb_any_to_s(mrb, mod);
@@ -1190,8 +1190,9 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
   mrb_value path;
   const char *name;
   size_t len;
+  mrb_sym classpath = mrb_intern2(mrb, "__classpath__", 13);
 
-  path = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern(mrb, "__classpath__"));
+  path = mrb_obj_iv_get(mrb, (struct RObject*)c, classpath);
   if (mrb_nil_p(path)) {
     struct RClass *outer = mrb_class_outer_module(mrb, c);
     mrb_sym sym = mrb_class_sym(mrb, c, outer);
@@ -1208,7 +1209,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
       name = mrb_sym2name_len(mrb, sym, &len);
       path = mrb_str_new(mrb, name, len);
     }
-    mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern(mrb, "__classpath__"), path);
+    mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path);
   }
   return path;
 }
@@ -1351,7 +1352,7 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
 {
   if (mrb_type(klass) == MRB_TT_SCLASS) {
     mrb_value s = mrb_str_new(mrb, "#<", 2);
-    mrb_value v = mrb_iv_get(mrb, klass, mrb_intern(mrb, "__attached__"));
+    mrb_value v = mrb_iv_get(mrb, klass, mrb_intern2(mrb, "__attached__", 12));
 
     mrb_str_cat2(mrb, s, "Class:");
     switch (mrb_type(v)) {
index 3141faf..30efa24 100644 (file)
@@ -560,7 +560,7 @@ for_body(codegen_scope *s, node *tree)
   s = prev;
   genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx - base, OP_L_BLOCK));
   pop();
-  idx = new_msym(s, mrb_intern(s->mrb, "each"));
+  idx = new_msym(s, mrb_intern2(s->mrb, "each", 4));
   genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0));
 }
 
@@ -960,7 +960,7 @@ static void
 gen_send_intern(codegen_scope *s)
 {
   pop();
-  genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern(s->mrb, "intern")), 0));
+  genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern2(s->mrb, "intern", 6)), 0));
   push();
 }
 static void
@@ -1152,12 +1152,12 @@ codegen(codegen_scope *s, node *tree, int val)
               codegen(s, n4->car, VAL);
             }
             else {
-              genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern(s->mrb, "StandardError"))));
+              genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern2(s->mrb, "StandardError", 13))));
               push();
             }
             genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
             pop();
-            genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern(s->mrb, "===")), 1));
+            genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern2(s->mrb, "===", 3)), 1));
             tmp = new_label(s);
             genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
             pos2 = tmp;
@@ -1361,7 +1361,7 @@ codegen(codegen_scope *s, node *tree, int val)
           if (head) {
             genop(s, MKOP_AB(OP_MOVE, cursp(), head));
             pop();
-            genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern(s->mrb, "===")), 1));
+            genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern2(s->mrb, "===", 3)), 1));
           }
           else {
             pop();
@@ -1702,7 +1702,7 @@ codegen(codegen_scope *s, node *tree, int val)
       }
       pop_n(n+1);
       if (sendv) n = CALL_MAXARGS;
-      genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern(s->mrb, "call")), n));
+      genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern2(s->mrb, "call", 4)), n));
       if (val) push();
     }
     break;
@@ -1969,7 +1969,7 @@ codegen(codegen_scope *s, node *tree, int val)
 
       default:
         {
-          int sym = new_msym(s, mrb_intern(s->mrb, "-"));
+          int sym = new_msym(s, mrb_intern2(s->mrb, "-", 1));
 
           genop(s, MKOP_ABx(OP_LOADI, cursp(), 0));
           push();
@@ -2032,6 +2032,26 @@ codegen(codegen_scope *s, node *tree, int val)
     gen_literal_array(s, tree, TRUE, val);
     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_intern2(s->mrb, "Kernel", 6));
+      int off = new_lit(s, mrb_str_new(s->mrb, p, len));
+
+      genop(s, MKOP_A(OP_OCLASS, cursp()));
+      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      push();
+      genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+      pop();
+      sym = new_sym(s, mrb_intern2(s->mrb, "`", 1));
+      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+      mrb_gc_arena_restore(s->mrb, ai);
+      push();
+    }
+    break;
+
   case NODE_REGX:
     if (val) {
       char *p1 = (char*)tree->car;
@@ -2053,7 +2073,7 @@ codegen(codegen_scope *s, node *tree, int val)
         pop();
       }
       pop();
-      sym = new_sym(s, mrb_intern(s->mrb, "compile"));
+      sym = new_sym(s, mrb_intern2(s->mrb, "compile", 7));
       genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
       mrb_gc_arena_restore(s->mrb, ai);
       push();
@@ -2101,7 +2121,7 @@ codegen(codegen_scope *s, node *tree, int val)
         pop();
       }
       pop();
-      sym = new_sym(s, mrb_intern(s->mrb, "compile"));
+      sym = new_sym(s, mrb_intern2(s->mrb, "compile", 7));
       genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
       mrb_gc_arena_restore(s->mrb, ai);
       push();
@@ -2166,7 +2186,7 @@ codegen(codegen_scope *s, node *tree, int val)
     {
       int a = new_msym(s, sym(tree->car));
       int b = new_msym(s, sym(tree->cdr));
-      int c = new_msym(s, mrb_intern(s->mrb, "alias_method"));
+      int c = new_msym(s, mrb_intern2(s->mrb, "alias_method", 12));
 
       genop(s, MKOP_A(OP_TCLASS, cursp()));
       push();
@@ -2185,7 +2205,7 @@ codegen(codegen_scope *s, node *tree, int val)
 
   case NODE_UNDEF:
     {
-      int undef = new_msym(s, mrb_intern(s->mrb, "undef_method"));
+      int undef = new_msym(s, mrb_intern2(s->mrb, "undef_method", 12));
       int num = 0;
       node *t = tree;
 
index b65ff21..7cb6b53 100644 (file)
@@ -44,7 +44,7 @@ exc_initialize(mrb_state *mrb, mrb_value exc)
   mrb_value mesg;
 
   if (mrb_get_args(mrb, "|o", &mesg) == 1) {
-    mrb_iv_set(mrb, exc, mrb_intern(mrb, "mesg"), mesg);
+    mrb_iv_set(mrb, exc, mrb_intern2(mrb, "mesg", 4), mesg);
   }
   return exc;
 }
@@ -73,7 +73,7 @@ exc_exception(mrb_state *mrb, mrb_value self)
   if (argc == 0) return self;
   if (mrb_obj_equal(mrb, self, a)) return self;
   exc = mrb_obj_clone(mrb, self);
-  mrb_iv_set(mrb, exc, mrb_intern(mrb, "mesg"), a);
+  mrb_iv_set(mrb, exc, mrb_intern2(mrb, "mesg", 4), a);
 
   return exc;
 }
@@ -89,7 +89,7 @@ exc_exception(mrb_state *mrb, mrb_value self)
 static mrb_value
 exc_to_s(mrb_state *mrb, mrb_value exc)
 {
-  mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern(mrb, "mesg"));
+  mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "mesg", 4));
 
   if (mrb_nil_p(mesg)) return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
   return mesg;
@@ -123,9 +123,9 @@ exc_inspect(mrb_state *mrb, mrb_value exc)
 {
   mrb_value str, mesg, file, line;
 
-  mesg = mrb_attr_get(mrb, exc, mrb_intern(mrb, "mesg"));
-  file = mrb_attr_get(mrb, exc, mrb_intern(mrb, "file"));
-  line = mrb_attr_get(mrb, exc, mrb_intern(mrb, "line"));
+  mesg = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "mesg", 4));
+  file = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "file", 4));
+  line = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "line", 4));
 
   if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
     str = file;
@@ -161,7 +161,7 @@ exc_equal(mrb_state *mrb, mrb_value exc)
   mrb_value obj;
   mrb_value mesg;
   mrb_bool equal_p;
-  mrb_sym id_mesg = mrb_intern(mrb, "mesg");
+  mrb_sym id_mesg = mrb_intern2(mrb, "mesg", 4);
 
   mrb_get_args(mrb, "o", &obj);
   if (mrb_obj_equal(mrb, exc, obj)) {
@@ -169,7 +169,7 @@ exc_equal(mrb_state *mrb, mrb_value exc)
   }
   else {
     if (mrb_obj_class(mrb, exc) != mrb_obj_class(mrb, obj)) {
-      if (mrb_respond_to(mrb, obj, mrb_intern(mrb, "message"))) {
+      if (mrb_respond_to(mrb, obj, mrb_intern2(mrb, "message", 7))) {
         mesg = mrb_funcall(mrb, obj, "message", 0);
       }
       else
@@ -191,15 +191,15 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
   mrb_callinfo *ci = mrb->ci;
   mrb_code *pc = ci->pc;
 
-  mrb_obj_iv_set(mrb, exc, mrb_intern(mrb, "ciidx"), mrb_fixnum_value(ci - mrb->cibase));
+  mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "ciidx", 5), mrb_fixnum_value(ci - mrb->cibase));
   ci--;
   while (ci >= mrb->cibase) {
     if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
       mrb_irep *irep = ci->proc->body.irep;
 
       if (irep->filename && irep->lines && irep->iseq <= pc && pc < irep->iseq + irep->ilen) {
-        mrb_obj_iv_set(mrb, exc, mrb_intern(mrb, "file"), mrb_str_new_cstr(mrb, irep->filename));
-        mrb_obj_iv_set(mrb, exc, mrb_intern(mrb, "line"), mrb_fixnum_value(irep->lines[pc - irep->iseq - 1]));
+        mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "file", 4), mrb_str_new_cstr(mrb, irep->filename));
+        mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "line", 4), mrb_fixnum_value(irep->lines[pc - irep->iseq - 1]));
         return;
       }
     }
@@ -335,7 +335,7 @@ mrb_bug_errno(const char *mesg, int errno_arg)
 int
 sysexit_status(mrb_state *mrb, mrb_value err)
 {
-  mrb_value st = mrb_iv_get(mrb, err, mrb_intern(mrb, "status"));
+  mrb_value st = mrb_iv_get(mrb, err, mrb_intern2(mrb, "status", 6));
   return mrb_fixnum(st);
 }
 
@@ -373,7 +373,7 @@ make_exception(mrb_state *mrb, int argc, mrb_value *argv, int isstr)
       n = 1;
 exception_call:
       {
-        mrb_sym exc = mrb_intern(mrb, "exception");
+        mrb_sym exc = mrb_intern2(mrb, "exception", 9);
         if (mrb_respond_to(mrb, argv[0], exc)) {
           mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
         }
index 262c713..6976530 100644 (file)
@@ -262,7 +262,7 @@ mrb_hash_init_core(mrb_state *mrb, mrb_value hash)
     RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT;
     ifnone = block;
   }
-  mrb_iv_set(mrb, hash, mrb_intern(mrb, "ifnone"), ifnone);
+  mrb_iv_set(mrb, hash, mrb_intern2(mrb, "ifnone", 6), ifnone);
   return hash;
 }
 
@@ -427,7 +427,7 @@ mrb_hash_set_default(mrb_state *mrb, mrb_value hash)
 
   mrb_get_args(mrb, "o", &ifnone);
   mrb_hash_modify(mrb, hash);
-  mrb_iv_set(mrb, hash, mrb_intern(mrb, "ifnone"), ifnone);
+  mrb_iv_set(mrb, hash, mrb_intern2(mrb, "ifnone", 6), ifnone);
   RHASH(hash)->flags &= ~(MRB_HASH_PROC_DEFAULT);
 
   return ifnone;
@@ -478,7 +478,7 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash)
 
   mrb_get_args(mrb, "o", &ifnone);
   mrb_hash_modify(mrb, hash);
-  mrb_iv_set(mrb, hash, mrb_intern(mrb, "ifnone"), ifnone);
+  mrb_iv_set(mrb, hash, mrb_intern2(mrb, "ifnone", 6), ifnone);
   RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT;
 
   return ifnone;
@@ -759,7 +759,7 @@ mrb_hash_replace(mrb_state *mrb, mrb_value hash)
   else {
     ifnone = RHASH_IFNONE(hash2);
   }
-  mrb_iv_set(mrb, hash, mrb_intern(mrb, "ifnone"), ifnone);
+  mrb_iv_set(mrb, hash, mrb_intern2(mrb, "ifnone", 6), ifnone);
 
   return hash;
 }
@@ -1104,7 +1104,7 @@ hash_equal(mrb_state *mrb, mrb_value hash1, mrb_value hash2, int eql)
 
   if (mrb_obj_equal(mrb, hash1, hash2)) return mrb_true_value();
   if (!mrb_hash_p(hash2)) {
-      if (!mrb_respond_to(mrb, hash2, mrb_intern(mrb, "to_hash"))) {
+      if (!mrb_respond_to(mrb, hash2, mrb_intern2(mrb, "to_hash", 7))) {
           return mrb_false_value();
       }
       if (eql)
index 66bd7b2..0c746d9 100644 (file)
@@ -29,7 +29,7 @@ typedef enum {
 int
 mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
 {
-    struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern(mrb, "to_s"));
+    struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern2(mrb, "to_s", 4));
     if (me && MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s))
       return TRUE;
     return FALSE;
@@ -283,7 +283,7 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj)
     clone->super = klass->super;
     if (klass->iv) {
       mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass));
-      mrb_obj_iv_set(mrb, (struct RObject*)clone, mrb_intern(mrb, "__attached__"), obj);
+      mrb_obj_iv_set(mrb, (struct RObject*)clone, mrb_intern2(mrb, "__attached__", 12), obj);
     }
     if (klass->mt) {
       clone->mt = kh_copy(mt, mrb, klass->mt);
@@ -928,7 +928,7 @@ mrb_f_raise(mrb_state *mrb, mrb_value self)
     /* fall through */
   default:
     exc = mrb_make_exception(mrb, argc, a);
-    mrb_obj_iv_set(mrb, mrb_obj_ptr(exc), mrb_intern(mrb, "lastpc"), mrb_voidp_value(mrb->ci->pc));
+    mrb_obj_iv_set(mrb, mrb_obj_ptr(exc), mrb_intern2(mrb, "lastpc", 6), mrb_voidp_value(mrb->ci->pc));
     mrb_exc_raise(mrb, exc);
     break;
   }
index 4f9db82..df27c43 100644 (file)
@@ -65,6 +65,8 @@ enum node_type {
     NODE_SYM,
     NODE_STR,
     NODE_DSTR,
+    NODE_XSTR,
+    NODE_DXSTR,
     NODE_REGX,
     NODE_DREGX,
     NODE_DREGX_ONCE,
index 8f1241d..29ea34c 100644 (file)
@@ -61,13 +61,27 @@ typedef unsigned int stack_type;
 #define sym(x) ((mrb_sym)(intptr_t)(x))
 #define nsym(x) ((node*)(intptr_t)(x))
 
-static mrb_sym
+static inline mrb_sym
 intern_gen(parser_state *p, const char *s)
 {
   return mrb_intern(p->mrb, s);
 }
 #define intern(s) intern_gen(p,(s))
 
+static inline mrb_sym
+intern_gen2(parser_state *p, const char *s, size_t len)
+{
+  return mrb_intern2(p->mrb, s, len);
+}
+#define intern2(s,len) intern_gen2(p,(s),(len))
+
+static inline mrb_sym
+intern_gen_c(parser_state *p, const char c)
+{
+  return mrb_intern2(p->mrb, &c, 1);
+}
+#define intern_c(c) intern_gen_c(p,(c))
+
 static void
 cons_free_gen(parser_state *p, node *cons)
 {
@@ -702,6 +716,20 @@ new_dstr(parser_state *p, node *a)
   return cons((node*)NODE_DSTR, a);
 }
 
+// (:str . (s . len))
+static node*
+new_xstr(parser_state *p, const char *s, int len)
+{
+  return cons((node*)NODE_XSTR, cons((node*)strndup(s, len), (node*)(intptr_t)len));
+}
+
+// (:xstr . a)
+static node*
+new_dxstr(parser_state *p, node *a)
+{
+  return cons((node*)NODE_DXSTR, a);
+}
+
 // (:dsym . a)
 static node*
 new_dsym(parser_state *p, node *a)
@@ -974,12 +1002,12 @@ heredoc_end(parser_state *p)
        keyword__ENCODING__
 
 %token <id>  tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
-%token <nd>  tINTEGER tFLOAT tCHAR tREGEXP
+%token <nd>  tINTEGER tFLOAT tCHAR tXSTRING tREGEXP
 %token <nd>  tSTRING tSTRING_PART tSTRING_MID
 %token <nd>  tNTH_REF tBACK_REF
 %token <num> tREGEXP_END
 
-%type <nd> singleton string string_rep string_interp regexp
+%type <nd> singleton string string_rep string_interp xstring regexp
 %type <nd> literal numeric cpath symbol
 %type <nd> top_compstmt top_stmts top_stmt
 %type <nd> bodystmt compstmt stmts stmt expr arg primary command command_call method_call
@@ -1028,7 +1056,7 @@ heredoc_end(parser_state *p)
 %token tAMPER             /* & */
 %token tLAMBDA            /* -> */
 %token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG
-%token tSTRING_BEG tSTRING_DVAR tLAMBEG
+%token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG
 %token <nd> tHEREDOC_BEG  /* <<, <<- */
 %token tHEREDOC_END tLITERAL_DELIM
 
@@ -1214,7 +1242,7 @@ stmt              : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym
                    }
                | primary_value '[' opt_call_args rbracket tOP_ASGN command_call
                    {
-                     $$ = new_op_asgn(p, new_call(p, $1, intern("[]"), $3), $5, $6);
+                     $$ = new_op_asgn(p, new_call(p, $1, intern2("[]",2), $3), $5, $6);
                    }
                | primary_value '.' tIDENTIFIER tOP_ASGN command_call
                    {
@@ -1453,7 +1481,7 @@ mlhs_node : variable
                    }
                | primary_value '[' opt_call_args rbracket
                    {
-                     $$ = new_call(p, $1, intern("[]"), $3);
+                     $$ = new_call(p, $1, intern2("[]",2), $3);
                    }
                | primary_value '.' tIDENTIFIER
                    {
@@ -1492,7 +1520,7 @@ lhs               : variable
                    }
                | primary_value '[' opt_call_args rbracket
                    {
-                     $$ = new_call(p, $1, intern("[]"), $3);
+                     $$ = new_call(p, $1, intern2("[]",2), $3);
                    }
                | primary_value '.' tIDENTIFIER
                    {
@@ -1575,34 +1603,35 @@ undef_list      : fsym
                    }
                ;
 
-op             : '|'           { $$ = intern("|"); }
-               | '^'           { $$ = intern("^"); }
-               | '&'           { $$ = intern("&"); }
-               | tCMP          { $$ = intern("<=>"); }
-               | tEQ           { $$ = intern("=="); }
-               | tEQQ          { $$ = intern("==="); }
-               | tMATCH        { $$ = intern("=~"); }
-               | tNMATCH       { $$ = intern("!~"); }
-               | '>'           { $$ = intern(">"); }
-               | tGEQ          { $$ = intern(">="); }
-               | '<'           { $$ = intern("<"); }
-               | tLEQ          { $$ = intern("<="); }
-               | tNEQ          { $$ = intern("!="); }
-               | tLSHFT        { $$ = intern("<<"); }
-               | tRSHFT        { $$ = intern(">>"); }
-               | '+'           { $$ = intern("+"); }
-               | '-'           { $$ = intern("-"); }
-               | '*'           { $$ = intern("*"); }
-               | tSTAR         { $$ = intern("*"); }
-               | '/'           { $$ = intern("/"); }
-               | '%'           { $$ = intern("%"); }
-               | tPOW          { $$ = intern("**"); }
-               | '!'           { $$ = intern("!"); }
-               | '~'           { $$ = intern("~"); }
-               | tUPLUS        { $$ = intern("+@"); }
-               | tUMINUS       { $$ = intern("-@"); }
-               | tAREF         { $$ = intern("[]"); }
-               | tASET         { $$ = intern("[]="); }
+op             : '|'           { $$ = intern_c('|'); }
+               | '^'           { $$ = intern_c('^'); }
+               | '&'           { $$ = intern_c('&'); }
+               | tCMP          { $$ = intern2("<=>",3); }
+               | tEQ           { $$ = intern2("==",2); }
+               | tEQQ          { $$ = intern2("===",3); }
+               | tMATCH        { $$ = intern2("=~",2); }
+               | tNMATCH       { $$ = intern2("!~",2); }
+               | '>'           { $$ = intern_c('>'); }
+               | tGEQ          { $$ = intern2(">=",2); }
+               | '<'           { $$ = intern_c('<'); }
+               | tLEQ          { $$ = intern2("<=",2); }
+               | tNEQ          { $$ = intern2("!=",2); }
+               | tLSHFT        { $$ = intern2("<<",2); }
+               | tRSHFT        { $$ = intern2(">>",2); }
+               | '+'           { $$ = intern_c('+'); }
+               | '-'           { $$ = intern_c('-'); }
+               | '*'           { $$ = intern_c('*'); }
+               | tSTAR         { $$ = intern_c('*'); }
+               | '/'           { $$ = intern_c('/'); }
+               | '%'           { $$ = intern_c('%'); }
+               | tPOW          { $$ = intern2("**",2); }
+               | '!'           { $$ = intern_c('!'); }
+               | '~'           { $$ = intern_c('~'); }
+               | tUPLUS        { $$ = intern2("+@",2); }
+               | tUMINUS       { $$ = intern2("-@",2); }
+               | tAREF         { $$ = intern2("[]",2); }
+               | tASET         { $$ = intern2("[]=",3); }
+               | '`'           { $$ = intern_c('`'); }
                ;
 
 reswords       : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__
@@ -1637,7 +1666,7 @@ arg               : lhs '=' arg
                    }
                | primary_value '[' opt_call_args rbracket tOP_ASGN arg
                    {
-                     $$ = new_op_asgn(p, new_call(p, $1, intern("[]"), $3), $5, $6);
+                     $$ = new_op_asgn(p, new_call(p, $1, intern2("[]",2), $3), $5, $6);
                    }
                | primary_value '.' tIDENTIFIER tOP_ASGN arg
                    {
@@ -1936,6 +1965,7 @@ mrhs              : args ',' arg_value
 
 primary                : literal
                | string
+               | xstring
                | regexp
                | heredoc
                | var_ref
@@ -2445,11 +2475,11 @@ method_call     : operation paren_args
                    }
                | primary_value '.' paren_args
                    {
-                     $$ = new_call(p, $1, intern("call"), $3);
+                     $$ = new_call(p, $1, intern2("call",4), $3);
                    }
                | primary_value tCOLON2 paren_args
                    {
-                     $$ = new_call(p, $1, intern("call"), $3);
+                     $$ = new_call(p, $1, intern2("call",4), $3);
                    }
                | keyword_super paren_args
                    {
@@ -2461,7 +2491,7 @@ method_call       : operation paren_args
                    }
                | primary_value '[' opt_call_args rbracket
                    {
-                     $$ = new_call(p, $1, intern("[]"), $3);
+                     $$ = new_call(p, $1, intern2("[]",2), $3);
                    }
                ;
 
@@ -2585,6 +2615,16 @@ string_interp    : tSTRING_MID
                    }
                ;
 
+xstring                : tXSTRING_BEG tXSTRING
+                   {
+                       $$ = $2;
+                   }
+               | tXSTRING_BEG string_rep tXSTRING
+                   {
+                     $$ = new_dxstr(p, push($2, $3));
+                   }
+               ;
+
 regexp         : tREGEXP_BEG tREGEXP
                    {
                        $$ = $2;
@@ -2985,6 +3025,8 @@ singleton : var_ref
                        switch ((enum node_type)(int)(intptr_t)$3->car) {
                        case NODE_STR:
                        case NODE_DSTR:
+                       case NODE_XSTR:
+                       case NODE_DXSTR:
                        case NODE_DREGX:
                        case NODE_MATCH:
                        case NODE_FLOAT:
@@ -3314,7 +3356,7 @@ newtok(parser_state *p)
 static void
 tokadd(parser_state *p, int c)
 {
-  if (p->bidx < 1024) {
+  if (p->bidx < MRB_PARSER_BUF_SIZE) {
     p->buf[p->bidx++] = c;
   }
 }
@@ -3328,7 +3370,7 @@ toklast(parser_state *p)
 static void
 tokfix(parser_state *p)
 {
-  if (p->bidx >= 1024) {
+  if (p->bidx >= MRB_PARSER_BUF_SIZE) {
     yyerror(p, "string too long (truncated)");
   }
   p->buf[p->bidx] = '\0';
@@ -3641,6 +3683,11 @@ parse_string(parser_state *p)
   p->lstate = EXPR_END;
   end_strterm(p);
 
+  if (type & STR_FUNC_XQUOTE) {
+    yylval.nd = new_xstr(p, tok(p), toklen(p));
+    return tXSTRING;
+  }
+
   if (type & STR_FUNC_REGEXP) {
     int f = 0;
     int c;
@@ -3840,7 +3887,7 @@ parser_yylex(parser_state *p)
   case '*':
     if ((c = nextc(p)) == '*') {
       if ((c = nextc(p)) == '=') {
-       yylval.id = intern("**");
+       yylval.id = intern2("**",2);
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
       }
@@ -3849,7 +3896,7 @@ parser_yylex(parser_state *p)
     }
     else {
       if (c == '=') {
-       yylval.id = intern("*");
+       yylval.id = intern_c('*');
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
       }
@@ -3949,7 +3996,7 @@ parser_yylex(parser_state *p)
     }
     if (c == '<') {
       if ((c = nextc(p)) == '=') {
-       yylval.id = intern("<<");
+       yylval.id = intern2("<<",2);
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
       }
@@ -3970,7 +4017,7 @@ parser_yylex(parser_state *p)
     }
     if (c == '>') {
       if ((c = nextc(p)) == '=') {
-       yylval.id = intern(">>");
+       yylval.id = intern2(">>",2);
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
       }
@@ -3988,6 +4035,21 @@ parser_yylex(parser_state *p)
     p->lex_strterm = new_strterm(p, str_squote, '\'', 0);
     return parse_string(p);
 
+  case '`':
+    if (p->lstate == EXPR_FNAME) {
+      p->lstate = EXPR_ENDFN;
+      return '`';
+    }
+    if (p->lstate == EXPR_DOT) {
+      if (cmd_state)
+        p->lstate = EXPR_CMDARG;
+      else
+        p->lstate = EXPR_ARG;
+      return '`';
+    }
+    p->lex_strterm = new_strterm(p, str_xquote, '`', 0);
+    return tXSTRING_BEG;
+
   case '?':
     if (IS_END()) {
       p->lstate = EXPR_VALUE;
@@ -4069,7 +4131,7 @@ parser_yylex(parser_state *p)
     if ((c = nextc(p)) == '&') {
       p->lstate = EXPR_BEG;
       if ((c = nextc(p)) == '=') {
-       yylval.id = intern("&&");
+       yylval.id = intern2("&&",2);
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
       }
@@ -4077,7 +4139,7 @@ parser_yylex(parser_state *p)
       return tANDOP;
     }
     else if (c == '=') {
-      yylval.id = intern("&");
+      yylval.id = intern_c('&');
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
     }
@@ -4103,7 +4165,7 @@ parser_yylex(parser_state *p)
     if ((c = nextc(p)) == '|') {
       p->lstate = EXPR_BEG;
       if ((c = nextc(p)) == '=') {
-       yylval.id = intern("||");
+       yylval.id = intern2("||",2);
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
       }
@@ -4111,7 +4173,7 @@ parser_yylex(parser_state *p)
       return tOROP;
     }
     if (c == '=') {
-      yylval.id = intern("|");
+      yylval.id = intern_c('|');
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
     }
@@ -4135,7 +4197,7 @@ parser_yylex(parser_state *p)
       return '+';
     }
     if (c == '=') {
-      yylval.id = intern("+");
+      yylval.id = intern_c('+');
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
     }
@@ -4163,7 +4225,7 @@ parser_yylex(parser_state *p)
       return '-';
     }
     if (c == '=') {
-      yylval.id = intern("-");
+      yylval.id = intern_c('-');
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
     }
@@ -4463,7 +4525,7 @@ parser_yylex(parser_state *p)
       return tREGEXP_BEG;
     }
     if ((c = nextc(p)) == '=') {
-      yylval.id = intern("/");
+      yylval.id = intern_c('/');
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
     }
@@ -4481,7 +4543,7 @@ parser_yylex(parser_state *p)
 
   case '^':
     if ((c = nextc(p)) == '=') {
-      yylval.id = intern("^");
+      yylval.id = intern_c('^');
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
     }
@@ -4628,6 +4690,10 @@ parser_yylex(parser_state *p)
        p->lex_strterm = new_strterm(p, str_sword, term, paren);
        return tWORDS_BEG;
 
+      case 'x':
+       p->lex_strterm = new_strterm(p, str_xquote, term, paren);
+       return tXSTRING_BEG;
+
       case 'r':
        p->lex_strterm = new_strterm(p, str_regexp, term, paren);
        return tREGEXP_BEG;
@@ -4650,7 +4716,7 @@ parser_yylex(parser_state *p)
       }
     }
     if ((c = nextc(p)) == '=') {
-      yylval.id = intern("%");
+      yylval.id = intern_c('%');
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
     }
@@ -5693,6 +5759,15 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
     dump_recur(mrb, tree, offset+1);
     break;
 
+  case NODE_XSTR:
+    printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr);
+    break;
+
+  case NODE_DXSTR:
+    printf("NODE_DXSTR\n");
+    dump_recur(mrb, tree, offset+1);
+    break;
+
   case NODE_REGX:
     printf("NODE_REGX /%s/%s\n", (char*)tree->car, (char*)tree->cdr);
     break;
index 8f16a4e..97d53cd 100644 (file)
@@ -532,10 +532,10 @@ mrb_str_cmp_m(mrb_state *mrb, mrb_value str1)
 
   mrb_get_args(mrb, "o", &str2);
   if (!mrb_string_p(str2)) {
-    if (!mrb_respond_to(mrb, str2, mrb_intern(mrb, "to_s"))) {
+    if (!mrb_respond_to(mrb, str2, mrb_intern2(mrb, "to_s", 4))) {
       return mrb_nil_value();
     }
-    else if (!mrb_respond_to(mrb, str2, mrb_intern(mrb, "<=>"))) {
+    else if (!mrb_respond_to(mrb, str2, mrb_intern2(mrb, "<=>", 3))) {
       return mrb_nil_value();
     }
     else {
@@ -572,7 +572,7 @@ mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2)
   if (mrb_obj_equal(mrb, str1, str2)) return TRUE;
   if (!mrb_string_p(str2)) {
     if (mrb_nil_p(str2)) return FALSE;
-    if (!mrb_respond_to(mrb, str2, mrb_intern(mrb, "to_str"))) {
+    if (!mrb_respond_to(mrb, str2, mrb_intern2(mrb, "to_str", 6))) {
       return FALSE;
     }
     str2 = mrb_funcall(mrb, str2, "to_str", 0);
index 6afc6b7..243cb4b 100644 (file)
@@ -62,7 +62,7 @@ mrb_intern2(mrb_state *mrb, const char *name, size_t len)
 }
 
 mrb_sym
-mrb_intern(mrb_state *mrb, const char *name)
+mrb_intern_cstr(mrb_state *mrb, const char *name)
 {
   return mrb_intern2(mrb, name, strlen(name));
 }
index 8509990..4345f49 100644 (file)
@@ -832,7 +832,7 @@ L_RETRY:
     goto L_RETRY;
   }
   c = base;
-  cm = mrb_intern(mrb, "const_missing");
+  cm = mrb_intern2(mrb, "const_missing", 13);
   while (c) {
     if (mrb_respond_to(mrb, mrb_obj_value(c), cm)) {
       mrb_value name = mrb_symbol_value(sym);
@@ -1047,7 +1047,7 @@ mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer)
 {
   mrb_value name;
 
-  name = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern(mrb, "__classid__"));
+  name = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern2(mrb, "__classid__", 11));
   if (mrb_nil_p(name)) {
 
     if (!outer) return 0;
index 9067183..c18054a 100644 (file)
--- a/src/vm.c
+++ b/src/vm.c
@@ -349,7 +349,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mr
     p = mrb_method_search_vm(mrb, &c, mid);
     if (!p) {
       undef = mid;
-      mid = mrb_intern(mrb, "method_missing");
+      mid = mrb_intern2(mrb, "method_missing", 14);
       p = mrb_method_search_vm(mrb, &c, mid);
       n++; argc++;
     }
@@ -869,7 +869,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
       if (!m) {
         mrb_value sym = mrb_symbol_value(mid);
 
-        mid = mrb_intern(mrb, "method_missing");
+        mid = mrb_intern2(mrb, "method_missing", 14);
         m = mrb_method_search_vm(mrb, &c, mid);
         if (n == CALL_MAXARGS) {
           mrb_ary_unshift(mrb, regs[a+1], sym);
@@ -1011,7 +1011,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
       c = mrb->ci->target_class->super;
       m = mrb_method_search_vm(mrb, &c, mid);
       if (!m) {
-        mid = mrb_intern(mrb, "method_missing");
+        mid = mrb_intern2(mrb, "method_missing", 14);
         m = mrb_method_search_vm(mrb, &c, mid);
         if (n == CALL_MAXARGS) {
           mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
@@ -1216,8 +1216,8 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
 
       L_RAISE:
         ci = mrb->ci;
-        mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern(mrb, "lastpc"), mrb_voidp_value(pc));
-        mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern(mrb, "ciidx"), mrb_fixnum_value(ci - mrb->cibase));
+        mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern2(mrb, "lastpc", 6), mrb_voidp_value(pc));
+        mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern2(mrb, "ciidx", 5), mrb_fixnum_value(ci - mrb->cibase));
         eidx = ci->eidx;
         if (ci == mrb->cibase) {
           if (ci->ridx == 0) goto L_STOP;
@@ -1333,7 +1333,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
       if (!m) {
         mrb_value sym = mrb_symbol_value(mid);
 
-        mid = mrb_intern(mrb, "method_missing");
+        mid = mrb_intern2(mrb, "method_missing", 14);
         m = mrb_method_search_vm(mrb, &c, mid);
         if (n == CALL_MAXARGS) {
           mrb_ary_unshift(mrb, regs[a+1], sym);