Example #1
0
File: vm.cpp Project: gcubar/XKP
variant execution_context::execute()
  {
    size_t isz = instructions_.size();

    while(pc_ < isz)
      {
        instruction& i = instructions_[pc_];
        //td: a fuction table would be better, no?
        switch(i.id)
          {
            case i_jump:
              {
                pc_   = i.data.value;
                jump_ = true;
                break;
              }

            case i_jump_if:
              {
                bool control = pop();
                if (control)
                  {
                    pc_   = i.data.value;
                    jump_ = true;
                  }
                break;
              }

            case i_jump_if_not:
              {
                bool control = variant_cast<bool>(pop(), false); //td: its bool or false
                if (!control)
                  {
                    pc_   = i.data.value;
                    jump_ = true;
                  }
                break;
              }

            case i_store:
              {
                stack_[i.data.value] = pop();
                break;
              }

            case i_load:
              {
                operands_.push(stack_[i.data.value]);
                break;
              }

            case i_load_constant:
              {
                operands_.push(constants_[i.data.value]);
                break;
              }

            case i_return:       return variant();
            case i_return_value: return operands_.top();

            case i_dup_top:
              {
                variant top = operands_.top();
                operands_.push( top );
                break;
              }
            case i_pop: operands_.pop(); break;

            case i_binary_operator:
              {
                operator_exec* e      = operators_.get_operator(i.data.value);
                variant        arg2   = pop();
                variant        arg1   = pop();
                variant        result = e->exec(arg1, arg2);

                operands_.push(result);
                break;
              }
            case i_unary_operator:
              {
                operator_exec* e      = operators_.get_operator(i.data.value);
                variant        arg1   = pop();
                variant        useless;
                variant        result = e->exec(arg1, useless);

                operands_.push(result);
                break;
              }
            case i_dynamic_binary_operator:
              {
                variant arg2  = pop();
                variant arg1  = pop();
                schema* type1 = true_type(arg1); assert(type1);
                schema* type2 = true_type(arg2); assert(type2);

                variant        result;
                operator_type  opid   = (operator_type)i.data.value;
                operator_exec* opexec = operators_.get_operator(opid, type1, type2);
                if (!opexec)
                  {
                    schema_item custom_operator;
                    if (type1->resolve(vm_operator_name[opid], custom_operator))
                      {
                        assert(custom_operator.exec); //read only

                        void*   caller_id;
                        if (custom_operator.flags & DYNAMIC_ACCESS)
                          {
                            IDynamicObject* obj = arg1; //td: catch type mismatch
                            caller_id = obj;
                          }
                        else
                          caller_id = arg1.get_pointer();

                        param_list args;
                        args.add(arg2);
                        result = custom_operator.exec->exec(caller_id, args );
                      }
                    else
                      {
												if (operators_.get_default_operator(opid, &opexec, null))
													{
														result = opexec->exec(arg1, arg2);
													}
												else
												{
													param_list error;
													error.add("id", SRuntime);
													error.add("desc", SCannotResolveOperator);
													error.add("operator", str(vm_operator_name[opid]));
													runtime_throw(error);
												}
                      }
                  }
                else result = opexec->exec(arg1, arg2);

                operands_.push(result);
                break;
              }
						case i_dynamic_binary_assign_operator:
							{
                bool		assign = false;
								variant arg1	 = pop();
                variant arg2   = pop();
                schema* type1  = true_type(arg1); assert(type1);
                schema* type2  = true_type(arg2); assert(type2);

                variant        result;
                operator_type  opid   = (operator_type)i.data.value;
                operator_exec* opexec = operators_.get_operator(opid, type1, type2);
                if (!opexec)
                  {
                    schema_item custom_operator;
                    if (type1->resolve(vm_operator_name[opid], custom_operator))
                      {
                        assert(custom_operator.exec); //read only

                        void*   caller_id;
                        if (custom_operator.flags & DYNAMIC_ACCESS)
                          {
                            IDynamicObject* obj = arg1; //td: catch type mismatch
                            caller_id = obj;
                          }
                        else
                          caller_id = arg1.get_pointer();

                        param_list args;
                        args.add(arg2);
                        result = custom_operator.exec->exec(caller_id, args );
                      }
										else
											{
												operator_exec* nopexec = operators_.get_operator(vm_native_op[opid], type1, type2);
												if (nopexec)
													{
														result = nopexec->exec(arg1, arg2);
														assign = true;
													}
												else
													{
														param_list error;
														error.add("id", SRuntime);
														error.add("desc", SCannotResolveOperator);
														error.add("operator", str(vm_operator_name[opid]));
														runtime_throw(error);
													}
											}
                  }
                else result = opexec->exec(arg1, arg2);

                operands_.push(result);
                operands_.push(!assign);
								break;
							}
            case i_dynamic_unary_operator:
              {
                variant arg1  = pop();
                schema* type1 = true_type(arg1); assert(type1);

                variant        result;
                operator_type  opid   = (operator_type)i.data.value;
                operator_exec* opexec = operators_.get_operator(opid, type1, null);
                if (!opexec)
                  {
                    schema_item custom_operator;
                    if (type1->resolve(vm_operator_name[opid], custom_operator))
                      {
                        assert(custom_operator.exec); //read only

                        void*   caller_id;
                        if (custom_operator.flags & DYNAMIC_ACCESS)
                          {
                            IDynamicObject* obj = arg1; //td: catch type mismatch
                            caller_id = obj;
                          }
                        else
                          caller_id = arg1.get_pointer();

                        param_list args;
                        result = custom_operator.exec->exec(caller_id, args );
                      }
                    else
                      {
												param_list error;
												error.add("id", SRuntime);
												error.add("desc", SCannotResolveOperator);
												error.add("operator", str(vm_operator_name[opid]));
												runtime_throw(error);
                      }
                  }
                else
                  {
                    variant arg2;
                    result = opexec->exec(arg1, arg2);
                  }

                operands_.push(result);
                break;
              }
            case i_dynamic_get:
              {
                str     getter_name = constants_[i.data.value];
                variant getted      = pop();

                variant result;
                if (!dynamic_try_get(getted, getter_name, result))
                  {
                    param_list error;
                    error.add("id", SRuntime);
                    error.add("desc", SCannotResolveDynamically);
                    error.add("object", getted);
                    error.add("property", getter_name);
                    runtime_throw(error);
                  }

                operands_.push(result);
                break;
              }
						case i_dynamic_set:
							{
                str     getter_name = constants_[i.data.value];
                variant getted      = pop();
								variant value			  = pop();

                variant result;
                if (!dynamic_set(getted, getter_name, value))
                  {
                    param_list error;
                    error.add("id", SRuntime);
                    error.add("desc", SCannotAssignDynamically);
                    error.add("object", getted);
                    error.add("property", getter_name);
                    runtime_throw(error);
                  }

                operands_.push(result);
								break;
							}
            case i_dynamic_resolve:
              {
                str     resolve_name  = constants_[i.data.value];
                variant resolver      = operands_.top();
                schema* resolver_type = true_type(resolver);

                schema_item itm;
                if (resolver_type->resolve(resolve_name, itm))
                  {
                    operands_.push(itm.exec); //td: not sure this should be done exclusively for executers
                  }
                else
                  {
                    IDynamicObject* obj = variant_cast<IDynamicObject*>(resolver, null);
                    if (obj && obj->resolve(resolve_name, itm))
                      {
                        if (!itm.exec)
                          {
                            param_list error;
                            error.add("id", SRuntime);
                            error.add("desc", SNotExecutableDynamic);
                            error.add("object", obj);
                            error.add("method", resolve_name);
                            runtime_throw(error);
                          }
                      
                        operands_.push(itm.exec);
                      }
                    else
                      {
                        param_list error;
                        error.add("id", SRuntime);
                        error.add("desc", SCannotResolveDynamically);
                        error.add("object", obj);
                        error.add("method", resolve_name);
                        runtime_throw(error);
                      }
                  }
                break;
              }
            case i_load_this:
              {
                operands_.push( this_ );
                break;
              }
            case i_call:
              {
                Executer call = pop();
                param_list pl;
                variant caller;

								if (i.data.call_data.invert)
									{
										caller = pop();

										for(int p = 0; p < i.data.call_data.param_count; p++)
											{
												pl.add(pop());
											}
									}
								else
									{
										for(int p = 0; p < i.data.call_data.param_count; p++)
											{
												pl.add(pop());
											}

										caller = pop();
									}

                if (caller.empty())
                  {
                    param_list error;
                    error.add("id", SRuntime);
                    error.add("desc", SCallingNull);
                    runtime_throw(error);
                  }

                void*   caller_id;
                if (i.data.call_data.is_dynamic)
                  {
                    IDynamicObject* obj = variant_cast<IDynamicObject*>(caller, null);
                    if (obj)
                      caller_id = obj;
                    else
                      caller_id = caller.get_pointer(); //revert to undynamic, there should be a better solution
                  }
                else
                  caller_id = caller.get_pointer();

                variant result = call->exec(caller_id, pl);
                operands_.push( result );
                break;
              }
            case i_this_call:
              {
                Executer call = pop();
                param_list pl;
                for(int p = 0; p < i.data.call_data.param_count; p++)
                  {
                    pl.add(pop());
                  }

                void* caller_id;
                if (i.data.call_data.is_dynamic)
                  {
                    IDynamicObject* obj = this_; //td: catch type mismatch
                    caller_id           = obj;
                  }
                else
                  caller_id = this_.get_pointer();

                operands_.push( call->exec(caller_id, pl) );
                break;
              }
            case i_get:
              {
                Getter  call   = pop();
                variant caller = pop();

                if (caller.empty())
                  {
                    param_list error;
                    error.add("id", SRuntime);
                    error.add("desc", SCallingNull);
                    runtime_throw(error);
                  }

                void* caller_id;
                if (i.data.value)
                  {
                    IDynamicObject* obj = caller; //td: catch type mismatch
                    caller_id           = obj;
                  }
                else
                  caller_id = caller.get_pointer();

                variant result = call->get(caller_id);
                operands_.push(result);
                break;
              }
            case i_set:
              {
                Setter call = pop();
                
								variant value;
                variant caller;
								if (i.data.set_data.invert)
									{
										caller = pop();
										value  = pop();
									}
								else
									{
										value  = pop();
										caller = pop();
									}

                void* caller_id;
								if (i.data.set_data.is_dynamic)
                  {
                    IDynamicObject* obj = caller; //td: catch type mismatch
                    caller_id           = obj;
                  }
                else
                  caller_id = caller.get_pointer();

                call->set(caller_id, value);
                break;
              }
            case i_instantiate:
              {
                schema* type = pop();
                param_list pl;
                for(int p = 0; p < i.data.value; p++)
                  {
                    pl.add(pop());
                  }

                variant result;
                if (type->create(result, &pl))
                  operands_.push(result);
                else
                  {
                    param_list error;
                    error.add("id", SRuntime);
                    error.add("desc", STypeDoesNotInstantiate);
                    runtime_throw(error);
                  }
                break;
              }
            case i_dispatch:
              {
                event_info      ev     = pop();
                IDynamicObject* caller = pop();

                param_list pl;
                for(int p = 0; p < i.data.value; p++)
                  {
                    pl.add(pop());
                  }

                caller->dispatch_event(ev.id, pl);
                break;
              }
						case i_nop: break;
            default:
              assert(false); //say wha
          }

        if (!jump_)
          pc_++;

        jump_ = false;
      }

    return variant();
  }