class Prototype
  def initialize
    @_method_list = {}
  end

  def _my_eval(*_str, &block)
    _s = (class << self; self; end)
    if block_given?
      _s.module_eval &block
    else
      _s.module_eval _str[0]
    end
  end

  def method_missing( _name, *_args)
    if _name.to_s =~ /([^=]+)=/ # 代入?
      _name_ = $1
      _my_eval %-
        def #{_name_}() @#{_name_} end
        def #{_name_}=(_val)
          if _val.kind_of? Proc
            @_method_list[ "#{_name_}" ] = _val
            _my_eval { define_method( :#{_name_}, _val) }
          else
            if @_method_list[ "#{_name_}" ]
              @_method_list[ "#{_name_}" ] = nil
              _my_eval { define_method( :#{_name_}) { @#{_name_}} }
            end
            @#{_name_} = _val
          end
        end
      -
      _x = _args
      _x = _args[0] if _x.kind_of? Array and _args.size==1
      send( _name, _x)  # _name_ = *_args
    else
      p "method_missing: #{_name.to_s}, #{_args}" if $DEBUG
      nil
    end
  end

  def get_method _name
    @_method_list[ _name ]
  end
end
a = Prototype.new

p a.x # => nil
a.x = 99
p a.x # => 99
a.x = "foo"
p a.x # => "foo"

p "---"
b = a.dup
b.y = "bar"
y = "global y"
b.x = lambda() { self.y }
   # selfがないと上のyを参照してしまう
p b.x # => "bar"
p a.x # => "foo"

p "---"
a.y = "buz"
a.x = b.get_method("x")
p a.x # => "buz"

javascriptのソースを移植するために作ってみたんだけれど,javascriptってこんな感じなの?


追記:dupじゃなくてcloneにしないと特異メソッドがコピーされない.なるほど.

俺言語暫定終了

rubyluaとcを足して3くらい右シフトしたやつ.

fun main()
{
  print( fact(5))    // => 120

  a = Point( 1, 2)

  a.pn()      // => 1, 2
  a.x = 4
  a["pn"]()   // => 4, 2

  c = a
  c.y = 99
  print( a.y) // => 99 書き換わってる…
}

fun Point(u,v)
{
  var obj = {.x = u, .y = v}
  obj.pn = fun { print(x); print(y) }
    // fun obj.pn {...} も fun obj["pn"] {...} も等価
  return obj
}

fun fact(n) { (n==0)? 1: n * fact(n-1) }

作ろうと思っていたものは大体出来たけど,達成感よりもまだやっと1合目かという気分.おかしいな.結構いい感じになるかと思ったんだけど.

コレクションを操作する命令/関数が全然ない所為か?eachとかmapとか

俺言語とセミコロン

セミコロンを省略できるようにと,パーサと悪戦苦闘をしたあげく,スキャナ側で不要な改行を削るようにしてみたのだが,どうにも上手くいかなかったので,RHGのパーサの部分を読んでみた.

スキャナで処理するところまではよかったのに,その後の爪が甘かったらしい.

基本的にはセミコロンを省いても動作するようになった.



いまのところ,カッコのバランスはみていないので

 a = (
  5 )        // ok: a = (5);と等価

 b = ((5
  + 2) * 3)  // ng: b = ((5; +2)*3); と解釈される

となってしまう.

'('は文の最後(の1つ前の終端記号)にならないので,改行はスキャナで削除されるけど,'5'は文の最後になりえるので,改行がパーサに渡されてしまう.

'('と対応する')'を数えれば式の途中であることは自明なので,改行を取り除くことが出来る…ということをrubyはやっているらしい.

四則演算とかのネット上によくあるパーサの説明と違って,本物のソースは勉強になる.

俺言語とクロージャ

ケース1:

fun main()
{
  var f;
  m = 1;
  {
    var m = 2;
    f = fun() {
      print( m);
      var m = 3;  // このmは無名関数のローカル変数
      print( m);
    };
  }
  f();       // => 2, 3
  print(m);  // => 1
}


ケース2:

fun main()
{
  var f;
  var m = 1;
  {
    f = fun() { print( m); };
    var m = 2;  // このmは無名関数と同じスコープ
  }
  f(); // => 2
}


ケース1は予想通りの挙動だけど,2が気持ち悪い.fに無名関数を代入している時点では,関数の中身を評価していないので,mが同じスコープに存在していないことを知らない.

俺言語

cで;いらなくね?とか構造体もデザイネータがあればいけるんじゃね?と行き当たりばったりに弄っていたら訳が分らなくなってきた.ちゃんと考えないと.

こんな感じになるといいなあ

a = { .x, .y }
a.x = 2         // セミコロン不要
a["y"] = 9      // ハッシュ?でもアクセス可能

// c/c++だとこんな感じ
struct Point { int x, y; };
Point a;
a.x = 2;
a.y = 9;

直近の暫定ゴールとしては,cのサブセット版に上記2つとクロージャがつけばいいか.

inject

class Array
  def sum()
    inject{|x,i| x+i }
  end
end

def f(n)
  n % 7
end

def g(n)
# 3*f((1..7).inject{|x,k| x+k**n})
  3*f((1..7).map{|k| k**n}.sum)
end

p f(10) #=> 3
p g(6)  #=> 18

injectがいるのが気持ち悪く感じる体になってしまった.合計を求めるのに中間変数を見たくない.

とはいえ,これはさすがにやりすぎだと感じる.

class Array
  def sum(nodata=nil)
    return nodata if empty?
    return self[0] if size==1
    self[0] + self[1..-1].sum
  end
end

p [1,2,3,4].sum(0) #=> 10