public object execXVARScript(BinaryReader source, ImportedObject[] imports) { //Create an XVARFunctionContainer int headercount = source.ReadInt32(); #region Generic import logic //Import imports from source machine foreach (ImportedObject e in imports) { internalobjects.Add(e.VObject.refValue, e.VObject); } //Import the global variables for (int i = 0; i < headercount; i++) { //Read in the reference value ON THE double (yes, pun intended :) double refval = source.ReadDouble(); if (source.ReadBoolean()) { int len = source.ReadInt32(); byte[] data = source.ReadBytes(len); VMObject obj = VMObject.Deserialize(data); obj.refValue = refval; internalobjects.Add(refval,obj); } else { internalobjects.Add(refval, null); } } long beginningoffile = source.BaseStream.Position; //Read in the length of the INIT function long initlen = source.ReadInt64(); byte[] mainmethod = source.ReadBytes((int)initlen); XVARMethod method = new XVARMethod(source.BaseStream,this); //TODO: Read in all of the functions (with offsets) while (true) { try { //Read in function length, and download function int funclen = source.ReadInt32(); //TODO: Correct this. There should be a better way to load functions (without loading them all into RAM first. Maybe as variables somehow???) byte[] functiondata = source.ReadBytes(funclen); MemoryStream mstream = new MemoryStream(functiondata); BinaryReader mreader = new BinaryReader(mstream); //Read in the return type (not really used for anything at THIS point) mreader.ReadDouble(); //Read in associated object VMObject assocObj = internalobjects[mreader.ReadDouble()]; assocObj.functions.Add(mreader.ReadInt32(), new FunctionDeclaration() { function = functiondata }); mstream.Dispose(); } catch (EndOfStreamException) { break; } } //Invoke the MAIN method source.BaseStream.Position = beginningoffile; return method.Invoke(new VMObject[0]); #endregion }
public void compileXVARScript(StreamReader source, ImportedObject[] imports, BinaryWriter output) { Dictionary<string, VMObject> objects = new Dictionary<string, VMObject>(); double objPos = 0; #region Import logic output.Write(imports.ToArray().Length); foreach (ImportedObject e in imports) { objects.Add(e.Name, e.VObject); if (e.VObject.refValue >= objPos) { //Write the reference value as a double! output.Write(e.VObject.refValue); //Whether or not to literally interpolate the value output.Write(e.VObject.storeAsLiteral); //TODO here //Somehow convert the native functions relating to the object into virtual XVAR function //definitions MethodInfo[] methods = e.VObject.GetType().GetMethods(); try { int methodindex = 0; foreach (MethodInfo et in methods) { e.VObject.functions.Add(methodindex, new FunctionDeclaration() { nativeMethod = et }); e.VObject.functionIdentifiers.Add(et.Name, methodindex); methodindex += 1; } } catch (Exception) { //Must have already been added } //END TODO here if (e.VObject.storeAsLiteral) { byte[] data = e.VObject.Serialize(); output.Write(data.Length); output.Write(data); } objPos = e.VObject.refValue + 1; } } #endregion //Opcode 4 = Internal function offset declaration (long) #region Compilation logic long lastfunctionoffset = 0; bool hascalled = false; long spos = output.BaseStream.Position; int funcID = 0; output.Write((long)0); long zpos = output.BaseStream.Position; string currentFunction = ""; FunctionDeclaration mdec = new FunctionDeclaration(); Dictionary<string, long> lostandfound = new Dictionary<string, long>(); VMObject parentObject = null; while (!source.EndOfStream) { string instruction = source.ReadLine(); string[] parts = intellisplit(instruction); if (parts[0] == "function") { mdec = new FunctionDeclaration(); output.BaseStream.Position = lastfunctionoffset; //Length of function output.Write((int)0); currentFunction = parts[3]; //Return type foreach (KeyValuePair<double, Type> e in VMObject.types) { if (e.Value.Name == parts[1]) { output.Write(e.Key); break; } } //Associate function with object VMObject obj = objects[parts[2]]; parentObject = obj; output.Write(obj.refValue); int ival = obj.functions.Count+1; funcID = ival; obj.functionIdentifiers.Add(parts[3], ival); //Write out the index of the function output.Write(ival); } if (parts[0] == "ndfunction") { long yval = output.BaseStream.Position; int tval = (int)(output.BaseStream.Position - lastfunctionoffset); output.BaseStream.Position = lastfunctionoffset; //Write function length output.Write(tval); //Data's already been written. Seek to beginning of stream! output.BaseStream.Position = yval; //Read the function back in output.BaseStream.Position = lastfunctionoffset; //Read function byte array byte[] mray = new byte[tval]; output.BaseStream.Read(mray,0,mray.Length); mdec.function = mray; long previous = lastfunctionoffset; parentObject.functions.Add(funcID, mdec); lastfunctionoffset = output.BaseStream.Position; if (lostandfound.Keys.Contains(currentFunction)) { output.BaseStream.Position = lostandfound[currentFunction]; output.Write(previous); output.BaseStream.Position = lastfunctionoffset; } } if (parts[0] == "unalloc") { //Opcode 3 try { output.Write((byte)3); output.Write(objects[parts[1]].refValue); objects.Remove(parts[1]); } catch (KeyNotFoundException) { throw new NullReferenceException("Invalid reference. Variable " + parts[1] + " has not been declared."); } } if (parts[0] == "stralloc") { //Opcode 2 output.Write((byte)2); //Store the string to a variable parts[1] = parts[1].Replace("\"", ""); output.Write(parts[1]); if (objects.Keys.Contains(parts[2])) { objects[parts[2]] = new VMString(parts[1]) { refValue = objPos }; } else { objects.Add(parts[2], new VMString(parts[1]) { refValue = objPos }); } output.Write(objPos); objPos += 1; } if (parts[0] == "ndinit") { if (!hascalled) { long cpos = output.BaseStream.Position; output.BaseStream.Position = spos; output.Write(cpos-zpos); output.BaseStream.Position = cpos; hascalled = true; lastfunctionoffset = cpos; } else { throw new ArgumentException("endinit may only be called once per session! What were you thinking?!?!?"); } } if (parts[0] == "call") { //Write out opcode (as byte) VMObject currentObj = objects[parts[1]]; if (!currentObj.functionIdentifiers.ContainsKey(parts[2])) { output.Write((byte)4); long ntpos = output.BaseStream.Position; //Function offset to be determined output.Write((long)-1); lostandfound.Add(parts[2], ntpos); } else { output.Write((byte)0); try { //Write out index of reference object (as double) output.Write(currentObj.refValue); try { FunctionDeclaration function = currentObj.functions[currentObj.functionIdentifiers[parts[2]]]; //Write out index of function (as int32) output.Write(currentObj.functionIdentifiers[parts[2]]); //Write out length of parameters (as int32) string[] args; try { args = parts[3].Split(",".ToArray(), StringSplitOptions.RemoveEmptyEntries); if (args[0] == "null") { args = new string[0]; } } catch (Exception) { args = new string[0]; } output.Write(args.Length); foreach (string et in args) { //Write out each reference as a double output.Write(objects[et].refValue); } if (parts.Length == 5) { //Whether or not the output should be assigned to a variable output.Write(true); //The variable to assign it to if (objects.ContainsKey(parts[4])) { output.Write(objects[parts[4]].refValue); } else { VMObject tobj = (VMObject)function.returnType.GetConstructor(new Type[0]).Invoke(null); tobj.refValue = objPos; //Populate the object's methods objects.Add(parts[4], tobj); output.Write(objPos); objPos += 1; } } else { output.Write(false); } } catch (AccessViolationException) { } } catch (KeyNotFoundException) { throw new NullReferenceException("Invalid reference. Variable " + parts[1] + " has not been declared."); } } } } #endregion }