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: ¶m_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: