public RuntimeFunction(UserFunction function) { if (function == null) { throw new ArgumentNullException(nameof(function)); } IP = function.IP; Parameters = new Variable[function.NumParameters]; for (int i = 0; i < function.NumParameters; i++) { Parameters[i] = new Variable(); } Variables = new Variable[function.NumVariables]; for (int i = 0; i < function.NumVariables; i++) { Variables[i] = new Variable(); } ReturnValue = new Variable(); }
/// <summary> /// Loads a precompiled program from disk. /// </summary> /// <remarks> /// NOTE: We should employ some sort of checksum to verify bytecode integrity. /// </remarks> /// <param name="path"></param> public void Load(string path) { int i, count; Reset(); try { using BinaryReader reader = new(File.Open(path, FileMode.Open)); // Check signature i = reader.ReadInt32(); if (i != FileSignature) { throw new Exception(InvalidFileFormat); } // Read reserved int i = reader.ReadInt32(); if (i != 0) { throw new Exception(InvalidFileFormat); } // Read flags FileFlag flags = (FileFlag)reader.ReadInt32(); // Read bytecodes count = reader.ReadInt32(); ByteCodes = new int[count]; for (i = 0; i < count; i++) { ByteCodes[i] = reader.ReadInt32(); } // Read functions count = reader.ReadInt32(); List <Function> functions = new(count); for (i = 0; i < count; i++) { string name = reader.ReadString(); FunctionType type = (FunctionType)reader.ReadInt32(); if (type == FunctionType.Internal) { // Temporarily set non-nullable action to null // We will correct further down var function = new InternalFunction(name, null !); functions.Add(function); } else if (type == FunctionType.Intrinsic) { var function = new IntrinsicFunction(name); functions.Add(function); } else // FunctionType.User { var function = new UserFunction(name, 0) { IP = reader.ReadInt32(), NumVariables = reader.ReadInt32(), NumParameters = reader.ReadInt32(), }; functions.Add(function); } } // Read global variables count = reader.ReadInt32(); Variables = new Variable[count]; for (i = 0; i < count; i++) { Variables[i] = ReadVariable(reader); } // Read literals count = reader.ReadInt32(); Literals = new Variable[count]; for (i = 0; i < count; i++) { Literals[i] = ReadVariable(reader); } // Read line numbers if (flags.HasFlag(FileFlag.HasLineNumbers)) { count = reader.ReadInt32(); LineNumbers = new int[count]; for (i = 0; i < count; i++) { LineNumbers[i] = reader.ReadInt32(); } Debug.Assert(LineNumbers.Length == ByteCodes.Length); } // Fixup internal functions foreach (var function in functions.OfType <InternalFunction>()) { if (InternalFunctions.InternalFunctionLookup.TryGetValue(function.Name, out InternalFunctionInfo? info)) { function.Action = info.Action; function.MinParameters = info.MinParameters; function.MaxParameters = info.MaxParameters; } else { throw new Exception($"Internal intrinsic function \"{function.Name}\" not found"); } } Functions = functions.ToArray(); } catch (Exception) { // Clear to known state if error Reset(); throw; } }