|
|
| version 1.394, 2016/11/01 22:39:00 | version 1.417, 2023/11/17 19:12:34 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: executor part of request class. | Parser: executor part of request class. |
| Copyright (c) 2001-2015 Art. Lebedev Studio (http://www.artlebedev.com) | Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru> |
| */ | */ |
| #include "pa_opcode.h" | #include "pa_opcode.h" |
| Line 242 void debug_dump(SAPI_Info& sapi_info, in | Line 242 void debug_dump(SAPI_Info& sapi_info, in |
| #define DEBUG_PRINT_OPS(local_ops) | #define DEBUG_PRINT_OPS(local_ops) |
| #endif | #endif |
| // Request | // Request |
| void Request::execute(ArrayOperation& ops) { | void Request::execute(ArrayOperation& ops) { |
| Line 281 void Request::execute(ArrayOperation& op | Line 280 void Request::execute(ArrayOperation& op |
| DEBUG_PRINT_STRING(name) | DEBUG_PRINT_STRING(name) |
| VStateless_class* vclass=get_class(name); | stack.push(get_class_ref(name)); |
| if(!vclass) | |
| throw Exception(PARSER_RUNTIME, &name, "class is undefined"); | |
| stack.push(*vclass); | |
| break; | break; |
| } | } |
| Line 298 void Request::execute(ArrayOperation& op | Line 293 void Request::execute(ArrayOperation& op |
| DEBUG_PRINT_STRING(name) | DEBUG_PRINT_STRING(name) |
| VStateless_class* vclass=get_class(name); | stack.push(*new VBaseClassWrapper(get_class_ref(name), get_self())); |
| if(!vclass) | |
| throw Exception(PARSER_RUNTIME, &name, "class is undefined"); | |
| stack.push(*new VBaseClassWrapper(*vclass, get_self())); | |
| break; | break; |
| } | } |
| Line 331 void Request::execute(ArrayOperation& op | Line 322 void Request::execute(ArrayOperation& op |
| if(opcode==OP::OP_GET_ELEMENT__SPECIAL){ | if(opcode==OP::OP_GET_ELEMENT__SPECIAL){ |
| stack.push(*value); | stack.push(*value); |
| } else { | } else { |
| write_pass_lang(*value); | write(*value); |
| } | } |
| break; | break; |
| } | } |
| Line 371 void Request::execute(ArrayOperation& op | Line 362 void Request::execute(ArrayOperation& op |
| DEBUG_PRINT_STRING(name) \ | DEBUG_PRINT_STRING(name) \ |
| Value& value=stack.pop().value(); \ | Value& value=stack.pop().value(); \ |
| put_element( context, name, vvalue ); \ | put_element( context, name, vvalue ); \ |
| break; \ | goto check_skip; \ |
| } | } |
| #define DO_CONSTRUCT_VALUE(context) DO_CONSTRUCT(context, &value) | #define DO_CONSTRUCT_VALUE(context) DO_CONSTRUCT(context, &value) |
| #define DO_CONSTRUCT_EXPR(context) { \ | #define DO_CONSTRUCT_EXPR(context) { \ |
| Line 414 void Request::execute(ArrayOperation& op | Line 405 void Request::execute(ArrayOperation& op |
| Value& ncontext=stack.pop().value(); | Value& ncontext=stack.pop().value(); |
| #endif | #endif |
| put_element(ncontext, name, &value); | put_element(ncontext, name, &value); |
| goto check_skip; | |
| break; | |
| } | } |
| case OP::OP_CONSTRUCT_EXPR: | case OP::OP_CONSTRUCT_EXPR: |
| Line 431 void Request::execute(ArrayOperation& op | Line 421 void Request::execute(ArrayOperation& op |
| #endif | #endif |
| Value& value=expr.as_expr_result(); | Value& value=expr.as_expr_result(); |
| put_element(ncontext, name, &value); | put_element(ncontext, name, &value); |
| break; | goto check_skip; |
| } | } |
| case OP::OP_CURLY_CODE__CONSTRUCT: | case OP::OP_CURLY_CODE__CONSTRUCT: |
| Line 452 void Request::execute(ArrayOperation& op | Line 442 void Request::execute(ArrayOperation& op |
| const String& name=stack.pop().string(); debug_name=&name; | const String& name=stack.pop().string(); debug_name=&name; |
| Value& ncontext=stack.pop().value(); | Value& ncontext=stack.pop().value(); |
| if(const VJunction* vjunction=ncontext.put_element(name, &value)) | if(const VJunction* vjunction=ncontext.put_element(name, &value)) |
| if(vjunction!=PUT_ELEMENT_REPLACED_ELEMENT) | |
| throw Exception(PARSER_RUNTIME, 0, "property value can not be code, use [] or () brackets"); | throw Exception(PARSER_RUNTIME, 0, "property value can not be code, use [] or () brackets"); |
| break; | break; |
| } | } |
| case OP::OP_NESTED_CODE: | case OP::OP_NESTED_CODE: |
| Line 469 void Request::execute(ArrayOperation& op | Line 458 void Request::execute(ArrayOperation& op |
| case OP::OP_WRITE_VALUE: | case OP::OP_WRITE_VALUE: |
| { | { |
| Value& value=stack.pop().value(); | Value& value=stack.pop().value(); |
| write_pass_lang(value); | write(value); |
| break; | break; |
| } | } |
| case OP::OP_WRITE_EXPR_RESULT: | case OP::OP_WRITE_EXPR_RESULT: |
| Line 487 void Request::execute(ArrayOperation& op | Line 476 void Request::execute(ArrayOperation& op |
| DEBUG_PRINT_STRING(string_value) | DEBUG_PRINT_STRING(string_value) |
| write_no_lang(string_value); | write(string_value); |
| break; | break; |
| } | } |
| Line 506 void Request::execute(ArrayOperation& op | Line 495 void Request::execute(ArrayOperation& op |
| } | } |
| Value& value=get_element(*rcontext, name); | Value& value=get_element(*rcontext, name); |
| stack.push(value); | stack.push(value); |
| break; | goto check_skip; |
| } | } |
| #else | #else |
| case OP::OP_GET_ELEMENT_OR_OPERATOR: | case OP::OP_GET_ELEMENT_OR_OPERATOR: |
| Line 520 void Request::execute(ArrayOperation& op | Line 509 void Request::execute(ArrayOperation& op |
| } | } |
| Value& value=get_element(ncontext, name); | Value& value=get_element(ncontext, name); |
| stack.push(value); | stack.push(value); |
| break; | goto check_skip; |
| } | } |
| #endif | #endif |
| Line 535 void Request::execute(ArrayOperation& op | Line 524 void Request::execute(ArrayOperation& op |
| const String& field_name=*i.next().value->get_string(); debug_name=&field_name; \ | const String& field_name=*i.next().value->get_string(); debug_name=&field_name; \ |
| DEBUG_PRINT_STRING(field_name) \ | DEBUG_PRINT_STRING(field_name) \ |
| code; \ | code; \ |
| break; \ | goto check_skip; \ |
| } | } |
| case OP::OP_GET_OBJECT_ELEMENT: DO_GET_OBJECT_ELEMENT({ | case OP::OP_GET_OBJECT_ELEMENT: DO_GET_OBJECT_ELEMENT({ |
| Line 544 void Request::execute(ArrayOperation& op | Line 533 void Request::execute(ArrayOperation& op |
| }) | }) |
| case OP::OP_GET_OBJECT_ELEMENT__WRITE: DO_GET_OBJECT_ELEMENT({ | case OP::OP_GET_OBJECT_ELEMENT__WRITE: DO_GET_OBJECT_ELEMENT({ |
| Value& value=get_element(object, field_name); | Value& value=get_element(object, field_name); |
| write_pass_lang(value); | write(value); |
| }) | }) |
| #ifdef FEATURE_GET_ELEMENT4CALL | #ifdef FEATURE_GET_ELEMENT4CALL |
| case OP::OP_GET_OBJECT_ELEMENT4CALL: DO_GET_OBJECT_ELEMENT({ | case OP::OP_GET_OBJECT_ELEMENT4CALL: DO_GET_OBJECT_ELEMENT({ |
| Line 566 void Request::execute(ArrayOperation& op | Line 555 void Request::execute(ArrayOperation& op |
| DEBUG_PRINT_STRING(var_name) \ | DEBUG_PRINT_STRING(var_name) \ |
| const String* field=&get_element(*rcontext, var_name).as_string(); \ | const String* field=&get_element(*rcontext, var_name).as_string(); \ |
| code; \ | code; \ |
| break; \ | goto check_skip; \ |
| } | } |
| case OP::OP_GET_OBJECT_VAR_ELEMENT: DO_GET_OBJECT_VAR_ELEMENT({ | case OP::OP_GET_OBJECT_VAR_ELEMENT: DO_GET_OBJECT_VAR_ELEMENT({ |
| Line 575 void Request::execute(ArrayOperation& op | Line 564 void Request::execute(ArrayOperation& op |
| }) | }) |
| case OP::OP_GET_OBJECT_VAR_ELEMENT__WRITE: DO_GET_OBJECT_VAR_ELEMENT({ | case OP::OP_GET_OBJECT_VAR_ELEMENT__WRITE: DO_GET_OBJECT_VAR_ELEMENT({ |
| Value& value=get_element(object, *field); | Value& value=get_element(object, *field); |
| write_pass_lang(value); | write(value); |
| }) | }) |
| #ifdef FEATURE_GET_ELEMENT4CALL | #ifdef FEATURE_GET_ELEMENT4CALL |
| case OP::OP_GET_OBJECT_VAR_ELEMENT4CALL: DO_GET_OBJECT_VAR_ELEMENT({ | case OP::OP_GET_OBJECT_VAR_ELEMENT4CALL: DO_GET_OBJECT_VAR_ELEMENT({ |
| Line 591 void Request::execute(ArrayOperation& op | Line 580 void Request::execute(ArrayOperation& op |
| Value& ncontext=stack.pop().value(); | Value& ncontext=stack.pop().value(); |
| Value& value=get_element(ncontext, name); | Value& value=get_element(ncontext, name); |
| stack.push(value); | stack.push(value); |
| break; | goto check_skip; |
| } | } |
| #ifdef FEATURE_GET_ELEMENT4CALL | #ifdef FEATURE_GET_ELEMENT4CALL |
| Line 601 void Request::execute(ArrayOperation& op | Line 590 void Request::execute(ArrayOperation& op |
| Value& ncontext=stack.pop().value(); | Value& ncontext=stack.pop().value(); |
| Value& value=get_element4call(ncontext, name); | Value& value=get_element4call(ncontext, name); |
| stack.push(value); | stack.push(value); |
| break; | goto check_skip; |
| } | } |
| #endif | #endif |
| Line 610 void Request::execute(ArrayOperation& op | Line 599 void Request::execute(ArrayOperation& op |
| const String& name=stack.pop().string(); debug_name=&name; | const String& name=stack.pop().string(); debug_name=&name; |
| Value& ncontext=stack.pop().value(); | Value& ncontext=stack.pop().value(); |
| Value& value=get_element(ncontext, name); | Value& value=get_element(ncontext, name); |
| write_pass_lang(value); | write(value); |
| break; | goto check_skip; |
| } | } |
| #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT | #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT |
| Line 624 void Request::execute(ArrayOperation& op | Line 613 void Request::execute(ArrayOperation& op |
| Value& value=get_element(*rcontext, name); | Value& value=get_element(*rcontext, name); |
| stack.push(value); | stack.push(value); |
| break; | goto check_skip; |
| } | } |
| case OP::OP_VALUE__GET_ELEMENT__WRITE: | case OP::OP_VALUE__GET_ELEMENT__WRITE: |
| Line 635 void Request::execute(ArrayOperation& op | Line 624 void Request::execute(ArrayOperation& op |
| DEBUG_PRINT_STRING(name) | DEBUG_PRINT_STRING(name) |
| Value& value=get_element(*rcontext, name); | Value& value=get_element(*rcontext, name); |
| write_pass_lang(value); | write(value); |
| break; | goto check_skip; |
| } | } |
| case OP::OP_WITH_ROOT__VALUE__GET_ELEMENT: | case OP::OP_WITH_ROOT__VALUE__GET_ELEMENT: |
| Line 648 void Request::execute(ArrayOperation& op | Line 637 void Request::execute(ArrayOperation& op |
| Value& value=get_element(*method_frame, name); | Value& value=get_element(*method_frame, name); |
| stack.push(value); | stack.push(value); |
| break; | goto check_skip; |
| } | } |
| #endif | #endif |
| Line 666 void Request::execute(ArrayOperation& op | Line 655 void Request::execute(ArrayOperation& op |
| if(opcode==OP::OP_WITH_SELF__VALUE__GET_ELEMENT){ | if(opcode==OP::OP_WITH_SELF__VALUE__GET_ELEMENT){ |
| stack.push(value); | stack.push(value); |
| } else { | } else { |
| write_pass_lang(value); | write(value); |
| } | } |
| break; | goto check_skip; |
| } | } |
| #endif | #endif |
| case OP::OP_OBJECT_POOL: | case OP::OP_OBJECT_POOL: |
| { | { |
| debug_name=0; | |
| ArrayOperation& local_ops=*i.next().ops; | ArrayOperation& local_ops=*i.next().ops; |
| WContext *saved_wcontext=wcontext; | WContext *saved_wcontext=wcontext; |
| Line 686 void Request::execute(ArrayOperation& op | Line 677 void Request::execute(ArrayOperation& op |
| execute(local_ops); | execute(local_ops); |
| stack.push(wcontext->result()); | stack.push((Value&)wcontext->result()); |
| wcontext=saved_wcontext; | wcontext=saved_wcontext; |
| break; | goto check_skip; |
| } | } |
| case OP::OP_STRING_POOL: | case OP::OP_STRING_POOL: |
| Line 708 void Request::execute(ArrayOperation& op | Line 700 void Request::execute(ArrayOperation& op |
| stack.push(*value); | stack.push(*value); |
| wcontext=saved_wcontext; | wcontext=saved_wcontext; |
| break; | goto check_skip; |
| } | } |
| // CALL | // CALL |
| Line 742 void Request::execute(ArrayOperation& op | Line 734 void Request::execute(ArrayOperation& op |
| break; | break; |
| } | } |
| #define METHOD_FRAME_ACTION(action) \ | #define METHOD_PARAMS_ACTION(action) \ |
| if(local_ops){ \ | if(local_ops){ \ |
| size_t first = stack.top_index(); \ | size_t first = stack.top_index(); \ |
| execute(*local_ops); \ | execute(*local_ops); \ |
| frame.store_params((Value**)stack.ptr(first), stack.top_index()-first); \ | if(!fskip){ \ |
| action; \ | frame.store_params((Value**)stack.ptr(first), stack.top_index()-first); \ |
| action; \ | |
| } \ | |
| stack.set_top_index(first); \ | stack.set_top_index(first); \ |
| } else { \ | } else { \ |
| frame.empty_params(); \ | frame.empty_params(); \ |
| Line 773 void Request::execute(ArrayOperation& op | Line 767 void Request::execute(ArrayOperation& op |
| Value *result; | Value *result; |
| { | { |
| VExpressionFrame frame(*junction->method, method_frame, junction->self); | EXPRESSION_FRAME_ACTION(*junction->method, method_frame, junction->self, { |
| METHOD_FRAME_ACTION(call_expression(frame)); | METHOD_PARAMS_ACTION(call(frame)); |
| result=&frame.result(); | result=&frame.result(); |
| // VMethodFrame desctructor deletes junctions in stack params here | // desctructor deletes junctions in stack params here |
| }); | |
| } | } |
| stack.push(*result); | stack.push(*result); |
| DEBUG_PRINT_STR("<-returned") | DEBUG_PRINT_STR("<-returned") |
| goto check_skip; | |
| if(get_skip()) | |
| return; | |
| if(get_interrupted()) { | |
| set_interrupted(false); | |
| throw Exception("parser.interrupted", 0, "execution stopped"); | |
| } | |
| break; | |
| } | } |
| case OP::OP_CALL__WRITE: | case OP::OP_CALL__WRITE: |
| Line 815 void Request::execute(ArrayOperation& op | Line 803 void Request::execute(ArrayOperation& op |
| size_t first = stack.top_index(); | size_t first = stack.top_index(); |
| execute(*local_ops); | execute(*local_ops); |
| MethodParams method_params; | if(!fskip){ |
| method_params.store_params((Value**)stack.ptr(first), stack.top_index()-first); | MethodParams method_params; |
| method.check_actual_numbered_params(junction->self, &method_params); | method_params.store_params((Value**)stack.ptr(first), stack.top_index()-first); |
| method.native_code(*this, method_params); // execute it | method.check_actual_numbered_params(junction->self, &method_params); |
| method.native_code(*this, method_params); // execute it | |
| } | |
| stack.set_top_index(first); | stack.set_top_index(first); |
| } else { | } else { |
| Line 827 void Request::execute(ArrayOperation& op | Line 817 void Request::execute(ArrayOperation& op |
| method.native_code(*this, method_params); // execute it | method.native_code(*this, method_params); // execute it |
| } | } |
| } else if(method.call_optimization==Method::CO_WITHOUT_WCONTEXT){ | } else if(method.call_optimization==Method::CO_WITHOUT_WCONTEXT){ |
| VMethodFrame frame(method, method_frame, junction->self); | METHOD_FRAME_ACTION(method, method_frame, junction->self, { |
| METHOD_FRAME_ACTION(call_write(frame)); | METHOD_PARAMS_ACTION(call_write(frame)) |
| }); | |
| } else | } else |
| #endif // OPTIMIZE_CALL | #endif // OPTIMIZE_CALL |
| { | { |
| VMethodFrame frame(method, method_frame, junction->self); | METHOD_FRAME_ACTION(method, method_frame, junction->self, { |
| METHOD_FRAME_ACTION(call(frame)); | METHOD_PARAMS_ACTION(call(frame)); |
| write_pass_lang(frame.result()); | write(frame.result()); |
| }); | |
| } | } |
| DEBUG_PRINT_STR("<-returned") | DEBUG_PRINT_STR("<-returned") |
| goto check_skip; | |
| if(get_skip()) | |
| return; | |
| if(get_interrupted()) { | |
| set_interrupted(false); | |
| throw Exception("parser.interrupted", 0, "execution stopped"); | |
| } | |
| break; | |
| } | } |
| case OP::OP_CONSTRUCT_OBJECT: | case OP::OP_CONSTRUCT_OBJECT: |
| Line 857 void Request::execute(ArrayOperation& op | Line 842 void Request::execute(ArrayOperation& op |
| DEBUG_PRINT_STRING(class_name) | DEBUG_PRINT_STRING(class_name) |
| VStateless_class* vclass=get_class(class_name); | VStateless_class& vclass=get_class_ref(class_name); |
| if(!vclass) | |
| throw Exception(PARSER_RUNTIME, &class_name, "class is undefined"); | |
| debug_origin=i.next().origin; | debug_origin=i.next().origin; |
| Value& vconstructor_name=*i.next().value; | Value& vconstructor_name=*i.next().value; |
| Line 867 void Request::execute(ArrayOperation& op | Line 850 void Request::execute(ArrayOperation& op |
| DEBUG_PRINT_STRING(constructor_name) | DEBUG_PRINT_STRING(constructor_name) |
| Junction* constructor_junction=get_element(*vclass, constructor_name).get_junction(); | Junction* constructor_junction=get_element(vclass, constructor_name).get_junction(); |
| if(!constructor_junction) | if(!constructor_junction) |
| throw Exception(PARSER_RUNTIME, &constructor_name, "constructor must be declared in class '%s'", vclass->type()); | throw Exception(PARSER_RUNTIME, &constructor_name, "constructor must be declared in class '%s'", vclass.type()); |
| ArrayOperation* local_ops=i.next().ops; | ArrayOperation* local_ops=i.next().ops; |
| DEBUG_PRINT_OPS(local_ops) | DEBUG_PRINT_OPS(local_ops) |
| Line 877 void Request::execute(ArrayOperation& op | Line 860 void Request::execute(ArrayOperation& op |
| Value *result; | Value *result; |
| { | { |
| Value& object=construct(*vclass, *constructor_junction->method); | Value& object=construct(vclass, *constructor_junction->method); |
| VConstructorFrame frame(*constructor_junction->method, method_frame, object); | CONSTRUCTOR_FRAME_ACTION(*constructor_junction->method, method_frame, object, { |
| METHOD_FRAME_ACTION(call(frame)); | METHOD_PARAMS_ACTION(call(frame)); |
| object.enable_default_setter(); | object.enable_default_setter(); |
| result=&frame.result(); | result=&frame.result(); |
| // VMethodFrame desctructor deletes junctions in stack params here | // desctructor deletes junctions in stack params here |
| }); | |
| } | } |
| if(opcode==OP::OP_CONSTRUCT_OBJECT) | if(opcode==OP::OP_CONSTRUCT_OBJECT) |
| stack.push(*result); | stack.push(*result); |
| else | else |
| write_pass_lang(*result); | write(*result); |
| DEBUG_PRINT_STR("<-returned") | DEBUG_PRINT_STR("<-returned") |
| break; | goto check_skip; |
| } | } |
| // expression ops: unary | // expression ops: unary |
| Line 934 void Request::execute(ArrayOperation& op | Line 918 void Request::execute(ArrayOperation& op |
| case OP::OP_FEXISTS: | case OP::OP_FEXISTS: |
| { | { |
| Value& a=stack.pop().value(); | Value& a=stack.pop().value(); |
| Value& value=VBool::get(file_exist(absolute(a.as_string()))); | Value& value=VBool::get(file_exist(full_disk_path(a.as_string()))); |
| stack.push(value); | stack.push(value); |
| break; | break; |
| } | } |
| case OP::OP_DEXISTS: | case OP::OP_DEXISTS: |
| { | { |
| Value& a=stack.pop().value(); | Value& a=stack.pop().value(); |
| Value& value=VBool::get(dir_exists(absolute(a.as_string()))); | Value& value=VBool::get(dir_exists(full_disk_path(a.as_string()))); |
| stack.push(value); | stack.push(value); |
| break; | break; |
| } | } |
| // expression ops: binary | // expression ops: binary |
| case OP::OP_SUB: | case OP::OP_SUB: |
| { | { |
| Value& b=stack.pop().value(); Value& a=stack.pop().value(); | volatile double b_double=stack.pop().value().as_double(); |
| Value& value=*new VDouble(a.as_double() - b.as_double()); | volatile double a_double=stack.pop().value().as_double(); |
| Value& value=*new VDouble(a_double - b_double); | |
| stack.push(value); | stack.push(value); |
| break; | break; |
| } | } |
| case OP::OP_ADD: | case OP::OP_ADD: |
| { | { |
| Value& b=stack.pop().value(); Value& a=stack.pop().value(); | volatile double b_double=stack.pop().value().as_double(); |
| Value& value=*new VDouble(a.as_double() + b.as_double()); | volatile double a_double=stack.pop().value().as_double(); |
| Value& value=*new VDouble(a_double + b_double); | |
| stack.push(value); | stack.push(value); |
| break; | break; |
| } | } |
| case OP::OP_MUL: | case OP::OP_MUL: |
| { | { |
| Value& b=stack.pop().value(); Value& a=stack.pop().value(); | volatile double b_double=stack.pop().value().as_double(); |
| Value& value=*new VDouble(a.as_double() * b.as_double()); | volatile double a_double=stack.pop().value().as_double(); |
| Value& value=*new VDouble(a_double * b_double); | |
| stack.push(value); | stack.push(value); |
| break; | break; |
| } | } |
| case OP::OP_DIV: | case OP::OP_DIV: |
| { | { |
| Value& b=stack.pop().value(); Value& a=stack.pop().value(); | volatile double b_double=stack.pop().value().as_double(); |
| volatile double a_double=stack.pop().value().as_double(); | |
| double a_double=a.as_double(); | |
| double b_double=b.as_double(); | |
| if(b_double == 0) { | if(b_double == 0) { |
| //const String* problem_source=b.as_string(); | //const String* problem_source=b.as_string(); |
| Line 984 void Request::execute(ArrayOperation& op | Line 972 void Request::execute(ArrayOperation& op |
| stack.push(value); | stack.push(value); |
| break; | break; |
| } | } |
| case OP::OP_MOD: | case OP::OP_MOD: |
| { | { |
| Value& b=stack.pop().value(); Value& a=stack.pop().value(); | volatile double b_double=stack.pop().value().as_double(); |
| volatile double a_double=stack.pop().value().as_double(); | |
| double a_double=a.as_double(); | |
| double b_double=b.as_double(); | |
| if(b_double == 0) { | if(b_double == 0) { |
| //const String* problem_source=b.as_string(); | //const String* problem_source=b.as_string(); |
| Line 1002 void Request::execute(ArrayOperation& op | Line 988 void Request::execute(ArrayOperation& op |
| } | } |
| case OP::OP_INTDIV: | case OP::OP_INTDIV: |
| { | { |
| Value& b=stack.pop().value(); Value& a=stack.pop().value(); | int b_int=stack.pop().value().as_int(); |
| int a_int=stack.pop().value().as_int(); | |
| int a_int=a.as_int(); | |
| int b_int=b.as_int(); | |
| if(b_int == 0) { | if(b_int == 0) { |
| //const String* problem_source=b.as_string(); | //const String* problem_source=b.as_string(); |
| Line 1073 void Request::execute(ArrayOperation& op | Line 1057 void Request::execute(ArrayOperation& op |
| result=false; | result=false; |
| Value& value=VBool::get(result); | Value& value=VBool::get(result); |
| stack.push(value); | stack.push(value); |
| break; | goto check_skip; |
| } | } |
| case OP::OP_LOG_OR: | case OP::OP_LOG_OR: |
| { | { |
| Line 1088 void Request::execute(ArrayOperation& op | Line 1072 void Request::execute(ArrayOperation& op |
| } | } |
| Value& value=VBool::get(result); | Value& value=VBool::get(result); |
| stack.push(value); | stack.push(value); |
| break; | goto check_skip; |
| } | } |
| case OP::OP_LOG_XOR: | case OP::OP_LOG_XOR: |
| { | { |
| Line 1194 void Request::execute(ArrayOperation& op | Line 1178 void Request::execute(ArrayOperation& op |
| stack.push(value); | stack.push(value); |
| break; | break; |
| } | } |
| default: | default: |
| throw Exception(0, 0, "invalid opcode %d", opcode); | { |
| throw Exception(0, 0, "invalid opcode %d", opcode); | |
| } | |
| check_skip: | |
| { | |
| if(fskip){ | |
| if(fskip==Request::SKIP_INTERRUPTED){ | |
| set_skip(Request::SKIP_NOTHING); | |
| throw Exception("parser.interrupted", 0, "execution stopped"); | |
| } | |
| return; | |
| } | |
| break; | |
| } | |
| } | } |
| } | } |
| } catch(const Exception&) { | } catch(const Exception&) { |
| Line 1225 Value& Request::construct(VStateless_cla | Line 1221 Value& Request::construct(VStateless_cla |
| // some stateless_class creatable derivates | // some stateless_class creatable derivates |
| return *result; | return *result; |
| } else | } else |
| throw Exception(PARSER_RUNTIME, | throw Exception(PARSER_RUNTIME, method.name, |
| 0, //&frame.name(), | "is not a constructor, system class '%s' can be constructed only implicitly", called_class.type()); |
| "is not a constructor, system class '%s' can be constructed only implicitly", | |
| called_class.type()); | |
| } else | } else |
| throw Exception(PARSER_RUNTIME, 0, "method is static and can not be used as constructor"); | throw Exception(PARSER_RUNTIME, method.name, "method of '%s' is static and can not be used as constructor", called_class.type()); |
| } | |
| inline void do_call(VMethodFrame& frame, Request &r){ | |
| Value& self=frame.self(); | |
| const Method& method=frame.method; | |
| Method::Call_type call_type=self.get_class()==&self ? Method::CT_STATIC : Method::CT_DYNAMIC; | |
| if(method.call_type==Method::CT_ANY || method.call_type==call_type) { // allowed call type? | |
| if(method.native_code) { // native code? | |
| method.check_actual_numbered_params(self, frame.numbered_params()); | |
| method.native_code(r, *frame.numbered_params()); // execute it | |
| } else // parser code, execute it | |
| r.recoursion_checked_execute(*method.parser_code); | |
| } else | |
| throw Exception(PARSER_RUNTIME, 0, "is not allowed to be called %s", call_type==Method::CT_STATIC ? "statically" : "dynamically"); | |
| } | |
| void Request::call(VMethodFrame& frame){ | |
| SAVE_CONTEXT | |
| rcontext=wcontext=method_frame=&frame; | |
| do_call(frame, *this); | |
| RESTORE_CONTEXT | |
| } | |
| void Request::call_expression(VMethodFrame& frame){ | |
| SAVE_CONTEXT | |
| rcontext=wcontext=method_frame=&frame; | |
| do_call(frame, *this); | |
| RESTORE_CONTEXT | |
| } | |
| void Request::call_write(VMethodFrame& frame){ | |
| VMethodFrame *saved_method_frame=method_frame; | |
| Value* saved_rcontext=rcontext; | |
| rcontext=method_frame=&frame; | |
| do_call(frame, *this); | |
| rcontext=saved_rcontext; | |
| method_frame=saved_method_frame; | |
| } | } |
| Value& Request::get_element(Value& ncontext, const String& name) { | Value& Request::get_element(Value& ncontext, const String& name) { |
| Line 1294 Value& Request::get_element4call(Value& | Line 1241 Value& Request::get_element4call(Value& |
| void Request::put_element(Value& ncontext, const String& name, Value* value) { | void Request::put_element(Value& ncontext, const String& name, Value* value) { |
| // put_element can return property-setting-junction | // put_element can return property-setting-junction |
| if(const VJunction* vjunction=ncontext.put_element(name, value)) | if(const VJunction* vjunction=ncontext.put_element(name, value)) { |
| if(vjunction!=PUT_ELEMENT_REPLACED_ELEMENT) { | const Junction& junction = vjunction->junction(); |
| const Junction& junction = vjunction->junction(); | int param_count=junction.method->params_count; |
| VConstructorFrame frame(*junction.method, method_frame /*caller*/, junction.self); | |
| if(junction.auto_name) { | |
| size_t param_count=frame.method_params_count(); | // default setter |
| if(param_count!=2) | |
| if(junction.auto_name){ | throw Exception(PARSER_RUNTIME, 0, "default setter method must have TWO parameters (has %d parameters)", param_count); |
| // default setter | |
| if(param_count!=2) | |
| throw Exception(PARSER_RUNTIME, 0, "default setter method must have TWO parameters (has %d parameters)", param_count); | |
| Value* params[2] = { new VString(*junction.auto_name), value }; | Value* params[2] = { new VString(*junction.auto_name), value }; |
| frame.store_params(params, 2); | |
| CONSTRUCTOR_FRAME_ACTION(*junction.method, method_frame /*caller*/, junction.self, { | |
| frame.store_params(params, 2); | |
| Temp_disable_default_setter temp(junction.self); | Temp_disable_default_setter temp(junction.self); |
| execute_method(frame); | call(frame); |
| } else { | }); |
| // setter | } else { |
| if(param_count!=1) | // setter |
| throw Exception(PARSER_RUNTIME, 0, "setter method must have ONE parameter (has %d parameters)", param_count); | if(param_count!=1) |
| throw Exception(PARSER_RUNTIME, 0, "setter method must have ONE parameter (has %d parameters)", param_count); | |
| CONSTRUCTOR_FRAME_ACTION(*junction.method, method_frame /*caller*/, junction.self, { | |
| frame.store_params(&value, 1); | frame.store_params(&value, 1); |
| execute_method(frame); | call(frame); |
| } | }); |
| } | } |
| } | |
| } | } |
| Value& Request::process_getter(Junction& junction) { | Value& Request::process_getter(Junction& junction) { |
| VMethodFrame frame(*junction.method, method_frame/*caller*/, junction.self); | int param_count=junction.method->params_count; |
| size_t param_count=frame.method_params_count(); | |
| if(junction.auto_name){ | if(junction.auto_name){ |
| // default getter | // default getter |
| Value *param; | if(param_count>1) |
| throw Exception(PARSER_RUNTIME, 0, "default getter method can't have more then 1 parameter (has %d parameters)", param_count); | |
| if(param_count){ | Value *param; |
| if(param_count>1) | METHOD_FRAME_ACTION(*junction.method, method_frame/*caller*/, junction.self, { |
| throw Exception(PARSER_RUNTIME, 0, "default getter method can't have more then 1 parameter (has %d parameters)", param_count); | |
| param=new VString(*junction.auto_name); | |
| frame.store_params(¶m, 1); | |
| } // no need for else frame.empty_params() | |
| Temp_disable_default_getter temp(junction.self); | if(param_count){ |
| execute_method(frame); | param=new VString(*junction.auto_name); |
| frame.store_params(¶m, 1); | |
| } // no need for else frame.empty_params() | |
| Temp_disable_default_getter temp(junction.self); | |
| call(frame); | |
| return frame.result(); | |
| }); | |
| } else { | } else { |
| // getter | // getter |
| if(param_count!=0) | if(param_count>0) |
| throw Exception(PARSER_RUNTIME, 0, "getter method must have no parameters (has %d parameters)", param_count); | throw Exception(PARSER_RUNTIME, 0, "getter method must have no parameters (has %d parameters)", param_count); |
| // no need for frame.empty_params() | METHOD_FRAME_ACTION(*junction.method, method_frame/*caller*/, junction.self, { |
| execute_method(frame); | // no need for frame.empty_params() |
| call(frame); | |
| return frame.result(); | |
| }); | |
| } | } |
| return frame.result(); | |
| } | } |
| Value& Request::process(Value& input_value) { | Value& Request::process(Value& input_value) { |
| Line 1374 Value& Request::process(Value& input_val | Line 1327 Value& Request::process(Value& input_val |
| // for code in [] and () wcontext is set 0 | // for code in [] and () wcontext is set 0 |
| // using the fact in decision "which wrapper to use" | // using the fact in decision "which wrapper to use" |
| bool using_code_frame=junction->wcontext; | if(junction->wcontext) { |
| if(using_code_frame) { | |
| // {} code wrapper | // {} code wrapper |
| VCodeFrame local(*junction->wcontext); | VCodeFrame local(*junction->wcontext); |
| wcontext=&local; | wcontext=&local; |
| Line 1446 void Request::process_write(Value& input | Line 1398 void Request::process_write(Value& input |
| // execute it | // execute it |
| recoursion_checked_execute(*junction->code); | recoursion_checked_execute(*junction->code); |
| RESTORE_CONTEXT | RESTORE_CONTEXT |
| write_pass_lang(local.result()); | write(local.result()); |
| } else { | } else { |
| // [] or () code wrapper | // [] or () code wrapper |
| WWrapper local(wcontext); | WWrapper local(wcontext); |
| Line 1455 void Request::process_write(Value& input | Line 1407 void Request::process_write(Value& input |
| // execute it | // execute it |
| recoursion_checked_execute(*junction->code); | recoursion_checked_execute(*junction->code); |
| RESTORE_CONTEXT | RESTORE_CONTEXT |
| write_pass_lang(local.result()); | write(local.result()); |
| } | } |
| DEBUG_PRINT_STR("<-ja returned") | DEBUG_PRINT_STR("<-ja returned") |
| Line 1467 void Request::process_write(Value& input | Line 1419 void Request::process_write(Value& input |
| // just return it as we do for usual objects | // just return it as we do for usual objects |
| } | } |
| write_pass_lang(input_value); | write(input_value); |
| } | } |
| void Request::execute_method(VMethodFrame& aframe) { | const String* Request::execute_method(VStateless_class& aclass, const String& method_name, Value* optional_param) { |
| SAVE_CONTEXT | if(const Method *method=aclass.get_method(method_name)){ |
| METHOD_FRAME_ACTION(*method, method_frame/*caller*/, aclass, { | |
| // initialize contexts | |
| rcontext=wcontext=method_frame=&aframe; | if(optional_param && method->params_count>0) { |
| frame.store_params(&optional_param, 1); | |
| // execute! | } else { |
| recoursion_checked_execute(*aframe.method.parser_code); | frame.empty_params(); |
| } | |
| // prevent non-string writes for better error reporting | |
| frame.write(frame); | |
| call(frame); | |
| RESTORE_CONTEXT | Value &result=frame.result(); |
| if(const String* sresult=result.get_string()){ | |
| return sresult; | |
| } | |
| result.bark("is '%s', it has no string representation", &method_name); | |
| }); | |
| } | |
| return 0; | |
| } | } |
| const String* Request::execute_method(Value& aself, const Method& method, Value* optional_param, bool do_return_string) { | bool Request::execute_method_if_exists(VStateless_class& aclass, const String& method_name, Value* optional_param) { |
| if(const Method *method=aclass.get_method(method_name)){ | |
| METHOD_FRAME_ACTION(*method, method_frame/*caller*/, aclass, { | |
| VMethodFrame local_frame(method, method_frame/*caller*/, aself); | if(optional_param && method->params_count>0) { |
| frame.store_params(&optional_param, 1); | |
| } else { | |
| frame.empty_params(); | |
| } | |
| if(optional_param && local_frame.method_params_count()>0) { | call(frame); |
| local_frame.store_params(&optional_param, 1); | }); |
| } else { | return true; |
| local_frame.empty_params(); | |
| } | } |
| return false; | |
| // prevent non-string writes for better error reporting | |
| if(do_return_string) | |
| local_frame.write(local_frame); | |
| execute_method(local_frame); | |
| return do_return_string ? local_frame.get_string() : 0; | |
| } | } |
| Request::Execute_nonvirtual_method_result | bool Request::execute_auto_method_if_exists(VStateless_class& aclass, const String& method_name, Value* optional_param) { |
| Request::execute_nonvirtual_method(VStateless_class& aclass, const String& method_name, VString* optional_param, bool do_return_string) { | if(const Method *method=aclass.get_method(method_name)){ |
| Execute_nonvirtual_method_result result; | METHOD_FRAME_ACTION(*method, method_frame/*caller*/, aclass, { |
| result.method=aclass.get_method(method_name); | Value* two_params[2]; |
| if(result.method) | |
| result.string=execute_method(aclass, *result.method, optional_param, do_return_string); | if (optional_param && method->params_count>1) { |
| return result; | two_params[0] = optional_param; |
| two_params[1] = new VString(*new String(aclass.type())); | |
| frame.store_params(two_params, 2); | |
| } else if (optional_param && method->params_count>0) { | |
| frame.store_params(&optional_param, 1); | |
| } else { | |
| frame.empty_params(); | |
| } | |
| call(frame); | |
| }); | |
| return true; | |
| } | |
| return false; | |
| } | } |
| const String* Request::execute_virtual_method(Value& aself, const String& method_name) { | const String* Request::get_method_filespec(const Method* method){ |
| if(Value* value=aself.get_element(method_name)) | Operation::Origin origin=get_method_origin(method); |
| if(Junction* junction=value->get_junction()) | return origin.file_no ? get_used_filespec(origin.file_no) : NULL; |
| if(const Method *method=junction->method) | |
| return execute_method(aself, *method, 0/*no params*/, true); | |
| return 0; | |
| } | } |
| const String* Request::get_method_filename(const Method* method){ | const Operation::Origin Request::get_method_origin(const Method* method){ |
| Operation::Origin origin={0, 0, 0}; | |
| if(ArrayOperation* code=method->parser_code) | if(ArrayOperation* code=method->parser_code) |
| if(code){ | if(code){ |
| Operation::Origin origin={0, 0, 0}; | |
| Array_iterator<Operation> i(*code); | Array_iterator<Operation> i(*code); |
| while( i.has_next() ){ | while( i.has_next() ){ |
| switch( i.next().code ){ | switch( i.next().code ){ |
| Line 1589 const String* Request::get_method_filena | Line 1562 const String* Request::get_method_filena |
| default: break; | default: break; |
| } | } |
| if(origin.file_no) | if(origin.file_no) |
| return get_used_filename(origin.file_no); | return origin; |
| } | } |
| } | } |
| return 0; | return origin; |
| } | } |