@@ -132,6 +132,8 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
132132 ]
133133 ) ;
134134 let source = objstr:: get_value ( source) ;
135+ // TODO: fix this newline bug:
136+ let source = format ! ( "{}\n " , source) ;
135137
136138 let mode = {
137139 let mode = objstr:: get_value ( mode) ;
@@ -206,19 +208,36 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
206208 arg_check ! (
207209 vm,
208210 args,
209- required = [
210- ( source , None ) , // TODO: Use more specific type
211+ required = [ ( source , None ) ] ,
212+ optional = [
211213 ( _globals, Some ( vm. ctx. dict_type( ) ) ) ,
212214 ( locals, Some ( vm. ctx. dict_type( ) ) )
213215 ]
214216 ) ;
215- // TODO: handle optional global and locals
216217
217- let code_obj = source; // if source.borrow().kind
218+ // Determine code object:
219+ let code_obj = if objtype:: isinstance ( source, & vm. ctx . code_type ( ) ) {
220+ source. clone ( )
221+ } else if objtype:: isinstance ( source, & vm. ctx . str_type ( ) ) {
222+ let mode = compile:: Mode :: Eval ;
223+ let source = objstr:: get_value ( source) ;
224+ // TODO: fix this newline bug:
225+ let source = format ! ( "{}\n " , source) ;
226+ compile:: compile ( vm, & source, mode, None ) ?
227+ } else {
228+ return Err ( vm. new_type_error ( "code argument must be str or code object" . to_string ( ) ) ) ;
229+ } ;
230+
231+ let locals = if let Some ( locals) = locals {
232+ locals. clone ( )
233+ } else {
234+ vm. new_dict ( )
235+ } ;
218236
237+ // TODO: handle optional globals
219238 // Construct new scope:
220239 let scope_inner = Scope {
221- locals : locals. clone ( ) ,
240+ locals : locals,
222241 parent : None ,
223242 } ;
224243 let scope = PyObject {
@@ -235,26 +254,38 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
235254 arg_check ! (
236255 vm,
237256 args,
238- required = [
239- ( source , None ) ,
257+ required = [ ( source , None ) ] ,
258+ optional = [
240259 ( _globals, Some ( vm. ctx. dict_type( ) ) ) ,
241260 ( locals, Some ( vm. ctx. dict_type( ) ) )
242261 ]
243262 ) ;
244- // TODO: handle optional global and locals
245263
246264 // Determine code object:
247265 let code_obj = if objtype:: isinstance ( source, & vm. ctx . str_type ( ) ) {
248266 let mode = compile:: Mode :: Exec ;
249267 let source = objstr:: get_value ( source) ;
268+ // TODO: fix this newline bug:
269+ let source = format ! ( "{}\n " , source) ;
250270 compile:: compile ( vm, & source, mode, None ) ?
251- } else {
271+ } else if objtype :: isinstance ( source , & vm . ctx . code_type ( ) ) {
252272 source. clone ( )
273+ } else {
274+ return Err ( vm. new_type_error ( "source argument must be str or code object" . to_string ( ) ) ) ;
253275 } ;
254276
277+ // handle optional global and locals
278+ let locals = if let Some ( locals) = locals {
279+ locals. clone ( )
280+ } else {
281+ vm. new_dict ( )
282+ } ;
283+
284+ // TODO: use globals
285+
255286 // Construct new scope:
256287 let scope_inner = Scope {
257- locals : locals. clone ( ) ,
288+ locals : locals,
258289 parent : None ,
259290 } ;
260291 let scope = PyObject {
@@ -416,15 +447,56 @@ fn builtin_map(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
416447}
417448
418449fn builtin_max ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
419- arg_check ! ( vm, args, required = [ ( x, None ) , ( y, None ) ] ) ;
450+ // arg_check!(vm, args, required = [(x, None), (y, None)]);
420451
421- let order = vm. call_method ( x, "__gt__" , vec ! [ y. clone( ) ] ) ?;
452+ let candidates = if args. args . len ( ) > 1 {
453+ args. args . clone ( )
454+ } else if args. args . len ( ) == 1 {
455+ vm. extract_elements ( & args. args [ 0 ] ) ?
456+ } else {
457+ // zero arguments means type error:
458+ return Err ( vm. new_type_error ( "Expected 1 or more arguments" . to_string ( ) ) ) ;
459+ } ;
422460
423- if objbool:: get_value ( & order) {
424- Ok ( x. clone ( ) )
461+ if candidates. len ( ) == 0 {
462+ let default = args. get_optional_kwarg ( "default" ) ;
463+ if default. is_none ( ) {
464+ return Err ( vm. new_value_error ( "max() arg is an empty sequence" . to_string ( ) ) ) ;
465+ } else {
466+ return Ok ( default. unwrap ( ) ) ;
467+ }
468+ }
469+
470+ let key_func = args. get_optional_kwarg ( "key" ) ;
471+
472+ // Start with first assumption:
473+ let mut candidates_iter = candidates. into_iter ( ) ;
474+ let mut x = candidates_iter. next ( ) . unwrap ( ) ;
475+ // TODO: this key function looks pretty duplicate. Maybe we can create
476+ // a local function?
477+ let mut x_key = if let Some ( f) = & key_func {
478+ let args = PyFuncArgs :: new ( vec ! [ x. clone( ) ] , vec ! [ ] ) ;
479+ vm. invoke ( f. clone ( ) , args) ?
425480 } else {
426- Ok ( y. clone ( ) )
481+ x. clone ( )
482+ } ;
483+
484+ for y in candidates_iter {
485+ let y_key = if let Some ( f) = & key_func {
486+ let args = PyFuncArgs :: new ( vec ! [ y. clone( ) ] , vec ! [ ] ) ;
487+ vm. invoke ( f. clone ( ) , args) ?
488+ } else {
489+ y. clone ( )
490+ } ;
491+ let order = vm. call_method ( & x_key, "__gt__" , vec ! [ y_key. clone( ) ] ) ?;
492+
493+ if !objbool:: get_value ( & order) {
494+ x = y. clone ( ) ;
495+ x_key = y_key;
496+ }
427497 }
498+
499+ Ok ( x)
428500}
429501
430502// builtin_memoryview
0 commit comments