Annotation of parser3/src/types/pa_vmethod_frame.h, revision 1.64

1.3       paf         1: /** @file
1.5       paf         2:        Parser: @b method_frame write context
1.3       paf         3: 
1.58      paf         4:        Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com)
1.22      paf         5:        Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.1       paf         6: */
                      7: 
                      8: #ifndef PA_VMETHOD_FRAME_H
                      9: #define PA_VMETHOD_FRAME_H
1.28      paf        10: 
1.64    ! misha      11: static const char * const IDENT_VMETHOD_FRAME_H="$Date: 2008-05-30 12:24:13 $";
1.1       paf        12: 
                     13: #include "pa_wcontext.h"
1.12      parser     14: #include "pa_vvoid.h"
1.1       paf        15: #include "pa_vjunction.h"
                     16: 
1.40      paf        17: // defines
                     18: 
1.42      paf        19: #define CALLER_ELEMENT_NAME "caller"
                     20: #define SELF_ELEMENT_NAME "self"
1.50      paf        21: #define RESULT_VAR_NAME "result"
1.63      misha      22: #define ALL_VARS_LOCAL_NAME "locals"
1.40      paf        23: 
1.46      paf        24: // forwards
                     25: 
                     26: class Request;
                     27: 
                     28: /**
                     29:        @b method parameters passed in this array.
                     30:        contains handy typecast ad junction/not junction ensurers
                     31: 
                     32: */
                     33: class MethodParams: public Array<Value*> {
                     34: public:
                     35:        Value& operator[] (size_t index) { return *get(index); }
                     36: 
                     37:        Value& last() { return *get(count()-1); }
                     38: 
                     39:        /// handy is-value-a-junction ensurer
                     40:        Value& as_junction(int index, const char* msg) { 
1.56      paf        41:                Value* value=get(index);
                     42:                return as_junction(value, msg, index); 
                     43:        }
                     44:        /// handy is-value-a-junction ensurer
                     45:        Value& as_junction(Value* value, const char* msg, int index) { 
                     46:                return get_as(value, true, msg, index); 
1.46      paf        47:        }
                     48:        /// handy value-is-not-a-junction ensurer
                     49:        Value& as_no_junction(int index, const char* msg) { 
1.56      paf        50:                Value* value=get(index);
                     51:                return as_no_junction(value, msg, index); 
                     52:        }
                     53:        /// handy value-is-not-a-junction ensurer
                     54:        Value& as_no_junction(Value* value, const char* msg, int index) { 
                     55:                return get_as(value, false, msg, index); 
1.46      paf        56:        }
1.62      misha      57:        /// handy is-value-a-junction ensurer or can be auto-processed
                     58:        Value& as_expression(int index, const char* msg) { 
                     59:                Value* value=get(index);
                     60:                if(value->is_evaluated_expr()){
                     61:                        return *value;
                     62:                } else {
                     63:                        return get_as(value, true, msg, index);
                     64:                }
                     65:        }
1.46      paf        66:        /// handy expression auto-processing to double
                     67:        double as_double(int index, const char* msg, Request& r) { 
1.56      paf        68:                Value* value=get(index);
1.60      paf        69:                if(!value->is_evaluated_expr())
1.57      paf        70:                        value=&get_processed(value, msg, index, r);
                     71:                return value->as_double(); 
1.46      paf        72:        }
                     73:        /// handy expression auto-processing to int
                     74:        int as_int(int index, const char* msg, Request& r) { 
1.56      paf        75:                Value* value=get(index);
1.60      paf        76:                if(!value->is_evaluated_expr())
1.57      paf        77:                        value=&get_processed(value, msg, index, r);
                     78:                return value->as_int(); 
1.46      paf        79:        }
                     80:        /// handy expression auto-processing to bool
                     81:        bool as_bool(int index, const char* msg, Request& r) { 
1.56      paf        82:                Value* value=get(index);
1.60      paf        83:                if(!value->is_evaluated_expr())
1.59      paf        84:                        value=&get_processed(value, msg, index, r);
                     85:                return value->as_bool(); 
1.46      paf        86:        }
                     87:        /// handy string ensurer
                     88:        const String& as_string(int index, const char* msg) { 
                     89:                return as_no_junction(index, msg).as_string();
                     90:        }
                     91: 
                     92: private:
                     93: 
                     94:        /// handy value-is/not-a-junction ensurer
1.56      paf        95:        Value& get_as(Value* value, bool as_junction, const char* msg, int index) { 
                     96:                if((value->get_junction()!=0) ^ as_junction)
1.61      misha      97:                        throw Exception(PARSER_RUNTIME,
1.46      paf        98:                                0,
                     99:                                "%s (parameter #%d)", msg, 1+index);
                    100: 
1.56      paf       101:                return *value;
1.46      paf       102:        }
                    103: 
1.56      paf       104:        Value& get_processed(Value* value, const char* msg, int index, Request& r);
1.46      paf       105: 
                    106: };
                    107: 
1.4       paf       108: /**    Method frame write context
                    109:        accepts values written by method code
                    110:        also handles method parameters and local variables
1.3       paf       111: */
1.46      paf       112: class VMethodFrame: public WContext {
1.63      misha     113: protected:
1.46      paf       114:        VMethodFrame *fcaller;
                    115: 
                    116:        size_t store_param_index;
                    117:        HashStringValue* my;/*OR*/MethodParams* fnumbered_params;
                    118:        Value* fself;
                    119: 
                    120:        Value* fresult_initial_void;
1.64    ! misha     121:        typedef const VJunction* (VMethodFrame::*put_element_t)(const String& aname, Value* avalue);
        !           122:        put_element_t put_element_impl;
1.46      paf       123: 
1.1       paf       124: public: // Value
                    125: 
1.46      paf       126:        override const char* type() const { return "method_frame"; }
1.20      paf       127: 
                    128:        /// VMethodFrame: $result | parent get_string(=accumulated fstring)
1.46      paf       129:        override const String* get_string() { 
1.20      paf       130:                // check the $result value
1.46      paf       131:                Value* result=get_result_variable();
1.20      paf       132:                // if we have one, return it's string value, else return as usual: accumulated fstring or fvalue
                    133:                return result ? result->get_string() : WContext::get_string();
                    134:        }
                    135:        
1.40      paf       136:        /// VMethodFrame: my or self_transparent or $caller
1.51      paf       137:        override Value* get_element(const String& aname, Value& /*aself*/, bool looking_up) { 
1.46      paf       138:                if(my) {
                    139:                        if(Value* result=my->get(aname))
1.1       paf       140:                                return result;
                    141:                }
1.51      paf       142:                if(Value* result=self().get_element(aname, self(), looking_up))
1.40      paf       143:                        return result;
                    144: 
1.42      paf       145:                if(aname==CALLER_ELEMENT_NAME)
1.40      paf       146:                        return caller();
1.42      paf       147: 
                    148:                if(aname==SELF_ELEMENT_NAME)
                    149:                        return &self();
1.40      paf       150: 
                    151:                return 0;
1.1       paf       152:        }
                    153: 
1.4       paf       154:        /// VMethodFrame: self_transparent
1.46      paf       155:        override VStateless_class* get_class() { return self().get_class(); }
1.44      paf       156: 
                    157:        /// VMethodFrame: self_transparent
1.46      paf       158:        override Value* base() { return self().base(); }
1.1       paf       159: 
1.64    ! misha     160:        /// VMethodFrame: my or self_transparent
        !           161:        override const VJunction* put_element(Value& /*aself*/, const String& aname, Value* avalue, bool /*areplace*/) {
        !           162:                return (this->*put_element_impl)(aname, avalue);
        !           163:        }
        !           164: 
        !           165: private:
        !           166: 
        !           167:        const VJunction* put_element_local(const String& aname, Value* avalue){
        !           168:                set_my_variable(aname, *avalue);
        !           169:                return PUT_ELEMENT_REPLACED_ELEMENT;
        !           170:        }
        !           171: 
        !           172:        const VJunction* put_element_global(const String& aname, Value* avalue){
        !           173:                if(my && my->put_replaced(aname, avalue))
        !           174:                        return PUT_ELEMENT_REPLACED_ELEMENT;
        !           175:                return self().put_element(self(), aname, avalue, false/*=always, areplace*/);
        !           176:        }
        !           177: 
1.30      paf       178: public: // WContext
1.1       paf       179: 
1.46      paf       180:        override StringOrValue result() {
1.1       paf       181:                // check the $result value
1.46      paf       182:                Value* result_value=get_result_variable();
1.1       paf       183:                // if we have one, return it, else return as usual: accumulated fstring or fvalue
1.52      paf       184:                return result_value ? StringOrValue(*result_value) : WContext::result();
1.1       paf       185:        }
                    186: 
1.46      paf       187:        void write(Value& avalue, String::Language alang) {
                    188:                WContext::write(avalue, alang);
                    189:        }
                    190: 
1.1       paf       191: public: // usage
                    192: 
1.46      paf       193:        VMethodFrame(
1.40      paf       194:                const Junction& ajunction/*info: always method-junction*/,
1.46      paf       195:                VMethodFrame *acaller);
1.1       paf       196: 
1.40      paf       197:        VMethodFrame *caller() { return fcaller; }
1.25      paf       198: 
1.38      paf       199:        void set_self(Value& aself) { fself=&aself; }
1.41      paf       200:        /// we sure that someone already set our self with VMethodFrame::set_self(Value&)
                    201:        Value& self() { return *fself; }
1.1       paf       202: 
1.27      paf       203:        bool can_store_param() {
                    204:                const Method& method=*junction.method;
1.46      paf       205:                return method.params_names && store_param_index<method.params_names->count();
1.27      paf       206:        }
1.46      paf       207:        void store_param(Value& value) {
1.1       paf       208:                const Method& method=*junction.method;
1.46      paf       209:                size_t max_params=
1.1       paf       210:                        method.max_numbered_params_count?method.max_numbered_params_count:
1.46      paf       211:                        method.params_names?method.params_names->count():
1.1       paf       212:                        0;
                    213:                if(store_param_index==max_params)
1.61      misha     214:                        throw Exception(PARSER_RUNTIME,
1.46      paf       215:                                0, //&name(),
1.7       paf       216:                                "method of %s (%s) accepts maximum %d parameter(s)", 
1.38      paf       217:                                        junction.self.get_class()->name_cstr(),
                    218:                                        junction.self.type(),
1.1       paf       219:                                        max_params);
                    220:                
1.46      paf       221:                if(fnumbered_params) { // are this method params numbered?
                    222:                        *fnumbered_params+=&value;
1.1       paf       223:                } else { // named param
1.25      paf       224:                        // speedup: not checking for clash with "result" fname
1.46      paf       225:                        const String& fname=*(*method.params_names)[store_param_index];
1.25      paf       226:                        set_my_variable(fname, value);
1.1       paf       227:                }
                    228:                store_param_index++;
                    229:        }
                    230:        void fill_unspecified_params() {
                    231:                const Method &method=*junction.method;
1.46      paf       232:                if(method.params_names) { // there are any named parameters might need filling?
                    233:                        size_t param_count=method.params_names->count();
                    234:                        for(; store_param_index<param_count; store_param_index++) {
                    235:                                const String& fname=*(*method.params_names)[store_param_index];
                    236:                                my->put(fname, new VVoid);
1.1       paf       237:                        }
1.46      paf       238:                }
1.1       paf       239:        }
                    240: 
1.46      paf       241:        MethodParams* numbered_params() { return fnumbered_params; }
1.18      paf       242: 
1.63      misha     243: protected:
1.18      paf       244: 
1.46      paf       245:        void set_my_variable(const String& fname, Value& value) {
                    246:                my->put(fname, &value); // remember param
1.25      paf       247:        }
                    248: 
1.46      paf       249:        Value* get_result_variable();
1.1       paf       250: 
                    251: public:
                    252:        
                    253:        const Junction& junction;
                    254: 
1.41      paf       255: };
                    256: 
                    257: ///    Auto-object used for temporary changing VMethod_frame::fself.
                    258: class Temp_method_frame_self {
                    259:        VMethodFrame& fmethod_frame;
1.46      paf       260:        Value* saved_self;
1.41      paf       261: public:
                    262:        Temp_method_frame_self(VMethodFrame& amethod_frame, Value& aself) :
                    263:                fmethod_frame(amethod_frame),
1.46      paf       264:                saved_self(&amethod_frame.self()) {
1.41      paf       265:                fmethod_frame.set_self(aself);
                    266:        }
                    267:        ~Temp_method_frame_self() {
1.46      paf       268:                fmethod_frame.set_self(*saved_self);
1.41      paf       269:        }
1.1       paf       270: };
                    271: 
                    272: #endif

E-mail: