--- parser3/src/main/Attic/core.C 2001/02/12 11:34:12 1.2 +++ parser3/src/main/Attic/core.C 2001/02/14 15:25:43 1.14 @@ -1,48 +1,115 @@ -void process(Pool& pool, - Value& self, - RContext& rcontext, WContext& wcontext, - StringIterator& code, char char_to_stop_before) { - - // $ on code? - process_dollar(pool, rcontext, wcontext, code, char_to_stop_before); - - // ^ on code? - process_bird(pool, rcontext, wcontext, code, char_to_stop_before); -} - -void process_dollar(Pool& pool, - Value& THIS, - RContext& rcontext, WContext& wcontext, - StringIterator& iter, char char_to_stop_before) { +enum Prefix { + NO_PREFIX, + ROOT_PREFIX, + SELF_PREFIX +}; + +enum CHAR_TYPE { + NO_TYPE=0, // these got skipped by String::skip_to + VAR_START_TYPE, + METHOD_START_TYPE, + STOP_TYPE,///=-1 // same as EOF type(-1), see String::skip_to + DOT_TYPE, + CONSTRUCTOR_BODY_START_TYPE, + CONSTRUCTOR_BODY_FINISH_TYPE, + BLOCK_START_TYPE, + BLOCK_FINISH_TYPE, + + Z_TYPE +}; + +Char_types var_or_method_start; +Char_types var_or_method_start_or_constructor_stop; +Char_types var_or_method_start_or_block_stop; +Char_types common_names_breaks, var_names_breaks, method_names_breaks; +String SELF; + +void prepare() { + var_or_method_start.set('$', VAR_START_TYPE); + var_or_method_start.set('^', METHOD_START_TYPE); + + var_or_method_start_or_constructor_stop=var_or_method_start; + var_or_method_start_or_constructor_stop.set(')', STOP_TYPE); + + var_or_method_start_or_block_stop=var_or_method_start; + var_or_method_start_or_block_stop.set(']', STOP_TYPE); + + common_names_breaks.set(0, ' ', STOP_TYPE); + common_names_breaks.set('.', DOT_TYPE); + common_names_breaks.set(')', STOP_TYPE); // var_or_method_start_or_constructor_stop + common_names_breaks.set(']', STOP_TYPE); // var_or_method_start_or_block_stop + + var_names_breaks=common_names_breaks; + var_names_breaks.set('(', CONSTRUCTOR_BODY_START_TYPE); + + method_names_breaks=common_names_breaks; + method_names_breaks.set('[', BLOCK_START_TYPE); + + SELF.APPEND("self", 0, 0); +} + +CHAR_TYPE process(method_self_n_params_n_locals& root, Value& self, + arcontext& arcontext, WContext& awcontext, + String_iterator& iter, Char_types& breaks) { + while(!iter.eof()) { + String_iterator start(iter); + CHAR_TYPE type=iter.skip_to(breaks); + awcontext.write(start, iter); + + switch(type) { + case VAR_START_TYPE: + process_var(root, self, arcontext, awcontext, iter, breaks); + break; + case METHOD_START_TYPE: + process_method(root, self, arcontext, awcontext, iter, breaks); + break; + default: + return type; + } + } + return -1; +} + +void process_var(method_self_n_params_n_locals& root, Value& self, + arcontext& arcontext, WContext& awcontext, + String_iterator& iter, Char_types& breaks) { // $name.field.subfield -- read // $name.field.subfield(constructor code) -- construct // $name.field.subfield[usage code & if none existed autoconstructed as VHash] -- use OR auto-VHash construct + Prefix prefix; Array/**/ names(pool); // what.they.refer.to left-to-right list - char names_ended_before; // the char after long name - get_names( - iter, " ([", - &names, &names_ended_before); // must return count()>0 + // the char type after long name + CHAR_TYPE names_ended_before=get_names( + iter, var_names_breaks, + &prefix, &names); // can return size()==0 when $self alone bool read_mode=name_ended_before==' '; - Value *context=read_mode?rcontext:wcontext; + Value *context= + prefix? + prefix==ROOT_PREFIX?root:self: + read_mode?arcontext:awcontext; if(read_mode) { - for(int i=0; iget_element(static_cast(names.get[i])); if(!context) // no such object field, nothing bad, just ignore that return; } - wcontext.write(context); + awcontext.write(context); } else { // write mode iter++; // skip '(' '[' bool construct_mode=names_ended_before=='('; - int steps=names.count(); + // 'context' dive into dotted path, + int steps=names.size(); + // if constructing then "excluding last .name" if(construct_mode) - steps--; + if(!steps--) // bad: "$self("; now we can safely do ".get[steps]" below + pool.exception().raise("self re-construction prohibited"); for(int i=0; i(names.get[i]); Value *next_current=context->get_element(name); @@ -52,71 +119,181 @@ void process_dollar(Pool& pool, } if(construct_mode) { - // pure side effect, no wcontext.write here + // .name(construct-code), processing on arcontext in empty temp awcontext + // pure side effect, no awcontext.write here + // last .name String& name=static_cast(names.get[steps]); WContext local_wcontext(pool /* empty */); - process(pool, rcontext, local_wcontext, iter, ')'); + process(root, self, arcontext, local_wcontext, iter, ')'); context->put_element(name, local_wcontext.value()); } else { // =='[' + // .name[with-code], processing on 'context' WContext local_context(pool, context); - process(pool, local_context, local_context, iter, ']'); - wcontext.write(local_context); + process(root, self, local_context, local_context, iter, ']'); + awcontext.write(local_context); } iter++; // skip ')' ']' } } -void process_bird(Pool& pool, - Value& self, - RContext& rcontext, WContext& wcontext, - StringIterator& iter, char char_to_stop_before) { +void process_method(method_self_n_params_n_locals& root, Value& self, + arcontext& arcontext, WContext& awcontext, + String_iterator& iter, char char_to_stop_before) { // ^name.field.subfield.method[..] -- plain call // ^name.field.subfield.method_ref[..] -- method ref call, when .get_method()!=0 + // ^class:method[..] -- no dotted path allowed before/after + // 1: wcontext.object_class == 0? -- constructor + // 2: wcontext.object_class.has_parent('class')? -- dynamic call + // 3: not -------------------------------------? -- static call + Prefix prefix; Array/**/ names(pool); // what.they.refer.to left-to-right list - char names_ended_before; // the char after long name - get_names( - iter, "[", - &names, &names_ended_before); // must return count()>0 - - Value *context=rcontext; + // the char type after long name + CHAR_TYPE names_ended_before=get_names( + iter, method_names_breaks, + &prefix, &names); // can return size()==0 when ^self alone + + Value *context= + prefix? + prefix==ROOT_PREFIX?root:self: + arcontext; iter++; // skip '[' - Value *local_self=context; - int steps=names.count()-1; + // 'context' dive into dotted path, excluding last .name + int steps=names.size()-1; + if(steps<0) // bad: "^self["; now we can safely do ".get[steps]" below + pool.exception().raise("call: calling method named 'self'"); for(int i=0; i(names.get[i]); - context=(local_self=context)->get_element(name); + context=context->get_element(name); if(!context) // no such object field, sad story: can't call method of void pool.exception().raise(name, "call: to void.method"); } + // last .name String& name=static_cast(names.get[steps]); + if(steps==0) { // the sole name on path, maybe ^class:method[ call + String_iterator ni(name); + if(ni.skip_to(':')) { // it is + ni++; // skip ':' + String method_name(pool); method_name.append(ni, 0); + name=method_name; // trim "class:" prefix from the name + + String cn(pool); cn.append(0, ni); + Class *right_class=classes.get(cn); + if(!right_class) // bad: no such class + pool.exception().raise(cn, "call: undefined class"); + Class *left_class=awcontext.get_class(); + if(left_class) { + if(left_class.has_parent(right_class)) // dynamic call + context=awcontext.value(); // it's 'self' instance + else // static call + context=right_class; // 'self' := class, not instance + } else { // constructor: $some(^class:method[..]) call + context=new(pool) VClass(pool, right_class); // 'self' := new instance of 'class:' + awcontext.write(context); + } + } + } // first we're trying to locate method with that 'name' Method *method=context.get_method(name); if(!method) { // no such method: try to locate method ref field Value *value=context.get_element(name); - if(!value) // failed: no element of that 'name' - pool.exception().raise(name, "call: no method field found"); - method=value->get_method(); - if(!method) // failed: that field wasn't method_ref - pool.exception().raise(name, "call: this field is not a method reference"); - local_self=value->get_self(); + if(value) { // good: we have some element of that 'name' + Method_ref *method_ref=value->get_method_ref(); + if(!method_ref) // bad: that field wasn't method_ref + pool.exception().raise(name, "call: this field is not a method reference"); + context=method_ref->self; + method=method_ref->method; + } else { // no element of that 'name', that must be operator then + Operator *op=operators.get(name); + if(!op) // bad: that 'name' is neither method nor field nor operator + pool.exception().raise(name, "call: neither method nor field nor operator"); + context=op->self; + method=op; + } } - Array/**/ param_values(pool); + // evaluate param values + Array/**/ param_values(pool); get_params( - iter, "]", + iter, + arcontext, ¶m_values); iter++; // skip ']' - Method_self_n_params local_rcontext(pool, - local_self, - method->param_names, param_values); - WContext local_wcontext(pool /* empty */); - process(pool, local_rcontext, local_wcontext, iter, ']'); - wcontext.write(local_wcontext); -} \ No newline at end of file + // prepare contexts + Method_self_n_params_n_locals local_rcontext(pool, + context, + method->param_names, param_values, + method->local_names); + WContext local_wcontext(pool, context); + String_iterator local_iter(method->code); + // call method/operator + process( + local_rcontext/* $:vars */, context /* $self.vars */, + local_rcontext, local_wcontext, + local_iter, 0); + awcontext.write(local_wcontext); +} + + +enum Prefix { + NO_PREFIX, + ROOT_PREFIX, + SELF_PREFIX +}; +CHAR_TYPE get_names( + String_iterator& iter, Char_types& breaks, + Prefix& prefix, Array& names) { + // $name.subname white-space + // $name.subname( $name.subname[ + // $name.subname) $name.subname] + // $:name... $self... + + if(iter.eof()) + return -1; + + if(iter()==':') { // $:name ? + prefix=ROOT_PREFIX; + iter++; // skip ':' + } else // $name + prefix=NO_PREFIX; + + CHAR_TYPE result; + while(true) { + // prepare context + WContext local_wcontext(pool /* empty */); + // execute code until separator, writing to that context + result=process(root, self, + arcontext, local_wcontext, + iter, breaks); + // read resulting name + String *name=local_wcontext.get_string(); + if(*name==SELF) // is it "self"? + if(prefix || names.size()) // already $: or $self. or $name. + pool.exception().raise("names: 'self' not first on chain"); + else // $self. + prefix=SELF_PREFIX; + else // simple $name or .name, emiting + names+=name; + + if(result!=DOT_TYPE) // not "name." ? + break; + } + + // can only return size()==0 when $self alone + if(names.size()==0 && prefix!=SELF_PREFIX) + pool.exception().raise("names: empty chain"); + + return result; +} + +void get_params( + String_iterator& iter, + Value *arcontext, + Array/**/& param_values) { +}