Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Play with Rubys AST

makicamel
February 11, 2020

Play with Rubys AST

数学の勉強のために Ruby の構文木と遊んでいる話
2020.02.11. 大江戸 Ruby 会議 08

makicamel

February 11, 2020
Tweet

More Decks by makicamel

Other Decks in Programming

Transcript

  1. ਺ֶͷษڧͷͨΊʹ
    3VCZͷߏจ໦ͱ༡ΜͰ͍Δ࿩
    2020.2.11.
    େߐށRubyձٞ08
    @makicamel

    View full-size slide

  2. •@makicamel / ઒ݪສق

    •޷͖ͳ΋ͷ͸Ϗʔϧɹɹͱ͓ञ
    •ࠓ೥ޙ൒ͷ໨ඪ͸਺ֶͷษڧ
    ࣗݾ঺հ

    View full-size slide

  3. ࠓ೔͸ 2 ݄ 11 ೔

    View full-size slide

  4. •@makicamel / ઒ݪສق

    •޷͖ͳ΋ͷ͸Ϗʔϧɹɹͱ͓ञ
    •ࠓ೥ޙ൒ͷ໨ඪ͸਺ֶͷษڧ
    ࣗݾ঺հ

    View full-size slide

  5. •਺ֶͰͭ·ͮ͘ग़དྷࣄ͕૿͖͑ͯͨ
    •CRuby ࣮૷ͱ͔ Kernel Ϟδϡʔϧ (ΔΓ·) ͱ͔

    ϓϩάϥϛϯάͷجૅ (ຊ) ͱ͔
    •ෳૉ਺ͱ͔ྦྷ৐ͱ͔ 2 ࣍ํఔࣜͱ͔ղͷެࣜͱ͔
    •௥͍ͬͯͨίʔυɾຊ్͕੾Εͯ͠·͏ͷ΋͍ͬͨͳ͍
    •ۤखҙࣝΛࠀ෰ͨ͠Β΋ͬͱָ͘͠ͳΓͦ͏
    ͳͥ਺ֶʁ

    View full-size slide

  6. 2 ࣍ํఔࣜ ͷ܎਺ 

    (͍ͣΕ΋࣮਺ͱ͢Δ) Λ༩͑ΒΕͨΒɺ

    ൑ผࣜͷ஋Λฦؔ͢਺ Λ

    σβΠϯϨγϐ※
    ʹ͕ͨͬͯ͠࡞Εɻ

    ͜͜Ͱ ͸ Ͱ͸ͳ͍ͱԾఆͯ͠Α͍ɻ
    ax2 + bx + c = 0 a, b, c
    hanbetsushiki
    a 0
    ϓϩάϥϛϯάͷجૅ $PNQVUFS4DJFODF-JCSBSZ

    ୈষؔ਺ͷఆٛcઙҪ݈Ұ

    IUUQTXXXBNB[PODPKQEQ
    ˞σβΠϯϨγϐͱ͸͜ͷຊͰఏএ͞Ε͍ͯΔɺϓϩάϥϜ࡞੒࣌ʹ͕ͨ͠͏΂͖ࢦ਑ͷ͜ͱ

    ͨͱ͑͹ʁ

    View full-size slide

  7. ɹɹɹɹɹɹɹɹ ͡Όͳͯ͘ɹɹɹɹ ͬͯॻ͖͍ͨ
    ͨͱ͑͹ʁ
    •൑ผࣜ
    •ํఔࣜ ʹରͯ͠ ͷ͜ͱ
    •Ruby Ͱॻ͘ͱ
    •௕͍
    •΋͏গ͠਺ࣜͬΆ͘ॻ͖͍ͨ
    ax2 + bx + c b2 − 4ac
    b ** 2 - 4 * a * c
    4 * a * c 4 a c

    View full-size slide

  8. Α͠ɺ࡞Ζ͏

    View full-size slide

  9. ࡞ͬͨ ͯΔ
    NBUI@QBSTFSNBLJDBNFMNBUI@QBSTFSc(JU)VC

    IUUQTHJUIVCDPNNBLJDBNFMNBUI@QBSTFS

    View full-size slide

  10. ࣮૷ํ਑
    •ͦ΋ͦ΋ɹɹɹɹ ͬͯॻ͘ͱͲ͏ͳΔ͔
    •γϯλοΫεΤϥʔ
    •Ϧςϥϧɾม਺͸ۭനจࣈ۠੾ΓͰฒ΂ΒΕͳ͍※
    •਺஋ͷޙʹ͓͚Δͷ͸ɹɹΈ͍ͨͳԋࢉࢠͳͲ
    4 a c
    ˞BMJBTΩʔϫʔυ΍ه๏ͱ͍ͬͨྫ֎͕͋Γ·͢
    *

    View full-size slide

  11. ࣮૷ํ਑
    •ͦ΋ͦ΋ɹɹɹɹ ͬͯॻ͘ͱͲ͏ͳΔ͔
    •γϯλοΫεΤϥʔ
    •Ϧςϥϧɾม਺͸ۭനจࣈ۠੾ΓͰฒ΂ΒΕͳ͍※
    •਺஋ͷޙʹ͓͚Δͷ͸ɹɹΈ͍ͨͳԋࢉࢠͳͲ
    4 a c
    ˞BMJBTΩʔϫʔυ΍ه๏ͱ͍ͬͨྫ֎͕͋Γ·͢
    *

    View full-size slide

  12. ࣮૷ํ਑
    Ruby ϓϩάϥϜͷ

    ߏจղੳΛ͢Δ

    View full-size slide

  13. ࣮૷ํ਑
    ɹRuby Ͱͭ͘Δ Ruby ͓΋͠Ζ͔ͬͨͰ͢Αʂ
    @neko314_

    View full-size slide

  14. Ruby Ͱͭ͘Δ Ruby
    •ԕ౻ (@mame) ͞Μͷஶ࡞
    •ʮRuby Ͱ Ruby Λ࡞Γͳ͕ΒRuby
    ΛֶͿʯຊ
    •Ruby Ͱ Ruby ΠϯλʔϓϦλΛ࡞Δ
    3VCZͰͭ͘Δ3VCZθϩ͔Βֶͼͳ͓͢ϓϩάϥϛϯάݴޠೖ໳cԕ౻ါհ

    IUUQTXXXMBNCEBOPUFDPNQSPEVDUTSVCZSVCZ
    ղઆ΋Θ͔Γ΍ͯ͘͢

    ֆ΋͔Θ͍ͯ͘ͱͯ΋ͨͷ͍͠

    View full-size slide

  15. ࣈ۟ղੳ
    ߏจղੳ
    ࣮ߦʢܭࢉʣ
    Ruby Ͱͭ͘Δ Ruby

    View full-size slide

  16. ࣈ۟ղੳ
    •ɹɹɹɹɹɹ ͱ͍͏ Ruby ϓϩάϥϜ͸
    4 * a * c
    def hello; "World"; end
    def hello ; “ World " ; end
    ࣈ۟ = Token (τʔΫϯ)
    4 * a * c
    ɹɹͱ͍͏ࣈ۟ʹ෼͚ΒΕΔ
    •ɹɹɹɹɹɹɹɹɹɹɹɹɹɹͱ͍͏ Ruby ϓϩάϥϜ͸
    ɹɹͱ͍͏ࣈ۟ʹ෼͚ΒΕΔ

    View full-size slide

  17. ࣈ۟ղੳ
    •ࣈ۟Λղੳͯ͠ҙຯ͚ͮ͢Δ
    •਺஋ɺԋࢉࢠɺจࣈྻɺࣝผࢠͳͲͳͲ
    •ࣈ۟ղੳ = Tokenize (τʔΫφΠζ)
    4 * a * c
    ਺஋ ԋࢉࢠ ԋࢉࢠ
    ࣝผࢠ ࣝผࢠ

    View full-size slide

  18. ߏจղੳ
    •ਓ͕ؒɹɹɹ
    4 * a * c
    4 * a * c ΛಡΉ࣌

    View full-size slide

  19. ߏจղੳ
    •ΠϯλʔϓϦλ͕ɹɹɹɹɹɹɹΛಡΉ࣌
    4 * a * c

    View full-size slide

  20. ߏจղੳ
    •ΠϯλʔϓϦλ͕ɹɹɹɹɹΛಡΉ࣌
    *
    4 * a
    4 * a

    View full-size slide

  21. ߏจղੳ
    •ΠϯλʔϓϦλ͕ɹɹɹɹɹɹɹΛಡΉ࣌
    *
    4 *
    a * c
    ൓స
    4 * a * c

    View full-size slide

  22. ߏจղੳ
    •ΠϯλʔϓϦλ͕ɹɹɹɹɹɹɹΛಡΉ࣌
    4 * *
    *
    a * c
    ߏจ໦
    4 * a * c

    View full-size slide

  23. ߏจղੳ
    •ΠϯλʔϓϦλ͕ɹɹɹɹɹɹɹΛಡΉ࣌
    4 * *
    *
    a * c
    4 * a * c
    •ߏจ໦ʹม׵͢Δ͜ͱ = ߏจղੳ = Parse
    •ղੳͷ్தͰਖ਼͍͠ߏจ͔νΣοΫ͢Δ

    View full-size slide

  24. ߏจղੳ
    ͜Μͳߏจ໦͕ಘΒΕͨ࣌ʹɹɹΛೖΕͨΒ͍͚ΔͷͰ͸…ʂʂ
    *
    4
    a

    View full-size slide

  25. ࣮૷ํ਑
    •ͦ΋ͦ΋ɹɹɹɹ ͬͯॻ͘ͱͲ͏ͳΔ͔
    •γϯλοΫεΤϥʔ
    •Ϧςϥϧɾม਺͸ۭനจࣈ۠੾ΓͰฒ΂ΒΕͳ͍※
    •਺஋ͷޙʹ͓͚Δͷ͸ɹɹΈ͍ͨͳԋࢉࢠͳͲ
    4 a c
    ˞BMJBTΩʔϫʔυ΍ه๏ͱ͍ͬͨྫ֎͕͋Γ·͢
    *

    View full-size slide

  26. ߏจղੳ
    ͜Μͳߏจ໦͕ಘΒΕͨ࣌ʹɹɹΛೖΕͨΒ͍͚ΔͷͰ͸…ʂʂ
    *
    4
    a

    ͜Μͳߏจ໦͸ଘࡏ͠ͳ͍

    View full-size slide

  27. ߏจղੳ
    •ɹɹɹɹɹɹͱ͍͏τʔΫϯ͕࿈ଓͯ͠ݱΕͨΒ
    ɹɹɹΛૠೖͯ͠ฦ͢
    4 a
    ਺஋ ࣝผࢠ
    *

    View full-size slide

  28. Ripper.lex
    TJOHMFUPONFUIPE3JQQFSMFYc3VCZϦϑΝϨϯεϚχϡΞϧ

    IUUQTEPDTSVCZMBOHPSHKBNFUIPE3JQQFSTMFYIUNM

    View full-size slide

  29. Ripper.lex
    Ripper.lex('4 * a')
    # => [[[1, 0], :on_int, "4", END],
    # [[1, 1], :on_sp, " ", END],
    # [[1, 2], :on_op, "*", BEG],
    # [[1, 3], :on_sp, " ", BEG],
    # [[1, 4], :on_ident, "a", ARG]]
    Ґஔ৘ใ

    View full-size slide

  30. Ripper.lex
    Ripper.lex('4 * a')
    # => [[[1, 0], :on_int, "4", END],
    # [[1, 1], :on_sp, " ", END],
    # [[1, 2], :on_op, "*", BEG],
    # [[1, 3], :on_sp, " ", BEG],
    # [[1, 4], :on_ident, "a", ARG]]
    ੔਺
    ۭനจࣈ
    ԋࢉࢠ
    ࣝผࢠ

    View full-size slide

  31. Ripper.lex
    Ripper.lex('4 * a')
    # => [[[1, 0], :on_int, "4", END],
    # [[1, 1], :on_sp, " ", END],
    # [[1, 2], :on_op, "*", BEG],
    # [[1, 3], :on_sp, " ", BEG],
    # [[1, 4], :on_ident, "a", ARG]]
    τʔΫϯจࣈྻ

    View full-size slide

  32. Ripper.lex
    Ripper.lex('4 * a')
    # => [[[1, 0], :on_int, "4", END],
    # [[1, 1], :on_sp, " ", END],
    # [[1, 2], :on_op, "*", BEG],
    # [[1, 3], :on_sp, " ", BEG],
    # [[1, 4], :on_ident, "a", ARG]]
    State

    View full-size slide

  33. Ripper::Lexer::State
    Ripper::Lexer.constants.select do |constant|
    constant.to_s.start_with? :EXPR.to_s
    end
    # => [
    :EXPR_NONE,
    :EXPR_BEG, :EXPR_END, :EXPR_ENDARG, :EXPR_ENDFN,
    :EXPR_ARG, :EXPR_CMDARG, :EXPR_MID, :EXPR_FNAME,
    :EXPR_DOT, :EXPR_CLASS, :EXPR_LABEL, :EXPR_LABELED,
    :EXPR_FITEM, :EXPR_VALUE,
    :EXPR_BEG_ANY, :EXPR_ARG_ANY, :EXPR_END_ANY
    ]
    •τʔΫϯͷ State

    View full-size slide

  34. class RDoc::Parser::RipperStateLex
    class InnerStateLex < Ripper::Filter
    private def on_variables(event, tok, data)
    if @in_fname
    @lex_state = EXPR_ENDFN
    @in_fname = false
    @continue = false
    elsif @continue
    case @lex_state
    when EXPR_DOT
    @lex_state = EXPR_ARG
    else
    @lex_state = EXPR_ENDFN
    @continue = false
    end
    else
    @lex_state = EXPR_CMDARG
    end
    data << Token.new(lineno, column, event, tok, @lex_state)
    end
    # ...
    end
    •ϓϩάϥϜͷͲ͜ʹ͋Δ͔ʹΑͬͯState͕มԽ͢Δ

    View full-size slide

  35. ܭࢉͷ࣮ߦ
    def evaluate(tree, genv, lenv)
    case tree[0]
    when "lit"
    tree[1]
    when "+"
    evaluate(tree[1], genv, lenv) + evaluate(tree[2], genv, lenv)
    when "-"
    evaluate(tree[1], genv, lenv) - evaluate(tree[2], genv, lenv)
    when "*"
    evaluate(tree[1], genv, lenv) * evaluate(tree[2], genv, lenv)
    when "/"
    evaluate(tree[1], genv, lenv) / evaluate(tree[2], genv, lenv)
    when "**"
    evaluate(tree[1], genv, lenv)**evaluate(tree[2], genv, lenv)
    when "%"
    evaluate(tree[1], genv, lenv) % evaluate(tree[2], genv, lenv)
    when "<"
    evaluate(tree[1], genv, lenv) < evaluate(tree[2], genv, lenv)
    when "<="
    evaluate(tree[1], genv, lenv) <= evaluate(tree[2], genv, lenv)
    when ">"
    # ...
    3VCZͰͭ͘Δ3VCZθϩ͔Βֶͼͳ͓͢ϓϩάϥϛϯάݴޠೖ໳cԕ౻ါհ

    IUUQTXXXMBNCEBOPUFDPNQSPEVDUTSVCZSVCZ

    View full-size slide

  36. खॱ
    1. Ripper ʹ͔͚ͯߏจղੳ͕Ͱ͖Δ͔νΣοΫ
    2. Ͱ͖ͳ͚Ε͹਺஋ͱม਺͕ฒΜͰ͍ΔจࣈྻΛ୳͢
    3. ਺஋ͱม਺ͷؒʹ * Λૠೖͯ͠ฦ͢
    4. 1 ʙ 3 ͷ܁Γฦ͠
    5. * ͕ૠೖ͞Εͨߏจ໦Λ࣮ߦ (ܭࢉ) ͢Δ
    ※ ߏจղੳ͸

    Ruby Ͱͭ͘Δ Ruby ͷิॿϥΠϒϥϦ

    minrubyΛ࢖͍·͢
    NJOSVCZNBNFNJOSVCZc(JU)VC

    IUUQTHJUIVCDPNNBNFNJOSVCZ

    View full-size slide

  37. खॱ
    1. Ripper ʹ͔͚ͯߏจղੳ͕Ͱ͖Δ͔νΣοΫ
    2. Ͱ͖ͳ͚Ε͹਺஋ͱม਺͕ฒΜͰ͍ΔจࣈྻΛ୳͢
    3. ਺஋ͱม਺ͷؒʹ * Λૠೖͯ͠ฦ͢
    4. 1 ʙ 3 ͷ܁Γฦ͠
    5. * ͕ૠೖ͞Εͨߏจ໦Λ࣮ߦ (ܭࢉ) ͢Δ
    NJOSVCZNBNFNJOSVCZc(JU)VC

    IUUQTHJUIVCDPNNBNFNJOSVCZ

    View full-size slide

  38. Ripper.sexp('4 * a')
    # => [:program,
    # [[:binary,
    # [:@int, "4", [1, 0]],
    # :*,
    # [:vcall, [:@ident, "a", [1, 4]]]]]]
    Ripper.sexp
    program͔Β࢝·ΔϦετ
    ೋ෼໦
    ਺஋Ϧςϥϧ
    ৐ࢉԋࢉࢠ
    ࣝผࢠ

    View full-size slide

  39. Ripper.sexp('4 a')
    # => nil
    Ripper.sexp

    View full-size slide

  40. Ripper.sexp
    class Ripper
    def Ripper.sexp(src, filename = '-', lineno = 1)
    builder = SexpBuilderPP.new(src, filename, lineno)
    sexp = builder.parse
    sexp unless builder.error?
    end
    # ...
    end
    DMBTT3JQQFSSVCZSVCZc(JU)VC

    IUUQTHJUIVCDPNSVCZSVCZCMPCGBCFYUSJQQFSMJCSJQQFSTFYQSC

    View full-size slide

  41. ߏจղੳνΣοΫ
    1. Ripper ʹ͔͚ͯߏจղੳ͕Ͱ͖Δ͔νΣοΫ
    module MathParser
    class MathRubyParser < MinRubyParser
    def mathruby_parse(program)
    converted_program = Ripper.sexp(program) ?
    program : reparse(program.strip)
    simplify(Ripper.sexp(converted_program))
    end
    # ...
    end
    end

    View full-size slide

  42. τʔΫϯνΣοΫ
    2. Ͱ͖ͳ͚Ε͹਺஋ͱม਺͕ฒΜͰ͍ΔจࣈྻΛ୳͢
    module MathParser::Converter
    def reparse(program)
    tokens = Ripper.lex(program)
    converted_program = convert(tokens)
    original_program = tokens.map{|token| token[2]}.join ""
    program.sub!(original_program, converted_program)
    Ripper.sexp(program).nil? ? reparse(program) : program
    end
    # ...
    end

    View full-size slide

  43. module MathParser::Converter
    def convert(tokens)
    lines = []
    tokens.last[0][0].times do |i|
    line_no = i + 1
    previous_numeric = false
    line = []
    tokens.map do |token|
    next if line_no > token[0][0]
    break if line_no < token[0][0]
    if space?(token)
    line << token[2]
    elsif currently_numeric?(token) && previous_numeric
    previous_numeric = true
    line << ["*", token[2]]
    else
    previous_numeric = currently_numeric?(token)
    line << token[2]
    end
    end
    lines << line.join("")
    end
    lines.join("")
    end
    # ...
    end
    ߦ൪߸ͷॳظԽ(1͔Β։࢝)
    ߦ൪߸͕ҧͬͨΒεΩοϓ
    line ʹτʔΫϯΛ௥Ճ

    View full-size slide

  44. module MathParser::Converter
    def convert(tokens)
    lines = []
    tokens.last[0][0].times do |i|
    line_no = i + 1
    previous_numeric = false
    line = []
    tokens.map do |token|
    next if line_no > token[0][0]
    break if line_no < token[0][0]
    if space?(token)
    line << token[2]
    elsif currently_numeric?(token) && previous_numeric
    previous_numeric = true
    line << ["*", token[2]]
    else
    previous_numeric = currently_numeric?(token)
    line << token[2]
    end
    end
    lines << line.join("")
    end
    lines.join("")
    end
    # ...
    end

    View full-size slide

  45. τʔΫϯνΣοΫ
    2. Ͱ͖ͳ͚Ε͹਺஋ͱม਺͕ฒΜͰ͍ΔจࣈྻΛ୳͢
    module MathParser::Converter
    def currently_numeric?(token)
    ref_variable?(token) || int?(token) ||
    float?(token) || rational?(token)
    end
    def ref_variable?(token)
    (token[1] == :on_ident) &&
    (EXPR_END | EXPR_LABEL) == token[3])
    end
    def int?(token)
    token[1] == :on_int
    end
    # ...
    end

    View full-size slide

  46. τʔΫϯνΣοΫ
    2. Ͱ͖ͳ͚Ε͹਺஋ͱม਺͕ฒΜͰ͍ΔจࣈྻΛ୳͢
    module MathParser::Converter
    def currently_numeric?(token)
    ref_variable?(token) || int?(token) ||
    float?(token) || rational?(token)
    end
    def ref_variable?(token)
    (token[1] == :on_ident) &&
    (EXPR_END | EXPR_LABEL) == token[3])
    end
    def int?(token)
    token[1] == :on_int
    end
    # ...
    end

    View full-size slide

  47. module MathParser::Converter
    def convert(tokens)
    lines = []
    tokens.last[0][0].times do |i|
    # ...
    tokens.map do |token|
    # ...
    if space?(token)
    line << token[2]
    elsif currently_numeric?(token) && previous_numeric
    previous_numeric = true
    line << ["*", token[2]]
    else
    previous_numeric = currently_numeric?(token)
    line << token[2]
    end
    end
    lines << line.join("")
    end
    # ...
    * ͷૠೖ
    3. ਺஋ͱม਺ͷؒʹ * Λૠೖͯ͠ฦ͢

    View full-size slide

  48. 4. 1 ʙ 3 ͷ܁Γฦ͠
    * ͷૠೖ
    module MathParser::Converter
    def reparse(program)
    tokens = Ripper.lex(program)
    converted_program = convert(tokens)
    original_program = tokens.map{|token| token[2]}.join ""
    program.sub!(original_program, converted_program)
    Ripper.sexp(program).nil? ? reparse(program) : program
    end
    # ...
    end

    View full-size slide

  49. 4. 1 ʙ 3 ͷ܁Γฦ͠
    Ripper.lex '1 2 3 4 5'
    # => [[[1, 0], :on_int, "1", END],
    # [[1, 1], :on_sp, " ", END],
    # [[1, 2], :on_idt, "2", END]]
    γϯλοΫεΤϥʔʹͳΔͱlex్͕தͰऴྃ͢Δ
    * ͷૠೖ
    program.sub!(original_program, converted_program)
    Ripper.sexp(program).nil? ? reparse(program) : program

    View full-size slide

  50. ܭࢉͷ࣮ߦ
    module MathParser
    class MathRubyParser < MinRubyParser
    def mathruby_parse(program)
    converted_program = Ripper.sexp(program) ?
    program : reparse(program.strip)
    simplify(Ripper.sexp(converted_program))
    end
    # ...
    end
    end
    5. * ͕ૠೖ͞Εͨߏจ໦Λ࣮ߦ (ܭࢉ) ͢Δ
    minruby ͷఏڙϝιου

    ߏจ໦Λऔಘͯ͘͠ΕΔ

    View full-size slide

  51. ܭࢉͷ࣮ߦ
    5. * ͕ૠೖ͞Εͨߏจ໦Λ࣮ߦ (ܭࢉ) ͢Δ
    module MathParser
    def evaluate(tree, genv, lenv)
    case tree[0]
    when "lit"
    tree[1]
    when "+"
    evaluate(tree[1], genv, lenv) + evaluate(tree[2], genv, lenv)
    when "-"
    evaluate(tree[1], genv, lenv) - evaluate(tree[2], genv, lenv)
    when "*"
    evaluate(tree[1], genv, lenv) * evaluate(tree[2], genv, lenv)
    when "/"
    evaluate(tree[1], genv, lenv) / evaluate(tree[2], genv, lenv)
    when "**"
    evaluate(tree[1], genv, lenv)**evaluate(tree[2], genv, lenv)
    when "%"
    evaluate(tree[1], genv, lenv) % evaluate(tree[2], genv, lenv)
    when "<"
    evaluate(tree[1], genv, lenv) < evaluate(tree[2], genv, lenv)
    when "<="
    evaluate(tree[1], genv, lenv) <= evaluate(tree[2], genv, lenv)
    when ">"
    # ...
    3VCZͰͭ͘Δ3VCZθϩ͔Βֶͼͳ͓͢ϓϩάϥϛϯάݴޠೖ໳cԕ౻ါհ

    IUUQTXXXMBNCEBOPUFDPNQSPEVDUTSVCZSVCZ
    evaluate ϝιου͸

    Ruby Ͱͭ͘Δ Ruby ͷ಺༰΄΅ͦͷ··

    View full-size slide

  52. ࣮ߦͯ͠ΈΔ

    View full-size slide

  53. Ͱ͖ͨʂʂ
    irb(main):001:0> require ‘math_parser'
    => true
    irb(main):002:0' mp '
    irb(main):003:0' a = 2
    irb(main):004:0' c = 3
    irb(main):005:0' 4 a c
    irb(main):006:0> '
    => 24

    View full-size slide

  54. irb(main):001:0> require ‘math_parser'
    => true
    irb(main):002:0' mp '
    irb(main):003:0' a = 2
    irb(main):004:0' c = 3
    irb(main):005:0' a 4 c
    irb(main):006:0> '
    Ͱ͖ͯͳ͍
    ϝιουݺͼग़͠ͱͯ͠ղऍ͞ΕΔ
    NoMethodError (undefined method `[]' for nil:NilClass)

    View full-size slide

  55. module MathParser
    def evaluate(tree, genv, lenv)
    case tree[0]
    # ...
    when "func_call"
    args = tree[2..].map { |t| evaluate(t, genv, lenv) }
    # ૊ΈࠐΈؔ਺
    if respond_to?(tree[1]) || Kernel.respond_to?(tree[1])
    send(tree[1], *args)
    # Ϣʔβఆٛؔ਺
    elsif genv.has_key? tree[1]
    func_lenv = {}
    mhd = genv[tree[1]]
    params = mhd[1]
    params.each_with_index { |param, j| func_lenv[param] = args[j] }
    evaluate(mhd[2], genv, func_lenv)
    # ະఆٛͷ৔߹͸ tree Λมߋͯ͠࠶౓ evaluate ͢Δ
    else
    new_tree = ["*", ["var_ref", tree[1]], tree[2]]
    evaluate(new_tree, genv, lenv)
    end
    # ...
    end
    end
    end
    5. * ͕ૠೖ͞Εͨߏจ໦Λ࣮ߦ (ܭࢉ) ͢Δ
    Ϣʔβఆٛؔ਺Λొ࿥

    View full-size slide

  56. Ͱ͖ͨʂʂ
    irb(main):001:0> require ‘math_parser'
    => true
    irb(main):002:0' mp '
    irb(main):003:0' a = 2
    irb(main):004:0' c = 3
    irb(main):005:0' a 4 c
    irb(main):006:0> '
    => 24

    View full-size slide

  57. Ͱ͖ͯͳ͍
    ͪΌΜͱͨ͠ΤϥʔΛ

    ฦ͢Α͏ʹ͍ͨ͠ͳ͋
    ෼਺ͱ͔ྦྷ৐ͱ͔

    ΋ͬͱײ֮తʹ

    ॻ͚ΔΑ͏ʹ͍ͨ͠ͳ͋
    ϝιου಺Ͱ͔͠ม਺

    ͍֮͑ͯΒΕͳ͍
    ͙͢Τϥʔग़Δ
    irb Έ͍ͨͳ REPL ্Ͱ

    ϝιουհͣ͞

    ࣮ߦͰ͖ΔΑ͏ʹ͍ͨ͠
    ●ɹ●
    ָ͠Έ

    View full-size slide

  58. ߏจղੳ͸ා͘ͳ͍
    ΊͪΌͪ͘Ό஍ಓ
    Ruby ͍͢͝
    Did you mean? ͍͢͝
    ͍͢͝΋ͷ͍ͬͺ͍͋Δ
    ·ͱΊ

    View full-size slide

  59. ࣗ෼Ͱ࢖͏ಓ۩

    ͭ͘Δͷָ͍͠ʂ
    ·ͱΊ

    View full-size slide

  60. Special Thanks
    Ruby Ͱͭ͘Δ Ruby | ԕ౻ ါհ (@mame) 

    https://www.lambdanote.com/products/ruby-ruby
    minruby | ԕ౻ ါհ (@mame) 

    https://github.com/mame/minruby

    View full-size slide

  61. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠

    View full-size slide