Slide 1

Slide 1 text

Hackarade #04 "Create your own interpreter" Yusuke Endoh (@mametter) 2018/10/05 (Fri.)

Slide 2

Slide 2 text

Today's Goal • Write a Ruby interpreter in Ruby

Slide 3

Slide 3 text

Today's Goal • Write a Ruby interpreter in Ruby ✕ eval(File.read(ARGV[0]))

Slide 4

Slide 4 text

Today's Goal • Write a Ruby interpreter in Ruby ✕ ✔ eval(File.read(ARGV[0])) evaluate( parse( File.read(ARGV[0])))

Slide 5

Slide 5 text

A simple structure of interpreter Parser Evaluator puts 3*(2+2) Program 12 Output + • Built-in features (String, Array, etc.) • Memory management (GC) • Libraries Interpreter

Slide 6

Slide 6 text

Parser • Converts a program text to "abstract syntax tree" (AST) Parser puts 3*(2+2) Program func_call AST * + "puts" 3 2 2

Slide 7

Slide 7 text

Evaluator • Runs the instruction by walking AST func_call AST * + "puts" 3 2 2 Evaluator

Slide 8

Slide 8 text

Evaluator • Runs the instruction by walking AST func_call AST * "puts" 3 Evaluator 4

Slide 9

Slide 9 text

Evaluator • Runs the instruction by walking AST func_call AST "puts" 12 Evaluator

Slide 10

Slide 10 text

Evaluator • Runs the instruction by walking AST AST nil Evaluator 12 Output

Slide 11

Slide 11 text

Today's Goal • Write a Ruby interpreter in Ruby

Slide 12

Slide 12 text

Today's Goal • Write a Ruby interpreter in Ruby – Impossible in one day!

Slide 13

Slide 13 text

Today's Goal • Write a Ruby interpreter in Ruby – Impossible in one day! • More precisely: Write a "MinRuby" interpreter in Ruby

Slide 14

Slide 14 text

Today's Goal • Write a Ruby interpreter in Ruby – Impossible in one day! • More precisely: Write a "MinRuby" interpreter in Ruby – Runs a program written in MinRuby (Target language) – Is written in Ruby (Host language)

Slide 15

Slide 15 text

MinRuby • Very small subset of Ruby – Arithmetic, comparison: – Statements, variables: – Branches, loop: – Function call: – Function definition: – Array and Hash: 1+2*3 42>40 x=42; x=x+1; p(x) if x < 2 while x < 10 func(1,2) p(42) def func(x,y); …; end a=[1,2,3]; a[1]=42; p(a[0]) 3*4==5+7 h={}; h["foo"]="bar"; p(h["foo"])

Slide 16

Slide 16 text

MinRuby • Very small subset of Ruby – Arithmetic, comparison: – Statements, variables: – Branches, loop: – Function call: – Function definition: – Array and Hash: • Class? Method call? Block? Not needed. 1+2*3 42>40 x=42; x=x+1; p(x) if x < 2 while x < 10 func(1,2) p(42) def func(x,y); …; end a=[1,2,3]; a[1]=42; p(a[0]) 3*4==5+7 h={}; h["foo"]="bar"; p(h["foo"])

Slide 17

Slide 17 text

Your task • Write "interp.rb" • Check if it works as the same as Ruby # test1-1.rb p(1 + 1) def parse(src); …; end def evaluate(tree); …; end evaluate(parse(File.read(ARGV[0]))) $ ruby test1-1.rb 2 $ ruby interp.rb test1-1.rb 2

Slide 18

Slide 18 text

Focus: Evaluator Parser Evaluator puts 3*(2+2) Program 12 Output Interpreter Use "minruby" gem A skeleton code is provided

Slide 19

Slide 19 text

"minruby" gem • Provides a MinRuby parser require "minruby" p minruby_parse( "3*(2+2)" ) #=> ["*", ["lit", 3], ["+", ["lit", 2], ["lit", 2] ] ] * + 3 2 2 Observe!

Slide 20

Slide 20 text

A evaluator skeleton • MinRuby interpreter with many "holes" # An implementation of the evaluator def evaluate(exp, env) case exp[0] when "+" evaluate(exp[1], env) + evaluate(exp[2], env) when "-" raise(NotImplementedError) # Problem 1 … end end evaluate(minruby_parse(minruby_load()), {})

Slide 21

Slide 21 text

Your task • Complete "interp.rb" and pass all test programs ("test*-*.rb") $ ruby interp.rb test1-1.rb 2 $ ruby interp.rb test1-2.rb Traceback (most recent call last): 2: from interp.rb:168:in `' 1: from interp.rb:94:in `evaluate' interp.rb:23:in `evaluate': NotImplementedError Fix it!

Slide 22

Slide 22 text

Problems 1..6 1. Arithmetics (test1-*.rb) 2. Statements and variables (test2-*.rb) 3. Branches and loops (test3-*.rb) 4. Function calls (test4-*.rb) 5. User-defined functions (test5-*.rb) 6. Arrays and Hashes (test6-*.rb) – You can implement and test them in turn

Slide 23

Slide 23 text

Problem 7 • Self-Hosting – Write a MinRuby interpreter in MinRuby • MinRuby is limited but still powerful to implement a MinRuby interpreter! $ ruby interp.rb interp.rb test1-1.rb ary.each do |x| ... end i = 0 while ary[i] x = ary[i] ... end $ ruby interp.rb interp.rb interp.rb test1-1.rb

Slide 24

Slide 24 text

Advanced Problems • Write your own MinRuby parser • Support advanced features – Blocks, class/modules, eval, callcc, … – Increment, lazy eval., type analysis, … • Write a XXX interpreter in XXX – MinSwift, Kotlin, Python, JavaScript, … • Do true self-hosting – Write a MinRuby parser in MinRuby • Write a MinRuby compiler in Ruby

Slide 25

Slide 25 text

Good luck! • The files and details are available at: – https://github.com/mame/cookpad- hackarade-minruby/ • Feel free to ask me any questions – Or some experts

Slide 26

Slide 26 text

Answer [PR] • A book to learn Ruby by writing Ruby interpreter in Ruby – (written in Japanese)