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