2017-07-13 10:26:03 +02:00
/*
* ERMInterpreter . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2011-12-14 00:23:17 +03:00
# include "StdInc.h"
2011-04-06 23:30:59 +03:00
# include "ERMInterpreter.h"
2011-05-22 21:46:52 +03:00
2011-12-14 00:23:17 +03:00
# include <cctype>
2014-10-02 17:23:22 +03:00
# include "../../lib/mapObjects/CObjectHandler.h"
# include "../../lib/mapObjects/MapObjects.h"
2011-06-20 14:41:04 +03:00
# include "../../lib/CHeroHandler.h"
# include "../../lib/CCreatureHandler.h"
2013-03-03 20:06:03 +03:00
# include "../../lib/VCMIDirs.h"
2014-04-20 10:13:37 +03:00
# include "../../lib/IGameCallback.h"
2014-06-27 11:12:45 +03:00
# include "../../lib/mapObjects/CGHeroInstance.h"
# include "../../lib/mapObjects/MiscObjects.h"
2011-04-06 23:30:59 +03:00
namespace spirit = boost : : spirit ;
2011-04-10 19:39:34 +03:00
using namespace VERMInterpreter ;
2014-11-14 06:45:44 +02:00
2011-05-17 22:24:18 +03:00
typedef int TUnusedType ;
2014-11-14 06:45:44 +02:00
2011-05-22 21:46:52 +03:00
ERMInterpreter * erm ;
2011-06-11 21:10:15 +03:00
Environment * topDyn ;
2011-05-17 22:24:18 +03:00
2011-04-06 23:30:59 +03:00
namespace ERMPrinter
{
//console printer
using namespace ERM ;
struct VarPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( TVarExpNotMacro const & val ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( val . varsym ) ;
2011-04-06 23:30:59 +03:00
if ( val . val . is_initialized ( ) )
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %d " , val . val . get ( ) ) ;
2011-04-06 23:30:59 +03:00
}
}
void operator ( ) ( TMacroUsage const & val ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " $%s$ " , val . macro ) ;
2011-04-06 23:30:59 +03:00
}
} ;
void varPrinter ( const TVarExp & var )
{
boost : : apply_visitor ( VarPrinterVisitor ( ) , var ) ;
}
struct IExpPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( int const & constant ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %d " , constant ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( TVarExp const & var ) const
{
varPrinter ( var ) ;
}
} ;
void iexpPrinter ( const TIexp & exp )
{
boost : : apply_visitor ( IExpPrinterVisitor ( ) , exp ) ;
}
struct IdentifierPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( TIexp const & iexp ) const
{
iexpPrinter ( iexp ) ;
}
void operator ( ) ( TArithmeticOp const & arop ) const
{
iexpPrinter ( arop . lhs ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %s " , arop . opcode ) ;
2011-04-06 23:30:59 +03:00
iexpPrinter ( arop . rhs ) ;
}
} ;
void identifierPrinter ( const boost : : optional < Tidentifier > & id )
{
if ( id . is_initialized ( ) )
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " identifier: " ) ;
2013-06-29 16:05:48 +03:00
for ( auto x : id . get ( ) )
2011-04-06 23:30:59 +03:00
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " # " ) ;
2011-04-06 23:30:59 +03:00
boost : : apply_visitor ( IdentifierPrinterVisitor ( ) , x ) ;
}
}
}
struct ConditionCondPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( TComparison const & cmp ) const
{
iexpPrinter ( cmp . lhs ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %s " , cmp . compSign ) ;
2011-04-06 23:30:59 +03:00
iexpPrinter ( cmp . rhs ) ;
}
void operator ( ) ( int const & flag ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " condflag %d " , flag ) ;
2011-04-06 23:30:59 +03:00
}
} ;
void conditionPrinter ( const boost : : optional < Tcondition > & cond )
{
if ( cond . is_initialized ( ) )
{
Tcondition condp = cond . get ( ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " condition: " ) ;
2011-04-06 23:30:59 +03:00
boost : : apply_visitor ( ConditionCondPrinterVisitor ( ) , condp . cond ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " cond type: %s " , condp . ctype ) ;
2011-04-06 23:30:59 +03:00
//recursive call
if ( condp . rhs . is_initialized ( ) )
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " rhs: " ) ;
2011-04-06 23:30:59 +03:00
boost : : optional < Tcondition > rhsc = condp . rhs . get ( ) . get ( ) ;
conditionPrinter ( rhsc ) ;
}
else
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " no rhs; " ) ;
2011-04-06 23:30:59 +03:00
}
}
}
struct BodyVarpPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( TVarExpNotMacro const & cmp ) const
{
if ( cmp . questionMark . is_initialized ( ) )
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %s " , cmp . questionMark . get ( ) ) ;
2011-04-06 23:30:59 +03:00
}
if ( cmp . val . is_initialized ( ) )
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " val:%d " , cmp . val . get ( ) ) ;
2011-04-06 23:30:59 +03:00
}
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " varsym: |%s| " , cmp . varsym ) ;
2011-04-06 23:30:59 +03:00
}
2011-05-14 16:20:19 +03:00
void operator ( ) ( TMacroUsage const & cmp ) const
2011-04-06 23:30:59 +03:00
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " ???$$%s$$ " , cmp . macro ) ;
2011-04-06 23:30:59 +03:00
}
} ;
struct BodyOptionItemPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( TVarConcatString const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " +concat \" " ) ;
2011-04-06 23:30:59 +03:00
varPrinter ( cmp . var ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " with %s " , cmp . string . str ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( TStringConstant const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " \" %s \" " , cmp . str ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( TCurriedString const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " cs: " ) ;
2011-04-06 23:30:59 +03:00
iexpPrinter ( cmp . iexp ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " '%s' " , cmp . string . str ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( TSemiCompare const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %s; rhs: " , cmp . compSign ) ;
2011-04-06 23:30:59 +03:00
iexpPrinter ( cmp . rhs ) ;
}
void operator ( ) ( TMacroUsage const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " $$%s$$ " , cmp . macro ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( TMacroDef const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " @@%s@@ " , cmp . macro ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( TIexp const & cmp ) const
{
iexpPrinter ( cmp ) ;
}
void operator ( ) ( TVarpExp const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " varp " ) ;
2011-04-06 23:30:59 +03:00
boost : : apply_visitor ( BodyVarpPrinterVisitor ( ) , cmp . var ) ;
}
void operator ( ) ( spirit : : unused_type const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " nothing " ) ;
2011-04-06 23:30:59 +03:00
}
} ;
struct BodyOptionVisitor : boost : : static_visitor < >
{
void operator ( ) ( TVRLogic const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %s " , cmp . opcode ) ;
2011-04-06 23:30:59 +03:00
iexpPrinter ( cmp . var ) ;
}
void operator ( ) ( TVRArithmetic const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %s " , cmp . opcode ) ;
2011-04-06 23:30:59 +03:00
iexpPrinter ( cmp . rhs ) ;
}
void operator ( ) ( TNormalBodyOption const & cmp ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %s~ " , cmp . optionCode ) ;
2013-06-29 16:05:48 +03:00
for ( auto optList : cmp . params )
2011-04-06 23:30:59 +03:00
{
boost : : apply_visitor ( BodyOptionItemPrinterVisitor ( ) , optList ) ;
}
}
} ;
void bodyPrinter ( const Tbody & body )
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " body items: " ) ;
2013-06-29 16:05:48 +03:00
for ( auto bi : body )
2011-04-06 23:30:59 +03:00
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " ( " ) ;
2011-04-06 23:30:59 +03:00
apply_visitor ( BodyOptionVisitor ( ) , bi ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " ) " ) ;
2011-04-06 23:30:59 +03:00
}
}
struct CommandPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( Ttrigger const & trig ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " trigger: %s " , trig . name ) ;
2011-04-06 23:30:59 +03:00
identifierPrinter ( trig . identifier ) ;
conditionPrinter ( trig . condition ) ;
}
void operator ( ) ( Tinstruction const & trig ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " instruction: %s " , trig . name ) ;
2011-04-06 23:30:59 +03:00
identifierPrinter ( trig . identifier ) ;
conditionPrinter ( trig . condition ) ;
bodyPrinter ( trig . body ) ;
}
void operator ( ) ( Treceiver const & trig ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " receiver: %s " , trig . name ) ;
2011-04-06 23:30:59 +03:00
identifierPrinter ( trig . identifier ) ;
conditionPrinter ( trig . condition ) ;
if ( trig . body . is_initialized ( ) )
bodyPrinter ( trig . body . get ( ) ) ;
}
void operator ( ) ( TPostTrigger const & trig ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " post trigger: %s " , trig . name ) ;
2011-04-06 23:30:59 +03:00
identifierPrinter ( trig . identifier ) ;
conditionPrinter ( trig . condition ) ;
}
} ;
struct LinePrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( Tcommand const & cmd ) const
{
CommandPrinterVisitor un ;
boost : : apply_visitor ( un , cmd . cmd ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " Line comment: %s " , cmd . comment ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( std : : string const & comment ) const
{
}
void operator ( ) ( spirit : : unused_type const & nothing ) const
{
}
} ;
void printERM ( const TERMline & ast )
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " " ) ;
2011-04-06 23:30:59 +03:00
boost : : apply_visitor ( LinePrinterVisitor ( ) , ast ) ;
}
void printTVExp ( const TVExp & exp ) ;
struct VOptionPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( TVExp const & cmd ) const
{
printTVExp ( cmd ) ;
}
void operator ( ) ( TSymbol const & cmd ) const
{
2013-06-29 16:05:48 +03:00
for ( auto mod : cmd . symModifier )
2011-04-06 23:30:59 +03:00
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( mod ) ;
2011-04-06 23:30:59 +03:00
}
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( cmd . sym ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( char const & cmd ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " '%s' " , cmd ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( int const & cmd ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %d " , cmd ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( double const & cmd ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %f " , cmd ) ;
2011-04-06 23:30:59 +03:00
}
void operator ( ) ( TERMline const & cmd ) const
{
printERM ( cmd ) ;
}
void operator ( ) ( TStringConstant const & cmd ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " ^%s^ " , cmd . str ) ;
2011-04-06 23:30:59 +03:00
}
} ;
void printTVExp ( const TVExp & exp )
{
2013-06-29 16:05:48 +03:00
for ( auto mod : exp . modifier )
2011-04-06 23:30:59 +03:00
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %s " , mod ) ;
2011-04-06 23:30:59 +03:00
}
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " [ " ) ;
2013-06-29 16:05:48 +03:00
for ( auto opt : exp . children )
2011-04-06 23:30:59 +03:00
{
boost : : apply_visitor ( VOptionPrinterVisitor ( ) , opt ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " " ) ;
2011-04-06 23:30:59 +03:00
}
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " ] " ) ;
2011-04-06 23:30:59 +03:00
}
struct TLPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( TVExp const & cmd ) const
{
printTVExp ( cmd ) ;
}
void operator ( ) ( TERMline const & cmd ) const
{
printERM ( cmd ) ;
}
} ;
void printAST ( const TLine & ast )
{
boost : : apply_visitor ( TLPrinterVisitor ( ) , ast ) ;
}
}
void ERMInterpreter : : scanForScripts ( )
{
using namespace boost : : filesystem ;
//parser checking
2014-08-21 23:26:28 +03:00
const path dataPath = VCMIDirs : : get ( ) . dataPaths ( ) . back ( ) / " Data " / " s " ;
if ( ! exists ( dataPath ) )
2011-04-06 23:30:59 +03:00
{
2016-08-29 18:49:52 +02:00
logGlobal - > warn ( " Warning: Folder %s doesn't exist! " , dataPath . string ( ) ) ;
2011-04-06 23:30:59 +03:00
return ;
}
directory_iterator enddir ;
2014-08-21 23:26:28 +03:00
for ( directory_iterator dir ( dataPath ) ; dir ! = enddir ; dir + + )
2011-04-06 23:30:59 +03:00
{
if ( is_regular ( dir - > status ( ) ) )
{
2014-08-21 23:26:28 +03:00
const std : : string ext = boost : : to_upper_copy ( dir - > path ( ) . extension ( ) . string ( ) ) ;
if ( ext = = " .ERM " | | ext = = " .VERM " )
2011-04-06 23:30:59 +03:00
{
ERMParser ep ( dir - > path ( ) . string ( ) ) ;
2017-07-16 11:58:05 +02:00
FileInfo * finfo = new FileInfo ( ) ;
2011-04-10 19:39:34 +03:00
finfo - > filename = dir - > path ( ) . string ( ) ;
2011-05-11 22:53:55 +03:00
std : : vector < LineInfo > buf = ep . parseFile ( ) ;
2011-04-10 19:39:34 +03:00
finfo - > length = buf . size ( ) ;
files . push_back ( finfo ) ;
for ( int g = 0 ; g < buf . size ( ) ; + + g )
{
2011-05-11 22:53:55 +03:00
scripts [ LinePointer ( finfo , g , buf [ g ] . realLineNum ) ] = buf [ g ] . tl ;
2011-04-10 19:39:34 +03:00
}
2011-04-06 23:30:59 +03:00
}
}
}
}
2017-07-15 13:08:20 +02:00
void ERMInterpreter : : printScripts ( EPrintMode mode )
2011-04-06 23:30:59 +03:00
{
2011-04-10 19:39:34 +03:00
std : : map < LinePointer , ERM : : TLine > : : const_iterator prevIt ;
for ( std : : map < LinePointer , ERM : : TLine > : : const_iterator it = scripts . begin ( ) ; it ! = scripts . end ( ) ; + + it )
2011-04-06 23:30:59 +03:00
{
2011-04-10 19:39:34 +03:00
if ( it = = scripts . begin ( ) | | it - > first . file ! = prevIt - > first . file )
2011-04-06 23:30:59 +03:00
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " ----------------- script %s ------------------ " , it - > first . file - > filename ) ;
2011-04-06 23:30:59 +03:00
}
2011-06-11 02:50:32 +03:00
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " %d " , it - > first . realLineNum ) ;
2011-04-10 19:39:34 +03:00
ERMPrinter : : printAST ( it - > second ) ;
prevIt = it ;
}
}
2011-04-16 20:39:38 +03:00
struct ScriptScanner : boost : : static_visitor < >
{
ERMInterpreter * interpreter ;
LinePointer lp ;
ScriptScanner ( ERMInterpreter * interpr , const LinePointer & _lp ) : interpreter ( interpr ) , lp ( _lp )
{ }
void operator ( ) ( TVExp const & cmd ) const
{
//
}
void operator ( ) ( TERMline const & cmd ) const
{
if ( cmd . which ( ) = = 0 ) //TCommand
{
Tcommand tcmd = boost : : get < Tcommand > ( cmd ) ;
switch ( tcmd . cmd . which ( ) )
{
case 0 : //trigger
{
Trigger trig ;
trig . line = lp ;
interpreter - > triggers [ TriggerType ( boost : : get < ERM : : Ttrigger > ( tcmd . cmd ) . name ) ] . push_back ( trig ) ;
}
break ;
case 3 : //post trigger
{
Trigger trig ;
trig . line = lp ;
interpreter - > postTriggers [ TriggerType ( boost : : get < ERM : : TPostTrigger > ( tcmd . cmd ) . name ) ] . push_back ( trig ) ;
}
break ;
default :
break ;
}
}
2012-02-16 20:10:58 +03:00
2011-04-16 20:39:38 +03:00
}
} ;
2011-04-10 19:39:34 +03:00
void ERMInterpreter : : scanScripts ( )
{
for ( std : : map < LinePointer , ERM : : TLine > : : const_iterator it = scripts . begin ( ) ; it ! = scripts . end ( ) ; + + it )
{
2011-04-16 20:39:38 +03:00
boost : : apply_visitor ( ScriptScanner ( this , it - > first ) , it - > second ) ;
2011-04-10 19:39:34 +03:00
}
}
ERMInterpreter : : ERMInterpreter ( )
{
2011-06-11 21:10:15 +03:00
erm = this ;
2013-06-26 17:25:23 +03:00
curFunc = nullptr ;
curTrigger = nullptr ;
2011-04-10 19:39:34 +03:00
globalEnv = new Environment ( ) ;
2011-06-11 21:10:15 +03:00
topDyn = globalEnv ;
2011-04-10 19:39:34 +03:00
}
2017-07-15 13:08:20 +02:00
void ERMInterpreter : : executeTrigger ( VERMInterpreter : : Trigger & trig , int funNum , std : : vector < int > funParams )
2011-04-10 19:39:34 +03:00
{
2011-05-12 23:49:37 +03:00
//function-related logic
if ( funNum ! = - 1 )
{
curFunc = getFuncVars ( funNum ) ;
for ( int g = 1 ; g < = FunctionLocalVars : : NUM_PARAMETERS ; + + g )
{
2011-05-14 16:20:19 +03:00
curFunc - > getParam ( g ) = g - 1 < funParams . size ( ) ? funParams [ g - 1 ] : 0 ;
2011-05-12 23:49:37 +03:00
}
}
2011-05-17 22:24:18 +03:00
else
curFunc = getFuncVars ( 0 ) ;
2011-05-12 23:49:37 +03:00
2011-05-03 17:45:57 +03:00
//skip the first line
2011-04-22 23:33:34 +03:00
LinePointer lp = trig . line ;
+ + lp ;
for ( ; lp . isValid ( ) ; + + lp )
2011-04-10 19:39:34 +03:00
{
ERM : : TLine curLine = retrieveLine ( lp ) ;
if ( isATrigger ( curLine ) )
break ;
executeLine ( lp ) ;
2011-04-06 23:30:59 +03:00
}
2011-05-12 23:49:37 +03:00
2013-06-26 17:25:23 +03:00
curFunc = nullptr ;
2011-04-06 23:30:59 +03:00
}
2011-04-10 19:39:34 +03:00
bool ERMInterpreter : : isATrigger ( const ERM : : TLine & line )
{
switch ( line . which ( ) )
{
case 0 : //v-exp
{
TVExp vexp = boost : : get < TVExp > ( line ) ;
if ( vexp . children . size ( ) = = 0 )
return false ;
switch ( getExpType ( vexp . children [ 0 ] ) )
{
case SYMBOL :
{
//TODO: what about sym modifiers?
2011-04-16 20:39:38 +03:00
//TOOD: macros?
2011-04-10 19:39:34 +03:00
ERM : : TSymbol sym = boost : : get < ERM : : TSymbol > ( vexp . children [ 0 ] ) ;
return sym . sym = = triggerSymbol | | sym . sym = = postTriggerSymbol ;
}
break ;
case TCMD :
return isCMDATrigger ( boost : : get < ERM : : Tcommand > ( vexp . children [ 0 ] ) ) ;
break ;
default :
return false ;
break ;
}
}
break ;
case 1 : //erm
{
2011-05-11 22:53:55 +03:00
TERMline ermline = boost : : get < TERMline > ( line ) ;
switch ( ermline . which ( ) )
2011-04-10 19:39:34 +03:00
{
case 0 : //tcmd
2011-05-11 22:53:55 +03:00
return isCMDATrigger ( boost : : get < ERM : : Tcommand > ( ermline ) ) ;
2011-04-10 19:39:34 +03:00
break ;
default :
return false ;
break ;
}
}
break ;
default :
assert ( 0 ) ; //it should never happen
break ;
}
assert ( 0 ) ;
2014-04-19 20:44:21 +03:00
return false ;
2011-04-10 19:39:34 +03:00
}
ERM : : EVOtions ERMInterpreter : : getExpType ( const ERM : : TVOption & opt )
{
//MAINTENANCE: keep it correct!
return static_cast < ERM : : EVOtions > ( opt . which ( ) ) ;
}
bool ERMInterpreter : : isCMDATrigger ( const ERM : : Tcommand & cmd )
{
switch ( cmd . cmd . which ( ) )
{
case 0 : //trigger
case 3 : //post trigger
return true ;
break ;
default :
return false ;
break ;
}
}
2011-05-22 21:46:52 +03:00
ERM : : TLine & ERMInterpreter : : retrieveLine ( LinePointer linePtr )
2011-04-10 19:39:34 +03:00
{
2011-05-11 22:53:55 +03:00
return scripts . find ( linePtr ) - > second ;
2011-04-10 19:39:34 +03:00
}
2011-04-16 20:39:38 +03:00
/////////
//code execution
2011-05-15 21:21:07 +03:00
template < typename OwnerType >
struct StandardBodyOptionItemVisitor : boost : : static_visitor < >
2011-05-03 17:45:57 +03:00
{
2011-05-22 21:46:52 +03:00
typedef OwnerType TReceiverType ;
2011-05-15 21:21:07 +03:00
OwnerType & owner ;
explicit StandardBodyOptionItemVisitor ( OwnerType & _owner ) : owner ( _owner )
{ }
virtual void operator ( ) ( TVarConcatString const & cmp ) const
{
throw EScriptExecError ( " String concatenation not allowed in this receiver " ) ;
}
virtual void operator ( ) ( TStringConstant const & cmp ) const
{
throw EScriptExecError ( " String constant not allowed in this receiver " ) ;
}
virtual void operator ( ) ( TCurriedString const & cmp ) const
{
throw EScriptExecError ( " Curried string not allowed in this receiver " ) ;
}
virtual void operator ( ) ( TSemiCompare const & cmp ) const
{
throw EScriptExecError ( " Semi comparison not allowed in this receiver " ) ;
}
2011-05-16 15:11:00 +03:00
// virtual void operator()(TMacroUsage const& cmp) const
// {
// throw EScriptExecError("Macro usage not allowed in this receiver");
// }
2011-05-15 21:21:07 +03:00
virtual void operator ( ) ( TMacroDef const & cmp ) const
{
throw EScriptExecError ( " Macro definition not allowed in this receiver " ) ;
}
virtual void operator ( ) ( TIexp const & cmp ) const
{
throw EScriptExecError ( " i-expression not allowed in this receiver " ) ;
}
virtual void operator ( ) ( TVarpExp const & cmp ) const
{
throw EScriptExecError ( " Varp expression not allowed in this receiver " ) ;
}
virtual void operator ( ) ( spirit : : unused_type const & cmp ) const
{
throw EScriptExecError ( " \' Nothing \' not allowed in this receiver " ) ;
}
} ;
template < typename T >
struct StandardReceiverVisitor : boost : : static_visitor < >
{
ERMInterpreter * interp ;
T identifier ;
StandardReceiverVisitor ( ERMInterpreter * _interpr , T ident ) : interp ( _interpr ) , identifier ( ident )
{ }
2011-05-03 17:45:57 +03:00
2011-05-15 21:21:07 +03:00
virtual void operator ( ) ( TVRLogic const & trig ) const
{
throw EScriptExecError ( " VR logic not allowed in this receiver! " ) ;
}
virtual void operator ( ) ( TVRArithmetic const & trig ) const
{
throw EScriptExecError ( " VR arithmetic not allowed in this receiver! " ) ;
}
virtual void operator ( ) ( TNormalBodyOption const & trig ) const = 0 ;
2011-05-22 21:46:52 +03:00
template < typename OptionPerformer >
void performOptionTakingOneParamter ( const ERM : : TNormalBodyOptionList & params ) const
{
if ( params . size ( ) = = 1 )
{
ERM : : TBodyOptionItem boi = params [ 0 ] ;
boost : : apply_visitor (
2011-05-27 16:49:18 +03:00
OptionPerformer ( * const_cast < typename OptionPerformer : : TReceiverType * > ( static_cast < const typename OptionPerformer : : TReceiverType * > ( this ) ) ) , boi ) ;
2011-05-22 21:46:52 +03:00
}
else
throw EScriptExecError ( " This receiver option takes exactly 1 parameter! " ) ;
}
template < template < int opcode > class OptionPerformer >
void performOptionTakingOneParamterWithIntDispatcher ( const ERM : : TNormalBodyOptionList & params ) const
{
if ( params . size ( ) = = 2 )
{
int optNum = erm - > getIexp ( params [ 0 ] ) . getInt ( ) ;
ERM : : TBodyOptionItem boi = params [ 1 ] ;
switch ( optNum )
{
case 0 :
boost : : apply_visitor (
2011-05-27 16:49:18 +03:00
OptionPerformer < 0 > ( * const_cast < typename OptionPerformer < 0 > : : TReceiverType * > ( static_cast < const typename OptionPerformer < 0 > : : TReceiverType * > ( this ) ) ) , boi ) ;
2011-05-22 21:46:52 +03:00
break ;
default :
throw EScriptExecError ( " Wrong number of option code! " ) ;
break ;
}
}
else
throw EScriptExecError ( " This receiver option takes exactly 2 parameters! " ) ;
}
2011-05-03 17:45:57 +03:00
} ;
2011-05-22 21:46:52 +03:00
////HE
struct HEPerformer ;
2011-05-03 17:45:57 +03:00
2011-05-22 21:46:52 +03:00
template < int opcode >
struct HE_BPerformer : StandardBodyOptionItemVisitor < HEPerformer >
2011-05-15 21:21:07 +03:00
{
2011-05-28 01:34:58 +03:00
explicit HE_BPerformer ( HEPerformer & _owner ) : StandardBodyOptionItemVisitor < HEPerformer > ( _owner )
2011-05-22 21:46:52 +03:00
{ }
using StandardBodyOptionItemVisitor < HEPerformer > : : operator ( ) ;
2011-05-15 21:21:07 +03:00
2013-06-26 17:25:23 +03:00
void operator ( ) ( TIexp const & cmp ) const override ;
void operator ( ) ( TVarpExp const & cmp ) const override ;
2011-05-15 21:21:07 +03:00
} ;
2011-05-03 17:45:57 +03:00
2011-05-22 21:46:52 +03:00
template < int opcode >
void HE_BPerformer < opcode > : : operator ( ) ( TIexp const & cmp ) const
2011-05-03 17:45:57 +03:00
{
2011-05-22 21:46:52 +03:00
throw EScriptExecError ( " Setting hero name is not implemented! " ) ;
}
template < int opcode >
struct HE_CPerformer : StandardBodyOptionItemVisitor < HEPerformer >
{
2011-05-28 01:34:58 +03:00
explicit HE_CPerformer ( HEPerformer & _owner ) : StandardBodyOptionItemVisitor < HEPerformer > ( _owner )
2011-05-03 17:45:57 +03:00
{ }
2011-05-22 21:46:52 +03:00
using StandardBodyOptionItemVisitor < HEPerformer > : : operator ( ) ;
2013-06-26 17:25:23 +03:00
void operator ( ) ( TIexp const & cmp ) const override ;
void operator ( ) ( TVarpExp const & cmp ) const override ;
2011-05-22 21:46:52 +03:00
} ;
template < int opcode >
void HE_CPerformer < opcode > : : operator ( ) ( TIexp const & cmp ) const
{
throw EScriptExecError ( " Setting hero army is not implemented! " ) ;
}
struct HEPerformer : StandardReceiverVisitor < const CGHeroInstance * >
{
2011-05-28 01:34:58 +03:00
HEPerformer ( ERMInterpreter * _interpr , const CGHeroInstance * hero ) : StandardReceiverVisitor < const CGHeroInstance * > ( _interpr , hero )
2011-05-22 21:46:52 +03:00
{ }
using StandardReceiverVisitor < const CGHeroInstance * > : : operator ( ) ;
2011-05-03 17:45:57 +03:00
2013-06-26 17:25:23 +03:00
void operator ( ) ( TNormalBodyOption const & trig ) const override
2011-05-03 17:45:57 +03:00
{
switch ( trig . optionCode )
{
2011-05-22 21:46:52 +03:00
case ' B ' :
2011-05-15 21:21:07 +03:00
{
2011-05-22 21:46:52 +03:00
performOptionTakingOneParamterWithIntDispatcher < HE_BPerformer > ( trig . params ) ;
2011-05-15 21:21:07 +03:00
}
break ;
2011-05-22 21:46:52 +03:00
case ' C ' :
2011-05-03 17:45:57 +03:00
{
2011-05-22 21:46:52 +03:00
const ERM : : TNormalBodyOptionList & params = trig . params ;
if ( params . size ( ) = = 4 )
2011-05-03 17:45:57 +03:00
{
2011-05-22 21:46:52 +03:00
if ( erm - > getIexp ( params [ 0 ] ) . getInt ( ) = = 0 )
{
2013-02-16 17:03:47 +03:00
SlotID slot = SlotID ( erm - > getIexp ( params [ 1 ] ) . getInt ( ) ) ;
2011-06-20 14:41:04 +03:00
const CStackInstance * stack = identifier - > getStackPtr ( slot ) ;
2011-05-22 21:46:52 +03:00
if ( params [ 2 ] . which ( ) = = 6 ) //varp
{
2011-06-20 14:41:04 +03:00
IexpValStr lhs = erm - > getIexp ( boost : : get < ERM : : TVarpExp > ( params [ 2 ] ) ) ;
if ( stack )
lhs . setTo ( stack - > getCreatureID ( ) ) ;
else
lhs . setTo ( - 1 ) ;
2011-05-22 21:46:52 +03:00
}
else
throw EScriptExecError ( " Setting stack creature type is not implemented! " ) ;
if ( params [ 3 ] . which ( ) = = 6 ) //varp
{
2013-02-16 17:03:47 +03:00
erm - > getIexp ( boost : : get < ERM : : TVarpExp > ( params [ 3 ] ) ) . setTo ( identifier - > getStackCount ( SlotID ( slot ) ) ) ;
2011-05-22 21:46:52 +03:00
}
else
throw EScriptExecError ( " Setting stack count is not implemented! " ) ;
}
2012-02-16 20:10:58 +03:00
else
2011-05-22 21:46:52 +03:00
throw EScriptExecError ( " Slot number must be an evaluable i-exp " ) ;
2011-05-03 17:45:57 +03:00
}
2011-05-22 21:46:52 +03:00
//todo else if(14 params)
2011-05-03 17:45:57 +03:00
else
2011-05-22 21:46:52 +03:00
throw EScriptExecError ( " Slot number must be an evaluable i-exp " ) ;
2011-05-15 21:21:07 +03:00
}
break ;
2011-05-22 21:46:52 +03:00
case ' E ' :
2011-05-15 21:21:07 +03:00
break ;
2011-05-22 21:46:52 +03:00
case ' N ' :
2011-05-15 21:21:07 +03:00
break ;
2011-05-03 17:45:57 +03:00
default :
break ;
}
}
2011-05-22 21:46:52 +03:00
} ;
2011-06-11 02:50:32 +03:00
struct IFPerformer ;
struct IF_MPerformer : StandardBodyOptionItemVisitor < IFPerformer >
{
explicit IF_MPerformer ( IFPerformer & _owner ) : StandardBodyOptionItemVisitor < IFPerformer > ( _owner ) { }
using StandardBodyOptionItemVisitor < IFPerformer > : : operator ( ) ;
2013-06-26 17:25:23 +03:00
void operator ( ) ( TStringConstant const & cmp ) const override ;
2011-06-11 02:50:32 +03:00
} ;
2011-06-20 14:41:04 +03:00
//according to the ERM help:
//"%%" -> "%"
//"%V#" -> current value of # flag.
//"%Vf"..."%Vt" -> current value of corresponding variable.
//"%W1"..."%W100" -> current value of corresponding hero variable.
//"%X1"..."%X16" -> current value of corresponding function parameter.
//"%Y1"..."%Y100" -> current value of corresponding local variable.
//"%Z1"..."%Z500" -> current value of corresponding string variable.
//"%$macro$" -> macro name of corresponding variable
//"%Dd" -> current day of week
//"%Dw" -> current week
//"%Dm" -> current month
//"%Da" -> current day from beginning of the game
//"%Gc" -> the color of current gamer in text
struct StringFormatter
2011-06-11 02:50:32 +03:00
{
2011-06-20 14:41:04 +03:00
int pos ;
int tokenLength ;
2013-06-26 17:25:23 +03:00
size_t percentPos ;
2011-06-20 14:41:04 +03:00
int charsToReplace ;
std : : string & msg ;
2011-06-11 02:50:32 +03:00
2011-06-28 17:19:16 +03:00
StringFormatter ( std : : string & MSG ) : pos ( 0 ) , msg ( MSG ) { }
2011-06-11 02:50:32 +03:00
2011-06-20 14:41:04 +03:00
static void format ( std : : string & msg )
2011-06-11 02:50:32 +03:00
{
2011-06-20 14:41:04 +03:00
StringFormatter sf ( msg ) ;
sf . format ( ) ;
2011-06-11 02:50:32 +03:00
}
// startpos is the first digit
// digits will be converted to number and returned
2011-06-20 14:41:04 +03:00
// ADDITIVE on digitsUsed
2012-02-16 20:10:58 +03:00
int getNum ( )
2011-06-11 02:50:32 +03:00
{
2011-06-20 14:41:04 +03:00
int toAdd = 0 ;
int numStart = percentPos + 2 ;
2013-06-26 17:25:23 +03:00
size_t numEnd = msg . find_first_not_of ( " 1234567890 " , numStart ) ;
2011-06-11 02:50:32 +03:00
if ( numEnd = = std : : string : : npos )
2011-06-20 14:41:04 +03:00
toAdd = msg . size ( ) - numStart ;
2011-06-11 02:50:32 +03:00
else
2011-06-20 14:41:04 +03:00
toAdd = numEnd - numStart ;
2011-06-11 02:50:32 +03:00
2011-06-20 14:41:04 +03:00
charsToReplace + = toAdd ;
return boost : : lexical_cast < int > ( msg . substr ( numStart , toAdd ) ) ;
2011-06-11 02:50:32 +03:00
}
2011-06-20 14:41:04 +03:00
void format ( )
2011-06-11 02:50:32 +03:00
{
while ( pos < msg . size ( ) )
{
2011-06-20 14:41:04 +03:00
percentPos = msg . find_first_of ( ' % ' , pos ) ;
charsToReplace = 1 ; //at least the same '%' needs to be replaced
std : : ostringstream replaceWithWhat ;
2011-06-11 02:50:32 +03:00
if ( percentPos = = std : : string : : npos ) //processing done?
break ;
if ( percentPos + 1 > = msg . size ( ) ) //at least one character after % is required
2012-02-16 20:10:58 +03:00
throw EScriptExecError ( " Formatting error: % at the end of string! " ) ;
2011-06-20 14:41:04 +03:00
charsToReplace + + ; //the sign after % is consumed
2011-06-11 02:50:32 +03:00
switch ( msg [ percentPos + 1 ] )
{
case ' % ' :
2011-06-20 14:41:04 +03:00
replaceWithWhat < < ' % ' ;
2011-06-11 02:50:32 +03:00
break ;
2011-06-20 14:41:04 +03:00
case ' F ' :
replaceWithWhat < < erm - > ermGlobalEnv - > getFlag ( getNum ( ) ) ;
break ;
case ' V ' :
if ( std : : isdigit ( msg [ percentPos + 2 ] ) )
replaceWithWhat < < erm - > ermGlobalEnv - > getStandardVar ( getNum ( ) ) ;
else
2011-06-11 02:50:32 +03:00
{
2011-06-20 14:41:04 +03:00
charsToReplace + + ;
replaceWithWhat < < erm - > ermGlobalEnv - > getQuickVar ( msg [ percentPos + 2 ] ) ;
2011-06-11 02:50:32 +03:00
}
2011-06-21 03:00:49 +03:00
break ;
2011-06-20 14:41:04 +03:00
case ' X ' :
replaceWithWhat < < erm - > getVar ( " x " , getNum ( ) ) . getInt ( ) ;
2011-06-11 02:50:32 +03:00
break ;
2011-06-20 14:41:04 +03:00
case ' Z ' :
replaceWithWhat < < erm - > ermGlobalEnv - > getZVar ( getNum ( ) ) ;
break ;
default :
throw EScriptExecError ( " Formatting error: unrecognized token indicator after %! " ) ;
2011-06-11 02:50:32 +03:00
}
2011-06-20 14:41:04 +03:00
msg . replace ( percentPos , charsToReplace , replaceWithWhat . str ( ) ) ;
pos = percentPos + 1 ;
}
}
} ;
struct IFPerformer : StandardReceiverVisitor < TUnusedType >
{
IFPerformer ( ERMInterpreter * _interpr ) : StandardReceiverVisitor < TUnusedType > ( _interpr , 0 )
{ }
using StandardReceiverVisitor < TUnusedType > : : operator ( ) ;
2013-06-26 17:25:23 +03:00
void operator ( ) ( TNormalBodyOption const & trig ) const override
2011-06-20 14:41:04 +03:00
{
switch ( trig . optionCode )
{
case ' M ' : //Show the message (Text) or contents of z$ variable on the screen immediately.
performOptionTakingOneParamter < IF_MPerformer > ( trig . params ) ;
break ;
default :
break ;
2011-06-11 02:50:32 +03:00
}
}
void showMessage ( const std : : string & msg )
{
std : : string msgToFormat = msg ;
2011-06-20 14:41:04 +03:00
StringFormatter : : format ( msgToFormat ) ;
2011-06-11 02:50:32 +03:00
acb - > showInfoDialog ( msgToFormat , icb - > getLocalPlayer ( ) ) ;
}
} ;
void IF_MPerformer : : operator ( ) ( TStringConstant const & cmp ) const
{
owner . showMessage ( cmp . str ) ;
}
2011-05-03 17:45:57 +03:00
2011-05-28 01:34:58 +03:00
template < int opcode >
void HE_BPerformer < opcode > : : operator ( ) ( TVarpExp const & cmp ) const
{
erm - > getIexp ( cmp ) . setTo ( owner . identifier - > name ) ;
}
template < int opcode >
void HE_CPerformer < opcode > : : operator ( ) ( TVarpExp const & cmp ) const
{
erm - > getIexp ( cmp ) . setTo ( owner . identifier - > name ) ;
}
2011-05-03 17:45:57 +03:00
2011-05-22 21:46:52 +03:00
////MA
struct MAPerformer ;
struct MA_PPerformer : StandardBodyOptionItemVisitor < MAPerformer >
2011-05-07 18:13:56 +03:00
{
2011-05-22 21:46:52 +03:00
explicit MA_PPerformer ( MAPerformer & _owner ) ;
using StandardBodyOptionItemVisitor < MAPerformer > : : operator ( ) ;
2013-06-26 17:25:23 +03:00
void operator ( ) ( TIexp const & cmp ) const override ;
void operator ( ) ( TVarpExp const & cmp ) const override ;
2011-05-22 21:46:52 +03:00
} ;
2011-05-03 17:45:57 +03:00
2011-05-17 22:24:18 +03:00
struct MAPerformer : StandardReceiverVisitor < TUnusedType >
{
2011-05-28 01:34:58 +03:00
MAPerformer ( ERMInterpreter * _interpr ) : StandardReceiverVisitor < TUnusedType > ( _interpr , 0 )
2011-05-17 22:24:18 +03:00
{ }
using StandardReceiverVisitor < TUnusedType > : : operator ( ) ;
2013-06-26 17:25:23 +03:00
void operator ( ) ( TNormalBodyOption const & trig ) const override
2011-05-17 22:24:18 +03:00
{
switch ( trig . optionCode )
{
case ' A ' : //sgc monster attack
break ;
case ' B ' : //spell?
break ;
case ' P ' : //hit points
{
//TODO
}
break ;
default :
break ;
}
}
2012-02-16 20:10:58 +03:00
2011-05-17 22:24:18 +03:00
} ;
2011-05-22 21:46:52 +03:00
void MA_PPerformer : : operator ( ) ( TIexp const & cmp ) const
{
}
void MA_PPerformer : : operator ( ) ( TVarpExp const & cmp ) const
{
}
////MO
struct MOPerformer ;
struct MO_GPerformer : StandardBodyOptionItemVisitor < MOPerformer >
{
2011-05-28 01:34:58 +03:00
explicit MO_GPerformer ( MOPerformer & _owner ) : StandardBodyOptionItemVisitor < MOPerformer > ( _owner )
2011-05-22 21:46:52 +03:00
{ }
using StandardBodyOptionItemVisitor < MOPerformer > : : operator ( ) ;
2013-06-26 17:25:23 +03:00
void operator ( ) ( TVarpExp const & cmp ) const override ;
void operator ( ) ( TIexp const & cmp ) const override ;
2011-05-22 21:46:52 +03:00
} ;
struct MOPerformer : StandardReceiverVisitor < int3 >
{
2011-05-28 01:34:58 +03:00
MOPerformer ( ERMInterpreter * _interpr , int3 pos ) : StandardReceiverVisitor < int3 > ( _interpr , pos )
2011-05-22 21:46:52 +03:00
{ }
using StandardReceiverVisitor < int3 > : : operator ( ) ;
2013-06-26 17:25:23 +03:00
void operator ( ) ( TNormalBodyOption const & trig ) const override
2011-05-22 21:46:52 +03:00
{
switch ( trig . optionCode )
{
case ' G ' :
{
performOptionTakingOneParamter < MO_GPerformer > ( trig . params ) ;
}
break ;
default :
break ;
}
}
} ;
void MO_GPerformer : : operator ( ) ( TIexp const & cmp ) const
{
throw EScriptExecError ( " Setting monster count is not implemented yet! " ) ;
}
void MO_GPerformer : : operator ( ) ( TVarpExp const & cmp ) const
{
const CGCreature * cre = erm - > getObjFromAs < CGCreature > ( owner . identifier ) ;
2013-02-16 17:03:47 +03:00
erm - > getIexp ( cmp ) . setTo ( cre - > getStackCount ( SlotID ( 0 ) ) ) ;
2011-05-22 21:46:52 +03:00
}
2011-05-03 17:45:57 +03:00
2011-05-22 21:46:52 +03:00
struct ConditionDisemboweler ;
//OB
2011-05-16 15:11:00 +03:00
struct OBPerformer ;
struct OB_UPerformer : StandardBodyOptionItemVisitor < OBPerformer >
{
2011-05-28 01:34:58 +03:00
explicit OB_UPerformer ( OBPerformer & owner ) : StandardBodyOptionItemVisitor < OBPerformer > ( owner )
2011-05-16 15:11:00 +03:00
{ }
using StandardBodyOptionItemVisitor < OBPerformer > : : operator ( ) ;
virtual void operator ( ) ( TIexp const & cmp ) const ;
virtual void operator ( ) ( TVarpExp const & cmp ) const ;
} ;
2011-05-15 21:21:07 +03:00
struct OBPerformer : StandardReceiverVisitor < int3 >
{
2011-05-28 01:34:58 +03:00
OBPerformer ( ERMInterpreter * _interpr , int3 objPos ) : StandardReceiverVisitor < int3 > ( _interpr , objPos )
2011-05-15 21:21:07 +03:00
{ }
using StandardReceiverVisitor < int3 > : : operator ( ) ; //it removes compilation error... not sure why it *must* be here
void operator ( ) ( TNormalBodyOption const & trig ) const
{
switch ( trig . optionCode )
{
case ' B ' : //removes description hint
{
//TODO
}
break ;
case ' C ' : //sgc of control word of object
{
//TODO
}
break ;
case ' D ' : //disable gamer to use object
{
//TODO
}
break ;
case ' E ' : //enable gamer to use object
{
//TODO
}
break ;
case ' H ' : //replace hint for object
{
//TODO
}
break ;
case ' M ' : //disabling messages and questions
{
//TODO
}
break ;
2011-05-16 15:11:00 +03:00
case ' R ' : //enable all gamers to use object
2011-05-15 21:21:07 +03:00
{
//TODO
}
break ;
case ' S ' : //disable all gamers to use object
{
//TODO
}
break ;
case ' T ' : //sgc of obj type
{
//TODO
}
break ;
case ' U ' : //sgc of obj subtype
{
2011-05-22 21:46:52 +03:00
performOptionTakingOneParamter < OB_UPerformer > ( trig . params ) ;
2011-05-15 21:21:07 +03:00
}
break ;
default :
throw EScriptExecError ( " Wrong OB receiver option! " ) ;
break ;
}
}
} ;
2011-05-16 15:11:00 +03:00
void OB_UPerformer : : operator ( ) ( TIexp const & cmp ) const
{
IexpValStr val = owner . interp - > getIexp ( cmp ) ;
2011-05-22 21:46:52 +03:00
throw EScriptExecError ( " Setting subID is not implemented yet! " ) ;
2011-05-16 15:11:00 +03:00
}
void OB_UPerformer : : operator ( ) ( TVarpExp const & cmp ) const
{
IexpValStr val = owner . interp - > getIexp ( cmp ) ;
2011-05-22 21:46:52 +03:00
val . setTo ( erm - > getObjFrom ( owner . identifier ) - > subID ) ;
}
/////VR
struct VRPerformer ;
struct VR_SPerformer : StandardBodyOptionItemVisitor < VRPerformer >
{
explicit VR_SPerformer ( VRPerformer & _owner ) ;
using StandardBodyOptionItemVisitor < VRPerformer > : : operator ( ) ;
2013-06-26 17:25:23 +03:00
void operator ( ) ( TStringConstant const & cmp ) const override ;
void operator ( ) ( TIexp const & cmp ) const override ;
2011-05-22 21:46:52 +03:00
} ;
struct VRPerformer : StandardReceiverVisitor < IexpValStr >
{
2011-05-28 01:34:58 +03:00
VRPerformer ( ERMInterpreter * _interpr , IexpValStr ident ) : StandardReceiverVisitor < IexpValStr > ( _interpr , ident )
2011-05-22 21:46:52 +03:00
{ }
2013-06-26 17:25:23 +03:00
void operator ( ) ( TVRLogic const & trig ) const override
2011-05-22 21:46:52 +03:00
{
int valr = interp - > getIexp ( trig . var ) . getInt ( ) ;
switch ( trig . opcode )
{
case ' & ' :
const_cast < VRPerformer * > ( this ) - > identifier . setTo ( identifier . getInt ( ) & valr ) ;
break ;
case ' | ' :
const_cast < VRPerformer * > ( this ) - > identifier . setTo ( identifier . getInt ( ) | valr ) ;
break ;
case ' X ' :
const_cast < VRPerformer * > ( this ) - > identifier . setTo ( identifier . getInt ( ) ^ valr ) ;
break ;
default :
throw EInterpreterError ( " Wrong opcode in VR logic expression! " ) ;
break ;
}
}
2013-06-26 17:25:23 +03:00
void operator ( ) ( TVRArithmetic const & trig ) const override
2011-05-22 21:46:52 +03:00
{
IexpValStr rhs = interp - > getIexp ( trig . rhs ) ;
switch ( trig . opcode )
{
case ' + ' :
const_cast < VRPerformer * > ( this ) - > identifier + = rhs ;
break ;
case ' - ' :
const_cast < VRPerformer * > ( this ) - > identifier - = rhs ;
break ;
case ' * ' :
const_cast < VRPerformer * > ( this ) - > identifier * = rhs ;
break ;
case ' : ' :
const_cast < VRPerformer * > ( this ) - > identifier / = rhs ;
break ;
case ' % ' :
const_cast < VRPerformer * > ( this ) - > identifier % = rhs ;
break ;
default :
throw EInterpreterError ( " Wrong opcode in VR arithmetic! " ) ;
break ;
}
}
2013-06-26 17:25:23 +03:00
void operator ( ) ( TNormalBodyOption const & trig ) const override
2011-05-22 21:46:52 +03:00
{
switch ( trig . optionCode )
{
case ' C ' : //setting/checking v vars
{
//TODO
}
break ;
case ' H ' : //checking if string is empty
{
//TODO
}
break ;
case ' M ' : //string operations
{
//TODO
}
break ;
case ' R ' : //random variables
{
//TODO
}
break ;
case ' S ' : //setting variable
{
2012-02-16 20:10:58 +03:00
performOptionTakingOneParamter < VR_SPerformer > ( trig . params ) ;
2011-05-22 21:46:52 +03:00
}
break ;
case ' T ' : //random variables
{
//TODO
}
break ;
case ' U ' : //search for a substring
{
//TODO
}
break ;
case ' V ' : //convert string to value
{
//TODO
}
break ;
default :
throw EScriptExecError ( " Wrong VR receiver option! " ) ;
break ;
}
}
} ;
2011-05-28 01:34:58 +03:00
VR_SPerformer : : VR_SPerformer ( VRPerformer & _owner ) : StandardBodyOptionItemVisitor < VRPerformer > ( _owner )
2011-05-22 21:46:52 +03:00
{ }
void VR_SPerformer : : operator ( ) ( ERM : : TIexp const & trig ) const
{
owner . identifier . setTo ( owner . interp - > getIexp ( trig ) ) ;
}
void VR_SPerformer : : operator ( ) ( TStringConstant const & cmp ) const
{
owner . identifier . setTo ( cmp . str ) ;
2011-05-16 15:11:00 +03:00
}
2011-05-03 17:45:57 +03:00
2011-05-22 21:46:52 +03:00
/////
2011-04-16 20:39:38 +03:00
struct ERMExpDispatch : boost : : static_visitor < >
{
2011-05-17 22:24:18 +03:00
struct HLP
{
int3 getPosFromIdentifier ( ERM : : Tidentifier tid , bool allowDummyFourth )
{
switch ( tid . size ( ) )
{
case 1 :
{
2011-06-18 21:24:56 +03:00
int num = erm - > getIexp ( tid [ 0 ] ) . getInt ( ) ;
return int3 ( erm - > ermGlobalEnv - > getStandardVar ( num ) ,
erm - > ermGlobalEnv - > getStandardVar ( num + 1 ) ,
erm - > ermGlobalEnv - > getStandardVar ( num + 2 ) ) ;
2011-05-17 22:24:18 +03:00
}
break ;
case 3 :
case 4 :
if ( tid . size ( ) = = 4 & & ! allowDummyFourth )
throw EScriptExecError ( " 4 items in identifier are not allowed for this receiver! " ) ;
2011-06-18 21:24:56 +03:00
return int3 ( erm - > getIexp ( tid [ 0 ] ) . getInt ( ) ,
erm - > getIexp ( tid [ 1 ] ) . getInt ( ) ,
erm - > getIexp ( tid [ 2 ] ) . getInt ( ) ) ;
2011-05-17 22:24:18 +03:00
break ;
default :
throw EScriptExecError ( " This receiver takes 1 or 3 items in identifier! " ) ;
break ;
}
}
template < typename Visitor >
void performBody ( const boost : : optional < ERM : : Tbody > & body , const Visitor & visitor )
{
if ( body . is_initialized ( ) )
{
ERM : : Tbody bo = body . get ( ) ;
for ( int g = 0 ; g < bo . size ( ) ; + + g )
{
boost : : apply_visitor ( visitor , bo [ g ] ) ;
}
}
}
} ;
2011-04-16 20:39:38 +03:00
void operator ( ) ( Ttrigger const & trig ) const
{
2011-04-22 23:33:34 +03:00
throw EInterpreterError ( " Triggers cannot be executed! " ) ;
2011-04-16 20:39:38 +03:00
}
void operator ( ) ( Tinstruction const & trig ) const
{
}
void operator ( ) ( Treceiver const & trig ) const
{
2012-02-16 20:10:58 +03:00
HLP helper ;
2011-06-21 03:00:49 +03:00
//check condition
if ( trig . condition . is_initialized ( ) )
2011-05-03 17:45:57 +03:00
{
2011-06-21 03:00:49 +03:00
if ( ! erm - > checkCondition ( trig . condition . get ( ) ) )
return ;
}
2011-05-03 17:45:57 +03:00
2011-06-21 03:00:49 +03:00
if ( trig . name = = " VR " )
{
2011-05-03 17:45:57 +03:00
//perform operations
if ( trig . identifier . is_initialized ( ) )
{
ERM : : Tidentifier ident = trig . identifier . get ( ) ;
if ( ident . size ( ) = = 1 )
{
2011-06-18 21:24:56 +03:00
IexpValStr ievs = erm - > getIexp ( ident [ 0 ] ) ;
2011-05-03 17:45:57 +03:00
2011-05-06 22:32:04 +03:00
//see body
2011-06-18 21:24:56 +03:00
helper . performBody ( trig . body , VRPerformer ( erm , ievs ) ) ;
2011-05-03 17:45:57 +03:00
}
else
throw EScriptExecError ( " VR receiver must be used with exactly one identifier item! " ) ;
}
else
throw EScriptExecError ( " VR receiver must be used with an identifier! " ) ;
}
2011-05-06 22:32:04 +03:00
else if ( trig . name = = " DO " )
{
//perform operations
if ( trig . identifier . is_initialized ( ) )
{
ERM : : Tidentifier tid = trig . identifier . get ( ) ;
if ( tid . size ( ) ! = 4 )
{
throw EScriptExecError ( " DO receiver takes exactly 4 arguments " ) ;
}
2011-06-18 21:24:56 +03:00
int funNum = erm - > getIexp ( tid [ 0 ] ) . getInt ( ) ,
startVal = erm - > getIexp ( tid [ 1 ] ) . getInt ( ) ,
stopVal = erm - > getIexp ( tid [ 2 ] ) . getInt ( ) ,
increment = erm - > getIexp ( tid [ 3 ] ) . getInt ( ) ;
2011-05-06 22:32:04 +03:00
for ( int it = startVal ; it < stopVal ; it + = increment )
{
2011-05-14 16:20:19 +03:00
std : : vector < int > params ( FunctionLocalVars : : NUM_PARAMETERS , 0 ) ;
params . back ( ) = it ;
//owner->getFuncVars(funNum)->getParam(16) = it;
2016-08-29 18:49:52 +02:00
2011-05-07 18:13:56 +03:00
std : : vector < int > v1 ;
2014-11-14 06:45:44 +02:00
v1 . push_back ( funNum ) ;
ERMInterpreter : : TIDPattern tip = { { v1 . size ( ) , v1 } } ;
2011-06-18 21:24:56 +03:00
erm - > executeTriggerType ( TriggerType ( " FU " ) , true , tip , params ) ;
it = erm - > getFuncVars ( funNum ) - > getParam ( 16 ) ;
2011-05-06 22:32:04 +03:00
}
}
}
2011-05-17 22:24:18 +03:00
else if ( trig . name = = " MA " )
{
if ( trig . identifier . is_initialized ( ) )
{
throw EScriptExecError ( " MA receiver doesn't take the identifier! " ) ;
}
2011-06-18 21:24:56 +03:00
helper . performBody ( trig . body , MAPerformer ( erm ) ) ;
2011-05-17 22:24:18 +03:00
}
2011-05-16 15:11:00 +03:00
else if ( trig . name = = " MO " )
{
int3 objPos ;
if ( trig . identifier . is_initialized ( ) )
{
ERM : : Tidentifier tid = trig . identifier . get ( ) ;
2011-06-18 21:24:56 +03:00
objPos = HLP ( ) . getPosFromIdentifier ( tid , true ) ;
2011-05-22 21:46:52 +03:00
2011-06-18 21:24:56 +03:00
helper . performBody ( trig . body , MOPerformer ( erm , objPos ) ) ;
2011-05-16 15:11:00 +03:00
}
else
throw EScriptExecError ( " MO receiver must have an identifier! " ) ;
}
2011-05-15 21:21:07 +03:00
else if ( trig . name = = " OB " )
{
int3 objPos ;
if ( trig . identifier . is_initialized ( ) )
{
ERM : : Tidentifier tid = trig . identifier . get ( ) ;
2011-06-18 21:24:56 +03:00
objPos = HLP ( ) . getPosFromIdentifier ( tid , false ) ;
2011-05-16 15:11:00 +03:00
2011-06-18 21:24:56 +03:00
helper . performBody ( trig . body , OBPerformer ( erm , objPos ) ) ;
2011-05-15 21:21:07 +03:00
}
else
throw EScriptExecError ( " OB receiver must have an identifier! " ) ;
}
2011-05-22 21:46:52 +03:00
else if ( trig . name = = " HE " )
{
if ( trig . identifier . is_initialized ( ) )
{
2013-11-07 15:48:41 +03:00
const CGHeroInstance * hero = nullptr ;
2011-05-22 21:46:52 +03:00
ERM : : Tidentifier tid = trig . identifier . get ( ) ;
switch ( tid . size ( ) )
{
case 1 :
{
int heroNum = erm - > getIexp ( tid [ 0 ] ) . getInt ( ) ;
if ( heroNum = = - 1 )
2014-11-14 06:45:44 +02:00
assert ( false ) ; //FIXME: use new hero selection mechanics
2011-05-22 21:46:52 +03:00
else
hero = icb - > getHeroWithSubid ( heroNum ) ;
}
break ;
case 3 :
{
int3 pos = helper . getPosFromIdentifier ( tid , false ) ;
hero = erm - > getObjFromAs < CGHeroInstance > ( pos ) ;
}
break ;
default :
throw EScriptExecError ( " HE receiver takes 1 or 3 items in identifier " ) ;
break ;
}
2011-06-18 21:24:56 +03:00
helper . performBody ( trig . body , HEPerformer ( erm , hero ) ) ;
2011-05-22 21:46:52 +03:00
}
else
throw EScriptExecError ( " HE receiver must have an identifier! " ) ;
}
2011-06-11 02:50:32 +03:00
else if ( trig . name = = " IF " )
{
2011-06-18 21:24:56 +03:00
helper . performBody ( trig . body , IFPerformer ( erm ) ) ;
2011-06-11 02:50:32 +03:00
}
2011-05-03 17:45:57 +03:00
else
{
2016-08-29 18:49:52 +02:00
logGlobal - > warn ( " %s receiver is not supported yet, doing nothing... " , trig . name ) ;
2011-05-16 15:11:00 +03:00
//not supported or invalid trigger
2011-05-03 17:45:57 +03:00
}
2011-04-16 20:39:38 +03:00
}
void operator ( ) ( TPostTrigger const & trig ) const
{
2011-04-22 23:33:34 +03:00
throw EInterpreterError ( " Post-triggers cannot be executed! " ) ;
2011-04-16 20:39:38 +03:00
}
} ;
struct CommandExec : boost : : static_visitor < >
{
void operator ( ) ( Tcommand const & cmd ) const
{
2011-06-18 21:24:56 +03:00
boost : : apply_visitor ( ERMExpDispatch ( ) , cmd . cmd ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " Line comment: %s " , cmd . comment ) ;
2011-04-16 20:39:38 +03:00
}
void operator ( ) ( std : : string const & comment ) const
{
//comment - do nothing
}
void operator ( ) ( spirit : : unused_type const & nothing ) const
{
//nothing - do nothing
}
} ;
struct LineExec : boost : : static_visitor < >
{
void operator ( ) ( TVExp const & cmd ) const
{
2011-06-04 21:16:32 +03:00
VNode line ( cmd ) ;
erm - > eval ( line ) ;
2011-04-16 20:39:38 +03:00
}
void operator ( ) ( TERMline const & cmd ) const
{
2011-06-04 21:16:32 +03:00
boost : : apply_visitor ( CommandExec ( ) , cmd ) ;
2011-04-16 20:39:38 +03:00
}
} ;
/////////
2011-04-10 19:39:34 +03:00
void ERMInterpreter : : executeLine ( const LinePointer & lp )
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " Executing line %d (internal %d) from %s " , getRealLine ( lp ) , lp . lineNum , lp . file - > filename ) ;
2011-06-24 00:42:30 +03:00
executeLine ( scripts [ lp ] ) ;
}
void ERMInterpreter : : executeLine ( const ERM : : TLine & line )
{
boost : : apply_visitor ( LineExec ( ) , line ) ;
2011-04-16 20:39:38 +03:00
}
2011-05-06 22:32:04 +03:00
IexpValStr ERMInterpreter : : getVar ( std : : string toFollow , boost : : optional < int > initVal ) const
2011-04-16 20:39:38 +03:00
{
2011-05-03 17:45:57 +03:00
IexpValStr ret ;
ret . type = IexpValStr : : WRONGVAL ;
2011-04-17 20:51:48 +03:00
2012-07-06 23:19:54 +03:00
int initV = 0 ;
2011-05-03 17:45:57 +03:00
bool hasInit = false ;
if ( initVal . is_initialized ( ) )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
initV = initVal . get ( ) ;
hasInit = true ;
}
2011-05-02 21:39:57 +03:00
2011-05-03 17:45:57 +03:00
int endNum = 0 ;
if ( toFollow [ 0 ] = = ' d ' )
{
endNum = 1 ;
//TODO: support
}
if ( toFollow . size ( ) = = 0 )
{
if ( hasInit )
2011-05-06 22:32:04 +03:00
ret = IexpValStr ( initV ) ;
2011-05-03 17:45:57 +03:00
else
throw EIexpProblem ( " No input to getVar! " ) ;
2011-04-17 20:51:48 +03:00
2011-05-03 17:45:57 +03:00
return ret ;
}
//now we have at least one element in toFollow
for ( int b = toFollow . size ( ) - 1 ; b > = endNum ; - - b )
{
2011-05-14 16:20:19 +03:00
bool retIt = b = = endNum /*+1*/ ; //if we should return the value are currently at
2011-05-03 17:45:57 +03:00
2011-05-14 16:20:19 +03:00
char cr = toFollow [ b ] ;
2011-05-03 17:45:57 +03:00
if ( cr = = ' c ' ) //write number of current day
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
//TODO
2011-04-17 20:51:48 +03:00
}
2011-05-03 17:45:57 +03:00
else if ( cr = = ' d ' ) //info for external env - add i/o set
2011-05-02 21:39:57 +03:00
{
2011-05-03 17:45:57 +03:00
throw EIexpProblem ( " d inside i-expression not allowed! " ) ;
2011-05-02 21:39:57 +03:00
}
2011-05-03 17:45:57 +03:00
else if ( cr = = ' e ' )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
if ( hasInit )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
if ( retIt )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
//these C-style cast is here just to shut up compiler errors
if ( initV > 0 & & initV < = FunctionLocalVars : : NUM_FLOATINGS )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
if ( curFunc )
2011-05-06 22:32:04 +03:00
ret = IexpValStr ( & curFunc - > getFloat ( initV ) ) ;
2011-05-03 17:45:57 +03:00
else
throw EIexpProblem ( " Function context not available! " ) ;
}
else if ( initV < 0 & & initV > = - TriggerLocalVars : : EVAR_NUM )
{
if ( curTrigger )
2011-05-06 22:32:04 +03:00
ret = IexpValStr ( & curTrigger - > ermLocalVars . getEvar ( initV ) ) ;
2011-04-17 20:51:48 +03:00
else
2011-05-03 17:45:57 +03:00
throw EIexpProblem ( " No trigger context available! " ) ;
2011-04-17 20:51:48 +03:00
}
else
2011-05-03 17:45:57 +03:00
throw EIexpProblem ( " index " + boost : : lexical_cast < std : : string > ( initV ) + " not allowed for e array " ) ;
2011-04-17 20:51:48 +03:00
}
else
throw EIexpProblem ( " e variables cannot appear in this context " ) ;
}
2011-05-03 17:45:57 +03:00
else
throw EIexpProblem ( " e variables cannot appear in this context " ) ;
}
else if ( cr > = ' f ' & & cr < = ' t ' )
{
if ( retIt )
2011-05-06 22:32:04 +03:00
ret = IexpValStr ( & ermGlobalEnv - > getQuickVar ( cr ) ) ;
2011-05-03 17:45:57 +03:00
else
{
if ( hasInit )
throw EIexpProblem ( " quick variables cannot be used in this context " ) ;
else
{
initV = ermGlobalEnv - > getQuickVar ( cr ) ;
hasInit = true ;
}
}
}
else if ( cr = = ' v ' ) //standard variables
{
if ( hasInit )
2011-04-17 20:51:48 +03:00
{
if ( retIt )
2011-05-06 22:32:04 +03:00
ret = IexpValStr ( & ermGlobalEnv - > getStandardVar ( initV ) ) ;
2011-04-17 20:51:48 +03:00
else
2011-05-03 17:45:57 +03:00
initV = ermGlobalEnv - > getStandardVar ( initV ) ;
2011-04-17 20:51:48 +03:00
}
2011-05-03 17:45:57 +03:00
else
throw EIexpProblem ( " standard variable cannot be used in this context! " ) ;
}
else if ( cr = = ' w ' ) //local hero variables
{
//TODO
}
else if ( cr = = ' x ' ) //function parameters
{
if ( hasInit )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
if ( curFunc )
2011-04-17 20:51:48 +03:00
{
2011-05-02 21:39:57 +03:00
if ( retIt )
2011-05-06 22:32:04 +03:00
ret = IexpValStr ( & curFunc - > getParam ( initV ) ) ;
2011-04-17 20:51:48 +03:00
else
2011-05-03 17:45:57 +03:00
initV = curFunc - > getParam ( initV ) ;
2011-04-17 20:51:48 +03:00
}
2011-05-03 17:45:57 +03:00
else throw EIexpProblem ( " Function parameters cannot be used outside a function! " ) ;
2011-04-17 20:51:48 +03:00
}
2011-05-03 17:45:57 +03:00
else
throw EIexpProblem ( " Specify which function parameter should be used " ) ;
}
else if ( cr = = ' y ' )
{
if ( hasInit )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
if ( initV > 0 & & initV < = FunctionLocalVars : : NUM_LOCALS )
2011-04-17 20:51:48 +03:00
{
2014-03-23 15:59:03 +03:00
int & valPtr = curFunc ? curFunc - > getLocal ( initV ) : const_cast < ERMInterpreter & > ( * this ) . getFuncVars ( 0 ) - > getLocal ( initV ) ; //retrieve local var if in function or use global set otherwise
2011-05-14 16:20:19 +03:00
if ( retIt )
ret = IexpValStr ( & valPtr ) ;
2011-05-03 17:45:57 +03:00
else
2011-05-14 16:20:19 +03:00
initV = curFunc - > getLocal ( initV ) ;
2011-04-17 20:51:48 +03:00
}
2011-05-03 17:45:57 +03:00
else if ( initV < 0 & & initV > = - TriggerLocalVars : : YVAR_NUM )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
if ( curTrigger )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
if ( retIt )
2011-05-06 22:32:04 +03:00
ret = IexpValStr ( & curTrigger - > ermLocalVars . getYvar ( initV ) ) ;
2011-04-17 20:51:48 +03:00
else
2011-05-03 17:45:57 +03:00
initV = curTrigger - > ermLocalVars . getYvar ( initV ) ;
2011-04-17 20:51:48 +03:00
}
else
2011-05-03 17:45:57 +03:00
throw EIexpProblem ( " Trigger local variables cannot be used outside triggers! " ) ;
2011-04-17 20:51:48 +03:00
}
else
2011-05-03 17:45:57 +03:00
throw EIexpProblem ( " Wrong argument for function local variable! " ) ;
2011-04-17 20:51:48 +03:00
}
2011-05-03 17:45:57 +03:00
else
throw EIexpProblem ( " y variable cannot be used in this context! " ) ;
}
else if ( cr = = ' z ' )
{
if ( hasInit )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
if ( retIt )
2011-04-17 20:51:48 +03:00
{
2011-05-03 17:45:57 +03:00
//these C-style casts are here just to shut up compiler errors
if ( initV > 0 )
2011-05-06 22:32:04 +03:00
ret = IexpValStr ( & ermGlobalEnv - > getZVar ( initV ) ) ;
2011-05-03 17:45:57 +03:00
else if ( initV < 0 )
{
if ( curFunc )
2011-05-06 22:32:04 +03:00
ret = IexpValStr ( & curFunc - > getString ( initV ) ) ;
2011-04-17 20:51:48 +03:00
else
2011-05-03 17:45:57 +03:00
throw EIexpProblem ( " Function local string variables cannot be used outside functions! " ) ;
2011-04-17 20:51:48 +03:00
}
else
2011-05-03 17:45:57 +03:00
throw EIexpProblem ( " Wrong parameter for string variable! " ) ;
2011-04-17 20:51:48 +03:00
}
else
2011-05-03 17:45:57 +03:00
throw EIexpProblem ( " String variables can only be returned! " ) ;
2011-04-17 20:51:48 +03:00
}
else
2011-05-03 17:45:57 +03:00
throw EIexpProblem ( " String variables cannot be used in this context! " ) ;
2011-04-17 20:51:48 +03:00
}
2011-05-03 17:45:57 +03:00
else
{
throw EIexpProblem ( std : : string ( " Symbol " ) + cr + " is not allowed in this context! " ) ;
}
2012-02-16 20:10:58 +03:00
2011-04-17 20:51:48 +03:00
}
2011-05-22 21:46:52 +03:00
ret . name = toFollow ;
if ( initVal . is_initialized ( ) )
{
ret . name + = boost : : lexical_cast < std : : string > ( initVal . get ( ) ) ;
}
2011-05-03 17:45:57 +03:00
return ret ;
}
2011-04-16 20:39:38 +03:00
2011-04-17 20:51:48 +03:00
namespace IexpDisemboweler
{
enum EDir { GET , SET } ;
}
2011-05-02 21:39:57 +03:00
struct LVL2IexpDisemboweler : boost : : static_visitor < IexpValStr >
2011-04-16 20:39:38 +03:00
{
2011-05-03 17:45:57 +03:00
/*const*/ ERMInterpreter * env ;
2011-05-28 01:34:58 +03:00
IexpDisemboweler : : EDir dir ;
2011-04-17 20:51:48 +03:00
2011-05-03 17:45:57 +03:00
LVL2IexpDisemboweler ( /*const*/ ERMInterpreter * _env , IexpDisemboweler : : EDir _dir )
2011-05-02 21:39:57 +03:00
: env ( _env ) , dir ( _dir ) //writes value to given var
2011-04-16 20:39:38 +03:00
{ }
2011-05-02 21:39:57 +03:00
IexpValStr processNotMacro ( const TVarExpNotMacro & val ) const
2011-04-16 20:39:38 +03:00
{
if ( val . questionMark . is_initialized ( ) )
2011-04-17 20:51:48 +03:00
throw EIexpProblem ( " Question marks ('?') are not allowed in getter i - expressions " ) ;
//const-cast just to do some code-reuse...
2011-05-02 21:39:57 +03:00
return env - > getVar ( val . varsym , val . val ) ;
2011-04-16 20:39:38 +03:00
}
2011-05-02 21:39:57 +03:00
IexpValStr operator ( ) ( TVarExpNotMacro const & val ) const
2011-04-16 20:39:38 +03:00
{
2011-05-02 21:39:57 +03:00
return processNotMacro ( val ) ;
2011-04-16 20:39:38 +03:00
}
2011-05-02 21:39:57 +03:00
IexpValStr operator ( ) ( TMacroUsage const & val ) const
2011-04-16 20:39:38 +03:00
{
2011-05-06 22:32:04 +03:00
return env - > getIexp ( val ) ;
2011-04-16 20:39:38 +03:00
}
} ;
2011-05-02 21:39:57 +03:00
struct LVL1IexpDisemboweler : boost : : static_visitor < IexpValStr >
2011-04-16 20:39:38 +03:00
{
2011-05-03 17:45:57 +03:00
/*const*/ ERMInterpreter * env ;
2011-05-28 01:34:58 +03:00
IexpDisemboweler : : EDir dir ;
2011-04-17 20:51:48 +03:00
2011-05-03 17:45:57 +03:00
LVL1IexpDisemboweler ( /*const*/ ERMInterpreter * _env , IexpDisemboweler : : EDir _dir )
2011-05-02 21:39:57 +03:00
: env ( _env ) , dir ( _dir ) //writes value to given var
2011-04-16 20:39:38 +03:00
{ }
2011-05-02 21:39:57 +03:00
IexpValStr operator ( ) ( int const & constant ) const
2011-04-16 20:39:38 +03:00
{
2011-04-17 20:51:48 +03:00
if ( dir = = IexpDisemboweler : : GET )
{
2011-05-11 22:53:55 +03:00
return IexpValStr ( constant ) ;
2011-04-17 20:51:48 +03:00
}
else
{
throw EIexpProblem ( " Cannot set a constant! " ) ;
}
2011-04-16 20:39:38 +03:00
}
2011-05-02 21:39:57 +03:00
IexpValStr operator ( ) ( TVarExp const & var ) const
2011-04-16 20:39:38 +03:00
{
2011-05-02 21:39:57 +03:00
return boost : : apply_visitor ( LVL2IexpDisemboweler ( env , dir ) , var ) ;
2011-04-16 20:39:38 +03:00
}
} ;
2011-04-10 19:39:34 +03:00
2011-05-03 17:45:57 +03:00
IexpValStr ERMInterpreter : : getIexp ( const ERM : : TIexp & iexp ) const
2011-04-16 20:39:38 +03:00
{
2011-05-03 17:45:57 +03:00
return boost : : apply_visitor ( LVL1IexpDisemboweler ( const_cast < ERMInterpreter * > ( this ) , IexpDisemboweler : : GET ) , iexp ) ;
2011-04-10 19:39:34 +03:00
}
2011-05-06 22:32:04 +03:00
IexpValStr ERMInterpreter : : getIexp ( const ERM : : TMacroUsage & macro ) const
{
std : : map < std : : string , ERM : : TVarExpNotMacro > : : const_iterator it =
ermGlobalEnv - > macroBindings . find ( macro . macro ) ;
if ( it = = ermGlobalEnv - > macroBindings . end ( ) )
throw EUsageOfUndefinedMacro ( macro . macro ) ;
return getVar ( it - > second . varsym , it - > second . val ) ;
}
IexpValStr ERMInterpreter : : getIexp ( const ERM : : TIdentifierInternal & tid ) const
{
if ( tid . which ( ) = = 0 )
{
2011-05-11 22:53:55 +03:00
return getIexp ( boost : : get < ERM : : TIexp > ( tid ) ) ;
2011-05-06 22:32:04 +03:00
}
else
throw EScriptExecError ( " Identifier must be a valid i-expression to perform this operation! " ) ;
}
2011-05-16 15:11:00 +03:00
IexpValStr ERMInterpreter : : getIexp ( const ERM : : TVarpExp & tid ) const
{
return boost : : apply_visitor ( LVL2IexpDisemboweler ( const_cast < ERMInterpreter * > ( this ) , IexpDisemboweler : : GET ) , tid . var ) ;
}
2011-05-22 21:46:52 +03:00
struct LVL3BodyOptionItemVisitor : StandardBodyOptionItemVisitor < IexpValStr >
{
2011-05-28 01:34:58 +03:00
explicit LVL3BodyOptionItemVisitor ( IexpValStr & _owner ) : StandardBodyOptionItemVisitor < IexpValStr > ( _owner )
2011-05-22 21:46:52 +03:00
{ }
using StandardBodyOptionItemVisitor < IexpValStr > : : operator ( ) ;
2013-06-26 17:25:23 +03:00
void operator ( ) ( TIexp const & cmp ) const override
2011-05-22 21:46:52 +03:00
{
owner = erm - > getIexp ( cmp ) ;
}
2013-06-26 17:25:23 +03:00
void operator ( ) ( TVarpExp const & cmp ) const override
2011-05-22 21:46:52 +03:00
{
owner = erm - > getIexp ( cmp ) ;
}
} ;
IexpValStr ERMInterpreter : : getIexp ( const ERM : : TBodyOptionItem & opit ) const
{
IexpValStr ret ;
boost : : apply_visitor ( LVL3BodyOptionItemVisitor ( ret ) , opit ) ;
return ret ;
}
2017-07-15 13:08:20 +02:00
void ERMInterpreter : : executeTriggerType ( VERMInterpreter : : TriggerType tt , bool pre , const TIDPattern & identifier , const std : : vector < int > & funParams )
2011-04-21 23:06:42 +03:00
{
2011-05-12 23:49:37 +03:00
struct HLP
{
static int calcFunNum ( VERMInterpreter : : TriggerType tt , const TIDPattern & identifier )
{
if ( tt . type ! = VERMInterpreter : : TriggerType : : FU )
return - 1 ;
return identifier . begin ( ) - > second [ 0 ] ;
}
} ;
2011-04-21 23:06:42 +03:00
TtriggerListType & triggerList = pre ? triggers : postTriggers ;
TriggerIdentifierMatch tim ;
2011-05-22 21:46:52 +03:00
tim . allowNoIdetifier = true ;
2011-04-21 23:06:42 +03:00
tim . ermEnv = this ;
tim . matchToIt = identifier ;
2011-04-22 23:33:34 +03:00
std : : vector < Trigger > & triggersToTry = triggerList [ tt ] ;
2011-04-21 23:06:42 +03:00
for ( int g = 0 ; g < triggersToTry . size ( ) ; + + g )
{
if ( tim . tryMatch ( & triggersToTry [ g ] ) )
{
2011-05-03 17:45:57 +03:00
curTrigger = & triggersToTry [ g ] ;
2011-05-14 16:20:19 +03:00
executeTrigger ( triggersToTry [ g ] , HLP : : calcFunNum ( tt , identifier ) , funParams ) ;
2011-04-21 23:06:42 +03:00
}
}
}
2011-05-10 01:20:47 +03:00
void ERMInterpreter : : executeTriggerType ( const char * trigger , int id )
{
TIDPattern tip ;
tip [ 0 ] = std : : vector < int > ( 1 , id ) ;
executeTriggerType ( VERMInterpreter : : TriggerType ( trigger ) , true , tip ) ;
}
void ERMInterpreter : : executeTriggerType ( const char * trigger )
{
executeTriggerType ( VERMInterpreter : : TriggerType ( trigger ) , true , TIDPattern ( ) ) ;
}
2011-05-22 21:46:52 +03:00
ERM : : TTriggerBase & ERMInterpreter : : retrieveTrigger ( ERM : : TLine & line )
2011-04-21 23:06:42 +03:00
{
if ( line . which ( ) = = 1 )
{
2011-05-22 21:46:52 +03:00
ERM : : TERMline & tl = boost : : get < ERM : : TERMline > ( line ) ;
2011-04-21 23:06:42 +03:00
if ( tl . which ( ) = = 0 )
{
2011-05-22 21:46:52 +03:00
ERM : : Tcommand & tcm = boost : : get < ERM : : Tcommand > ( tl ) ;
2011-04-21 23:06:42 +03:00
if ( tcm . cmd . which ( ) = = 0 )
{
return boost : : get < ERM : : Ttrigger > ( tcm . cmd ) ;
}
2011-05-17 22:24:18 +03:00
else if ( tcm . cmd . which ( ) = = 3 )
{
return boost : : get < ERM : : TPostTrigger > ( tcm . cmd ) ;
}
2011-05-11 22:53:55 +03:00
throw ELineProblem ( " Given line is not a trigger! " ) ;
2011-04-21 23:06:42 +03:00
}
2011-05-11 22:53:55 +03:00
throw ELineProblem ( " Given line is not a command! " ) ;
2011-04-21 23:06:42 +03:00
}
throw ELineProblem ( " Given line is not an ERM trigger! " ) ;
}
2011-05-02 21:39:57 +03:00
template < typename T >
bool compareExp ( const T & lhs , const T & rhs , std : : string op )
{
if ( op = = " < " )
{
return lhs < rhs ;
}
else if ( op = = " > " )
{
return lhs > rhs ;
}
else if ( op = = " >= " | | op = = " => " )
{
return lhs > = rhs ;
}
else if ( op = = " <= " | | op = = " =< " )
{
return lhs < = rhs ;
}
else if ( op = = " == " )
{
return lhs = = rhs ;
}
else if ( op = = " <> " | | op = = " >< " )
{
return lhs ! = rhs ;
}
else
throw EScriptExecError ( std : : string ( " Wrong comparison sign: " ) + op ) ;
}
struct ConditionDisemboweler : boost : : static_visitor < bool >
{
ConditionDisemboweler ( ERMInterpreter * _ei ) : ei ( _ei )
{ }
bool operator ( ) ( TComparison const & cmp ) const
{
IexpValStr lhs = ei - > getIexp ( cmp . lhs ) ,
rhs = ei - > getIexp ( cmp . rhs ) ;
switch ( lhs . type )
{
case IexpValStr : : FLOATVAR :
switch ( rhs . type )
{
case IexpValStr : : FLOATVAR :
2011-05-06 22:32:04 +03:00
return compareExp ( lhs . getFloat ( ) , rhs . getFloat ( ) , cmp . compSign ) ;
2011-05-02 21:39:57 +03:00
break ;
default :
throw EScriptExecError ( " Incompatible types for comparison " ) ;
}
break ;
case IexpValStr : : INT :
case IexpValStr : : INTVAR :
switch ( rhs . type )
{
case IexpValStr : : INT :
case IexpValStr : : INTVAR :
2011-05-06 22:32:04 +03:00
return compareExp ( lhs . getInt ( ) , rhs . getInt ( ) , cmp . compSign ) ;
break ;
2011-05-02 21:39:57 +03:00
default :
throw EScriptExecError ( " Incompatible types for comparison " ) ;
}
break ;
case IexpValStr : : STRINGVAR :
switch ( rhs . type )
{
case IexpValStr : : STRINGVAR :
2011-05-06 22:32:04 +03:00
return compareExp ( lhs . getString ( ) , rhs . getString ( ) , cmp . compSign ) ;
2011-05-02 21:39:57 +03:00
break ;
default :
throw EScriptExecError ( " Incompatible types for comparison " ) ;
}
break ;
default :
throw EScriptExecError ( " Wrong type of left iexp! " ) ;
}
2012-02-16 20:10:58 +03:00
return false ; //we should never reach this place
2011-05-02 21:39:57 +03:00
}
bool operator ( ) ( int const & flag ) const
{
return ei - > ermGlobalEnv - > getFlag ( flag ) ;
}
private :
ERMInterpreter * ei ;
} ;
bool ERMInterpreter : : checkCondition ( ERM : : Tcondition cond )
{
bool ret = boost : : apply_visitor ( ConditionDisemboweler ( this ) , cond . cond ) ;
if ( cond . rhs . is_initialized ( ) )
{ //taking care of rhs expression
bool rhs = checkCondition ( cond . rhs . get ( ) . get ( ) ) ;
switch ( cond . ctype )
{
case ' & ' :
ret & = rhs ;
break ;
case ' | ' :
ret | = rhs ;
break ;
case ' X ' :
ret ^ = rhs ;
break ;
default :
throw EInterpreterProblem ( std : : string ( " Strange - wrong condition connection ( " ) + cond . ctype + " ) ! " ) ;
break ;
}
}
return ret ;
}
2011-05-06 22:32:04 +03:00
FunctionLocalVars * ERMInterpreter : : getFuncVars ( int funNum )
{
2011-05-14 16:20:19 +03:00
if ( funNum > = ARRAY_COUNT ( funcVars ) | | funNum < 0 )
throw EScriptExecError ( " Attempt of accessing variables of function with index out of boundaries! " ) ;
return funcVars + funNum ;
2011-05-06 22:32:04 +03:00
}
2011-05-10 01:20:47 +03:00
void ERMInterpreter : : executeInstructions ( )
{
//TODO implement me
}
2011-06-27 19:03:03 +03:00
int ERMInterpreter : : getRealLine ( const LinePointer & lp )
2011-05-14 16:20:19 +03:00
{
for ( std : : map < VERMInterpreter : : LinePointer , ERM : : TLine > : : const_iterator i = scripts . begin ( ) ; i ! = scripts . end ( ) ; i + + )
2011-06-27 19:03:03 +03:00
if ( i - > first . lineNum = = lp . lineNum & & i - > first . file - > filename = = lp . file - > filename )
2011-05-14 16:20:19 +03:00
return i - > first . realLineNum ;
return - 1 ;
}
2011-05-15 21:21:07 +03:00
void ERMInterpreter : : setCurrentlyVisitedObj ( int3 pos )
{
ermGlobalEnv - > getStandardVar ( 998 ) = pos . x ;
ermGlobalEnv - > getStandardVar ( 999 ) = pos . y ;
ermGlobalEnv - > getStandardVar ( 1000 ) = pos . z ;
}
2011-04-10 19:39:34 +03:00
const std : : string ERMInterpreter : : triggerSymbol = " trigger " ;
const std : : string ERMInterpreter : : postTriggerSymbol = " postTrigger " ;
2011-04-16 20:39:38 +03:00
const std : : string ERMInterpreter : : defunSymbol = " defun " ;
2011-04-10 19:39:34 +03:00
2011-04-16 20:39:38 +03:00
struct TriggerIdMatchHelper : boost : : static_visitor < >
{
int & ret ;
2011-04-17 20:51:48 +03:00
ERMInterpreter * interpreter ;
Trigger * trig ;
TriggerIdMatchHelper ( int & b , ERMInterpreter * ermint , Trigger * _trig )
: ret ( b ) , interpreter ( ermint ) , trig ( _trig )
2011-04-16 20:39:38 +03:00
{ }
void operator ( ) ( TIexp const & iexp ) const
{
2011-05-03 17:45:57 +03:00
IexpValStr val = interpreter - > getIexp ( iexp ) ;
2011-05-02 21:39:57 +03:00
switch ( val . type )
{
case IexpValStr : : INT :
case IexpValStr : : INTVAR :
2011-05-06 22:32:04 +03:00
ret = val . getInt ( ) ;
break ;
2011-05-02 21:39:57 +03:00
default :
throw EScriptExecError ( " Incompatible i-exp type! " ) ;
2011-05-06 22:32:04 +03:00
break ;
2011-05-02 21:39:57 +03:00
}
2011-04-16 20:39:38 +03:00
}
void operator ( ) ( TArithmeticOp const & arop ) const
{
//error?!?
}
} ;
2011-04-21 23:06:42 +03:00
bool TriggerIdentifierMatch : : tryMatch ( Trigger * interptrig ) const
2011-04-16 20:39:38 +03:00
{
2011-05-02 21:39:57 +03:00
bool ret = true ;
2011-05-17 22:24:18 +03:00
const ERM : : TTriggerBase & trig = ERMInterpreter : : retrieveTrigger ( ermEnv - > retrieveLine ( interptrig - > line ) ) ;
2011-04-16 20:39:38 +03:00
if ( trig . identifier . is_initialized ( ) )
{
2011-04-21 23:06:42 +03:00
2011-04-16 20:39:38 +03:00
ERM : : Tidentifier tid = trig . identifier . get ( ) ;
std : : map < int , std : : vector < int > > : : const_iterator it = matchToIt . find ( tid . size ( ) ) ;
if ( it = = matchToIt . end ( ) )
2011-05-02 21:39:57 +03:00
ret = false ;
2011-04-16 20:39:38 +03:00
else
{
const std : : vector < int > & pattern = it - > second ;
for ( int g = 0 ; g < pattern . size ( ) ; + + g )
{
int val = - 1 ;
2011-04-17 20:51:48 +03:00
boost : : apply_visitor ( TriggerIdMatchHelper ( val , ermEnv , interptrig ) , tid [ g ] ) ;
2011-04-21 23:06:42 +03:00
if ( pattern [ g ] ! = val )
{
2011-05-02 21:39:57 +03:00
ret = false ;
2011-04-21 23:06:42 +03:00
}
2011-04-16 20:39:38 +03:00
}
}
}
else
{
2011-05-02 21:39:57 +03:00
ret = allowNoIdetifier ;
}
//check condition
if ( ret )
{
if ( trig . condition . is_initialized ( ) )
{
return ermEnv - > checkCondition ( trig . condition . get ( ) ) ;
}
else //no condition
2011-04-16 20:39:38 +03:00
return true ;
}
2011-05-02 21:39:57 +03:00
else
return false ;
2011-04-16 20:39:38 +03:00
}
2011-04-22 23:33:34 +03:00
VERMInterpreter : : ERMEnvironment : : ERMEnvironment ( )
{
for ( int g = 0 ; g < NUM_QUICKS ; + + g )
quickVars [ g ] = 0 ;
for ( int g = 0 ; g < NUM_STANDARDS ; + + g )
standardVars [ g ] = 0 ;
//string should be automatically initialized to ""
for ( int g = 0 ; g < NUM_FLAGS ; + + g )
flags [ g ] = false ;
}
2011-05-02 21:39:57 +03:00
int & VERMInterpreter : : ERMEnvironment : : getQuickVar ( const char letter )
{
assert ( letter > = ' f ' & & letter < = ' t ' ) ; //it should be check by another function, just making sure here
return quickVars [ letter - ' f ' ] ;
}
int & VERMInterpreter : : ERMEnvironment : : getStandardVar ( int num )
{
if ( num < 1 | | num > NUM_STANDARDS )
throw EScriptExecError ( " Number of standard variable out of bounds " ) ;
return standardVars [ num - 1 ] ;
}
std : : string & VERMInterpreter : : ERMEnvironment : : getZVar ( int num )
{
if ( num < 1 | | num > NUM_STRINGS )
throw EScriptExecError ( " Number of string variable out of bounds " ) ;
return strings [ num - 1 ] ;
}
bool & VERMInterpreter : : ERMEnvironment : : getFlag ( int num )
{
if ( num < 1 | | num > NUM_FLAGS )
throw EScriptExecError ( " Number of flag out of bounds " ) ;
return flags [ num - 1 ] ;
}
2011-04-22 23:33:34 +03:00
VERMInterpreter : : TriggerLocalVars : : TriggerLocalVars ( )
{
for ( int g = 0 ; g < EVAR_NUM ; + + g )
evar [ g ] = 0.0 ;
for ( int g = 0 ; g < YVAR_NUM ; + + g )
yvar [ g ] = 0 ;
}
2011-05-02 21:39:57 +03:00
double & VERMInterpreter : : TriggerLocalVars : : getEvar ( int num )
{
num = - num ;
if ( num < 1 | | num > EVAR_NUM )
throw EScriptExecError ( " Number of trigger local floating point variable out of bounds " ) ;
return evar [ num - 1 ] ;
}
int & VERMInterpreter : : TriggerLocalVars : : getYvar ( int num )
{
2011-05-11 22:53:55 +03:00
num = - num ; //we handle negative indices
2011-05-02 21:39:57 +03:00
if ( num < 1 | | num > YVAR_NUM )
throw EScriptExecError ( " Number of trigger local variable out of bounds " ) ;
return yvar [ num - 1 ] ;
}
2011-06-11 21:10:15 +03:00
bool VERMInterpreter : : Environment : : isBound ( const std : : string & name , EIsBoundMode mode ) const
2011-04-22 23:33:34 +03:00
{
2011-06-04 21:16:32 +03:00
std : : map < std : : string , VOption > : : const_iterator it = symbols . find ( name ) ;
2011-06-11 21:10:15 +03:00
if ( mode = = LOCAL_ONLY )
2011-04-22 23:33:34 +03:00
{
2011-06-11 21:10:15 +03:00
return it ! = symbols . end ( ) ;
}
if ( mode = = GLOBAL_ONLY & & parent )
{
return parent - > isBound ( name , mode ) ;
2011-04-22 23:33:34 +03:00
}
//we have it; if globalOnly is true, lexical parent is false here so we are global env
if ( it ! = symbols . end ( ) )
return true ;
//here, we don;t have it; but parent can have
if ( parent )
2011-06-11 21:10:15 +03:00
return parent - > isBound ( name , mode ) ;
2011-04-22 23:33:34 +03:00
return false ;
}
2011-06-04 21:16:32 +03:00
VOption & VERMInterpreter : : Environment : : retrieveValue ( const std : : string & name )
2011-04-22 23:33:34 +03:00
{
2011-06-04 21:16:32 +03:00
std : : map < std : : string , VOption > : : iterator it = symbols . find ( name ) ;
2011-04-22 23:33:34 +03:00
if ( it = = symbols . end ( ) )
{
if ( parent )
{
return parent - > retrieveValue ( name ) ;
}
throw ESymbolNotFound ( name ) ;
}
return it - > second ;
}
bool VERMInterpreter : : Environment : : unbind ( const std : : string & name , EUnbindMode mode )
{
2011-06-11 21:10:15 +03:00
if ( isBound ( name , ANYWHERE ) )
2011-04-22 23:33:34 +03:00
{
if ( symbols . find ( name ) ! = symbols . end ( ) ) //result of isBound could be from higher lexical env
symbols . erase ( symbols . find ( name ) ) ;
if ( mode = = FULLY_RECURSIVE & & parent )
parent - > unbind ( name , mode ) ;
return true ;
}
if ( parent & & ( mode = = RECURSIVE_UNTIL_HIT | | mode = = FULLY_RECURSIVE ) )
return parent - > unbind ( name , mode ) ;
//neither bound nor have lexical parent
return false ;
}
2011-05-02 21:39:57 +03:00
2011-06-04 21:16:32 +03:00
void VERMInterpreter : : Environment : : localBind ( std : : string name , const VOption & sym )
{
symbols [ name ] = sym ;
}
2011-06-11 21:10:15 +03:00
void VERMInterpreter : : Environment : : setPatent ( Environment * _parent )
{
parent = _parent ;
}
Environment * VERMInterpreter : : Environment : : getPatent ( ) const
{
return parent ;
}
void VERMInterpreter : : Environment : : bindAtFirstHit ( std : : string name , const VOption & sym )
{
if ( isBound ( name , Environment : : LOCAL_ONLY ) | | ! parent )
localBind ( name , sym ) ;
else
parent - > bindAtFirstHit ( name , sym ) ;
}
2011-05-02 21:39:57 +03:00
int & VERMInterpreter : : FunctionLocalVars : : getParam ( int num )
{
if ( num < 1 | | num > NUM_PARAMETERS )
throw EScriptExecError ( " Number of parameter out of bounds " ) ;
return params [ num - 1 ] ;
}
int & VERMInterpreter : : FunctionLocalVars : : getLocal ( int num )
{
if ( num < 1 | | num > NUM_LOCALS )
throw EScriptExecError ( " Number of local variable out of bounds " ) ;
return locals [ num - 1 ] ;
}
std : : string & VERMInterpreter : : FunctionLocalVars : : getString ( int num )
{
num = - num ; //we deal with negative indices
if ( num < 1 | | num > NUM_PARAMETERS )
throw EScriptExecError ( " Number of function local string variable out of bounds " ) ;
return strings [ num - 1 ] ;
}
double & VERMInterpreter : : FunctionLocalVars : : getFloat ( int num )
{
if ( num < 1 | | num > NUM_FLOATINGS )
throw EScriptExecError ( " Number of float var out of bounds " ) ;
return floats [ num - 1 ] ;
}
2011-05-06 22:32:04 +03:00
2011-05-12 23:49:37 +03:00
void VERMInterpreter : : FunctionLocalVars : : reset ( )
{
for ( int g = 0 ; g < ARRAY_COUNT ( params ) ; + + g )
params [ g ] = 0 ;
for ( int g = 0 ; g < ARRAY_COUNT ( locals ) ; + + g )
locals [ g ] = 0 ;
for ( int g = 0 ; g < ARRAY_COUNT ( strings ) ; + + g )
strings [ g ] = " " ;
for ( int g = 0 ; g < ARRAY_COUNT ( floats ) ; + + g )
floats [ g ] = 0.0 ;
}
2011-05-06 22:32:04 +03:00
void IexpValStr : : setTo ( const IexpValStr & second )
{
2016-08-29 18:49:52 +02:00
logGlobal - > trace ( " setting %s to %s " , getName ( ) , second . getName ( ) ) ;
2011-05-06 22:32:04 +03:00
switch ( type )
{
case IexpValStr : : FLOATVAR :
* val . flvar = second . getFloat ( ) ;
break ;
case IexpValStr : : INT :
throw EScriptExecError ( " VR S: value not assignable! " ) ;
break ;
case IexpValStr : : INTVAR :
* val . integervar = second . getInt ( ) ;
break ;
case IexpValStr : : STRINGVAR :
* val . stringvar = second . getString ( ) ;
break ;
default :
throw EScriptExecError ( " Wrong type of identifier iexp! " ) ;
}
}
void IexpValStr : : setTo ( int val )
{
2016-08-29 18:49:52 +02:00
logGlobal - > trace ( " setting %s to %d " , getName ( ) , val ) ;
2011-05-06 22:32:04 +03:00
switch ( type )
{
case INTVAR :
* this - > val . integervar = val ;
break ;
default :
throw EIexpProblem ( " Incompatible type! " ) ;
break ;
}
}
2011-12-14 00:23:17 +03:00
void IexpValStr : : setTo ( double val )
2011-05-06 22:32:04 +03:00
{
2016-08-29 18:49:52 +02:00
logGlobal - > trace ( " setting %s to %f " , getName ( ) , val ) ;
2011-05-06 22:32:04 +03:00
switch ( type )
{
case FLOATVAR :
* this - > val . flvar = val ;
break ;
default :
throw EIexpProblem ( " Incompatible type! " ) ;
break ;
}
}
void IexpValStr : : setTo ( const std : : string & val )
{
2016-08-29 18:49:52 +02:00
logGlobal - > trace ( " setting %s to %s " , getName ( ) , val ) ;
2011-05-06 22:32:04 +03:00
switch ( type )
{
case STRINGVAR :
* this - > val . stringvar = val ;
break ;
default :
throw EIexpProblem ( " Incompatible type! " ) ;
break ;
}
}
int IexpValStr : : getInt ( ) const
{
switch ( type )
{
case IexpValStr : : INT :
return val . val ;
break ;
case IexpValStr : : INTVAR :
return * val . integervar ;
break ;
default :
throw EIexpProblem ( " Cannot get iexp as int! " ) ;
break ;
}
}
2011-12-14 00:23:17 +03:00
double IexpValStr : : getFloat ( ) const
2011-05-06 22:32:04 +03:00
{
switch ( type )
{
case IexpValStr : : FLOATVAR :
return * val . flvar ;
break ;
default :
throw EIexpProblem ( " Cannot get iexp as float! " ) ;
break ;
}
}
std : : string IexpValStr : : getString ( ) const
{
switch ( type )
{
case IexpValStr : : STRINGVAR :
return * val . stringvar ;
break ;
default :
throw EScriptExecError ( " Cannot get iexp as string! " ) ;
break ;
}
}
2011-05-22 21:46:52 +03:00
std : : string IexpValStr : : getName ( ) const
{
if ( name . size ( ) )
{
return name ;
}
else if ( type = = IexpValStr : : INT )
{
return " Literal " + boost : : lexical_cast < std : : string > ( getInt ( ) ) ;
}
2011-05-25 02:17:57 +03:00
else
return " Unknown variable " ;
2011-05-22 21:46:52 +03:00
}
void ERMInterpreter : : init ( )
{
ermGlobalEnv = new ERMEnvironment ( ) ;
globalEnv = new Environment ( ) ;
//TODO: reset?
for ( int g = 0 ; g < ARRAY_COUNT ( funcVars ) ; + + g )
funcVars [ g ] . reset ( ) ;
scanForScripts ( ) ;
scanScripts ( ) ;
executeInstructions ( ) ;
executeTriggerType ( " PI " ) ;
}
void ERMInterpreter : : heroVisit ( const CGHeroInstance * visitor , const CGObjectInstance * visitedObj , bool start )
{
if ( ! visitedObj )
return ;
setCurrentlyVisitedObj ( visitedObj - > pos ) ;
TIDPattern tip ;
2012-02-16 20:10:58 +03:00
tip [ 1 ] = { visitedObj - > ID } ;
tip [ 2 ] = { visitedObj - > ID , visitedObj - > subID } ;
tip [ 3 ] = { visitedObj - > pos . x , visitedObj - > pos . y , visitedObj - > pos . z } ;
2011-05-22 21:46:52 +03:00
executeTriggerType ( VERMInterpreter : : TriggerType ( " OB " ) , start , tip ) ;
}
void ERMInterpreter : : battleStart ( const CCreatureSet * army1 , const CCreatureSet * army2 , int3 tile , const CGHeroInstance * hero1 , const CGHeroInstance * hero2 , bool side )
{
executeTriggerType ( " BA " , 0 ) ;
executeTriggerType ( " BR " , - 1 ) ;
executeTriggerType ( " BF " , 0 ) ;
//TODO tactics or not
}
const CGObjectInstance * ERMInterpreter : : getObjFrom ( int3 pos )
{
std : : vector < const CGObjectInstance * > objs = icb - > getVisitableObjs ( pos ) ;
if ( ! objs . size ( ) )
throw EScriptExecError ( " Attempt to obtain access to nonexistent object! " ) ;
return objs . back ( ) ;
}
2011-05-29 21:16:49 +03:00
2011-06-04 21:16:32 +03:00
struct VOptionPrinter : boost : : static_visitor < >
{
void operator ( ) ( VNIL const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > error ( " VNIL " ) ;
2011-06-04 21:16:32 +03:00
}
void operator ( ) ( VNode const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > error ( " --vnode (will be supported in future versions)-- " ) ;
2011-06-04 21:16:32 +03:00
}
void operator ( ) ( VSymbol const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > error ( opt . text ) ;
2011-06-04 21:16:32 +03:00
}
void operator ( ) ( TLiteral const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > error ( boost : : to_string ( opt ) ) ;
2011-06-04 21:16:32 +03:00
}
void operator ( ) ( ERM : : Tcommand const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > error ( " --erm command (will be supported in future versions)-- " ) ;
2011-06-04 21:16:32 +03:00
}
2011-06-11 21:10:15 +03:00
void operator ( ) ( VFunc const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > error ( " function " ) ;
2011-06-11 21:10:15 +03:00
}
2011-06-04 21:16:32 +03:00
} ;
2011-06-18 21:24:56 +03:00
struct _SbackquoteEval : boost : : static_visitor < VOption >
{
VOption operator ( ) ( VNIL const & opt ) const
{
return opt ;
}
VOption operator ( ) ( VNode const & opt ) const
{
VNode ret = opt ;
if ( opt . children . size ( ) = = 2 )
{
VOption fo = opt . children [ 0 ] ;
if ( isA < VSymbol > ( fo ) )
{
if ( getAs < VSymbol > ( fo ) . text = = " comma " )
{
return erm - > eval ( opt . children [ 1 ] ) ;
}
}
}
for ( int g = 0 ; g < opt . children . size ( ) ; + + g )
{
ret . children [ g ] = boost : : apply_visitor ( _SbackquoteEval ( ) , ret . children [ g ] ) ;
}
return ret ;
}
VOption operator ( ) ( VSymbol const & opt ) const
{
return opt ;
}
VOption operator ( ) ( TLiteral const & opt ) const
{
return opt ;
}
VOption operator ( ) ( ERM : : Tcommand const & opt ) const
{
boost : : apply_visitor ( ERMExpDispatch ( ) , opt . cmd ) ;
return opt ;
}
VOption operator ( ) ( VFunc const & opt ) const
{
return opt ;
}
} ;
2011-06-04 21:16:32 +03:00
struct VNodeEvaluator : boost : : static_visitor < VOption >
{
Environment & env ;
VNode & exp ;
VNodeEvaluator ( Environment & _env , VNode & _exp ) : env ( _env ) , exp ( _exp )
{ }
VOption operator ( ) ( VNIL const & opt ) const
{
throw EVermScriptExecError ( " Nil does not evaluate to a function " ) ;
}
VOption operator ( ) ( VNode const & opt ) const
{
//otherwise...
2011-06-11 21:10:15 +03:00
VNode tmpn ( exp ) ;
tmpn . children . car ( ) = erm - > eval ( opt ) ;
VFunc fun = getAs < VFunc > ( tmpn . children . car ( ) . getAsItem ( ) ) ;
return fun ( tmpn . children . cdr ( ) ) ;
2011-06-04 21:16:32 +03:00
}
VOption operator ( ) ( VSymbol const & opt ) const
{
2014-11-14 06:45:44 +02:00
std : : map < std : : string , VFunc : : Eopt > symToFunc =
{
{ " < " , VFunc : : LT } , { " <= " , VFunc : : LE } , { " > " , VFunc : : GT } , { " >= " , VFunc : : GE } , { " = " , VFunc : : EQ } , { " + " , VFunc : : ADD } , { " - " , VFunc : : SUB } ,
{ " * " , VFunc : : MULT } , { " / " , VFunc : : DIV } , { " % " , VFunc : : MOD }
} ;
2011-06-11 21:10:15 +03:00
2011-06-04 21:16:32 +03:00
//check keywords
if ( opt . text = = " quote " )
{
if ( exp . children . size ( ) = = 2 )
return exp . children [ 1 ] ;
else
throw EVermScriptExecError ( " quote special form takes only one argument " ) ;
}
2011-06-18 21:24:56 +03:00
else if ( opt . text = = " backquote " )
{
if ( exp . children . size ( ) = = 2 )
return boost : : apply_visitor ( _SbackquoteEval ( ) , exp . children [ 1 ] ) ;
else
throw EVermScriptExecError ( " backquote special form takes only one argument " ) ;
2012-02-16 20:10:58 +03:00
2011-06-18 21:24:56 +03:00
}
2011-06-04 21:16:32 +03:00
else if ( opt . text = = " if " )
{
if ( exp . children . size ( ) > 4 )
throw EVermScriptExecError ( " if statement takes no more than three arguments " ) ;
2011-06-18 21:24:56 +03:00
if ( ! isA < VNIL > ( erm - > eval ( exp . children [ 1 ] ) ) )
2011-06-04 21:16:32 +03:00
{
if ( exp . children . size ( ) > 2 )
return erm - > eval ( exp . children [ 2 ] ) ;
else
throw EVermScriptExecError ( " this if form needs at least two arguments " ) ;
}
else
{
if ( exp . children . size ( ) > 3 )
return erm - > eval ( exp . children [ 3 ] ) ;
else
throw EVermScriptExecError ( " this if form needs at least three arguments " ) ;
}
}
2011-06-11 21:10:15 +03:00
else if ( opt . text = = " lambda " )
{
if ( exp . children . size ( ) < = 2 )
{
throw EVermScriptExecError ( " Too few arguments for lambda special form " ) ;
}
VFunc ret ( exp . children . cdr ( ) . getAsCDR ( ) . getAsList ( ) ) ;
VNode arglist = getAs < VNode > ( exp . children [ 1 ] ) ;
for ( int g = 0 ; g < arglist . children . size ( ) ; + + g )
{
ret . args . push_back ( getAs < VSymbol > ( arglist . children [ g ] ) ) ;
}
return ret ;
}
2011-06-04 21:16:32 +03:00
else if ( opt . text = = " print " )
{
if ( exp . children . size ( ) = = 2 )
{
VOption printed = erm - > eval ( exp . children [ 1 ] ) ;
boost : : apply_visitor ( VOptionPrinter ( ) , printed ) ;
return printed ;
}
else
throw EVermScriptExecError ( " print special form takes only one argument " ) ;
}
else if ( opt . text = = " setq " )
{
if ( exp . children . size ( ) ! = 3 )
2011-06-18 21:24:56 +03:00
throw EVermScriptExecError ( " setq special form takes exactly 2 arguments " ) ;
2011-06-04 21:16:32 +03:00
2011-06-18 21:24:56 +03:00
env . bindAtFirstHit ( getAs < VSymbol > ( exp . children [ 1 ] ) . text , erm - > eval ( exp . children [ 2 ] ) ) ;
return getAs < VSymbol > ( exp . children [ 1 ] ) ;
2011-06-11 21:10:15 +03:00
}
2011-06-14 20:29:13 +03:00
else if ( opt . text = = " defun " )
{
if ( exp . children . size ( ) < 4 )
{
2011-06-18 21:24:56 +03:00
throw EVermScriptExecError ( " defun special form takes at least 3 arguments " ) ;
2011-06-14 20:29:13 +03:00
}
VFunc f ( exp . children . cdr ( ) . getAsCDR ( ) . getAsCDR ( ) . getAsList ( ) ) ;
VNode arglist = getAs < VNode > ( exp . children [ 2 ] ) ;
for ( int g = 0 ; g < arglist . children . size ( ) ; + + g )
{
f . args . push_back ( getAs < VSymbol > ( arglist . children [ g ] ) ) ;
}
env . localBind ( getAs < VSymbol > ( exp . children [ 1 ] ) . text , f ) ;
return f ;
}
2011-06-18 21:24:56 +03:00
else if ( opt . text = = " defmacro " )
{
if ( exp . children . size ( ) < 4 )
{
throw EVermScriptExecError ( " defmacro special form takes at least 3 arguments " ) ;
}
VFunc f ( exp . children . cdr ( ) . getAsCDR ( ) . getAsCDR ( ) . getAsList ( ) , true ) ;
VNode arglist = getAs < VNode > ( exp . children [ 2 ] ) ;
for ( int g = 0 ; g < arglist . children . size ( ) ; + + g )
{
f . args . push_back ( getAs < VSymbol > ( arglist . children [ g ] ) ) ;
}
env . localBind ( getAs < VSymbol > ( exp . children [ 1 ] ) . text , f ) ;
return f ;
}
else if ( opt . text = = " progn " )
{
for ( int g = 1 ; g < exp . children . size ( ) ; + + g )
{
if ( g < exp . children . size ( ) - 1 )
erm - > eval ( exp . children [ g ] ) ;
else
return erm - > eval ( exp . children [ g ] ) ;
}
return VNIL ( ) ;
}
else if ( opt . text = = " do " ) //evaluates second argument as long first evaluates to non-nil
{
if ( exp . children . size ( ) ! = 3 )
{
throw EVermScriptExecError ( " do special form takes exactly 2 arguments " ) ;
}
while ( ! isA < VNIL > ( erm - > eval ( exp . children [ 1 ] ) ) )
{
erm - > eval ( exp . children [ 2 ] ) ;
}
return VNIL ( ) ;
}
2011-06-11 21:10:15 +03:00
//"apply" part of eval, a bit blurred in this implementation but this way it looks good too
else if ( symToFunc . find ( opt . text ) ! = symToFunc . end ( ) )
{
VFunc f ( symToFunc [ opt . text ] ) ;
2011-06-18 21:24:56 +03:00
if ( f . macro )
{
return f ( exp . children . cdr ( ) ) ;
}
else
{
VOptionList ls = erm - > evalEach ( exp . children . cdr ( ) ) ;
return f ( VermTreeIterator ( ls ) ) ;
}
2011-06-04 21:16:32 +03:00
}
2011-06-14 20:29:13 +03:00
else if ( topDyn - > isBound ( opt . text , Environment : : ANYWHERE ) )
{
VOption & bValue = topDyn - > retrieveValue ( opt . text ) ;
if ( ! isA < VFunc > ( bValue ) )
{
throw EVermScriptExecError ( " This value does not evaluate to a function! " ) ;
}
VFunc f = getAs < VFunc > ( bValue ) ;
2011-06-18 21:24:56 +03:00
VOptionList ls = f . macro ? exp . children . cdr ( ) . getAsList ( ) : erm - > evalEach ( exp . children . cdr ( ) ) ;
2011-06-14 20:29:13 +03:00
return f ( VermTreeIterator ( ls ) ) ;
}
2016-08-29 18:49:52 +02:00
logGlobal - > error ( " Cannot evaluate: " ) ;
2011-06-18 21:24:56 +03:00
printVOption ( exp ) ;
2011-06-14 20:29:13 +03:00
throw EVermScriptExecError ( " Cannot evaluate given expression " ) ;
2011-06-04 21:16:32 +03:00
}
VOption operator ( ) ( TLiteral const & opt ) const
{
throw EVermScriptExecError ( " String literal does not evaluate to a function " ) ;
}
VOption operator ( ) ( ERM : : Tcommand const & opt ) const
{
throw EVermScriptExecError ( " ERM command does not evaluate to a function " ) ;
}
2011-06-11 21:10:15 +03:00
VOption operator ( ) ( VFunc const & opt ) const
{
return opt ;
}
2011-06-04 21:16:32 +03:00
} ;
struct VEvaluator : boost : : static_visitor < VOption >
{
Environment & env ;
VEvaluator ( Environment & _env ) : env ( _env )
{ }
VOption operator ( ) ( VNIL const & opt ) const
{
return opt ;
}
VOption operator ( ) ( VNode const & opt ) const
{
2011-06-11 21:10:15 +03:00
if ( opt . children . size ( ) = = 0 )
return VNIL ( ) ;
else
{
VOption & car = const_cast < VNode & > ( opt ) . children . car ( ) . getAsItem ( ) ;
return boost : : apply_visitor ( VNodeEvaluator ( env , const_cast < VNode & > ( opt ) ) , car ) ;
}
2011-06-04 21:16:32 +03:00
}
VOption operator ( ) ( VSymbol const & opt ) const
{
return env . retrieveValue ( opt . text ) ;
}
VOption operator ( ) ( TLiteral const & opt ) const
{
return opt ;
}
VOption operator ( ) ( ERM : : Tcommand const & opt ) const
{
return VNIL ( ) ;
}
2011-06-11 21:10:15 +03:00
VOption operator ( ) ( VFunc const & opt ) const
{
return opt ;
}
2011-06-04 21:16:32 +03:00
} ;
2017-07-15 13:08:20 +02:00
VOption ERMInterpreter : : eval ( VOption line , Environment * env )
2011-06-04 21:16:32 +03:00
{
// if(line.children.isNil())
// return;
2012-02-16 20:10:58 +03:00
//
2011-06-04 21:16:32 +03:00
// VOption & car = line.children.car().getAsItem();
2016-08-29 18:49:52 +02:00
logGlobal - > trace ( " \t evaluating " ) ;
2011-06-11 21:10:15 +03:00
printVOption ( line ) ;
return boost : : apply_visitor ( VEvaluator ( env ? * env : * topDyn ) , line ) ;
2011-06-04 21:16:32 +03:00
}
2017-07-15 13:08:20 +02:00
VOptionList ERMInterpreter : : evalEach ( VermTreeIterator list , Environment * env )
2011-06-04 21:16:32 +03:00
{
VOptionList ret ;
for ( int g = 0 ; g < list . size ( ) ; + + g )
{
ret . push_back ( eval ( list . getIth ( g ) , env ) ) ;
}
return ret ;
}
2011-06-11 02:50:32 +03:00
void ERMInterpreter : : executeUserCommand ( const std : : string & cmd )
{
2016-08-29 18:49:52 +02:00
logGlobal - > trace ( " ERM here: received command: %s " , cmd ) ;
2011-06-24 00:42:30 +03:00
if ( cmd . size ( ) < 3 )
{
2016-08-29 18:49:52 +02:00
logGlobal - > error ( " That can't be a valid command: %s " , cmd ) ;
2011-06-24 00:42:30 +03:00
return ;
}
try
{
if ( cmd [ 0 ] = = ' ! ' ) //should be a neat (V)ERM command
{
ERM : : TLine line = ERMParser : : parseLine ( cmd ) ;
executeLine ( line ) ;
}
}
catch ( std : : exception & e )
{
2016-08-29 18:49:52 +02:00
logGlobal - > error ( " Failed executing user command! Exception info: %s " , e . what ( ) ) ;
2011-06-24 00:42:30 +03:00
}
2011-06-11 02:50:32 +03:00
}
2018-02-10 20:52:23 +02:00
void ERMInterpreter : : giveInfoCB ( CPrivilegedInfoCallback * cb )
2011-06-20 14:41:04 +03:00
{
icb = cb ;
}
void ERMInterpreter : : giveActionCB ( IGameEventRealizer * cb )
{
acb = cb ;
}
2011-05-29 21:16:49 +03:00
namespace VERMInterpreter
{
VOption convertToVOption ( const ERM : : TVOption & tvo )
{
return boost : : apply_visitor ( OptionConverterVisitor ( ) , tvo ) ;
}
VNode : : VNode ( const ERM : : TVExp & exp )
{
for ( int i = 0 ; i < exp . children . size ( ) ; + + i )
{
2011-06-04 21:16:32 +03:00
children . push_back ( convertToVOption ( exp . children [ i ] ) ) ;
2011-05-29 21:16:49 +03:00
}
2011-06-18 21:24:56 +03:00
processModifierList ( exp . modifier , false ) ;
2011-05-29 21:16:49 +03:00
}
VNode : : VNode ( const VOption & first , const VOptionList & rest ) /*merges given arguments into [a, rest] */
{
setVnode ( first , rest ) ;
}
VNode : : VNode ( const VOptionList & cdren ) : children ( cdren )
{ }
VNode : : VNode ( const ERM : : TSymbol & sym )
{
2011-06-11 21:10:15 +03:00
children . car ( ) = VSymbol ( sym . sym ) ;
2011-06-18 21:24:56 +03:00
processModifierList ( sym . symModifier , true ) ;
2011-05-29 21:16:49 +03:00
}
void VNode : : setVnode ( const VOption & first , const VOptionList & rest )
{
children . car ( ) = first ;
children . cdr ( ) = rest ;
}
2011-06-18 21:24:56 +03:00
void VNode : : processModifierList ( const std : : vector < TVModifier > & modifierList , bool asSymbol )
2011-05-29 21:16:49 +03:00
{
for ( int g = 0 ; g < modifierList . size ( ) ; + + g )
{
2011-06-18 21:24:56 +03:00
if ( asSymbol )
{
children . resize ( children . size ( ) + 1 ) ;
for ( int i = children . size ( ) - 1 ; i > 0 ; i - - )
{
children [ i ] = children [ i - 1 ] ;
}
}
else
{
children . cdr ( ) = VNode ( children ) ;
}
2012-02-16 20:10:58 +03:00
2011-05-29 21:16:49 +03:00
if ( modifierList [ g ] = = " ` " )
{
children . car ( ) = VSymbol ( " backquote " ) ;
}
else if ( modifierList [ g ] = = " ,! " )
{
children . car ( ) = VSymbol ( " comma-unlist " ) ;
}
else if ( modifierList [ g ] = = " , " )
{
children . car ( ) = VSymbol ( " comma " ) ;
}
else if ( modifierList [ g ] = = " #' " )
{
children . car ( ) = VSymbol ( " get-func " ) ;
}
else if ( modifierList [ g ] = = " ' " )
{
children . car ( ) = VSymbol ( " quote " ) ;
}
else
throw EInterpreterError ( " Incorrect value of modifier! " ) ;
}
}
VermTreeIterator & VermTreeIterator : : operator = ( const VOption & opt )
{
switch ( state )
{
case CAR :
2011-06-11 21:10:15 +03:00
if ( parent - > size ( ) < = basePos )
parent - > push_back ( opt ) ;
2011-05-29 21:16:49 +03:00
else
2011-06-11 21:10:15 +03:00
( * parent ) [ basePos ] = opt ;
2011-05-29 21:16:49 +03:00
break ;
2011-06-11 21:10:15 +03:00
case NORM :
parent - > resize ( basePos + 1 ) ;
( * parent ) [ basePos ] = opt ;
2011-05-29 21:16:49 +03:00
break ;
default : //should never happen
break ;
}
return * this ;
}
VermTreeIterator & VermTreeIterator : : operator = ( const std : : vector < VOption > & opt )
{
switch ( state )
{
case CAR :
//TODO: implement me
break ;
2011-06-11 21:10:15 +03:00
case NORM :
parent - > resize ( basePos + 1 ) ;
parent - > insert ( parent - > begin ( ) + basePos , opt . begin ( ) , opt . end ( ) ) ;
2011-05-29 21:16:49 +03:00
break ;
default : //should never happen
break ;
}
return * this ;
}
VermTreeIterator & VermTreeIterator : : operator = ( const VOptionList & opt )
{
2011-06-04 21:16:32 +03:00
return * this = opt ;
}
VOption & VermTreeIterator : : getAsItem ( )
{
if ( state = = CAR )
2011-06-11 21:10:15 +03:00
return ( * parent ) [ basePos ] ;
2011-06-04 21:16:32 +03:00
else
throw EInterpreterError ( " iterator is not in car state, cannot get as list " ) ;
}
2011-06-11 21:10:15 +03:00
VermTreeIterator VermTreeIterator : : getAsCDR ( )
2011-06-04 21:16:32 +03:00
{
VermTreeIterator ret = * this ;
ret . basePos + + ;
return ret ;
}
VOption & VermTreeIterator : : getIth ( int i )
{
2011-06-11 21:10:15 +03:00
return ( * parent ) [ basePos + i ] ;
2011-06-04 21:16:32 +03:00
}
size_t VermTreeIterator : : size ( ) const
{
2011-06-11 21:10:15 +03:00
return parent - > size ( ) - basePos ;
}
VERMInterpreter : : VOptionList VermTreeIterator : : getAsList ( )
{
VOptionList ret ;
for ( int g = basePos ; g < parent - > size ( ) ; + + g )
{
ret . push_back ( ( * parent ) [ g ] ) ;
}
return ret ;
2011-05-29 21:16:49 +03:00
}
2011-06-11 21:10:15 +03:00
2011-05-29 21:16:49 +03:00
VOption OptionConverterVisitor : : operator ( ) ( ERM : : TVExp const & cmd ) const
{
return VNode ( cmd ) ;
}
VOption OptionConverterVisitor : : operator ( ) ( ERM : : TSymbol const & cmd ) const
{
if ( cmd . symModifier . size ( ) = = 0 )
return VSymbol ( cmd . sym ) ;
else
return VNode ( cmd ) ;
}
VOption OptionConverterVisitor : : operator ( ) ( char const & cmd ) const
{
return TLiteral ( cmd ) ;
}
VOption OptionConverterVisitor : : operator ( ) ( double const & cmd ) const
{
return TLiteral ( cmd ) ;
}
VOption OptionConverterVisitor : : operator ( ) ( int const & cmd ) const
{
return TLiteral ( cmd ) ;
}
VOption OptionConverterVisitor : : operator ( ) ( ERM : : Tcommand const & cmd ) const
{
return cmd ;
}
VOption OptionConverterVisitor : : operator ( ) ( ERM : : TStringConstant const & cmd ) const
{
return TLiteral ( cmd . str ) ;
}
2011-06-04 21:16:32 +03:00
bool VOptionList : : isNil ( ) const
{
return size ( ) = = 0 ;
}
VermTreeIterator VOptionList : : cdr ( )
{
VermTreeIterator ret ( * this ) ;
2011-06-11 21:10:15 +03:00
ret . basePos = 1 ;
2011-06-04 21:16:32 +03:00
return ret ;
}
VermTreeIterator VOptionList : : car ( )
{
VermTreeIterator ret ( * this ) ;
ret . state = VermTreeIterator : : CAR ;
return ret ;
}
2011-06-11 21:10:15 +03:00
VERMInterpreter : : VOption VFunc : : operator ( ) ( VermTreeIterator params )
{
switch ( option )
{
case DEFAULT :
{
if ( params . size ( ) ! = args . size ( ) )
{
throw EVermScriptExecError ( " Expected " + boost : : lexical_cast < std : : string > ( args . size ( ) ) + " arguments! " ) ;
}
IntroduceDynamicEnv dyn ;
for ( int i = 0 ; i < args . size ( ) ; + + i )
{
2011-06-18 21:24:56 +03:00
if ( macro )
topDyn - > localBind ( args [ i ] . text , params . getIth ( i ) ) ;
else
topDyn - > localBind ( args [ i ] . text , erm - > eval ( params . getIth ( i ) ) ) ;
2011-06-11 21:10:15 +03:00
}
//execute
2011-06-18 21:24:56 +03:00
VOptionList toEval = body ;
if ( macro )
{
//first evaluation (in place of definition)
toEval = erm - > evalEach ( toEval ) ;
}
//second evaluation for macros/evaluation of funcs
VOptionList ret = erm - > evalEach ( toEval ) ;
2011-06-11 21:10:15 +03:00
return ret [ ret . size ( ) - 1 ] ;
}
break ;
case LT :
{
if ( params . size ( ) ! = 2 )
throw EVermScriptExecError ( " < special function takes exactly 2 arguments " ) ;
TLiteral lhs = getAs < TLiteral > ( params . getIth ( 0 ) ) ,
rhs = getAs < TLiteral > ( params . getIth ( 1 ) ) ;
if ( lhs < rhs )
return lhs ;
else
return VNIL ( ) ;
}
break ;
case LE :
{
if ( params . size ( ) ! = 2 )
throw EVermScriptExecError ( " <= special function takes exactly 2 arguments " ) ;
TLiteral lhs = getAs < TLiteral > ( params . getIth ( 0 ) ) ,
rhs = getAs < TLiteral > ( params . getIth ( 1 ) ) ;
if ( lhs < = rhs )
return lhs ;
else
return VNIL ( ) ;
}
break ;
case GT :
{
if ( params . size ( ) ! = 2 )
throw EVermScriptExecError ( " > special function takes exactly 2 arguments " ) ;
TLiteral lhs = getAs < TLiteral > ( params . getIth ( 0 ) ) ,
rhs = getAs < TLiteral > ( params . getIth ( 1 ) ) ;
if ( lhs > = rhs )
return lhs ;
else
return VNIL ( ) ;
}
break ;
case GE :
{
if ( params . size ( ) ! = 2 )
throw EVermScriptExecError ( " >= special function takes exactly 2 arguments " ) ;
TLiteral lhs = getAs < TLiteral > ( params . getIth ( 0 ) ) ,
rhs = getAs < TLiteral > ( params . getIth ( 1 ) ) ;
if ( lhs > = rhs )
return lhs ;
else
return VNIL ( ) ;
}
break ;
2011-06-18 21:24:56 +03:00
case EQ :
{
if ( params . size ( ) ! = 2 )
throw EVermScriptExecError ( " = special function takes exactly 2 arguments " ) ;
printVOption ( params . getIth ( 0 ) ) ;
printVOption ( params . getIth ( 1 ) ) ;
TLiteral lhs = getAs < TLiteral > ( params . getIth ( 0 ) ) ,
rhs = getAs < TLiteral > ( params . getIth ( 1 ) ) ;
if ( lhs . type ( ) = = rhs . type ( ) )
{
if ( boost : : apply_visitor ( _opEQvis ( lhs ) , rhs ) )
return lhs ;
else
return VNIL ( ) ;
}
else
throw EVermScriptExecError ( " Incompatible types in = special function " ) ;
2012-02-16 20:10:58 +03:00
2011-06-18 21:24:56 +03:00
}
break ;
2011-06-14 20:29:13 +03:00
case ADD :
{
if ( params . size ( ) = = 0 )
throw EVermScriptExecError ( " + special function takes at least 1 argument " ) ;
TLiteral par1 = getAs < TLiteral > ( params . getIth ( 0 ) ) ;
int retI = 0 ;
double retD = 0.0 ;
int used = isA < int > ( par1 ) ? 0 : 1 ;
for ( int i = 0 ; i < params . size ( ) ; + + i )
{
if ( used = = 0 )
retI + = getAs < int > ( getAs < TLiteral > ( params . getIth ( i ) ) ) ;
else
retD + = getAs < double > ( getAs < TLiteral > ( params . getIth ( i ) ) ) ;
}
if ( used = = 0 )
return retI ;
else
return retD ;
}
break ;
case SUB :
{
if ( params . size ( ) ! = 2 )
throw EVermScriptExecError ( " - special function takes at least 2 argument " ) ;
TLiteral par1 = getAs < TLiteral > ( params . getIth ( 0 ) ) ;
int used = isA < int > ( par1 ) ? 0 : 1 ;
if ( used = = 0 )
return getAs < int > ( getAs < TLiteral > ( params . getIth ( 0 ) ) ) - getAs < int > ( getAs < TLiteral > ( params . getIth ( 1 ) ) ) ;
else
return getAs < double > ( getAs < TLiteral > ( params . getIth ( 1 ) ) ) - getAs < double > ( getAs < TLiteral > ( params . getIth ( 1 ) ) ) ;
}
break ;
case MULT :
{
if ( params . size ( ) = = 0 )
throw EVermScriptExecError ( " * special function takes at least 1 argument " ) ;
TLiteral par1 = getAs < TLiteral > ( params . getIth ( 0 ) ) ;
int retI = 1 ;
double retD = 1.0 ;
int used = isA < int > ( par1 ) ? 0 : 1 ;
for ( int i = 0 ; i < params . size ( ) ; + + i )
{
if ( used = = 0 )
retI * = getAs < int > ( getAs < TLiteral > ( params . getIth ( i ) ) ) ;
else
retD * = getAs < double > ( getAs < TLiteral > ( params . getIth ( i ) ) ) ;
}
if ( used = = 0 )
return retI ;
else
return retD ;
}
break ;
case DIV :
{
if ( params . size ( ) ! = 2 )
throw EVermScriptExecError ( " / special function takes at least 2 argument " ) ;
TLiteral par1 = getAs < TLiteral > ( params . getIth ( 0 ) ) ;
int used = isA < int > ( par1 ) ? 0 : 1 ;
if ( used = = 0 )
return getAs < int > ( getAs < TLiteral > ( params . getIth ( 0 ) ) ) / getAs < int > ( getAs < TLiteral > ( params . getIth ( 1 ) ) ) ;
else
return getAs < double > ( getAs < TLiteral > ( params . getIth ( 1 ) ) ) / getAs < double > ( getAs < TLiteral > ( params . getIth ( 1 ) ) ) ;
}
break ;
case MOD :
{
if ( params . size ( ) ! = 2 )
throw EVermScriptExecError ( " % special function takes at least 2 argument " ) ;
return getAs < int > ( getAs < TLiteral > ( params . getIth ( 0 ) ) ) % getAs < int > ( getAs < TLiteral > ( params . getIth ( 1 ) ) ) ;
}
break ;
2011-06-11 21:10:15 +03:00
default :
throw EInterpreterError ( " VFunc in forbidden mode! " ) ;
break ;
}
}
IntroduceDynamicEnv : : IntroduceDynamicEnv ( )
{
Environment * nen = new Environment ( ) ;
nen - > setPatent ( topDyn ) ;
topDyn = nen ;
}
IntroduceDynamicEnv : : ~ IntroduceDynamicEnv ( )
{
topDyn - > setPatent ( topDyn - > getPatent ( ) ) ;
}
bool operator < = ( const TLiteral & t1 , const TLiteral & t2 )
{
if ( t1 . type ( ) = = t2 . type ( ) )
{
return boost : : apply_visitor ( _opLEvis ( t1 ) , t2 ) ;
}
throw EVermScriptExecError ( " These types are incomparable! " ) ;
}
bool operator > ( const TLiteral & t1 , const TLiteral & t2 )
{
if ( t1 . type ( ) = = t2 . type ( ) )
{
return boost : : apply_visitor ( _opGTvis ( t1 ) , t2 ) ;
}
throw EVermScriptExecError ( " These types are incomparable! " ) ;
}
bool operator > = ( const TLiteral & t1 , const TLiteral & t2 )
{
if ( t1 . type ( ) = = t2 . type ( ) )
{
return boost : : apply_visitor ( _opGEvis ( t1 ) , t2 ) ;
}
throw EVermScriptExecError ( " These types are incomparable! " ) ;
}
2011-06-18 21:24:56 +03:00
struct _VLITPrinter : boost : : static_visitor < void >
{
void operator ( ) ( const std : : string & par ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " ^%s^ " , par ) ;
2011-06-18 21:24:56 +03:00
}
template < typename T >
void operator ( ) ( const T & par ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( boost : : to_string ( par ) ) ;
2011-06-18 21:24:56 +03:00
}
} ;
struct _VOPTPrinter : boost : : static_visitor < void >
{
void operator ( ) ( VNIL const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " [] " ) ;
2011-06-18 21:24:56 +03:00
}
void operator ( ) ( VNode const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " [ " ) ;
2011-06-18 21:24:56 +03:00
for ( int g = 0 ; g < opt . children . size ( ) ; + + g )
{
boost : : apply_visitor ( _VOPTPrinter ( ) , opt . children [ g ] ) ;
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " " ) ;
2011-06-18 21:24:56 +03:00
}
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " ] " ) ;
2011-06-18 21:24:56 +03:00
}
void operator ( ) ( VSymbol const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( opt . text ) ;
2011-06-18 21:24:56 +03:00
}
void operator ( ) ( TLiteral const & opt ) const
{
boost : : apply_visitor ( _VLITPrinter ( ) , opt ) ;
}
void operator ( ) ( ERM : : Tcommand const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " --erm-- " ) ;
2011-06-18 21:24:56 +03:00
}
void operator ( ) ( VFunc const & opt ) const
{
2016-08-29 18:49:52 +02:00
logGlobal - > debug ( " function " ) ;
2011-06-18 21:24:56 +03:00
}
} ;
2011-06-11 21:10:15 +03:00
void printVOption ( const VOption & opt )
{
boost : : apply_visitor ( _VOPTPrinter ( ) , opt ) ;
}
2011-06-14 16:22:00 +03:00
}