From 3b6f3669a584830ca9be9e1f70fe941c91d2009c Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 13 Nov 2017 14:12:39 +0100 Subject: [PATCH] Implement Binding interface https://ruby-doc.org/core-2.4.0/Binding.html --- tests/objects/test_bindingobject.py | 38 +++++++++++++++++++++++++++++ topaz/objects/bindingobject.py | 38 +++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/tests/objects/test_bindingobject.py b/tests/objects/test_bindingobject.py index ea3701e24..ee1f8bda1 100644 --- a/tests/objects/test_bindingobject.py +++ b/tests/objects/test_bindingobject.py @@ -33,3 +33,41 @@ def test_unused_closure(self, space): return binding.eval('12') """) assert space.int_w(w_res) == 12 + + def test_local_variable_definedp(self, space): + w_res = space.execute(""" + a = 5 + return binding.local_variable_defined?('a') + """) + assert w_res == space.w_true + + def test_local_variable_get(self, space): + w_res = space.execute(""" + a = 5 + return binding.local_variable_get('a') + """) + assert space.int_w(w_res) == 5 + + def test_local_variable_set(self, space): + w_res = space.execute(""" + a = 5 + binding.local_variable_set('a', 42) + return a + """) + assert space.int_w(w_res) == 42 + + def test_local_variables(self, space): + w_res = space.execute(""" + a = 5 + x = 'foo' + return binding.local_variables + """) + res_w = space.listview(w_res) + assert space.str_w(res_w[0]) == 'a' + assert space.str_w(res_w[1]) == 'x' + + def test_receiver(self, space): + w_res = space.execute(""" + return binding.receiver == self + """) + assert w_res == space.w_true diff --git a/topaz/objects/bindingobject.py b/topaz/objects/bindingobject.py index f7408384e..6b429306f 100644 --- a/topaz/objects/bindingobject.py +++ b/topaz/objects/bindingobject.py @@ -1,11 +1,14 @@ +from rpython.rlib import jit + from topaz.astcompiler import SymbolTable +from topaz.closure import ClosureCell from topaz.module import ClassDef from topaz.objects.objectobject import W_Object class W_BindingObject(W_Object): classdef = ClassDef("Binding", W_Object.classdef) - _immutable_fields_ = ["names[*]", "cells[*]", "w_self", "lexical_scope"] + _immutable_fields_ = ["names[*]?", "cells[*]?", "w_self", "lexical_scope"] def __init__(self, space, names, cells, w_self, lexical_scope): W_Object.__init__(self, space) @@ -22,8 +25,39 @@ def method_eval(self, space, source): for name in self.names: symtable.cells[name] = symtable.FREEVAR bc = space.compile(source, "(eval)", symtable=symtable) - frame = space.create_frame(bc, w_self=self.w_self, lexical_scope=self.lexical_scope) + frame = space.create_frame( + bc, w_self=self.w_self, lexical_scope=self.lexical_scope) for idx, cell in enumerate(self.cells): frame.cells[idx + len(bc.cellvars)] = cell with space.getexecutioncontext().visit_frame(frame): return space.execute_frame(frame, bc) + + @classdef.method("local_variable_defined?", key="symbol") + def method_local_variable_definedp(self, space, key): + return space.newbool(key in self.names) + + @jit.unroll_safe + @classdef.method("local_variable_get", key="symbol") + def method_local_variable_get(self, space, key): + for idx, name in enumerate(self.names): + if name == key: + return self.cells[idx].get(space, None, 0) + return space.w_nil + + @jit.unroll_safe + @classdef.method("local_variable_set", key="symbol") + def method_local_variable_set(self, space, key, w_value): + for idx, name in enumerate(self.names): + if name == key: + self.cells[idx].set(space, None, 0, w_value) + return + self.names.append(key) + self.cells.append(ClosureCell(w_value)) + + @classdef.method("local_variables") + def method_local_variables(self, space): + return space.newarray([space.newstr_fromstr(n) for n in self.names]) + + @classdef.method("receiver") + def method_receiver(self, space): + return self.w_self