|
|
| version 1.415, 2023/10/06 20:02:50 | version 1.423, 2024/10/02 21:24:41 |
|---|---|
| Line 19 | Line 19 |
| #include "pa_vtable.h" | #include "pa_vtable.h" |
| #include "pa_vfile.h" | #include "pa_vfile.h" |
| #include "pa_vimage.h" | #include "pa_vimage.h" |
| #include "pa_varray.h" | |
| #include "pa_wwrapper.h" | #include "pa_wwrapper.h" |
| volatile const char * IDENT_EXECUTE_C="$Id$" IDENT_PA_OPCODE_H IDENT_PA_OPERATION_H IDENT_PA_VCODE_FRAME_H IDENT_PA_WWRAPPER_H; | volatile const char * IDENT_EXECUTE_C="$Id$" IDENT_PA_OPCODE_H IDENT_PA_OPERATION_H IDENT_PA_VCODE_FRAME_H IDENT_PA_WWRAPPER_H; |
| Line 34 const char *opcode_name[]={ | Line 35 const char *opcode_name[]={ |
| // actions | // actions |
| "WITH_ROOT", "WITH_SELF", "WITH_READ", "WITH_WRITE", | "WITH_ROOT", "WITH_SELF", "WITH_READ", "WITH_WRITE", |
| "VALUE__GET_CLASS", "VALUE__GET_BASE_CLASS", | "VALUE__GET_CLASS", "VALUE__GET_BASE_CLASS", |
| "CONSTRUCT_VALUE", "CONSTRUCT_EXPR", "CURLY_CODE__CONSTRUCT", | "CONSTRUCT_VALUE", "CONSTRUCT_EXPR", "CURLY_CODE__CONSTRUCT", "CONSTRUCT_ARRAY", |
| "WRITE_VALUE", "WRITE_EXPR_RESULT", "STRING__WRITE", | "WRITE_VALUE", "WRITE_EXPR_RESULT", "STRING__WRITE", |
| #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT | #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT |
| "VALUE__GET_ELEMENT_OR_OPERATOR", | "VALUE__GET_ELEMENT_OR_OPERATOR", |
| Line 128 void debug_printf(SAPI_Info& sapi_info, | Line 129 void debug_printf(SAPI_Info& sapi_info, |
| } | } |
| void debug_dump(SAPI_Info& sapi_info, int level, ArrayOperation& ops) { | void debug_dump(SAPI_Info& sapi_info, int level, ArrayOperation& ops) { |
| Array_iterator<Operation> i(ops); | for(Array_iterator<Operation> i(ops); i;) { |
| while(i.has_next()) { | |
| OP::OPCODE opcode=i.next().code; | OP::OPCODE opcode=i.next().code; |
| #if defined(OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT) || defined(OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT) | #if defined(OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT) || defined(OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT) |
| Line 220 void debug_dump(SAPI_Info& sapi_info, in | Line 220 void debug_dump(SAPI_Info& sapi_info, in |
| case OP::OP_NESTED_CODE: | case OP::OP_NESTED_CODE: |
| case OP::OP_OBJECT_POOL: | case OP::OP_OBJECT_POOL: |
| case OP::OP_STRING_POOL: | case OP::OP_STRING_POOL: |
| case OP::OP_CONSTRUCT_ARRAY: | |
| case OP::OP_CALL: | case OP::OP_CALL: |
| case OP::OP_CALL__WRITE: | case OP::OP_CALL__WRITE: |
| if(ArrayOperation* local_ops=i.next().ops) | if(ArrayOperation* local_ops=i.next().ops) |
| Line 245 void debug_dump(SAPI_Info& sapi_info, in | Line 246 void debug_dump(SAPI_Info& sapi_info, in |
| // Request | // Request |
| void Request::execute(ArrayOperation& ops) { | void Request::execute(ArrayOperation& ops) { |
| register Stack<StackItem>& stack=this->stack; // helps a lot on MSVC: 'esi' | Stack<StackItem>& stack=this->stack; // helps a lot on MSVC: 'esi' |
| const String* debug_name=0; Operation::Origin debug_origin={0, 0, 0}; | const String* debug_name=0; Operation::Origin debug_origin={0, 0, 0}; |
| try{ | try{ |
| Line 254 void Request::execute(ArrayOperation& op | Line 255 void Request::execute(ArrayOperation& op |
| debug_dump(sapi_info, 0, ops); | debug_dump(sapi_info, 0, ops); |
| debug_printf(sapi_info, "execution-------------------------\n"); | debug_printf(sapi_info, "execution-------------------------\n"); |
| #endif | #endif |
| for(Array_iterator<Operation> i(ops); i.has_next(); ) { | for(Array_iterator<Operation> i(ops); i; ) { |
| OP::OPCODE opcode=i.next().code; | OP::OPCODE opcode=i.next().code; |
| #ifdef DEBUG_EXECUTE | #ifdef DEBUG_EXECUTE |
| Line 442 void Request::execute(ArrayOperation& op | Line 443 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)) |
| throw Exception(PARSER_RUNTIME, 0, "property value can not be code, use [] or () brackets"); | throw Exception(PARSER_RUNTIME, 0, "property value cannot be code, use [] or () brackets"); |
| break; | break; |
| } | } |
| case OP::OP_CONSTRUCT_ARRAY: | |
| { | |
| ArrayOperation* local_ops=i.next().ops; | |
| DEBUG_PRINT_OPS(local_ops) | |
| DEBUG_PRINT_STR("->\n") | |
| size_t first = stack.top_index(); | |
| execute(*local_ops); | |
| Value *value=new VArray(stack.top_index()-first, (Value**)stack.ptr(first)); | |
| stack.set_top_index(first); | |
| #ifdef OPTIMIZE_BYTECODE_CONSTRUCT | |
| const String& name=stack.pop().string(); debug_name=&name; | |
| Value& ncontext=stack.pop().value(); | |
| #else | |
| const String& name=stack.pop().string(); debug_name=&name; | |
| Value& ncontext=stack.pop().value(); | |
| #endif | |
| put_element(ncontext, name, value); | |
| DEBUG_PRINT_STR("<-returned") | |
| goto check_skip; | |
| } | |
| case OP::OP_NESTED_CODE: | case OP::OP_NESTED_CODE: |
| { | { |
| ArrayOperation& local_ops=*i.next().ops; | ArrayOperation& local_ops=*i.next().ops; |
| Line 759 void Request::execute(ArrayOperation& op | Line 786 void Request::execute(ArrayOperation& op |
| Junction* junction=value.get_junction(); | Junction* junction=value.get_junction(); |
| if(!junction) { | if(!junction) { |
| if(value.is("void")) | if(dynamic_cast<VVoid*>(&value)) |
| throw Exception(PARSER_RUNTIME, 0, "undefined method"); | throw Exception(PARSER_RUNTIME, 0, "undefined method"); |
| else | else |
| throw Exception(PARSER_RUNTIME, 0, "is '%s', not a method or junction, can not call it", value.type()); | throw Exception(PARSER_RUNTIME, 0, "is '%s', not a method or junction, cannot call it", value.type()); |
| } | } |
| Value *result; | Value *result; |
| Line 790 void Request::execute(ArrayOperation& op | Line 817 void Request::execute(ArrayOperation& op |
| Junction* junction=value.get_junction(); | Junction* junction=value.get_junction(); |
| if(!junction) { | if(!junction) { |
| if(value.is("void")) | if(dynamic_cast<VVoid*>(&value)) |
| throw Exception(PARSER_RUNTIME, 0, "undefined method"); | throw Exception(PARSER_RUNTIME, 0, "undefined method"); |
| else | else |
| throw Exception(PARSER_RUNTIME, 0, "is '%s', not a method or junction, can not call it", value.type()); | throw Exception(PARSER_RUNTIME, 0, "is '%s', not a method or junction, cannot call it", value.type()); |
| } | } |
| const Method& method=*junction->method; | const Method& method=*junction->method; |
| Line 933 void Request::execute(ArrayOperation& op | Line 960 void Request::execute(ArrayOperation& op |
| // 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(); |
| volatile double a_double=stack.pop().value().as_double(); | |
| double a_double=a.as_double(); | |
| double b_double=b.as_double(); | |
| Value& value=*new VDouble(a_double - b_double); | Value& value=*new VDouble(a_double - b_double); |
| stack.push(value); | stack.push(value); |
| Line 944 void Request::execute(ArrayOperation& op | Line 969 void Request::execute(ArrayOperation& op |
| } | } |
| 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(); |
| volatile double a_double=stack.pop().value().as_double(); | |
| double a_double=a.as_double(); | |
| double b_double=b.as_double(); | |
| Value& value=*new VDouble(a_double + b_double); | Value& value=*new VDouble(a_double + b_double); |
| stack.push(value); | stack.push(value); |
| Line 955 void Request::execute(ArrayOperation& op | Line 978 void Request::execute(ArrayOperation& op |
| } | } |
| 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(); |
| volatile double a_double=stack.pop().value().as_double(); | |
| double a_double=a.as_double(); | |
| double b_double=b.as_double(); | |
| Value& value=*new VDouble(a_double * b_double); | Value& value=*new VDouble(a_double * b_double); |
| stack.push(value); | stack.push(value); |
| Line 966 void Request::execute(ArrayOperation& op | Line 987 void Request::execute(ArrayOperation& op |
| } | } |
| 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 982 void Request::execute(ArrayOperation& op | Line 1001 void Request::execute(ArrayOperation& op |
| } | } |
| 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 998 void Request::execute(ArrayOperation& op | Line 1015 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 1236 Value& Request::construct(VStateless_cla | Line 1251 Value& Request::construct(VStateless_cla |
| throw Exception(PARSER_RUNTIME, method.name, | throw Exception(PARSER_RUNTIME, method.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, method.name, "method of '%s' is static and can not be used as constructor", called_class.type()); | throw Exception(PARSER_RUNTIME, method.name, "method of '%s' is static and cannot be used as constructor", called_class.type()); |
| } | } |
| Value& Request::get_element(Value& ncontext, const String& name) { | Value& Request::get_element(Value& ncontext, const String& name) { |
| Line 1288 Value& Request::process_getter(Junction& | Line 1303 Value& Request::process_getter(Junction& |
| if(junction.auto_name){ | if(junction.auto_name){ |
| // default getter | // default getter |
| if(param_count>1) | if(param_count>1) |
| throw Exception(PARSER_RUNTIME, 0, "default getter method can't have more then 1 parameter (has %d parameters)", param_count); | throw Exception(PARSER_RUNTIME, 0, "default getter method can't have more than 1 parameter (has %d parameters)", param_count); |
| Value *param; | Value *param; |
| METHOD_FRAME_ACTION(*junction.method, method_frame/*caller*/, junction.self, { | METHOD_FRAME_ACTION(*junction.method, method_frame/*caller*/, junction.self, { |
| Line 1345 Value& Request::process(Value& input_val | Line 1360 Value& Request::process(Value& input_val |
| wcontext=&local; | wcontext=&local; |
| // execute it | // execute it |
| recoursion_checked_execute(*junction->code); | recursion_checked_execute(*junction->code); |
| result=wcontext->result(); | result=wcontext->result(); |
| } else { | } else { |
| Line 1354 Value& Request::process(Value& input_val | Line 1369 Value& Request::process(Value& input_val |
| wcontext=&local; | wcontext=&local; |
| // execute it | // execute it |
| recoursion_checked_execute(*junction->code); | recursion_checked_execute(*junction->code); |
| result=wcontext->result(); | result=wcontext->result(); |
| } | } |
| Line 1366 Value& Request::process(Value& input_val | Line 1381 Value& Request::process(Value& input_val |
| return result; | return result; |
| } | } |
| // it is then method-junction, do not explode it | // then it is a method-junction, do not explode it |
| // just return it as we do for usual objects | // just return it as we do for usual objects |
| } | } |
| Line 1397 void Request::process_write(Value& input | Line 1412 void Request::process_write(Value& input |
| #ifdef OPTIMIZE_CALL | #ifdef OPTIMIZE_CALL |
| if(wcontext==junction->wcontext){ | if(wcontext==junction->wcontext){ |
| // no wrappers for wcontext | // no wrappers for wcontext |
| recoursion_checked_execute(*junction->code); | recursion_checked_execute(*junction->code); |
| RESTORE_CONTEXT | RESTORE_CONTEXT |
| } else | } else |
| Line 1408 void Request::process_write(Value& input | Line 1423 void Request::process_write(Value& input |
| wcontext=&local; | wcontext=&local; |
| // execute it | // execute it |
| recoursion_checked_execute(*junction->code); | recursion_checked_execute(*junction->code); |
| RESTORE_CONTEXT | RESTORE_CONTEXT |
| write(local.result()); | write(local.result()); |
| } else { | } else { |
| Line 1417 void Request::process_write(Value& input | Line 1432 void Request::process_write(Value& input |
| wcontext=&local; | wcontext=&local; |
| // execute it | // execute it |
| recoursion_checked_execute(*junction->code); | recursion_checked_execute(*junction->code); |
| RESTORE_CONTEXT | RESTORE_CONTEXT |
| write(local.result()); | write(local.result()); |
| } | } |
| Line 1427 void Request::process_write(Value& input | Line 1442 void Request::process_write(Value& input |
| return; | return; |
| } | } |
| // it is then method-junction, do not explode it | // then it is a method-junction, do not explode it |
| // just return it as we do for usual objects | // just return it as we do for usual objects |
| } | } |
| Line 1476 bool Request::execute_method_if_exists(V | Line 1491 bool Request::execute_method_if_exists(V |
| return false; | return false; |
| } | } |
| bool Request::execute_auto_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, { | |
| Value* two_params[2]; | |
| if (optional_param && method->params_count>1) { | |
| 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::get_method_filespec(const Method* method){ | const String* Request::get_method_filespec(const Method* method){ |
| Operation::Origin origin=get_method_origin(method); | Operation::Origin origin=get_method_origin(method); |
| return origin.file_no ? get_used_filespec(origin.file_no) : NULL; | return origin.file_no ? get_used_filespec(origin.file_no) : NULL; |
| Line 1486 const Operation::Origin Request::get_met | Line 1523 const Operation::Origin Request::get_met |
| if(ArrayOperation* code=method->parser_code) | if(ArrayOperation* code=method->parser_code) |
| if(code){ | if(code){ |
| Array_iterator<Operation> i(*code); | for(Array_iterator<Operation> i(*code); i; ){ |
| while( i.has_next() ){ | |
| switch( i.next().code ){ | switch( i.next().code ){ |
| case OP::OP_CURLY_CODE__STORE_PARAM: | case OP::OP_CURLY_CODE__STORE_PARAM: |
| case OP::OP_EXPR_CODE__STORE_PARAM: | case OP::OP_EXPR_CODE__STORE_PARAM: |