Skip to content

Commit 23865d7

Browse files
committed
functions can now refer to themselves
1 parent ead754f commit 23865d7

6 files changed

Lines changed: 56 additions & 37 deletions

File tree

pixie/stdlib.lisp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -474,15 +474,14 @@
474474
(defn swap! [a f & args]
475475
(reset! a (apply f @a args)))
476476

477-
(def update-inner-f (fn inner-f
478-
([m f k]
479-
(assoc m k (f (get m k))))
480-
([m f k & ks]
481-
(assoc m k (apply update-inner-f m f ks)))))
482-
483477
(defn update-in
484478
[m ks f & args]
485-
(let [f (fn [m] (apply f m args))]
479+
(let [f (fn [m] (apply f m args))
480+
update-inner-f (fn update-inner-f
481+
([m f k]
482+
(assoc m k (f (get m k))))
483+
([m f k & ks]
484+
(assoc m k (apply update-inner-f m f ks))))]
486485
(apply update-inner-f m f ks)))
487486

488487
(defn nil? [x]

pixie/vm/code.py

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,6 @@ def set_macro(self):
102102
def is_macro(self):
103103
return self._is_macro
104104

105-
def _invoke(self, args):
106-
raise NotImplementedError()
107-
108105
def get_consts(self):
109106
raise NotImplementedError()
110107

@@ -116,9 +113,12 @@ def stack_size(self):
116113
return 0
117114

118115
def invoke(self, args):
119-
result = self._invoke(args)
116+
result = self.invoke(args)
120117
return result
121118

119+
def invoke_with(self, args, this_fn):
120+
return self.invoke(args)
121+
122122

123123
class MultiArityFn(BaseCode):
124124
_type = object.Type(u"pixie.stdlib.MultiArityFn")
@@ -155,8 +155,11 @@ def get_fn(self, arity):
155155

156156
affirm(False, u"Wrong number of args to fn: got " + unicode(str(arity)) + u" expected " + u",".join(acc))
157157

158-
def _invoke(self, args):
159-
return self.get_fn(len(args)).invoke(args)
158+
def invoke(self, args):
159+
return self.invoke_with(args, self)
160+
161+
def invoke_with(self, args, self_fn):
162+
return self.get_fn(len(args)).invoke_with(args, self_fn)
160163

161164

162165

@@ -171,12 +174,15 @@ def __init__(self):
171174
def type(self):
172175
return NativeFn._type
173176

174-
def _invoke(self, args):
177+
def invoke(self, args):
175178
return self.inner_invoke(args)
176179

177180
def inner_invoke(self, args):
178181
raise NotImplementedError()
179182

183+
def invoke_with(self, args, this_fn):
184+
return self.invoke(args)
185+
180186

181187
class Code(BaseCode):
182188
"""Interpreted code block. Contains consts and """
@@ -201,9 +207,12 @@ def with_meta(self, meta):
201207
def get_debug_points(self):
202208
return self._debug_points
203209

204-
def _invoke(self, args):
210+
def invoke(self, args):
211+
return self.invoke_with(args, self)
212+
213+
def invoke_with(self, args, this_fn):
205214
try:
206-
return interpret(self, args)
215+
return interpret(self, args, self_obj=this_fn)
207216
except object.WrappedException as ex:
208217
ex._ex._trace.append(object.PixieCodeInfo(self._name))
209218
raise
@@ -242,20 +251,23 @@ def __init__(self, code, required_arity, meta=nil):
242251
def with_meta(self, meta):
243252
return VariadicCode(self._code, self._required_arity, meta)
244253

245-
def _invoke(self, args):
254+
def invoke(self, args):
255+
return self.invoke_with(args, self)
256+
257+
def invoke_with(self, args, self_fn):
246258
from pixie.vm.array import array
247259
argc = len(args)
248260
if self._required_arity == 0:
249-
return self._code.invoke([array(args)])
261+
return self._code.invoke_with([array(args)], self_fn)
250262
if argc == self._required_arity:
251263
new_args = resize_list(args, len(args) + 1)
252264
new_args[len(args)] = array([])
253-
return self._code.invoke(new_args)
265+
return self._code.invoke_with(new_args, self_fn)
254266
elif argc > self._required_arity:
255267
start = slice_from_start(args, self._required_arity, 1)
256268
rest = slice_to_end(args, self._required_arity)
257269
start[self._required_arity] = array(rest)
258-
return self._code.invoke(start)
270+
return self._code.invoke_with(start, self_fn)
259271
affirm(False, u"Got " + unicode(str(argc)) + u" arg(s) need at least " + unicode(str(self._required_arity)))
260272

261273
class Closure(BaseCode):
@@ -274,9 +286,12 @@ def __init__(self, code, closed_overs, meta=nil):
274286
def with_meta(self, meta):
275287
return Closure(self._code, self._closed_overs, meta)
276288

277-
def _invoke(self, args):
289+
def invoke(self, args):
290+
return self.invoke_with(args, self)
291+
292+
def invoke_with(self, args, self_fn):
278293
try:
279-
return interpret(self, args)
294+
return interpret(self, args, self_obj=self_fn)
280295
except object.WrappedException as ex:
281296
ex._ex._trace.append(object.PixieCodeInfo(self._code._name))
282297
raise
@@ -381,7 +396,10 @@ def deref(self):
381396
def is_defined(self):
382397
return self._root is not undefined
383398

384-
def _invoke(self, args):
399+
def invoke_with(self, args, this_fn):
400+
return self.invoke(args)
401+
402+
def invoke(self, args):
385403
return self.deref().invoke(args)
386404

387405
class bindings(py_object):
@@ -510,7 +528,7 @@ class DefaultProtocolFn(NativeFn):
510528
def __init__(self, pfn):
511529
self._pfn = pfn
512530

513-
def _invoke(self, args):
531+
def invoke(self, args):
514532
from pixie.vm.string import String
515533
tp = args[0].type()._name
516534
affirm(False, u"No override for " + tp + u" on " + self._pfn._name + u" in protocol " + self._pfn._protocol._name)
@@ -574,7 +592,7 @@ def get_protocol_fn(self, tp, rev):
574592
fn = self._dict.get(tp, self._default_fn)
575593
return promote(fn)
576594

577-
def _invoke(self, args):
595+
def invoke(self, args):
578596
a = args[0].type()
579597
fn = self.get_protocol_fn(a, self._rev)
580598
try:
@@ -621,7 +639,7 @@ def get_fn(self, tp1, tp2, _rev):
621639
fn = d1.get(tp2, self._default_fn)
622640
return promote(fn)
623641

624-
def _invoke(self, args):
642+
def invoke(self, args):
625643
affirm(len(args) >= 2, u"DoublePolymorphicFunctions take at least two args")
626644
a = args[0].type()
627645
b = args[1].type()

pixie/vm/compiler.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ def call_macro(var, form, ctx):
275275
class CompileMapRf(code.NativeFn):
276276
def __init__(self, ctx):
277277
self._ctx = ctx
278-
def _invoke(self, args):
278+
def invoke(self, args):
279279
map_entry = args[1]
280280
compile_form(rt.key(map_entry), self._ctx)
281281
compile_form(rt.val(map_entry), self._ctx)
@@ -407,7 +407,7 @@ def compile_platform_eq(form, ctx):
407407
def add_args(name, args, ctx):
408408
required_args = -1
409409
local_idx = 0
410-
#ctx.add_local(name, Self())
410+
ctx.add_local(name, Self())
411411
for x in range(rt.count(args)):
412412
arg = rt.nth(args, rt.wrap(x))
413413
affirm(isinstance(arg, symbol.Symbol), u"Argument names must be symbols")
@@ -456,7 +456,7 @@ def compile_fn(form, ctx):
456456

457457
def compile_fn_body(name, args, body, ctx):
458458
new_ctx = Context(name._str, rt.count(args), ctx)
459-
required_args = add_args(name, args, new_ctx)
459+
required_args = add_args(name._str, args, new_ctx)
460460
bc = 0
461461

462462
if name is not None:

pixie/vm/interpreter.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ class Frame(object):
3131
"base_code",
3232
"closed_overs[*]",
3333
"finished",
34-
"_is_continuation"
34+
"_is_continuation",
35+
"self_obj"
3536
]
36-
def __init__(self, code_obj, args):
37+
def __init__(self, code_obj, args, self_obj):
3738
self = hint(self, access_directly=True, fresh_virtualizable=True)
3839
self.code_obj = code_obj
40+
self.self_obj = self_obj
3941
self.sp = r_uint(0)
4042
self.ip = r_uint(0)
4143
self.stack = [None] * code_obj.stack_size()
@@ -169,7 +171,7 @@ def interpret(code_obj=None, args=[], self_obj = None, frame=None):
169171

170172
if frame is None:
171173
assert code_obj is not None
172-
frame = Frame(code_obj, args)
174+
frame = Frame(code_obj, args, self_obj or code_obj)
173175

174176

175177

@@ -302,7 +304,7 @@ def interpret(code_obj=None, args=[], self_obj = None, frame=None):
302304
argc = frame.get_inst()
303305
args = frame.pop_n(argc)
304306

305-
frame = Frame(frame.code_obj, args)
307+
frame = Frame(frame.code_obj, args, frame.self_obj)
306308

307309
jitdriver.can_enter_jit(bc=frame.bc,
308310
ip=frame.ip,
@@ -313,7 +315,7 @@ def interpret(code_obj=None, args=[], self_obj = None, frame=None):
313315
continue
314316

315317
if inst == code.PUSH_SELF:
316-
frame.push(frame.code_obj)
318+
frame.push(frame.self_obj)
317319
continue
318320

319321
if inst == code.DUP_NTH:

pixie/vm/stacklet.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def __init__(self, h):
5757
def type(self):
5858
return WrappedHandler._type
5959

60-
def _invoke(self, args):
60+
def invoke(self, args):
6161
affirm(len(args) == 1, u"Only one arg to continuation allowed")
6262
global_state._from = global_state._to
6363
global_state._to = self

pixie/vm/test/test_stacklet.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from pixie.vm.primitives import nil
66

77
class YieldingFn(code.BaseCode):
8-
def _invoke(self, args):
8+
def invoke(self, args):
99
assert len(args) == 2
1010
hdler = args[0]
1111
arg = args[1]
@@ -29,7 +29,7 @@ def yielding_fn(yld):
2929
class WrappingFn(code.NativeFn):
3030
def __init__(self, cont):
3131
self._cont = cont
32-
def _invoke(self, args):
32+
def invoke(self, args):
3333
ret = args[0]
3434
ret.invoke([self._cont.invoke([4])])
3535

0 commit comments

Comments
 (0)