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