polserver/pol-core/bscript/executor.h
turleypol 1eedfb7a5e Merge remote-tracking branch 'origin/master' into vector_classes
* origin/master: (84 commits)
  store skillid in the attributes if available
  added docs for checkskill change
  use the correct id as skillid
  CheckSkill() accepts now also attribute name instead of skillid
  Move StoredToken to its own cpp/h
  Items can now be created with an assigned quality from an itemdescriptor (#161)
  *** OG Compiler: decouple web script preprocessing from FileContents
  fix optimizer bug: can stop optimizing prematurely if pre- or post-decrement operators are present
  Fix a bug in the legacy compiler .ecl output
  Move compiler to Legacy namespace
  Allow discord notification to fail and still have a successful build. It will otherwise always fail on forks, because it needs a github secret.
  Ensure textentry_uoemod is not overwritten
  fixed potential out of bound read
  escript_grammar.cmake from Turley
  generated lib/EscriptGrammar from grammar
  EscriptGrammar from escript-antlr repo commit  ef133e3a3a3184936e93493c863b7b995cdf4737 (#162)
  Incorporate ANTLR into the cmake build.
  Fix luck mod being assigned to luck from itemdesc files Fixed swing speed increase being printed twice when saving items. Fixed spelling mistake in docs.
  Style fix
  - Fix up docs. - Change modifier calculation to correctly use double. - Change rounding calculation as per Turley's suggestion.
  ...
2020-08-02 13:18:54 +02:00

496 lines
14 KiB
C++

/** @file
*
* @par History
* - 2009/09/05 Turley: Added struct .? and .- as shortcut for .exists() and .erase()
*/
#ifndef __EXECUTOR_H
#define __EXECUTOR_H
#include "pol_global_config.h"
#ifndef __EXECTYPE_H
#include "exectype.h"
#endif
#ifndef BSCRIPT_BOBJECT_H
#include "bobject.h"
#endif
#include <exception>
#include <memory>
#include <set>
#include <stack>
#include <string>
#include <vector>
#include "../clib/refptr.h"
#include "../clib/spinlock.h"
#include "bobject.h"
#include "eprog.h"
#include "executortype.h"
#include <format/format.h>
namespace Pol
{
namespace Core
{
class UOExecutor;
void list_script( UOExecutor* uoexec );
} // namespace Core
namespace Bscript
{
class Executor;
class ExecutorModule;
class ModuleFunction;
class String;
class Token;
#ifdef ESCRIPT_PROFILE
#include <map>
struct profile_instr
{
unsigned long sum;
unsigned long max;
unsigned long min;
unsigned long count;
};
typedef std::map<std::string, profile_instr> escript_profile_map;
extern escript_profile_map EscriptProfileMap;
#endif
typedef std::vector<BObjectRef> ValueStackCont;
// FIXME: how to make this a nested struct in Executor?
struct ReturnContext
{
unsigned PC;
unsigned ValueStackDepth;
};
struct BackupStruct
{
std::unique_ptr<BObjectRefVec> Locals;
ValueStackCont ValueStack;
unsigned PC;
};
enum class ExecutorType
{
EXECUTOR,
POL
};
class Executor
{
public:
static Clib::SpinLock _executor_lock;
virtual size_t sizeEstimate() const;
friend void Core::list_script( Core::UOExecutor* uoexec );
int done;
void seterror( bool err );
bool error() const;
bool error_;
bool halt_;
bool run_ok_;
virtual ExecutorType type() { return ExecutorType::EXECUTOR; }
enum DEBUG_LEVEL
{
NONE,
SOURCELINES,
INSTRUCTIONS
};
DEBUG_LEVEL debug_level;
unsigned PC; // program counter
bool AttachFunctionalityModules();
bool setProgram( EScriptProgram* prog );
BObjectRefVec Globals2;
std::vector<BObjectRefVec*> upperLocals2;
std::vector<ReturnContext> ControlStack;
BObjectRefVec* Locals2;
static UninitObject* m_SharedUninitObject;
ValueStackCont ValueStack;
static ExecInstrFunc GetInstrFunc( const Token& token );
/*
These must both be deleted. instr references _symbols, so it should be deleted first.
FIXME: there should be a separate object, called EProgram or something,
that owns both the instructions and the symbols. It should be ref_counted,
so a code repository can store programs that multiple Executors use.
That means debugger stuff has to come out of Instruction.
*/
unsigned nLines;
std::vector<BObjectRef> fparams;
friend class ExecutorModule;
void setFunctionResult( BObjectImp* imp );
protected:
int getParams( unsigned howMany );
void cleanParams();
public:
int makeString( unsigned param );
bool hasParams( unsigned howmany ) const { return ( fparams.size() >= howmany ); }
size_t numParams() const { return fparams.size(); }
BObjectImp* getParamImp( unsigned param );
BObjectImp* getParamImp( unsigned param, BObjectImp::BObjectType type );
BObjectImp* getParamImp2( unsigned param, BObjectImp::BObjectType type );
BObject* getParamObj( unsigned param );
const String* getStringParam( unsigned param );
const BLong* getLongParam( unsigned param );
bool getStringParam( unsigned param, const String*& pstr );
bool getUnicodeStringParam( unsigned param, const String*& pstr ); // accepts also BLong array
bool getParam( unsigned param, int& value );
bool getParam( unsigned param, int& value, int maxval );
bool getParam( unsigned param, int& value, int minval, int maxval );
bool getRealParam( unsigned param, double& value );
bool getObjArrayParam( unsigned param, ObjArray*& pobjarr );
bool getParam( unsigned param, unsigned& value );
bool getParam( unsigned param, unsigned short& value );
bool getParam( unsigned param, unsigned short& value, unsigned short maxval );
bool getParam( unsigned param, unsigned short& value, unsigned short minval,
unsigned short maxval );
bool getParam( unsigned param, short& value );
bool getParam( unsigned param, short& value, short maxval );
bool getParam( unsigned param, short& value, short minval, short maxval );
bool getParam( unsigned param, signed char& value );
void* getApplicPtrParam( unsigned param, const BApplicObjType* pointer_type );
BApplicObjBase* getApplicObjParam( unsigned param, const BApplicObjType* object_type );
const char* paramAsString( unsigned param );
double paramAsDouble( unsigned param );
int paramAsLong( unsigned param );
protected:
int makeDouble( unsigned param );
BObject* getParam( unsigned param );
BObject getValue( void );
BObjectRef getObjRef( void );
public:
int getToken( Token& token, unsigned position );
BObjectRef& LocalVar( unsigned int varnum );
BObjectRef& GlobalVar( unsigned int varnum );
int makeGlobal( const Token& token );
void popParam( const Token& token );
void popParamByRef( const Token& token );
void getArg( const Token& token );
void pushArg( BObjectImp* arg );
void pushArg( const BObjectRef& ref );
static BObjectRef addmember( BObject& left, const BObject& right );
static BObjectRef removemember( BObject& left, const BObject& right );
static BObjectRef checkmember( BObject& left, const BObject& right );
void addmember2( BObject& left, const BObject& right );
static bool builtinMethodForced( const char*& methodname );
// execmodules: modules associated with the current program. References modules owned by
// availmodules.
std::vector<ExecutorModule*> execmodules;
std::vector<ExecutorModule*> availmodules; // owns
public:
Executor();
virtual ~Executor();
void addModule( ExecutorModule* module ); // NOTE, executor deletes its modules when done
ExecutorModule* findModule( const std::string& name );
ModuleFunction* current_module_function;
// NOTE: the debugger code expects these to be virtual..
void execFunc( const Token& token );
void execInstr();
void ins_nop( const Instruction& ins );
void ins_jmpiftrue( const Instruction& ins );
void ins_jmpiffalse( const Instruction& ins );
void ins_skipiftrue_else_consume( const Instruction& ins );
void ins_globalvar( const Instruction& ins );
void ins_localvar( const Instruction& ins );
void ins_makeLocal( const Instruction& ins );
void ins_declareArray( const Instruction& ins );
void ins_long( const Instruction& ins );
void ins_double( const Instruction& ins );
void ins_string( const Instruction& ins );
void ins_error( const Instruction& ins );
void ins_struct( const Instruction& ins );
void ins_array( const Instruction& ins );
void ins_dictionary( const Instruction& ins );
void ins_uninit( const Instruction& ins );
void ins_ident( const Instruction& ins );
void ins_unminus( const Instruction& ins );
void ins_unplusplus( const Instruction& ins );
void ins_unminusminus( const Instruction& ins );
void ins_unplusplus_post( const Instruction& ins );
void ins_unminusminus_post( const Instruction& ins );
void ins_logical_and( const Instruction& ins );
void ins_logical_or( const Instruction& ins );
void ins_logical_not( const Instruction& ins );
void ins_bitwise_not( const Instruction& ins );
void ins_set_member( const Instruction& ins );
void ins_set_member_consume( const Instruction& ins );
void ins_get_member( const Instruction& ins );
void ins_get_member_id( const Instruction& ins ); // test id
void ins_set_member_id( const Instruction& ins ); // test id
void ins_set_member_id_consume( const Instruction& ins ); // test id
void ins_set_member_id_consume_plusequal( const Instruction& ins ); // test id
void ins_set_member_id_consume_minusequal( const Instruction& ins ); // test id
void ins_set_member_id_consume_timesequal( const Instruction& ins ); // test id
void ins_set_member_id_consume_divideequal( const Instruction& ins ); // test id
void ins_set_member_id_consume_modulusequal( const Instruction& ins ); // test id
void ins_set_member_id_unplusplus( const Instruction& ins ); // test id
void ins_set_member_id_unminusminus( const Instruction& ins ); // test id
void ins_set_member_id_unplusplus_post( const Instruction& ins ); // test id
void ins_set_member_id_unminusminus_post( const Instruction& ins ); // test id
void ins_assign_localvar( const Instruction& ins );
void ins_assign_globalvar( const Instruction& ins );
void ins_assign_consume( const Instruction& ins );
void ins_consume( const Instruction& ins );
void ins_assign( const Instruction& ins );
void ins_array_assign( const Instruction& ins );
void ins_array_assign_consume( const Instruction& ins );
void ins_multisubscript_assign( const Instruction& ins );
void ins_multisubscript_assign_consume( const Instruction& ins );
void ins_multisubscript( const Instruction& ins );
void ins_add( const Instruction& ins );
void ins_subtract( const Instruction& ins );
void ins_mult( const Instruction& ins );
void ins_div( const Instruction& ins );
void ins_modulus( const Instruction& ins );
void ins_insert_into( const Instruction& ins );
void ins_plusequal( const Instruction& ins );
void ins_minusequal( const Instruction& ins );
void ins_timesequal( const Instruction& ins );
void ins_divideequal( const Instruction& ins );
void ins_modulusequal( const Instruction& ins );
void ins_bitshift_right( const Instruction& ins );
void ins_bitshift_left( const Instruction& ins );
void ins_bitwise_and( const Instruction& ins );
void ins_bitwise_xor( const Instruction& ins );
void ins_bitwise_or( const Instruction& ins );
void ins_equal( const Instruction& ins );
void ins_notequal( const Instruction& ins );
void ins_lessthan( const Instruction& ins );
void ins_lessequal( const Instruction& ins );
void ins_greaterthan( const Instruction& ins );
void ins_greaterequal( const Instruction& ins );
void ins_goto( const Instruction& ins );
void ins_arraysubscript( const Instruction& ins );
void ins_func( const Instruction& ins );
void ins_call_method( const Instruction& ins );
void ins_call_method_id( const Instruction& ins );
void ins_statementbegin( const Instruction& ins );
void ins_progend( const Instruction& ins );
void ins_makelocal( const Instruction& ins );
void ins_jsr_userfunc( const Instruction& ins );
void ins_pop_param( const Instruction& ins );
void ins_pop_param_byref( const Instruction& ins );
void ins_get_arg( const Instruction& ins );
void ins_leave_block( const Instruction& ins );
void ins_gosub( const Instruction& ins );
void ins_return( const Instruction& ins );
void ins_exit( const Instruction& ins );
void ins_member( const Instruction& ins );
void ins_addmember( const Instruction& ins );
void ins_removemember( const Instruction& ins );
void ins_checkmember( const Instruction& ins );
void ins_dictionary_addmember( const Instruction& ins );
void ins_addmember2( const Instruction& ins );
void ins_addmember_assign( const Instruction& ins );
void ins_in( const Instruction& ins );
void ins_initforeach( const Instruction& ins );
void ins_stepforeach( const Instruction& ins );
void ins_initforeach2( const Instruction& ins );
void ins_stepforeach2( const Instruction& ins );
void ins_casejmp( const Instruction& ins );
void ins_initfor( const Instruction& ins );
void ins_nextfor( const Instruction& ins );
void ins_funcref( const Instruction& ins );
static int ins_casejmp_findlong( const Token& token, BLong* blong );
static int ins_casejmp_findstring( const Token& token, String* bstringimp );
static int ins_casejmp_finddefault( const Token& token );
bool running_to_completion() const;
void set_running_to_completion( bool to_completion );
bool runnable() const;
void calcrunnable();
bool halt() const;
void sethalt( bool halt );
bool debugging() const;
void setdebugging( bool debugging );
void attach_debugger();
void detach_debugger();
std::string dbg_get_instruction( size_t atPC ) const;
void dbg_ins_trace();
void dbg_step_into();
void dbg_step_over();
void dbg_run();
void dbg_break();
void dbg_setbp( unsigned atPC );
void dbg_clrbp( unsigned atPC );
void dbg_clrallbp();
bool exec();
void reinitExec();
void initForFnCall( unsigned in_PC );
void show_context( unsigned atPC );
void show_context( fmt::Writer& os, unsigned atPC );
int getDebugLevel() { return debug_level; }
void setDebugLevel( DEBUG_LEVEL level ) { debug_level = level; }
void setViewMode( bool vm ) { viewmode_ = vm; }
const std::string& scriptname() const;
bool empty_scriptname();
const EScriptProgram* prog() const;
private:
ref_ptr<EScriptProgram> prog_;
bool prog_ok_;
bool viewmode_;
bool runs_to_completion_;
bool debugging_;
enum DEBUG_STATE
{
DEBUG_STATE_NONE,
DEBUG_STATE_ATTACHING,
DEBUG_STATE_ATTACHED,
DEBUG_STATE_INS_TRACE,
DEBUG_STATE_INS_TRACE_BRK,
DEBUG_STATE_RUN,
DEBUG_STATE_BREAK_INTO,
DEBUG_STATE_STEP_INTO,
DEBUG_STATE_STEPPING_INTO,
DEBUG_STATE_STEP_OVER,
DEBUG_STATE_STEPPING_OVER
};
DEBUG_STATE debug_state_;
std::set<unsigned> breakpoints_;
std::set<unsigned> tmpbreakpoints_;
unsigned bp_skip_;
BObjectImp* func_result_;
private: // not implemented
Executor( const Executor& exec );
Executor& operator=( const Executor& exec );
#ifdef ESCRIPT_PROFILE
unsigned long GetTimeUs();
void profile_escript( std::string name, unsigned long profile_start );
#endif
};
inline const std::string& Executor::scriptname() const
{
return prog_->name;
}
inline bool Executor::empty_scriptname()
{
return prog_->name.get().empty();
}
inline const EScriptProgram* Executor::prog() const
{
return prog_.get();
}
inline bool Executor::runnable( void ) const
{
return run_ok_;
}
inline void Executor::calcrunnable()
{
run_ok_ = !error_ && !halt_;
}
inline void Executor::seterror( bool err )
{
error_ = err;
calcrunnable();
}
inline bool Executor::error() const
{
return error_;
}
inline void Executor::sethalt( bool halt )
{
halt_ = halt;
calcrunnable();
}
inline bool Executor::halt() const
{
return halt_;
}
inline bool Executor::debugging() const
{
return debugging_;
}
inline void Executor::setdebugging( bool debugging )
{
debugging_ = debugging;
}
inline bool Executor::running_to_completion() const
{
return runs_to_completion_;
}
inline void Executor::set_running_to_completion( bool to_completion )
{
runs_to_completion_ = to_completion;
}
} // namespace Bscript
} // namespace Pol
#endif