private void ExecuteFunction(RuntimeFunction function) { Debug.Assert(function != null); if (function == null) { throw new ArgumentNullException(nameof(function)); } FunctionStack.Push(function); Reader.Push(); Debug.Assert(function.IP != ByteCodes.InvalidIP); Reader.GoTo(function.IP); // Dispatch each bytecode to its handler ByteCode bytecode; do { bytecode = Reader.GetNext(); Debug.Assert(ByteCodeHandlerLookup.ContainsKey(bytecode)); ByteCodeHandlerLookup[bytecode](this); } while (bytecode != ByteCode.Return); FunctionStack.Pop(); Reader.Pop(); }
/// <summary> /// Executes the given program. /// </summary> /// <returns>Returns a variable that contains the result of the program.</returns> public Variable Execute() { Reader.GoTo(0); FunctionStack.Clear(); VarStack.Clear(); UserData = null; OnBegin(); try { // Initial bytecodes are call to main() function ByteCode bytecode = Reader.GetNext(); Debug.Assert(bytecode == ByteCode.ExecFunction); int mainId = Reader.GetNextValue(); // Validate if (bytecode != ByteCode.ExecFunction || Program.Functions[mainId] is not UserFunction userFunction) { throw new Exception("Invalid bytecode program : Missing call to function main."); } RuntimeFunction function = new(userFunction); // Execute this function ExecuteFunction(function); // Return result return(function.ReturnValue); } catch (Exception ex) { // Include line-number information if possible if (Program.LineNumbers != null) { Debug.Assert(Program.LineNumbers.Length == Program.ByteCodes.Length); int ip = (Reader.IP - 1); if (ip >= 0 && ip < Program.LineNumbers.Length) { string s = $"\"{ex.Message}\" exception on line {Program.LineNumbers[ip]}. See inner exception for details."; throw new Exception(s, ex); } } throw; } finally { OnEnd(); } }