Annotation of parser3/src/main/execute.C, revision 1.432
1.117 paf 1: /** @file
1.118 paf 2: Parser: executor part of request class.
3:
1.430 moko 4: Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com)
1.414 moko 5: Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
1.243 paf 6: */
1.118 paf 7:
1.152 paf 8: #include "pa_opcode.h"
1.8 paf 9: #include "pa_array.h"
1.11 paf 10: #include "pa_request.h"
1.15 paf 11: #include "pa_vstring.h"
1.22 paf 12: #include "pa_vhash.h"
1.167 parser 13: #include "pa_vvoid.h"
1.145 paf 14: #include "pa_vcode_frame.h"
1.321 misha 15: #include "pa_vmethod_frame.h"
1.38 paf 16: #include "pa_vobject.h"
1.49 paf 17: #include "pa_vdouble.h"
1.54 paf 18: #include "pa_vbool.h"
1.94 paf 19: #include "pa_vtable.h"
1.132 paf 20: #include "pa_vfile.h"
1.144 paf 21: #include "pa_vimage.h"
1.421 moko 22: #include "pa_varray.h"
1.194 parser 23: #include "pa_wwrapper.h"
1.1 paf 24:
1.432 ! moko 25: volatile const char * IDENT_EXECUTE_C="$Id: execute.C,v 1.431 2026/09/26 21:34:36 moko Exp $" IDENT_PA_OPCODE_H IDENT_PA_OPERATION_H IDENT_PA_VCODE_FRAME_H IDENT_PA_WWRAPPER_H;
1.368 moko 26:
1.233 paf 27: //#define DEBUG_EXECUTE
1.157 parser 28:
29: #ifdef DEBUG_EXECUTE
1.387 moko 30: const char *opcode_name[]={
1.49 paf 31: // literals
1.109 paf 32: "VALUE", "CURLY_CODE__STORE_PARAM", "EXPR_CODE__STORE_PARAM",
1.209 paf 33: "NESTED_CODE",
1.49 paf 34:
35: // actions
1.187 parser 36: "WITH_ROOT", "WITH_SELF", "WITH_READ", "WITH_WRITE",
1.387 moko 37: "VALUE__GET_CLASS", "VALUE__GET_BASE_CLASS",
1.421 moko 38: "CONSTRUCT_VALUE", "CONSTRUCT_EXPR", "CURLY_CODE__CONSTRUCT", "CONSTRUCT_ARRAY",
1.108 paf 39: "WRITE_VALUE", "WRITE_EXPR_RESULT", "STRING__WRITE",
1.328 misha 40: #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT
41: "VALUE__GET_ELEMENT_OR_OPERATOR",
42: #else
43: "GET_ELEMENT_OR_OPERATOR",
44: #endif
45: "GET_ELEMENT",
1.346 misha 46: "GET_ELEMENT__WRITE",
47: #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT
48: "VALUE__GET_ELEMENT",
49: "VALUE__GET_ELEMENT__WRITE",
1.347 misha 50: "WITH_ROOT__VALUE__GET_ELEMENT",
1.346 misha 51: #endif
1.335 misha 52: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT
53: "GET_OBJECT_ELEMENT",
54: "GET_OBJECT_ELEMENT__WRITE",
55: #endif
56: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT
57: "GET_OBJECT_VAR_ELEMENT",
58: "GET_OBJECT_VAR_ELEMENT__WRITE",
1.334 misha 59: #endif
1.345 misha 60: #ifdef OPTIMIZE_BYTECODE_GET_SELF_ELEMENT
61: "WITH_SELF__VALUE__GET_ELEMENT",
62: "WITH_SELF__VALUE__GET_ELEMENT__WRITE",
63: #endif
1.376 moko 64:
65: #ifdef FEATURE_GET_ELEMENT4CALL
66: "GET_ELEMENT4CALL",
67: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT
68: "GET_OBJECT_ELEMENT4CALL",
69: #endif
70: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT
71: "GET_OBJECT_VAR_ELEMENT4CALL",
72: #endif
73: #endif // FEATURE_GET_ELEMENT4CALL
74:
1.232 paf 75: "OBJECT_POOL", "STRING_POOL",
1.348 misha 76: "PREPARE_TO_CONSTRUCT_OBJECT",
77: "CONSTRUCT_OBJECT",
78: "CONSTRUCT_OBJECT__WRITE",
1.232 paf 79: "CALL", "CALL__WRITE",
1.49 paf 80:
1.337 misha 81: #ifdef OPTIMIZE_BYTECODE_CONSTRUCT
1.344 misha 82: "WITH_ROOT__VALUE__CONSTRUCT_EXPR",
83: "WITH_ROOT__VALUE__CONSTRUCT_VALUE",
84: "WITH_WRITE__VALUE__CONSTRUCT_EXPR",
85: "WITH_WRITE__VALUE__CONSTRUCT_VALUE",
1.345 misha 86: "WITH_SELF__VALUE__CONSTRUCT_EXPR",
87: "WITH_SELF__VALUE__CONSTRUCT_VALUE",
1.337 misha 88: #endif
89:
1.372 misha 90: #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT__SPECIAL
91: "GET_ELEMENT__SPECIAL",
92: "GET_ELEMENT__SPECIAL__WRITE",
93: #endif
1.49 paf 94: // expression ops: unary
1.148 paf 95: "NEG", "INV", "NOT", "DEF", "IN", "FEXISTS", "DEXISTS",
1.49 paf 96: // expression ops: binary
1.201 paf 97: "SUB", "ADD", "MUL", "DIV", "MOD", "INTDIV",
1.275 paf 98: "BIN_SL", "BIN_SR",
1.56 paf 99: "BIN_AND", "BIN_OR", "BIN_XOR",
100: "LOG_AND", "LOG_OR", "LOG_XOR",
1.49 paf 101: "NUM_LT", "NUM_GT", "NUM_LE", "NUM_GE", "NUM_EQ", "NUM_NE",
1.103 paf 102: "STR_LT", "STR_GT", "STR_LE", "STR_GE", "STR_EQ", "STR_NE",
103: "IS"
1.1 paf 104: };
105:
1.342 misha 106: const char* debug_value_to_cstr(Value& value){
107: const String* string=value.get_string();
108:
109: if(string)
110: return string->cstr();
111: else
112: if(value.is_bool())
1.386 moko 113: return value.as_bool() ? "<true>" : "<false>";
1.342 misha 114: else
115: return "<value>";
116: }
117:
1.297 paf 118: void va_debug_printf(SAPI_Info& sapi_info, const char* fmt,va_list args) {
1.127 paf 119: char buf[MAX_STRING];
120: vsnprintf(buf, MAX_STRING, fmt, args);
1.297 paf 121: SAPI::log(sapi_info, "%s", buf);
1.107 paf 122: }
123:
1.297 paf 124: void debug_printf(SAPI_Info& sapi_info, const char* fmt, ...) {
1.334 misha 125: va_list args;
126: va_start(args, fmt);
127: va_debug_printf(sapi_info, fmt, args);
128: va_end(args);
1.105 paf 129: }
130:
1.297 paf 131: void debug_dump(SAPI_Info& sapi_info, int level, ArrayOperation& ops) {
1.419 moko 132: for(Array_iterator<Operation> i(ops); i;) {
1.323 misha 133: OP::OPCODE opcode=i.next().code;
1.1 paf 134:
1.337 misha 135: #if defined(OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT) || defined(OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT)
1.334 misha 136: if(
1.335 misha 137: 1==0
138: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT
139: || opcode==OP::OP_GET_OBJECT_ELEMENT
140: || opcode==OP::OP_GET_OBJECT_ELEMENT__WRITE
1.376 moko 141: #ifdef FEATURE_GET_ELEMENT4CALL
142: || opcode==OP::OP_GET_OBJECT_ELEMENT4CALL
143: #endif
1.335 misha 144: #endif
145: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT
146: || opcode==OP::OP_GET_OBJECT_VAR_ELEMENT
147: || opcode==OP::OP_GET_OBJECT_VAR_ELEMENT__WRITE
1.376 moko 148: #ifdef FEATURE_GET_ELEMENT4CALL
149: || opcode==OP::OP_GET_OBJECT_VAR_ELEMENT4CALL
150: #endif
1.335 misha 151: #endif
1.334 misha 152: ){
153: i.next(); // skip origin
154: Value& value1=*i.next().value;
155: i.next(); // skip origin
156: Value& value2=*i.next().value;
1.386 moko 157: debug_printf(sapi_info, "%*s%s \"%s\" \"%s\"", level*4, "", opcode_name[opcode], debug_value_to_cstr(value1), debug_value_to_cstr(value2));
1.334 misha 158: continue;
159: }
160: #endif
1.348 misha 161: if(
162: opcode==OP::OP_CONSTRUCT_OBJECT
163: || opcode==OP::OP_CONSTRUCT_OBJECT__WRITE
164: ){
165: i.next(); // skip origin
166: Value& value1=*i.next().value;
167: i.next(); // skip origin
168: Value& value2=*i.next().value;
169: debug_printf(sapi_info,
170: "%*s%s"
171: " \"%s\" \"%s\"",
172: level*4, "", opcode_name[opcode],
173: debug_value_to_cstr(value1), debug_value_to_cstr(value2));
174:
175: if(ArrayOperation* local_ops=i.next().ops)
176: debug_dump(sapi_info, level+1, *local_ops);
177: continue;
178: }
1.328 misha 179: if(
180: opcode==OP::OP_VALUE
181: || opcode==OP::OP_STRING__WRITE
182: || opcode==OP::OP_VALUE__GET_CLASS
1.383 moko 183: || opcode==OP::OP_VALUE__GET_BASE_CLASS
1.328 misha 184: #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT
185: || opcode==OP::OP_VALUE__GET_ELEMENT
186: || opcode==OP::OP_VALUE__GET_ELEMENT__WRITE
187: || opcode==OP::OP_VALUE__GET_ELEMENT_OR_OPERATOR
1.347 misha 188: || opcode==OP::OP_WITH_ROOT__VALUE__GET_ELEMENT
1.328 misha 189: #endif
1.345 misha 190: #ifdef OPTIMIZE_BYTECODE_GET_SELF_ELEMENT
191: || opcode==OP::OP_WITH_SELF__VALUE__GET_ELEMENT
192: || opcode==OP::OP_WITH_SELF__VALUE__GET_ELEMENT__WRITE
193: #endif
1.342 misha 194: #ifdef OPTIMIZE_BYTECODE_CONSTRUCT
1.344 misha 195: || opcode==OP::OP_WITH_ROOT__VALUE__CONSTRUCT_EXPR
196: || opcode==OP::OP_WITH_ROOT__VALUE__CONSTRUCT_VALUE
197: || opcode==OP::OP_WITH_WRITE__VALUE__CONSTRUCT_EXPR
198: || opcode==OP::OP_WITH_WRITE__VALUE__CONSTRUCT_VALUE
1.345 misha 199: || opcode==OP::OP_WITH_SELF__VALUE__CONSTRUCT_EXPR
200: || opcode==OP::OP_WITH_SELF__VALUE__CONSTRUCT_VALUE
1.342 misha 201: #endif
1.328 misha 202: ) {
1.297 paf 203: Operation::Origin origin=i.next().origin;
204: Value& value=*i.next().value;
1.342 misha 205:
1.297 paf 206: debug_printf(sapi_info,
1.133 paf 207: "%*s%s"
208: " \"%s\" %s",
1.297 paf 209: level*4, "", opcode_name[opcode],
1.342 misha 210: debug_value_to_cstr(value), value.type());
1.133 paf 211: continue;
1.15 paf 212: }
1.348 misha 213:
1.297 paf 214: debug_printf(sapi_info, "%*s%s", level*4, "", opcode_name[opcode]);
1.1 paf 215:
1.297 paf 216: switch(opcode) {
1.428 moko 217: case OP::OP_CURLY_CODE__STORE_PARAM:
1.323 misha 218: case OP::OP_EXPR_CODE__STORE_PARAM:
219: case OP::OP_CURLY_CODE__CONSTRUCT:
220: case OP::OP_NESTED_CODE:
1.346 misha 221: case OP::OP_OBJECT_POOL:
1.323 misha 222: case OP::OP_STRING_POOL:
1.421 moko 223: case OP::OP_CONSTRUCT_ARRAY:
1.323 misha 224: case OP::OP_CALL:
225: case OP::OP_CALL__WRITE:
1.297 paf 226: if(ArrayOperation* local_ops=i.next().ops)
227: debug_dump(sapi_info, level+1, *local_ops);
1.1 paf 228: }
229: }
230: }
1.336 misha 231: #define DEBUG_PRINT_STR(str) debug_printf(sapi_info, str);
232: #define DEBUG_PRINT_STRING(value) debug_printf(sapi_info, " \"%s\" ", value.cstr());
1.342 misha 233: #define DEBUG_PRINT_VALUE_AND_TYPE(value) debug_printf(sapi_info, " \"%s\" %s", debug_value_to_cstr(value), value.type());
1.336 misha 234: #define DEBUG_PRINT_OPS(local_ops) \
235: debug_printf(sapi_info, \
236: " (%d)\n", local_ops?local_ops->count():0); \
237: if(local_ops) debug_dump(sapi_info, 1, *local_ops);
238:
239: #else
240: #define DEBUG_PRINT_STR(str)
241: #define DEBUG_PRINT_STRING(value)
1.342 misha 242: #define DEBUG_PRINT_VALUE_AND_TYPE(value)
1.336 misha 243: #define DEBUG_PRINT_OPS(local_ops)
1.157 parser 244: #endif
1.1 paf 245:
1.297 paf 246: // Request
247:
248: void Request::execute(ArrayOperation& ops) {
1.431 moko 249: SINGLE_METHOD_FRAME_STORAGE; // one frame at a time, see SINGLE_METHOD_FRAME
1.418 moko 250: Stack<StackItem>& stack=this->stack; // helps a lot on MSVC: 'esi'
1.159 parser 251:
1.304 paf 252: const String* debug_name=0; Operation::Origin debug_origin={0, 0, 0};
1.297 paf 253: try{
1.157 parser 254: #ifdef DEBUG_EXECUTE
1.297 paf 255: debug_printf(sapi_info, "source----------------------------\n");
256: debug_dump(sapi_info, 0, ops);
257: debug_printf(sapi_info, "execution-------------------------\n");
1.157 parser 258: #endif
1.419 moko 259: for(Array_iterator<Operation> i(ops); i; ) {
1.322 misha 260: OP::OPCODE opcode=i.next().code;
1.293 paf 261:
1.157 parser 262: #ifdef DEBUG_EXECUTE
1.297 paf 263: debug_printf(sapi_info, "%d:%s", stack.top_index()+1, opcode_name[opcode]);
1.157 parser 264: #endif
1.11 paf 265:
1.297 paf 266: switch(opcode) {
1.51 paf 267: // param in next instruction
1.322 misha 268: case OP::OP_VALUE:
1.32 paf 269: {
1.297 paf 270: debug_origin=i.next().origin;
271: Value& value=*i.next().value;
1.342 misha 272:
273: DEBUG_PRINT_VALUE_AND_TYPE(value)
274:
1.297 paf 275: stack.push(value);
1.32 paf 276: break;
277: }
1.328 misha 278: case OP::OP_VALUE__GET_CLASS:
279: {
1.383 moko 280: debug_origin=i.next().origin;
281: const String& name=*i.next().value->get_string(); debug_name=&name;
282:
283: DEBUG_PRINT_STRING(name)
284:
1.413 moko 285: stack.push(get_class_ref(name));
1.383 moko 286: break;
287: }
288:
289: case OP::OP_VALUE__GET_BASE_CLASS:
290: {
291: // ^class:method[] call
1.328 misha 292:
293: debug_origin=i.next().origin;
1.372 misha 294: const String& name=*i.next().value->get_string(); debug_name=&name;
1.328 misha 295:
1.336 misha 296: DEBUG_PRINT_STRING(name)
1.328 misha 297:
1.413 moko 298: stack.push(*new VBaseClassWrapper(get_class_ref(name), get_self()));
1.328 misha 299: break;
300: }
1.372 misha 301:
302: #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT__SPECIAL
303: case OP::OP_GET_ELEMENT__SPECIAL:
304: case OP::OP_GET_ELEMENT__SPECIAL__WRITE:
305: {
306: const String& name=stack.pop().string(); debug_name=&name;
307: Value& ncontext=stack.pop().value();
308:
309: Value* value=0;
310: if(VStateless_class* vclass=ncontext.get_class()){
1.382 moko 311: if(SYMBOLS_EQ(name,CLASS_SYMBOL)){
1.372 misha 312: value=vclass;
1.382 moko 313: } else if(SYMBOLS_EQ(name,CLASS_NAME_SYMBOL)){
1.379 moko 314: value=new VString(*new String(vclass->type()));
1.372 misha 315: }
316: } else {
1.381 moko 317: // VJunction is without class, returning self
1.382 moko 318: if(SYMBOLS_EQ(name,CLASS_SYMBOL)){
1.381 moko 319: value=&ncontext;
1.382 moko 320: } else if(SYMBOLS_EQ(name,CLASS_NAME_SYMBOL)){
1.381 moko 321: value=new VString(*new String(ncontext.type()));
322: }
1.380 moko 323: }
1.372 misha 324: if(opcode==OP::OP_GET_ELEMENT__SPECIAL){
325: stack.push(*value);
326: } else {
1.396 moko 327: write(*value);
1.372 misha 328: }
329: break;
330: }
331: #endif
332:
1.51 paf 333: // OP_WITH
1.322 misha 334: case OP::OP_WITH_ROOT:
1.187 parser 335: {
1.297 paf 336: stack.push(*method_frame);
1.187 parser 337: break;
338: }
1.336 misha 339: case OP::OP_WITH_SELF:
1.37 paf 340: {
1.297 paf 341: stack.push(get_self());
1.37 paf 342: break;
343: }
1.336 misha 344: case OP::OP_WITH_READ:
1.15 paf 345: {
1.297 paf 346: stack.push(*rcontext);
1.20 paf 347: break;
348: }
1.336 misha 349: case OP::OP_WITH_WRITE:
1.20 paf 350: {
1.287 paf 351: if(wcontext==method_frame)
1.384 moko 352: throw Exception(PARSER_RUNTIME, 0, "$.name outside of $name[...]");
1.287 paf 353:
1.297 paf 354: stack.push(*wcontext);
1.20 paf 355: break;
356: }
1.37 paf 357:
1.51 paf 358: // OTHER ACTIONS BUT WITHs
1.337 misha 359:
360: #ifdef OPTIMIZE_BYTECODE_CONSTRUCT
1.392 moko 361: #define DO_CONSTRUCT(context, vvalue) { \
1.347 misha 362: debug_origin=i.next().origin; \
363: const String& name=*i.next().value->get_string(); debug_name=&name; \
364: DEBUG_PRINT_STRING(name) \
365: Value& value=stack.pop().value(); \
366: put_element( context, name, vvalue ); \
1.403 moko 367: goto check_skip; \
1.347 misha 368: }
369: #define DO_CONSTRUCT_VALUE(context) DO_CONSTRUCT(context, &value)
1.392 moko 370: #define DO_CONSTRUCT_EXPR(context) { \
1.347 misha 371: DO_CONSTRUCT(context, &value.as_expr_result()) \
372: }
373:
1.344 misha 374: case OP::OP_WITH_WRITE__VALUE__CONSTRUCT_EXPR:
1.347 misha 375: {
376: if(wcontext==method_frame)
377: throw Exception(PARSER_RUNTIME, 0, "$.name outside of $name[...]");
378: DO_CONSTRUCT_EXPR(*wcontext)
379: }
380:
1.344 misha 381: case OP::OP_WITH_WRITE__VALUE__CONSTRUCT_VALUE:
1.338 misha 382: {
383: if(wcontext==method_frame)
1.347 misha 384: throw Exception(PARSER_RUNTIME, 0, "$.name outside of $name[...]");
385: DO_CONSTRUCT_VALUE(*wcontext)
1.338 misha 386: }
1.345 misha 387:
1.347 misha 388: case OP::OP_WITH_ROOT__VALUE__CONSTRUCT_EXPR: DO_CONSTRUCT_EXPR(*method_frame)
1.337 misha 389:
1.347 misha 390: case OP::OP_WITH_ROOT__VALUE__CONSTRUCT_VALUE: DO_CONSTRUCT_VALUE(*method_frame)
1.337 misha 391:
1.347 misha 392: case OP::OP_WITH_SELF__VALUE__CONSTRUCT_EXPR: DO_CONSTRUCT_EXPR(get_self())
1.342 misha 393:
1.347 misha 394: case OP::OP_WITH_SELF__VALUE__CONSTRUCT_VALUE: DO_CONSTRUCT_VALUE(get_self())
1.345 misha 395:
1.340 misha 396: #endif // OPTIMIZE_BYTECODE_CONSTRUCT
1.337 misha 397:
1.344 misha 398: case OP::OP_CONSTRUCT_VALUE:
1.337 misha 399: {
1.344 misha 400: #ifdef OPTIMIZE_BYTECODE_CONSTRUCT
401: const String& name=stack.pop().string(); debug_name=&name;
402: Value& ncontext=stack.pop().value();
403: Value& value=stack.pop().value();
404: #else
405: Value& value=stack.pop().value();
406: const String& name=stack.pop().string(); debug_name=&name;
407: Value& ncontext=stack.pop().value();
408: #endif
409: put_element(ncontext, name, &value);
1.403 moko 410: goto check_skip;
1.337 misha 411: }
412:
1.322 misha 413: case OP::OP_CONSTRUCT_EXPR:
1.80 paf 414: {
1.344 misha 415: #ifdef OPTIMIZE_BYTECODE_CONSTRUCT
416: const String& name=stack.pop().string(); debug_name=&name;
417: Value& ncontext=stack.pop().value();
418: Value& expr=stack.pop().value();
419: #else
1.308 paf 420: Value& expr=stack.pop().value();
1.297 paf 421: const String& name=stack.pop().string(); debug_name=&name;
422: Value& ncontext=stack.pop().value();
1.344 misha 423: #endif
1.308 paf 424: Value& value=expr.as_expr_result();
1.329 misha 425: put_element(ncontext, name, &value);
1.403 moko 426: goto check_skip;
1.80 paf 427: }
1.337 misha 428:
1.322 misha 429: case OP::OP_CURLY_CODE__CONSTRUCT:
1.182 parser 430: {
1.297 paf 431: ArrayOperation& local_ops=*i.next().ops;
1.336 misha 432:
433: DEBUG_PRINT_OPS((&local_ops))
434:
1.326 misha 435: VJunction& value=*new VJunction(
1.297 paf 436: get_self(), 0,
1.257 paf 437: method_frame,
1.240 paf 438: rcontext,
439: wcontext,
1.312 paf 440: &local_ops);
1.238 paf 441:
1.326 misha 442: wcontext->attach_junction(&value);
443:
1.297 paf 444: const String& name=stack.pop().string(); debug_name=&name;
445: Value& ncontext=stack.pop().value();
1.426 moko 446: if(ncontext.put_element(name, &value))
1.422 moko 447: throw Exception(PARSER_RUNTIME, 0, "property value cannot be code, use [] or () brackets");
1.403 moko 448:
1.182 parser 449: break;
450: }
1.421 moko 451:
452: case OP::OP_CONSTRUCT_ARRAY:
453: {
1.429 moko 454: debug_name=0;
455:
1.421 moko 456: ArrayOperation* local_ops=i.next().ops;
457:
458: DEBUG_PRINT_OPS(local_ops)
459: DEBUG_PRINT_STR("->\n")
460:
461: size_t first = stack.top_index();
462: execute(*local_ops);
463: Value *value=new VArray(stack.top_index()-first, (Value**)stack.ptr(first));
464: stack.set_top_index(first);
465:
466: const String& name=stack.pop().string(); debug_name=&name;
467: Value& ncontext=stack.pop().value();
1.429 moko 468:
1.421 moko 469: put_element(ncontext, name, value);
470:
471: DEBUG_PRINT_STR("<-returned")
472: goto check_skip;
473: }
474:
1.322 misha 475: case OP::OP_NESTED_CODE:
1.209 paf 476: {
1.297 paf 477: ArrayOperation& local_ops=*i.next().ops;
1.336 misha 478:
479: DEBUG_PRINT_OPS((&local_ops))
480:
1.297 paf 481: stack.push(local_ops);
1.209 paf 482: break;
483: }
1.322 misha 484: case OP::OP_WRITE_VALUE:
1.13 paf 485: {
1.297 paf 486: Value& value=stack.pop().value();
1.396 moko 487: write(value);
1.86 paf 488: break;
489: }
1.322 misha 490: case OP::OP_WRITE_EXPR_RESULT:
1.108 paf 491: {
1.351 misha 492: Value& value=stack.pop().value();
493: wcontext->write(value.as_expr_result());
1.108 paf 494: break;
495: }
1.322 misha 496: case OP::OP_STRING__WRITE:
1.86 paf 497: {
1.297 paf 498: i.next(); // ignore origin
499: Value* value=i.next().value;
1.336 misha 500:
501: const String& string_value=*value->get_string();
502:
503: DEBUG_PRINT_STRING(string_value)
504:
1.396 moko 505: write(string_value);
1.13 paf 506: break;
1.14 paf 507: }
1.328 misha 508:
509: #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT
510: case OP::OP_VALUE__GET_ELEMENT_OR_OPERATOR:
511: {
512: debug_origin=i.next().origin;
513: const String& name=*i.next().value->get_string(); debug_name=&name;
514:
1.336 misha 515: DEBUG_PRINT_STRING(name)
516:
1.330 misha 517: if(Method* method=main_class.get_method(name)){ // looking operator of that name FIRST
1.427 moko 518: stack.push(*method->get_vjunction(main_class));
1.330 misha 519: break;
520: }
521: Value& value=get_element(*rcontext, name);
1.328 misha 522: stack.push(value);
1.403 moko 523: goto check_skip;
1.328 misha 524: }
525: #else
1.322 misha 526: case OP::OP_GET_ELEMENT_OR_OPERATOR:
1.215 paf 527: {
1.297 paf 528: const String& name=stack.pop().string(); debug_name=&name;
529: Value& ncontext=stack.pop().value();
1.330 misha 530: if(Method* method=main_class.get_method(name)){ // looking operator of that name FIRST
1.427 moko 531: stack.push(*method->get_vjunction(main_class));
1.330 misha 532: break;
533: }
534: Value& value=get_element(ncontext, name);
1.297 paf 535: stack.push(value);
1.403 moko 536: goto check_skip;
1.215 paf 537: }
1.328 misha 538: #endif
539:
1.335 misha 540: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT
1.336 misha 541:
1.376 moko 542: #define DO_GET_OBJECT_ELEMENT(code) {\
543: debug_origin=i.next().origin; \
544: const String& context_name=*i.next().value->get_string(); debug_name=&context_name; \
545: DEBUG_PRINT_STRING(context_name) \
546: Value& object=get_element(*rcontext, context_name); \
547: debug_origin=i.next().origin; \
548: const String& field_name=*i.next().value->get_string(); debug_name=&field_name; \
549: DEBUG_PRINT_STRING(field_name) \
550: code; \
1.403 moko 551: goto check_skip; \
1.376 moko 552: }
1.336 misha 553:
1.376 moko 554: case OP::OP_GET_OBJECT_ELEMENT: DO_GET_OBJECT_ELEMENT({
555: Value& value=get_element(object, field_name);
556: stack.push(value);
557: })
558: case OP::OP_GET_OBJECT_ELEMENT__WRITE: DO_GET_OBJECT_ELEMENT({
1.334 misha 559: Value& value=get_element(object, field_name);
1.396 moko 560: write(value);
1.376 moko 561: })
562: #ifdef FEATURE_GET_ELEMENT4CALL
563: case OP::OP_GET_OBJECT_ELEMENT4CALL: DO_GET_OBJECT_ELEMENT({
564: Value& value=get_element4call(object, field_name);
565: stack.push(value);
566: })
567: #endif
1.335 misha 568: #endif
569:
570: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT
1.336 misha 571:
1.376 moko 572: #define DO_GET_OBJECT_VAR_ELEMENT(code) {\
573: debug_origin=i.next().origin; \
574: const String& context_name=*i.next().value->get_string(); debug_name=&context_name; \
575: DEBUG_PRINT_STRING(context_name) \
576: Value& object=get_element(*rcontext, context_name); \
577: debug_origin=i.next().origin; \
578: const String& var_name=*i.next().value->get_string(); debug_name=&var_name; \
579: DEBUG_PRINT_STRING(var_name) \
580: const String* field=&get_element(*rcontext, var_name).as_string(); \
581: code; \
1.403 moko 582: goto check_skip; \
1.376 moko 583: }
1.335 misha 584:
1.376 moko 585: case OP::OP_GET_OBJECT_VAR_ELEMENT: DO_GET_OBJECT_VAR_ELEMENT({
586: Value& value=get_element(object, *field);
587: stack.push(value);
588: })
589: case OP::OP_GET_OBJECT_VAR_ELEMENT__WRITE: DO_GET_OBJECT_VAR_ELEMENT({
1.335 misha 590: Value& value=get_element(object, *field);
1.396 moko 591: write(value);
1.376 moko 592: })
593: #ifdef FEATURE_GET_ELEMENT4CALL
594: case OP::OP_GET_OBJECT_VAR_ELEMENT4CALL: DO_GET_OBJECT_VAR_ELEMENT({
595: Value& value=get_element4call(object, *field);
596: stack.push(value);
597: })
598: #endif
599: #endif
1.335 misha 600:
1.376 moko 601: case OP::OP_GET_ELEMENT:
602: {
603: const String& name=stack.pop().string(); debug_name=&name;
604: Value& ncontext=stack.pop().value();
605: Value& value=get_element(ncontext, name);
606: stack.push(value);
1.403 moko 607: goto check_skip;
1.334 misha 608: }
609:
1.376 moko 610: #ifdef FEATURE_GET_ELEMENT4CALL
611: case OP::OP_GET_ELEMENT4CALL:
1.11 paf 612: {
1.297 paf 613: const String& name=stack.pop().string(); debug_name=&name;
614: Value& ncontext=stack.pop().value();
1.376 moko 615: Value& value=get_element4call(ncontext, name);
1.297 paf 616: stack.push(value);
1.403 moko 617: goto check_skip;
1.17 paf 618: }
1.376 moko 619: #endif
1.17 paf 620:
1.346 misha 621: case OP::OP_GET_ELEMENT__WRITE:
622: {
623: const String& name=stack.pop().string(); debug_name=&name;
624: Value& ncontext=stack.pop().value();
625: Value& value=get_element(ncontext, name);
1.396 moko 626: write(value);
1.403 moko 627: goto check_skip;
1.346 misha 628: }
629:
1.328 misha 630: #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT
631: case OP::OP_VALUE__GET_ELEMENT:
632: {
633: debug_origin=i.next().origin;
634: const String& name=*i.next().value->get_string(); debug_name=&name;
635:
1.336 misha 636: DEBUG_PRINT_STRING(name)
1.328 misha 637:
1.330 misha 638: Value& value=get_element(*rcontext, name);
1.328 misha 639: stack.push(value);
1.403 moko 640: goto check_skip;
1.328 misha 641: }
642:
643: case OP::OP_VALUE__GET_ELEMENT__WRITE:
644: {
645: debug_origin=i.next().origin;
646: const String& name=*i.next().value->get_string(); debug_name=&name;
647:
1.336 misha 648: DEBUG_PRINT_STRING(name)
1.328 misha 649:
1.330 misha 650: Value& value=get_element(*rcontext, name);
1.396 moko 651: write(value);
1.403 moko 652: goto check_skip;
1.328 misha 653: }
1.347 misha 654:
655: case OP::OP_WITH_ROOT__VALUE__GET_ELEMENT:
656: {
657: debug_origin=i.next().origin;
658: const String& name=*i.next().value->get_string(); debug_name=&name;
659:
660: DEBUG_PRINT_STRING(name)
661:
662: Value& value=get_element(*method_frame, name);
663: stack.push(value);
1.403 moko 664: goto check_skip;
1.347 misha 665: }
1.328 misha 666: #endif
1.32 paf 667:
1.345 misha 668: #ifdef OPTIMIZE_BYTECODE_GET_SELF_ELEMENT
669: case OP::OP_WITH_SELF__VALUE__GET_ELEMENT:
670: case OP::OP_WITH_SELF__VALUE__GET_ELEMENT__WRITE:
671: {
672: debug_origin=i.next().origin;
673: const String& name=*i.next().value->get_string(); debug_name=&name;
674:
675: DEBUG_PRINT_STRING(name)
676:
677: Value& value=get_element(get_self(), name);
678:
679: if(opcode==OP::OP_WITH_SELF__VALUE__GET_ELEMENT){
680: stack.push(value);
681: } else {
1.396 moko 682: write(value);
1.345 misha 683: }
1.403 moko 684: goto check_skip;
1.345 misha 685: }
686: #endif
687:
1.322 misha 688: case OP::OP_OBJECT_POOL:
1.17 paf 689: {
1.406 moko 690: debug_name=0;
691:
1.297 paf 692: ArrayOperation& local_ops=*i.next().ops;
1.226 paf 693:
1.257 paf 694: WContext *saved_wcontext=wcontext;
1.348 misha 695: #ifdef OPTIMIZE_SINGLE_STRING_WRITE
1.351 misha 696: WObjectPoolWrapper local(wcontext);
1.348 misha 697: #else
1.351 misha 698: WWrapper local(wcontext);
1.348 misha 699: #endif
1.226 paf 700: wcontext=&local;
701:
1.297 paf 702: execute(local_ops);
1.226 paf 703:
1.400 moko 704: stack.push((Value&)wcontext->result());
1.403 moko 705:
1.257 paf 706: wcontext=saved_wcontext;
1.403 moko 707: goto check_skip;
1.15 paf 708: }
1.13 paf 709:
1.322 misha 710: case OP::OP_STRING_POOL:
1.49 paf 711: {
1.297 paf 712: ArrayOperation& local_ops=*i.next().ops;
1.226 paf 713:
1.257 paf 714: WContext *saved_wcontext=wcontext;
1.351 misha 715: WWrapper local(wcontext);
1.226 paf 716: wcontext=&local;
717:
1.297 paf 718: execute(local_ops);
1.226 paf 719:
1.49 paf 720: // from "$a $b" part of expression taking only string value,
721: // ignoring any other content of wcontext
1.367 moko 722: const String* string=wcontext->get_string();
723: Value* value=string ? new VString(*string) : new VString();
1.297 paf 724: stack.push(*value);
725:
1.257 paf 726: wcontext=saved_wcontext;
1.403 moko 727: goto check_skip;
1.49 paf 728: }
729:
1.51 paf 730: // CALL
1.322 misha 731: case OP::OP_CURLY_CODE__STORE_PARAM:
732: case OP::OP_EXPR_CODE__STORE_PARAM:
1.28 paf 733: {
1.237 paf 734: // code
1.297 paf 735: ArrayOperation& local_ops=*i.next().ops;
1.336 misha 736:
737: DEBUG_PRINT_OPS((&local_ops))
738:
1.237 paf 739: // when they evaluate expression parameter,
740: // the object expression result
741: // does not need to be written into calling frame
742: // it must go into any expressions using that parameter
743: // hence, we zero junction.wcontext here, and later
744: // in .process we would test that field
745: // in decision "which wwrapper to use"
1.326 misha 746: VJunction& value=*new VJunction(
1.297 paf 747: get_self(), 0,
1.257 paf 748: method_frame,
1.237 paf 749: rcontext,
1.322 misha 750: opcode==OP::OP_EXPR_CODE__STORE_PARAM?0:wcontext,
1.312 paf 751: &local_ops);
1.343 misha 752: #ifndef USE_DESTRUCTORS
1.326 misha 753: if (opcode!=OP::OP_EXPR_CODE__STORE_PARAM)
1.343 misha 754: wcontext->attach_junction(&value);
1.326 misha 755: #endif
1.237 paf 756: // store param
1.329 misha 757: stack.push(value);
1.29 paf 758: break;
759: }
760:
1.397 moko 761: #define METHOD_PARAMS_ACTION(action) \
1.386 moko 762: if(local_ops){ \
763: size_t first = stack.top_index(); \
764: execute(*local_ops); \
1.403 moko 765: if(!fskip){ \
766: frame.store_params((Value**)stack.ptr(first), stack.top_index()-first); \
767: action; \
768: } \
1.386 moko 769: stack.set_top_index(first); \
770: } else { \
771: frame.empty_params(); \
772: action; \
1.350 misha 773: }
774:
1.322 misha 775: case OP::OP_CALL:
1.29 paf 776: {
1.297 paf 777: ArrayOperation* local_ops=i.next().ops;
1.237 paf 778:
1.336 misha 779: DEBUG_PRINT_OPS(local_ops)
780: DEBUG_PRINT_STR("->\n")
781:
1.297 paf 782: Value& value=stack.pop().value();
1.237 paf 783:
1.297 paf 784: Junction* junction=value.get_junction();
785: if(!junction) {
1.420 moko 786: if(dynamic_cast<VVoid*>(&value))
1.386 moko 787: throw Exception(PARSER_RUNTIME, 0, "undefined method");
1.297 paf 788: else
1.422 moko 789: throw Exception(PARSER_RUNTIME, 0, "is '%s', not a method or junction, cannot call it", value.type());
1.297 paf 790: }
1.237 paf 791:
1.370 moko 792: Value *result;
793: {
1.431 moko 794: SINGLE_EXPRESSION_FRAME_ACTION(*junction->method, method_frame, junction->self, {
1.397 moko 795: METHOD_PARAMS_ACTION(call(frame));
796: result=&frame.result();
797: // desctructor deletes junctions in stack params here
798: });
1.370 moko 799: }
800: stack.push(*result);
1.332 misha 801:
1.336 misha 802: DEBUG_PRINT_STR("<-returned")
1.403 moko 803: goto check_skip;
1.332 misha 804: }
1.220 paf 805:
1.332 misha 806: case OP::OP_CALL__WRITE:
807: {
808: ArrayOperation* local_ops=i.next().ops;
809:
1.336 misha 810: DEBUG_PRINT_OPS(local_ops)
811: DEBUG_PRINT_STR("->\n")
812:
1.332 misha 813: Value& value=stack.pop().value();
814:
815: Junction* junction=value.get_junction();
816: if(!junction) {
1.420 moko 817: if(dynamic_cast<VVoid*>(&value))
1.386 moko 818: throw Exception(PARSER_RUNTIME, 0, "undefined method");
1.332 misha 819: else
1.422 moko 820: throw Exception(PARSER_RUNTIME, 0, "is '%s', not a method or junction, cannot call it", value.type());
1.332 misha 821: }
822:
1.391 moko 823: const Method& method=*junction->method;
1.332 misha 824: #ifdef OPTIMIZE_CALL
1.353 misha 825: if(method.call_optimization==Method::CO_WITHOUT_FRAME){
1.332 misha 826: if(local_ops){ // store param code goes here
827: size_t first = stack.top_index();
828: execute(*local_ops);
829:
1.403 moko 830: if(!fskip){
831: MethodParams method_params;
832: method_params.store_params((Value**)stack.ptr(first), stack.top_index()-first);
833: method.check_actual_numbered_params(junction->self, &method_params);
834: method.native_code(*this, method_params); // execute it
835: }
1.332 misha 836:
837: stack.set_top_index(first);
838: } else {
839: MethodParams method_params;
840: method.check_actual_numbered_params(junction->self, &method_params);
841: method.native_code(*this, method_params); // execute it
842: }
1.353 misha 843: } else if(method.call_optimization==Method::CO_WITHOUT_WCONTEXT){
1.431 moko 844: SINGLE_METHOD_FRAME_ACTION(method, method_frame, junction->self, {
1.397 moko 845: METHOD_PARAMS_ACTION(call_write(frame))
846: });
1.332 misha 847: } else
848: #endif // OPTIMIZE_CALL
849: {
1.431 moko 850: SINGLE_METHOD_FRAME_ACTION(method, method_frame, junction->self, {
1.397 moko 851: METHOD_PARAMS_ACTION(call(frame));
852: write(frame.result());
853: });
1.332 misha 854: }
1.336 misha 855:
856: DEBUG_PRINT_STR("<-returned")
1.403 moko 857: goto check_skip;
1.49 paf 858: }
859:
1.348 misha 860: case OP::OP_CONSTRUCT_OBJECT:
861: case OP::OP_CONSTRUCT_OBJECT__WRITE:
862: {
863: debug_origin=i.next().origin;
864: Value& vclass_name=*i.next().value;
1.360 pretende 865: const String& class_name=*vclass_name.get_string(); debug_name=&class_name;
1.348 misha 866:
867: DEBUG_PRINT_STRING(class_name)
868:
1.413 moko 869: VStateless_class& vclass=get_class_ref(class_name);
1.348 misha 870:
871: debug_origin=i.next().origin;
872: Value& vconstructor_name=*i.next().value;
873: const String& constructor_name=*vconstructor_name.get_string(); debug_name=&constructor_name;
874:
875: DEBUG_PRINT_STRING(constructor_name)
876:
1.424 moko 877: // not get_element4call for better error reporting
1.413 moko 878: Junction* constructor_junction=get_element(vclass, constructor_name).get_junction();
1.363 moko 879: if(!constructor_junction)
1.424 moko 880: throw Exception(PARSER_RUNTIME, &constructor_name, "%s constructor not found", vclass.type());
1.350 misha 881:
1.348 misha 882: ArrayOperation* local_ops=i.next().ops;
883: DEBUG_PRINT_OPS(local_ops)
884: DEBUG_PRINT_STR("->\n")
885:
1.370 moko 886: Value *result;
887: {
1.413 moko 888: Value& object=construct(vclass, *constructor_junction->method);
1.431 moko 889: SINGLE_CONSTRUCTOR_FRAME_ACTION(*constructor_junction->method, method_frame, object, {
1.397 moko 890: METHOD_PARAMS_ACTION(call(frame));
891: object.enable_default_setter();
892: result=&frame.result();
893: // desctructor deletes junctions in stack params here
894: });
1.370 moko 895: }
1.355 misha 896:
1.350 misha 897: if(opcode==OP::OP_CONSTRUCT_OBJECT)
1.370 moko 898: stack.push(*result);
1.350 misha 899: else
1.396 moko 900: write(*result);
1.348 misha 901:
902: DEBUG_PRINT_STR("<-returned")
1.403 moko 903: goto check_skip;
1.348 misha 904: }
905:
1.55 paf 906: // expression ops: unary
1.322 misha 907: case OP::OP_NEG:
1.55 paf 908: {
1.297 paf 909: Value& a=stack.pop().value();
910: Value& value=*new VDouble(-a.as_double());
911: stack.push(value);
1.55 paf 912: break;
913: }
1.322 misha 914: case OP::OP_INV:
1.55 paf 915: {
1.297 paf 916: Value& a=stack.pop().value();
917: Value& value=*new VDouble(~a.as_int());
918: stack.push(value);
1.55 paf 919: break;
920: }
1.322 misha 921: case OP::OP_NOT:
1.55 paf 922: {
1.297 paf 923: Value& a=stack.pop().value();
1.327 misha 924: Value& value=VBool::get(!a.as_bool());
1.297 paf 925: stack.push(value);
1.55 paf 926: break;
927: }
1.322 misha 928: case OP::OP_DEF:
1.62 paf 929: {
1.297 paf 930: Value& a=stack.pop().value();
1.327 misha 931: Value& value=VBool::get(a.is_defined());
1.297 paf 932: stack.push(value);
1.62 paf 933: break;
934: }
1.322 misha 935: case OP::OP_IN:
1.62 paf 936: {
1.297 paf 937: Value& a=stack.pop().value();
938: const String& path=a.as_string();
1.327 misha 939: Value& value=VBool::get(request_info.uri && *request_info.uri && path.this_starts(request_info.uri));
1.297 paf 940: stack.push(value);
1.62 paf 941: break;
942: }
1.322 misha 943: case OP::OP_FEXISTS:
1.62 paf 944: {
1.297 paf 945: Value& a=stack.pop().value();
1.432 ! moko 946: const String* path=real_disk_path(a.as_string());
! 947: Value& value=VBool::get(path && file_exist(*path));
1.297 paf 948: stack.push(value);
1.148 paf 949: break;
950: }
1.322 misha 951: case OP::OP_DEXISTS:
1.148 paf 952: {
1.297 paf 953: Value& a=stack.pop().value();
1.432 ! moko 954: const String* path=real_disk_path(a.as_string());
! 955: Value& value=VBool::get(path && dir_exists(*path));
1.297 paf 956: stack.push(value);
1.62 paf 957: break;
958: }
1.55 paf 959:
960: // expression ops: binary
1.415 moko 961: case OP::OP_SUB:
1.53 paf 962: {
1.416 moko 963: volatile double b_double=stack.pop().value().as_double();
964: volatile double a_double=stack.pop().value().as_double();
1.415 moko 965:
966: Value& value=*new VDouble(a_double - b_double);
1.297 paf 967: stack.push(value);
1.53 paf 968: break;
969: }
1.415 moko 970: case OP::OP_ADD:
1.53 paf 971: {
1.416 moko 972: volatile double b_double=stack.pop().value().as_double();
973: volatile double a_double=stack.pop().value().as_double();
1.415 moko 974:
975: Value& value=*new VDouble(a_double + b_double);
1.297 paf 976: stack.push(value);
1.53 paf 977: break;
978: }
1.415 moko 979: case OP::OP_MUL:
1.49 paf 980: {
1.416 moko 981: volatile double b_double=stack.pop().value().as_double();
982: volatile double a_double=stack.pop().value().as_double();
1.415 moko 983:
984: Value& value=*new VDouble(a_double * b_double);
1.297 paf 985: stack.push(value);
1.53 paf 986: break;
987: }
1.415 moko 988: case OP::OP_DIV:
1.53 paf 989: {
1.416 moko 990: volatile double b_double=stack.pop().value().as_double();
991: volatile double a_double=stack.pop().value().as_double();
1.170 parser 992:
1.171 parser 993: if(b_double == 0) {
1.297 paf 994: //const String* problem_source=b.as_string();
1.386 moko 995: throw Exception("number.zerodivision", 0, "Division by zero");
1.171 parser 996: }
1.170 parser 997:
1.297 paf 998: Value& value=*new VDouble(a_double / b_double);
999: stack.push(value);
1.54 paf 1000: break;
1001: }
1.415 moko 1002: case OP::OP_MOD:
1.55 paf 1003: {
1.416 moko 1004: volatile double b_double=stack.pop().value().as_double();
1005: volatile double a_double=stack.pop().value().as_double();
1.170 parser 1006:
1.173 parser 1007: if(b_double == 0) {
1.297 paf 1008: //const String* problem_source=b.as_string();
1.386 moko 1009: throw Exception("number.zerodivision", 0, "Modulus by zero");
1.171 parser 1010: }
1.170 parser 1011:
1.297 paf 1012: Value& value=*new VDouble(fmod(a_double, b_double));
1013: stack.push(value);
1.201 paf 1014: break;
1015: }
1.322 misha 1016: case OP::OP_INTDIV:
1.201 paf 1017: {
1.428 moko 1018: pa_wint b_int=stack.pop().value().as_wint();
1019: pa_wint a_int=stack.pop().value().as_wint();
1.201 paf 1020:
1021: if(b_int == 0) {
1.297 paf 1022: //const String* problem_source=b.as_string();
1.386 moko 1023: throw Exception("number.zerodivision", 0, "Division by zero");
1.201 paf 1024: }
1025:
1.297 paf 1026: Value& value=*new VInt(a_int / b_int);
1027: stack.push(value);
1.55 paf 1028: break;
1029: }
1.322 misha 1030: case OP::OP_BIN_SL:
1.274 paf 1031: {
1.297 paf 1032: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1033: Value& value=*new VInt(
1.428 moko 1034: a.as_wint() <<
1035: b.as_wint());
1.297 paf 1036: stack.push(value);
1.274 paf 1037: break;
1038: }
1.322 misha 1039: case OP::OP_BIN_SR:
1.274 paf 1040: {
1.297 paf 1041: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1042: Value& value=*new VInt(
1.428 moko 1043: a.as_wint() >>
1044: b.as_wint());
1.297 paf 1045: stack.push(value);
1.274 paf 1046: break;
1047: }
1.322 misha 1048: case OP::OP_BIN_AND:
1.54 paf 1049: {
1.297 paf 1050: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1051: Value& value=*new VInt(
1.428 moko 1052: a.as_wint() &
1053: b.as_wint());
1.297 paf 1054: stack.push(value);
1.54 paf 1055: break;
1056: }
1.322 misha 1057: case OP::OP_BIN_OR:
1.54 paf 1058: {
1.297 paf 1059: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1060: Value& value=*new VInt(
1.428 moko 1061: a.as_wint() |
1062: b.as_wint());
1.297 paf 1063: stack.push(value);
1.55 paf 1064: break;
1065: }
1.322 misha 1066: case OP::OP_BIN_XOR:
1.56 paf 1067: {
1.297 paf 1068: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1069: Value& value=*new VInt(
1.428 moko 1070: a.as_wint() ^
1071: b.as_wint());
1.297 paf 1072: stack.push(value);
1.56 paf 1073: break;
1074: }
1.322 misha 1075: case OP::OP_LOG_AND:
1.55 paf 1076: {
1.297 paf 1077: ArrayOperation& local_ops=stack.pop().ops(); Value& a=stack.pop().value();
1.263 paf 1078: bool result;
1.297 paf 1079: if(a.as_bool()) {
1080: execute(local_ops);
1081: Value& b=stack.pop().value();
1082: result=b.as_bool();
1.209 paf 1083: } else
1.263 paf 1084: result=false;
1.327 misha 1085: Value& value=VBool::get(result);
1.297 paf 1086: stack.push(value);
1.403 moko 1087: goto check_skip;
1.55 paf 1088: }
1.322 misha 1089: case OP::OP_LOG_OR:
1.55 paf 1090: {
1.297 paf 1091: ArrayOperation& local_ops=stack.pop().ops(); Value& a=stack.pop().value();
1.263 paf 1092: bool result;
1.297 paf 1093: if(a.as_bool())
1.263 paf 1094: result=true;
1.209 paf 1095: else {
1.297 paf 1096: execute(local_ops);
1097: Value& b=stack.pop().value();
1098: result=b.as_bool();
1.209 paf 1099: }
1.327 misha 1100: Value& value=VBool::get(result);
1.297 paf 1101: stack.push(value);
1.403 moko 1102: goto check_skip;
1.56 paf 1103: }
1.322 misha 1104: case OP::OP_LOG_XOR:
1.56 paf 1105: {
1.297 paf 1106: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1.327 misha 1107: Value& value=VBool::get(a.as_bool() ^ b.as_bool());
1.297 paf 1108: stack.push(value);
1.55 paf 1109: break;
1110: }
1.428 moko 1111: case OP::OP_NUM_LT:
1.55 paf 1112: {
1.297 paf 1113: volatile double b_double=stack.pop().value().as_double();
1114: volatile double a_double=stack.pop().value().as_double();
1.327 misha 1115: Value& value=VBool::get(a_double<b_double);
1.297 paf 1116: stack.push(value);
1.55 paf 1117: break;
1118: }
1.428 moko 1119: case OP::OP_NUM_GT:
1.55 paf 1120: {
1.297 paf 1121: volatile double b_double=stack.pop().value().as_double();
1122: volatile double a_double=stack.pop().value().as_double();
1.327 misha 1123: Value& value=VBool::get(a_double>b_double);
1.297 paf 1124: stack.push(value);
1.55 paf 1125: break;
1126: }
1.428 moko 1127: case OP::OP_NUM_LE:
1.55 paf 1128: {
1.297 paf 1129: volatile double b_double=stack.pop().value().as_double();
1130: volatile double a_double=stack.pop().value().as_double();
1.327 misha 1131: Value& value=VBool::get(a_double<=b_double);
1.297 paf 1132: stack.push(value);
1.55 paf 1133: break;
1134: }
1.428 moko 1135: case OP::OP_NUM_GE:
1.55 paf 1136: {
1.297 paf 1137: volatile double b_double=stack.pop().value().as_double();
1138: volatile double a_double=stack.pop().value().as_double();
1.327 misha 1139: Value& value=VBool::get(a_double>=b_double);
1.297 paf 1140: stack.push(value);
1.55 paf 1141: break;
1142: }
1.428 moko 1143: case OP::OP_NUM_EQ:
1.55 paf 1144: {
1.297 paf 1145: volatile double b_double=stack.pop().value().as_double();
1146: volatile double a_double=stack.pop().value().as_double();
1.327 misha 1147: Value& value=VBool::get(a_double==b_double);
1.297 paf 1148: stack.push(value);
1.55 paf 1149: break;
1150: }
1.428 moko 1151: case OP::OP_NUM_NE:
1.55 paf 1152: {
1.297 paf 1153: volatile double b_double=stack.pop().value().as_double();
1154: volatile double a_double=stack.pop().value().as_double();
1.327 misha 1155: Value& value=VBool::get(a_double!=b_double);
1.297 paf 1156: stack.push(value);
1.54 paf 1157: break;
1158: }
1.428 moko 1159: case OP::OP_STR_LT:
1.58 paf 1160: {
1.297 paf 1161: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1.327 misha 1162: Value& value=VBool::get(a.as_string() < b.as_string());
1.297 paf 1163: stack.push(value);
1.58 paf 1164: break;
1165: }
1.428 moko 1166: case OP::OP_STR_GT:
1.58 paf 1167: {
1.297 paf 1168: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1.327 misha 1169: Value& value=VBool::get(a.as_string() > b.as_string());
1.297 paf 1170: stack.push(value);
1.58 paf 1171: break;
1172: }
1.428 moko 1173: case OP::OP_STR_LE:
1.58 paf 1174: {
1.297 paf 1175: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1.327 misha 1176: Value& value=VBool::get(a.as_string() <= b.as_string());
1.297 paf 1177: stack.push(value);
1.58 paf 1178: break;
1179: }
1.428 moko 1180: case OP::OP_STR_GE:
1.54 paf 1181: {
1.297 paf 1182: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1.327 misha 1183: Value& value=VBool::get(a.as_string() >= b.as_string());
1.297 paf 1184: stack.push(value);
1.58 paf 1185: break;
1186: }
1.428 moko 1187: case OP::OP_STR_EQ:
1.58 paf 1188: {
1.297 paf 1189: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1.327 misha 1190: Value& value=VBool::get(a.as_string() == b.as_string());
1.297 paf 1191: stack.push(value);
1.58 paf 1192: break;
1193: }
1.428 moko 1194: case OP::OP_STR_NE:
1.58 paf 1195: {
1.297 paf 1196: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1.327 misha 1197: Value& value=VBool::get(a.as_string() != b.as_string());
1.297 paf 1198: stack.push(value);
1.103 paf 1199: break;
1200: }
1.322 misha 1201: case OP::OP_IS:
1.103 paf 1202: {
1.297 paf 1203: Value& b=stack.pop().value(); Value& a=stack.pop().value();
1.327 misha 1204: Value& value=VBool::get(a.is(b.as_string().cstr()));
1.297 paf 1205: stack.push(value);
1.28 paf 1206: break;
1207: }
1.11 paf 1208: default:
1.403 moko 1209: {
1210: throw Exception(0, 0, "invalid opcode %d", opcode);
1211: }
1212: check_skip:
1213: {
1214: if(fskip){
1215: if(fskip==Request::SKIP_INTERRUPTED){
1216: set_skip(Request::SKIP_NOTHING);
1217: throw Exception("parser.interrupted", 0, "execution stopped");
1218: }
1219: return;
1220: }
1221: break;
1222: }
1.11 paf 1223: }
1224: }
1.306 paf 1225: } catch(const Exception&) {
1.297 paf 1226: // record it to stack trace
1.301 paf 1227: if(debug_name)
1228: exception_trace.push(Trace(debug_name, debug_origin));
1.297 paf 1229: rethrow;
1230: }
1.1 paf 1231: }
1.17 paf 1232:
1.330 misha 1233: #define SAVE_CONTEXT \
1.386 moko 1234: VMethodFrame *saved_method_frame=method_frame; \
1235: Value* saved_rcontext=rcontext; \
1.330 misha 1236: WContext *saved_wcontext=wcontext;
1237:
1.386 moko 1238: #define RESTORE_CONTEXT \
1239: wcontext=saved_wcontext; \
1240: rcontext=saved_rcontext; \
1.330 misha 1241: method_frame=saved_method_frame;
1242:
1.384 moko 1243: Value& Request::construct(VStateless_class &called_class, const Method &method){
1.363 moko 1244:
1245: if(method.call_type!=Method::CT_STATIC) {
1246: // this is a constructor call
1247: if(Value* result=called_class.create_new_value(fpool)) {
1.319 misha 1248: // some stateless_class creatable derivates
1.363 moko 1249: return *result;
1250: } else
1.401 moko 1251: throw Exception(PARSER_RUNTIME, method.name,
1252: "is not a constructor, system class '%s' can be constructed only implicitly", called_class.type());
1.363 moko 1253: } else
1.422 moko 1254: throw Exception(PARSER_RUNTIME, method.name, "method of '%s' is static and cannot be used as constructor", called_class.type());
1.363 moko 1255: }
1.319 misha 1256:
1.330 misha 1257: Value& Request::get_element(Value& ncontext, const String& name) {
1.376 moko 1258: Value* value=ncontext.get_element(name);
1.388 moko 1259: return *(value ? &process(*value) : VVoid::get());
1.376 moko 1260: }
1261:
1.383 moko 1262: #ifdef FEATURE_GET_ELEMENT4CALL
1.376 moko 1263: Value& Request::get_element4call(Value& ncontext, const String& name) {
1264: Value* value=ncontext.get_element4call(name);
1.388 moko 1265: return *(value ? &process(*value) : VVoid::get());
1.309 paf 1266: }
1.383 moko 1267: #endif
1.309 paf 1268:
1.329 misha 1269: void Request::put_element(Value& ncontext, const String& name, Value* value) {
1.309 paf 1270: // put_element can return property-setting-junction
1.407 moko 1271: if(const VJunction* vjunction=ncontext.put_element(name, value)) {
1272: const Junction& junction = vjunction->junction();
1273: int param_count=junction.method->params_count;
1274:
1275: if(junction.auto_name) {
1276: // default setter
1277: if(param_count!=2)
1278: throw Exception(PARSER_RUNTIME, 0, "default setter method must have TWO parameters (has %d parameters)", param_count);
1279:
1280: Value* params[2] = { new VString(*junction.auto_name), value };
1281:
1282: CONSTRUCTOR_FRAME_ACTION(*junction.method, method_frame /*caller*/, junction.self, {
1283: frame.store_params(params, 2);
1284: Temp_disable_default_setter temp(junction.self);
1285: call(frame);
1286: });
1287: } else {
1288: // setter
1289: if(param_count!=1)
1290: throw Exception(PARSER_RUNTIME, 0, "setter method must have ONE parameter (has %d parameters)", param_count);
1291:
1292: CONSTRUCTOR_FRAME_ACTION(*junction.method, method_frame /*caller*/, junction.self, {
1293: frame.store_params(&value, 1);
1294: call(frame);
1295: });
1.364 moko 1296: }
1.407 moko 1297: }
1.364 moko 1298: }
1299:
1.385 moko 1300: Value& Request::process_getter(Junction& junction) {
1.397 moko 1301: int param_count=junction.method->params_count;
1.364 moko 1302:
1.397 moko 1303: if(junction.auto_name){
1.364 moko 1304: // default getter
1.397 moko 1305: if(param_count>1)
1.422 moko 1306: throw Exception(PARSER_RUNTIME, 0, "default getter method can't have more than 1 parameter (has %d parameters)", param_count);
1.397 moko 1307:
1.364 moko 1308: Value *param;
1.397 moko 1309: METHOD_FRAME_ACTION(*junction.method, method_frame/*caller*/, junction.self, {
1.364 moko 1310:
1.397 moko 1311: if(param_count){
1312: param=new VString(*junction.auto_name);
1313: frame.store_params(¶m, 1);
1314: } // no need for else frame.empty_params()
1315:
1316: Temp_disable_default_getter temp(junction.self);
1317: call(frame);
1318: return frame.result();
1319: });
1.364 moko 1320: } else {
1321: // getter
1.397 moko 1322: if(param_count>0)
1.386 moko 1323: throw Exception(PARSER_RUNTIME, 0, "getter method must have no parameters (has %d parameters)", param_count);
1.364 moko 1324:
1.397 moko 1325: METHOD_FRAME_ACTION(*junction.method, method_frame/*caller*/, junction.self, {
1326: // no need for frame.empty_params()
1327: call(frame);
1328: return frame.result();
1329: });
1.364 moko 1330: }
1.309 paf 1331:
1.34 paf 1332: }
1.70 paf 1333:
1.389 moko 1334: Value& Request::process(Value& input_value) {
1.297 paf 1335: Junction* junction=input_value.get_junction();
1.307 paf 1336: if(junction) {
1337: if(junction->is_getter) { // is it a getter-junction?
1.389 moko 1338: return process(process_getter(*junction));
1.307 paf 1339: }
1340:
1341: if(junction->code) { // is it a code-junction?
1342: // process it
1.385 moko 1343: ValueRef result;
1.336 misha 1344:
1345: DEBUG_PRINT_STR("ja->\n")
1.238 paf 1346:
1.307 paf 1347: if(!junction->method_frame)
1.386 moko 1348: throw Exception(PARSER_RUNTIME, 0, "junction used outside of context");
1.240 paf 1349:
1.330 misha 1350: SAVE_CONTEXT
1.307 paf 1351:
1352: method_frame=junction->method_frame;
1353: rcontext=junction->rcontext;
1354:
1.389 moko 1355: // for code in [] and () wcontext is set 0
1356: // using the fact in decision "which wrapper to use"
1.399 moko 1357: if(junction->wcontext) {
1.389 moko 1358: // {} code wrapper
1.318 misha 1359: VCodeFrame local(*junction->wcontext);
1.307 paf 1360: wcontext=&local;
1361:
1362: // execute it
1.423 moko 1363: recursion_checked_execute(*junction->code);
1.307 paf 1364:
1.318 misha 1365: result=wcontext->result();
1.307 paf 1366: } else {
1.389 moko 1367: // [] or () code wrapper
1.351 misha 1368: WWrapper local(wcontext);
1.307 paf 1369: wcontext=&local;
1370:
1371: // execute it
1.423 moko 1372: recursion_checked_execute(*junction->code);
1.307 paf 1373:
1374: result=wcontext->result();
1375: }
1376:
1.330 misha 1377: RESTORE_CONTEXT
1.207 paf 1378:
1.336 misha 1379: DEBUG_PRINT_STR("<-ja returned")
1380:
1.307 paf 1381: return result;
1382: }
1383:
1.422 moko 1384: // then it is a method-junction, do not explode it
1.307 paf 1385: // just return it as we do for usual objects
1386: }
1387:
1388: return input_value;
1.85 paf 1389: }
1390:
1.332 misha 1391: void Request::process_write(Value& input_value) {
1392: Junction* junction=input_value.get_junction();
1393: if(junction) {
1.375 moko 1394: // no getter-junction check as process_write is called
1395: // to process method arguments, not from get_element
1.332 misha 1396:
1397: if(junction->code) { // is it a code-junction?
1.389 moko 1398: // process it
1.336 misha 1399:
1400: DEBUG_PRINT_STR("ja->\n")
1401:
1.332 misha 1402: if(!junction->method_frame)
1.386 moko 1403: throw Exception(PARSER_RUNTIME, 0, "junction used outside of context");
1.332 misha 1404:
1405: SAVE_CONTEXT
1406:
1407: method_frame=junction->method_frame;
1408: rcontext=junction->rcontext;
1409:
1.389 moko 1410: // for code in [] and () wcontext is set 0
1.332 misha 1411: // using the fact in decision "which wwrapper to use"
1412: #ifdef OPTIMIZE_CALL
1413: if(wcontext==junction->wcontext){
1414: // no wrappers for wcontext
1.423 moko 1415: recursion_checked_execute(*junction->code);
1.332 misha 1416: RESTORE_CONTEXT
1417:
1418: } else
1419: #endif
1420: if(junction->wcontext) {
1.389 moko 1421: // {} code wrapper
1.332 misha 1422: VCodeFrame local(*junction->wcontext);
1423: wcontext=&local;
1424:
1425: // execute it
1.423 moko 1426: recursion_checked_execute(*junction->code);
1.332 misha 1427: RESTORE_CONTEXT
1.396 moko 1428: write(local.result());
1.332 misha 1429: } else {
1.389 moko 1430: // [] or () code wrapper
1.351 misha 1431: WWrapper local(wcontext);
1.332 misha 1432: wcontext=&local;
1433:
1434: // execute it
1.423 moko 1435: recursion_checked_execute(*junction->code);
1.332 misha 1436: RESTORE_CONTEXT
1.396 moko 1437: write(local.result());
1.332 misha 1438: }
1.336 misha 1439:
1440: DEBUG_PRINT_STR("<-ja returned")
1441:
1.332 misha 1442: return;
1443: }
1444:
1.422 moko 1445: // then it is a method-junction, do not explode it
1.332 misha 1446: // just return it as we do for usual objects
1447: }
1448:
1.396 moko 1449: write(input_value);
1.332 misha 1450: }
1451:
1.408 moko 1452: const String* Request::execute_method(VStateless_class& aclass, const String& method_name, Value* optional_param) {
1453: if(const Method *method=aclass.get_method(method_name)){
1454: METHOD_FRAME_ACTION(*method, method_frame/*caller*/, aclass, {
1.317 misha 1455:
1.408 moko 1456: if(optional_param && method->params_count>0) {
1457: frame.store_params(&optional_param, 1);
1458: } else {
1459: frame.empty_params();
1460: }
1.246 paf 1461:
1.408 moko 1462: // prevent non-string writes for better error reporting
1.397 moko 1463: frame.write(frame);
1.408 moko 1464:
1465: call(frame);
1.208 paf 1466:
1.410 moko 1467: Value &result=frame.result();
1468: if(const String* sresult=result.get_string()){
1469: return sresult;
1470: }
1471: result.bark("is '%s', it has no string representation", &method_name);
1.408 moko 1472: });
1473: }
1474: return 0;
1.242 paf 1475: }
1476:
1.408 moko 1477: bool Request::execute_method_if_exists(VStateless_class& aclass, const String& method_name, Value* optional_param) {
1478: if(const Method *method=aclass.get_method(method_name)){
1479: METHOD_FRAME_ACTION(*method, method_frame/*caller*/, aclass, {
1480:
1481: if(optional_param && method->params_count>0) {
1482: frame.store_params(&optional_param, 1);
1483: } else {
1484: frame.empty_params();
1485: }
1.99 paf 1486:
1.408 moko 1487: call(frame);
1488: });
1489: return true;
1490: }
1491: return false;
1.176 parser 1492: }
1.362 misha 1493:
1.417 moko 1494: bool Request::execute_auto_method_if_exists(VStateless_class& aclass, const String& method_name, Value* optional_param) {
1495: if(const Method *method=aclass.get_method(method_name)){
1496: METHOD_FRAME_ACTION(*method, method_frame/*caller*/, aclass, {
1497: Value* two_params[2];
1498:
1499: if (optional_param && method->params_count>1) {
1500: two_params[0] = optional_param;
1501: two_params[1] = new VString(*new String(aclass.type()));
1502: frame.store_params(two_params, 2);
1503: } else if (optional_param && method->params_count>0) {
1504: frame.store_params(&optional_param, 1);
1505: } else {
1506: frame.empty_params();
1507: }
1508:
1509: call(frame);
1510: });
1511: return true;
1512: }
1513: return false;
1514: }
1515:
1.398 moko 1516: const String* Request::get_method_filespec(const Method* method){
1.404 moko 1517: Operation::Origin origin=get_method_origin(method);
1518: return origin.file_no ? get_used_filespec(origin.file_no) : NULL;
1519: }
1520:
1521: const Operation::Origin Request::get_method_origin(const Method* method){
1522: Operation::Origin origin={0, 0, 0};
1523:
1.362 misha 1524: if(ArrayOperation* code=method->parser_code)
1525: if(code){
1.419 moko 1526: for(Array_iterator<Operation> i(*code); i; ){
1.362 misha 1527: switch( i.next().code ){
1528: case OP::OP_CURLY_CODE__STORE_PARAM:
1529: case OP::OP_EXPR_CODE__STORE_PARAM:
1530: case OP::OP_CURLY_CODE__CONSTRUCT:
1531: case OP::OP_NESTED_CODE:
1532: case OP::OP_OBJECT_POOL:
1533: case OP::OP_STRING_POOL:
1534: case OP::OP_CALL:
1535: case OP::OP_CALL__WRITE:
1536: {
1537: i.next(); // skip local ops
1538: i.next(); // skip next opcode
1539: // continue execution
1540: }
1541: case OP::OP_CONSTRUCT_OBJECT:
1542: case OP::OP_CONSTRUCT_OBJECT__WRITE:
1543: case OP::OP_VALUE:
1544: case OP::OP_STRING__WRITE:
1545: case OP::OP_VALUE__GET_CLASS:
1.383 moko 1546: case OP::OP_VALUE__GET_BASE_CLASS:
1.362 misha 1547: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT
1548: case OP::OP_GET_OBJECT_ELEMENT:
1549: case OP::OP_GET_OBJECT_ELEMENT__WRITE:
1550: #endif
1551: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT
1552: case OP::OP_GET_OBJECT_VAR_ELEMENT:
1553: case OP::OP_GET_OBJECT_VAR_ELEMENT__WRITE:
1554: #endif
1555: #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT
1556: case OP::OP_VALUE__GET_ELEMENT:
1557: case OP::OP_VALUE__GET_ELEMENT__WRITE:
1558: case OP::OP_VALUE__GET_ELEMENT_OR_OPERATOR:
1559: case OP::OP_WITH_ROOT__VALUE__GET_ELEMENT:
1560: #endif
1561: #ifdef OPTIMIZE_BYTECODE_GET_SELF_ELEMENT
1562: case OP::OP_WITH_SELF__VALUE__GET_ELEMENT:
1563: case OP::OP_WITH_SELF__VALUE__GET_ELEMENT__WRITE:
1564: #endif
1.377 moko 1565:
1566: #ifdef FEATURE_GET_ELEMENT4CALL
1567: case OP::OP_GET_ELEMENT4CALL:
1568: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT
1569: case OP::OP_GET_OBJECT_ELEMENT4CALL:
1570: #endif
1571: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT
1572: case OP::OP_GET_OBJECT_VAR_ELEMENT4CALL:
1573: #endif
1574: #endif // FEATURE_GET_ELEMENT4CALL
1575:
1.362 misha 1576: #ifdef OPTIMIZE_BYTECODE_CONSTRUCT
1577: case OP::OP_WITH_ROOT__VALUE__CONSTRUCT_EXPR:
1578: case OP::OP_WITH_ROOT__VALUE__CONSTRUCT_VALUE:
1579: case OP::OP_WITH_WRITE__VALUE__CONSTRUCT_EXPR:
1580: case OP::OP_WITH_WRITE__VALUE__CONSTRUCT_VALUE:
1581: case OP::OP_WITH_SELF__VALUE__CONSTRUCT_EXPR:
1582: case OP::OP_WITH_SELF__VALUE__CONSTRUCT_VALUE:
1583: #endif
1584: {
1585: origin=i.next().origin;
1586: break;
1587: }
1.373 moko 1588: default: break;
1.362 misha 1589: }
1590: if(origin.file_no)
1.404 moko 1591: return origin;
1.362 misha 1592: }
1593: }
1.404 moko 1594: return origin;
1.362 misha 1595: }
1596:
E-mail: