Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4be2f24

Browse files
Merge pull requestRustPython#184 from RustPython/metaclasses
WIP - Specify metaclass and create class with correct type.
2 parents89cfdbe +aa10e9b commit4be2f24

File tree

10 files changed

+266
-71
lines changed

10 files changed

+266
-71
lines changed

‎src/main.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ fn shell_exec(vm: &mut VirtualMachine, source: &str, scope: PyObjectRef) -> bool
127127
}
128128
Err(err) =>{
129129
// Enum rather than special string here.
130-
let msg =match vm.get_attribute(err.clone(),"msg"){
130+
let name = vm.new_str("msg".to_string());
131+
let msg =match vm.get_attribute(err.clone(), name){
131132
Ok(value) => objstr::get_value(&value),
132133
Err(_) =>panic!("Expected msg attribute on exception object!"),
133134
};

‎tests/snippets/metaclasses.py‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
classMC(type):
2+
classes= []
3+
count=0
4+
5+
def__new__(cls,name,bases,namespace):
6+
MC.classes.append(name)
7+
returntype.__new__(cls,name,bases,namespace)
8+
9+
def__call__(cls):
10+
MC.count+=1
11+
returntype.__call__(cls,MC.count)
12+
13+
classC(object,metaclass=MC):
14+
def__new__(cls,count):
15+
self=object.__new__(cls)
16+
self.count=count
17+
returnself
18+
19+
classD(object,metaclass=MC):
20+
pass
21+
22+
assertMC==type(C)
23+
assertC==type(C())
24+
assertMC.classes== ['C','D']
25+
assertC().count==2

‎vm/src/builtins.rs‎

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ fn dir_object(vm: &mut VirtualMachine, obj: &PyObjectRef) -> PyObjectRef {
5050

5151
fnbuiltin_abs(vm:&mutVirtualMachine,args:PyFuncArgs) ->PyResult{
5252
arg_check!(vm, args, required =[(x,None)]);
53-
match vm.get_attribute(x.clone(),&"__abs__"){
53+
match vm.get_method(x.clone(),"__abs__"){
5454
Ok(attrib) => vm.invoke(attrib,PyFuncArgs::new(vec![],vec![])),
5555
Err(..) =>Err(vm.new_type_error("bad operand for abs".to_string())),
5656
}
@@ -134,7 +134,7 @@ fn builtin_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
134134

135135
fnbuiltin_divmod(vm:&mutVirtualMachine,args:PyFuncArgs) ->PyResult{
136136
arg_check!(vm, args, required =[(x,None),(y,None)]);
137-
match vm.get_attribute(x.clone(),&"__divmod__"){
137+
match vm.get_method(x.clone(),"__divmod__"){
138138
Ok(attrib) => vm.invoke(attrib,PyFuncArgs::new(vec![y.clone()],vec![])),
139139
Err(..) =>Err(vm.new_type_error("unsupported operand type(s) for divmod".to_string())),
140140
}
@@ -218,11 +218,7 @@ fn builtin_getattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
218218
args,
219219
required =[(obj,None),(attr,Some(vm.ctx.str_type()))]
220220
);
221-
ifletPyObjectKind::String{ref value} = attr.borrow().kind{
222-
vm.get_attribute(obj.clone(), value)
223-
}else{
224-
panic!("argument checking failure: attr not string")
225-
}
221+
vm.get_attribute(obj.clone(), attr.clone())
226222
}
227223

228224
// builtin_globals
@@ -233,15 +229,11 @@ fn builtin_hasattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
233229
args,
234230
required =[(obj,None),(attr,Some(vm.ctx.str_type()))]
235231
);
236-
ifletPyObjectKind::String{ref value} = attr.borrow().kind{
237-
let has_attr =match vm.get_attribute(obj.clone(), value){
238-
Ok(..) =>true,
239-
Err(..) =>false,
240-
};
241-
Ok(vm.context().new_bool(has_attr))
242-
}else{
243-
panic!("argument checking failure: attr not string")
244-
}
232+
let has_attr =match vm.get_attribute(obj.clone(), attr.clone()){
233+
Ok(..) =>true,
234+
Err(..) =>false,
235+
};
236+
Ok(vm.context().new_bool(has_attr))
245237
}
246238

247239
fnbuiltin_hash(vm:&mutVirtualMachine,args:PyFuncArgs) ->PyResult{
@@ -308,7 +300,7 @@ fn builtin_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
308300
}
309301
_ =>{
310302
let len_method_name ="__len__".to_string();
311-
match vm.get_attribute(obj.clone(),&len_method_name){
303+
match vm.get_method(obj.clone(),&len_method_name){
312304
Ok(value) => vm.invoke(value,PyFuncArgs::default()),
313305
Err(..) =>Err(vm.context().new_str(
314306
format!(
@@ -444,7 +436,7 @@ fn builtin_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
444436
optional =[(mod_value,Some(vm.ctx.int_type()))]
445437
);
446438
let pow_method_name ="__pow__".to_string();
447-
let result =match vm.get_attribute(x.clone(),&pow_method_name){
439+
let result =match vm.get_method(x.clone(),&pow_method_name){
448440
Ok(attrib) => vm.invoke(attrib,PyFuncArgs::new(vec![y.clone()],vec![])),
449441
Err(..) =>Err(vm.new_type_error("unsupported operand type(s) for pow".to_string())),
450442
};
@@ -454,7 +446,7 @@ fn builtin_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
454446
match mod_value{
455447
Some(mod_value) =>{
456448
let mod_method_name ="__mod__".to_string();
457-
match vm.get_attribute(
449+
match vm.get_method(
458450
result.expect("result not defined").clone(),
459451
&mod_method_name,
460452
){
@@ -644,14 +636,10 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
644636
pubfnbuiltin_build_class_(vm:&mutVirtualMachine,mutargs:PyFuncArgs) ->PyResult{
645637
let function = args.shift();
646638
let name_arg = args.shift();
647-
let name_arg_ref = name_arg.borrow();
648-
let name =match name_arg_ref.kind{
649-
PyObjectKind::String{ref value} => value,
650-
_ =>panic!("Class name must by a string!"),
651-
};
652639
letmut bases = args.args.clone();
640+
let metaclass = args.get_kwarg("metaclass", vm.get_type());
641+
653642
bases.push(vm.context().object());
654-
let metaclass = vm.get_type();
655643
let namespace = vm.new_dict();
656644
&vm.invoke(
657645
function,
@@ -660,5 +648,18 @@ pub fn builtin_build_class_(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> Py
660648
kwargs:vec![],
661649
},
662650
);
663-
objtype::new(metaclass, name, bases, namespace)
651+
652+
let bases = vm.context().new_tuple(bases);
653+
654+
// Special case: __new__ must be looked up on the metaclass, not the meta-metaclass as
655+
// per vm.call(metaclass, "__new__", ...)
656+
let new = metaclass.get_attr("__new__").unwrap();
657+
let wrapped = vm.call_get_descriptor(new, metaclass)?;
658+
vm.invoke(
659+
wrapped,
660+
PyFuncArgs{
661+
args:vec![name_arg, bases, namespace],
662+
kwargs:vec![],
663+
},
664+
)
664665
}

‎vm/src/compile.rs‎

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ impl Compiler {
436436
name,
437437
body,
438438
bases,
439-
keywords: _,
439+
keywords,
440440
decorator_list,
441441
} =>{
442442
self.prepare_decorators(decorator_list)?;
@@ -483,9 +483,34 @@ impl Compiler {
483483
for basein bases{
484484
self.compile_expression(base)?;
485485
}
486-
self.emit(Instruction::CallFunction{
487-
typ:CallType::Positional(2 + bases.len()),
488-
});
486+
487+
if keywords.len() >0{
488+
letmut kwarg_names =vec![];
489+
for keywordin keywords{
490+
ifletSome(name) =&keyword.name{
491+
kwarg_names.push(bytecode::Constant::String{
492+
value: name.to_string(),
493+
});
494+
}else{
495+
// This means **kwargs!
496+
panic!("name must be set");
497+
}
498+
self.compile_expression(&keyword.value)?;
499+
}
500+
501+
self.emit(Instruction::LoadConst{
502+
value: bytecode::Constant::Tuple{
503+
elements: kwarg_names,
504+
},
505+
});
506+
self.emit(Instruction::CallFunction{
507+
typ:CallType::Keyword(2 + keywords.len() + bases.len()),
508+
});
509+
}else{
510+
self.emit(Instruction::CallFunction{
511+
typ:CallType::Positional(2 + bases.len()),
512+
});
513+
}
489514

490515
self.apply_decorators(decorator_list);
491516

‎vm/src/frame.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,8 @@ impl Frame {
123123
&exception,
124124
&vm.ctx.exceptions.base_exception_type
125125
));
126-
let traceback = vm
127-
.get_attribute(exception.clone(),&"__traceback__".to_string())
128-
.unwrap();
126+
let traceback_name = vm.new_str("__traceback__".to_string());
127+
let traceback = vm.get_attribute(exception.clone(), traceback_name).unwrap();
129128
trace!("Adding to traceback: {:?} {:?}", traceback, lineno);
130129
let pos = vm.ctx.new_tuple(vec![
131130
vm.ctx.new_str(filename.clone()),
@@ -1007,6 +1006,7 @@ impl Frame {
10071006

10081007
fnload_attr(&mutself,vm:&mutVirtualMachine,attr_name:&str) ->FrameResult{
10091008
let parent =self.pop_value();
1009+
let attr_name = vm.new_str(attr_name.to_string());
10101010
let obj = vm.get_attribute(parent, attr_name)?;
10111011
self.push_value(obj);
10121012
Ok(None)

‎vm/src/obj/objbool.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObje
1515
PyObjectKind::String{ref value} => !value.is_empty(),
1616
PyObjectKind::None{ ..} =>false,
1717
_ =>{
18-
ifletOk(f) =objtype::get_attribute(vm,obj.clone(),&String::from("__bool__")){
18+
ifletOk(f) =vm.get_method(obj.clone(),"__bool__"){
1919
let bool_res = vm.invoke(f,PyFuncArgs::default())?;
2020
let v =match bool_res.borrow().kind{
2121
PyObjectKind::Integer{ref value} => !value.is_zero(),

‎vm/src/obj/objobject.rs‎

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::super::pyobject::{
55
usesuper::super::vm::VirtualMachine;
66
usesuper::objbool;
77
usesuper::objdict;
8+
usesuper::objstr;
89
usesuper::objtype;
910

1011
pubfnnew_instance(vm:&mutVirtualMachine,mutargs:PyFuncArgs) ->PyResult{
@@ -15,12 +16,6 @@ pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
1516
Ok(obj)
1617
}
1718

18-
pubfncall(vm:&mutVirtualMachine,mutargs:PyFuncArgs) ->PyResult{
19-
let instance = args.shift();
20-
let function = objtype::get_attribute(vm, instance,&String::from("__call__"))?;
21-
vm.invoke(function, args)
22-
}
23-
2419
pubfncreate_object(type_type:PyObjectRef,object_type:PyObjectRef,dict_type:PyObjectRef){
2520
(*object_type.borrow_mut()).kind =PyObjectKind::Class{
2621
name:String::from("object"),
@@ -101,6 +96,10 @@ pub fn init(context: &PyContext) {
10196
object.set_attr("__hash__", context.new_rustfunc(object_hash));
10297
object.set_attr("__str__", context.new_rustfunc(object_str));
10398
object.set_attr("__repr__", context.new_rustfunc(object_repr));
99+
object.set_attr(
100+
"__getattribute__",
101+
context.new_rustfunc(object_getattribute),
102+
);
104103
}
105104

106105
fnobject_init(vm:&mutVirtualMachine,_args:PyFuncArgs) ->PyResult{
@@ -114,3 +113,54 @@ fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
114113
_ =>Err(vm.new_type_error("TypeError: no dictionary.".to_string())),
115114
}
116115
}
116+
117+
fnobject_getattribute(vm:&mutVirtualMachine,args:PyFuncArgs) ->PyResult{
118+
arg_check!(
119+
vm,
120+
args,
121+
required =[
122+
(obj,Some(vm.ctx.object())),
123+
(name_str,Some(vm.ctx.str_type()))
124+
]
125+
);
126+
let name = objstr::get_value(&name_str);
127+
trace!("object.__getattribute__({:?}, {:?})", obj, name);
128+
let cls = obj.typ();
129+
130+
ifletSome(attr) = cls.get_attr(&name){
131+
let attr_class = attr.typ();
132+
if attr_class.has_attr("__set__"){
133+
ifletSome(descriptor) = attr_class.get_attr("__get__"){
134+
return vm.invoke(
135+
descriptor,
136+
PyFuncArgs{
137+
args:vec![attr, obj.clone(), cls],
138+
kwargs:vec![],
139+
},
140+
);
141+
}
142+
}
143+
}
144+
145+
ifletSome(obj_attr) = obj.get_attr(&name){
146+
Ok(obj_attr)
147+
}elseifletSome(attr) = cls.get_attr(&name){
148+
vm.call_get_descriptor(attr, obj.clone())
149+
}else{
150+
ifletSome(getter) = cls.get_attr("__getattr__"){
151+
vm.invoke(
152+
getter,
153+
PyFuncArgs{
154+
args:vec![cls, name_str.clone()],
155+
kwargs:vec![],
156+
},
157+
)
158+
}else{
159+
let attribute_error = vm.context().exceptions.attribute_error.clone();
160+
Err(vm.new_exception(
161+
attribute_error,
162+
format!("{:?} object has no attribute {}", cls, name),
163+
))
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp