Skip to content

Instantly share code, notes, and snippets.

@sma
Created December 25, 2009 17:56
Show Gist options
  • Save sma/263687 to your computer and use it in GitHub Desktop.
Save sma/263687 to your computer and use it in GitHub Desktop.
enough Python code to simulate a run a simple Ruby fragment in AST form
class RbClass:
def __init__(self):
self.methods = {}
def define_method(self, name, method):
self.methods[name] = method
def lookup(self, name):
return self.methods[name]
class RbObject:
def __init__(self, rb_class):
self.rb_class = rb_class
self.instvars = {}
class RbMethod:
def __init__(self, params, body):
self.params, self.body = params, body
def call(self, env):
return self.body.eval(self.params.bind(env))
class RbBlock(object):
def __init__(self, env, params, body):
self.env, self.params, self.body = env, params, body
def call(self, env):
env = Env(env.ruby, self.env.receiver, env.args)
return self.body.eval(self.params.bind(env))
class Block_call_method:
def call(self, env):
return env.receiver.call(env)
class Object_puts_method:
def call(self, env):
for arg in env.args: print arg
class Ruby:
def __init__(self):
self.object_class = RbClass()
self.object_class.define_method("puts", Object_puts_method())
self.block_class = RbClass()
self.block_class.define_method("call", Block_call_method())
self.main = RbObject(self.object_class)
def class_of(self, obj):
if isinstance(obj, RbBlock):
return self.block_class
return obj.rb_class
class Env:
def __init__(self, ruby, receiver=None, args=None):
self.ruby = ruby
self.receiver = receiver or ruby.main
self.args = args
self.locals = {}
def define_method(self, name, method):
self.ruby.class_of(self.receiver).define_method(name, method)
def send(self, receiver, name, args):
return self.ruby.class_of(receiver).lookup(name).call(Env(self.ruby, receiver, args))
class Seq:
def __init__(self, *body):
self.body = body
def eval(self, env):
result = None
for ast in self.body:
result = ast.eval(env)
return result
class Def:
def __init__(self, name, params, *body):
self.name, self.params, self.body = name, params, Seq(*body)
def eval(self, env):
env.define_method(self.name, RbMethod(self.params, self.body))
class Params:
def __init__(self, *names):
self.names = names
def bind(self, env):
for name, arg in zip(self.names, env.args):
env.locals[name] = arg
return env
class Assign:
def __init__(self, lhs, rhs):
self.lhs, self.rhs = lhs, rhs
def eval(self, env):
self.lhs.set(env, self.rhs.eval(env))
class InstVar:
def __init__(self, name):
self.name = name
def set(self, env, value):
env.receiver.instvars[self.name] = value
def eval(self, env):
return env.receiver.instvars[self.name]
class Var:
def __init__(self, name):
self.name = name
def eval(self, env):
return env.locals[self.name]
class Call:
def __init__(self, name, *args):
self.name, self.args = name, args
def eval(self, env):
return env.send(env.receiver, self.name, [arg.eval(env) for arg in self.args])
class Block:
def __init__(self, params, *body):
self.params, self.body = params, Seq(*body)
def eval(self, env):
return RbBlock(env, self.params, self.body)
class Interpolation:
def __init__(self, *parts):
self.parts = parts
def eval(self, env):
return "".join(str(part.eval(env)) for part in self.parts)
class Lit:
def __init__(self, value):
self.value = value
def eval(self, env):
return self.value
class ReceiverCall:
def __init__(self, receiver, name, *args):
self.receiver, self.name, self.args = receiver, name, args
def eval(self, env):
return env.send(self.receiver.eval(env), self.name, [arg.eval(env) for arg in self.args])
ast = Seq(
Def("remember", Params("a_block"),
Assign(InstVar("@block"), Var("a_block"))
),
Call("remember", Block(Params("name"),
Call("puts", Interpolation(Lit("Hello, "), Var("name"), Lit("!")))
)),
ReceiverCall(InstVar("@block"), "call", Lit("Stefan"))
)
ast.eval(Env(Ruby()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment