| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using Antlr4.Runtime;
- using MoonSharp.Interpreter.CoreLib;
- using MoonSharp.Interpreter.Debugging;
- using MoonSharp.Interpreter.Diagnostics;
- using MoonSharp.Interpreter.Execution.VM;
- using MoonSharp.Interpreter.Interop;
- using MoonSharp.Interpreter.Loaders;
- using MoonSharp.Interpreter.Tree;
- using MoonSharp.Interpreter.Tree.Statements;
- namespace MoonSharp.Interpreter
- {
- /// <summary>
- /// This class implements a Moon# scripting session. Multiple Script objects can coexist in the same program but cannot share
- /// data among themselves unless some mechanism is put in place.
- /// </summary>
- public class Script
- {
- Processor m_MainRoutine = null;
- List<Processor> m_Coroutines = new List<Processor>();
- ByteCode m_ByteCode;
- List<SourceCode> m_Sources = new List<SourceCode>();
- Table m_GlobalTable;
- IDebugger m_Debugger;
- IScriptLoader m_ScriptLoader = DefaultScriptLoader;
- Table[] m_TypeMetatables = new Table[(int)DataType.MaxMetaTypes];
- static Script()
- {
- DefaultScriptLoader = new ClassicLuaScriptLoader();
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="Script"/> class.
- /// </summary>
- public Script()
- : this(CoreModules.Preset_Default)
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="Script"/> class.
- /// </summary>
- /// <param name="coreModules">The core modules to be pre-registered in the default global table.</param>
- public Script(CoreModules coreModules)
- {
- DebugPrint = s => { Console.WriteLine(s); };
- m_ByteCode = new ByteCode();
- m_GlobalTable = new Table(this).RegisterCoreModules(coreModules);
- m_MainRoutine = new Processor(this, m_GlobalTable, m_ByteCode);
- ReseedRandomGenerator(DateTime.Now.Millisecond);
- }
- /// <summary>
- /// Gets or sets the script loader to use. A script loader wraps all code loading from files, so that access
- /// to the filesystem can be completely overridden.
- /// </summary>
- /// <value>
- /// The current script loader.
- /// </value>
- public IScriptLoader ScriptLoader
- {
- get { return m_ScriptLoader; }
- set { m_ScriptLoader = value; }
- }
- /// <summary>
- /// Gets or sets the script loader which will be used as the value of the
- /// ScriptLoader property for all newly created scripts.
- /// </summary>
- public static IScriptLoader DefaultScriptLoader { get; set; }
- /// <summary>
- /// Gets the default global table for this script. Unless a different table is intentionally passed (or setfenv has been used)
- /// execution uses this table.
- /// </summary>
- public Table Globals
- {
- get { return m_GlobalTable; }
- }
- /// <summary>
- /// Loads a string containing a Lua/Moon# function.
- /// </summary>
- /// <param name="code">The code.</param>
- /// <param name="globalTable">The global table to bind to this chunk.</param>
- /// <param name="funcFriendlyName">Name of the function used to report errors, etc.</param>
- /// <returns>
- /// A DynValue containing a function which will execute the loaded code.
- /// </returns>
- public DynValue LoadFunction(string code, Table globalTable = null, string funcFriendlyName = null)
- {
- string chunkName = string.Format("<string:{0:X4}>", m_Sources.Count);
- SourceCode source = new SourceCode(funcFriendlyName ?? chunkName, code);
- m_Sources.Add(source);
- int address = Loader.LoadFunctionFromICharStream(new AntlrInputStream(code),
- m_ByteCode,
- funcFriendlyName ?? chunkName,
- m_Sources.Count - 1,
- globalTable ?? m_GlobalTable);
- if (m_Debugger != null)
- m_Debugger.SetSourceCode(m_ByteCode, null);
- return MakeClosure(address);
- }
- /// <summary>
- /// Loads a string containing a Lua/Moon# script.
- /// </summary>
- /// <param name="code">The code.</param>
- /// <param name="globalTable">The global table to bind to this chunk.</param>
- /// <param name="codeFriendlyName">Name of the code - used to report errors, etc.</param>
- /// <returns>
- /// A DynValue containing a function which will execute the loaded code.
- /// </returns>
- public DynValue LoadString(string code, Table globalTable = null, string codeFriendlyName = null)
- {
- string chunkName = string.Format("<string:{0:X4}>", m_Sources.Count);
- SourceCode source = new SourceCode(codeFriendlyName ?? chunkName, code);
- m_Sources.Add(source);
- int address = Loader.LoadChunkFromICharStream(new AntlrInputStream(code),
- m_ByteCode,
- codeFriendlyName ?? chunkName,
- m_Sources.Count - 1,
- globalTable ?? m_GlobalTable);
- if (m_Debugger != null)
- m_Debugger.SetSourceCode(m_ByteCode, null);
- return MakeClosure(address);
- }
- /// <summary>
- /// Loads a string containing a Lua/Moon# script.
- /// </summary>
- /// <param name="filename">The code.</param>
- /// <param name="globalContext">The global table to bind to this chunk.</param>
- /// <returns>A DynValue containing a function which will execute the loaded code.</returns>
- public DynValue LoadFile(string filename, Table globalContext = null)
- {
- filename = m_ScriptLoader.ResolveFileName(filename, globalContext ?? m_GlobalTable);
- return LoadResolvedFile(filename, globalContext);
- }
- private DynValue LoadResolvedFile(string filename, Table globalContext)
- {
- if (m_ScriptLoader.HasCustomFileLoading())
- {
- return LoadString(m_ScriptLoader.LoadFile(filename, globalContext ?? m_GlobalTable), globalContext, filename);
- }
- else
- {
- return LoadString(File.ReadAllText(filename), globalContext, filename);
- }
- }
- /// <summary>
- /// Loads and executes a string containing a Lua/Moon# script.
- /// </summary>
- /// <param name="code">The code.</param>
- /// <param name="globalContext">The global context.</param>
- /// <returns>
- /// A DynValue containing the result of the processing of the loaded chunk.
- /// </returns>
- public DynValue DoString(string code, Table globalContext = null)
- {
- DynValue func = LoadString(code, globalContext);
- return Call(func);
- }
- /// <summary>
- /// Loads and executes a file containing a Lua/Moon# script.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <param name="globalContext">The global context.</param>
- /// <returns>
- /// A DynValue containing the result of the processing of the loaded chunk.
- /// </returns>
- public DynValue DoFile(string filename, Table globalContext = null)
- {
- DynValue func = LoadFile(filename, globalContext);
- return Call(func);
- }
- /// <summary>
- /// Runs the specified file with all possible defaults for quick experimenting.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// A DynValue containing the result of the processing of the executed script.
- public static DynValue RunFile(string filename)
- {
- Script S = new Script();
- return S.DoFile(filename);
- }
- /// <summary>
- /// Runs the specified code with all possible defaults for quick experimenting.
- /// </summary>
- /// <param name="code">The Lua/Moon# code.</param>
- /// A DynValue containing the result of the processing of the executed script.
- public static DynValue RunString(string code)
- {
- Script S = new Script();
- return S.DoString(code);
- }
- /// <summary>
- /// Creates a closure from a bytecode address.
- /// </summary>
- /// <param name="address">The address.</param>
- /// <returns></returns>
- private DynValue MakeClosure(int address)
- {
- Closure c = new Closure(this, address,
- new SymbolRef[0],
- new DynValue[0]);
- return DynValue.NewClosure(c);
- }
- /// <summary>
- /// Calls the specified function.
- /// </summary>
- /// <param name="function">The Lua/Moon# function to be called - callbacks are not supported.</param>
- /// <returns></returns>
- public DynValue Call(DynValue function)
- {
- return m_MainRoutine.Call(function, new DynValue[0]);
- }
- /// <summary>
- /// Calls the specified function.
- /// </summary>
- /// <param name="function">The Lua/Moon# function to be called - callbacks are not supported.</param>
- /// <param name="args">The arguments to pass to the function.</param>
- /// <returns></returns>
- public DynValue Call(DynValue function, params DynValue[] args)
- {
- return m_MainRoutine.Call(function, args);
- }
- /// <summary>
- /// Calls the specified function.
- /// </summary>
- /// <param name="function">The Lua/Moon# function to be called - callbacks are not supported.</param>
- /// <param name="args">The arguments to pass to the function.</param>
- /// <returns></returns>
- public DynValue Call(DynValue function, params object[] args)
- {
- return m_MainRoutine.Call(function, args.Select(v => DynValue.FromObject(this, v)).ToArray());
- }
- /// <summary>
- /// Calls the specified function.
- /// </summary>
- /// <param name="function">The Lua/Moon# function to be called - callbacks are not supported.</param>
- /// <returns></returns>
- public DynValue Call(object function)
- {
- return Call(DynValue.FromObject(this, function));
- }
- /// <summary>
- /// Calls the specified function.
- /// </summary>
- /// <param name="function">The Lua/Moon# function to be called - callbacks are not supported.</param>
- /// <param name="args">The arguments to pass to the function.</param>
- /// <returns></returns>
- public DynValue Call(object function, params object[] args)
- {
- return Call(DynValue.FromObject(this, function), args);
- }
- /// <summary>
- /// Gets the main chunk function.
- /// </summary>
- /// <returns>A DynValue containing a function which executes the first chunk that has been loaded.</returns>
- public DynValue GetMainChunk()
- {
- return MakeClosure(0);
- }
- /// <summary>
- /// Attaches a debugger.
- /// </summary>
- /// <param name="debugger">The debugger object.</param>
- public void AttachDebugger(IDebugger debugger)
- {
- m_Debugger = debugger;
- m_MainRoutine.AttachDebugger(debugger);
- foreach (var C in m_Coroutines)
- C.AttachDebugger(debugger);
- m_Debugger.SetSourceCode(m_ByteCode, null);
- }
- /// <summary>
- /// Loads a module as per the "require" Lua function. http://www.lua.org/pil/8.1.html
- /// </summary>
- /// <param name="modname">The module name</param>
- /// <param name="globalContext">The global context.</param>
- /// <returns></returns>
- /// <exception cref="ScriptRuntimeException">Raised if module is not found</exception>
- public DynValue RequireModule(string modname, Table globalContext = null)
- {
- Table globals = globalContext ?? m_GlobalTable;
- string filename = m_ScriptLoader.ResolveModuleName(modname, globals);
- if (filename == null)
- throw new ScriptRuntimeException("module '{0}' not found", modname);
- DynValue func = LoadResolvedFile(filename, globalContext);
- return func;
- }
- /// <summary>
- /// Gets the random generator associated with this Script
- /// </summary>
- public Random RandomGenerator { get; private set; }
- /// <summary>
- /// Reseeds the random generator.
- /// </summary>
- /// <param name="seed">The seed.</param>
- public void ReseedRandomGenerator(double seed)
- {
- RandomGenerator = new Random();
- }
- /// <summary>
- /// Gets a type metatable.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns></returns>
- public Table GetTypeMetatable(DataType type)
- {
- int t = (int)type;
- if (t >= 0 && t < m_TypeMetatables.Length)
- return m_TypeMetatables[t];
- return null;
- }
- /// <summary>
- /// Sets a type metatable.
- /// </summary>
- /// <param name="type">The type. Must be Nil, Boolean, Number, String or Function</param>
- /// <param name="metatable">The metatable.</param>
- /// <exception cref="System.ArgumentException">Specified type not supported : + type.ToString()</exception>
- public void SetTypeMetatable(DataType type, Table metatable)
- {
- int t = (int)type;
- if (t >= 0 && t < m_TypeMetatables.Length)
- m_TypeMetatables[t] = metatable;
- else
- throw new ArgumentException("Specified type not supported : " + type.ToString());
- }
- /// <summary>
- /// Gets or sets the debug print handler
- /// </summary>
- public Action<string> DebugPrint { get; set; }
- /// <summary>
- /// Warms up the parser/lexer structures so that Moon# operations start faster.
- /// </summary>
- public static void WarmUp()
- {
- Script s = new Script(CoreModules.Basic);
- s.LoadString("return 1;");
- }
- }
- }
|