--- parser3/src/main/execute.C 2001/10/29 16:07:36 1.200 +++ parser3/src/main/execute.C 2002/01/31 15:16:01 1.214 @@ -2,9 +2,9 @@ Parser: executor part of request class. Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) - Author: Alexander Petrosyan (http://design.ru/paf) + Author: Alexander Petrosyan (http://paf.design.ru) - $Id: execute.C,v 1.200 2001/10/29 16:07:36 paf Exp $ + $Id: execute.C,v 1.214 2002/01/31 15:16:01 paf Exp $ */ #include "pa_opcode.h" @@ -25,12 +25,13 @@ //#define DEBUG_EXECUTE -const uint ANTI_ENDLESS_EXECUTE_RECOURSION=200; +const uint ANTI_ENDLESS_EXECUTE_RECOURSION=500; #ifdef DEBUG_EXECUTE char *opcode_name[]={ // literals "VALUE", "CURLY_CODE__STORE_PARAM", "EXPR_CODE__STORE_PARAM", + "NESTED_CODE", // actions "WITH_ROOT", "WITH_SELF", "WITH_READ", "WITH_WRITE", @@ -43,11 +44,12 @@ char *opcode_name[]={ "GET_METHOD_FRAME", "STORE_PARAM", "PREPARE_TO_CONSTRUCT_OBJECT", "CALL", + "PREPARE_TO_CONSTRUCT_EXPR" // expression ops: unary "NEG", "INV", "NOT", "DEF", "IN", "FEXISTS", "DEXISTS", // expression ops: binary - "SUB", "ADD", "MUL", "DIV", "MOD", + "SUB", "ADD", "MUL", "DIV", "MOD", "INTDIV", "BIN_AND", "BIN_OR", "BIN_XOR", "LOG_AND", "LOG_OR", "LOG_XOR", "NUM_LT", "NUM_GT", "NUM_LE", "NUM_GE", "NUM_EQ", "NUM_NE", @@ -89,6 +91,7 @@ void debug_dump(Pool& pool, int level, c case OP_CURLY_CODE__STORE_PARAM: case OP_EXPR_CODE__STORE_PARAM: case OP_CURLY_CODE__CONSTRUCT: + case OP_NESTED_CODE: const Array *local_ops=reinterpret_cast(i.next()); debug_dump(pool, level+1, *local_ops); } @@ -99,6 +102,7 @@ void debug_dump(Pool& pool, int level, c #define PUSH(value) stack.push(value) #define POP() static_cast(stack.pop()) #define POP_NAME() static_cast(stack.pop())->as_string() +#define POP_CODE() static_cast(stack.pop()) void Request::execute(const Array& ops) { // _asm int 3; @@ -118,6 +122,7 @@ void Request::execute(const Array& ops) Value *value; Value *a; Value *b; + Array *b_code; switch(op.code) { // param in next instruction case OP_VALUE: @@ -162,7 +167,7 @@ void Request::execute(const Array& ops) case OP_GET_CLASS: { // maybe they do ^class:method[] call, remember the fact - wcontext->set_somebody_entered_some_class(); + wcontext->set_somebody_entered_some_class(true); const String& name=POP_NAME(); value=static_cast(classes().get(name)); @@ -205,6 +210,25 @@ void Request::execute(const Array& ops) Value *ncontext=POP(); ncontext->put_element(name, value); value->set_name(name); + + // forget the fact they've entered some $class/object.xxx + // see OP_GET_ELEMENT + wcontext->set_somebody_entered_some_object(false); + wcontext->set_somebody_entered_some_class(false); + break; + } + case OP_PREPARE_TO_CONSTRUCT_EXPR: + { + // here, not in OP_CONSTRUCT_EXPR + // because then would be too late - expression already would try to evaluate + // in wrong state + // not the case with OP_CONSTRUCT_VALUE, there we have write pool + // (separate wcontext with it's own state + + // forget the fact they've entered some $class/object.xxx + // see OP_GET_ELEMENT + wcontext->set_somebody_entered_some_object(false); + wcontext->set_somebody_entered_some_class(false); break; } case OP_CONSTRUCT_EXPR: @@ -214,6 +238,12 @@ void Request::execute(const Array& ops) Value *ncontext=POP(); ncontext->put_element(name, value->as_expr_result()); value->set_name(name); + + // forget the fact that they've entered some ^class/object.xxx or $class/object.xxx + // during expression evaluation + // see OP_GET_ELEMENT + wcontext->set_somebody_entered_some_object(false); + wcontext->set_somebody_entered_some_class(false); break; } case OP_CURLY_CODE__CONSTRUCT: @@ -237,14 +267,25 @@ void Request::execute(const Array& ops) value->set_name(name); break; } + case OP_NESTED_CODE: + { + Array *local_ops=static_cast(i.next()); +#ifdef DEBUG_EXECUTE + debug_printf(pool(), " (%d)\n", local_ops->size()); + debug_dump(pool(), 1, *local_ops); +#endif + PUSH(local_ops); + break; + } case OP_WRITE_VALUE: { value=POP(); write_assign_lang(*value); - // forget the fact they've entered some ^object.method[]. + // forget the fact they've entered some ^object/class.xxx or $object/class.xxx // see OP_GET_ELEMENT wcontext->set_somebody_entered_some_object(false); + wcontext->set_somebody_entered_some_class(false); break; } case OP_WRITE_EXPR_RESULT: @@ -265,11 +306,14 @@ void Request::execute(const Array& ops) case OP_GET_ELEMENT: { + //_asm int 3; + // uses entered object/class flags to plug in operators + value=get_element(); + // maybe they do ^object.method[] call, remember the fact + // must be below get_element() call, it checks it wcontext->set_somebody_entered_some_object(true); - //_asm int 3; - value=get_element(); PUSH(value); break; } @@ -292,7 +336,7 @@ void Request::execute(const Array& ops) } case OP_REDUCE_EWPOOL: { - value=wcontext->result(); + value=&wcontext->result(); flang=static_cast(reinterpret_cast(POP())); wcontext=static_cast(POP()); PUSH(value); @@ -371,12 +415,14 @@ void Request::execute(const Array& ops) // this is a constructor call if(Value *value=called_class->create_new_value(pool())) { - // some stateless_object creatable derivates + // some stateless_class creatable derivates self=value; - } else { - // stateful object - self=NEW VObject(pool(), *called_class); - } + } else + throw Exception(0, 0, + &frame->name(), + "is not a constructor, system class '%s' can be constructed only implicitly", + called_class->name().cstr()); + frame->write(*self, String::UL_CLEAN // not used, always an object, not string ); @@ -400,7 +446,7 @@ void Request::execute(const Array& ops) } frame->set_self(*self); - root=rcontext=wcontext=frame; + rcontext=wcontext=frame; { // take object or class from any wrappers // and substitute class alias to the class they are called AS @@ -414,6 +460,7 @@ void Request::execute(const Array& ops) method.call_type==call_type) { // allowed call type? try { if(method.native_code) { // native code? + // root unchanged, so that ^for ^foreach & co may write to locals method.check_actual_numbered_params( frame->junction.self, frame->name(), frame->numbered_params()); @@ -421,15 +468,17 @@ void Request::execute(const Array& ops) *this, frame->name(), frame->numbered_params()); // execute it } else { // parser code - if(++anti_endless_execute_recoursion==ANTI_ENDLESS_EXECUTE_RECOURSION) { - anti_endless_execute_recoursion=0; // give @exception a chance - throw Exception(0, 0, - &frame->name(), - "endless recursion detected"); + root=frame; + { // anti_endless_execute_recoursion + if(++anti_endless_execute_recoursion==ANTI_ENDLESS_EXECUTE_RECOURSION) { + anti_endless_execute_recoursion=0; // give @exception a chance + throw Exception(0, 0, + &frame->name(), + "call canceled - endless recursion detected"); + } + execute(*method.parser_code); // execute it + anti_endless_execute_recoursion--; } - - execute(*method.parser_code); // execute it - anti_endless_execute_recoursion--; } } catch(...) { // record it to stack trace @@ -443,13 +492,18 @@ void Request::execute(const Array& ops) call_type==Method::CT_STATIC?"statically":"dynamically"); } - value=wcontext->result(); + value=&wcontext->result(); wcontext=static_cast(POP()); rcontext=POP(); root=POP(); self=static_cast(POP()); + // forget the fact they've entered some ^object/class.xxx + // see OP_GET_ELEMENT + wcontext->set_somebody_entered_some_object(false); + wcontext->set_somebody_entered_some_class(false); + PUSH(value); #ifdef DEBUG_EXECUTE debug_printf(pool(), "<-returned"); @@ -579,6 +633,28 @@ void Request::execute(const Array& ops) PUSH(value); break; } + case OP_INTDIV: + { + b=POP(); a=POP(); + + int a_int=a->as_int(); + int b_int=b->as_int(); + + if(b_int == 0) { + const String *problem_source=&b->as_string(); +#ifndef NO_STRING_ORIGIN + if(!problem_source->origin().file) + problem_source=&b->name(); +#endif + throw Exception(0, 0, + problem_source, + "Division by zero"); + } + + value=NEW VInt(pool(), a_int / b_int); + PUSH(value); + break; + } case OP_BIN_AND: { b=POP(); a=POP(); @@ -608,15 +684,30 @@ void Request::execute(const Array& ops) } case OP_LOG_AND: { - b=POP(); a=POP(); - value=NEW VBool(pool(), a->as_bool() && b->as_bool()); + b_code=POP_CODE(); a=POP(); + bool result; + if(a->as_bool()) { + execute(*b_code); + b=POP(); + result=b->as_bool(); + } else + result=false; + value=NEW VBool(pool(), result); PUSH(value); break; } case OP_LOG_OR: { - b=POP(); a=POP(); - value=NEW VBool(pool(), a->as_bool() || b->as_bool()); + b_code=POP_CODE(); a=POP(); + bool result; + if(a->as_bool()) + result=true; + else { + execute(*b_code); + b=POP(); + result=b->as_bool(); + } + value=NEW VBool(pool(), result); PUSH(value); break; } @@ -732,11 +823,15 @@ Value *Request::get_element() { const String& name=POP_NAME(); Value *ncontext=POP(); Value *value=ncontext->get_element(name); - if(!value) + // operators can not be in form... + if(!value && + !wcontext->get_somebody_entered_some_class () && // $class:xxx + !wcontext->get_somebody_entered_some_object()) // $object.xxx + // they can only be in form ^xxx or $xxx if(Method* method=OP.get_method(name)) { // maybe operator? // as if that method were in self and we have normal dynamic method here Junction& junction=*NEW Junction(pool(), - *root/*self*/, self->get_class(), method, 0,0,0,0); + *root, self->get_class(), method, 0,0,0,0); value=NEW VJunction(junction); } if(value) @@ -790,14 +885,25 @@ Value& Request::process(Value& value, co self=&junction->self; root=junction->root; rcontext=junction->rcontext; - execute(*junction->code); + + { // anti_endless_execute_recoursion + if(++anti_endless_execute_recoursion==ANTI_ENDLESS_EXECUTE_RECOURSION) { + anti_endless_execute_recoursion=0; // give @exception a chance + throw Exception(0, 0, + name, + "junction evaluation canceled - endless recursion detected"); + } + execute(*junction->code); + anti_endless_execute_recoursion--; + } + if(using_code_frame) { // CodeFrame soul: // string writes were intercepted // returning them as the result of getting code-junction result=NEW VString(*frame->get_string()); } else - result=frame->result(); + result=&frame->result(); wcontext=static_cast(POP()); rcontext=POP(); @@ -815,8 +921,8 @@ Value& Request::process(Value& value, co return *result; } -const String *Request::execute_method(Value& aself, const Method& method, - bool return_cstr) { +const String *Request::execute_method(Value& aself, const Method& method, + bool return_cstr) { PUSH(self); PUSH(root); PUSH(rcontext); @@ -830,11 +936,32 @@ const String *Request::execute_method(Va execute(*method.parser_code); // result - const String *result; - if(return_cstr) - result=&wcontext->as_string(); - else - result=0; // ignore result + const String *result=return_cstr ? &wcontext->as_string() : 0; + + wcontext=static_cast(POP()); + rcontext=POP(); + root=POP(); + self=static_cast(POP()); + + // return + return result; +} + +const String& Request::execute_method(VMethodFrame& amethodFrame, const Method& method) { + PUSH(self); + PUSH(root); + PUSH(rcontext); + PUSH(wcontext); + + // initialize contexts + root=rcontext=self=&amethodFrame; + wcontext=&amethodFrame; + + // execute! + execute(*method.parser_code); + + // result + const String& result=wcontext->as_string(); wcontext=static_cast(POP()); rcontext=POP(); @@ -846,18 +973,17 @@ const String *Request::execute_method(Va } const String *Request::execute_virtual_method(Value& aself, - const String& method_name, - bool return_cstr) { + const String& method_name) { if(Value *value=aself.get_element(method_name)) if(Junction *junction=value->get_junction()) if(const Method *method=junction->method) - return execute_method(aself, *method, return_cstr); + return execute_method(aself, *method, true /*return_cstr*/); return 0; } const String *Request::execute_nonvirtual_method(VStateless_class& aclass, - const String& method_name, + const String& method_name, bool return_cstr) { if(const Method *method=aclass.get_method(method_name)) return execute_method(aclass, *method, return_cstr);