📄 class.cpp
字号:
m_field_list.push_back(pe);
if(t.is_object()) m_obj_list.push_back(pe);
}
}
// if we have a base class, then create a fake entry
Class *bc = base_class();
if (bc) {
PEntry pe = new Entry;
*pe = *(bc->entry());
pe->rmode = OREL;
pe->data = 0;
// m_obj_list->push_back(pe);
m_base_entry = pe;
}
// *fix 1.1.0 Returns false if there is nothing requiring construction
return m_obj_list.size() > 0 || m_base_entry != NULL;
}
void compile(PExpr ex)
{
// *fix 0.9.6 Is necessary to check the temp context after every expression compile!
Parser::code().compile(ex,DROP_VALUE);
Parser::check_temp_context();
}
PExpr call_function(Function *pf, PExpr e=NULL)
// shortcut for calling functions of one or none arguments;
// always forces call of actual function, virtual or not (see compile_function_call() in code.cpp)
{
return new Expr(DCALL,pf->return_type(),pf,Expressions::expr_list(e));
}
// auto contruction/destruction code generation
// do note that the _base class_ is treated specially; we have already physically
// constructed the object, so all we do is call the inherited method!
bool Class::auto_construct(bool make_method)
{
using namespace Expressions;
bool copy_ctor = false;
if (!make_method) { // if we were called to initialize an existing constructor...
FunctionContext *fc = (FunctionContext *)&Parser::state.context();
// which was a copy constructor, a special case; (no default operation!)
// *fix 1.0.0 But we do need to use any explicit initializations in the ctor init list
copy_ctor = fc->function() == copy_constructor();
} else if (imported()) { // *change 1.2.0 Special case of importing a class moved here....
declare_method(constructor_name(),t_void,NULL,t_void,IsConstructor);
return true;
}
if (m_field_list.size() == 0) { // then build the list of fields....
bool needs_construction = build_obj_list();
// *fix 1.1.0 Don't interfere with attempts to finalize existing ctors or dtors.
if (! make_method) needs_construction = true;
// *fix 1.1.0 Create a default ctor if there's a VMT, even if nothing needs to be constructed
// *fix 1.2.6 I've uncommented this line, having forgotten why it was commented ;)
// for GCC3 imports, we really do need to know if something's a 'plain old data struct'!
if (! needs_construction && ! has_VMT()) return false;
}
try {
if (make_method) {
begin_method(constructor_name(),t_void,NULL,t_void,IsConstructor);
}
// *fix 0.9.5 One place where you can construct an abstract base class
if (!copy_ctor && m_base_entry != NULL && !base_class()->simple_struct()) {
PExpr ec = construct_op(base_class(), s_entry_map[m_base_entry],false);
if (ec->is_nil()) throw "cannot construct base class";
compile(ec);
// Imported constructors of classes w/ vtables must be followed by
// code to (optionally) patch the vtable, if a derived UC class is
// overriding any methods!
// *fix 1.2.0 We must emit VTABLE_PATCH for _any_ class which has modified the vtable
// of some imported ancestor class. (This was only working for directly derived classes!)
if (vtable_size() > 0)
Parser::code().out(CodeGenerator::instruction_with_pointer(VTABLE_PATCH,this));
}
EntryList::iterator eli;
FORALL(eli, m_field_list) {
PEntry pe = *eli;
bool obj_has_ctor = pe->type.is_object() && as_class(pe)->has_constructors();
// if there was a class init list, this map has been filled in.
PExprList pel = s_entry_map[pe];
if ((!copy_ctor && obj_has_ctor) || pel != NULL) {
PExpr ec = initialize_op(pe,NULL,pel,0);
if (ec->is_nil()) throw "cannot initialize member object";
compile(ec);
}
}
} catch(char *msg) {
error (msg);
}
// *fix 0.9.5 Absolutely essential that this ALWAYS happens!
s_entry_map.clear();
if (make_method) end_method();
return true;
}
void Class::auto_destruct(bool make_method)
{
using namespace Expressions;
if (m_obj_list.size() == 0 && !build_obj_list()) return;
// *fix 1.2.3 Derived objects may have needed the building of a ctor,
// but that doesn't mean they need a dtor.
if (m_obj_list.size() == 0 && base_class()->destructor() == NULL) return;
if (imported()) { // *add 1.2.0 needing to force the import of a class dtor
declare_method(destructor_name(),t_void,NULL,t_void,IsDestructor);
return;
}
// Build up a list of member fields which have dtors
EntryList::iterator eli;
EntryList ls;
FORALL(eli,m_obj_list)
if (as_class(*eli)->destructor()) ls.push_back(*eli);
// *fix 0.9.6 we can bail out if there's no such member fields AND no base dtor
bool base_has_dtor = m_base_entry != NULL && base_class()->destructor() != NULL;
if (ls.size()==0 && ! base_has_dtor) return;
if (make_method) begin_method(destructor_name(),t_void,NULL,t_void,IsDestructor);
if (base_has_dtor) {
compile(call_function(base_class()->destructor()));
}
// and call the dtor for all such member objects...
for(eli = ls.begin(); eli != ls.end(); eli++) {
Function *pd = as_class(*eli)->destructor();
compile(method_call(pd,entry_op(*eli),NULL));
}
if (make_method) end_method();
}
void Class::auto_assign_copy(bool is_assign)
// either creates a default assignment operator,
// or a copy constructor, using memberwise
// assigment/initialization
// Construct these in all cases!
{
using namespace Expressions;
// *fix 1.2.7 Ensure that the field list has been updated.
if (m_field_list.size() == 0) build_obj_list();
char *arg_name = "$obj";
Type t_const_oref = ref_to(this,true);
PEntry pe;
PExpr ex,em,ea,eo;
Class *bc = base_class();
if (is_assign) {
PEntry pe = lookup("="); // *fix 0.9.5 auto-assign calls _inherited_ operator=
// ea is the formal parameter (const T&)
ea = entry_op(begin_method("=",ref_to(this,false),arg_name,t_const_oref,IsPlain));
if (bc && pe) { // but do we have operator=(const T&) ??
PExpr efn = function_op(entry_op(pe),expr_list(ea));
if (!efn->is_nil()) compile(efn);
}
} else {
ea = entry_op(begin_method(constructor_name(),t_void,arg_name,t_const_oref,IsConstructor));
if (bc && bc->copy_constructor()) compile(call_function(bc->copy_constructor(),ea));
}
// over all non-function non-static members of this class...
EntryList::iterator eli;
FORALL(eli,m_field_list){
pe = *eli;
em = entry_op(pe);
eo = make_op(DOT,pe->type,ea,em);
// *fix 1.1.4 Don't enforce constness check when generating these assignments!
if (is_assign) ex = assign_op(em,eo,false);
else {
// *hack 1.1.4 Ignore arrays when building copy ctor for now
if (Parser::array_size(pe) > 1) continue;
else ex = initialize_op(pe,eo,NULL,0);
}
if (ex && !ex->is_nil()) compile(ex);
else if (m_obj_list.size() != 0) warning("cannot build assign/copy ctor");
}
// operator= must return its reference argument...
// Crucial not to _drop_ the stack at this point!
if (is_assign) Parser::code().compile(ea,0);
end_method();
}
///// Friendship mangement /////////////
bool Class::is_friend_class(Class *pc)
{
return is_friend_function(pc);
}
bool Class::is_friend_function(void *fn)
{
return utils::find(m_friend_objects,(Function *)fn);
}
void Class::add_friend_object(void *pc, bool is_class)
{
m_friend_objects.push_back((Function *)pc);
}
PClass Class::generate_try_block_handler()
{
using namespace Parser;
using namespace Expressions;
// Construct a class with a single 32-bit field and a constructor
// for initializing same...NB that it has a VMT so that it gets put
// on the ODS, where we will use it as a unique marker.
Type tc = state.add_class(STRUCT,TRY_BLOCK_HANDLER_CLASS,ForwardClass,t_void);
Class *pc = tc.as_class();
pc->next_slot(); // a fiddle, since we don't have any v. methods!
pc->construct_VMT();
state.push_context(pc);
PEntry field = state.add_variable(t_int,"_field_",NULL,None);
PEntry arg = begin_method(pc->constructor_name(),t_void,"_arg_",t_int,IsConstructor);
PExpr ea = assign_op(entry_op(field),entry_op(arg));
code().compile(ea,DROP_VALUE);
end_method();
state.pop_context();
return pc;
}
// *add 1.2.6 the Enum object now carries the list of its members
void Enum::add_entry(PEntry pe)
{
m_entries.push_back(pe);
}
Table* Enum::context()
{
// we can assume that the entries have been added to the enclosing context
return m_entries.size() > 0 ? m_entries.front()->context : NULL;
}
string Enum::lookup_value(int val)
{
EntryList::iterator eli;
for (eli = m_entries.begin(); eli != m_entries.end(); ++eli) {
PEntry pe = *eli;
int entry_val = *(int *)pe->global_ptr();
if (val == entry_val) return pe->name;
}
return "<undef>";
}
namespace {
// private utilities!
bool grab_list(const TypeList& tl1, TypeList& tl2)
{
if (tl1.size()==0) return false;
tl2 = tl1;
return true;
}
// these guys provide a simplified way of generating a class method,
// of one or none arguments. Used to construct default constructors, etc.
PEntry begin_method(string name, Type rtype, char *arg_name, Type atype, int ftype)
{
using Parser::state;
Class *ccntxt;
Sig sig(rtype);
if (arg_name) sig << arg_name << atype;
bool wuz_function = state.context().type() == FUNCTION;
if (wuz_function) ccntxt = (Class *)state.pop_context();
Function *pfn = Parser::state.start_function(sig.m_type,name.c_str());
Parser::state.pop_context(); // usually done by block-end!
if (wuz_function) state.push_context(ccntxt);
pfn->set_construct_destruct(ftype);
mFe = pfn->context();
Parser::state.push_context(pfn->context());
return mFe->lookup(arg_name);
}
void declare_method(string name, Type rtype, char *arg_name, Type atype, int ftype)
{
Sig sig(rtype);
if (arg_name) sig << arg_name << atype;
Parser::state.set_construct_destruct(ftype);
Parser::state.declare_function(sig.m_type,name.c_str());
}
void end_method()
{
mFe->finalize();
Parser::state.pop_context(); // see ParserState::finalize_block()
Parser::state.set_construct_destruct(IsPlain); // *fix 1.2.3b
}
typedef TypeDistance (*TypeMatch) (Type,Type);
Function *get_match(const TypeList& tl, const FunctionList& fl, Type t, TypeMatch tmatch)
{
TypeList::const_iterator tli;
FunctionList::const_iterator fli;
t.strip_qualifiers();
for(tli = tl.begin(), fli = fl.begin(); tli != tl.end(); ++tli,++fli)
if (tmatch(*tli,t) != NO_MATCH) return *fli; // *fix 1.1.3 wuz (*tli,t)
return NULL;
}
Function *get_std_match(const TypeList& tl, const FunctionList& fl, Type t)
{
Function *pf = get_match(tl,fl,t,trivial_match);
if (pf) return pf;
pf = get_match(tl,fl,t,promote_match);
if (pf) return pf;
pf = get_match(tl,fl,t,std_match);
return pf;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -