Skip to content

Commit ef599ea

Browse files
committed
Implement the 'perform:withArguments' primitive.
This requires a few more changes than might appear immediately necessary. First, to make things a bit nicer, I've (slightly tortuously) added an "iter" method to both types of Array. Then, in order to avoid the problem that Java SOM has (SOM-st/SOM#43 (comment)), we have to check the number of arguments passed, which means storing those in methods.
1 parent 48f10d9 commit ef599ea

File tree

7 files changed

+128
-24
lines changed

7 files changed

+128
-24
lines changed

lang_tests/perform_witharguments.som

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"
2+
VM:
3+
status: success
4+
stdout:
5+
5
6+
6
7+
7
8+
"
9+
10+
perform_witharguments = (
11+
run = (
12+
self perform: #f:b:c: withArguments: #(5 6 7).
13+
)
14+
15+
f: a b: b c: c = (
16+
a println.
17+
b println.
18+
c println.
19+
)
20+
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"
2+
VM:
3+
status: error
4+
stderr:
5+
Traceback...
6+
...
7+
Tried passing 1 arguments to a function that requires 3.
8+
"
9+
10+
perform_witharguments_wrong = (
11+
run = (
12+
self perform: #f:b:c: withArguments: #(5).
13+
)
14+
15+
f: a b: b c: c = (
16+
a println.
17+
b println.
18+
c println.
19+
)
20+
)

src/lib/compiler/ast_to_instrs.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,10 @@ impl<'a, 'input> Compiler<'a, 'input> {
248248
((pairs[0].0, name), args)
249249
}
250250
};
251+
let args_len = args.len();
251252
let body = self.c_body(vm, astmeth.span, (name.0, &name.1), args, &astmeth.body)?;
252253
let sig = String_::new_sym(vm, name.1.clone());
253-
let meth = Method::new(vm, sig, body);
254+
let meth = Method::new(vm, sig, args_len, body);
254255
Ok((name.1, Val::from_obj(vm, meth)))
255256
}
256257

src/lib/vm/core.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,44 @@ impl VM {
919919
}
920920
}
921921
Primitive::PerformInSuperClass => unimplemented!(),
922-
Primitive::PerformWithArguments => unimplemented!(),
922+
Primitive::PerformWithArguments => {
923+
let args_tobj = stry!(self.stack.pop().tobj(self));
924+
let args = stry!(args_tobj.to_array());
925+
let sig_val = self.stack.pop();
926+
let sig = stry!(String_::symbol_to_string_(self, sig_val));
927+
let cls_val = rcv.get_class(self);
928+
let cls = stry!(cls_val.downcast::<Class>(self));
929+
match cls.get_method(self, sig.as_str()) {
930+
Ok(m) => {
931+
if args_tobj.length() != m.num_params() {
932+
return SendReturn::Err(VMError::new(
933+
self,
934+
VMErrorKind::WrongNumberOfArgs {
935+
wanted: m.num_params(),
936+
got: args_tobj.length(),
937+
},
938+
));
939+
}
940+
for v in args.iter() {
941+
self.stack.push(v);
942+
}
943+
self.send_args_on_stack(rcv, m, args_tobj.length())
944+
}
945+
Err(box VMError {
946+
kind: VMErrorKind::UnknownMethod,
947+
..
948+
}) => {
949+
let meth = cls
950+
.get_method(self, "doesNotUnderstand:arguments:")
951+
.unwrap();
952+
self.stack.push(sig_val);
953+
let arr = NormalArray::new(self, 0);
954+
self.stack.push(arr);
955+
self.send_args_on_stack(rcv, meth, 2)
956+
}
957+
Err(e) => return SendReturn::Err(e),
958+
}
959+
}
923960
Primitive::PerformWithArgumentsInSuperClass => unimplemented!(),
924961
Primitive::PositiveInfinity => {
925962
let dbl = Double::new(self, f64::INFINITY);

src/lib/vm/error.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ pub enum VMErrorKind {
182182
UnknownGlobal(String),
183183
/// An unknown method.
184184
UnknownMethod,
185+
/// Tried calling a method with the wrong number of arguments.
186+
WrongNumberOfArgs {
187+
wanted: usize,
188+
got: usize,
189+
},
185190
}
186191

187192
impl VMErrorKind {
@@ -234,6 +239,10 @@ impl VMErrorKind {
234239
VMErrorKind::ShiftTooBig => Ok("Shift too big".to_owned()),
235240
VMErrorKind::UnknownGlobal(name) => Ok(format!("Unknown global '{}'", name)),
236241
VMErrorKind::UnknownMethod => Ok("Unknown method".to_owned()),
242+
VMErrorKind::WrongNumberOfArgs { wanted, got } => Ok(format!(
243+
"Tried passing {} arguments to a function that requires {}",
244+
got, wanted
245+
)),
237246
}
238247
}
239248
}

src/lib/vm/objects/array.rs

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,20 @@ use crate::vm::{
1010
};
1111

1212
pub trait Array {
13+
/// Return the item at index `idx` (using SOM indexing starting at 1) or an error if the index
14+
/// is invalid.
1315
fn at(&self, vm: &VM, idx: usize) -> Result<Val, Box<VMError>>;
16+
17+
/// Return the item at index `idx` (using SOM indexing starting at 1). This will lead to
18+
/// undefined behaviour if the index is invalid.
1419
unsafe fn unchecked_at(&self, idx: usize) -> Val;
20+
21+
/// Set the item at index `idx` (using SOM indexing starting at 1) to `val` or return an error
22+
/// if the index is invalid.
1523
fn at_put(&self, vm: &mut VM, idx: usize, val: Val) -> Result<(), Box<VMError>>;
24+
25+
/// Iterate over this array's values.
26+
fn iter<'a>(&'a self) -> ArrayIterator<'a>;
1627
}
1728

1829
#[derive(Debug)]
@@ -54,8 +65,6 @@ impl StaticObjType for NormalArray {
5465
}
5566

5667
impl Array for NormalArray {
57-
/// Return the item at index `idx` (using SOM indexing starting at 1) or an error if the index
58-
/// is invalid.
5968
fn at(&self, vm: &VM, mut idx: usize) -> Result<Val, Box<VMError>> {
6069
let store = unsafe { &*self.store.get() };
6170
if idx > 0 && idx <= store.len() {
@@ -72,8 +81,6 @@ impl Array for NormalArray {
7281
}
7382
}
7483

75-
/// Return the item at index `idx` (using SOM indexing starting at 1). This will lead to
76-
/// undefined behaviour if the index is invalid.
7784
unsafe fn unchecked_at(&self, mut idx: usize) -> Val {
7885
debug_assert!(idx > 0);
7986
let store = &*self.store.get();
@@ -82,8 +89,6 @@ impl Array for NormalArray {
8289
*store.get_unchecked(idx)
8390
}
8491

85-
/// Set the item at index `idx` (using SOM indexing starting at 1) to `val` or return an error
86-
/// if the index is invalid.
8792
fn at_put(&self, vm: &mut VM, mut idx: usize, val: Val) -> Result<(), Box<VMError>> {
8893
let store = unsafe { &mut *self.store.get() };
8994
if idx > 0 && idx <= store.len() {
@@ -100,6 +105,14 @@ impl Array for NormalArray {
100105
))
101106
}
102107
}
108+
109+
fn iter<'a>(&'a self) -> ArrayIterator<'a> {
110+
ArrayIterator {
111+
arr: self,
112+
len: self.length(),
113+
i: 0,
114+
}
115+
}
103116
}
104117

105118
impl NormalArray {
@@ -163,8 +176,6 @@ impl StaticObjType for MethodsArray {
163176
}
164177

165178
impl Array for MethodsArray {
166-
/// Return the item at index `idx` (using SOM indexing starting at 1) or an error if the index
167-
/// is invalid.
168179
fn at(&self, vm: &VM, mut idx: usize) -> Result<Val, Box<VMError>> {
169180
let store = unsafe { &*self.store.get() };
170181
if idx > 0 && idx <= store.len() {
@@ -181,8 +192,6 @@ impl Array for MethodsArray {
181192
}
182193
}
183194

184-
/// Return the item at index `idx` (using SOM indexing starting at 1). This will lead to
185-
/// undefined behaviour if the index is invalid.
186195
unsafe fn unchecked_at(&self, mut idx: usize) -> Val {
187196
debug_assert!(idx > 0);
188197
let store = &*self.store.get();
@@ -191,8 +200,6 @@ impl Array for MethodsArray {
191200
*store.get_unchecked(idx)
192201
}
193202

194-
/// Set the item at index `idx` (using SOM indexing starting at 1) to `val` or return an error
195-
/// if the index is invalid.
196203
fn at_put(&self, vm: &mut VM, mut idx: usize, val: Val) -> Result<(), Box<VMError>> {
197204
let store = unsafe { &mut *self.store.get() };
198205
if idx > 0 && idx <= store.len() {
@@ -210,6 +217,14 @@ impl Array for MethodsArray {
210217
))
211218
}
212219
}
220+
221+
fn iter<'a>(&'a self) -> ArrayIterator<'a> {
222+
ArrayIterator {
223+
arr: self,
224+
len: self.length(),
225+
i: 0,
226+
}
227+
}
213228
}
214229

215230
impl MethodsArray {
@@ -221,23 +236,19 @@ impl MethodsArray {
221236
},
222237
)
223238
}
224-
225-
/// Iterate over this array's values.
226-
pub fn iter<'a>(&'a self) -> MethodsArrayIterator<'a> {
227-
MethodsArrayIterator { arr: self, i: 0 }
228-
}
229239
}
230240

231-
pub struct MethodsArrayIterator<'a> {
232-
arr: &'a MethodsArray,
241+
pub struct ArrayIterator<'a> {
242+
arr: &'a dyn Array,
243+
len: usize,
233244
i: usize,
234245
}
235246

236-
impl<'a> Iterator for MethodsArrayIterator<'a> {
247+
impl<'a> Iterator for ArrayIterator<'a> {
237248
type Item = Val;
238249

239250
fn next(&mut self) -> Option<Val> {
240-
if self.i < self.arr.length() {
251+
if self.i < self.len {
241252
self.i += 1;
242253
Some(unsafe { self.arr.unchecked_at(self.i) })
243254
} else {

src/lib/vm/objects/method.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::{
1414
#[derive(Debug)]
1515
pub struct Method {
1616
sig: Cell<Val>,
17+
num_params: usize,
1718
pub body: MethodBody,
1819
holder: Cell<Val>,
1920
}
@@ -57,9 +58,10 @@ impl StaticObjType for Method {
5758
}
5859

5960
impl Method {
60-
pub fn new(vm: &VM, sig: Val, body: MethodBody) -> Method {
61+
pub fn new(vm: &VM, sig: Val, num_params: usize, body: MethodBody) -> Method {
6162
Method {
6263
sig: Cell::new(sig),
64+
num_params,
6365
body,
6466
holder: Cell::new(vm.nil),
6567
}
@@ -69,6 +71,10 @@ impl Method {
6971
self.holder.get()
7072
}
7173

74+
pub fn num_params(&self) -> usize {
75+
self.num_params
76+
}
77+
7278
pub fn set_holder(&self, _: &VM, class: Val) {
7379
self.holder.set(class);
7480
}

0 commit comments

Comments
 (0)