Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT...

160
MWRC 2013, Salt Lake City, UT Ryan Davis, Seattle.rb Trolls of 2013 Trolls of 2013

Transcript of Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT...

Page 1: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbTrolls of 2013

Trolls of 2013

Page 2: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbTrolls of 2013

• Followup of my talk, “Occupy Ruby: Why We Need to Moderate the 1%”

• 130 Slides in 30 minutes. 4.3 spm

• I must go quickly, so please hold questions.

• Ummm... no.

Setting Expectations

Page 3: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Let’s Wr!e an Interpreter!

Page 4: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Setting Expectations

• 160 Slides in 30 minutes. 5.3 spm.

• Boatloads of content. Almost all code.

• I was asked to “Hurt Brains”.

• TODO

Page 5: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Expanded to 45 minutes?!?

Page 6: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Added15 minutes of kittens

to the end

Page 7: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

OMG WHY?!?

Page 8: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

BecauseI’m a pervert!

Page 9: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Wa!… No!

Page 10: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Because we can!

Page 11: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

"e “Uby”Interpreter

Page 12: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Branching Logic:if/else/elsif

if condition then true_codeelse false_codeend

Page 13: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Loops: whilewhile condition codeend

Page 14: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Local Variablesmeaning = 42pi = 3

Page 15: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Functionsdef fib n if n <= 2 then 1 else fib(n-2) + fib(n-1) endend

Page 16: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Functions

recursive function calls

local variables

“primitive” function callsdef fib n if n <= 2 then 1 else fib(n-2) + fib(n-1) endend

Page 17: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Uby Roadmap

Variables Conditionals

Runtime

Environment

Functions

Parser

Loops

Page 18: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Parsing: ruby_parser

Page 19: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

ConditionalsLoops

Runtime

Environment

Functions

Parser

Variables

Page 20: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

RubyParser.new.parse " def fib n if n <= 2 then 1 else fib(n-2) + fib(n-1) end end"

Page 21: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

:defn

:fib

:args:n

:if

:call

:lvar :n

:<

:lit 2

:lit 1

:call

:call

nil

:fib

:call

:lvar :n

:-

:lit 2:+

:call nil :fib

:call

:lvar :n

:-

:lit 1

Page 22: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We
Page 23: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

:defn

:fib

:args:n

:if

:call

:lvar :n

:<

:lit 2

:lit 1

:call

:call

nil

:fib

:call

:lvar :n

:-

:lit 2:+

:call nil :fib

:call

:lvar :n

:-

:lit 1

Page 24: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

:defn

:fib

:args

:n

:if

:call

:lvar :n

:<

:lit 2

:lit 1

:call

:call

nil

:fib

:call

:lvar :n

:-

:lit 2:+

:call nil :fib

:call

:lvar :n

:-

:lit 1

Page 25: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

:defn

:fib

:args

:n

:if

:call

:lvar :n

:<

:lit 2

:lit 1

:call

:call

nil

:fib

:call

:lvar :n

:-

:lit 2:+

:call nil :fib

:call

:lvar :n

:-

:lit 1

Page 26: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

else

:call nil :fib

:call

:lvar :n

:-

:lit 1

:call nil :fib

:call

:lvar :n

:-

:lit 2

:call :+

condition

:call

:lvar :n

:<

:lit 2

:defn

:fib :args

:n

:if

then

:lit 1

Page 27: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

s(:defn, :fib, s(:args, :n), s(:if, s(:call, s(:lvar, :n), :<=, s(:lit, 2)), s(:lit, 1), s(:call, s(:call, nil, :fib, s(:call, s(:lvar, :n), :-, s(:lit, 2))), :+, s(:call, nil, :fib, s(:call, s(:lvar, :n), :-, s(:lit, 1))))))

Page 28: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

S-Expression Vocabulary

s(:call, s(:lit, 3), :+, s(:lit, 4))

Sexp Sub-sexps

Rest(cdr)

Head/Type(car)

Page 29: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

All for free using ruby_parser

Page 30: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

OK…No more talk about

parsing.

Page 31: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Further study on parsers:

Michael Jackson’sParsing Expressions in Ruby

MWRC 2011http://www.confreaks.com/videos/582

Page 32: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Interpre#ng via sexp_processor

Page 33: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

ConditionalsLoops

Environment

Variables

Functions

Parser

Runtime

Page 34: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

How to get 7 from 3+4?

73 + 4 ??????

Page 35: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Start with the source

3 + 4

Page 36: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Parse it

3 + 4s(:call, s(:lit, 3), :+, s(:lit, 4))

Page 37: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

s(:call, s(:lit, 3), :+, s(:lit, 4))

Then process by type

3 + 4

process_call

process_lit

Page 38: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

s(:call, s(:lit, 3), :+, s(:lit, 4))

First with the inner values

3 + 4

process_lit

Page 39: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

s(:call, 3, :+, s(:lit, 4))

First with the inner values

3 + 4

process_lit

Page 40: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

s(:call, 3, :+, 4)

First with the inner values

3 + 4

Page 41: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

s(:call, 3, :+, 4)

then with the outer

3 + 4

process_call

Page 42: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

proc { |a, b| a + b }[3, 4]

then with the outer

3 + 4

Page 43: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

proc { |a, b| a + b }[3, 4]

resulting in a final value

3 + 4 7

Page 44: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

SexpProcessorclass UbyInterpreter def process_lit s s.last endend s(:lit, 3)

3

Page 45: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Test Dr$en Interpreters

Page 46: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Loops Conditionals

Runtime

Environment

Functions

Parser

Test

Dri

ven

Variables

Page 47: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Unit Testsdef test_sanity val = lang.eval("3 + 4") assert_equal 7, valend

Page 48: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Unit TestsInput Source

Expected Value

def test_sanity val = lang.eval("3 + 4") assert_equal 7, valend

Page 49: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Premature Refactoring

Input SourceExpected Value

def assert_eval exp, src assert_equal exp, lang.eval(src)end

def test_sanity assert_eval 7, "3 + 4"end

Page 50: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

San% Test:3 + 4

Page 51: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

ConditionalsLoops

Environment

Functions

Parser

Test

Dri

ven

Runtime

Variables

Page 52: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Test Infrastructureclass TestUbyInterpreter < MiniTest::Unit::TestCase attr_accessor :int

def setup self.int = UbyInterpreter.new end

def assert_eval exp, src, msg = nil assert_equal exp, int.eval(src), msg endend

Page 53: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Our First Test:class TestUbyInterpreter < MiniTest::Unit::TestCase attr_accessor :int

def setup self.int = UbyInterpreter.new end

def assert_eval exp, src assert_equal exp, ri.eval(src) end

def test_sanity assert_eval 3, "3" assert_eval 7, "3 + 4" endend

Old Code

New Code

Page 54: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Our First Test:class TestUbyInterpreter < MiniTest::Unit::TestCase

# ...

def test_sanity assert_eval 3, "3" assert_eval 7, "3 + 4" endend

Old Code

New Code

Page 55: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Our first error:# Running tests:

E

Finished tests in 0.000364s, 2747.2527 tests/s, 0.0000 assertions/s.

1) Error:TestUbyInterpreter#test_sanity:NameError: uninitialized constant TestUbyInterpreter::UbyInterpreter ./test/test_ruby_interpreter.rb:11:in `setup'

Page 56: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Define the constantclass UbyInterpreter < SexpInterpreter VERSION = "1.0.0"end

Page 57: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Wash, rinse…# Running tests:

E

Finished tests in 0.000578s, 1730.1038 tests/s, 0.0000 assertions/s.

1) Error:TestUbyInterpreter#test_sanity:NoMethodError: private method `eval' called for #<UbyInterpreter:0x105be17d8> ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:19:in `test_sanity'

Page 58: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Implement eval & parseclass UbyInterpreter < SexpInterpreter # ... attr_accessor :parser

def initialize super

self.parser = Ruby19Parser.new end

def eval src process parse src end

def parse src self.parser.process src endend

Page 59: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Finally!# Running tests:

E

Finished tests in 0.001365s, 732.6007 tests/s, 0.0000 assertions/s.

1) Error:TestUbyInterpreter#test_sanity:UnknownNodeError: Bug! Unknown node-type :lit to UbyInterpreter ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:19:in `test_sanity'

Page 60: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Implement process_litclass UbyInterpreter < SexpInterpreter

# ...

def process_lit s s.last endend

Page 61: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Tada! Second Assertion! 1) Error:TestUbyInterpreter#test_sanity:UnknownNodeError: Bug! Unknown node-type :call to UbyInterpreter ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:20:in `test_sanity'

Page 62: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Define :call genericallyclass UbyInterpreter < SexpInterpreter

# ...

def process_call s raise "Boom: #{s.inspect}" endend

Page 63: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

See sub-sexps 1) Error:TestUbyInterpreter#test_sanity:RuntimeError: Boom: s(:call, s(:lit, 3), :+, s(:lit, 4)) ./lib/ruby_interpreter.rb:35:in `process_call' ./lib/ruby_interpreter.rb:19:in `eval' ./test/test_ruby_interpreter.rb:17:in `assert_eval' ./test/test_ruby_interpreter.rb:22:in `test_sanity'

Page 64: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Unpack sub-sexpsclass UbyInterpreter < SexpInterpreter

# ...

def process_call s _, recv, msg, *args = s

raise "Boom: #{recv}, #{msg}, #{args.inspect}" endend

Page 65: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Unpacked sub-sexps 1) Error:TestUbyInterpreter#test_sanity:RuntimeError: Boom: s(:lit, 3), +, [s(:lit, 4)] ./lib/ruby_interpreter.rb:31:in `process_call'

Page 66: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Process sub-sexpsclass UbyInterpreter < SexpInterpreter def process_call s _, recv, msg, *args = s

recv = process recv args.map! { |sub| process sub }

raise "Boom: #{recv}, #{msg}, #{args.inspect}" endend

Page 67: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Processed Values 1) Error:TestUbyInterpreter#test_sanity:RuntimeError: Boom: 3, +, [4] ./lib/ruby_interpreter.rb:43:in `process_call'

Page 68: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Cheat: Send to Rubyclass UbyInterpreter < SexpInterpreter def process_call s _, recv, msg, *args = s

recv = process recv args.map! { |sub| process sub }

recv.send(msg, *args) # big ol' hack… endend

Page 69: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Sanity!# Running tests:

.

Finished tests in 0.001625s, 615.3846 tests/s, 1230.7692 assertions/s.

1 tests, 2 assertions, 0 failures, 0 errors, 0 skips

Page 70: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!class UbyInterpreter < SexpInterpreter VERSION = "1.0.0"

attr_accessor :parser

def initialize super self.parser = Ruby19Parser.new end

def eval src process parse src end

def parse src self.parser.process src end

def process_lit s s.last end

def process_call s _, recv, msg, *args = s

recv = process recv args.map! { |sub| process sub }

recv.send(msg, *args) # big ol' hack… endend

Yay!

Overblown

Calculator!

Page 71: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Cond!ionals&

Truthiness

Page 72: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Loops

Runtime

Environment

Variables

Functions

Parser

Test

Dri

ven

Conditionals

Page 73: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Add :if testsclass TestUbyInterpreter < MiniTest::Unit::TestCase # ...

def test_if assert_eval 42, "if true then 42 else 24 end" end

def test_if_falsey assert_eval 24, "if nil then 42 else 24 end" assert_eval 24, "if false then 42 else 24 end" endend

Page 74: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Unknown :if 1) Error:TestUbyInterpreter#test_if:UnknownNodeError: Bug! Unknown node-type :if to UbyInterpreter ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:34:in `test_if'

2) Error:TestUbyInterpreter#test_if_falsey:UnknownNodeError: Bug! Unknown node-type :if to UbyInterpreter ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:38:in `test_if_falsey'

3 tests, 2 assertions, 0 failures, 2 errors, 0 skips

Page 75: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Define :if genericallyclass UbyInterpreter < SexpInterpreter # ...

def process_if s raise "Boom: #{s.inspect}" endend

Page 76: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

See sub-sexps 1) Error:TestUbyInterpreter#test_if:RuntimeError: Boom: s(:if, s(:true), s(:lit, 42), s(:lit, 24)) ./lib/ruby_interpreter.rb:38:in `process_if' ... ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:34:in `test_if'

2) Error:TestUbyInterpreter#test_if_falsey:RuntimeError: Boom: s(:if, s(:nil), s(:lit, 42), s(:lit, 24)) ./lib/ruby_interpreter.rb:38:in `process_if' ... ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:38:in `test_if_falsey'

Page 77: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Process sub-sexpsclass UbyInterpreter < SexpInterpreter # ...

def process_if s _, c, t, f = s

c = process c

if c then process t else process f end endend

Why evaluate c before t &

f?

if true then puts "happy"else system "rm -rf /"end

Page 78: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Sub-sexps fail 1) Error:TestUbyInterpreter#test_if:UnknownNodeError: Bug! Unknown node-type :true to UbyInterpreter ./lib/ruby_interpreter.rb:40:in `process_if' ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:34:in `test_if'

2) Error:TestUbyInterpreter#test_if_falsey:UnknownNodeError: Bug! Unknown node-type :nil to UbyInterpreter ./lib/ruby_interpreter.rb:40:in `process_if' ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:38:in `test_if_falsey'

Page 79: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Define :nil and :trueclass UbyInterpreter < SexpInterpreter # ...

def process_nil s nil end

def process_true s true endend

Page 80: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Third failure 1) Error:TestUbyInterpreter#test_if_falsey:UnknownNodeError: Bug! Unknown node-type :false to UbyInterpreter ./lib/ruby_interpreter.rb:40:in `process_if' ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:39:in `test_if_falsey'

Page 81: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Define :falseclass UbyInterpreter < SexpInterpreter # ...

def process_false s false endend

Page 82: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Voilà!# Running tests:

...

Finished tests in 0.002860s, 1048.9510 tests/s, 1748.2517 assertions/s.

3 tests, 5 assertions, 0 failures, 0 errors, 0 skips

Page 83: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Test Driven Process

Processsub-sexps

Tests Pass

Add afailing test

Errornode-type

Add genericnode-type

Failure sub-sexpcomponents

Page 84: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Yes, development this fast…

with autotest.

Page 85: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Page 86: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Brain Hurt Yet?

Page 87: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Good

Page 88: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Wait till I get going!

Where was I?

Page 89: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Local Variables

Page 90: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Loops Conditionals

Runtime

Functions

Parser

Test

Dri

ven

Variables

Environment

Page 91: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Local Variables!class TestUbyInterpreter < MiniTest::Unit::TestCase # ...

def test_lvar assert_eval 42, "x = 42; x" endend

Page 92: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Block?!? 1) Error:TestUbyInterpreter#test_lvar:UnknownNodeError: Bug! Unknown node-type :block to UbyInterpreter ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:24:in `test_lvar'

Page 93: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Define :blockclass UbyInterpreter < SexpInterpreter # ...

def process_block s raise "Boom: #{s.inspect}" endend

Page 94: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Ohhh… 1) Error:TestUbyInterpreter#test_lvar:RuntimeError: Boom: s(:block, s(:lasgn, :x, s(:lit, 42)), s(:lvar, :x)) ./lib/ruby_interpreter.rb:25:in `process_block' ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:24:in `test_lvar'

Page 95: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Process all sub-sexpsclass UbyInterpreter < SexpInterpreter # ...

def process_block s result = nil s.rest.each do |sub| result = process sub end result endend

Page 96: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

:lasgn is undefined 1) Error:TestUbyInterpreter#test_lvar:UnknownNodeError: Bug! Unknown node-type :lasgn to UbyInterpreter ./lib/ruby_interpreter.rb:27:in `process_block' ./lib/ruby_interpreter.rb:26:in `each' ./lib/ruby_interpreter.rb:26:in `process_block' ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:24:in `test_lvar'

Page 97: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Define :lasgnclass UbyInterpreter < SexpInterpreter # ...

def process_lasgn s raise "Boom: #{s.inspect}" endend

Page 98: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Looks like name/value 1) Error:TestUbyInterpreter#test_lvar:RuntimeError: Boom: s(:lasgn, :x, s(:lit, 42)) ./lib/ruby_interpreter.rb:58:in `process_lasgn' ./lib/ruby_interpreter.rb:27:in `process_block' ./lib/ruby_interpreter.rb:26:in `each' ./lib/ruby_interpreter.rb:26:in `process_block' ./lib/ruby_interpreter.rb:17:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:24:in `test_lvar'

Page 99: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Add a stupid tableclass UbyInterpreter < SexpInterpreter # ...

attr_accessor :env

def initialize # ... self.env = {} # omg this is horrible end

def process_lasgn s _, n, v = s

self.env[n] = process v endend

EnvironmentEnvironment

x 42

Page 100: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Now we need to read 1) Error:TestUbyInterpreter#test_lvar:UnknownNodeError: Bug! Unknown node-type :lvar to UbyInterpreter ./lib/ruby_interpreter.rb:29:in `process_block' ./lib/ruby_interpreter.rb:28:in `each' ./lib/ruby_interpreter.rb:28:in `process_block' ./lib/ruby_interpreter.rb:19:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:24:in `test_lvar'

Page 101: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Access the tableclass UbyInterpreter < SexpInterpreter # ...

def process_lvar s _, name = s

self.env[name] endend

Page 102: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Voilà# Running tests:

....

Finished tests in 0.003666s, 1091.1075 tests/s, 1636.6612 assertions/s.

4 tests, 6 assertions, 0 failures, 0 errors, 0 skips

Page 103: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Page 104: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Just wait…

Page 105: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

It gets “better”

Page 106: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Fun&ions

Page 107: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Conditionals

Runtime

Environment

Variables

Parser

Test

Dri

ven

Loops

Functions

Page 108: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Add :defn Testclass TestUbyInterpreter < MiniTest::Unit::TestCase # ...

def test_defn assert_eval nil, <<-EOM def double n 2 * n end EOM

assert_eval 42, "double(21)" endend

Page 109: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Unknown :defn 1) Error:TestUbyInterpreter#test_defn:UnknownNodeError: Bug! Unknown node-type :defn to UbyInterpreter ./lib/ruby_interpreter.rb:19:in `eval' ./test/test_ruby_interpreter.rb:17:in `assert_eval' ./test/test_ruby_interpreter.rb:45:in `test_defn'

Page 110: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Generic :defnclass UbyInterpreter < SexpInterpreter # ...

def process_defn s raise "Boom: #{s.inspect}" endend

Page 111: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Examine sub-sexps 1) Error:TestUbyInterpreter#test_defn:RuntimeError: Boom: s(:defn, :double, s(:args, :n), s(:call, s(:lit, 2), :*, s(:lvar, :n))) ./lib/ruby_interpreter.rb:44:in `process_defn' ./lib/ruby_interpreter.rb:19:in `eval' ./test/test_ruby_interpreter.rb:17:in `assert_eval' ./test/test_ruby_interpreter.rb:45:in `test_defn'

Page 112: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Unpack & Storeclass UbyInterpreter < SexpInterpreter # ...

def process_defn s _, name, args, *body = s

self.env[name] = [args, body]

nil endend

EnvironmentEnvironment

n 8

life 42

pi 3

double

[ s(:args, :n),

[s(:call, s(:lit, 2), :*, s(:lvar, :n))]]

Page 113: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

What’s up with :call? 1) Error:TestUbyInterpreter#test_defn:NoMethodError: undefined method `double' for nil:NilClass ./lib/ruby_interpreter.rb:40:in `send' ./lib/ruby_interpreter.rb:40:in `process_call' ./lib/ruby_interpreter.rb:19:in `eval' ./test/test_ruby_interpreter.rb:17:in `assert_eval' ./test/test_ruby_interpreter.rb:54:in `test_defn'

Page 114: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

No NilClass#doubleclass UbyInterpreter < SexpInterpreter # ...

def process_call s _, recv, msg, *args = s

recv = process recv args.map! { |sub| process sub }

recv.send(msg, *args) # big ol' hack… endend

Page 115: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Isolate the Problemclass UbyInterpreter < SexpInterpreter # ...

def process_call s _, recv, msg, *args = s

recv = process recv args.map! { |sub| process sub }

if recv then recv.send(msg, *args) # less of a hack else raise "argh" end endend

Page 116: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Error, Isolated 1) Error:TestUbyInterpreter#test_defn:RuntimeError: argh ./lib/ruby_interpreter.rb:43:in `process_call' ./lib/ruby_interpreter.rb:19:in `eval' ./test/test_ruby_interpreter.rb:17:in `assert_eval' ./test/test_ruby_interpreter.rb:54:in `test_defn'

Page 117: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Set vars & run the codeclass UbyInterpreter < SexpInterpreter # ...

def process_call s _, recv, msg, *args = s

recv = process recv args.map! { |sub| process sub }

if recv then recv.send(msg, *args) # less of a hack else decls, body = self.env[msg]

decls.rest.zip(args).each do |name, val| self.env[name] = val end

process_block s(:block, *body) end endend

Page 118: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

args... decls... zip bwuh?

Page 119: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

EnvironmentEnvironment

n 21

life 42

pi 3

double

[ s(:args, :n),

s(:call, s(:lit, 2), :*, s(:lvar, :n))]

EnvironmentEnvironment

n 8

life 42

pi 3

double

[ s(:args, :n),

s(:call, s(:lit, 2), :*, s(:lvar, :n))]

s(:call, nil, :double, s(:lit, 21))

decls.rest.zip(args).each do |k, v| self.env[k] = vend

[:n].zip([21]).each do |k, v| self.env[k] = vend

self.env[:n] = 21

decls

args

Page 120: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Voilà!# Running tests:

.....

Finished tests in 0.011826s, 422.7972 tests/s, 676.4756 assertions/s.

5 tests, 8 assertions, 0 failures, 0 errors, 0 skips

Page 121: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

“Getting to green just means you don’t have enough

tests.”– Kent Beck

Page 122: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Fibonacci

Page 123: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Conditionals

Runtime

Parser

Test

Dri

ven

Environment

Loops

Functions

Variables

Page 124: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Finally Freakin’ Fibonacci!class TestUbyInterpreter < MiniTest::Unit::TestCase # ...

def test_fib assert_eval nil, <<-END def fib n if n <= 2 then 1 else fib(n-2) + fib(n-1) end end END

assert_eval 8, "fib(6)" endend

Page 125: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Whoa… it ran… but failed 1) Failure:TestUbyInterpreter#test_fib [./test/test_ruby_interpreter.rb:71]:Expected: 8 Actual: 3

6 tests, 10 assertions, 1 failures, 0 errors, 0 skips

Page 126: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

EnvironmentEnvironment

n 4

life 42

pi 3

fib

[ s(:args, :n),

s(:if, ...)]

EnvironmentEnvironment

n 6

life 42

pi 3

fib

[ s(:args, :n),

s(:if, ...)]

EnvironmentEnvironment

n 8

life 42

pi 3

fib

[ s(:args, :n),

s(:if, ...)]

That stupid Table?Yeah...

def fib n if n <= 2 then 1 else fib(n-2) + fib(n-1) endendn = 8; fib(6)n = 6; fib(4) + fib(5)n = 4; ... and so on...

Page 127: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

[ s(:args, :n),

s(:if, ...)]

fib

3pi

42life

n 8

[ s(:args, :n),

s(:if, ...)]

fib

3pi

42life

n 5

[ s(:args, :n),

s(:if, ...)]

fib

3pi

42life

n 3

[ s(:args, :n),

s(:if, ...)]

fib

3pi

42life

n 1

Wanted: Stacked Hashn 1

n 3

n 5

[ s(:args, :n),

s(:if, ...)]

fib

3pi

42life

n 8

fib(1)

fib(3)

fib(5)

original

but acts like:

Page 128: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

6z

5y

4x

2b

3c

42x

1a

z 6

y 5

x 42

3c

2b

1a

Environment Classenv[:x] == ?

env[:x] = 42

all:

scope:

scope:

scope:

Page 129: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!class UbyInterpreter < SexpInterpreter # ...

class Environment def [] k self.all[k] end

def []= k, v @env.last[k] = v end

def all @env.inject(&:merge) end

def scope @env.push({})

yield ensure @env.pop end

def initialize @env = [{}] end endend

Writes to top layer only

Reads from everything

Flattened. Newest wins

Automatic layering

Page 130: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Replace stupid tableclass UbyInterpreter < SexpInterpreter # ...

def initialize # ... self.env = Environment.new end

# ...end

Page 131: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Scope every callclass UbyInterpreter < SexpInterpreter # ...

def process_call s _, recv, msg, *args = s

recv = process recv args.map! { |sub| process sub }

if recv then recv.send(msg, *args) # less of a hack else self.env.scope do decls.rest.zip(args).each do |name, val| self.env[name] = val end

process_block s(:block, *body) end end endend

Page 132: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Finally# Running tests:

......

Finished tests in 0.016849s, 356.1042 tests/s, 712.2084 assertions/s.

6 tests, 12 assertions, 0 failures, 0 errors, 0 skips

Page 133: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

While Loops

Page 134: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Runtime

Environment

Variables

Functions

Parser

Test

Dri

ven

ConditionalsLoops

Page 135: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Refactor Fibonnaciclass TestUbyInterpreter < MiniTest::Unit::TestCase # ...

def define_fib assert_eval nil, <<-END def fib n if n <= 2 then 1 else fib(n-2) + fib(n-1) end end END endend

Page 136: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Add :while testsclass TestUbyInterpreter < MiniTest::Unit::TestCase # ...

def test_while_sum_of_fibs define_fib

assert_eval 1+1+2+3+5+8+13+21+34+55, <<-EOM n = 1 sum = 0 while n <= 10 sum += fib(n) n += 1 end sum EOM endend

Page 137: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Unknown :while 1) Error:TestUbyInterpreter#test_while_fib:UnknownNodeError: Bug! Unknown node-type :while to UbyInterpreter ./lib/ruby_interpreter.rb:29:in `process_block' ./lib/ruby_interpreter.rb:28:in `each' ./lib/ruby_interpreter.rb:28:in `process_block' ./lib/ruby_interpreter.rb:19:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:86:in `test_while_fib'

Page 138: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Define :while genericallyclass UbyInterpreter < SexpInterpreter # ...

def process_while s raise "Boom: #{s.inspect} endend

Page 139: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

See sub-sexps 1) Error:TestUbyInterpreter#test_while:RuntimeError: Boom: s(:while, s(:call, s(:lvar, :n), :<, s(:lit, 41)), s(:lasgn, :n, s(:call, s(:lvar, :n), :+, s(:lit, 1))), true) ./lib/ruby_interpreter.rb:104:in `process_while' ./lib/ruby_interpreter.rb:29:in `process_block' ./lib/ruby_interpreter.rb:28:in `each' ./lib/ruby_interpreter.rb:28:in `process_block' ./lib/ruby_interpreter.rb:19:in `eval' ./test/test_ruby_interpreter.rb:15:in `assert_eval' ./test/test_ruby_interpreter.rb:62:in `test_while'

Page 140: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Define :whileclass UbyInterpreter < SexpInterpreter # ...

def process_while s _, cond, *body = s body.pop # pre vs post condition -- ignore for now

while process cond process_block s(:block, *body) end endend

Page 141: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Voilà# Running tests:

.......

Finished tests in 0.020218s, 346.2261 tests/s, 544.0696 assertions/s.

7 tests, 11 assertions, 0 failures, 0 errors, 0 skips

Page 142: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

What Have We Done?

Page 143: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!require "ruby_parser"require "sexp_processor"

class UbyInterpreter < SexpInterpreter VERSION = "1.0.0"

attr_accessor :parser attr_accessor :env

def initialize super

self.parser = Ruby19Parser. new self.env = Environment.new end

def eval src process parse src end

def parse src self.parser.process src end

def process_block s result = nil s.rest.each do |sub| result = process sub end result end

def process_call s _, recv, msg, *args = s

recv = process recv args.map! { |sub| process sub }

if recv then recv.send(msg, *args) else d, body = self.env[msg]

self.env.scope do d.rest.zip(args). each do |k, v| self.env[k] = v end

process_block s(:block, *body) end end end

def process_defn s _, name, args, *body = s

self.env[name] = [args, body]

nil end

def process_false s false end

def process_if s _, c, t, f = s

c = process c

if c then process t else process f end end

def process_lasgn s _, name, val = s

self.env[name] = process val end

def process_lit s s.last end

def process_lvar s _, name = s

self.env[name] end

def process_nil s nil end

def process_true s true end

def process_while s _, cond, *body = s body.pop

while process cond process_block s(:block, *body) end end

class Environment def [] k self.all[k] end

def []= k, v @env.last[k] = v end

def all @env.inject(&:merge) end

def scope @env.push({})

yield ensure @env.pop end

def initialize @env = [{}] end endend

Page 144: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

class TestUbyInterpreter < MiniTest::Unit::TestCase attr_accessor :int

def setup self.int = UbyInterpreter.new end

def assert_eval exp, src, msg = nil assert_equal exp, int.eval(src), msg end

def define_fib assert_eval nil, <<-END def fib n if n <= 2 then 1 else fib(n-2) + fib(n-1) end end END end

def test_sanity assert_eval 3, "3" assert_eval 7, "3 + 4" end

def test_defn assert_eval nil, <<-EOM n = 24 def double n 2 * n end EOM

assert_eval 42, "double(21)" end

def test_fib define_fib

assert_eval 8, "fib(6)" end

def test_if assert_eval 42, "if true then 42 else 24 end" end

def test_if_falsey assert_eval 24, "if nil then 42 else 24 end" assert_eval 24, "if false then 42 else 24 end" end

def test_lvar assert_eval 42, "x = 42; x" end

def test_while_fib define_fib

assert_eval 1+1+2+3+5+8+13+21+34+55, <<-EOM n = 1 sum = 0 while n <= 10 sum += fib(n) n += 1 end sum EOM endend

Page 145: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

“Uby” Language

• Basic numeric types, true, false, nil.• Conditional branching and looping.• Primitive & user defined functions.• Local variables & variable scoping.• Test-driven, extensible, patterns-based design.• ~2 hours, ~130 LOC impl, ~70 LOC test.• Fits in one head.

Page 146: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

What Else Can We Do?• Add richer types: strings, arrays, hashes, etc.

• Enforce different scoping rules (eg. ruby's opaque def).

• Implement recursive tail-calls.

• Add an object system.

• Change the way functions are called.

Page 147: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Further Study

Page 148: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Page 149: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Page 150: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Fantastic Books

Page 151: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Page 152: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

No time for questions?

Please grab me in the hallway.

Page 153: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

"ank You…

Page 154: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Bonus:Life T'

Page 155: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Typeface:L$o(

Page 156: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Rubyb g k p q" ) ∂

Page 157: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Scoring Ligatured Wordsligatures = /NN|OO|TT|Qu|fff|tt|www|[HMN]E|[HN]K|(?:ff|[Tcfs])h|(?:ff|[cfs])k|(?:ff|[cfi])t|(?:ff|it|tt|[frt])y|[is]p|tt?i|O[CG]|i[vw]|ff?[bj]/

dict = File.readlines("/usr/share/dict/words").map(&:chomp)words = Hash.new 0

dict.each do |word| start = 0

hits = word.scan(ligatures) words[word] = hits.size unless hits.empty?end

words.sort_by { |w,v| [-v, w] }.each do |word, score| puts "%2d: %s" % [score, word]end

Page 158: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Ar+!e&onicapen!en#a(,'an!produ"#$

Page 159: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

Page 160: Trolls of 2013ryan/presentations/2013_MWRC... · 2013-04-08 · MWRC 2013, Salt Lake City, UT Trolls of 2013 Ryan Davis, Seattle.rb • Followup of my talk, “Occupy Ruby: Why We

MWRC 2013, Salt Lake City, UT

Ryan Davis, Seattle.rbLet’s Write an Interpreter!

"ank You