Diff for /parser3/src/main/Attic/core.C between versions 1.17 and 1.66

version 1.17, 2001/02/14 16:08:20 version 1.66, 2001/03/13 17:54:13
Line 1 Line 1
 // TODO:   /*
 //   $RESULT          Parser
 //   ^menu[!unevaluated!]          Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
           Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
 enum Prefix {  
         NO_PREFIX,          $Id$
         ROOT_PREFIX,  */
         SELF_PREFIX  
 };  #include "core.h"
   #include "_string.h"
 enum CHAR_TYPE {  #include "_double.h"
         NO_TYPE=0, // these got skipped by String::skip_to  #include "_int.h"
         VAR_START_TYPE,  #include "_table.h"
         METHOD_START_TYPE,  #include "_form.h"
         STOP_TYPE,///=-1 // same as EOF type(-1), see String::skip_to  #include "_env.h"
         DOT_TYPE,  
         CONSTRUCTOR_BODY_START_TYPE,  #define NEW_STRING(name, value)  name=new(pool) String(pool); name->APPEND_CONST(value)
         CONSTRUCTOR_BODY_FINISH_TYPE,  #define LOCAL_STRING(name, value)  String name(pool); name.APPEND_CONST(value)
         BLOCK_START_TYPE,  
         BLOCK_FINISH_TYPE,  String *unnamed_name;
         PARAM_STOP_NORMAL_TYPE,  String *empty_string;
         PARAM_STOP_SPECIAL_TYPE,  
           String *auto_method_name;
         Z_TYPE  String *main_method_name;
 };  
   String *root_class_name;
 Char_types var_or_method_start;  String *main_class_name;
 Char_types var_or_method_start_or_constructor_stop;  String *env_class_name;
 Char_types var_or_method_start_or_block_stop;  String *table_class_name;
 Char_types var_or_method_start_or_block_stop_or_param_stop_normal;  String *form_class_name;
 Char_types var_or_method_start_or_block_stop_or_param_stop_special;  
 Char_types common_names_breaks, var_names_breaks, method_names_breaks;  Hash *untaint_lang_name2enum;
 String SELF;  
 String RESULT;  
   void core(Pool& pool) {
 void prepare() {          // names
         var_or_method_start.set('$', VAR_START_TYPE);          NEW_STRING(unnamed_name, UNNAMED_NAME);
         var_or_method_start.set('^', METHOD_START_TYPE);          empty_string=new(pool) String(pool); 
   
         var_or_method_start_or_constructor_stop=var_or_method_start;          NEW_STRING(auto_method_name, AUTO_METHOD_NAME);
         var_or_method_start_or_constructor_stop.set(')', STOP_TYPE);          NEW_STRING(main_method_name, MAIN_METHOD_NAME);
   
         var_or_method_start_or_block_stop=var_or_method_start;          NEW_STRING(root_class_name, ROOT_CLASS_NAME);
         var_or_method_start_or_block_stop.set(']', STOP_TYPE);          NEW_STRING(main_class_name, MAIN_CLASS_NAME);
           NEW_STRING(table_class_name, TABLE_CLASS_NAME);
         var_or_method_start_or_block_stop_or_param_stop_normal=var_or_method_start_or_block_stop;          NEW_STRING(env_class_name, ENV_CLASS_NAME);     
         var_or_method_start_or_block_stop_or_param_stop_normal.set(';', PARAM_STOP_NORMAL_TYPE);          NEW_STRING(form_class_name, FORM_CLASS_NAME);   
         var_or_method_start_or_block_stop_or_param_stop_special=var_or_method_start_or_block_stop;  
         var_or_method_start_or_block_stop_or_param_stop_special.set('`', PARAM_STOP_SPECIAL_TYPE);          // hashes
           untaint_lang_name2enum=new(pool) Hash(pool);
         common_names_breaks.set(0, ' ', STOP_TYPE);          LOCAL_STRING(as_is, "as-is");  
         common_names_breaks.set('.', DOT_TYPE);          untaint_lang_name2enum->put(as_is, (int)String::Untaint_lang::AS_IS);
         common_names_breaks.set(')', STOP_TYPE); // var_or_method_start_or_constructor_stop          LOCAL_STRING(table, "table");
         common_names_breaks.set(']', STOP_TYPE); // var_or_method_start_or_block_stop          untaint_lang_name2enum->put(table, (int)String::Untaint_lang::TABLE);
           LOCAL_STRING(sql, "sql");
         var_names_breaks=common_names_breaks;          untaint_lang_name2enum->put(sql, (int)String::Untaint_lang::SQL);
         var_names_breaks.set('(', CONSTRUCTOR_BODY_START_TYPE);          LOCAL_STRING(js, "js");
           untaint_lang_name2enum->put(js, (int)String::Untaint_lang::JS);
         method_names_breaks=common_names_breaks;          LOCAL_STRING(html, "html");
         method_names_breaks.set('[', BLOCK_START_TYPE);          untaint_lang_name2enum->put(html, (int)String::Untaint_lang::HTML);
           LOCAL_STRING(html_typo, "html-typo");
         SELF.APPEND("self", 0, 0);          untaint_lang_name2enum->put(html_typo, (int)String::Untaint_lang::HTML_TYPO);
         RESULT.APPEND("result", 0, 0);  
 }          // read-only stateless classes
           initialize_string_class(pool, *(string_class=new(pool) VStateless_class(pool)));  string_class->freeze();
 CHAR_TYPE process(method_self_n_params_n_locals& root, Value& self,          initialize_double_class(pool, *(double_class=new(pool) VStateless_class(pool)));  double_class->freeze();
                                   arcontext& arcontext, WContext& awcontext,           initialize_int_class(pool, *(int_class=new(pool) VStateless_class(pool)));  int_class->freeze();
                                   String_iterator& iter, Char_types& breaks) {          initialize_table_class(pool, *(table_class=new(pool) VStateless_class(pool)));  table_class->freeze();
         while(!iter.eof()) {  
                 String_iterator start(iter);          // read-only stateless base classes
                 CHAR_TYPE type=iter.skip_to(breaks);          initialize_env_base_class(pool, *(env_base_class=new(pool) VStateless_class(pool)));  env_base_class->freeze();
                 awcontext.write(start, iter);          initialize_form_base_class(pool, *(form_base_class=new(pool) VStateless_class(pool)));  form_base_class->freeze();
   
                 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/*<String&>*/ names(pool);  // what.they.refer.to left-to-right list  
         // 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=  
                 prefix?  
                         prefix==ROOT_PREFIX?root:self:  
                 read_mode?arcontext:awcontext;  
           
         if(read_mode) {  
                 // 'context' dive into dotted path  
                 for(int i=0; i<names.size(); i++) {  
                         context=context->get_element(static_cast<Value *>(names.get[i]));  
                         if(!context) // no such object field, nothing bad, just ignore that  
                                 return;  
                 }  
                 awcontext.write(context);  
         } else { // write mode  
                 iter++; // skip '(' '['  
   
                 bool construct_mode=names_ended_before=='(';  
   
                 // 'context' dive into dotted path,   
                 int steps=names.size();  
                 // if constructing then "excluding last .name"  
                 if(construct_mode)  
                         if(!steps--) // bad: "$self("; now we can safely do ".get[steps]" below  
                                 pool.exception().raise("self re-construction prohibited");  
                 for(int i=0; i<steps; i++) {  
                         String& name=static_cast<String&>(names.get[i]);  
                         Value *next_current=context->get_element(name);  
                         if(next_current)  
                                 next_current=context->put_element(name, new(pool) VHash(pool));  
                         context=new_current;  
                 }  
   
                 if(construct_mode) {    
                         // .name(construct-code), processing on arcontext in empty temp awcontext  
                         // pure side effect, no awcontext.write here  
                         // last .name  
                         // prepare context  
                         String& name=static_cast<String&>(names.get[steps]);  
                         WContext local_wcontext(pool /* empty */);  
                         // evaluate constructor-code in that context  
                         process(root, self,   
                                 arcontext, local_wcontext,   
                                 iter, var_or_method_start_or_constructor_stop);  
                         // store constructed value under 'name'  
                         context->put_element(name, local_wcontext.value());  
                 } else { // =='['  .name[with-code]  
                         // prepare context  
                         WContext local_context(pool, context);  
                         // evaluate with-code in that context  
                         process(root, self,   
                                 local_context, local_context,   
                                 iter, var_or_method_start_or_block_stop);  
                         // emit result  
                         awcontext.write(local_context);  
                 }  
                   
                 iter++; // skip ')' ']'  
         }  
 }  
   
 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/*<String&>*/ names(pool);  // what.they.refer.to left-to-right list  
         // 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 '['  
   
         // '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<steps; i++) {  
                 String& name=static_cast<String&>(names.get[i]);  
                 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<String&>(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) { // 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;  
                 }  
         }  
   
   
         // evaluate param values  
         Array/*<Value&>*/ param_values(pool);  
         get_params(  
                 iter,  
                 arcontext,  
                 &param_values);  
         iter++; // skip ']'  
   
         // 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 in those contexts  
         process(  
                 local_rcontext/* $:vars */, context /* $self.vars */,  
                 local_rcontext, local_wcontext,   
                 local_iter, var_or_method_start);  
         // emit result  
         awcontext.write(local_wcontext);  
 }  
   
   
 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)  
                         pool.exception().raise("names: name string missing");  
                 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;  
   
                 // stop if not '.', otherwise continue with next name on chain  
                 if(result!=DOT_TYPE)  
                         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/*<Values&>*/& param_values) {  
         // arg1;arg2;...]  
         // ...`argX.1;argX.2`...]  
           
         while(true) {  
                 // prepare context  
                 WContext local_wcontext(pool /* empty */);  
                 bool back_stick_at_start=iter()=='`'; // parameter starts with '`' ?  
                 if(back_stick_at_start)  
                         iter++; // skip '`'  
                 // evaluate param body in that context  
                 CHAR_TYPE type=process(root, self, // parameter must end on ';' or '`' depending on start  
                         arcontext, local_wcontext,   
                         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  
                         );  
                 switch(type) {  
                 case PARAM_STOP_NORMAL_TYPE:  
                         iter++; // skip ';'  
                         break;  
                 case PARAM_STOP_SPECIAL_TYPE:  
                         iter++; // skip '`'  
                         char c=iter();  
                         if(c==';')  
                                 iter++; // skip ';'  
                         else if(c!=']')  
                                 pool.exception().raise("params: closing backstick doesn't adjoin semicolon or closing bracket");  
                         break;  
                 default:  
                         break; // ']'  or eof: ^method[params;...;eof which would'nt process honestly  
                 }  
   
                 // emit resulting param's value  
                 param_values+=local_wcontext.value();  
   
                 // stop on ] or eof, otherwise continue with next param  
                 if(type==STOP_TYPE || type<0)  
                         break;  
         }  
 }  }

Removed from v.1.17  
changed lines
  Added in v.1.66


E-mail: