Skip to content

Commit dea06b1

Browse files
committed
Merge pull request pixie-lang#212 from thomasmulvaney/fn-arg-check
Fn arg check
2 parents 2373aac + 7191e20 commit dea06b1

7 files changed

Lines changed: 88 additions & 60 deletions

File tree

pixie/test.pxi

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,22 @@
6161
yr# ~y]
6262
(assert (= xr# yr#) (str (show '~x xr#) " != " (show '~y yr#)))))
6363

64+
(defmacro assert-throws? [klass msg body]
65+
`(try
66+
~body
67+
(assert false (str "Expected a " ~klass " exception: " ~msg))
68+
(catch e#
69+
(assert (= (type e#) ~klass)
70+
(str "Expected exception of class " ~klass " but got " (type e#)))
71+
(assert (= (ex-msg e#) ~msg)
72+
(str "Expected message: " ~msg " but got " (ex-msg e#))))))
73+
6474
(defmacro assert [x]
6575
`(let [x# ~x]
6676
(assert x# (str '~x " is " x#))))
6777

78+
79+
6880
(defn show
6981
([orig res]
7082
(if (= orig res)

pixie/vm/code.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
py_object = object
22
import pixie.vm.object as object
3-
from pixie.vm.object import affirm
3+
from pixie.vm.object import affirm, runtime_error
44
from pixie.vm.primitives import nil, false
55
from rpython.rlib.rarithmetic import r_uint
66
from rpython.rlib.jit import elidable_promote, promote
@@ -101,6 +101,9 @@ def meta(self):
101101
def with_meta(self, meta):
102102
assert false, "not implemented"
103103

104+
def name(self):
105+
return self._name
106+
104107
def set_macro(self):
105108
self._is_macro = True
106109

@@ -130,15 +133,16 @@ class MultiArityFn(BaseCode):
130133
def type(self):
131134
return MultiArityFn._type
132135

133-
def __init__(self, arities, required_arity=0, rest_fn=None, meta=nil):
136+
def __init__(self, name, arities, required_arity=0, rest_fn=None, meta=nil):
134137
BaseCode.__init__(self)
138+
self._name = name
135139
self._arities = arities
136140
self._required_arity = required_arity
137141
self._rest_fn = rest_fn
138142
self._meta = meta
139143

140144
def with_meta(self, meta):
141-
return MultiArityFn(self._arities, self._required_arity, self._rest_fn, meta)
145+
return MultiArityFn(self._name, self._arities, self._required_arity, self._rest_fn, meta)
142146

143147
@elidable_promote()
144148
def get_fn(self, arity):
@@ -153,9 +157,9 @@ def get_fn(self, arity):
153157
acc.append(unicode(str(x)))
154158

155159
if self._rest_fn:
156-
acc.append(u" or more")
160+
acc.append(unicode(str(self._rest_fn.required_arity())) + u" or more")
157161

158-
affirm(False, u"Wrong number of args to fn: got " + unicode(str(arity)) + u" expected " + u",".join(acc))
162+
runtime_error(u"Wrong number of arguments " + unicode(str(arity)) + u" for function '" + unicode(self._name) + u"'. Expected " + u",".join(acc))
159163

160164
def invoke(self, args):
161165
return self.invoke_with(args, self)
@@ -209,7 +213,12 @@ def get_debug_points(self):
209213
return self._debug_points
210214

211215
def invoke(self, args):
212-
return self.invoke_with(args, self)
216+
if len(args) == self.get_arity():
217+
return self.invoke_with(args, self)
218+
else:
219+
runtime_error(u"Invalid number of arguments " + unicode(str(len(args)))
220+
+ u" for function '" + unicode(str(self._name)) + u"'. Expected "
221+
+ unicode(str(self.get_arity())))
213222

214223
def invoke_with(self, args, this_fn):
215224
try:
@@ -254,6 +263,12 @@ def __init__(self, code, required_arity, meta=nil):
254263

255264
def with_meta(self, meta):
256265
return VariadicCode(self._code, self._required_arity, meta)
266+
267+
def name(self):
268+
return None
269+
270+
def required_arity(self):
271+
return self._required_arity
257272

258273
def invoke(self, args):
259274
return self.invoke_with(args, self)
@@ -292,6 +307,10 @@ def __init__(self, code, closed_overs, meta=nil):
292307
def with_meta(self, meta):
293308
return Closure(self._code, self._closed_overs, meta)
294309

310+
311+
def name(self):
312+
return None
313+
295314
def invoke(self, args):
296315
return self.invoke_with(args, self)
297316

pixie/vm/compiler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def gensym2(prefix):
3333
return rt.symbol(rt.str(prefix, i))
3434

3535
gensym = code.intern_var(u"pixie.stdlib", u"gensym")
36-
gensym.set_root(code.MultiArityFn({0: code.wrap_fn(gensym1), 1: code.wrap_fn(gensym2)}))
36+
gensym.set_root(code.MultiArityFn(u"gensym", {0: code.wrap_fn(gensym1), 1: code.wrap_fn(gensym2)}))
3737

3838
class with_ns(object):
3939
def __init__(self, nm, include_stdlib=False):

pixie/vm/interpreter.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,8 @@ def push_nth(self, delta):
9898
self.push(self.nth(delta))
9999

100100
def push_arg(self, idx):
101-
if not 0 <= idx < len(self.args):
102-
runtime_error(u"Invalid number of arguments " + unicode(str(idx))
103-
+ u" for function '" + unicode(str(self.code_obj._name)) + u"'. Expected "
104-
+ unicode(str(self.code_obj.get_arity())))
105-
106-
self.push(self.args[r_uint(idx)])
101+
if 0 <= idx < len(self.args):
102+
self.push(self.args[r_uint(idx)])
107103

108104
@unroll_safe
109105
def push_n(self, args, argc):
@@ -140,6 +136,7 @@ def make_multi_arity(frame, argc):
140136
d = {}
141137
required_arity = 0
142138
rest_fn = None
139+
fn_name = None
143140
for i in range(argc):
144141
a = frame.get_inst()
145142
if a & 256:
@@ -148,9 +145,9 @@ def make_multi_arity(frame, argc):
148145
rest_fn = frame.pop()
149146
else:
150147
fn = frame.pop()
148+
fn_name = fn.name()
151149
d[a] = fn
152-
153-
return code.MultiArityFn(d, required_arity, rest_fn)
150+
return code.MultiArityFn(fn_name, d, required_arity, rest_fn)
154151

155152
class ShallowContinuation(Object):
156153
_type = Type(u"pixie.stdlib.ShallowContinuation")

pixie/vm/libs/string.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def index_of4(a, sep, start, end):
4747
runtime_error(u"Third and fourth argument must be non-negative integers")
4848

4949
index_of = intern_var(u"pixie.string.internal", u"index-of")
50-
index_of.set_root(MultiArityFn({2: wrap_fn(index_of2), 3: wrap_fn(index_of3), 4: wrap_fn(index_of4)},
50+
index_of.set_root(MultiArityFn(u"index-of", {2: wrap_fn(index_of2), 3: wrap_fn(index_of3), 4: wrap_fn(index_of4)},
5151
required_arity = 2))
5252

5353
def substring2(a, start):
@@ -64,7 +64,7 @@ def substring3(a, start, end):
6464
runtime_error(u"Second and third argument must be non-negative integers")
6565

6666
substring = intern_var(u"pixie.string.internal", u"substring")
67-
substring.set_root(MultiArityFn({2: wrap_fn(substring2), 3: wrap_fn(substring3)},
67+
substring.set_root(MultiArityFn(u"substring", {2: wrap_fn(substring2), 3: wrap_fn(substring3)},
6868
required_arity = 2))
6969

7070
@as_var("pixie.string.internal", "upper-case")

tests/pixie/tests/test-fns.pxi

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,40 +18,41 @@
1818
(t/deftest test-code-arity-errors
1919
(let [arity-0 (fn arity-0 [])
2020
arity-1 (fn arity-1 [a])
21-
arity-2 (fn arity-2 [a b])]
22-
(try
23-
(arity-0 :foo)
24-
(catch e
25-
(t/assert=
26-
(ex-msg e)
27-
"Invalid number of arguments 1 for function 'arity-0'. Expected 0")))
28-
(try
29-
(arity-0 :foo :bar)
30-
(catch e
31-
(t/assert=
32-
(ex-msg e)
33-
"Invalid number of arguments 2 for function 'arity-0'. Expected 0")))
34-
(try
35-
(arity-1)
36-
(catch e
37-
(t/assert=
38-
(ex-msg e)
39-
"Invalid number of arguments 0 for function 'arity-1'. Expected 1")))
40-
(try
41-
(arity-1 :foo :bar)
42-
(catch e
43-
(t/assert=
44-
(ex-msg e)
45-
"Invalid number of arguments 2 for function 'arity-1'. Expected 1")))
46-
(try
47-
(arity-2)
48-
(catch e
49-
(t/assert=
50-
(ex-msg e)
51-
"Invalid number of arguments 0 for function 'arity-2'. Expected 2")))
52-
(try
53-
(arity-2 :foo)
54-
(catch e
55-
(t/assert=
56-
(ex-msg e)
57-
"Invalid number of arguments 1 for function 'arity-2'. Expected 2")))))
21+
arity-2 (fn arity-2 [a b])
22+
arity-0-or-1 (fn arity-0-or-1 ([]) ([a]))
23+
arity-1-or-3 (fn arity-1-or-3 ([a]) ([a b c]))
24+
arity-0-or-1-or-3-or-more
25+
(fn arity-0-or-1-or-3-or-more ([]) ([a]) ([a b c & more]))]
26+
(t/assert-throws? RuntimeException
27+
"Invalid number of arguments 1 for function 'arity-0'. Expected 0"
28+
(arity-0 :foo))
29+
(t/assert-throws? RuntimeException
30+
"Invalid number of arguments 2 for function 'arity-0'. Expected 0"
31+
(arity-0 :foo :bar))
32+
(t/assert-throws? RuntimeException
33+
"Invalid number of arguments 0 for function 'arity-1'. Expected 1"
34+
(arity-1))
35+
(t/assert-throws? RuntimeException
36+
"Invalid number of arguments 2 for function 'arity-1'. Expected 1"
37+
(arity-1 :foo :bar))
38+
(t/assert-throws? RuntimeException
39+
"Invalid number of arguments 0 for function 'arity-2'. Expected 2"
40+
(arity-2))
41+
(t/assert-throws? RuntimeException
42+
"Invalid number of arguments 1 for function 'arity-2'. Expected 2"
43+
(arity-2 :foo))
44+
(t/assert-throws? RuntimeException
45+
"Wrong number of arguments 2 for function 'arity-0-or-1'. Expected 1,0"
46+
(arity-0-or-1 :foo :bar))
47+
(t/assert-throws? RuntimeException
48+
"Wrong number of arguments 3 for function 'arity-0-or-1'. Expected 1,0"
49+
(arity-0-or-1 :foo :bar :baz))
50+
(t/assert-throws? RuntimeException
51+
"Wrong number of arguments 2 for function 'arity-1-or-3'. Expected 3,1"
52+
(arity-1-or-3 :foo :bar))
53+
(t/assert-throws? RuntimeException
54+
"Wrong number of arguments 0 for function 'arity-1-or-3'. Expected 3,1"
55+
(arity-1-or-3))
56+
(t/assert-throws? RuntimeException
57+
"Wrong number of arguments 2 for function 'arity-0-or-1-or-3-or-more'. Expected 1,0,3 or more"
58+
(arity-0-or-1-or-3-or-more :foo :bar))))

tests/pixie/tests/test-stdlib.pxi

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,9 @@
311311
(t/assert= (merge-with identity {} {:a 1, :b 2}) {:a 1, :b 2})
312312
(t/assert= (merge-with identity {:a 1} {:b 2}) {:a 1, :b 2})
313313

314-
(t/assert= (merge-with #(identity %1) {:a 1} {:a 2}) {:a 1})
315-
(t/assert= (merge-with #(identity %1) {:a 1} {:a 2} {:a 3}) {:a 1})
316-
(t/assert= (merge-with #(identity %2) {:a 1} {:a 2}) {:a 2})
314+
(t/assert= (merge-with (fn [a b] a) {:a 1} {:a 2}) {:a 1})
315+
(t/assert= (merge-with (fn [a b] a) {:a 1} {:a 2} {:a 3}) {:a 1})
316+
(t/assert= (merge-with (fn [a b] b) {:a 1} {:a 2}) {:a 2})
317317

318318
(t/assert= (merge-with + {:a 21} {:a 21}) {:a 42})
319319
(t/assert= (merge-with + {:a 21} {:a 21, :b 1}) {:a 42, :b 1}))
@@ -333,9 +333,8 @@
333333

334334
(t/deftest test-range
335335
(t/assert= (= (-seq (range 10))
336-
(-seq (-iterator (range 10))
337-
(reduce conj nil (range 10))
338-
'(0 1 2 3 4 5 6 7 8 9)))
336+
(-seq (-iterator (range 10)))
337+
'(0 1 2 3 4 5 6 7 8 9))
339338
true))
340339

341340
(t/deftest test-ns

0 commit comments

Comments
 (0)