Created
December 25, 2009 17:56
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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