Annotation of parser3/src/main/core.C, revision 1.17

1.17    ! paf         1: // TODO: 
        !             2: //   $RESULT
        !             3: //   ^menu[!unevaluated!]
1.15      paf         4: 
1.10      paf         5: enum Prefix {
                      6:        NO_PREFIX,
                      7:        ROOT_PREFIX,
                      8:        SELF_PREFIX
                      9: };
                     10: 
                     11: enum CHAR_TYPE {
                     12:        NO_TYPE=0, // these got skipped by String::skip_to
1.11      paf        13:        VAR_START_TYPE,
                     14:        METHOD_START_TYPE,
                     15:        STOP_TYPE,///=-1 // same as EOF type(-1), see String::skip_to
                     16:        DOT_TYPE,
                     17:        CONSTRUCTOR_BODY_START_TYPE,
                     18:        CONSTRUCTOR_BODY_FINISH_TYPE,
                     19:        BLOCK_START_TYPE,
                     20:        BLOCK_FINISH_TYPE,
1.17    ! paf        21:        PARAM_STOP_NORMAL_TYPE,
        !            22:        PARAM_STOP_SPECIAL_TYPE,
1.11      paf        23:        
                     24:        Z_TYPE
1.10      paf        25: };
                     26: 
1.11      paf        27: Char_types var_or_method_start;
                     28: Char_types var_or_method_start_or_constructor_stop;
                     29: Char_types var_or_method_start_or_block_stop;
1.17    ! paf        30: Char_types var_or_method_start_or_block_stop_or_param_stop_normal;
        !            31: Char_types var_or_method_start_or_block_stop_or_param_stop_special;
1.11      paf        32: Char_types common_names_breaks, var_names_breaks, method_names_breaks;
1.12      paf        33: String SELF;
1.15      paf        34: String RESULT;
1.10      paf        35: 
                     36: void prepare() {
1.11      paf        37:        var_or_method_start.set('$', VAR_START_TYPE);
                     38:        var_or_method_start.set('^', METHOD_START_TYPE);
                     39: 
                     40:        var_or_method_start_or_constructor_stop=var_or_method_start;
                     41:        var_or_method_start_or_constructor_stop.set(')', STOP_TYPE);
                     42: 
                     43:        var_or_method_start_or_block_stop=var_or_method_start;
                     44:        var_or_method_start_or_block_stop.set(']', STOP_TYPE);
                     45: 
1.17    ! paf        46:        var_or_method_start_or_block_stop_or_param_stop_normal=var_or_method_start_or_block_stop;
        !            47:        var_or_method_start_or_block_stop_or_param_stop_normal.set(';', PARAM_STOP_NORMAL_TYPE);
        !            48:        var_or_method_start_or_block_stop_or_param_stop_special=var_or_method_start_or_block_stop;
        !            49:        var_or_method_start_or_block_stop_or_param_stop_special.set('`', PARAM_STOP_SPECIAL_TYPE);
        !            50: 
1.11      paf        51:        common_names_breaks.set(0, ' ', STOP_TYPE);
                     52:        common_names_breaks.set('.', DOT_TYPE);
                     53:        common_names_breaks.set(')', STOP_TYPE); // var_or_method_start_or_constructor_stop
                     54:        common_names_breaks.set(']', STOP_TYPE); // var_or_method_start_or_block_stop
                     55: 
                     56:        var_names_breaks=common_names_breaks;
                     57:        var_names_breaks.set('(', CONSTRUCTOR_BODY_START_TYPE);
                     58: 
                     59:        method_names_breaks=common_names_breaks;
                     60:        method_names_breaks.set('[', BLOCK_START_TYPE);
1.12      paf        61: 
                     62:        SELF.APPEND("self", 0, 0);
1.15      paf        63:        RESULT.APPEND("result", 0, 0);
1.10      paf        64: }
                     65: 
1.12      paf        66: CHAR_TYPE process(method_self_n_params_n_locals& root, Value& self,
                     67:                                  arcontext& arcontext, WContext& awcontext, 
                     68:                                  String_iterator& iter, Char_types& breaks) {
1.10      paf        69:        while(!iter.eof()) {
                     70:                String_iterator start(iter);
                     71:                CHAR_TYPE type=iter.skip_to(breaks);
                     72:                awcontext.write(start, iter);
                     73: 
                     74:                switch(type) {
1.11      paf        75:                case VAR_START_TYPE: 
                     76:                        process_var(root, self, arcontext, awcontext, iter, breaks);
1.10      paf        77:                        break;
1.11      paf        78:                case METHOD_START_TYPE:
                     79:                        process_method(root, self, arcontext, awcontext, iter, breaks);
1.10      paf        80:                        break;
1.12      paf        81:                default:
                     82:                        return type;
1.10      paf        83:                }
                     84:        }
1.12      paf        85:        return -1;
1.1       paf        86: }
                     87: 
1.11      paf        88: void process_var(method_self_n_params_n_locals& root, Value& self,
                     89:                                 arcontext& arcontext, WContext& awcontext, 
                     90:                                 String_iterator& iter, Char_types& breaks) {
1.1       paf        91: 
                     92:        // $name.field.subfield -- read
                     93:        // $name.field.subfield(constructor code) -- construct
                     94:        // $name.field.subfield[usage code & if none existed autoconstructed as VHash] -- use OR auto-VHash construct
                     95:        
1.11      paf        96:        Prefix prefix;
1.1       paf        97:        Array/*<String&>*/ names(pool);  // what.they.refer.to left-to-right list
1.12      paf        98:        // the char type after long name
                     99:        CHAR_TYPE names_ended_before=get_names( 
1.11      paf       100:                iter, var_names_breaks,
1.14      paf       101:                &prefix, &names); // can return size()==0 when $self alone
1.1       paf       102: 
                    103:        bool read_mode=name_ended_before==' ';
1.6       paf       104:        Value *context=
                    105:                prefix?
1.8       paf       106:                        prefix==ROOT_PREFIX?root:self:
1.7       paf       107:                read_mode?arcontext:awcontext;
1.1       paf       108:        
                    109:        if(read_mode) {
1.3       paf       110:                // 'context' dive into dotted path
1.12      paf       111:                for(int i=0; i<names.size(); i++) {
1.1       paf       112:                        context=context->get_element(static_cast<Value *>(names.get[i]));
                    113:                        if(!context) // no such object field, nothing bad, just ignore that
                    114:                                return;
                    115:                }
1.7       paf       116:                awcontext.write(context);
1.1       paf       117:        } else { // write mode
                    118:                iter++; // skip '(' '['
                    119: 
                    120:                bool construct_mode=names_ended_before=='(';
                    121: 
1.4       paf       122:                // 'context' dive into dotted path, 
1.12      paf       123:                int steps=names.size();
1.4       paf       124:                // if constructing then "excluding last .name"
1.1       paf       125:                if(construct_mode)
1.6       paf       126:                        if(!steps--) // bad: "$self("; now we can safely do ".get[steps]" below
                    127:                                pool.exception().raise("self re-construction prohibited");
1.1       paf       128:                for(int i=0; i<steps; i++) {
                    129:                        String& name=static_cast<String&>(names.get[i]);
                    130:                        Value *next_current=context->get_element(name);
                    131:                        if(next_current)
                    132:                                next_current=context->put_element(name, new(pool) VHash(pool));
                    133:                        context=new_current;
                    134:                }
                    135: 
                    136:                if(construct_mode) {  
1.7       paf       137:                        // .name(construct-code), processing on arcontext in empty temp awcontext
                    138:                        // pure side effect, no awcontext.write here
1.3       paf       139:                        // last .name
1.15      paf       140:                        // prepare context
1.1       paf       141:                        String& name=static_cast<String&>(names.get[steps]);
                    142:                        WContext local_wcontext(pool /* empty */);
1.15      paf       143:                        // evaluate constructor-code in that context
1.16      paf       144:                        process(root, self, 
                    145:                                arcontext, local_wcontext, 
                    146:                                iter, var_or_method_start_or_constructor_stop);
1.15      paf       147:                        // store constructed value under 'name'
1.1       paf       148:                        context->put_element(name, local_wcontext.value());
1.15      paf       149:                } else { // =='['  .name[with-code]
                    150:                        // prepare context
1.1       paf       151:                        WContext local_context(pool, context);
1.15      paf       152:                        // evaluate with-code in that context
1.16      paf       153:                        process(root, self, 
                    154:                                local_context, local_context, 
                    155:                                iter, var_or_method_start_or_block_stop);
1.15      paf       156:                        // emit result
1.7       paf       157:                        awcontext.write(local_context);
1.1       paf       158:                }
                    159:                
                    160:                iter++; // skip ')' ']'
                    161:        }
                    162: }
                    163: 
1.11      paf       164: void process_method(method_self_n_params_n_locals& root, Value& self,
                    165:                                        arcontext& arcontext, WContext& awcontext, 
                    166:                                        String_iterator& iter, char char_to_stop_before) {
1.1       paf       167:        
                    168:        // ^name.field.subfield.method[..] -- plain call
                    169:        // ^name.field.subfield.method_ref[..] -- method ref call, when .get_method()!=0
1.8       paf       170:        // ^class:method[..]  -- no dotted path allowed before/after
                    171:        //  1: wcontext.object_class == 0?  -- constructor
                    172:        //  2: wcontext.object_class.has_parent('class')? -- dynamic call
                    173:        //  3: not -------------------------------------? -- static call
1.1       paf       174:        
1.11      paf       175:        Prefix prefix;
1.1       paf       176:        Array/*<String&>*/ names(pool);  // what.they.refer.to left-to-right list
1.12      paf       177:        // the char type after long name
                    178:        CHAR_TYPE names_ended_before=get_names(
1.11      paf       179:                iter, method_names_breaks,
1.14      paf       180:                &prefix, &names); // can return size()==0 when ^self alone
1.1       paf       181: 
1.6       paf       182:        Value *context=
                    183:                prefix?
1.8       paf       184:                        prefix==ROOT_PREFIX?root:self:
1.7       paf       185:                arcontext;
1.1       paf       186:        iter++; // skip '['
                    187: 
1.3       paf       188:        // 'context' dive into dotted path, excluding last .name
1.12      paf       189:        int steps=names.size()-1;
1.6       paf       190:        if(steps<0) // bad: "^self["; now we can safely do ".get[steps]" below
                    191:                pool.exception().raise("call: calling method named 'self'");
1.1       paf       192:        for(int i=0; i<steps; i++) {
                    193:                String& name=static_cast<String&>(names.get[i]);
1.6       paf       194:                context=context->get_element(name);
1.1       paf       195:                if(!context) // no such object field, sad story: can't call method of void
                    196:                        pool.exception().raise(name, "call: to void.method");
                    197:        }
                    198:        
1.3       paf       199:        // last .name
1.1       paf       200:        String& name=static_cast<String&>(names.get[steps]);
1.8       paf       201:        if(steps==0) { // the sole name on path, maybe ^class:method[ call
                    202:                String_iterator ni(name);
                    203:                if(ni.skip_to(':')) { // it is
                    204:                        ni++; // skip ':'
                    205:                        String method_name(pool); method_name.append(ni, 0);
                    206:                        name=method_name; // trim "class:" prefix from the name
                    207: 
                    208:                        String cn(pool);  cn.append(0, ni);
                    209:                        Class *right_class=classes.get(cn);
1.9       paf       210:                        if(!right_class) // bad: no such class
1.8       paf       211:                                pool.exception().raise(cn, "call: undefined class");
                    212:                        Class *left_class=awcontext.get_class();
                    213:                        if(left_class) {
                    214:                                if(left_class.has_parent(right_class)) // dynamic call
1.10      paf       215:                                        context=awcontext.value(); // it's 'self' instance
1.8       paf       216:                                else // static call
1.9       paf       217:                                        context=right_class; // 'self' := class, not instance
1.8       paf       218:                        } else { // constructor: $some(^class:method[..]) call
1.10      paf       219:                                context=new(pool) VClass(pool, right_class); // 'self' := new instance of 'class:'
1.8       paf       220:                                awcontext.write(context);
                    221:                        }
                    222:                }
                    223:        }
1.1       paf       224:        // first we're trying to locate method with that 'name'
                    225:        Method *method=context.get_method(name);
                    226:        if(!method) { // no such method: try to locate method ref field
                    227:                Value *value=context.get_element(name);
1.6       paf       228:                if(value) { // good: we have some element of that 'name'
                    229:                        Method_ref *method_ref=value->get_method_ref();
                    230:                        if(!method_ref) // bad: that field wasn't method_ref
                    231:                                pool.exception().raise(name, "call: this field is not a method reference");
1.11      paf       232:                        context=method_ref->self;
1.6       paf       233:                        method=method_ref->method;
                    234:                } else { // no element of that 'name', that must be operator then
1.11      paf       235:                        Operator *op=operators.get(name);
                    236:                        if(!op) // bad: that 'name' is neither method nor field nor operator
1.6       paf       237:                                pool.exception().raise(name, "call: neither method nor field nor operator");
1.11      paf       238:                        context=op->self;
                    239:                        method=op;
1.6       paf       240:                }
1.1       paf       241:        }
                    242: 
                    243: 
1.14      paf       244:        // evaluate param values
1.10      paf       245:        Array/*<Value&>*/ param_values(pool);
1.1       paf       246:        get_params(
1.6       paf       247:                iter,
1.9       paf       248:                arcontext,
1.1       paf       249:                &param_values);
                    250:        iter++; // skip ']'
                    251: 
1.14      paf       252:        // prepare contexts
1.12      paf       253:        Method_self_n_params_n_locals local_rcontext(pool, 
1.6       paf       254:                context,
1.7       paf       255:                method->param_names, param_values,
                    256:                method->local_names);
1.9       paf       257:        WContext local_wcontext(pool, context);
1.10      paf       258:        String_iterator local_iter(method->code);
1.15      paf       259:        // call method/operator in those contexts
1.6       paf       260:        process(
1.9       paf       261:                local_rcontext/* $:vars */, context /* $self.vars */,
1.6       paf       262:                local_rcontext, local_wcontext, 
1.16      paf       263:                local_iter, var_or_method_start);
1.15      paf       264:        // emit result
1.7       paf       265:        awcontext.write(local_wcontext);
1.10      paf       266: }
                    267: 
                    268: 
1.12      paf       269: CHAR_TYPE get_names(
1.11      paf       270:                String_iterator& iter, Char_types& breaks,
1.12      paf       271:                Prefix& prefix, Array& names) {
                    272:        // $name.subname white-space
                    273:        // $name.subname( $name.subname[
                    274:        // $name.subname) $name.subname]
                    275:        // $:name... $self...
                    276: 
1.13      paf       277:        if(iter.eof())
                    278:                return -1;
                    279: 
1.14      paf       280:        if(iter()==':') { // $:name ?
1.12      paf       281:                prefix=ROOT_PREFIX;
                    282:                iter++; // skip ':'
1.14      paf       283:        } else // $name
1.12      paf       284:                prefix=NO_PREFIX;
                    285: 
1.13      paf       286:        CHAR_TYPE result;
                    287:        while(true) {
1.14      paf       288:                // prepare context
1.12      paf       289:                WContext local_wcontext(pool /* empty */);
1.14      paf       290:                // execute code until separator, writing to that context
1.12      paf       291:                result=process(root, self,
                    292:                        arcontext, local_wcontext, 
                    293:                        iter, breaks);
1.14      paf       294:                // read resulting name
1.12      paf       295:                String *name=local_wcontext.get_string();
1.17    ! paf       296:                if(!name)
        !           297:                        pool.exception().raise("names: name string missing");
1.12      paf       298:                if(*name==SELF) // is it "self"?
                    299:                        if(prefix || names.size()) // already $: or $self.  or $name.
                    300:                                pool.exception().raise("names: 'self' not first on chain");
                    301:                        else // $self.
                    302:                                prefix=SELF_PREFIX;
                    303:                else // simple $name or .name, emiting
                    304:                        names+=name;
                    305: 
1.17    ! paf       306:                // stop if not '.', otherwise continue with next name on chain
        !           307:                if(result!=DOT_TYPE)
1.12      paf       308:                        break;
                    309:        }
                    310: 
1.14      paf       311:        // can only return size()==0 when $self alone
1.12      paf       312:        if(names.size()==0 && prefix!=SELF_PREFIX)
                    313:                pool.exception().raise("names: empty chain");
1.10      paf       314: 
1.12      paf       315:        return result;
1.10      paf       316: }
                    317: 
                    318: void get_params(
                    319:                String_iterator& iter,
                    320:                Value *arcontext,
                    321:                Array/*<Values&>*/& param_values) {
1.17    ! paf       322:        // arg1;arg2;...]
        !           323:        // ...`argX.1;argX.2`...]
        !           324:        
        !           325:        while(true) {
        !           326:                // prepare context
        !           327:                WContext local_wcontext(pool /* empty */);
        !           328:                bool back_stick_at_start=iter()=='`'; // parameter starts with '`' ?
        !           329:                if(back_stick_at_start)
        !           330:                        iter++; // skip '`'
        !           331:                // evaluate param body in that context
        !           332:                CHAR_TYPE type=process(root, self, // parameter must end on ';' or '`' depending on start
        !           333:                        arcontext, local_wcontext, 
        !           334:                        iter, back_stick_at_start?var_or_method_start_or_block_stop_or_param_stop_special:var_or_method_start_or_block_stop_or_param_stop_normal
        !           335:                        );
        !           336:                switch(type) {
        !           337:                case PARAM_STOP_NORMAL_TYPE:
        !           338:                        iter++; // skip ';'
        !           339:                        break;
        !           340:                case PARAM_STOP_SPECIAL_TYPE:
        !           341:                        iter++; // skip '`'
        !           342:                        char c=iter();
        !           343:                        if(c==';')
        !           344:                                iter++; // skip ';'
        !           345:                        else if(c!=']')
        !           346:                                pool.exception().raise("params: closing backstick doesn't adjoin semicolon or closing bracket");
        !           347:                        break;
        !           348:                default:
        !           349:                        break; // ']'  or eof: ^method[params;...;eof which would'nt process honestly
        !           350:                }
        !           351: 
        !           352:                // emit resulting param's value
        !           353:                param_values+=local_wcontext.value();
        !           354: 
        !           355:                // stop on ] or eof, otherwise continue with next param
        !           356:                if(type==STOP_TYPE || type<0)
        !           357:                        break;
        !           358:        }
1.10      paf       359: }

E-mail: