$30 off During Our Annual Pro Sale. View Details »

Heredoc In Demon Castle

yui-knk
July 14, 2018

Heredoc In Demon Castle

yui-knk

July 14, 2018
Tweet

More Decks by yui-knk

Other Decks in Programming

Transcript

  1. ࣗݾ঺հ • ۚࢠ ༤Ұ࿠ • Treasure Data ॴଐ • APIνʔϜ

    (RailsΞϓϦΛॻ͍͍ͯ·͢) • CRuby Committer 2015/12~ • GitHub (yui-knk)
  2. $ ruby --dump=p -e '1 + 2' ########################################################### ## Do

    NOT use this node dump for any purpose other than ## ## debug and research. Compatibility is not guaranteed. ## ########################################################### # @ NODE_SCOPE (line: 1, location: (1,0)-(1,5)) # +- nd_tbl: (empty) # +- nd_args: # | (null node) # +- nd_body: # @ NODE_OPCALL (line: 1, location: (1,0)-(1,5))* # +- nd_mid: :+ # +- nd_recv: # | @ NODE_LIT (line: 1, location: (1,0)-(1,1)) # | +- nd_lit: 1 # +- nd_args: # @ NODE_ARRAY (line: 1, location: (1,4)-(1,5)) # +- nd_alen: 1 # +- nd_head: # | @ NODE_LIT (line: 1, location: (1,4)-(1,5)) # | +- nd_lit: 2 # +- nd_next: # (null node)
  3. 3VCZ7."45 RubyVM::AST.parse("1 + 2") # => #<RubyVM::AST::Node(NODE_SCOPE(0) 1:0, 1:5): >

    RubyVM::AST.parse("1 + 2").children[1].children # => [ # #<RubyVM::AST::Node(NODE_LIT(59) 1:0, 1:1): >, # #<RubyVM::AST::Node(NODE_ARRAY(42) 1:4, 1:5): > # ]
  4. 4ZOUBY&SSPS $ ruby -e 'RubyVM::AST.parse("1 + ")' Traceback (most recent

    call last): 1: from -e:1:in `<main>' -e:1:in `parse': no file name:1: syntax error, unexpected end-of-input (SyntaxError)
  5. DIJMESFO # 2.6.0-preview2 RubyVM::AST.parse("1 + 2").children[1].children # => [ #

    #<RubyVM::AST::Node(NODE_LIT(59) 1:0, 1:1): >, # #<RubyVM::AST::Node(NODE_ARRAY(42) 1:4, 1:5): > # ] # trunk RubyVM::AST.parse("1 + 2").children[2].children # => [ # #<RubyVM::AST::Node(NODE_LIT(59) 1:0, 1:1): >, # :+, # #<RubyVM::AST::Node(NODE_ARRAY(42) 1:4, 1:5): > # ] mid
  6. DIJMESFO # trunk RubyVM::AST.parse("def a; end").children[2].children # => [ #

    :a, # #<RubyVM::AST::Node(NODE_SCOPE(0) 1:0, 1:10): > # ]
  7. ѱຐ৓ • ѱຐ৓ parse.y ͱ͍ΘΕΔϑΝΠϧ͕͋Δ • https://slide.rabbit-shocker.org/authors/nobu/ rubykaigi-2017/ • parse.y

    ͸Rubyͷจ๏Λఆ͍ٛͯ͠ΔϑΝΠϧ • Bison ͱ͍͏πʔϧͰ Cݴޠͷίʔυʹม׵͢Δ op : '|' { ifndef_ripper($$ = '|'); } | '^' { ifndef_ripper($$ = '^'); } | '&' { ifndef_ripper($$ = '&'); }
  8. QBSTFZ $ git shortlog -s -n parse.y | head -10

    912 nobu 362 matz 140 mame 91 yui-knk 55 ko1 38 aamine 37 akr 33 naruse 25 usa 8 normal
  9. Ґஔ৘ใ # trunk RubyVM::AST.parse("1 + 2").children[2].children # => [ #

    #<RubyVM::AST::Node(NODE_LIT(59) 1:0, 1:1): >, # :+, # #<RubyVM::AST::Node(NODE_ARRAY(42) 1:4, 1:5): > # ]
  10. 3VCZJTU)PUMJOLT ʲୈճʳ def foo; <<bar end; def baz; <<quux end

    In foo! bar In baz! quux p foo # => " In foo!\n" p baz # => " In baz!\n" https://magazine.rubyist.net/articles/0042/0042-Hotlinks.html#ruby %E3%81%AE%E7%BF%92%E5%BE%97
  11. 3VCZͷώΞυΩϡϝϯτ str = <<STR Ruby is... A dynamic, open source

    programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write. STR puts str # Ruby is... # A dynamic, open source programming language with a focus on simplicity and productivity. It # has an elegant syntax that is natural to read and easy to write.
  12. 3VCZͷώΞυΩϡϝϯτ str = <<STR Ruby is... A dynamic, open source

    programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write. STR puts str # Ruby is... # A dynamic, open source programming language with a focus on simplicity and productivity. It # has an elegant syntax that is natural to read and easy to write.
  13. 3VCZͷώΞυΩϡϝϯτ str = <<STR Ruby is... A dynamic, open source

    programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write. STR puts str # Ruby is... # A dynamic, open source programming language with a focus on simplicity and productivity. It # has an elegant syntax that is natural to read and easy to write.
  14. 3VCZͷώΞυΩϡϝϯτ • <<"STR" (ࣜల։͢Δ) • <<'STR' (ࣜల։͠ͳ͍) • <<`STR` (ίϚϯυ࣮ߦ)

    puts <<"STR" #{1 + 2} STR # => 3 puts <<'STR' #{1 + 2} STR # => #{1 + 2} puts <<`STR` uname STR # => Darwin
  15. ͳ͔ʹώΞυΩϡϝϯτ͕ॻ͚Δ p <<STR1 This is str1. #{<<STR2}. 12345 This is

    str2. STR2 ABCDE STR1 # "This is str1.\nThis is str2.\n. 12345\nABCDE\n"
  16. • String#+ ͸จࣈྻ݁߹ ߦʹෳ਺ͷώΞυΩϡϝϯτ͕ॻ͚Δ p (<<STR1 + <<STR2) This is

    str1. STR1 This is str2. STR2 # "This is str1.\nThis is str2.\n"
  17. • ) ΛಡΉ ߦʹෳ਺ͷώΞυΩϡϝϯτ͕ॻ͚Δ p (<<STR1 + <<STR2) This is

    str1. STR1 This is str2. STR2 # "This is str1.\nThis is str2.\n"
  18. # +- nd_body: # @ NODE_DASGN_CURR (line: 1, location: (1,0)-

    (1,10))* # +- nd_vid: :s # +- nd_value: # @ NODE_STR (line: 1, location: (1,4)- (1,10))* # +- nd_lit: "abcde\n fghij\n" Ґஔ৘ใ s = <<~STR abcde fghij STR
  19. • pi ͸ π (ԁप཰) • e ͸ωΠϐΞ਺ $ ruby

    pie.rb Traceback (most recent call last): 11: from pie.rb:3:in `<main>' 10: from pie.rb:1:in `_2_' 9: from pie.rb:4:in `_7_' 8: from pie.rb:1:in `_1_' 7: from pie.rb:5:in `_8_' 6: from pie.rb:9:in `_2_' 5: from pie.rb:2:in `_8_' 4: from pie.rb:6:in `_1_' 3: from pie.rb:5:in `_8_' 2: from pie.rb:3:in `_2_' 1: from pie.rb:5:in `_8_' pie.rb:10:in `end': ^ ^ (Look_Forward_Ruby_2_5) | | pi e
  20. • “Look_Forward_Ruby_2_5” exception ͷbacktrace $ ruby pie.rb Traceback (most recent

    call last): 11: from pie.rb:3:in `<main>' 10: from pie.rb:1:in `_2_' 9: from pie.rb:4:in `_7_' 8: from pie.rb:1:in `_1_' 7: from pie.rb:5:in `_8_' 6: from pie.rb:9:in `_2_' 5: from pie.rb:2:in `_8_' 4: from pie.rb:6:in `_1_' 3: from pie.rb:5:in `_8_' 2: from pie.rb:3:in `_2_' 1: from pie.rb:5:in `_8_' pie.rb:10:in `end': ^ ^ (Look_Forward_Ruby_2_5) | | pi e
  21. • e ͸ method name (easy) • pi ͸ backtrace

    (strange) $ ruby pie.rb Traceback (most recent call last): 11: from pie.rb:3:in `<main>' 10: from pie.rb:1:in `_2_' 9: from pie.rb:4:in `_7_' 8: from pie.rb:1:in `_1_' 7: from pie.rb:5:in `_8_' 6: from pie.rb:9:in `_2_' 5: from pie.rb:2:in `_8_' 4: from pie.rb:6:in `_1_' 3: from pie.rb:5:in `_8_' 2: from pie.rb:3:in `_2_' 1: from pie.rb:5:in `_8_' pie.rb:10:in `end': ^ ^ (Look_Forward_Ruby_2_5) | | pi e
  22. • e ͸ method name (easy) • pi ͸ backtrace

    (strange) $ ruby pie.rb Traceback (most recent call last): 11: from pie.rb:3:in `<main>' 10: from pie.rb:1:in `_2_' 9: from pie.rb:4:in `_7_' 8: from pie.rb:1:in `_1_' 7: from pie.rb:5:in `_8_' 6: from pie.rb:9:in `_2_' 5: from pie.rb:2:in `_8_' 4: from pie.rb:6:in `_1_' 3: from pie.rb:5:in `_8_' 2: from pie.rb:3:in `_2_' 1: from pie.rb:5:in `_8_' pie.rb:10:in `end': ^ ^ (Look_Forward_Ruby_2_5) | | pi e
  23. module M1;def self._1_; M51._8_;end;end; module M1;def self._2_; _7_;end;end module M2;def

    self._8_;M6._1_;end;end module M3;def self._2_; M53._8_;end;end; <<STR1; M1._2_; #{def _7_; M1._1_; end} #{module M51;def self._8_;M9._2_;end;end; module M52;def self._8_;M3._2_;end;end; module M53;def self._8_; M10.end;end;end} #{module M6;def self._1_; M52._8_;end;end;} #{def _1_; raise; end} #{module M9;def self._2_; M2._8_;end;end} #{class Look_Forward_Ruby_2_5 < Exception;end; module M10; def self.end; raise Look_Forward_Ruby_2_5.new(" ^ ^\n | |\n pi e");end;end} STR1
  24. module M1;def self._1_; M51._8_;end;end; module M1;def self._2_; _7_;end;end module M2;def

    self._8_;M6._1_;end;end module M3;def self._2_; M53._8_;end;end; <<STR1; M1._2_; #{def _7_; M1._1_; end} #{module M51;def self._8_;M9._2_;end;end; module M52;def self._8_;M3._2_;end;end; module M53;def self._8_; M10.end;end;end} #{module M6;def self._1_; M52._8_;end;end;} #{def _1_; raise; end} #{module M9;def self._2_; M2._8_;end;end} #{class Look_Forward_Ruby_2_5 < Exception;end; module M10; def self.end; raise Look_Forward_Ruby_2_5.new(" ^ ^\n | |\n pi e");end;end} STR1 Go to next line
  25. module M1;def self._1_; M51._8_;end;end; module M1;def self._2_; _7_;end;end module M2;def

    self._8_;M6._1_;end;end module M3;def self._2_; M53._8_;end;end; <<STR1; M1._2_; #{def _7_; M1._1_; end} #{module M51;def self._8_;M9._2_;end;end; module M52;def self._8_;M3._2_;end;end; module M53;def self._8_; M10.end;end;end} #{module M6;def self._1_; M52._8_;end;end;} #{def _1_; raise; end} #{module M9;def self._2_; M2._8_;end;end} #{class Look_Forward_Ruby_2_5 < Exception;end; module M10; def self.end; raise Look_Forward_Ruby_2_5.new(" ^ ^\n | |\n pi e");end;end} STR1 Go to next line Define method(s)
  26. module M1;def self._1_; M51._8_;end;end; module M1;def self._2_; _7_;end;end module M2;def

    self._8_;M6._1_;end;end module M3;def self._2_; M53._8_;end;end; <<STR1; M1._2_; #{def _7_; M1._1_; end} #{module M51;def self._8_;M9._2_;end;end; module M52;def self._8_;M3._2_;end;end; module M53;def self._8_; M10.end;end;end} #{module M6;def self._1_; M52._8_;end;end;} #{def _1_; raise; end} #{module M9;def self._2_; M2._8_;end;end} #{class Look_Forward_Ruby_2_5 < Exception;end; module M10; def self.end; raise Look_Forward_Ruby_2_5.new(" ^ ^\n | |\n pi e");end;end} STR1 Go to next line Define method(s) Go back
  27. module M1;def self._1_; M51._8_;end;end; module M1;def self._2_; _7_;end;end module M2;def

    self._8_;M6._1_;end;end module M3;def self._2_; M53._8_;end;end; <<STR1; M1._2_; #{def _7_; M1._1_; end} #{module M51;def self._8_;M9._2_;end;end; module M52;def self._8_;M3._2_;end;end; module M53;def self._8_; M10.end;end;end} #{module M6;def self._1_; M52._8_;end;end;} #{def _1_; raise; end} #{module M9;def self._2_; M2._8_;end;end} #{class Look_Forward_Ruby_2_5 < Exception;end; module M10; def self.end; raise Look_Forward_Ruby_2_5.new(" ^ ^\n | |\n pi e");end;end} STR1 Go to next line Define method(s) Go back Call entry point
  28. IFSFEPDNPEFͱ͸ • lex.strtermͷঢ়ଶͷ͜ͱ static enum yytokentype parser_yylex(struct parser_params *p) {

    ... if (p->lex.strterm) { if (p->lex.strterm->flags & STRTERM_HEREDOC) { return here_document(p, &p->lex.strterm->u.heredoc); } else { token_flush(p); return parse_string(p, &p->lex.strterm->u.literal); } } ...
  29. IFSFEPD@JEFOUJpFS • func: Indent΍Quoteͷ৘ใ • term_len: <<STR ͷ͏ͪ STR Ҏ֎ͷ௕͞

    (Ґஔܭࢉ༻) • term: STR ͱ͍͏String • lastline: ݱࡏͷߦ΁ͷϙΠϯλ • lastidx: <<STR ͷ຤ඌͷΧϥϜ൪߸ • ruby_sourceline: ݱࡏͷߦ൪߸
  30. • func: 0x22 (INDENT & EXPAND) • term_len: 3 •

    term: STR1 p <<-STR1.upcase This is str1. STR1 term_len term
  31. • func: 0x22 (INDENT & EXPAND) • term_len: 3 •

    term: STR1 p <<-STR1.upcase This is str1. STR1 Ґஔ৘ใ = term_len + term
  32. • func: 0x22 (INDENT & EXPAND) • term_len: 3 •

    term: STR1 • lastidx: 9 • ruby_sourceline: 1 p <<-STR1.upcase This is str1. STR1 lastidx lastline
  33. • func: 0x22 (INDENT & EXPAND) • term_len: 3 •

    term: STR1 • lastidx: 9 • ruby_sourceline: 1 p <<-STR1.upcase This is str1. STR1 lastidx lastline
  34. • ҎԼͷ3ͭ͸1ͭͷStringΦϒδΣΫτʹͳ͍ͬͯΔ • term_len: 3 • func: 0x22 (INDENT &

    EXPAND) • term: STR1 p <<-STR1.upcase This is str1. STR1 term_len term 3 0x22 STR1 ͸·ΓͲ͜Ζ String