summaryrefslogtreecommitdiff
path: root/indra/newview/llluamanager.h
blob: b98b5d4ef642c887861196dccb2841ffdee34742 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
 * @file llluamanager.h
 * @brief classes and functions for interfacing with LUA.
 *
 * $LicenseInfo:firstyear=2023&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2023, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef LL_LLLUAMANAGER_H
#define LL_LLLUAMANAGER_H

#include "fsyspath.h"
#include "llcoros.h"
#include "llsd.h"
#include <functional>
#include <string>
#include <utility>                  // std::pair

#include "luau/lua.h"
#include "luau/lualib.h"

class LuaState;

class LLLUAmanager
{
    friend class ScriptObserver;

public:
    // Pass a callback with this signature to obtain the result, if any, of
    // running a script or source string.
    // count <  0 means error, and result.asString() is the error message.
    // count == 0 with result.isUndefined() means the script returned no results.
    // count == 1 means the script returned one result.
    // count >  1 with result.isArray() means the script returned multiple
    //            results, represented as the entries of the result array.
    typedef std::function<void(int count, const LLSD& result)> script_result_fn;
    // same semantics as script_result_fn parameters
    typedef std::pair<int, LLSD> script_result;

    // Run the script specified by the command line passed as @a filename.
    // This can be followed by some number of command-line arguments, which
    // a Lua script can view using either '...' or predefined global 'arg'.
    // The script pathname or its arguments can be quoted using 'single
    // quotes' or "double quotes", or special characters can be \escaped.
    // runScriptFile() recognizes the case in which the whole 'filename'
    // string is a path containing spaces; if so no arguments are permitted.
    // In either form, if the script pathname isn't absolute, it is sought on
    // LuaCommandPath.
    // If autorun is true, statistics will count this as an autorun script.
    static void runScriptFile(const std::string &filename, bool autorun = false,
                              script_result_fn result_cb = {});
    // Start running a Lua script file, returning an LLCoros::Future whose
    // get() method will pause the calling coroutine until it can deliver the
    // (count, result) pair described above. Between startScriptFile() and
    // Future::get(), the caller and the Lua script coroutine will run
    // concurrently.
    // @a filename is as described for runScriptFile().
    static LLCoros::Future<script_result> startScriptFile(const std::string& filename);
    // Run a Lua script file, and pause the calling coroutine until it completes.
    // The return value is the (count, result) pair described above.
    // @a filename is as described for runScriptFile().
    static script_result waitScriptFile(const std::string& filename);

    static void runScriptLine(const std::string &chunk, script_result_fn result_cb = {});
    // Start running a Lua chunk, returning an LLCoros::Future whose
    // get() method will pause the calling coroutine until it can deliver the
    // (count, result) pair described above. Between startScriptLine() and
    // Future::get(), the caller and the Lua script coroutine will run
    // concurrently.
    static LLCoros::Future<script_result> startScriptLine(const std::string& chunk);
    // Run a Lua chunk, and pause the calling coroutine until it completes.
    // The return value is the (count, result) pair described above.
    static script_result waitScriptLine(const std::string& chunk);

    static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; }

    static S32 sAutorunScriptCount;
    static S32 sScriptCount;

 private:
   static std::map<std::string, std::string> sScriptNames;
};

class LLRequireResolver
{
 public:
    static void resolveRequire(lua_State *L, std::string path);

 private:
    fsyspath mPathToResolve;
    fsyspath mSourceDir;

    LLRequireResolver(lua_State *L, const std::string& path);

    void findModule();
    lua_State *L;

    bool findModuleImpl(const std::string& absolutePath);
    void runModule(const std::string& desc, const std::string& code);
};

// RAII class to guarantee that a script entry is erased even when coro is terminated
class ScriptObserver
{
  public:
    ScriptObserver(const std::string &coro_name, const std::string &filename) : mCoroName(coro_name)
    {
        LLLUAmanager::sScriptNames[mCoroName] = filename;
    }
    ~ScriptObserver() { LLLUAmanager::sScriptNames.erase(mCoroName); }

  private:
    std::string mCoroName;
};
#endif