Exemple #1
0
        // Try to create object code from source code
        // If error, just throw exception
        private ScriptObjCode TryToCompile()
        {
            m_CompilerErrors.Clear();

            // If object file exists, create ScriptObjCode directly from that.
            // Otherwise, compile the source to create object file then create
            // ScriptObjCode from that.
            string assetID = m_Item.AssetID.ToString();

            m_CameFrom = "asset://" + assetID;
            ScriptObjCode objCode = Compile();

            if (m_CompilerErrors.Count != 0)
            {
                throw new Exception("compilation errors");
            }

            if (objCode == null)
            {
                throw new Exception("compilation failed");
            }

            return(objCode);
        }
Exemple #2
0
        /**
         * @brief Take an object file created by ScriptObjWriter() and convert it to a series of dynamic methods.
         * @param sdTypes   = script-defined types
         * @param objReader = where to read object file from (as written by ScriptObjWriter above).
         * @param scriptObjCode.EndMethod = called for each method defined at the end of the methods definition
         * @param objectTokens = write disassemble/decompile data (or null if not wanted)
         */
        public static void CreateObjCode(Dictionary <string, TokenDeclSDType> sdTypes, BinaryReader objReader,
                                         ScriptObjCode scriptObjCode, ObjectTokens objectTokens)
        {
            Dictionary <string, DynamicMethod> methods = new Dictionary <string, DynamicMethod>();
            DynamicMethod                  method      = null;
            ILGenerator                    ilGen       = null;
            Dictionary <int, Label>        labels      = new Dictionary <int, Label>();
            Dictionary <int, LocalBuilder> locals      = new Dictionary <int, LocalBuilder>();
            Dictionary <int, string>       labelNames  = new Dictionary <int, string>();
            Dictionary <int, string>       localNames  = new Dictionary <int, string>();

            object[] ilGenArg = new object[1];
            int      offset   = 0;
            Dictionary <int, ScriptSrcLoc> srcLocs = null;
            string srcFile = "";
            int    srcLine = 0;
            int    srcPosn = 0;

            while (true)
            {
                // Get IL instruction offset at beginning of instruction.
                offset = 0;
                if ((ilGen != null) && (monoGetCurrentOffset != null))
                {
                    offset = (int)monoGetCurrentOffset.Invoke(null, ilGenArg);
                }

                // Read and decode next internal format code from input file (.xmrobj file).
                ScriptObjWriterCode code = (ScriptObjWriterCode)objReader.ReadByte();
                switch (code)
                {
                // Reached end-of-file so we are all done.
                case ScriptObjWriterCode.TheEnd:
                    return;

                // Beginning of method's contents.
                // Method must have already been declared via DclMethod
                // so all we need is its name to retrieve from methods[].
                case ScriptObjWriterCode.BegMethod:
                {
                    string methName = objReader.ReadString();

                    method      = methods[methName];
                    ilGen       = method.GetILGenerator();
                    ilGenArg[0] = ilGen;

                    labels.Clear();
                    locals.Clear();
                    labelNames.Clear();
                    localNames.Clear();

                    srcLocs = new Dictionary <int, ScriptSrcLoc>();
                    if (objectTokens != null)
                    {
                        objectTokens.BegMethod(method);
                    }
                    break;
                }

                // End of method's contents (ie, an OpCodes.Ret was probably just output).
                // Call the callback to tell it the method is complete, and it can do whatever
                // it wants with the method.
                case ScriptObjWriterCode.EndMethod:
                {
                    ilGen       = null;
                    ilGenArg[0] = null;
                    scriptObjCode.EndMethod(method, srcLocs);
                    srcLocs = null;
                    if (objectTokens != null)
                    {
                        objectTokens.EndMethod();
                    }
                    break;
                }

                // Declare a label for branching to.
                case ScriptObjWriterCode.DclLabel:
                {
                    int    number = objReader.ReadInt32();
                    string name   = objReader.ReadString();

                    labels.Add(number, ilGen.DefineLabel());
                    labelNames.Add(number, name + "_" + number.ToString());
                    if (objectTokens != null)
                    {
                        objectTokens.DefineLabel(number, name);
                    }
                    break;
                }

                // Declare a local variable to store into.
                case ScriptObjWriterCode.DclLocal:
                {
                    int    number = objReader.ReadInt32();
                    string name   = objReader.ReadString();
                    string type   = objReader.ReadString();
                    Type   syType = GetTypeFromStr(sdTypes, type);

                    locals.Add(number, ilGen.DeclareLocal(syType));
                    localNames.Add(number, name + "_" + number.ToString());
                    if (objectTokens != null)
                    {
                        objectTokens.DefineLocal(number, name, type, syType);
                    }
                    break;
                }

                // Declare a method that will subsequently be defined.
                // We create the DynamicMethod object at this point in case there
                // are forward references from other method bodies.
                case ScriptObjWriterCode.DclMethod:
                {
                    string methName = objReader.ReadString();
                    Type   retType  = GetTypeFromStr(sdTypes, objReader.ReadString());
                    int    nArgs    = objReader.ReadInt32();

                    Type[]   argTypes = new Type[nArgs];
                    string[] argNames = new string[nArgs];
                    for (int i = 0; i < nArgs; i++)
                    {
                        argTypes[i] = GetTypeFromStr(sdTypes, objReader.ReadString());
                        argNames[i] = objReader.ReadString();
                    }
                    methods.Add(methName, new DynamicMethod(methName, retType, argTypes));
                    if (objectTokens != null)
                    {
                        objectTokens.DefineMethod(methName, retType, argTypes, argNames);
                    }
                    break;
                }

                // Mark a previously declared label at this spot.
                case ScriptObjWriterCode.MarkLabel:
                {
                    int number = objReader.ReadInt32();

                    ilGen.MarkLabel(labels[number]);

                    if (objectTokens != null)
                    {
                        objectTokens.MarkLabel(offset, number);
                    }
                    break;
                }

                // Try/Catch blocks.
                case ScriptObjWriterCode.BegExcBlk:
                {
                    ilGen.BeginExceptionBlock();
                    if (objectTokens != null)
                    {
                        objectTokens.BegExcBlk(offset);
                    }
                    break;
                }

                case ScriptObjWriterCode.BegCatBlk:
                {
                    Type excType = GetTypeFromStr(sdTypes, objReader.ReadString());
                    ilGen.BeginCatchBlock(excType);
                    if (objectTokens != null)
                    {
                        objectTokens.BegCatBlk(offset, excType);
                    }
                    break;
                }

                case ScriptObjWriterCode.BegFinBlk:
                {
                    ilGen.BeginFinallyBlock();
                    if (objectTokens != null)
                    {
                        objectTokens.BegFinBlk(offset);
                    }
                    break;
                }

                case ScriptObjWriterCode.EndExcBlk:
                {
                    ilGen.EndExceptionBlock();
                    if (objectTokens != null)
                    {
                        objectTokens.EndExcBlk(offset);
                    }
                    break;
                }

                // Emit an opcode with no operand.
                case ScriptObjWriterCode.EmitNull:
                {
                    OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);

                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitNull(offset, opCode);
                    }
                    break;
                }

                // Emit an opcode with a FieldInfo operand.
                case ScriptObjWriterCode.EmitField:
                {
                    OpCode opCode        = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    Type   reflectedType = GetTypeFromStr(sdTypes, objReader.ReadString());
                    string fieldName     = objReader.ReadString();

                    FieldInfo field = reflectedType.GetField(fieldName);
                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, field);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitField(offset, opCode, field);
                    }
                    break;
                }

                // Emit an opcode with a LocalBuilder operand.
                case ScriptObjWriterCode.EmitLocal:
                {
                    OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    int    number = objReader.ReadInt32();
                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, locals[number]);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitLocal(offset, opCode, number);
                    }
                    break;
                }

                // Emit an opcode with a Type operand.
                case ScriptObjWriterCode.EmitType:
                {
                    OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    string name   = objReader.ReadString();
                    Type   type   = GetTypeFromStr(sdTypes, name);

                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, type);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitType(offset, opCode, type);
                    }
                    break;
                }

                // Emit an opcode with a Label operand.
                case ScriptObjWriterCode.EmitLabel:
                {
                    OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    int    number = objReader.ReadInt32();

                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, labels[number]);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitLabel(offset, opCode, number);
                    }
                    break;
                }

                // Emit an opcode with a Label array operand.
                case ScriptObjWriterCode.EmitLabels:
                {
                    OpCode  opCode  = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    int     nLabels = objReader.ReadInt32();
                    Label[] lbls    = new Label[nLabels];
                    int[]   nums    = new int[nLabels];
                    for (int i = 0; i < nLabels; i++)
                    {
                        nums[i] = objReader.ReadInt32();
                        lbls[i] = labels[nums[i]];
                    }

                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, lbls);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitLabels(offset, opCode, nums);
                    }
                    break;
                }

                // Emit an opcode with a MethodInfo operand (such as a call) of an external function.
                case ScriptObjWriterCode.EmitMethodExt:
                {
                    OpCode opCode   = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    string methName = objReader.ReadString();
                    Type   methType = GetTypeFromStr(sdTypes, objReader.ReadString());
                    int    nArgs    = objReader.ReadInt32();

                    Type[] argTypes = new Type[nArgs];
                    for (int i = 0; i < nArgs; i++)
                    {
                        argTypes[i] = GetTypeFromStr(sdTypes, objReader.ReadString());
                    }
                    MethodInfo methInfo = methType.GetMethod(methName, argTypes);
                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, methInfo);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitMethod(offset, opCode, methInfo);
                    }
                    break;
                }

                // Emit an opcode with a MethodInfo operand of an internal function
                // (previously declared via DclMethod).
                case ScriptObjWriterCode.EmitMethodInt:
                {
                    OpCode opCode   = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    string methName = objReader.ReadString();

                    MethodInfo methInfo = methods[methName];
                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, methInfo);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitMethod(offset, opCode, methInfo);
                    }
                    break;
                }

                // Emit an opcode with a ConstructorInfo operand.
                case ScriptObjWriterCode.EmitCtor:
                {
                    OpCode opCode   = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    Type   ctorType = GetTypeFromStr(sdTypes, objReader.ReadString());
                    int    nArgs    = objReader.ReadInt32();
                    Type[] argTypes = new Type[nArgs];
                    for (int i = 0; i < nArgs; i++)
                    {
                        argTypes[i] = GetTypeFromStr(sdTypes, objReader.ReadString());
                    }

                    ConstructorInfo ctorInfo = ctorType.GetConstructor(argTypes);
                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, ctorInfo);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitCtor(offset, opCode, ctorInfo);
                    }
                    break;
                }

                // Emit an opcode with a constant operand of various types.
                case ScriptObjWriterCode.EmitDouble:
                {
                    OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    double value  = objReader.ReadDouble();

                    if (opCode != OpCodes.Ldc_R8)
                    {
                        throw new Exception("bad opcode " + opCode.ToString());
                    }
                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, value);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitDouble(offset, opCode, value);
                    }
                    break;
                }

                case ScriptObjWriterCode.EmitFloat:
                {
                    OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    float  value  = objReader.ReadSingle();

                    if (opCode != OpCodes.Ldc_R4)
                    {
                        throw new Exception("bad opcode " + opCode.ToString());
                    }
                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, value);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitFloat(offset, opCode, value);
                    }
                    break;
                }

                case ScriptObjWriterCode.EmitInteger:
                {
                    OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    int    value  = objReader.ReadInt32();

                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);

                    if (opCode == OpCodes.Ldc_I4)
                    {
                        if ((value >= -1) && (value <= 8))
                        {
                            opCode = opCodesLdcI4M1P8[value + 1];
                            ilGen.Emit(opCode);
                            if (objectTokens != null)
                            {
                                objectTokens.EmitNull(offset, opCode);
                            }
                            break;
                        }
                        if ((value >= 0) && (value <= 127))
                        {
                            opCode = OpCodes.Ldc_I4_S;
                            ilGen.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
                            goto pemitint;
                        }
                    }

                    ilGen.Emit(opCode, value);
pemitint:
                    if (objectTokens != null)
                    {
                        objectTokens.EmitInteger(offset, opCode, value);
                    }
                    break;
                }

                case ScriptObjWriterCode.EmitString:
                {
                    OpCode opCode = ReadOpCode(objReader, ref srcFile, ref srcLine, ref srcPosn);
                    string value  = objReader.ReadString();

                    SaveSrcLoc(srcLocs, offset, srcFile, srcLine, srcPosn);
                    ilGen.Emit(opCode, value);

                    if (objectTokens != null)
                    {
                        objectTokens.EmitString(offset, opCode, value);
                    }
                    break;
                }

                // Who knows what?
                default:
                    throw new Exception("bad ScriptObjWriterCode " + ((byte)code).ToString());
                }
            }
        }
Exemple #3
0
        /**
         * @brief Compile a script to produce a ScriptObjCode object
         * @returns object code pointer or null if compile error
         *          also can throw compile error exception
         */
        public ScriptObjCode Compile()
        {
            Stream       objFileStream = null;
            StreamWriter asmFileWriter = null;
            string       sourceHash    = null;
            TextWriter   saveSource    = null;

            string objFileName = GetScriptFileName(m_ScriptObjCodeKey + ".yobj");
            string tmpFileName = GetScriptFileName(m_ScriptObjCodeKey + ".ytmp");

            // If we already have an object file, don't bother compiling.
            if (!m_ForceRecomp && File.Exists(objFileName))
            {
                objFileStream = File.OpenRead(objFileName);
            }
            else
            {
                // If source file empty, try to read from asset server.
                if (EmptySource(m_SourceCode))
                {
                    m_SourceCode = FetchSource(m_CameFrom);
                }

                // Maybe write script source to a file for debugging.
                if (m_Engine.m_ScriptDebugSaveSource)
                {
                    string lslFileName = GetScriptFileName(m_ScriptObjCodeKey + ".lsl");
//                    m_log.Debug ("[YEngine]: MMRScriptCompileSaveSource: saving to " + lslFileName);
                    saveSource = File.CreateText(lslFileName);
                }

                // Parse source string into tokens.
                TokenBegin tokenBegin;
                try
                {
                    tokenBegin = TokenBegin.Construct(m_CameFrom, saveSource, ErrorHandler, m_SourceCode, out sourceHash);
                }
                finally
                {
                    if (saveSource != null)
                    {
                        saveSource.Close();
                    }
                }
                if (tokenBegin == null)
                {
                    m_log.Debug("[YEngine]: parsing errors on " + m_ScriptObjCodeKey);
                    return(null);
                }

                // Create object file one way or another.
                try
                {
                    // Create abstract syntax tree from raw tokens.
                    TokenScript tokenScript = ScriptReduce.Reduce(tokenBegin);
                    if (tokenScript == null)
                    {
                        m_log.Warn("[YEngine]: reduction errors on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
                        PrintCompilerErrors();
                        return(null);
                    }

                    // Compile abstract syntax tree to write object file.
                    using (BinaryWriter objFileWriter = new BinaryWriter(File.Create(tmpFileName)))
                    {
                        bool ok = ScriptCodeGen.CodeGen(tokenScript, objFileWriter, sourceHash);
                        if (!ok)
                        {
                            m_log.Warn("[YEngine]: compile error on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
                            PrintCompilerErrors();
                            return(null);
                        }
                    }

                    // File has been completely written.
                    // If there is an old one laying around, delete it now.
                    // Then re-open the new file for reading from the beginning.
                    if (File.Exists(objFileName))
                    {
                        File.Replace(tmpFileName, objFileName, null);
                    }
                    else
                    {
                        File.Move(tmpFileName, objFileName);
                    }

                    objFileStream = File.OpenRead(objFileName);
                }
                finally
                {
                    // In case something went wrong writing temp file, delete it.
                    File.Delete(tmpFileName);
                }

                // Since we just wrote the .xmrobj file, maybe save disassembly.
                if (m_Engine.m_ScriptDebugSaveIL)
                {
                    string asmFileName = GetScriptFileName(m_ScriptObjCodeKey + ".yasm");
//                    m_log.Debug ("[YEngine]: MMRScriptCompileSaveILGen: saving to " + asmFileName);
                    asmFileWriter = File.CreateText(asmFileName);
                }
            }

            // Read object file to create ScriptObjCode object.
            // Maybe also write disassembly to a file for debugging.
            BinaryReader  objFileReader = new BinaryReader(objFileStream);
            ScriptObjCode scriptObjCode = null;

            try
            {
                scriptObjCode = new ScriptObjCode(objFileReader, asmFileWriter, null);
            }
            finally
            {
                objFileReader.Close();
                if (asmFileWriter != null)
                {
                    asmFileWriter.Flush();
                    asmFileWriter.Close();
                }
            }

            return(scriptObjCode);
        }