Esempio n. 1
0
bool OTScriptChai::ExecuteScript(OTVariable* pReturnVar)
{
    using namespace chaiscript;

    OT_ASSERT(nullptr != chai);

    if (m_str_script.size() > 0) {

        /*
        chai->add(user_type<OTParty>(), "OTParty");
        chai->add(constructor<OTParty()>(), "OTParty");
        chai->add(constructor<OTParty(const OTParty&)>(), "OTParty");
        chai->add(fun<OTParty&(OTParty::*)(const
        OTParty&)>(&OTParty::operator=), "=");

        chai->add(fun(&OTParty::GetPartyName), "GetPartyName");
        chai->add(fun(&OTParty::GetNymID), "GetNymID");
        chai->add(fun(&OTParty::GetEntityID), "GetEntityID");
        chai->add(fun(&OTParty::GetPartyID), "GetPartyID");
        chai->add(fun(&OTParty::HasActiveAgent), "HasActiveAgent");
        */

        // etc

        //      chai->add(m); // Here we add the OTParty class to the
        // chaiscript engine.

        for (auto& it : m_mapParties) {
            OTParty* pParty = it.second;
            OT_ASSERT(nullptr != pParty);

            std::string party_name = pParty->GetPartyName();

            //          std::cerr << " TESTING PARTY: " << party_name <<
            // std::endl;
            //          chai->add(chaiscript::var(&d), "d");

            // Currently I don't make the entire party available -- just his ID.
            //
            // Update: The client side uses constant variables only (a block or
            // two down
            // from here) and it stores the user's ID, and acct IDs, directly in
            // those
            // variables based on name.  Whereas the server side passes in
            // Parties and
            // PartyAccounts, and only the names are made available inside the
            // scripts.
            // This way the scripts must entirely rely on the server-side API,
            // functions
            // such as move_funds(from_name, to_name), which expect a name, and
            // translate
            // only internally to resolve the ID.
            // (Contrast this with client-side scripts, which actually have the
            // real ID
            // available inside the script, and which can call any OT API
            // function that
            // exists...)
            //
            chai->add_global_const(const_var(party_name),
                                   party_name.c_str()); // Why name and not
                                                        // ID? See comment
                                                        // just above.
        }

        for (auto& it : m_mapAccounts) {
            OTPartyAccount* pAcct = it.second;
            OT_ASSERT(nullptr != pAcct);

            std::string acct_name = pAcct->GetName().Get();

            //          std::cerr << " TESTING ACCOUNT: " << acct_name <<
            // std::endl;
            //          chai->add(chaiscript::var(&d), "d");

            // Currently I don't make the entire account available -- just his
            // ID.
            //
            chai->add_global_const(const_var(acct_name),
                                   acct_name.c_str()); // See comment in
                                                       // above block for
                                                       // party name.
        }

        /*
         enum OTVariable_Access
         {
             Var_Constant,        // Constant -- you cannot change this value.
             Var_Persistent,    // Persistent -- changing value doesn't require
         notice to parties.
             Var_Important,        // Important -- changing value requires
         notice to parties.
             Var_Error_Access    // should never happen.
         };

         OTVariable_Access      GetAccess() const { return m_Access; }

         int64_t& GetValueLong() { return m_lValue; }
         bool& GetValueBool() { return m_bValue; }
         std::string& GetValueString() { return m_str_Value; }
         */

        for (auto& it : m_mapVariables) {
            const std::string var_name = it.first;
            OTVariable* pVar = it.second;
            OT_ASSERT((nullptr != pVar) && (var_name.size() > 0));

            switch (pVar->GetType()) {
            case OTVariable::Var_Integer: {
                int32_t& nValue = pVar->GetValueInteger();

                if (OTVariable::Var_Constant ==
                    pVar->GetAccess()) // no pointer here, since it's constant.
                    chai->add_global_const(const_var(pVar->CopyValueInteger()),
                                           var_name.c_str());
                else
                    chai->add(var(&nValue), // passing ptr here so the
                                            // script can modify this
                                            // variable if it wants.
                              var_name.c_str());
            } break;

            case OTVariable::Var_Bool: {
                bool& bValue = pVar->GetValueBool();

                if (OTVariable::Var_Constant ==
                    pVar->GetAccess()) // no pointer here, since it's constant.
                    chai->add_global_const(const_var(pVar->CopyValueBool()),
                                           var_name.c_str());
                else
                    chai->add(var(&bValue), // passing ptr here so the
                                            // script can modify this
                                            // variable if it wants.
                              var_name.c_str());
            } break;

            case OTVariable::Var_String: {
                std::string& str_Value = pVar->GetValueString();

                if (OTVariable::Var_Constant ==
                    pVar->GetAccess()) // no pointer here, since it's constant.
                {
                    chai->add_global_const(const_var(pVar->CopyValueString()),
                                           var_name.c_str());

                    //                      otErr << "\n\n\nOTSCRIPT DEBUGGING
                    // (const var added to script): %s\n\n\n",
                    // str_Value.c_str());
                }
                else {
                    chai->add(var(&str_Value), // passing ptr here so the
                                               // script can modify this
                                               // variable if it wants.
                              var_name.c_str());

                    //                      otErr << "\n\n\nOTSCRIPT DEBUGGING
                    // var added to script: %s \n\n\n", str_Value.c_str());
                }
            } break;

            default:
                otErr << "OTScriptChai::ExecuteScript: Failure: Unknown "
                         "variable type for variable: " << var_name << "\n";
                return false;
            }
        }

        // Here we add the mapOfParties user-defined type to the chaiscript
        // engine.
        //      chai->add(user_type<mapOfParties>(), "mapOfParties");

        // Here we add the m_mapParties member variable itself
        //      chai->add_global_const(const_var(m_mapParties),
        // "Parties");

        try {
            if (nullptr == pReturnVar) // Nothing to return.
                chai->eval(m_str_script.c_str(),
                           exception_specification<const std::exception&>(),
                           m_str_display_filename);

            else // There's a return variable.
            {
                switch (pReturnVar->GetType()) {
                case OTVariable::Var_Integer: {
                    int32_t nResult = chai->eval<int32_t>(
                        m_str_script.c_str(),
                        exception_specification<const std::exception&>(),
                        m_str_display_filename);
                    pReturnVar->SetValue(nResult);
                } break;

                case OTVariable::Var_Bool: {
                    bool bResult = chai->eval<bool>(
                        m_str_script.c_str(),
                        exception_specification<const std::exception&>(),
                        m_str_display_filename);
                    pReturnVar->SetValue(bResult);
                } break;

                case OTVariable::Var_String: {
                    std::string str_Result = chai->eval<std::string>(
                        m_str_script.c_str(),
                        exception_specification<const std::exception&>(),
                        m_str_display_filename);
                    pReturnVar->SetValue(str_Result);
                } break;

                default:
                    otErr << "OTScriptChai::ExecuteScript: Unknown return type "
                             "passed in, "
                             "unable to service it.\n";
                    return false;
                } // switch
            }     // else return variable.
        }         // try
        catch (const chaiscript::exception::eval_error& ee) {
            // Error in script parsing / execution
            otErr << "OTScriptChai::ExecuteScript: \n Caught "
                     "chaiscript::exception::eval_error: \n " << ee.reason
                  << ". \n   File: " << ee.filename
                  << "\n"
                     "   Start position, line: " << ee.start_position.line
                  << " column: " << ee.start_position.column
                  << "\n"
                     "   End position,   line: " << ee.end_position.line
                  << " column: " << ee.end_position.column << "\n\n";

            std::cout << ee.what();
            if (ee.call_stack.size() > 0) {
                std::cout << "during evaluation at ("
                          << ee.call_stack[0]->start.line << ", "
                          << ee.call_stack[0]->start.column << ")";
            }
            std::cout << std::endl;
            std::cout << std::endl;

            //          std::cout << ee.what();
            if (ee.call_stack.size() > 0) {
                //                std::cout << "during evaluation at (" <<
                // *(ee.call_stack[0]->filename) << " " <<
                // ee.call_stack[0]->start.line << ", " <<
                // ee.call_stack[0]->start.column << ")";

                //                const std::string text;
                //                boost::shared_ptr<const std::string> filename;

                for (size_t j = 1; j < ee.call_stack.size(); ++j) {
                    if (ee.call_stack[j]->identifier !=
                            chaiscript::AST_Node_Type::Block &&
                        ee.call_stack[j]->identifier !=
                            chaiscript::AST_Node_Type::File) {
                        std::cout << std::endl;
                        std::cout << "  from " << *(ee.call_stack[j]->filename)
                                  << " (" << ee.call_stack[j]->start.line
                                  << ", " << ee.call_stack[j]->start.column
                                  << ") : ";
                        std::cout << ee.call_stack[j]->text << std::endl;
                    }
                }
            }
            std::cout << std::endl;

            return false;
        }
        catch (const chaiscript::exception::bad_boxed_cast& e) {
            // Error unboxing return value
            otErr << "OTScriptChai::ExecuteScript: Caught "
                     "chaiscript::exception::bad_boxed_cast : "
                  << ((e.what() != nullptr) ? e.what()
                                            : "e.what() returned null, sorry")
                  << ".\n";
            return false;
        }
        catch (const std::exception& e) {
            // Error explicitly thrown from script
            otErr << "OTScriptChai::ExecuteScript: Caught std::exception "
                     "exception: " << ((e.what() != nullptr)
                                           ? e.what()
                                           : "e.what() returned null, sorry")
                  << "\n";
            return false;
        }
        //      catch (chaiscript::Boxed_Value bv)
        catch (...) {
            //          int32_t i = chaiscript::boxed_cast<int32_t>(bv);
            otErr << "OTScriptChai::ExecuteScript: Caught exception.\n";
            return false;
        }
    }

    return true;
}