#include "gamestate.h" #include "game.h" #include "astleaf.h" #include "astleafliteral.h" #include using namespace Bu; GameState::GameState( Game *pGame, Interface *pIface ) : pGame( pGame ), pIface( pIface ), bRunning( true ), bReturnOnly( false ) { } GameState::~GameState() { } void GameState::parse( class AstBranch *pAst ) { if( pAst->getType() != AstNode::tScope ) throw Bu::ExceptionBase("Nope, nothing doing, you can't parse a non-scope AstBranch."); lsLocal.push( new Scope() ); int iDepth = lsLocal.getSize(); parse( pAst->getNodeList() ); if( lsLocal.getSize() == iDepth ) delete lsLocal.peekPop(); } void GameState::init() { Variable vStart = pGame->getParam("start"); if( vStart.getType() != Variable::tSituation ) throw Bu::ExceptionBase("game.start is not set to a situation name."); gotoSituation( vStart.getString() ); } void GameState::gotoSituation( const Bu::String &sName ) { lStack.clear(); for( ScopeList::iterator i = lsLocal.begin(); i; i++ ) delete *i; lsLocal.clear(); Situation *pSit = pGame->getSituation( sName ); sCurSituation = sName; if( !hsSituation.has( sName ) ) { hsSituation.insert( sName, new Scope() ); pSit->exec( *this, Situation::modeSetup ); } // This is here in case you use a goto in a setup mode if( bEscape ) return; pSit->exec( *this, Situation::modeEnter ); } void GameState::callFunction( const Bu::String &sName ) { pGame->getFunction( sName )->call( *this ); } void GameState::execCommand( const Bu::String &sCmd ) { Bu::StringList lCmd = tokenize( sCmd ); if( !pGame->getSituation( sCurSituation )->execCommand( *this, lCmd ) ) { if( !pGame->execCommand( *this, lCmd ) ) { sio << "I don't understand that command." << sio.nl; return; } } } bool GameState::hasVariable( const Bu::String &sName, ScopeId id ) { switch( id ) { case sidLocal: return lsLocal.peek()->has( sName ); case sidGlobal: return sGlobal.has( sName ); case sidPlayer: return sPlayer.has( sName ); case sidSituation: return hsSituation.get( sCurSituation )->has( sName ); } throw Bu::ExceptionBase("Really bad scopeid passed into getVariable"); } void GameState::delVariable( const Bu::String &sName, ScopeId id ) { switch( id ) { case sidLocal: return lsLocal.peek()->erase( sName ); case sidGlobal: return sGlobal.erase( sName ); case sidPlayer: return sPlayer.erase( sName ); case sidSituation: return hsSituation.get( sCurSituation )->erase( sName ); } throw Bu::ExceptionBase("Really bad scopeid passed into getVariable"); } Variable &GameState::getVariable( const Bu::String &sName, ScopeId id ) { try { switch( id ) { case sidLocal: return lsLocal.peek()->get( sName ); case sidGlobal: return sGlobal.get( sName ); case sidPlayer: return sPlayer.get( sName ); case sidSituation: return hsSituation.get( sCurSituation )->get( sName ); } } catch( Bu::HashException &e ) { throw Bu::ExceptionBase("No %d variable named %s found.", id, sName.getStr() ); } throw Bu::ExceptionBase("Really bad scopeid passed into getVariable"); } void GameState::setVariable( const Bu::String &sName, const Variable &v, ScopeId id ) { switch( id ) { case sidLocal: lsLocal.peek()->insert( sName, v ); return; case sidGlobal: sGlobal.insert( sName, v ); return; case sidPlayer: sPlayer.insert( sName, v ); return; case sidSituation: hsSituation.get( sCurSituation )->insert( sName, v ); return; } throw Bu::ExceptionBase("Really bad scopeid passed into setVariable"); } Variable &GameState::deref( Variable &src, bool bCreate ) { if( src.getType() == Variable::tVariable ) { VariableRef r = src.getVariableRef(); try { switch( r.sid ) { case sidLocal: return lsLocal.peek()->get( r.sName ); case sidGlobal: return sGlobal.get( r.sName ); case sidPlayer: return sPlayer.get( r.sName ); case sidSituation: return hsSituation.get( sCurSituation )->get( r.sName ); } } catch( Bu::HashException &e ) { if( bCreate ) { switch( r.sid ) { case sidLocal: lsLocal.peek()->insert( r.sName, Variable() ); return lsLocal.peek()->get( r.sName ); case sidGlobal: sGlobal.insert( r.sName, Variable() ); return sGlobal.get( r.sName ); case sidPlayer: sPlayer.insert( r.sName, Variable() ); return sPlayer.get( r.sName ); case sidSituation: hsSituation.get( sCurSituation )->insert( r.sName, Variable() ); return hsSituation.get( sCurSituation )->get( r.sName ); } } else { throw Bu::ExceptionBase("No %d variable named %s found.", r.sid, r.sName.getStr() ); } } } else if( src.getType() == Variable::tVarPtr ) { return *src.getVariablePtr(); } return src; } Bu::StringList GameState::tokenize( const Bu::String &sSrc ) { Bu::StringList lRet; Bu::String sToken; bool bWs = true; Bu::String::const_iterator i = sSrc.begin(); while( i ) { for(; i; i++ ) { if( *i != ' ' && *i != '\t' && *i != '\n' && *i != '\r' ) break; } for(; i; i++ ) { if( i == ' ' || i == '\t' || *i == '\n' || *i == '\r' ) { break; } sToken.append( *i ); } if( sToken.getSize() > 0 ) { lRet.append( sToken ); sToken.clear(); } } return lRet; } void GameState::exit() { bRunning = false; bEscape = true; } Variable GameState::popDeref() { Variable v = lStack.peekPop(); if( v.getType() == Variable::tVariable ) { VariableRef r = v.getVariableRef(); return getVariable( r.sName, r.sid ); } else if( v.getType() == Variable::tVarPtr ) { return *v.getVariablePtr(); } return v; } void GameState::parse( const AstBranch::NodeList &lCode ) { bEscape = false; for( AstBranch::NodeList::const_iterator i = lCode.begin(); i; i++ ) { // sio << "Stack: " << lStack << sio.nl; // sio << "exec: " << (*i)->getType() << sio.nl; switch( (*i)->getType() ) { // tLeaf case AstNode::tNot: { Variable x = popDeref(); if( x.getType() != Variable::tBool ) throw Bu::ExceptionBase("Non-bool used with logical not operator."); push( Variable( !x.getBool() ) ); } break; case AstNode::tComp: { push( popDeref() == popDeref() ); } break; case AstNode::tCompGt: { Variable y = popDeref(); Variable x = popDeref(); push( x > y ); } break; case AstNode::tCompLt: { Variable y = popDeref(); Variable x = popDeref(); push( x < y ); } break; case AstNode::tCompGtEq: { Variable y = popDeref(); Variable x = popDeref(); push( x >= y ); } break; case AstNode::tCompLtEq: { Variable y = popDeref(); Variable x = popDeref(); push( x <= y ); } break; case AstNode::tStore: { Variable y = popDeref(); deref( lStack.peek(), true ) = y; /* Variable dst = pop(); VariableRef r = dst.getVariableRef(); setVariable( r.sName, y, r.sid ); */ } break; case AstNode::tStoreRev: { Variable dst = pop(); Variable y = popDeref(); VariableRef r = dst.getVariableRef(); setVariable( r.sName, y, r.sid ); } break; case AstNode::tAnd: { Variable y = popDeref(); Variable x = popDeref(); if( x.getType() != Variable::tBool || y.getType() != Variable::tBool ) { throw Bu::ExceptionBase("Non-bool used in logical AND operator."); } lStack.push( Variable( x.getBool() && y.getBool() ) ); } break; case AstNode::tOr: { Variable y = popDeref(); Variable x = popDeref(); if( x.getType() != Variable::tBool || y.getType() != Variable::tBool ) { throw Bu::ExceptionBase("Non-bool used in logical OR operator."); } lStack.push( Variable( x.getBool() || y.getBool() ) ); } break; case AstNode::tPlus: { Variable y = popDeref(); Variable x = popDeref(); lStack.push( x + y ); } break; case AstNode::tMinus: { Variable y = popDeref(); Variable x = popDeref(); lStack.push( x - y ); } break; case AstNode::tDivide: { Variable y = popDeref(); Variable x = popDeref(); lStack.push( x / y ); } break; case AstNode::tMultiply: { Variable y = popDeref(); Variable x = popDeref(); lStack.push( x * y ); } break; case AstNode::tPlusStore: { Variable y = popDeref(); deref( lStack.peek(), true ) += y; } break; case AstNode::tMinusStore: { Variable y = popDeref(); deref( lStack.peek(), true ) -= y; } break; case AstNode::tDivideStore: { Variable y = popDeref(); deref( lStack.peek(), true ) /= y; } break; case AstNode::tMultiplyStore: { Variable y = popDeref(); deref( lStack.peek(), true ) *= y; } break; case AstNode::tNegate: push( -popDeref() ); break; case AstNode::tIn: { Variable v = popDeref(); Variable x = popDeref(); if( v.getType() == Variable::tDictionary || v.getType() == Variable::tList ) { push( Variable( v.has( x ) ) ); } else { throw Bu::ExceptionBase("Invalid type for operator in"); } } break; case AstNode::tGoto: { Variable x = popDeref(); if( x.getType() != Variable::tSituation ) throw Bu::ExceptionBase("You cannot goto anything but a situation."); gotoSituation( x.getString() ); bEscape = true; return; } break; case AstNode::tSwap: { Variable y = pop(); Variable x = pop(); push( y ); push( x ); } break; case AstNode::tReturn: bReturnOnly = true; bEscape = true; return; break; case AstNode::tAppend: { Variable v = popDeref(); deref( lStack.peek() ) += v; } break; case AstNode::tInsert: { Variable v = popDeref(); Variable k = popDeref(); deref( lStack.peek() ).insert( k, v ); } break; case AstNode::tIndex: { Variable v = popDeref(); Variable cx = pop(); Variable &c = deref( cx ); push( Variable( &c.get( v ) ) ); } break; // tLeafLiteral case AstNode::tVarName: case AstNode::tLiteral: lStack.push( dynamic_cast(*i)->getValue() ); break; case AstNode::tFuncCall: callFunction( dynamic_cast(*i) ->getValue().getString() ); bReturnOnly = false; bEscape = false; break; // tBranch case AstNode::tScope: throw Bu::ExceptionBase("Scope? that shouldn't be here..."); break; case AstNode::tIf: { AstBranch::NodeList lIf = dynamic_cast(*i)->getNodeList(); AstBranch::NodeList::const_iterator iIf = lIf.begin(); parse( dynamic_cast(*iIf)->getNodeList() ); Variable v = popDeref(); if( v.getType() != Variable::tBool ) throw Bu::ExceptionBase("conditional did not evaluate to boolean."); iIf++; if( v.getBool() ) { parse( dynamic_cast(*iIf)-> getNodeList() ); } else { iIf++; if( iIf ) parse( dynamic_cast(*iIf)-> getNodeList() ); } } break; case AstNode::tForEach: { AstBranch::NodeList lFe = dynamic_cast(*i)->getNodeList(); AstBranch::NodeList::const_iterator iEach = lFe.begin(); AstBranch::NodeList::const_iterator iIn = iEach+1; AstBranch::NodeList::const_iterator iDo = iIn+1; const AstBranch::NodeList &lEachVrs = dynamic_cast(*iEach)->getNodeList(); AstBranch::NodeList::const_iterator iEachVrs = lEachVrs.begin(); bool bUseKey = false; VariableRef vrKey, vrValue; if( lEachVrs.getSize() == 2 ) { vrKey = dynamic_cast(*iEachVrs)-> getValue().getVariableRef(); iEachVrs++; vrValue = dynamic_cast(*iEachVrs)-> getValue().getVariableRef(); bUseKey = true; } else { vrValue = dynamic_cast(*iEachVrs)-> getValue().getVariableRef(); } parse( dynamic_cast(*iIn)->getNodeList() ); Variable vIn = popDeref(); const AstBranch::NodeList &rDo = dynamic_cast(*iDo)->getNodeList(); if( vIn.getType() == Variable::tDictionary ) { const Variable::VariableHash &rHash = vIn.getHash(); for( Variable::VariableHash::const_iterator i = rHash.begin(); i; i++ ) { if( bUseKey ) setVariable( vrKey.sName, i.getKey(), vrKey.sid ); setVariable( vrValue.sName, i.getValue(), vrValue.sid ); parse( rDo ); } } else if( vIn.getType() == Variable::tList ) { if( bUseKey ) { throw Bu::ExceptionBase("You cannot use key:value pairs as iterators in a for each loop iterating over a list."); } const Variable::VariableArray &rList = vIn.getList(); for( Variable::VariableArray::const_iterator i = rList.begin(); i; i++ ) { setVariable( vrValue.sName, *i, vrValue.sid ); parse( rDo ); } } } break; case AstNode::tWhile: { AstBranch::NodeList lWhile = dynamic_cast(*i)->getNodeList(); AstBranch::NodeList::const_iterator iTest = lWhile.begin(); AstBranch::NodeList::const_iterator iDo = iTest+1; for(;;) { parse( dynamic_cast(*iTest)-> getNodeList() ); Variable v = popDeref(); if( v.getType() != Variable::tBool ) throw Bu::ExceptionBase("conditional did not evaluate to boolean."); if( !v.getBool() ) break; parse( dynamic_cast(*iDo)-> getNodeList() ); } } break; } if( bEscape || !bRunning ) { return; } } }