Slide 1

Slide 1 text

rakulangで実装する! RubyVM 八雲アナグラ id:anatofuz 2024/02/10 YAPC::Hiroshima 2024 1

Slide 2

Slide 2 text

このトークの対象者 ● 令和最新版Rakulangの最新情報を知りたい方 ● 特に明日すぐに役に立たない話を聞きたい方 ● ノリと勢い 2

Slide 3

Slide 3 text

$self 3 ● 八雲アナグラ(@AnaTofuZ) ● 株式会社はてな ノベルチーム ● 沖縄から引っ越して今は京都は宇治にいます ● 普段はPerlとTypeScriptを書いてます ● 推しは宝灯桃汁です

Slide 4

Slide 4 text

【PR】 来週は推しのイベントです 4

Slide 5

Slide 5 text

目次 5 ● Rakulangについて ● RubyVMとは ● 実際にやってみた

Slide 6

Slide 6 text

6 Rakulangについて

Slide 7

Slide 7 text

Raku ● かつてのPerl6 ○ Python2とPython3の違いではない ■ むしろJavaとJavaScriptの関係だった ○ 2019年にRakuに改名 ● 仕様と実装が分離している ○ テストスイート(仕様)に合格したら”Raku” ○ 歴史的にはPugs, Pallot, Yapsi, Nieczaなど ○ 今はRakudo一択 7

Slide 8

Slide 8 text

Raku 8 ● マスコットはCamelia ○ Perl6からのマスコット ● 海外ではWebでも使われてる ○ Cro ■ Rakuでよく使われてるヤツ ■ Edument社からRakuコミュニティ移管 ○ Humming-Bird ■ Sinatraっぽいやつ

Slide 9

Slide 9 text

Raku 最近単独 カンファレンスが 行われたりしてる 9

Slide 10

Slide 10 text

世界観 ● シジルがある ○ 1要素も@%を使う ● 型も書ける ● .でメソッドが呼び出 せる ● オブジェクト指向 ● Perlとは似てるが 微妙に異なる 10

Slide 11

Slide 11 text

Webっぽい 11

Slide 12

Slide 12 text

Rakudo ● ナウでヤングなRaku処理系 ○ MoarVM (実行環境) ○ NQP (NotQuitPerl, Rakuのサブセット) ○ Raku自身 ■ RakuはNQPとRakuで書かれてる ● だいたい月イチでリリース ○ https://github.com/rakudo/rakudo/releases ● JVMで動くバージョンもある ○ …が、MoarVMに比べてバグりがち 12

Slide 13

Slide 13 text

インストール方法 13 ● rakudo-star(*)がオススメ ○ $brew install rakudo-star ● env系もいろいろ ○ rakudobrew ○ rakuenv ○ asdf-raku ■ mise(rtx)でも入るぜ

Slide 14

Slide 14 text

コーディング支援系 ● RakuNavigator ○ https://github.com/bscan/RakuNavigator ○ RakuのLSP ○ PerlNavigatorインスパイア作品 ○ VSCode使うならオススメ 14

Slide 15

Slide 15 text

簡単にわかる! Rakulang 15 アレ Perl5 Rakulang 実行コマンド perl raku ファイル拡張子 *.pl *.raku モジュール拡張子 *.pm *.rakumod テスト *.t *.rakutest

Slide 16

Slide 16 text

モジュール ● zef コマンドでいれられる ○ cpanm的なヤツ ○ かつてはpandaというのもあったが... ● https://raku.land/ でモジュールを探せる ○ landだけに土アイコン!!!! ● 歴史的にエコシステムが2つある ○ fez (zefで使われてるヤツ・主流) ○ p6c (歴史的にいるヤツ・fezに移行中) 16

Slide 17

Slide 17 text

17 RubyVM

Slide 18

Slide 18 text

18 …の前にプログラミング言語について ● コンピューターはCPUが命令を 実行することで処理がすすむ ● CPUの命令(機械語) ● 機械語に対応したプログラミング言語に CPUの種類に応じたアセンブラがある

Slide 19

Slide 19 text

こういうヤツ 19

Slide 20

Slide 20 text

20 コンパイル言語 Cやgolangはコンパイルをして ソースコードを機械語に変換する ソースコード コンパイル 機械語をCPUが実行

Slide 21

Slide 21 text

21 スクリプト言語 RubyやPerlはコンパイルをして ソースコードをバイトコードに変換する ソースコード コンパイル バイトコードをVMが 実行 VM

Slide 22

Slide 22 text

コンパイル vs スクリプト ● 最近の言語は両方ともコンパイルする ● 実行するヤツが違う ○ コンパイル ■ 直接CPU ○ スクリプト ■ プロセスVM経由でCPUが実行 ■ JITがあると直接CPUが実行する(ので早いぜ) 22

Slide 23

Slide 23 text

プロセスVM ● OS上のプロセスとして動くVM ○ OSを動かす目的なVMではない ● VMさえハードウェアに対応すれば動くソフト はハードウェアの制約がない ● JVM,MoarVMもこの一種 ● RubyはYARVが該当 23

Slide 24

Slide 24 text

プロセスVMを実装する ● 複雑ではあるがソフトウェアであるので何か しらの言語で再実装が可能 ● 極端なことを言うと巨大なfor文とif文を実装 すればOK ○ バイトコードな命令セットを特定の条件で読む(for) ○ 命令セットに応じた処理をする(if文) 24

Slide 25

Slide 25 text

言語開発系の鉄則 ● いきなり頑張らない ● 無理をしない ● インクリメンタルに開発する 25

Slide 26

Slide 26 text

いきなり頑張らない ● 初手バイトコードを読みに行ったりしない ○ 普段しないことなので大変 ○ バイトコードの読解から実行まで距離がある ● 次から次へと新情報がやってくるので全部真 面目に最初からやろうとすると疲れて飽きる ○ 最初は普段のプログラミングに近いところから行く 26

Slide 27

Slide 27 text

無理をしない ● 関数定義とかは一旦おいておこう ○ 意外とFizzBuzzまで行くのがムズい ● HelloWorldとIF文が動けば優勝 ○ ここまで動くと楽しくなってくる 27

Slide 28

Slide 28 text

インクリメンタルに開発する 28 ● ちょっとずつ実装する ○ まずはHello Worldから ● 命令セット全部移植しようとしない ● 完全にうまくやろうとしない ○ 面倒なところは諦める ○ 仕事のコードではない

Slide 29

Slide 29 text

29 RakulangでRubyVM を作るぞ!!

Slide 30

Slide 30 text

RubyVM 30 ● Rubyバイトコードを実際に実行する処理系 ● YARV ○ C言語で実装されているいわゆるCRuby ○ 最近はRustで書かれたYJITもあるがここでは割愛 ● スタックマシン

Slide 31

Slide 31 text

スタックマシン vs レジスタマシン ● スタックマシン ○ クソデカスタックを使って計算をする ■ push, popみたいな動作が主 ○ こっちの方が実装が簡単(とされている) ● レジスタマシン ○ 現実のCPUと同じようにレジスタ(変数)を持つ ■ レジスタ同士で計算する ● なんと今日2つ出てきます 31

Slide 32

Slide 32 text

実装するぞ!!! 1. Rakuで実行したいRubyのコードを書く 2. バイトコードを取り出す 3. バイトコードを実行するRakuを書く 32

Slide 33

Slide 33 text

実装するぞ!!! 1. Rakuで実行したいRubyのコードを書く 2. バイトコードを取り出す 3. バイトコードを実行するRakuを書く たいへん!!! 33

Slide 34

Slide 34 text

実装するぞ!!! 1. Rakuで実行したいRubyのコードを書く 2. バイトコードを取り出す 3. バイトコードを人間が読める形式にする 4. 人間が読める形式の文字列をRakuで評価する なのでバイト列は今回はノータッチ!!! 34

Slide 35

Slide 35 text

class RubyVM 35 https://docs.ruby-lang.org/ja/latest/class/RubyVM.html

Slide 36

Slide 36 text

RubyVM::InstructionSequence 36 https://docs.ruby-lang.org/ja/latest/class/RubyVM=3a=3aInstructionSequence.html

Slide 37

Slide 37 text

37

Slide 38

Slide 38 text

38

Slide 39

Slide 39 text

RubyVMの命令セット ● RubyVM::InstructionSequenceのdisasmを 使うといい感じに命令を見ることが出来る ● それぞれどういった意味の命令かは調べる必 要がある ○ C言語のソースコードを読む ○ ググって有識者の解説を確認する ○ フィーリング ■ 仕事じゃないので動けばよかろう 39

Slide 40

Slide 40 text

HelloWorld 40

Slide 41

Slide 41 text

HelloWorld 41 アドレス

Slide 42

Slide 42 text

HelloWorld 42 アドレス オペコード (命令)

Slide 43

Slide 43 text

HelloWorld 43 アドレス オペコード (命令) オペランド (引数)

Slide 44

Slide 44 text

RubyVMの雰囲気 ● 上から順に命令を実行していけばだいたいOK ● HelloWorldではアドレスは無視する 44

Slide 45

Slide 45 text

HelloWorld 45 今回はスルー

Slide 46

Slide 46 text

HelloWorld 46 スタックに文字 列をpush

Slide 47

Slide 47 text

HelloWorld 47 スタックに文字 列をpush

Slide 48

Slide 48 text

HelloWorld 48 スタックに文字 列をpush momojiru

Slide 49

Slide 49 text

HelloWorld 49 メソッド呼び出 し(今回はputs) momojiru

Slide 50

Slide 50 text

HelloWorld 50 メソッド呼び出 し(今回はputs) momojiru 引数が取られる

Slide 51

Slide 51 text

HelloWorld 51 return

Slide 52

Slide 52 text

ヒアドキュメントでコードをコピペ 52

Slide 53

Slide 53 text

ヒアドキュメントでコードをコピペ 53

Slide 54

Slide 54 text

3ブロックに分解する 54

Slide 55

Slide 55 text

3ブロックに分解する 55 行単位で分割 しながら配列に 変換

Slide 56

Slide 56 text

3ブロックに分解する 56 素朴に空白で 3分割

Slide 57

Slide 57 text

3ブロックに分解する 57 ハッシュを作る

Slide 58

Slide 58 text

最初なのでputstringでputsしちゃう 58

Slide 59

Slide 59 text

HelloWorld ● 完全にエミュレートしてるわけではないがそ れっぽく動いた ● 次はif文にチャレンジする 59

Slide 60

Slide 60 text

60

Slide 61

Slide 61 text

61

Slide 62

Slide 62 text

62 2024

Slide 63

Slide 63 text

63 2024 2

Slide 64

Slide 64 text

64 0

Slide 65

Slide 65 text

65 0

Slide 66

Slide 66 text

66 0 0

Slide 67

Slide 67 text

67 true

Slide 68

Slide 68 text

68 true 0017にjumpす ると終わる

Slide 69

Slide 69 text

RubyVMの雰囲気 ● 上から順に命令を実行していけばだいたいOK ● HelloWorldではアドレスは無視する ● IF文では分岐が必要 ○ True/Falseで実行する命令を変える必要がある ● このためにはアドレスを見て処理していく必 要がある ○ プログラムカウンタを導入 69

Slide 70

Slide 70 text

RubyVMの雰囲気 ● 上から順に命令を実行していけばだいたいOK ● HelloWorldではアドレスは無視する ● IF文では分岐が必要 ○ True/Falseで実行する命令を変える必要がある ● このためにはアドレスを見て処理していく必 要がある ○ プログラムカウンタを導入 70 今実行しているア ドレスを保持する 変数

Slide 71

Slide 71 text

そろそろ命令をちゃんと管理する 71

Slide 72

Slide 72 text

実行する命令のclass導入 72

Slide 73

Slide 73 text

実行する命令のclass導入 73 hasでインス タンス変数

Slide 74

Slide 74 text

実行する命令のclass導入 74 次のアドレスを計 算するために命令 の長さを出す

Slide 75

Slide 75 text

75

Slide 76

Slide 76 text

76

Slide 77

Slide 77 text

77 スタックとプログ ラムカウンタ導入

Slide 78

Slide 78 text

78 実行処理 (public method)

Slide 79

Slide 79 text

79 loopで無限ループ

Slide 80

Slide 80 text

80 アドレスに 該当する命令を 持ってくる

Slide 81

Slide 81 text

81 !をつけると private method

Slide 82

Slide 82 text

82 given-whenで パターンマッチ (Opcode型)

Slide 83

Slide 83 text

83 今回は真面目に stack操作する

Slide 84

Slide 84 text

84 今回は真面目に stack操作する

Slide 85

Slide 85 text

85 stackの値を使って 演算

Slide 86

Slide 86 text

86 stackの値がfalse ならjump

Slide 87

Slide 87 text

87 どうせsayだけなの で手抜き

Slide 88

Slide 88 text

88 ここで終了

Slide 89

Slide 89 text

89

Slide 90

Slide 90 text

90 if文実装成功!!!

Slide 91

Slide 91 text

91 if文実装成功!!! if-elseを導入する ● 今のままだとif文の条件分岐が動いてなくて も正常に動作した(ように見える)のでelseを 導入してみる

Slide 92

Slide 92 text

92

Slide 93

Slide 93 text

93

Slide 94

Slide 94 text

94 !?!?!?!?

Slide 95

Slide 95 text

95 無限ループからの脱出なので...

Slide 96

Slide 96 text

96 無限ループからの脱出なので...

Slide 97

Slide 97 text

97

Slide 98

Slide 98 text

98 💪

Slide 99

Slide 99 text

まとめ ● Rakulang普通にプログラミングできる ● RubyVMはまずは文字列から攻めるとわかり やすい ● 気楽にやっていこう 99