const call_order_object* borrow(account_id_type who, asset what, asset collateral) { return borrow(who(db), what, collateral); }
/// Master config parser. This handles 'import' and 'version-ge' etc. /// Then it defers to the inferior parser for a line it does not understand. /// /// Note: old-style 'version-ge: 1.2.3' etc apply to the rest of the file, but /// new-style 'version: >= 1.2.3' apply only up to the next 'version:' bool load_config_file(ZString filename, ConfigItemParser slave) { io::LineReader in(filename); if (!in.is_open()) { PRINTF("Unable to open file: %s\n"_fmt, filename); return false; } io::Line line_; bool rv = true; bool good_version = true; while (in.read_line(line_)) { if (is_comment(line_.text)) continue; auto line = io::respan(line_.to_span(), ZString(line_.text)); io::Spanned<XString> key; io::Spanned<ZString> value; if (!config_split(line, &key, &value)) { line.span.error("Bad config line"_s); rv = false; continue; } if (key.data == "version"_s) { if (value.data == "all"_s) { good_version = true; } else { good_version = true; while (good_version && value.data) { ZString::iterator it = std::find(value.data.begin(), value.data.end(), ' '); io::Spanned<XString> value_head; value_head.data = value.data.xislice_h(it); value_head.span = value.span; value.data = value.data.xislice_t(it).lstrip(); value_head.span.end.column = value_head.span.begin.column + value_head.data.size() - 1; value.span.begin.column = value.span.end.column - value.data.size() + 1; good_version &= check_version(value_head, borrow(rv)); } } continue; } if (!good_version) { continue; } if (key.data == "import"_s) { if (!load_config_file(value.data, slave)) { value.span.error("Failed to include file"_s); rv = false; } continue; } else if (key.data == "version-lt"_s) { Version vers; if (!extract(value.data, &vers)) { value.span.error("Bad value"_s); rv = false; continue; } if (CURRENT_VERSION < vers) continue; break; } else if (key.data == "version-le"_s) { Version vers; if (!extract(value.data, &vers)) { rv = false; value.span.error("Bad value"_s); continue; } if (CURRENT_VERSION <= vers) continue; break; } else if (key.data == "version-gt"_s) { Version vers; if (!extract(value.data, &vers)) { rv = false; value.span.error("Bad value"_s); continue; } if (CURRENT_VERSION > vers) continue; break; } else if (key.data == "version-ge"_s) { Version vers; if (!extract(value.data, &vers)) { rv = false; value.span.error("Bad value"_s); continue; } if (CURRENT_VERSION >= vers) continue; break; } else { rv &= slave(key, value); } // nothing to see here, move along } return rv; }
/* * Traverse the actual block layout, and find out the intervals for * each exception region in the tree. * * The basic idea here is that we haven't constrained block layout * based on the exception tree, but adjacent blocks are still * reasonably likely to have the same ExnNode. Try to coalesce the EH * regions we create for in those cases. */ void emit_ehent_tree(FuncEmitter& fe, const php::Func& func, const EmitBcInfo& info) { std::map< borrowed_ptr<const php::ExnNode>, std::vector<std::unique_ptr<EHRegion>> > exnMap; /* * While walking over the blocks in layout order, we track the set * of "active" exnNodes. This are a list of exnNodes that inherit * from each other. When a new active node is pushed, begin an * EHEnt, and when it's popped, it's done. */ std::vector<borrowed_ptr<const php::ExnNode>> activeList; auto pop_active = [&] (Offset past) { auto p = activeList.back(); activeList.pop_back(); exnMap[p].back()->past = past; }; auto push_active = [&] (const php::ExnNode* p, Offset start) { auto const parent = activeList.empty() ? nullptr : borrow(exnMap[activeList.back()].back()); exnMap[p].push_back( folly::make_unique<EHRegion>( EHRegion { p, parent, start, kInvalidOffset } ) ); activeList.push_back(p); }; /* * Walk over the blocks, and compare the new block's exnNode path to * the active one. Find the least common ancestor of the two paths, * then modify the active list by popping and then pushing nodes to * set it to the new block's path. */ for (auto& b : info.blockOrder) { auto const offset = info.blockInfo[b->id].offset; if (!b->exnNode) { while (!activeList.empty()) pop_active(offset); continue; } std::vector<borrowed_ptr<const php::ExnNode>> current; exn_path(current, b->exnNode); auto const prefix = shared_prefix(current, activeList); for (size_t i = prefix, sz = activeList.size(); i < sz; ++i) { pop_active(offset); } for (size_t i = prefix, sz = current.size(); i < sz; ++i) { push_active(current[i], offset); } if (debug && !activeList.empty()) { current.clear(); exn_path(current, activeList.back()); assert(current == activeList); } } while (!activeList.empty()) { pop_active(info.blockInfo[info.blockOrder.back()->id].past); } /* * We've created all our regions, but we need to sort them instead * of trying to get the UnitEmitter to do it. * * The UnitEmitter expects EH regions that look a certain way * (basically the way emitter.cpp likes them). There are some rules * about the order it needs to have at runtime, which we set up * here. * * Essentially, an entry a is less than an entry b iff: * * - a starts before b * - a starts at the same place, but encloses b entirely * - a has the same extents as b, but is a parent of b */ std::vector<borrowed_ptr<EHRegion>> regions; for (auto& mapEnt : exnMap) { for (auto& region : mapEnt.second) { regions.push_back(borrow(region)); } } std::sort( begin(regions), end(regions), [&] (borrowed_ptr<const EHRegion> a, borrowed_ptr<const EHRegion> b) { if (a == b) return false; if (a->start == b->start) { if (a->past == b->past) { // When regions exactly overlap, the parent is less than the // child. for (auto p = b->parent; p != nullptr; p = p->parent) { if (p == a) return true; } // If a is not a parent of b, and they have the same region; // then b better be a parent of a. if (debug) { auto p = a->parent; for (; p != b && p != nullptr; p = p->parent) continue; assert(p == b); } return false; } return a->past > b->past; } return a->start < b->start; } ); std::map<borrowed_ptr<const EHRegion>,uint32_t> parentIndexMap; for (auto& r : regions) { emit_eh_region(fe, r, info.blockInfo, parentIndexMap); } fe.setEHTabIsSorted(); }
TEST(Type, IndexBased) { auto const program = folly::make_unique<php::Program>(); program->units.push_back(make_test_unit()); auto const unit = borrow(program->units.back()); auto const func = [&]() -> borrowed_ptr<php::Func> { for (auto& f : unit->funcs) { if (f->name->isame(s_test.get())) return borrow(f); } return nullptr; }(); EXPECT_TRUE(func != nullptr); auto const ctx = Context { unit, func }; Index idx{borrow(program)}; auto const cls = idx.resolve_class(ctx, s_TestClass.get()); if (!cls) EXPECT_TRUE(false); auto const objExactTy = objExact(*cls); auto const subObjTy = subObj(*cls); auto const clsExactTy = clsExact(*cls); auto const subClsTy = subCls(*cls); // Basic relationship between the class types and object types. EXPECT_EQ(objcls(objExactTy), clsExactTy); EXPECT_EQ(objcls(subObjTy), subClsTy); // =TestClass <: <=TestClass, and not vice versa. EXPECT_TRUE(objExactTy.subtypeOf(subObjTy)); EXPECT_TRUE(!subObjTy.subtypeOf(objExactTy)); // =TestClass <: <=TestClass, and not vice versa. EXPECT_TRUE(clsExactTy.subtypeOf(subClsTy)); EXPECT_TRUE(!subClsTy.subtypeOf(clsExactTy)); // =TestClass couldBe <= TestClass, and vice versa. EXPECT_TRUE(objExactTy.couldBe(subObjTy)); EXPECT_TRUE(subObjTy.couldBe(objExactTy)); EXPECT_TRUE(clsExactTy.couldBe(subClsTy)); EXPECT_TRUE(subClsTy.couldBe(clsExactTy)); // Foo= and Foo<= are both subtypes of Foo, and couldBe Foo. EXPECT_TRUE(objExactTy.subtypeOf(TObj)); EXPECT_TRUE(subObjTy.subtypeOf(TObj)); EXPECT_TRUE(objExactTy.couldBe(TObj)); EXPECT_TRUE(subObjTy.couldBe(TObj)); EXPECT_TRUE(TObj.couldBe(objExactTy)); EXPECT_TRUE(TObj.couldBe(subObjTy)); EXPECT_TRUE(clsExactTy.subtypeOf(TCls)); EXPECT_TRUE(subClsTy.subtypeOf(TCls)); EXPECT_TRUE(clsExactTy.couldBe(TCls)); EXPECT_TRUE(subClsTy.couldBe(TCls)); EXPECT_TRUE(TCls.couldBe(clsExactTy)); EXPECT_TRUE(TCls.couldBe(subClsTy)); // Obj= and Obj<= both couldBe ?Obj, and vice versa. EXPECT_TRUE(objExactTy.couldBe(TOptObj)); EXPECT_TRUE(subObjTy.couldBe(TOptObj)); EXPECT_TRUE(TOptObj.couldBe(objExactTy)); EXPECT_TRUE(TOptObj.couldBe(subObjTy)); // Obj= and Obj<= are subtypes of ?Obj. EXPECT_TRUE(objExactTy.subtypeOf(TOptObj)); EXPECT_TRUE(subObjTy.subtypeOf(TOptObj)); // Obj= is a subtype of ?Obj=, and also ?Obj<=. EXPECT_TRUE(objExactTy.subtypeOf(opt(objExactTy))); EXPECT_TRUE(objExactTy.subtypeOf(opt(subObjTy))); EXPECT_TRUE(!opt(objExactTy).subtypeOf(objExactTy)); EXPECT_TRUE(!opt(subObjTy).subtypeOf(objExactTy)); // Obj= couldBe ?Obj= and ?Obj<=, and vice versa. EXPECT_TRUE(objExactTy.couldBe(opt(objExactTy))); EXPECT_TRUE(opt(objExactTy).couldBe(objExactTy)); EXPECT_TRUE(objExactTy.couldBe(opt(subObjTy))); EXPECT_TRUE(opt(subObjTy).couldBe(objExactTy)); // Obj<= is not a subtype of ?Obj=, it is overlapping but // potentially contains other types. (We might eventually check // whether objects are final as part of this, but not right now.) EXPECT_TRUE(!subObjTy.subtypeOf(opt(objExactTy))); EXPECT_TRUE(!opt(objExactTy).subtypeOf(subObjTy)); // Obj<= couldBe ?Obj= and vice versa. EXPECT_TRUE(subObjTy.couldBe(opt(objExactTy))); EXPECT_TRUE(opt(objExactTy).couldBe(subObjTy)); }
bool is_pseudomain(borrowed_ptr<const php::Func> f) { return borrow(f->unit->pseudomain) == f; }
TEST(Type, Hierarchies) { auto const program = folly::make_unique<php::Program>(); program->units.push_back(make_test_unit()); auto const unit = borrow(program->units.back()); auto const func = [&]() -> borrowed_ptr<php::Func> { for (auto& f : unit->funcs) { if (f->name->isame(s_test.get())) return borrow(f); } return nullptr; }(); EXPECT_TRUE(func != nullptr); auto const ctx = Context { unit, func }; Index idx{borrow(program)}; // load classes in hierarchy auto const clsBase = idx.resolve_class(ctx, s_Base.get()); if (!clsBase) EXPECT_TRUE(false); auto const clsA = idx.resolve_class(ctx, s_A.get()); if (!clsA) EXPECT_TRUE(false); auto const clsB = idx.resolve_class(ctx, s_B.get()); if (!clsB) EXPECT_TRUE(false); auto const clsAA = idx.resolve_class(ctx, s_AA.get()); if (!clsAA) EXPECT_TRUE(false); auto const clsAB = idx.resolve_class(ctx, s_AB.get()); if (!clsAB) EXPECT_TRUE(false); auto const clsBA = idx.resolve_class(ctx, s_BA.get()); if (!clsBA) EXPECT_TRUE(false); auto const clsBB = idx.resolve_class(ctx, s_BB.get()); if (!clsBB) EXPECT_TRUE(false); auto const clsBAA = idx.resolve_class(ctx, s_BAA.get()); if (!clsBAA) EXPECT_TRUE(false); auto const clsTestClass = idx.resolve_class(ctx, s_TestClass.get()); if (!clsTestClass) EXPECT_TRUE(false); auto const clsNonUnique = idx.resolve_class(ctx, s_NonUnique.get()); if (!clsNonUnique) EXPECT_TRUE(false); // make *exact type* and *sub type* types and objects for all loaded classes auto const objExactBaseTy = objExact(*clsBase); auto const subObjBaseTy = subObj(*clsBase); auto const clsExactBaseTy = clsExact(*clsBase); auto const subClsBaseTy = subCls(*clsBase); auto const objExactATy = objExact(*clsA); auto const subObjATy = subObj(*clsA); auto const clsExactATy = clsExact(*clsA); auto const subClsATy = subCls(*clsA); auto const objExactAATy = objExact(*clsAA); auto const subObjAATy = subObj(*clsAA); auto const clsExactAATy = clsExact(*clsAA); auto const subClsAATy = subCls(*clsAA); auto const objExactABTy = objExact(*clsAB); auto const subObjABTy = subObj(*clsAB); auto const clsExactABTy = clsExact(*clsAB); auto const subClsABTy = subCls(*clsAB); auto const objExactBTy = objExact(*clsB); auto const subObjBTy = subObj(*clsB); auto const clsExactBTy = clsExact(*clsB); auto const subClsBTy = subCls(*clsB); auto const objExactBATy = objExact(*clsBA); auto const subObjBATy = subObj(*clsBA); auto const clsExactBATy = clsExact(*clsBA); auto const subClsBATy = subCls(*clsBA); auto const objExactBBTy = objExact(*clsBB); auto const subObjBBTy = subObj(*clsBB); auto const clsExactBBTy = clsExact(*clsBB); auto const subClsBBTy = subCls(*clsBB); auto const objExactBAATy = objExact(*clsBAA); auto const subObjBAATy = subObj(*clsBAA); auto const clsExactBAATy = clsExact(*clsBAA); auto const subClsBAATy = subCls(*clsBAA); auto const objExactTestClassTy = objExact(*clsTestClass); auto const subObjTestClassTy = subObj(*clsTestClass); auto const clsExactTestClassTy = clsExact(*clsTestClass); auto const subClsTestClassTy = subCls(*clsTestClass); auto const objExactNonUniqueTy = objExact(*clsNonUnique); auto const subObjNonUniqueTy = subObj(*clsNonUnique); auto const clsExactNonUniqueTy = clsExact(*clsNonUnique); auto const subClsNonUniqueTy = subCls(*clsNonUnique); // check that type from object and type are the same (obnoxious test) EXPECT_EQ(objcls(objExactBaseTy), clsExactBaseTy); EXPECT_EQ(objcls(subObjBaseTy), subClsBaseTy); EXPECT_EQ(objcls(objExactATy), clsExactATy); EXPECT_EQ(objcls(subObjATy), subClsATy); EXPECT_EQ(objcls(objExactAATy), clsExactAATy); EXPECT_EQ(objcls(subObjAATy), subClsAATy); EXPECT_EQ(objcls(objExactABTy), clsExactABTy); EXPECT_EQ(objcls(subObjABTy), subClsABTy); EXPECT_EQ(objcls(objExactBTy), clsExactBTy); EXPECT_EQ(objcls(subObjBTy), subClsBTy); EXPECT_EQ(objcls(objExactBATy), clsExactBATy); EXPECT_EQ(objcls(subObjBATy), subClsBATy); EXPECT_EQ(objcls(objExactBBTy), clsExactBBTy); EXPECT_EQ(objcls(subObjBBTy), subClsBBTy); EXPECT_EQ(objcls(objExactBAATy), clsExactBAATy); EXPECT_EQ(objcls(subObjBAATy), subClsBAATy); // both subobj(A) and subcls(A) of no_override class A change to exact types EXPECT_EQ(objcls(objExactABTy), subClsABTy); EXPECT_EQ(objcls(subObjABTy), clsExactABTy); // a T= is a subtype of itself but not a strict subtype // also a T= is in a "could be" relationship with itself. EXPECT_TRUE(objcls(objExactBaseTy).subtypeOf(clsExactBaseTy)); EXPECT_FALSE(objcls(objExactBaseTy).strictSubtypeOf(objcls(objExactBaseTy))); EXPECT_TRUE(objcls(objExactBAATy).subtypeOf(clsExactBAATy)); EXPECT_FALSE(clsExactBAATy.strictSubtypeOf(objcls(objExactBAATy))); EXPECT_TRUE(clsExactBAATy.couldBe(clsExactBAATy)); // Given the hierarchy A <- B <- C where A is the base then: // B= is not in any subtype relationshipt with a A= or C=. // Neither they are in "could be" relationships. // Overall T= sets are always disjoint. EXPECT_FALSE(objcls(objExactBATy).subtypeOf(clsExactBaseTy)); EXPECT_FALSE(objcls(objExactBATy).subtypeOf(clsExactBTy)); EXPECT_FALSE(objcls(objExactBATy).subtypeOf(clsExactBAATy)); EXPECT_FALSE(clsExactBATy.strictSubtypeOf(objcls(objExactBaseTy))); EXPECT_FALSE(clsExactBATy.strictSubtypeOf(objcls(objExactBTy))); EXPECT_FALSE(clsExactBATy.strictSubtypeOf(objcls(objExactBAATy))); EXPECT_FALSE(clsExactBATy.couldBe(objcls(objExactBaseTy))); EXPECT_FALSE(objcls(objExactBATy).couldBe(clsExactBTy)); EXPECT_FALSE(clsExactBATy.couldBe(objcls(objExactBAATy))); // any T= is both a subtype and strict subtype of T<=. // Given the hierarchy A <- B <- C where A is the base then: // C= is a subtype and a strict subtype of B<=, ?B<=, A<= and ?A<=. // The "could be" relationship also holds. EXPECT_TRUE(objcls(objExactATy).subtypeOf(subClsATy)); EXPECT_TRUE(objcls(objExactBAATy).subtypeOf(subClsBaseTy)); EXPECT_TRUE(objExactBAATy.subtypeOf(opt(subObjBaseTy))); EXPECT_TRUE(objcls(objExactBAATy).subtypeOf(subClsBTy)); EXPECT_TRUE(objExactBAATy.subtypeOf(opt(subObjBTy))); EXPECT_TRUE(clsExactBAATy.subtypeOf(objcls(subObjBATy))); EXPECT_TRUE(objExactBAATy.subtypeOf(opt(subObjBATy))); EXPECT_TRUE(clsExactBAATy.subtypeOf(objcls(subObjBAATy))); EXPECT_TRUE(objExactBAATy.subtypeOf(opt(subObjBAATy))); EXPECT_TRUE(objcls(objExactATy).strictSubtypeOf(subClsATy)); EXPECT_TRUE(objcls(objExactBAATy).strictSubtypeOf(subClsBaseTy)); EXPECT_TRUE(objExactBAATy.strictSubtypeOf(opt(subObjBaseTy))); EXPECT_TRUE(objcls(objExactBAATy).strictSubtypeOf(subClsBTy)); EXPECT_TRUE(objExactBAATy.strictSubtypeOf(opt(subObjBTy))); EXPECT_TRUE(clsExactBAATy.strictSubtypeOf(objcls(subObjBATy))); EXPECT_TRUE(objExactBAATy.strictSubtypeOf(opt(subObjBATy))); EXPECT_TRUE(clsExactBAATy.strictSubtypeOf(objcls(subObjBAATy))); EXPECT_TRUE(objExactBAATy.strictSubtypeOf(opt(subObjBAATy))); EXPECT_TRUE(objcls(objExactATy).couldBe(subClsATy)); EXPECT_TRUE(objcls(objExactBAATy).couldBe(subClsBaseTy)); EXPECT_TRUE(objExactBAATy.couldBe(opt(subObjBaseTy))); EXPECT_TRUE(objcls(objExactBAATy).couldBe(subClsBTy)); EXPECT_TRUE(objExactBAATy.couldBe(opt(subObjBTy))); EXPECT_TRUE(clsExactBAATy.couldBe(objcls(subObjBATy))); EXPECT_TRUE(objExactBAATy.couldBe(opt(subObjBATy))); EXPECT_TRUE(clsExactBAATy.couldBe(objcls(subObjBAATy))); EXPECT_TRUE(objExactBAATy.couldBe(opt(subObjBAATy))); // a T<= is a subtype of itself but not a strict subtype // also a T<= is in a "could be" relationship with itself EXPECT_TRUE(objcls(subObjBaseTy).subtypeOf(subClsBaseTy)); EXPECT_FALSE(objcls(subObjBaseTy).strictSubtypeOf(objcls(subObjBaseTy))); EXPECT_TRUE(objcls(subObjBAATy).subtypeOf(subClsBAATy)); EXPECT_FALSE(subClsBAATy.strictSubtypeOf(objcls(subObjBAATy))); EXPECT_TRUE(subClsBAATy.couldBe(subClsBAATy)); // a T<= type is in no subtype relationship with T=. // However a T<= is in a "could be" relationship with T=. EXPECT_FALSE(objcls(subObjATy).subtypeOf(clsExactATy)); EXPECT_FALSE(objcls(subObjATy).strictSubtypeOf(clsExactATy)); EXPECT_TRUE(clsExactATy.couldBe(objcls(subObjATy))); // Given 2 types A and B in no inheritance relationship then // A<= and B<= are in no subtype or "could be" relationship. // Same if one of the 2 types is an optional type EXPECT_FALSE(objcls(subObjATy).subtypeOf(clsExactBTy)); EXPECT_FALSE(objcls(subObjATy).strictSubtypeOf(clsExactBTy)); EXPECT_FALSE(subObjATy.subtypeOf(opt(objExactBTy))); EXPECT_FALSE(subObjATy.strictSubtypeOf(opt(objExactBTy))); EXPECT_FALSE(clsExactATy.couldBe(objcls(subObjBTy))); EXPECT_FALSE(objExactATy.couldBe(opt(subObjBTy))); EXPECT_FALSE(objcls(subObjBTy).subtypeOf(clsExactATy)); EXPECT_FALSE(subObjBTy.subtypeOf(opt(objExactATy))); EXPECT_FALSE(objcls(subObjBTy).strictSubtypeOf(clsExactATy)); EXPECT_FALSE(subObjBTy.strictSubtypeOf(opt(objExactATy))); EXPECT_FALSE(clsExactBTy.couldBe(objcls(subObjATy))); EXPECT_FALSE(objExactBTy.couldBe(opt(subObjATy))); // Given the hierarchy A <- B <- C where A is the base then: // C<= is a subtype and a strict subtype of B<=, ?B<=, A<= and ?A<=. // It is also in a "could be" relationship with all its ancestors // (including optional) EXPECT_TRUE(objcls(subObjBAATy).subtypeOf(subClsBaseTy)); EXPECT_TRUE(subObjBAATy.subtypeOf(opt(subObjBaseTy))); EXPECT_TRUE(objcls(subObjBAATy).subtypeOf(subClsBTy)); EXPECT_TRUE(subObjBAATy.subtypeOf(opt(subObjBTy))); EXPECT_TRUE(subClsBAATy.subtypeOf(objcls(subObjBATy))); EXPECT_TRUE(subObjBAATy.subtypeOf(opt(subObjBATy))); EXPECT_TRUE(objcls(subObjBAATy).strictSubtypeOf(subClsBaseTy)); EXPECT_TRUE(subObjBAATy.strictSubtypeOf(opt(subObjBaseTy))); EXPECT_TRUE(objcls(subObjBAATy).strictSubtypeOf(subClsBTy)); EXPECT_TRUE(subObjBAATy.strictSubtypeOf(opt(subObjBTy))); EXPECT_TRUE(subClsBAATy.strictSubtypeOf(objcls(subObjBATy))); EXPECT_TRUE(subObjBAATy.strictSubtypeOf(opt(subObjBATy))); EXPECT_TRUE(objcls(subObjBAATy).couldBe(subClsBaseTy)); EXPECT_TRUE(subObjBAATy.couldBe(opt(subObjBaseTy))); EXPECT_TRUE(objcls(subObjBAATy).couldBe(subClsBTy)); EXPECT_TRUE(subObjBAATy.couldBe(opt(subObjBTy))); EXPECT_TRUE(subClsBAATy.couldBe(objcls(subObjBATy))); EXPECT_TRUE(subObjBAATy.couldBe(opt(subObjBATy))); // Given the hierarchy A <- B <- C where A is the base then: // A<= is not in a subtype neither a strict subtype with B<=, ?B<=, A<= // ?A<=. However A<= is in a "could be" relationship with all its // children (including optional) EXPECT_FALSE(objcls(subObjBaseTy).subtypeOf(subClsATy)); EXPECT_FALSE(subObjBaseTy.subtypeOf(opt(subObjATy))); EXPECT_FALSE(objcls(subObjBaseTy).subtypeOf(subClsBTy)); EXPECT_FALSE(subObjBaseTy.subtypeOf(opt(subObjBTy))); EXPECT_FALSE(subClsBaseTy.subtypeOf(objcls(subObjAATy))); EXPECT_FALSE(subObjBaseTy.subtypeOf(opt(subObjAATy))); EXPECT_FALSE(subClsBaseTy.subtypeOf(objcls(subObjABTy))); EXPECT_FALSE(subObjBaseTy.subtypeOf(opt(subObjABTy))); EXPECT_FALSE(objcls(subObjBaseTy).subtypeOf(subClsBATy)); EXPECT_FALSE(subObjBaseTy.subtypeOf(opt(subObjBATy))); EXPECT_FALSE(subClsBaseTy.subtypeOf(objcls(subObjBBTy))); EXPECT_FALSE(subObjBaseTy.subtypeOf(opt(subObjBBTy))); EXPECT_FALSE(subClsBaseTy.subtypeOf(objcls(subObjBAATy))); EXPECT_FALSE(subObjBaseTy.subtypeOf(opt(subObjBAATy))); EXPECT_FALSE(objcls(subObjBaseTy).strictSubtypeOf(subClsATy)); EXPECT_FALSE(subObjBaseTy.strictSubtypeOf(opt(subObjATy))); EXPECT_FALSE(objcls(subObjBaseTy).strictSubtypeOf(subClsBTy)); EXPECT_FALSE(subObjBaseTy.strictSubtypeOf(opt(subObjBTy))); EXPECT_FALSE(subClsBaseTy.strictSubtypeOf(objcls(subObjAATy))); EXPECT_FALSE(subObjBaseTy.strictSubtypeOf(opt(subObjAATy))); EXPECT_FALSE(subClsBaseTy.strictSubtypeOf(objcls(subObjABTy))); EXPECT_FALSE(subObjBaseTy.strictSubtypeOf(opt(subObjABTy))); EXPECT_FALSE(objcls(subObjBaseTy).strictSubtypeOf(subClsBATy)); EXPECT_FALSE(subObjBaseTy.strictSubtypeOf(opt(subObjBATy))); EXPECT_FALSE(subClsBaseTy.strictSubtypeOf(objcls(subObjBBTy))); EXPECT_FALSE(subObjBaseTy.strictSubtypeOf(opt(subObjBBTy))); EXPECT_FALSE(subClsBaseTy.strictSubtypeOf(objcls(subObjBAATy))); EXPECT_FALSE(subObjBaseTy.strictSubtypeOf(opt(subObjBAATy))); EXPECT_TRUE(objcls(subObjBaseTy).couldBe(subClsATy)); EXPECT_TRUE(subObjBaseTy.couldBe(opt(subObjATy))); EXPECT_TRUE(objcls(subObjBaseTy).couldBe(subClsBTy)); EXPECT_TRUE(subObjBaseTy.couldBe(opt(subObjBTy))); EXPECT_TRUE(subClsBaseTy.couldBe(objcls(subObjAATy))); EXPECT_TRUE(subObjBaseTy.couldBe(opt(subObjAATy))); EXPECT_TRUE(subClsBaseTy.couldBe(objcls(subObjABTy))); EXPECT_TRUE(subObjBaseTy.couldBe(opt(subObjABTy))); EXPECT_TRUE(objcls(subObjBaseTy).couldBe(subClsBATy)); EXPECT_TRUE(subObjBaseTy.couldBe(opt(subObjBATy))); EXPECT_TRUE(subClsBaseTy.couldBe(objcls(subObjBBTy))); EXPECT_TRUE(subObjBaseTy.couldBe(opt(subObjBBTy))); EXPECT_TRUE(subClsBaseTy.couldBe(objcls(subObjBAATy))); EXPECT_TRUE(subObjBaseTy.couldBe(opt(subObjBAATy))); // check union_of and commonAncestor API EXPECT_TRUE((*(*clsA).commonAncestor(*clsB)).same(*clsBase)); EXPECT_TRUE((*(*clsB).commonAncestor(*clsA)).same(*clsBase)); EXPECT_TRUE((*(*clsAA).commonAncestor(*clsAB)).same(*clsA)); EXPECT_TRUE((*(*clsAB).commonAncestor(*clsAA)).same(*clsA)); EXPECT_TRUE((*(*clsA).commonAncestor(*clsBAA)).same(*clsBase)); EXPECT_TRUE((*(*clsBAA).commonAncestor(*clsA)).same(*clsBase)); EXPECT_TRUE((*(*clsBAA).commonAncestor(*clsB)).same(*clsB)); EXPECT_TRUE((*(*clsB).commonAncestor(*clsBAA)).same(*clsB)); EXPECT_TRUE((*(*clsBAA).commonAncestor(*clsBB)).same(*clsB)); EXPECT_TRUE((*(*clsBB).commonAncestor(*clsBAA)).same(*clsB)); EXPECT_TRUE((*(*clsAA).commonAncestor(*clsBase)).same(*clsBase)); EXPECT_TRUE((*(*clsBase).commonAncestor(*clsAA)).same(*clsBase)); EXPECT_FALSE((*clsAA).commonAncestor(*clsTestClass)); EXPECT_FALSE((*clsTestClass).commonAncestor(*clsAA)); EXPECT_FALSE((*clsBAA).commonAncestor(*clsNonUnique)); EXPECT_FALSE((*clsNonUnique).commonAncestor(*clsBAA)); // check union_of // union of subCls EXPECT_EQ(union_of(subClsATy, subClsBTy), subClsBaseTy); EXPECT_EQ(union_of(subClsAATy, subClsABTy), subClsATy); EXPECT_EQ(union_of(subClsATy, subClsBAATy), subClsBaseTy); EXPECT_EQ(union_of(subClsBAATy, subClsBTy), subClsBTy); EXPECT_EQ(union_of(subClsBAATy, subClsBBTy), subClsBTy); EXPECT_EQ(union_of(subClsAATy, subClsBaseTy), subClsBaseTy); EXPECT_EQ(union_of(subClsAATy, subClsTestClassTy), TCls); EXPECT_EQ(union_of(subClsBAATy, subClsNonUniqueTy), TCls); // union of subCls and clsExact mixed EXPECT_EQ(union_of(clsExactATy, subClsBTy), subClsBaseTy); EXPECT_EQ(union_of(subClsAATy, clsExactABTy), subClsATy); EXPECT_EQ(union_of(clsExactATy, subClsBAATy), subClsBaseTy); EXPECT_EQ(union_of(subClsBAATy, clsExactBTy), subClsBTy); EXPECT_EQ(union_of(clsExactBAATy, subClsBBTy), subClsBTy); EXPECT_EQ(union_of(subClsAATy, clsExactBaseTy), subClsBaseTy); EXPECT_EQ(union_of(clsExactAATy, subClsTestClassTy), TCls); EXPECT_EQ(union_of(subClsBAATy, clsExactNonUniqueTy), TCls); // union of clsExact EXPECT_EQ(union_of(clsExactATy, clsExactBTy), subClsBaseTy); EXPECT_EQ(union_of(clsExactAATy, clsExactABTy), subClsATy); EXPECT_EQ(union_of(clsExactATy, clsExactBAATy), subClsBaseTy); EXPECT_EQ(union_of(clsExactBAATy, clsExactBTy), subClsBTy); EXPECT_EQ(union_of(clsExactBAATy, clsExactBBTy), subClsBTy); EXPECT_EQ(union_of(clsExactAATy, clsExactBaseTy), subClsBaseTy); EXPECT_EQ(union_of(clsExactAATy, subClsTestClassTy), TCls); EXPECT_EQ(union_of(clsExactBAATy, clsExactNonUniqueTy), TCls); // union of subObj EXPECT_EQ(union_of(subObjATy, subObjBTy), subObjBaseTy); EXPECT_EQ(union_of(subObjAATy, subObjABTy), subObjATy); EXPECT_EQ(union_of(subObjATy, subObjBAATy), subObjBaseTy); EXPECT_EQ(union_of(subObjBAATy, subObjBTy), subObjBTy); EXPECT_EQ(union_of(subObjBAATy, subObjBBTy), subObjBTy); EXPECT_EQ(union_of(subObjAATy, subObjBaseTy), subObjBaseTy); EXPECT_EQ(union_of(subObjAATy, subObjTestClassTy), TObj); EXPECT_EQ(union_of(subObjBAATy, subObjNonUniqueTy), TObj); // union of subObj and objExact mixed EXPECT_EQ(union_of(objExactATy, subObjBTy), subObjBaseTy); EXPECT_EQ(union_of(subObjAATy, objExactABTy), subObjATy); EXPECT_EQ(union_of(objExactATy, subObjBAATy), subObjBaseTy); EXPECT_EQ(union_of(subObjBAATy, objExactBTy), subObjBTy); EXPECT_EQ(union_of(objExactBAATy, subObjBBTy), subObjBTy); EXPECT_EQ(union_of(subObjAATy, objExactBaseTy), subObjBaseTy); EXPECT_EQ(union_of(objExactAATy, subObjTestClassTy), TObj); EXPECT_EQ(union_of(subObjBAATy, objExactNonUniqueTy), TObj); // union of objExact EXPECT_EQ(union_of(objExactATy, objExactBTy), subObjBaseTy); EXPECT_EQ(union_of(objExactAATy, objExactABTy), subObjATy); EXPECT_EQ(union_of(objExactATy, objExactBAATy), subObjBaseTy); EXPECT_EQ(union_of(objExactBAATy, objExactBTy), subObjBTy); EXPECT_EQ(union_of(objExactBAATy, objExactBBTy), subObjBTy); EXPECT_EQ(union_of(objExactAATy, objExactBaseTy), subObjBaseTy); EXPECT_EQ(union_of(objExactAATy, objExactTestClassTy), TObj); EXPECT_EQ(union_of(objExactBAATy, objExactNonUniqueTy), TObj); // optional sub obj EXPECT_EQ(union_of(opt(subObjATy), opt(subObjBTy)), opt(subObjBaseTy)); EXPECT_EQ(union_of(subObjAATy, opt(subObjABTy)), opt(subObjATy)); EXPECT_EQ(union_of(opt(subObjATy), subObjBAATy), opt(subObjBaseTy)); EXPECT_EQ(union_of(opt(subObjBAATy), opt(subObjBTy)), opt(subObjBTy)); EXPECT_EQ(union_of(opt(subObjBAATy), subObjBBTy), opt(subObjBTy)); EXPECT_EQ(union_of(opt(subObjAATy), opt(subObjBaseTy)), opt(subObjBaseTy)); EXPECT_EQ(union_of(subObjAATy, opt(subObjTestClassTy)), opt(TObj)); EXPECT_EQ(union_of(subObjBAATy, opt(subObjNonUniqueTy)), opt(TObj)); // optional sub and exact obj mixed EXPECT_EQ(union_of(opt(objExactATy), subObjBTy), opt(subObjBaseTy)); EXPECT_EQ(union_of(subObjAATy, opt(objExactABTy)), opt(subObjATy)); EXPECT_EQ(union_of(opt(objExactATy), objExactBAATy), opt(subObjBaseTy)); EXPECT_EQ(union_of(subObjBAATy, opt(objExactBTy)), opt(subObjBTy)); EXPECT_EQ(union_of(opt(subObjBAATy), objExactBBTy), opt(subObjBTy)); EXPECT_EQ(union_of(objExactAATy, opt(objExactBaseTy)), opt(subObjBaseTy)); EXPECT_EQ(union_of(opt(subObjAATy), objExactTestClassTy), opt(TObj)); EXPECT_EQ(union_of(subObjBAATy, opt(objExactNonUniqueTy)), opt(TObj)); }
/** Translate python list of tuples to Config * * [(K,V)] -> Config * float -> double * str -> string * [[()]] -> vector<Config> (recurse) * ndarray -> vector<double> * TODO: [0.0] -> vector<double> */ void List2Config(Config& ret, PyObject *list, unsigned depth) { if(depth>3) throw std::runtime_error("too deep for Dict2Config"); PyRef<> iter(PyObject_GetIter(list)); while(true) { PyObject *item = PyIter_Next(iter.py()); if(!item) break; PyRef<> itemref(item); const char *kname; PyObject *value; if(!PyArg_ParseTuple(item, "sO", &kname, &value)) throw std::runtime_error("list item is not a tuple?"); if(PyArray_Check(value)) { // array as vector<double> PyRef<> arr(PyArray_ContiguousFromAny(value, NPY_DOUBLE, 0, 2)); double *buf = (double*)PyArray_DATA(arr.py()); std::vector<double> temp(PyArray_SIZE(arr.py())); std::copy(buf, buf+temp.size(), temp.begin()); ret.swap<std::vector<double> >(kname, temp); } else if(PyNumber_Check(value)) { // scalar as double PyRef<> dval(PyNumber_Float(value)); double val = PyFloat_AsDouble(dval.py()); ret.set<double>(kname, val); } else if(PyUnicode_Check(value) || (PY_MAJOR_VERSION < 3 && PyBytes_Check(value))) { // string PyRef<> valref(value, borrow()); PyCString sval(valref); const char *val = sval.c_str(); ret.set<std::string>(kname, val); } else if(PySequence_Check(value)) { // list of dict Py_ssize_t N = PySequence_Size(value); Config::vector_t output; output.reserve(N); for(Py_ssize_t i=0; i<N; i++) { PyRef<> elem(PySequence_GetItem(value, i)); if(PyDict_Check(elem.py())) { elem.reset(PyMapping_Items(elem.py())); } if(!PyList_Check(elem.py())) { PyTypeObject *valuetype = (PyTypeObject*)PyObject_Type(elem.py()); throw std::invalid_argument(SB()<<"lists must contain only dict or list of tuples, not "<<valuetype->tp_name); } output.push_back(ret.new_scope()); List2Config(output.back(), elem.py(), depth+1); // inheirt parent scope } ret.set<Config::vector_t>(kname, output); } else { PyTypeObject *valuetype = (PyTypeObject*)PyObject_Type(value); throw std::invalid_argument(SB()<<"Must be a dict, not "<<valuetype->tp_name); } } }
Config* PyGLPSParse2Config(PyObject *, PyObject *args, PyObject *kws) { PyObject *conf = NULL, *extra_defs = Py_None; const char *path = NULL; const char *pnames[] = {"config", "path", "extra", NULL}; if(!PyArg_ParseTupleAndKeywords(args, kws, "O|zO", (char**)pnames, &conf, &path, &extra_defs)) return NULL; GLPSParser parser; if(extra_defs==Py_None) { // no-op } else if(PyDict_Check(extra_defs)) { PyObject *key, *value; Py_ssize_t pos = 0; while(PyDict_Next(extra_defs, &pos, &key, &value)) { PyRef<> keyx(key, borrow()); PyCString keystr(keyx); Config::value_t curval; if(PyNumber_Check(value)) { PyRef<> pyf(PyNumber_Float(value)); curval = PyFloat_AsDouble(pyf.py()); } else if(PyString_Check(value)) { PyRef<> valuex(value, borrow()); PyCString valstr(valuex); curval = valstr.c_str(); } else { PyErr_SetString(PyExc_ValueError, "extra {} can contain only numbers or strings"); return NULL; } parser.setVar(keystr.c_str(), curval); } } else { PyErr_SetString(PyExc_ValueError, "'extra' must be a dict"); return NULL; } PyGetBuf buf; std::auto_ptr<Config> C; PyRef<> listref; if(PyObject_HasAttrString(conf, "read")) { // file-like PyCString pyname; if(!path && PyObject_HasAttrString(conf, "name")) { path = pyname.c_str(pydirname(PyObject_GetAttrString(conf, "name"))); } PyRef<> pybytes(PyObject_CallMethod(conf, "read", "")); if(!buf.get(pybytes.py())) { PyErr_SetString(PyExc_TypeError, "read() must return a buffer"); return NULL; } C.reset(parser.parse_byte((const char*)buf.data(), buf.size(), path)); } else if(buf.get(conf)) { C.reset(parser.parse_byte((const char*)buf.data(), buf.size(), path)); #if PY_MAJOR_VERSION >= 3 } else if(PyUnicode_Check(conf)) { // py3 str (aka unicode) doesn't implement buffer iface PyCString buf; const char *cbuf = buf.c_str(conf); C.reset(parser.parse_byte(cbuf, strlen(cbuf), path)); #endif } else { if(PyDict_Check(conf)) { listref.reset(PyMapping_Items(conf)); conf = listref.py(); } if(PyList_Check(conf)) { C.reset(list2conf(conf)); } else { throw std::invalid_argument("'config' must be dict, list of tuples, or byte buffer"); } } return C.release(); }