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

Cookpad Hackarade #04: Create Your Own Interpreter

Cookpad Hackarade #04: Create Your Own Interpreter

Yusuke Endoh

October 09, 2018
Tweet

More Decks by Yusuke Endoh

Other Decks in Programming

Transcript

  1. Today's Goal • Write a Ruby interpreter in Ruby ✕

    ✔ eval(File.read(ARGV[0])) evaluate( parse( File.read(ARGV[0])))
  2. 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
  3. Parser • Converts a program text to "abstract syntax tree"

    (AST) Parser puts 3*(2+2) Program func_call AST * + "puts" 3 2 2
  4. Today's Goal • Write a Ruby interpreter in Ruby –

    Impossible in one day! • More precisely: Write a "MinRuby" interpreter in Ruby
  5. 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)
  6. 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"])
  7. 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"])
  8. 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
  9. "minruby" gem • Provides a MinRuby parser require "minruby" p

    minruby_parse( "3*(2+2)" ) #=> ["*", ["lit", 3], ["+", ["lit", 2], ["lit", 2] ] ] * + 3 2 2 Observe!
  10. 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()), {})
  11. 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 `<main>' 1: from interp.rb:94:in `evaluate' interp.rb:23:in `evaluate': NotImplementedError Fix it!
  12. 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
  13. 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
  14. 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
  15. 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
  16. Answer [PR] • A book to learn Ruby by writing

    Ruby interpreter in Ruby – (written in Japanese)