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

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

E-mail: