Annotation of parser3/src/types/pa_vclass.C, revision 1.37

1.7       paf         1: /**    @file
                      2:        Parser: @b class parser class impl.
1.1       paf         3: 
1.37    ! misha       4:        Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com)
1.7       paf         5:        Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.1       paf         6: */
                      7: 
1.37    ! misha       8: static const char * const IDENT_VCLASS_C="$Date: 2008-06-16 12:42:20 $";
1.7       paf         9: 
1.1       paf        10: #include "pa_vclass.h"
                     11: 
1.24      paf        12: Property& VClass::add_property(const String& aname) {
                     13:        String prop_name=aname.mid(4, aname.length());
                     14:        
                     15:        Property* result;
                     16:        if(Value* value=ffields.get(prop_name)) {
                     17:                result=value->get_property();
                     18:                if(!result) // can occur in ^process
                     19:                        throw Exception("parser.compile",
                     20:                                &prop_name,
                     21:                                "property can not be created, already exists field (%s) with that name", value->get_class()->name_cstr());
                     22:        } else {
                     23:                VProperty* vproperty=new VProperty();
                     24:                ffields.put(prop_name, vproperty);
                     25:                result=&vproperty->get();
                     26:        }
                     27:        return *result;
                     28: }
                     29: 
1.22      paf        30: /// preparing property accessors to fields
1.35      misha      31: void VClass::add_method(const String& aname, Method& amethod) {
                     32:        if(aname.starts_with("GET_")){
1.36      misha      33:                if(aname=="GET_DEFAULT")
1.35      misha      34:                        set_default_getter(&amethod);
                     35:                else
                     36:                        add_property(aname).getter=&amethod;
1.36      misha      37:        } else if(aname.starts_with("SET_")){
1.24      paf        38:                add_property(aname).setter=&amethod;
1.36      misha      39:        } else if(aname=="GET"){
                     40:                set_scalar(&amethod);
                     41:        }
                     42: 
                     43: 
1.25      paf        44:        // NOT under 'else' for backward compatiblilty: 
                     45:        // if someone used get_xxx names to name regular methods
1.24      paf        46:        // still register method:
                     47:        VStateless_class::add_method(aname, amethod);
1.22      paf        48: }
                     49: 
1.17      paf        50: Value* VClass::as(const char* atype, bool looking_up) {
                     51:        if(Value* result=Value::as(atype, looking_up))
1.12      paf        52:                return result;
1.11      paf        53:        else
1.12      paf        54:                return fbase?fbase->as(atype, looking_up):0;
1.11      paf        55: }
                     56: 
1.22      paf        57: /// VClass: $CLASS, (field/property)=STATIC value;(method)=method_ref with self=object_class
1.28      paf        58: Value* VClass::get_element(const String& aname, Value& aself, bool alooking_up) {
1.30      paf        59:        bool property_but_no_getter_in_self=false;
                     60: 
1.22      paf        61:        // simple things first: $field=static field/property
                     62:        if(Value* result=ffields.get(aname)) {
1.35      misha      63:                Property* prop=result->get_property();
                     64: 
                     65:                if(!prop) // just field, not a property
                     66:                        return result;
                     67: 
                     68:                if(Method* method=prop->getter) // has getter
                     69:                        return new VJunction(aself, method, true /*is_getter*/);
                     70: 
                     71:                property_but_no_getter_in_self=true;
1.21      paf        72:        }
                     73: 
1.14      paf        74:        // $CLASS, $method, or other base element
1.35      misha      75:        if(Value* result=VStateless_class::get_element(aname, aself, false))
1.37    ! misha      76:                return result; // @TODO: this can be SIGNIFICANTLY sped up by caching in ffields! [THOUGH decide about different aself] // what REALLY would speed up things is to join storage of properties/methods/fields of all vobject parents into last descenant [sort of vmt + all fields as in other langs]
1.30      paf        77: 
                     78:        if(property_but_no_getter_in_self)
1.34      misha      79:                throw Exception(PARSER_RUNTIME,
1.31      paf        80:                        0,
                     81:                        "this property has no getter method (@GET_%s[])", aname.cstr());
1.7       paf        82: 
1.35      misha      83:        // no field or method found: looking for default getter
                     84:        if(alooking_up)
                     85:                if(Value* result=get_default_getter(aself, aname))
                     86:                        return result;
                     87: 
1.7       paf        88:        return 0;
                     89: }
                     90: 
1.32      paf        91: #define PROPERTY_BUT_NO_SETTER_IN_SELF reinterpret_cast<const VJunction*>(2)
                     92: const VJunction* VClass::prevent_overwrite_property(Value* value, Prevent_info* info) {
1.25      paf        93:        if(Property* property=value->get_property()) {
1.28      paf        94:                if(Method* setter=property->setter)
1.32      paf        95:                        return new VJunction(*info->self, setter);
1.29      paf        96: 
                     97:                return PROPERTY_BUT_NO_SETTER_IN_SELF;
1.25      paf        98:        }
                     99: 
                    100:        return 0;
                    101: }
1.32      paf       102: const VJunction* VClass::prevent_append_if_exists_in_base(Value* value, Prevent_info* info)  {
1.28      paf       103:        if(VStateless_class* cbase=info->_this->fbase) {
1.29      paf       104:                if(Value* obase=info->self->base()) // MXdoc has fbase but does not have object_base[ base() ]
1.32      paf       105:                        if(const VJunction* result=cbase->put_element(*obase, *info->name, value, true/*try to replace! NEVER overwrite*/))
1.29      paf       106:                                return result; // replaced in base
1.28      paf       107:        }
1.25      paf       108: 
1.28      paf       109:        return 0;
                    110: }
1.25      paf       111: /// VClass: (field/property)=value - static values only
1.32      paf       112: const VJunction* VClass::put_element(Value& aself, const String& aname, Value* avalue, bool areplace) {
1.28      paf       113:        Prevent_info info={this, &aself, &aname};
1.29      paf       114:        if(areplace) {
                    115:                bool property_but_no_setter_in_self=false;
                    116:                // trying to replace it in fields/properties
1.32      paf       117:                if(const VJunction* result=ffields.maybe_replace_never_append<const VJunction*>(aname, avalue, 
1.28      paf       118:                        prevent_overwrite_property,
1.29      paf       119:                        &info))
                    120:                        if(result==PROPERTY_BUT_NO_SETTER_IN_SELF)
                    121:                                property_but_no_setter_in_self=true; // continue to find setter up the tree
                    122:                        else
                    123:                                return result; // replaced locally
                    124: 
                    125:                // if not found locally, going up the tree
                    126:                if(fbase)
                    127:                        if(Value* obase=aself.base()) // MXdoc has fbase but does not have object_base[ base() ]
1.32      paf       128:                                if(const VJunction* result=fbase->put_element(*obase, aname, avalue, true/*try to replace! NEVER overwrite*/))
1.29      paf       129:                                        return result; // replaced in base
                    130: 
                    131:                if(property_but_no_setter_in_self)
1.34      misha     132:                        throw Exception(PARSER_RUNTIME,
1.29      paf       133:                                0,
1.31      paf       134:                                "this property has no setter method (@SET_%s[value])", aname.cstr());
1.29      paf       135: 
                    136:                return 0;
                    137:        } else // append if not existed neither in fields nor in base classes
1.32      paf       138:                return ffields.maybe_replace_maybe_append<const VJunction*>(aname, avalue, 
1.28      paf       139:                        prevent_overwrite_property,
                    140:                        prevent_append_if_exists_in_base, 
                    141:                        &info);
1.7       paf       142: }
                    143: 
                    144: /// @returns object of this class
1.28      paf       145: Value* VClass::create_new_value(Pool& apool, HashStringValue& afields) { 
                    146:        return new VObject(apool, *this, afields);
1.1       paf       147: }

E-mail: