Commit 4c9e23d2 authored by Marius Wachtler's avatar Marius Wachtler

Merge branch 'master' of https://github.com/dropbox/pyston into generators

Conflicts:
	src/codegen/compvars.h
	src/codegen/runtime_hooks.h
	src/runtime/objmodel.h
parents f019f57c acbc8021
......@@ -76,7 +76,7 @@ public:
bool visit_name(AST_Name* node) {
if (node->ctx_type == AST_TYPE::Load)
_doLoad(node->id);
else if (node->ctx_type == AST_TYPE::Store)
else if (node->ctx_type == AST_TYPE::Store || node->ctx_type == AST_TYPE::Del)
_doStore(node->id);
else {
assert(0);
......
......@@ -184,6 +184,7 @@ public:
break;
case AST_TYPE::Param:
case AST_TYPE::Store:
case AST_TYPE::Del:
doWrite(node->id);
break;
default:
......@@ -242,7 +243,9 @@ public:
virtual bool visit_delete(AST_Delete* node) {
for (auto t : node->targets) {
RELEASE_ASSERT(t->type != AST_TYPE::Name, "");
if (t->type == AST_TYPE::Name) {
doWrite(ast_cast<AST_Name>(t)->id);
}
}
return false;
}
......
......@@ -476,8 +476,19 @@ private:
virtual void visit_delete(AST_Delete* node) {
for (AST_expr* target : node->targets) {
RELEASE_ASSERT(target->type == AST_TYPE::Subscript, "");
getType(ast_cast<AST_Subscript>(target)->value);
switch (target->type) {
case AST_TYPE::Subscript:
getType(ast_cast<AST_Subscript>(target)->value);
break;
case AST_TYPE::Attribute:
getType(ast_cast<AST_Attribute>(target)->value);
break;
case AST_TYPE::Name:
sym_table.erase(ast_cast<AST_Name>(target)->id);
break;
default:
RELEASE_ASSERT(0, "%d", target->type);
}
}
}
......
......@@ -218,6 +218,27 @@ public:
converted->decvref(emitter);
}
void delattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, const std::string* attr) {
llvm::Constant* ptr = getStringConstantPtr(*attr + '\0');
// TODO
// bool do_patchpoint = ENABLE_ICDELATTRS && !info.isInterpreted();
bool do_patchpoint = false;
if (do_patchpoint) {
PatchpointSetupInfo* pp
= patchpoints::createDelattrPatchpoint(emitter.currentFunction(), info.getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(var->getValue());
llvm_args.push_back(ptr);
emitter.createPatchpoint(pp, (void*)pyston::delattr, llvm_args, info.exc_info);
} else {
emitter.createCall2(info.exc_info, g.funcs.delattr, var->getValue(), ptr);
}
}
virtual llvm::Value* makeClassCheck(IREmitter& emitter, ConcreteCompilerVariable* var, BoxedClass* cls) {
assert(var->getValue()->getType() == g.llvm_value_type_ptr);
// TODO this is brittle: directly embeds the position of the class object:
......@@ -765,6 +786,12 @@ public:
call.setDoesNotReturn();
}
virtual void delattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr) {
llvm::CallInst* call = emitter.getBuilder()->CreateCall2(
g.funcs.raiseAttributeErrorStr, getStringConstantPtr("int\0"), getStringConstantPtr(*attr + '\0'));
call->setDoesNotReturn();
}
virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, ConcreteCompilerVariable* var,
ConcreteCompilerType* other_type) {
if (other_type == this) {
......@@ -963,6 +990,12 @@ public:
call.setDoesNotReturn();
}
virtual void delattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr) {
llvm::CallInst* call = emitter.getBuilder()->CreateCall2(
g.funcs.raiseAttributeErrorStr, getStringConstantPtr("float\0"), getStringConstantPtr(*attr + '\0'));
call->setDoesNotReturn();
}
virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, ConcreteCompilerVariable* var,
ConcreteCompilerType* other_type) {
if (other_type == this) {
......@@ -1220,6 +1253,10 @@ public:
return UNKNOWN->setattr(emitter, info, var, attr, v);
}
void delattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, const std::string* attr) {
return UNKNOWN->delattr(emitter, info, var, attr);
}
virtual void print(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
converted->print(emitter, info);
......@@ -1891,6 +1928,6 @@ ConcreteCompilerVariable* undefVariable() {
}
ConcreteCompilerType* LIST, *SLICE, *MODULE, *DICT, *SET;
ConcreteCompilerType* LIST, *SLICE, *MODULE, *DICT, *SET, *FROZENSET;
} // namespace pyston
......@@ -30,7 +30,7 @@ class CompilerType;
class IREmitter;
extern ConcreteCompilerType* INT, *BOXED_INT, *FLOAT, *BOXED_FLOAT, *VOID, *UNKNOWN, *BOOL, *STR, *NONE, *LIST, *SLICE,
*MODULE, *DICT, *BOOL, *BOXED_BOOL, *BOXED_TUPLE, *SET, *CLOSURE, *GENERATOR;
*MODULE, *DICT, *BOOL, *BOXED_BOOL, *BOXED_TUPLE, *SET, *FROZENSET, *CLOSURE, *GENERATOR;
extern CompilerType* UNDEF;
class CompilerType {
......@@ -100,6 +100,12 @@ public:
printf("setattr not defined for %s\n", debugName().c_str());
abort();
}
virtual void delattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr) {
printf("delattr not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args,
......@@ -232,6 +238,7 @@ public:
virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool cls_only)
= 0;
virtual void setattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, CompilerVariable* v) = 0;
virtual void delattr(IREmitter& emitter, const OpInfo& info, const std::string* attr) = 0;
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool clsonly,
struct ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) = 0;
......@@ -296,6 +303,11 @@ public:
virtual void setattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, CompilerVariable* v) {
type->setattr(emitter, info, this, attr, v);
}
virtual void delattr(IREmitter& emitter, const OpInfo& info, const std::string* attr) {
type->delattr(emitter, info, this, attr);
}
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool clsonly,
struct ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
......
......@@ -670,8 +670,10 @@ private:
// TODO should mark as DEAD here, though we won't end up setting all the names appropriately
// state = DEAD;
llvm::CallSite call = emitter.createCall2(exc_info, g.funcs.assertNameDefined, getConstantInt(0, g.i1),
getStringConstantPtr(node->id + '\0'));
llvm::CallSite call = emitter.createCall(
exc_info, g.funcs.assertNameDefined,
{ getConstantInt(0, g.i1), getStringConstantPtr(node->id + '\0'),
embedConstantPtr(UnboundLocalError, g.llvm_class_type_ptr), getConstantInt(true, g.i1) });
call.setDoesNotReturn();
return undefVariable();
}
......@@ -692,16 +694,19 @@ private:
emitter.getBuilder()->CreateCondBr(is_defined_var->getValue(), from_local, from_global);
emitter.getBuilder()->SetInsertPoint(from_local);
curblock = from_local;
CompilerVariable* local = symbol_table[node->id];
ConcreteCompilerVariable* converted_local = local->makeConverted(emitter, local->getBoxType());
// don't decvref local here, because are manufacturing a new vref
emitter.getBuilder()->CreateBr(join);
emitter.getBuilder()->SetInsertPoint(from_global);
curblock = from_global;
ConcreteCompilerVariable* global = _getGlobal(node, exc_info);
emitter.getBuilder()->CreateBr(join);
emitter.getBuilder()->SetInsertPoint(join);
curblock = join;
llvm::PHINode* phi = emitter.getBuilder()->CreatePHI(g.llvm_value_type_ptr, 2, node->id);
phi->addIncoming(converted_local->getValue(), from_local);
phi->addIncoming(global->getValue(), from_global);
......@@ -709,8 +714,10 @@ private:
return new ConcreteCompilerVariable(UNKNOWN, phi, true);
}
emitter.createCall2(exc_info, g.funcs.assertNameDefined, is_defined_var->getValue(),
getStringConstantPtr(node->id + '\0'));
emitter.createCall(exc_info, g.funcs.assertNameDefined,
{ is_defined_var->getValue(), getStringConstantPtr(node->id + '\0'),
embedConstantPtr(UnboundLocalError, g.llvm_class_type_ptr),
getConstantInt(true, g.i1) });
// At this point we know the name must be defined (otherwise the assert would have fired):
_popFake(defined_name);
......@@ -1329,8 +1336,14 @@ private:
case AST_TYPE::Subscript:
_doDelitem(static_cast<AST_Subscript*>(target), exc_info);
break;
case AST_TYPE::Attribute:
_doDelAttr(static_cast<AST_Attribute*>(target), exc_info);
break;
case AST_TYPE::Name:
_doDelName(static_cast<AST_Name*>(target), exc_info);
break;
default:
ASSERT(0, "UnSupported del target: %d", target->type);
ASSERT(0, "Unsupported del target: %d", target->type);
abort();
}
}
......@@ -1366,6 +1379,51 @@ private:
converted_slice->decvref(emitter);
}
void _doDelAttr(AST_Attribute* node, ExcInfo exc_info) {
CompilerVariable* value = evalExpr(node->value, exc_info);
value->delattr(emitter, getEmptyOpInfo(exc_info), &node->attr);
}
void _doDelName(AST_Name* target, ExcInfo exc_info) {
auto scope_info = irstate->getScopeInfo();
if (scope_info->refersToGlobal(target->id)) {
// Can't use delattr since the errors are different:
emitter.createCall2(exc_info, g.funcs.delGlobal,
embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr),
embedConstantPtr(&target->id, g.llvm_str_type_ptr));
return;
}
assert(!scope_info->refersToClosure(target->id));
assert(!scope_info->saveInClosure(
target->id)); // SyntaxError: can not delete variable 'x' referenced in nested scope
// A del of a missing name generates different error messages in a function scope vs a classdef scope
bool local_error_msg = (irstate->getSourceInfo()->ast->type != AST_TYPE::ClassDef);
if (symbol_table.count(target->id) == 0) {
llvm::CallSite call = emitter.createCall(exc_info, g.funcs.assertNameDefined,
{ getConstantInt(0, g.i1), getStringConstantPtr(target->id + '\0'),
embedConstantPtr(NameError, g.llvm_class_type_ptr),
getConstantInt(local_error_msg, g.i1) });
call.setDoesNotReturn();
return;
}
std::string defined_name = _getFakeName("is_defined", target->id.c_str());
ConcreteCompilerVariable* is_defined_var = static_cast<ConcreteCompilerVariable*>(_getFake(defined_name, true));
if (is_defined_var) {
emitter.createCall(exc_info, g.funcs.assertNameDefined,
{ is_defined_var->getValue(), getStringConstantPtr(target->id + '\0'),
embedConstantPtr(NameError, g.llvm_class_type_ptr),
getConstantInt(local_error_msg, g.i1) });
_popFake(defined_name);
}
symbol_table.erase(target->id);
}
CLFunction* _wrapFunction(AST* node, AST_arguments* args, const std::vector<AST_stmt*>& body) {
// Different compilations of the parent scope of a functiondef should lead
// to the same CLFunction* being used:
......@@ -1770,20 +1828,19 @@ private:
void doRaise(AST_Raise* node, ExcInfo exc_info) {
std::vector<llvm::Value*> args;
llvm::Value* raise_func = g.funcs.raise0;
if (node->arg0) {
raise_func = g.funcs.raise1;
CompilerVariable* arg0 = evalExpr(node->arg0, exc_info);
ConcreteCompilerVariable* converted_arg0 = arg0->makeConverted(emitter, arg0->getBoxType());
arg0->decvref(emitter);
args.push_back(converted_arg0->getValue());
for (auto a : { node->arg0, node->arg1, node->arg2 }) {
if (a) {
CompilerVariable* v = evalExpr(a, exc_info);
ConcreteCompilerVariable* converted = v->makeConverted(emitter, v->getBoxType());
v->decvref(emitter);
args.push_back(converted->getValue());
} else {
args.push_back(embedConstantPtr(None, g.llvm_value_type_ptr));
}
}
RELEASE_ASSERT(node->arg1 == NULL, "");
RELEASE_ASSERT(node->arg2 == NULL, "");
emitter.createCall(exc_info, raise_func, args);
emitter.createCall(exc_info, g.funcs.raise3, args);
emitter.getBuilder()->CreateUnreachable();
endBlock(DEAD);
......
......@@ -113,6 +113,9 @@ def convert(n, f):
if isinstance(n, _ast.Num):
if isinstance(n.n, int):
f.write('\x10')
elif isinstance(n.n, long):
assert (-1L<<60) < n.n < (1L<<60)
f.write('\x10')
elif isinstance(n.n, float):
f.write('\x20')
else:
......@@ -140,10 +143,18 @@ def convert(n, f):
convert(el, f)
elif isinstance(v, str):
_print_str(v, f)
elif isinstance(v, unicode):
print >>sys.stderr, "Warning, converting unicode string to str!"
sys.stderr.flush()
_print_str(v.encode("ascii"), f)
elif isinstance(v, bool):
f.write(struct.pack("B", v))
elif isinstance(v, int):
f.write(struct.pack(">q", v))
elif isinstance(v, long):
assert (-1L<<60) < v < (1L<<60)
print >>sys.stderr, "Warning, converting long to int!"
f.write(struct.pack(">q", v))
elif isinstance(v, float):
f.write(struct.pack(">d", v))
elif v is None or isinstance(v, _ast.AST):
......
......@@ -139,6 +139,10 @@ PatchpointSetupInfo* createSetattrPatchpoint(CompiledFunction* parent_cf, TypeRe
return PatchpointSetupInfo::initialize(false, 2, 128, parent_cf, Setattr, type_recorder);
}
PatchpointSetupInfo* createDelattrPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder) {
return PatchpointSetupInfo::initialize(false, 1, 144, parent_cf, Delattr, type_recorder);
}
PatchpointSetupInfo* createCallsitePatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder, int num_args) {
// TODO These are very large, but could probably be made much smaller with IC optimizations
// - using rewriter2 for better code
......
......@@ -32,6 +32,7 @@ enum PatchpointType {
GetGlobal,
Getattr,
Setattr,
Delattr,
Getitem,
Setitem,
Delitem,
......@@ -91,6 +92,7 @@ PatchpointSetupInfo* createCallsitePatchpoint(CompiledFunction* parent_cf, TypeR
PatchpointSetupInfo* createGetGlobalPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createGetattrPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createSetattrPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createDelattrPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createGetitemPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createSetitemPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createDelitemPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
......
......@@ -174,10 +174,12 @@ void initGlobalFuncs(GlobalState& g) {
GET(getattr);
GET(setattr);
GET(delattr);
GET(getitem);
GET(setitem);
GET(delitem);
GET(getGlobal);
GET(delGlobal);
GET(binop);
GET(compare);
GET(augbinop);
......@@ -227,8 +229,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(__cxa_begin_catch);
g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_);
GET(raise0);
GET(raise1);
GET(raise3);
g.funcs.div_i64_i64 = getFunc((void*)div_i64_i64, "div_i64_i64");
g.funcs.mod_i64_i64 = getFunc((void*)mod_i64_i64, "mod_i64_i64");
......
......@@ -33,8 +33,9 @@ struct GlobalFuncs {
llvm::Value* boxInt, *unboxInt, *boxFloat, *unboxFloat, *boxStringPtr, *boxCLFunction, *unboxCLFunction,
*boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice,
*createUserClass, *createClosure, *createGenerator, *insideGenerator;
llvm::Value* getattr, *setattr, *print, *nonzero, *binop, *compare, *augbinop, *unboxedLen, *getitem, *getclsattr,
*getGlobal, *setitem, *delitem, *unaryop, *import, *importFrom, *importStar, *repr, *isinstance, *yield;
llvm::Value* getattr, *setattr, *delattr, *delitem, *delGlobal, *print, *nonzero, *binop, *compare, *augbinop,
*unboxedLen, *getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import, *importFrom, *importStar, *repr,
*isinstance, *yield;
llvm::Value* checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError,
*assertNameDefined, *assertFail;
......@@ -44,7 +45,7 @@ struct GlobalFuncs {
llvm::Value* reoptCompiledFunc, *compilePartialFunc;
llvm::Value* __cxa_begin_catch, *__cxa_end_catch;
llvm::Value* raise0, *raise1;
llvm::Value* raise3;
llvm::Value* div_i64_i64, *mod_i64_i64, *pow_i64_i64;
llvm::Value* div_float_float, *mod_float_float, *pow_float_float;
......
......@@ -1098,8 +1098,18 @@ public:
target = astsubs;
break;
}
case AST_TYPE::Attribute: {
AST_Attribute* astattr = static_cast<AST_Attribute*>(remapExpr(t, false));
astattr->ctx_type = AST_TYPE::Del;
target = astattr;
break;
}
case AST_TYPE::Name: {
target = t;
break;
}
default:
RELEASE_ASSERT(0, "UnSupported del target: %d", t->type);
RELEASE_ASSERT(0, "Unsupported del target: %d", t->type);
}
astdel->targets.push_back(target);
push_back(astdel);
......
......@@ -42,6 +42,7 @@ bool ENABLE_ICDELITEMS = 1 && ENABLE_ICS;
bool ENABLE_ICCALLSITES = 1 && ENABLE_ICS;
bool ENABLE_ICSETATTRS = 1 && ENABLE_ICS;
bool ENABLE_ICGETATTRS = 1 && ENABLE_ICS;
bool ENALBE_ICDELATTRS = 1 && ENABLE_ICS;
bool ENABLE_ICGETGLOBALS = 1 && ENABLE_ICS;
bool ENABLE_ICBINEXPS = 1 && ENABLE_ICS;
bool ENABLE_ICNONZEROS = 1 && ENABLE_ICS;
......
......@@ -29,7 +29,7 @@ extern int MAX_OPT_ITERATIONS;
extern bool SHOW_DISASM, FORCE_OPTIMIZE, BENCH, PROFILE, DUMPJIT, TRAP, USE_STRIPPED_STDLIB, ENABLE_INTERPRETER;
extern bool ENABLE_ICS, ENABLE_ICGENERICS, ENABLE_ICGETITEMS, ENABLE_ICSETITEMS, ENABLE_ICDELITEMS, ENABLE_ICBINEXPS,
ENABLE_ICNONZEROS, ENABLE_ICCALLSITES, ENABLE_ICSETATTRS, ENABLE_ICGETATTRS, ENABLE_ICGETGLOBALS,
ENABLE_ICNONZEROS, ENABLE_ICCALLSITES, ENABLE_ICSETATTRS, ENABLE_ICGETATTRS, ENALBE_ICDELATTRS, ENABLE_ICGETGLOBALS,
ENABLE_SPECULATION, ENABLE_OSR, ENABLE_LLVMOPTS, ENABLE_INLINING, ENABLE_REOPT, ENABLE_PYSTON_PASSES,
ENABLE_TYPE_FEEDBACK;
}
......
......@@ -344,6 +344,7 @@ public:
return -1;
return it->second;
}
HiddenClass* delAttrToMakeHC(const std::string& attr);
};
class Box;
......@@ -373,6 +374,7 @@ private:
class SetattrRewriteArgs2;
class GetattrRewriteArgs;
class GetattrRewriteArgs2;
class DelattrRewriteArgs2;
struct HCAttrs {
public:
......@@ -404,6 +406,7 @@ public:
Box* getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2);
Box* getattr(const std::string& attr) { return getattr(attr, NULL, NULL); }
void delattr(const std::string& attr, DelattrRewriteArgs2* rewrite_args);
};
......
......@@ -532,6 +532,7 @@ void setupBuiltins() {
builtins_module->giveAttr("bool", bool_cls);
builtins_module->giveAttr("dict", dict_cls);
builtins_module->giveAttr("set", set_cls);
builtins_module->giveAttr("frozenset", frozenset_cls);
builtins_module->giveAttr("tuple", tuple_cls);
builtins_module->giveAttr("instancemethod", instancemethod_cls);
}
......
......@@ -63,6 +63,7 @@ void force() {
FORCE(getattr);
FORCE(setattr);
FORCE(delattr);
FORCE(print);
FORCE(nonzero);
FORCE(binop);
......@@ -72,6 +73,7 @@ void force() {
FORCE(getitem);
FORCE(getclsattr);
FORCE(getGlobal);
FORCE(delGlobal);
FORCE(setitem);
FORCE(delitem);
FORCE(unaryop);
......@@ -96,7 +98,7 @@ void force() {
FORCE(callattr);
FORCE(raise0);
FORCE(raise1);
FORCE(raise3);
FORCE(div_i64_i64);
FORCE(mod_i64_i64);
......
......@@ -99,6 +99,17 @@ struct SetattrRewriteArgs2 {
out_success(false) {}
};
struct DelattrRewriteArgs2 {
Rewriter2* rewriter;
RewriterVarUsage2 obj;
bool more_guards_after;
bool out_success;
DelattrRewriteArgs2(Rewriter2* rewriter, RewriterVarUsage2&& obj, bool more_guards_after)
: rewriter(rewriter), obj(std::move(obj)), more_guards_after(more_guards_after), out_success(false) {}
};
struct LenRewriteArgs {
Rewriter* rewriter;
RewriterVar obj;
......@@ -240,9 +251,12 @@ extern "C" void assertFail(BoxedModule* inModule, Box* msg) {
}
}
extern "C" void assertNameDefined(bool b, const char* name) {
extern "C" void assertNameDefined(bool b, const char* name, BoxedClass* exc_cls, bool local_var_msg) {
if (!b) {
raiseExcHelper(UnboundLocalError, "local variable '%s' referenced before assignment", name);
if (local_var_msg)
raiseExcHelper(exc_cls, "local variable '%s' referenced before assignment", name);
else
raiseExcHelper(exc_cls, "name '%s' is not defined", name);
}
}
......@@ -332,6 +346,31 @@ HiddenClass* HiddenClass::getOrMakeChild(const std::string& attr) {
return rtn;
}
/**
* del attr from current HiddenClass, pertain the orders of remaining attrs
*/
HiddenClass* HiddenClass::delAttrToMakeHC(const std::string& attr) {
int idx = getOffset(attr);
assert(idx >= 0);
std::vector<std::string> new_attrs(attr_offsets.size() - 1);
for (auto it = attr_offsets.begin(); it != attr_offsets.end(); ++it) {
if (it->second < idx)
new_attrs[it->second] = it->first;
else if (it->second > idx) {
new_attrs[it->second - 1] = it->first;
}
}
// TODO we can first locate the parent HiddenClass of the deleted
// attribute and hence avoid creation of its ancestors.
HiddenClass* cur = getRoot();
for (const auto& attr : new_attrs) {
cur = cur->getOrMakeChild(attr);
}
return cur;
}
HiddenClass* HiddenClass::getRoot() {
static HiddenClass* root = new HiddenClass();
return root;
......@@ -2635,6 +2674,87 @@ extern "C" void delitem(Box* target, Box* slice) {
}
}
void Box::delattr(const std::string& attr, DelattrRewriteArgs2* rewrite_args) {
// as soon as the hcls changes, the guard on hidden class won't pass.
HCAttrs* attrs = getAttrsPtr();
HiddenClass* hcls = attrs->hcls;
HiddenClass* new_hcls = hcls->delAttrToMakeHC(attr);
// The order of attributes is pertained as delAttrToMakeHC constructs
// the new HiddenClass by invoking getOrMakeChild in the prevous order
// of remaining attributes
int num_attrs = hcls->attr_offsets.size();
int offset = hcls->getOffset(attr);
assert(offset >= 0);
Box** start = attrs->attr_list->attrs;
memmove(start + offset, start + offset + 1, (num_attrs - offset - 1) * sizeof(Box*));
attrs->hcls = new_hcls;
// guarantee the size of the attr_list equals the number of attrs
int new_size = sizeof(HCAttrs::AttrList) + sizeof(Box*) * (num_attrs - 1);
attrs->attr_list = (HCAttrs::AttrList*)rt_realloc(attrs->attr_list, new_size);
}
extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom,
DelattrRewriteArgs2* rewrite_args) {
static const std::string delattr_str("__delattr__");
static const std::string delete_str("__delete__");
// custom __delattr__
if (allow_custom) {
Box* delAttr = typeLookup(obj->cls, delattr_str, NULL, NULL);
if (delAttr != NULL) {
Box* boxstr = boxString(attr);
Box* rtn = runtimeCall2(delAttr, ArgPassSpec(2), obj, boxstr);
return;
}
}
// first check wether the deleting attribute is a descriptor
Box* clsAttr = typeLookup(obj->cls, attr, NULL, NULL);
if (clsAttr != NULL) {
Box* delAttr = getattr_internal(clsAttr, delete_str, false, true, NULL, NULL);
if (delAttr != NULL) {
Box* boxstr = boxString(attr);
Box* rtn = runtimeCall2(delAttr, ArgPassSpec(2), clsAttr, obj);
return;
}
}
// check if the attribute is in the instance's __dict__
Box* attrVal = getattr_internal(obj, attr, false, false, NULL, NULL);
if (attrVal != NULL) {
obj->delattr(attr, NULL);
} else {
// the exception cpthon throws is different when the class contains the attribute
if (clsAttr != NULL) {
raiseExcHelper(AttributeError, "'%s' object attribute '%s' is read-only", getTypeName(obj)->c_str(),
attr.c_str());
} else {
raiseAttributeError(obj, attr.c_str());
}
}
}
// del target.attr
extern "C" void delattr(Box* obj, const char* attr) {
static StatCounter slowpath_delattr("slowpath_delattr");
slowpath_delattr.log();
if (obj->cls == type_cls) {
BoxedClass* cobj = static_cast<BoxedClass*>(obj);
if (!isUserDefined(cobj)) {
raiseExcHelper(TypeError, "can't set attributes of built-in/extension type '%s'\n",
getNameOfClass(cobj)->c_str());
}
}
delattr_internal(obj, attr, true, NULL);
}
// For use on __init__ return values
static void assertInitNone(Box* obj) {
if (obj != None) {
......@@ -2780,7 +2900,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
// If this is true, not supposed to call __init__:
RELEASE_ASSERT(made->cls == ccls, "allowed but unsupported");
if (init_attr) {
if (init_attr && init_attr != typeLookup(object_cls, _init_str, NULL, NULL)) {
Box* initrtn;
if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_init);
......@@ -2852,6 +2972,13 @@ Box* typeNew(Box* cls, Box* obj) {
return rtn;
}
extern "C" void delGlobal(BoxedModule* m, std::string* name) {
if (!m->getattr(*name)) {
raiseExcHelper(NameError, "name '%s' is not defined", name->c_str());
}
m->delattr(*name, NULL);
}
extern "C" Box* getGlobal(BoxedModule* m, std::string* name) {
static StatCounter slowpath_getglobal("slowpath_getglobal");
slowpath_getglobal.log();
......
......@@ -31,8 +31,6 @@ class BoxedGenerator;
// user-level raise functions that implement python-level semantics
extern "C" void raise0() __attribute__((__noreturn__));
extern "C" void raise1(Box*) __attribute__((__noreturn__));
extern "C" void raise2(Box*, Box*) __attribute__((__noreturn__));
extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__));
void raiseExc(Box* exc_obj) __attribute__((__noreturn__));
......@@ -46,6 +44,7 @@ extern "C" const std::string* getNameOfClass(BoxedClass* cls);
extern "C" void my_assert(bool b);
extern "C" Box* getattr(Box* obj, const char* attr);
extern "C" void setattr(Box* obj, const char* attr, Box* attr_val);
extern "C" void delattr(Box* obj, const char* attr);
extern "C" bool nonzero(Box* obj);
extern "C" Box* runtimeCall(Box*, ArgPassSpec, Box*, Box*, Box*, Box**, const std::vector<const std::string*>*);
extern "C" Box* callattr(Box*, std::string*, bool, ArgPassSpec, Box*, Box*, Box*, Box**,
......@@ -67,6 +66,7 @@ extern "C" i64 unboxedLen(Box* obj);
extern "C" Box* binop(Box* lhs, Box* rhs, int op_type);
extern "C" Box* augbinop(Box* lhs, Box* rhs, int op_type);
extern "C" Box* getGlobal(BoxedModule* m, std::string* name);
extern "C" void delGlobal(BoxedModule* m, std::string* name);
extern "C" Box* getitem(Box* value, Box* slice);
extern "C" void setitem(Box* target, Box* slice, Box* value);
extern "C" void delitem(Box* target, Box* slice);
......@@ -76,7 +76,7 @@ extern "C" Box* import(const std::string* name);
extern "C" Box* importFrom(Box* obj, const std::string* attr);
extern "C" void importStar(Box* from_module, BoxedModule* to_module);
extern "C" void checkUnpackingLength(i64 expected, i64 given);
extern "C" void assertNameDefined(bool b, const char* name);
extern "C" void assertNameDefined(bool b, const char* name, BoxedClass* exc_cls, bool local_var_msg);
extern "C" void assertFail(BoxedModule* inModule, Box* msg);
extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent);
extern "C" BoxedClosure* createClosure(BoxedClosure* parent_closure);
......@@ -96,7 +96,8 @@ enum LookupScope {
extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope, CallRewriteArgs* rewrite_args,
ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<const std::string*>* keyword_names);
extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom,
DelattrRewriteArgs2* rewrite_args);
struct CompareRewriteArgs;
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args);
Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool allow_custom,
......
......@@ -23,6 +23,7 @@
namespace pyston {
BoxedClass* set_cls, *set_iterator_cls;
BoxedClass* frozenset_cls;
extern "C" void setGCHandler(GCVisitor* v, void* p);
extern "C" void setIteratorGCHandler(GCVisitor* v, void* p);
......@@ -82,20 +83,22 @@ Box* setiteratorNext(BoxedSetIterator* self) {
}
Box* setAdd2(Box* _self, Box* b) {
assert(_self->cls == set_cls);
assert(_self->cls == set_cls || _self->cls == frozenset_cls);
BoxedSet* self = static_cast<BoxedSet*>(_self);
self->s.insert(b);
return None;
}
Box* setNew(Box* cls, Box* container) {
assert(cls == set_cls);
Box* setNew(Box* _cls, Box* container) {
assert(_cls->cls == type_cls);
BoxedClass* cls = static_cast<BoxedClass*>(_cls);
assert(cls == set_cls || cls == frozenset_cls);
if (container == None)
return new BoxedSet();
return new BoxedSet(cls);
Box* rtn = new BoxedSet();
Box* rtn = new BoxedSet(cls);
for (Box* e : container->pyElements()) {
setAdd2(rtn, e);
}
......@@ -103,12 +106,10 @@ Box* setNew(Box* cls, Box* container) {
return rtn;
}
Box* setRepr(BoxedSet* self) {
assert(self->cls == set_cls);
static Box* _setRepr(BoxedSet* self, const char* type_name) {
std::ostringstream os("");
os << "set([";
os << type_name << "([";
bool first = true;
for (Box* elt : self->s) {
if (!first) {
......@@ -121,11 +122,21 @@ Box* setRepr(BoxedSet* self) {
return boxString(os.str());
}
Box* setRepr(BoxedSet* self) {
assert(self->cls == set_cls);
return _setRepr(self, "set");
}
Box* frozensetRepr(BoxedSet* self) {
assert(self->cls == frozenset_cls);
return _setRepr(self, "frozenset");
}
Box* setOrSet(BoxedSet* lhs, BoxedSet* rhs) {
assert(lhs->cls == set_cls);
assert(rhs->cls == set_cls);
assert(lhs->cls == set_cls || lhs->cls == frozenset_cls);
assert(rhs->cls == set_cls || rhs->cls == frozenset_cls);
BoxedSet* rtn = new BoxedSet();
BoxedSet* rtn = new BoxedSet(lhs->cls);
for (Box* elt : lhs->s) {
rtn->s.insert(elt);
......@@ -137,10 +148,10 @@ Box* setOrSet(BoxedSet* lhs, BoxedSet* rhs) {
}
Box* setAndSet(BoxedSet* lhs, BoxedSet* rhs) {
assert(lhs->cls == set_cls);
assert(rhs->cls == set_cls);
assert(lhs->cls == set_cls || lhs->cls == frozenset_cls);
assert(rhs->cls == set_cls || rhs->cls == frozenset_cls);
BoxedSet* rtn = new BoxedSet();
BoxedSet* rtn = new BoxedSet(lhs->cls);
for (Box* elt : lhs->s) {
if (rhs->s.count(elt))
......@@ -150,10 +161,10 @@ Box* setAndSet(BoxedSet* lhs, BoxedSet* rhs) {
}
Box* setSubSet(BoxedSet* lhs, BoxedSet* rhs) {
assert(lhs->cls == set_cls);
assert(rhs->cls == set_cls);
assert(lhs->cls == set_cls || lhs->cls == frozenset_cls);
assert(rhs->cls == set_cls || rhs->cls == frozenset_cls);
BoxedSet* rtn = new BoxedSet();
BoxedSet* rtn = new BoxedSet(lhs->cls);
for (Box* elt : lhs->s) {
// TODO if len(rhs) << len(lhs), it might be more efficient
......@@ -165,10 +176,10 @@ Box* setSubSet(BoxedSet* lhs, BoxedSet* rhs) {
}
Box* setXorSet(BoxedSet* lhs, BoxedSet* rhs) {
assert(lhs->cls == set_cls);
assert(rhs->cls == set_cls);
assert(lhs->cls == set_cls || lhs->cls == frozenset_cls);
assert(rhs->cls == set_cls || rhs->cls == frozenset_cls);
BoxedSet* rtn = new BoxedSet();
BoxedSet* rtn = new BoxedSet(lhs->cls);
for (Box* elt : lhs->s) {
if (rhs->s.count(elt) == 0)
......@@ -184,17 +195,17 @@ Box* setXorSet(BoxedSet* lhs, BoxedSet* rhs) {
}
Box* setIter(BoxedSet* self) {
assert(self->cls == set_cls);
assert(self->cls == set_cls || self->cls == frozenset_cls);
return new BoxedSetIterator(self);
}
Box* setLen(BoxedSet* self) {
assert(self->cls == set_cls);
assert(self->cls == set_cls || self->cls == frozenset_cls);
return boxInt(self->s.size());
}
Box* setAdd(BoxedSet* self, Box* v) {
assert(self->cls == set_cls);
assert(self->cls == set_cls || self->cls == frozenset_cls);
self->s.insert(v);
return None;
}
......@@ -206,6 +217,7 @@ using namespace pyston::set;
void setupSet() {
set_cls->giveAttr("__name__", boxStrConstant("set"));
frozenset_cls->giveAttr("__name__", boxStrConstant("frozenset"));
set_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedSet), false);
set_iterator_cls->giveAttr("__name__", boxStrConstant("setiterator"));
......@@ -217,40 +229,56 @@ void setupSet() {
set_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)setNew, UNKNOWN, 2, 1, false, false), { None }));
frozenset_cls->giveAttr("__new__", set_cls->getattr("__new__"));
Box* repr = new BoxedFunction(boxRTFunction((void*)setRepr, STR, 1));
set_cls->giveAttr("__repr__", repr);
set_cls->giveAttr("__str__", repr);
Box* set_repr = new BoxedFunction(boxRTFunction((void*)setRepr, STR, 1));
set_cls->giveAttr("__repr__", set_repr);
set_cls->giveAttr("__str__", set_repr);
std::vector<ConcreteCompilerType*> v_ss, v_su;
Box* frozenset_repr = new BoxedFunction(boxRTFunction((void*)frozensetRepr, STR, 1));
frozenset_cls->giveAttr("__repr__", frozenset_repr);
frozenset_cls->giveAttr("__str__", frozenset_repr);
std::vector<ConcreteCompilerType*> v_ss, v_sf, v_su, v_ff, v_fs, v_fu;
v_ss.push_back(SET);
v_ss.push_back(SET);
v_sf.push_back(SET);
v_sf.push_back(FROZENSET);
v_su.push_back(SET);
v_su.push_back(UNKNOWN);
CLFunction* or_ = createRTFunction(2, 0, false, false);
addRTFunction(or_, (void*)setOrSet, SET, v_ss);
set_cls->giveAttr("__or__", new BoxedFunction(or_));
CLFunction* sub_ = createRTFunction(2, 0, false, false);
addRTFunction(sub_, (void*)setSubSet, SET, v_ss);
set_cls->giveAttr("__sub__", new BoxedFunction(sub_));
CLFunction* xor_ = createRTFunction(2, 0, false, false);
addRTFunction(xor_, (void*)setXorSet, SET, v_ss);
set_cls->giveAttr("__xor__", new BoxedFunction(xor_));
CLFunction* and_ = createRTFunction(2, 0, false, false);
addRTFunction(and_, (void*)setAndSet, SET, v_ss);
set_cls->giveAttr("__and__", new BoxedFunction(and_));
v_ff.push_back(FROZENSET);
v_ff.push_back(FROZENSET);
v_fs.push_back(FROZENSET);
v_fs.push_back(SET);
v_fu.push_back(FROZENSET);
v_fu.push_back(UNKNOWN);
auto add = [&](const std::string& name, void* func) {
CLFunction* func_obj = createRTFunction(2, 0, false, false);
addRTFunction(func_obj, (void*)func, SET, v_ss);
addRTFunction(func_obj, (void*)func, SET, v_sf);
addRTFunction(func_obj, (void*)func, FROZENSET, v_fs);
addRTFunction(func_obj, (void*)func, FROZENSET, v_ff);
set_cls->giveAttr(name, new BoxedFunction(func_obj));
frozenset_cls->giveAttr(name, set_cls->getattr(name));
};
add("__or__", (void*)setOrSet);
add("__sub__", (void*)setSubSet);
add("__xor__", (void*)setXorSet);
add("__and__", (void*)setAndSet);
set_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)setIter, typeFromClass(set_iterator_cls), 1)));
frozenset_cls->giveAttr("__iter__", set_cls->getattr("__iter__"));
set_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)setLen, BOXED_INT, 1)));
frozenset_cls->giveAttr("__len__", set_cls->getattr("__len__"));
set_cls->giveAttr("add", new BoxedFunction(boxRTFunction((void*)setAdd, NONE, 2)));
set_cls->freeze();
frozenset_cls->freeze();
}
void teardownSet() {
......
......@@ -25,14 +25,14 @@ namespace pyston {
void setupSet();
void teardownSet();
extern BoxedClass* set_cls;
extern const ObjectFlavor set_flavor;
extern BoxedClass* set_cls, *frozenset_cls;
extern const ObjectFlavor set_flavor, frozenset_flavor;
class BoxedSet : public Box {
public:
std::unordered_set<Box*, PyHasher, PyEq, StlCompatAllocator<Box*> > s;
BoxedSet() __attribute__((visibility("default"))) : Box(&set_flavor, set_cls) {}
BoxedSet(BoxedClass* cls) __attribute__((visibility("default"))) : Box(&set_flavor, cls) {}
};
}
......
......@@ -198,21 +198,30 @@ void raise0() {
raiseRaw(last_exc);
}
void raise1(Box* b) {
if (b->cls == type_cls) {
BoxedClass* c = static_cast<BoxedClass*>(b);
void raise3(Box* arg0, Box* arg1, Box* arg2) {
RELEASE_ASSERT(arg2 == None, "unsupported");
if (arg0->cls == type_cls) {
BoxedClass* c = static_cast<BoxedClass*>(arg0);
if (isSubclass(c, Exception)) {
auto exc_obj = exceptionNew1(c);
Box* exc_obj;
if (arg1 != None)
exc_obj = exceptionNew2(c, arg1);
else
exc_obj = exceptionNew1(c);
raiseExc(exc_obj);
} else {
raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not %s",
getTypeName(b)->c_str());
getTypeName(arg0)->c_str());
}
}
if (arg1 != None)
raiseExcHelper(TypeError, "instance exception may not have a separate value");
// TODO: should only allow throwing of old-style classes or things derived
// from BaseException:
raiseExc(b);
raiseExc(arg0);
}
void raiseExcHelper(BoxedClass* cls, const char* msg, ...) {
......
......@@ -518,7 +518,8 @@ Box* objectNew(BoxedClass* cls, BoxedTuple* args) {
assert(args->cls == tuple_cls);
if (args->elts.size() != 0) {
if (typeLookup(cls, "__init__", NULL, NULL) == NULL)
// TODO slow
if (typeLookup(cls, "__init__", NULL, NULL) == typeLookup(object_cls, "__init__", NULL, NULL))
raiseExcHelper(TypeError, "object.__new__() takes no parameters");
}
......@@ -530,6 +531,10 @@ Box* objectNew(BoxedClass* cls, BoxedTuple* args) {
return rtn;
}
Box* objectInit(Box* b, BoxedTuple* args) {
return None;
}
bool TRACK_ALLOCATIONS = false;
void setupRuntime() {
gc::registerStaticRootObj(HiddenClass::getRoot());
......@@ -572,6 +577,7 @@ void setupRuntime() {
dict_cls = new BoxedClass(object_cls, 0, sizeof(BoxedDict), false);
file_cls = new BoxedClass(object_cls, 0, sizeof(BoxedFile), false);
set_cls = new BoxedClass(object_cls, 0, sizeof(BoxedSet), false);
frozenset_cls = new BoxedClass(object_cls, 0, sizeof(BoxedSet), false);
member_cls = new BoxedClass(object_cls, 0, sizeof(BoxedMemberDescriptor), false);
closure_cls = new BoxedClass(object_cls, offsetof(BoxedClosure, attrs), sizeof(BoxedClosure), false);
......@@ -585,10 +591,12 @@ void setupRuntime() {
MODULE = typeFromClass(module_cls);
DICT = typeFromClass(dict_cls);
SET = typeFromClass(set_cls);
FROZENSET = typeFromClass(frozenset_cls);
BOXED_TUPLE = typeFromClass(tuple_cls);
object_cls->giveAttr("__name__", boxStrConstant("object"));
object_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)objectNew, UNKNOWN, 1, 0, true, false)));
object_cls->giveAttr("__init__", new BoxedFunction(boxRTFunction((void*)objectInit, UNKNOWN, 1, 0, true, false)));
object_cls->freeze();
auto typeCallObj = boxRTFunction((void*)typeCall, UNKNOWN, 1, 0, true, false);
......
import sys
def p():
print hasattr(sys.modules['__main__'], 'a')
p()
a = 1
p()
del a
p()
try:
del a
except NameError, e:
print e
a = 1
def mk_cls(b1, b2):
class C(object):
if b1:
a = 2
if b2:
# with b1==False and b2==True, this reference to 'a' will go to the global scope.
# The 'del a' will still refer to the local scope and raise a NameError.
print a
del a
print hasattr(C, 'a')
mk_cls(False, False)
mk_cls(True, False)
mk_cls(True, True)
try:
mk_cls(False, True)
assert 0
except NameError, e:
print e
def f1(b1, b2):
if b1:
a = 2
if b2:
del a
f1(False, False)
f1(True, False)
f1(True, True)
try:
f1(False, True)
assert 0
except NameError, e:
print e
def f2():
del a
try:
f2()
assert 0
except NameError, e:
print e
# expected: fail
# - deletes on names
x = 1
def f():
if 0:
......
#delete attribute of built-in types
def del_builtin_attr(o):
try:
del a.__init__
print "error"
except AttributeError, e:
#print repr(e)
print e
try:
del a.aaaa
print "error"
except AttributeError, e:
#print repr(e)
print e
a=1
del_builtin_attr(a)
a=1.0
del_builtin_attr(a)
a=[1]
del_builtin_attr(a)
b={}
del_builtin_attr(a)
"""
test del procedure
> invoke __delattr__ if exists
> del instance __dict__
> if attr is not in __dict__ of instance, check if attr exists in the its class.
>if found, invoke __delete__ attribute if exists or throw AttributeError.
>if not, throw AttributeError
"""
class CustDelClass(object):
def __init__(self, val):
self.val = val
def __delattr__(self, attr):
print "del attribute %s"%(attr)
a = CustDelClass(1)
del a.val
print a.val
class AttrClass(object):
#
#classAttr = 1
def __init__(self, val):
self.val = val
def speak(self):
#print "val:%s, classAttr:%d"%(self.val, self.classAttr)
print "val%s"%(self.val)
#check the val of b should not be affected
a = AttrClass(1)
b = AttrClass(2)
a.speak()
del a.val
try:
a.speak()
print "del a.val error"
except AttributeError, e:
print e
try:
b.speak()
print "success"
except AttributeError, e:
print "error"
#could assign a new value
a.val = 1
try:
a.speak()
print "success"
except AttributeError, e:
print "error"
"""
try:
del a.classAttr
print "error"
except AttributeError, e:
print repr(e)
"""
try:
del a.speak
print "del func error"
except AttributeError, e:
print "del func"
del AttrClass.speak
try:
a.speak()
print "error"
except AttributeError, e:
print e
#test custom del attr
class CustDelClass(object):
def __init__(self, val):
self.val = val
def __delattr__(self, attr):
print "__delattr__ %s"%(attr)
def speak(self):
print "val:%s"%(self.val)
a=CustDelClass(1)
del a.attr
#custom set and get attr
class CustSetClass(object):
def __setattr__(self, attr, val):
print "__setattr__ %s %s"%(attr, val)
#def __getattr__(self, attr):
def __getattribute__(self, attr):
print "__getattribute__:%s"%(attr)
return attr
a=CustSetClass()
a.attr
a.val
#del won't invoke __getattr__ or __getattribute__ to check wether attr is an attribute of a
try:
del a.attr
except AttributeError, e:
print e
"""
#descriptor
class RevealAccess(object):
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print 'Retrieving', self.name
return self.val
def __delete__(self, obj):
print 'delete', self.name
class MyClass(object):
x = RevealAccess(10, 'var "x"')
a=MyClass()
del a.x
"""
def f(o):
print o.a
class C(object):
pass
c = C()
c.a = 1
f(c)
del c.a
try:
f(c)
print "f(c) error"
except AttributeError, e:
print e
......@@ -320,3 +320,19 @@ def f10():
with expected_exception(ZeroDivisionError):
raise
f10()
def f11():
print "f11"
# old style exception syntax"
try:
raise Exception, 12345
except Exception, e:
print e
try:
raise KeyError(), 12345
except TypeError, e:
print e
f11()
......@@ -51,3 +51,19 @@ def f():
except:
print True
f()
def f11():
print "f11"
# old style exception syntax"
try:
raise KeyError, 12345
except KeyError, e:
print e
try:
raise KeyError(), 12345
except TypeError, e:
print e
f11()
......@@ -31,3 +31,20 @@ print set([1])
for i in set([1]):
print i
s = frozenset(range(5))
print len(s)
print sorted(s)
print frozenset()
print hasattr(s, "remove")
print hasattr(s, "add")
print frozenset() | frozenset()
print set() | frozenset()
print frozenset() | set()
print set() | set()
......@@ -91,10 +91,11 @@ def canonicalize_stderr(stderr):
substitutions = [
("NameError: global name '", "NameError: name '"),
("AttributeError: '(\w+)' object attribute '(\w+)' is read-only", "AttributeError: \\2"),
]
for pattern, subst_with in substitutions:
stderr = stderr.replace(pattern, subst_with)
stderr = re.sub(pattern, subst_with, stderr)
return stderr
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment